T30: the main window opens at the size it was left at: its size, read once the bounds settle and kept in the settings unless the window is maximized or full screen, opens the next window, shrunk where it passes the screen
CI / platforms (ubuntu-24.04) (push) Successful in 1m1s
CI / platforms (windows-latest) (push) Successful in 1m40s
CI / macos (push) Successful in 12m35s

This commit is contained in:
ZacharyZhang-NY committed 2026-10-16 03:43:15 -04:00
1 parent a5dbfbcbae
commit 1bf420ce41
6 files changed
+93 -9

No files matched your search

+70 -6
View File
@@ -1,10 +1,10 @@
use std::borrow::Cow;
use std::{borrow::Cow, time::Duration};
use anyhow::Context as _;
use ely_gpui_component::theme::ActiveTheme;
use gpui::{
App, AppContext, Bounds, TitlebarOptions, WindowBounds, WindowDecorations, WindowHandle,
WindowOptions, px, size,
App, AppContext, Bounds, Context, Pixels, Size, Task, TitlebarOptions, Window, WindowBounds,
WindowDecorations, WindowHandle, WindowOptions, px, size,
};
#[cfg(target_os = "macos")]
@@ -17,6 +17,9 @@ use crate::{
workspace::{self, TITLE, Workspace},
};
/// How long the window's size holds before it is kept, so a drag saves once.
const SETTLE: Duration = Duration::from_millis(500);
/// The id the macOS bundle and Linux desktop entry share.
pub const APP_ID: &str = "com.zacharyzhang.elyterminal";
@@ -85,7 +88,8 @@ pub fn start(cx: &mut App) -> anyhow::Result<()> {
/// Opens the main window running `launch`.
pub fn open(launch: Launch, cx: &mut App) -> anyhow::Result<WindowHandle<Workspace>> {
let bounds = Bounds::centered(None, size(px(1200.0), px(760.0)), cx);
let kept = opening_size(cx);
let bounds = Bounds::centered(None, kept, cx);
let background = blur::appearance(SettingsStore::get(cx));
let options = WindowOptions {
window_bounds: Some(WindowBounds::Windowed(bounds)),
@@ -105,11 +109,71 @@ pub fn open(launch: Launch, cx: &mut App) -> anyhow::Result<WindowHandle<Workspa
window
.observe_window_appearance(|_, cx| themes::apply(cx))
.detach();
cx.new(|cx| Workspace::new(pty, events, launch, window, cx))
cx.new(|cx| {
keep_size(window, cx);
Workspace::new(pty, events, launch, window, cx)
})
})?;
log::info!(
"app: main window open, blur: {background:?} on {}",
"app: main window open at {} by {}, blur: {background:?} on {}",
f32::from(kept.width),
f32::from(kept.height),
std::env::consts::OS
);
Ok(window)
}
/// The kept size, within the primary display's visible area where that is known.
fn opening_size(cx: &App) -> Size<Pixels> {
let settings = SettingsStore::get(cx);
let room = cx
.primary_display()
.map(|display| display.visible_bounds().size);
let fit = |want: f32, side: Option<Pixels>| match side.map(f32::from) {
Some(side) if side > 0.0 && want > side => {
log::info!(
"app: a kept side of {want} px passes the screen's {side}; the window takes {side}"
);
px(side)
}
_ => px(want),
};
size(
fit(settings.window_width, room.map(|area| area.width)),
fit(settings.window_height, room.map(|area| area.height)),
)
}
/// Keeps the window's size in the settings once it settles; maximized or full screen, the size before stays.
fn keep_size(window: &mut Window, cx: &mut Context<Workspace>) {
let mut _settling: Option<Task<()>> = None;
cx.observe_window_bounds(window, move |_, window, cx| {
_settling = Some(cx.spawn_in(window, async move |_, cx| {
cx.background_executor().timer(SETTLE).await;
// Read once settled: X11 marks a window maximized after its new size.
let kept = cx.update(|window, cx| {
if window.is_maximized() || window.is_fullscreen() {
return Ok(());
}
let area = window.window_bounds().get_bounds().size;
let (width, height) = (
f32::from(area.width).round(),
f32::from(area.height).round(),
);
SettingsStore::update(cx, |settings| {
settings.window_width = width;
settings.window_height = height;
})
.with_context(|| {
format!("app: the window's size, {width} by {height}, is not kept")
})
});
match kept {
Ok(Ok(())) => {}
Ok(Err(error)) => log::error!("{error:#}"),
Err(_) => log::debug!("app: the window closed before its size settled"),
}
}));
})
.detach();
}
+17
View File
@@ -75,6 +75,9 @@ pub struct Settings {
pub show_sessions: bool,
pub show_panel: bool,
pub panel: PanelTab,
/// The main window's size, unmaximized, in pixels.
pub window_width: f32,
pub window_height: f32,
}
impl Default for Settings {
@@ -100,6 +103,8 @@ impl Default for Settings {
show_sessions: true,
show_panel: true,
panel: PanelTab::Git,
window_width: 1200.0,
window_height: 760.0,
}
}
}
@@ -109,6 +114,7 @@ pub const LINE_HEIGHT: RangeInclusive<f32> = 1.0..=2.0;
pub const OPACITY: RangeInclusive<f32> = 0.3..=1.0;
pub const PADDING: RangeInclusive<f32> = 0.0..=64.0;
pub const SCROLLBACK: RangeInclusive<u32> = 0..=100_000;
pub const WINDOW: RangeInclusive<f32> = 100.0..=16384.0;
impl Settings {
/// Every value inside its range, every theme built in; the error names the field.
@@ -119,6 +125,8 @@ impl Settings {
within("padding_x", self.padding_x, &PADDING)?;
within("padding_y", self.padding_y, &PADDING)?;
within("scrollback", self.scrollback, &SCROLLBACK)?;
within("window_width", self.window_width, &WINDOW)?;
within("window_height", self.window_height, &WINDOW)?;
for (field, id) in [
("theme", Some(&self.theme)),
("dark_theme", self.dark_theme.as_ref()),
@@ -225,6 +233,15 @@ mod tests {
error.to_string(),
"scrollback is 100001, outside 0 to 100000"
);
let settings = Settings {
window_width: 50.0,
..Settings::default()
};
let error = settings.validate().expect_err("too narrow");
assert_eq!(
error.to_string(),
"window_width is 50, outside 100 to 16384"
);
}
#[test]