diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index e11d449924..f2aa5c1184 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -64,7 +64,7 @@ impl Render for CollabTitlebarItem { .w_full() .h(titlebar_height(cx)) .map(|this| { - if cx.is_full_screen() { + if cx.is_fullscreen() { this.pl_2() } else { // Use pixels here instead of a rem-based size because the macOS traffic diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 90b036a78b..ecebbd2849 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -191,8 +191,8 @@ pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle { fn show_character_palette(&self); fn minimize(&self); fn zoom(&self); - fn toggle_full_screen(&self); - fn is_full_screen(&self) -> bool; + fn toggle_fullscreen(&self); + fn is_fullscreen(&self) -> bool; fn on_request_frame(&self, callback: Box); fn on_input(&self, callback: Box bool>); fn on_active_status_change(&self, callback: Box); @@ -596,7 +596,7 @@ pub enum WindowKind { /// Platform level interface /// bounds: Bounds -/// full_screen: bool +/// fullscreen: bool /// The appearance of the window, as defined by the operating system. /// diff --git a/crates/gpui/src/platform/linux/wayland/window.rs b/crates/gpui/src/platform/linux/wayland/window.rs index 8959c08eb9..897a32a420 100644 --- a/crates/gpui/src/platform/linux/wayland/window.rs +++ b/crates/gpui/src/platform/linux/wayland/window.rs @@ -362,7 +362,7 @@ impl PlatformWindow for WaylandWindow { // todo(linux) } - fn toggle_full_screen(&self) { + fn toggle_fullscreen(&self) { if !self.0.inner.borrow().fullscreen { self.0.toplevel.set_fullscreen(None); } else { @@ -370,7 +370,7 @@ impl PlatformWindow for WaylandWindow { } } - fn is_full_screen(&self) -> bool { + fn is_fullscreen(&self) -> bool { self.0.inner.borrow_mut().fullscreen } diff --git a/crates/gpui/src/platform/linux/x11/window.rs b/crates/gpui/src/platform/linux/x11/window.rs index 1a59d85bb5..3b07b5c587 100644 --- a/crates/gpui/src/platform/linux/x11/window.rs +++ b/crates/gpui/src/platform/linux/x11/window.rs @@ -438,12 +438,12 @@ impl PlatformWindow for X11Window { } // todo(linux) - fn toggle_full_screen(&self) { + fn toggle_fullscreen(&self) { unimplemented!() } // todo(linux) - fn is_full_screen(&self) -> bool { + fn is_fullscreen(&self) -> bool { false } diff --git a/crates/gpui/src/platform/mac/status_item.rs b/crates/gpui/src/platform/mac/status_item.rs index 9c7903a0fc..39df3f15c0 100644 --- a/crates/gpui/src/platform/mac/status_item.rs +++ b/crates/gpui/src/platform/mac/status_item.rs @@ -252,7 +252,7 @@ impl platform::Window for StatusItem { } } - fn toggle_full_screen(&self) { + fn toggle_fullscreen(&self) { unimplemented!() } diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index e648f508b6..8240b21101 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -941,7 +941,7 @@ impl PlatformWindow for MacWindow { .detach(); } - fn toggle_full_screen(&self) { + fn toggle_fullscreen(&self) { let this = self.0.lock(); let window = this.native_window; this.executor @@ -953,7 +953,7 @@ impl PlatformWindow for MacWindow { .detach(); } - fn is_full_screen(&self) -> bool { + fn is_fullscreen(&self) -> bool { let this = self.0.lock(); let window = this.native_window; diff --git a/crates/gpui/src/platform/test/window.rs b/crates/gpui/src/platform/test/window.rs index 08fb108c88..f9150b409a 100644 --- a/crates/gpui/src/platform/test/window.rs +++ b/crates/gpui/src/platform/test/window.rs @@ -197,12 +197,12 @@ impl PlatformWindow for TestWindow { unimplemented!() } - fn toggle_full_screen(&self) { + fn toggle_fullscreen(&self) { let mut lock = self.0.lock(); lock.is_fullscreen = !lock.is_fullscreen; } - fn is_full_screen(&self) -> bool { + fn is_fullscreen(&self) -> bool { self.0.lock().is_fullscreen } diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 58dad7c074..36ca490960 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -909,10 +909,10 @@ impl PlatformWindow for WindowsWindow { fn zoom(&self) {} // todo(windows) - fn toggle_full_screen(&self) {} + fn toggle_fullscreen(&self) {} // todo(windows) - fn is_full_screen(&self) -> bool { + fn is_fullscreen(&self) -> bool { false } diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index 1bba88f0f8..01f5be498c 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -338,9 +338,6 @@ fn default_bounds(cx: &mut AppContext) -> Bounds { }) } -// Fixed, Maximized, Fullscreen, and 'Inherent / default' -// Platform part, you don't, you only need Fixed, Maximized, Fullscreen - impl Window { pub(crate) fn new( handle: AnyWindowHandle, @@ -386,7 +383,7 @@ impl Window { let last_input_timestamp = Rc::new(Cell::new(Instant::now())); if fullscreen { - platform_window.toggle_full_screen(); + platform_window.toggle_fullscreen(); } platform_window.on_close(Box::new({ @@ -807,8 +804,8 @@ impl<'a> WindowContext<'a> { } /// Retusn whether or not the window is currently fullscreen - pub fn is_full_screen(&self) -> bool { - self.window.platform_window.is_full_screen() + pub fn is_fullscreen(&self) -> bool { + self.window.platform_window.is_fullscreen() } fn appearance_changed(&mut self) { @@ -1481,8 +1478,8 @@ impl<'a> WindowContext<'a> { } /// Toggle full screen status on the current window at the platform level. - pub fn toggle_full_screen(&self) { - self.window.platform_window.toggle_full_screen(); + pub fn toggle_fullscreen(&self) { + self.window.platform_window.toggle_fullscreen(); } /// Present a platform dialog. diff --git a/crates/workspace/src/persistence.rs b/crates/workspace/src/persistence.rs index 2e6375b999..48bb339558 100644 --- a/crates/workspace/src/persistence.rs +++ b/crates/workspace/src/persistence.rs @@ -138,6 +138,7 @@ define_connection! { // window_width: Option, // WindowBounds::Fixed RectF width // window_height: Option, // WindowBounds::Fixed RectF height // display: Option, // Display id + // fullscreen: Option, // Is the window fullscreen? // ) // // pane_groups( @@ -274,7 +275,11 @@ define_connection! { // Add pane group flex data sql!( ALTER TABLE pane_groups ADD COLUMN flexes TEXT; - ) + ), + // Add fullscreen field to workspace + sql!( + ALTER TABLE workspaces ADD COLUMN fullscreen INTEGER; //bool + ), ]; } @@ -290,11 +295,12 @@ impl WorkspaceDb { // Note that we re-assign the workspace_id here in case it's empty // and we've grabbed the most recent workspace - let (workspace_id, workspace_location, bounds, display, docks): ( + let (workspace_id, workspace_location, bounds, display, fullscreen, docks): ( WorkspaceId, WorkspaceLocation, Option, Option, + Option, DockStructure, ) = self .select_row_bound(sql! { @@ -307,6 +313,7 @@ impl WorkspaceDb { window_width, window_height, display, + fullscreen, left_dock_visible, left_dock_active_panel, left_dock_zoom, @@ -332,6 +339,7 @@ impl WorkspaceDb { .context("Getting center group") .log_err()?, bounds: bounds.map(|bounds| bounds.0), + fullscreen: fullscreen.unwrap_or(false), display, docks, }) @@ -412,6 +420,16 @@ impl WorkspaceDb { } } + query! { + pub fn last_monitor() -> Result> { + SELECT display + FROM workspaces + WHERE workspace_location IS NOT NULL + ORDER BY timestamp DESC + LIMIT 1 + } + } + query! { pub async fn delete_workspace_by_id(id: WorkspaceId) -> Result<()> { DELETE FROM workspaces @@ -648,6 +666,14 @@ impl WorkspaceDb { WHERE workspace_id = ?1 } } + + query! { + pub(crate) async fn set_fullscreen(workspace_id: WorkspaceId, fullscreen: bool) -> Result<()> { + UPDATE workspaces + SET fullscreen = ?2 + WHERE workspace_id = ?1 + } + } } #[cfg(test)] @@ -733,6 +759,7 @@ mod tests { bounds: Default::default(), display: Default::default(), docks: Default::default(), + fullscreen: false, }; let workspace_2 = SerializedWorkspace { @@ -742,6 +769,7 @@ mod tests { bounds: Default::default(), display: Default::default(), docks: Default::default(), + fullscreen: false, }; db.save_workspace(workspace_1.clone()).await; @@ -840,6 +868,7 @@ mod tests { bounds: Default::default(), display: Default::default(), docks: Default::default(), + fullscreen: false, }; db.save_workspace(workspace.clone()).await; @@ -868,6 +897,7 @@ mod tests { bounds: Default::default(), display: Default::default(), docks: Default::default(), + fullscreen: false, }; let mut workspace_2 = SerializedWorkspace { @@ -877,6 +907,7 @@ mod tests { bounds: Default::default(), display: Default::default(), docks: Default::default(), + fullscreen: false, }; db.save_workspace(workspace_1.clone()).await; @@ -913,6 +944,7 @@ mod tests { bounds: Default::default(), display: Default::default(), docks: Default::default(), + fullscreen: false, }; db.save_workspace(workspace_3.clone()).await; @@ -946,6 +978,7 @@ mod tests { bounds: Default::default(), display: Default::default(), docks: Default::default(), + fullscreen: false, } } diff --git a/crates/workspace/src/persistence/model.rs b/crates/workspace/src/persistence/model.rs index c03b1dc116..6e5ce246c9 100644 --- a/crates/workspace/src/persistence/model.rs +++ b/crates/workspace/src/persistence/model.rs @@ -70,6 +70,7 @@ pub(crate) struct SerializedWorkspace { pub(crate) location: WorkspaceLocation, pub(crate) center_group: SerializedPaneGroup, pub(crate) bounds: Option>, + pub(crate) fullscreen: bool, pub(crate) display: Option, pub(crate) docks: DockStructure, } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index cced552b10..10b373702c 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -694,15 +694,28 @@ impl Workspace { let display_bounds = display.bounds(); window_bounds.origin.x -= display_bounds.origin.x; window_bounds.origin.y -= display_bounds.origin.y; + let fullscreen = cx.is_fullscreen(); if let Some(display_uuid) = display.uuid().log_err() { - cx.background_executor() - .spawn(DB.set_window_bounds( - workspace_id, - SerializedWindowsBounds(window_bounds), - display_uuid, - )) - .detach_and_log_err(cx); + // Only update the window bounds when not full screen, + // so we can remember the last non-fullscreen bounds + // across restarts + if fullscreen { + cx.background_executor() + .spawn(DB.set_fullscreen(workspace_id, true)) + .detach_and_log_err(cx); + } else { + cx.background_executor() + .spawn(DB.set_fullscreen(workspace_id, false)) + .detach_and_log_err(cx); + cx.background_executor() + .spawn(DB.set_window_bounds( + workspace_id, + SerializedWindowsBounds(window_bounds), + display_uuid, + )) + .detach_and_log_err(cx); + } } } cx.notify(); @@ -834,36 +847,41 @@ impl Workspace { window } else { let window_bounds_override = window_bounds_env_override(&cx); - let (bounds, display) = if let Some(bounds) = window_bounds_override { - (Some(bounds), None) - } else { - serialized_workspace - .as_ref() - .and_then(|serialized_workspace| { - let serialized_display = serialized_workspace.display?; - let mut bounds = serialized_workspace.bounds?; - // Stored bounds are relative to the containing display. - // So convert back to global coordinates if that screen still exists - let screen = cx - .update(|cx| { - cx.displays().into_iter().find(|display| { - display.uuid().ok() == Some(serialized_display) - }) - }) - .ok()??; - let screen_bounds = screen.bounds(); - bounds.origin.x += screen_bounds.origin.x; - bounds.origin.y += screen_bounds.origin.y; - - Some((bounds, serialized_display)) + let (bounds, display, fullscreen) = if let Some(bounds) = window_bounds_override { + (Some(bounds), None, false) + } else if let Some((serialized_display, mut bounds, fullscreen)) = + serialized_workspace.as_ref().and_then(|workspace| { + Some((workspace.display?, workspace.bounds?, workspace.fullscreen)) + }) + { + // Stored bounds are relative to the containing display. + // So convert back to global coordinates if that screen still exists + let screen_bounds = cx + .update(|cx| { + cx.displays() + .into_iter() + .find(|display| display.uuid().ok() == Some(serialized_display)) }) - .unzip() + .ok() + .flatten() + .map(|screen| screen.bounds()); + + if let Some(screen_bounds) = screen_bounds { + bounds.origin.x += screen_bounds.origin.x; + bounds.origin.y += screen_bounds.origin.y; + } + + (Some(bounds), Some(serialized_display), fullscreen) + } else { + let display = DB.last_monitor().log_err().flatten(); + (None, display, false) }; // Use the serialized workspace to construct the new window let mut options = cx.update(|cx| (app_state.build_window_options)(display, cx))?; options.bounds = bounds; + options.fullscreen = fullscreen; cx.open_window(options, { let app_state = app_state.clone(); let project_handle = project_handle.clone(); @@ -3420,6 +3438,7 @@ impl Workspace { bounds: Default::default(), display: Default::default(), docks, + fullscreen: cx.is_fullscreen(), }; cx.spawn(|_| persistence::DB.save_workspace(serialized_workspace)) diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 06ddf2e278..33f3dc1c92 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -222,7 +222,7 @@ pub fn initialize_workspace(app_state: Arc, cx: &mut AppContext) { cx.zoom_window(); }) .register_action(|_, _: &ToggleFullScreen, cx| { - cx.toggle_full_screen(); + cx.toggle_fullscreen(); }) .register_action(|_, action: &OpenZedUrl, cx| { OpenListener::global(cx).open_urls(vec![action.url.clone()])