Open new windows with a default size and position (#9204)

This PR changes GPUI to open windows with a default size and location,
and to otherwise inherit from their spawning window.

Note: The linux build now crashes on startup.

Release Notes:

- N/A

---------

Co-authored-by: Nathan <nathan@zed.dev>
Co-authored-by: Ezekiel Warren <zaucy@users.noreply.github.com>
This commit is contained in:
Mikayla Maki 2024-03-12 21:19:51 -07:00 committed by GitHub
parent 9a2dceeea1
commit e792c1a5c5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 443 additions and 347 deletions

View file

@ -4,7 +4,7 @@ use std::path::Path;
use anyhow::{anyhow, bail, Context, Result};
use db::{define_connection, query, sqlez::connection::Connection, sqlez_macros::sql};
use gpui::{point, size, Axis, Bounds, WindowBounds};
use gpui::{point, size, Axis, Bounds};
use sqlez::{
bindable::{Bind, Column, StaticColumnCount},
@ -59,7 +59,7 @@ impl sqlez::bindable::Column for SerializedAxis {
}
#[derive(Clone, Debug, PartialEq)]
pub(crate) struct SerializedWindowsBounds(pub(crate) WindowBounds);
pub(crate) struct SerializedWindowsBounds(pub(crate) Bounds<gpui::GlobalPixels>);
impl StaticColumnCount for SerializedWindowsBounds {
fn column_count() -> usize {
@ -69,30 +69,15 @@ impl StaticColumnCount for SerializedWindowsBounds {
impl Bind for SerializedWindowsBounds {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
let (region, next_index) = match self.0 {
WindowBounds::Fullscreen => {
let next_index = statement.bind(&"Fullscreen", start_index)?;
(None, next_index)
}
WindowBounds::Maximized => {
let next_index = statement.bind(&"Maximized", start_index)?;
(None, next_index)
}
WindowBounds::Fixed(region) => {
let next_index = statement.bind(&"Fixed", start_index)?;
(Some(region), next_index)
}
};
let next_index = statement.bind(&"Fixed", start_index)?;
statement.bind(
&region.map(|region| {
(
SerializedGlobalPixels(region.origin.x),
SerializedGlobalPixels(region.origin.y),
SerializedGlobalPixels(region.size.width),
SerializedGlobalPixels(region.size.height),
)
}),
&(
SerializedGlobalPixels(self.0.origin.x),
SerializedGlobalPixels(self.0.origin.y),
SerializedGlobalPixels(self.0.size.width),
SerializedGlobalPixels(self.0.size.height),
),
next_index,
)
}
@ -102,18 +87,16 @@ impl Column for SerializedWindowsBounds {
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let (window_state, next_index) = String::column(statement, start_index)?;
let bounds = match window_state.as_str() {
"Fullscreen" => SerializedWindowsBounds(WindowBounds::Fullscreen),
"Maximized" => SerializedWindowsBounds(WindowBounds::Maximized),
"Fixed" => {
let ((x, y, width, height), _) = Column::column(statement, next_index)?;
let x: f64 = x;
let y: f64 = y;
let width: f64 = width;
let height: f64 = height;
SerializedWindowsBounds(WindowBounds::Fixed(Bounds {
SerializedWindowsBounds(Bounds {
origin: point(x.into(), y.into()),
size: size(width.into(), height.into()),
}))
})
}
_ => bail!("Window State did not have a valid string"),
};

View file

@ -6,7 +6,7 @@ use db::sqlez::{
bindable::{Bind, Column, StaticColumnCount},
statement::Statement,
};
use gpui::{AsyncWindowContext, Model, Task, View, WeakView, WindowBounds};
use gpui::{AsyncWindowContext, Bounds, GlobalPixels, Model, Task, View, WeakView};
use project::Project;
use std::{
path::{Path, PathBuf},
@ -69,7 +69,7 @@ pub(crate) struct SerializedWorkspace {
pub(crate) id: WorkspaceId,
pub(crate) location: WorkspaceLocation,
pub(crate) center_group: SerializedPaneGroup,
pub(crate) bounds: Option<WindowBounds>,
pub(crate) bounds: Option<Bounds<GlobalPixels>>,
pub(crate) display: Option<Uuid>,
pub(crate) docks: DockStructure,
}

View file

@ -32,7 +32,7 @@ use gpui::{
FocusableView, Global, GlobalPixels, InteractiveElement, IntoElement, KeyContext, Keystroke,
LayoutId, ManagedView, Model, ModelContext, ParentElement, PathPromptOptions, Pixels, Point,
PromptLevel, Render, SharedString, Size, Styled, Subscription, Task, View, ViewContext,
VisualContext, WeakView, WindowBounds, WindowContext, WindowHandle, WindowOptions,
VisualContext, WeakView, WindowContext, WindowHandle, WindowOptions,
};
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem};
use itertools::Itertools;
@ -362,8 +362,7 @@ pub struct AppState {
pub user_store: Model<UserStore>,
pub workspace_store: Model<WorkspaceStore>,
pub fs: Arc<dyn fs::Fs>,
pub build_window_options:
fn(Option<WindowBounds>, Option<Uuid>, &mut AppContext) -> WindowOptions,
pub build_window_options: fn(Option<Uuid>, &mut AppContext) -> WindowOptions,
pub node_runtime: Arc<dyn NodeRuntime>,
}
@ -424,7 +423,7 @@ impl AppState {
user_store,
workspace_store,
node_runtime: FakeNodeRuntime::new(),
build_window_options: |_, _, _| Default::default(),
build_window_options: |_, _| Default::default(),
})
}
}
@ -690,18 +689,16 @@ impl Workspace {
cx.observe_window_bounds(move |_, cx| {
if let Some(display) = cx.display() {
// Transform fixed bounds to be stored in terms of the containing display
let mut bounds = cx.window_bounds();
if let WindowBounds::Fixed(window_bounds) = &mut bounds {
let display_bounds = display.bounds();
window_bounds.origin.x -= display_bounds.origin.x;
window_bounds.origin.y -= display_bounds.origin.y;
}
let mut window_bounds = cx.window_bounds();
let display_bounds = display.bounds();
window_bounds.origin.x -= display_bounds.origin.x;
window_bounds.origin.y -= display_bounds.origin.y;
if let Some(display_uuid) = display.uuid().log_err() {
cx.background_executor()
.spawn(DB.set_window_bounds(
workspace_id,
SerializedWindowsBounds(bounds),
SerializedWindowsBounds(window_bounds),
display_uuid,
))
.detach_and_log_err(cx);
@ -847,19 +844,16 @@ impl Workspace {
// Stored bounds are relative to the containing display.
// So convert back to global coordinates if that screen still exists
if let WindowBounds::Fixed(mut window_bounds) = bounds {
let screen = cx
.update(|cx| {
cx.displays().into_iter().find(|display| {
display.uuid().ok() == Some(serialized_display)
})
let screen = cx
.update(|cx| {
cx.displays().into_iter().find(|display| {
display.uuid().ok() == Some(serialized_display)
})
.ok()??;
let screen_bounds = screen.bounds();
window_bounds.origin.x += screen_bounds.origin.x;
window_bounds.origin.y += screen_bounds.origin.y;
bounds = WindowBounds::Fixed(window_bounds);
}
})
.ok()??;
let screen_bounds = screen.bounds();
bounds.origin.x += screen_bounds.origin.x;
bounds.origin.y += screen_bounds.origin.y;
Some((bounds, serialized_display))
})
@ -867,9 +861,8 @@ impl Workspace {
};
// Use the serialized workspace to construct the new window
let options =
cx.update(|cx| (app_state.build_window_options)(bounds, display, cx))?;
let mut options = cx.update(|cx| (app_state.build_window_options)(display, cx))?;
options.bounds = bounds;
cx.open_window(options, {
let app_state = app_state.clone();
let project_handle = project_handle.clone();
@ -3610,7 +3603,7 @@ impl Workspace {
client,
user_store,
fs: project.read(cx).fs().clone(),
build_window_options: |_, _, _| Default::default(),
build_window_options: |_, _| Default::default(),
node_runtime: FakeNodeRuntime::new(),
});
let workspace = Self::new(0, project, app_state, cx);
@ -3663,17 +3656,15 @@ impl Workspace {
}
}
fn window_bounds_env_override(cx: &AsyncAppContext) -> Option<WindowBounds> {
fn window_bounds_env_override(cx: &AsyncAppContext) -> Option<Bounds<GlobalPixels>> {
let display_origin = cx
.update(|cx| Some(cx.displays().first()?.bounds().origin))
.ok()??;
ZED_WINDOW_POSITION
.zip(*ZED_WINDOW_SIZE)
.map(|(position, size)| {
WindowBounds::Fixed(Bounds {
origin: display_origin + position,
size,
})
.map(|(position, size)| Bounds {
origin: display_origin + position,
size,
})
}
@ -4553,7 +4544,8 @@ pub fn join_hosted_project(
let window_bounds_override = window_bounds_env_override(&cx);
cx.update(|cx| {
let options = (app_state.build_window_options)(window_bounds_override, None, cx);
let mut options = (app_state.build_window_options)(None, cx);
options.bounds = window_bounds_override;
cx.open_window(options, |cx| {
cx.new_view(|cx| Workspace::new(0, project, app_state.clone(), cx))
})
@ -4611,7 +4603,8 @@ pub fn join_in_room_project(
let window_bounds_override = window_bounds_env_override(&cx);
cx.update(|cx| {
let options = (app_state.build_window_options)(window_bounds_override, None, cx);
let mut options = (app_state.build_window_options)(None, cx);
options.bounds = window_bounds_override;
cx.open_window(options, |cx| {
cx.new_view(|cx| Workspace::new(0, project, app_state.clone(), cx))
})