T19: the main window lets the desktop through while Background opacity is under 1, blurred or clear as Background blur says, set at open and as the settings change; Ely's new ColumnShell::glass grounds every column and the title bar in the palette's glass, which the opacity sets, and the Ely pin moves to it past 27 of Ely's own commits; dialogs stay solid; the terminal paints no second ground; shot names the window's AppKit views
CI / platforms (windows-latest) (push) Failing after 8s
CI / macos (push) Failing after 8m32s
CI / platforms (ubuntu-24.04) (push) Canceled after 0s

This commit is contained in:
ZacharyZhang-NY committed 2026-10-14 23:27:19 -04:00
1 parent d0162ef009
commit c98bbad6e0
11 files changed
+137 -28

No files matched your search

+11 -3
View File
@@ -10,6 +10,7 @@ use gpui::{
#[cfg(target_os = "macos")]
use crate::term::mac;
use crate::{
blur,
settings::{self, SettingsStore},
term::{ICONS, Launch, MONO, config, input, shell::ShellIntegration, spawn},
themes,
@@ -60,8 +61,10 @@ pub fn start(cx: &mut App) -> anyhow::Result<()> {
mac::deliver_command_key_ups()?;
}
themes::apply(cx);
let chosen =
|settings: &settings::Settings| (settings.theme.clone(), settings.dark_theme.clone());
let chosen = |settings: &settings::Settings| {
let theme = (settings.theme.clone(), settings.dark_theme.clone());
(theme, settings.background_opacity)
};
let mut worn = chosen(SettingsStore::get(cx));
cx.observe_global::<SettingsStore>(move |cx| {
let now = chosen(SettingsStore::get(cx));
@@ -77,6 +80,7 @@ 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 background = blur::appearance(SettingsStore::get(cx));
let options = WindowOptions {
window_bounds: Some(WindowBounds::Windowed(bounds)),
titlebar: Some(TitlebarOptions {
@@ -86,6 +90,7 @@ pub fn open(launch: Launch, cx: &mut App) -> anyhow::Result<WindowHandle<Workspa
}),
// Ely's columns draw the controls; only Linux reads this, and must not draw its own.
window_decorations: Some(WindowDecorations::Client),
window_background: background,
..Default::default()
};
let (pty, events) = spawn(&launch, (80, 24), (8, 16), config(SettingsStore::get(cx)))?;
@@ -95,6 +100,9 @@ pub fn open(launch: Launch, cx: &mut App) -> anyhow::Result<WindowHandle<Workspa
.detach();
cx.new(|cx| Workspace::new(pty, events, launch, window, cx))
})?;
log::info!("app: main window open");
log::info!(
"app: main window open, blur: {background:?} on {}",
std::env::consts::OS
);
Ok(window)
}
+46
View File
@@ -0,0 +1,46 @@
use gpui::{Window, WindowBackgroundAppearance};
use crate::settings::Settings;
/// What the window shows of the desktop: blurred or clear while the background lets it through.
pub fn appearance(settings: &Settings) -> WindowBackgroundAppearance {
if settings.background_opacity >= 1.0 {
WindowBackgroundAppearance::Opaque
} else if settings.background_blur {
WindowBackgroundAppearance::Blurred
} else {
WindowBackgroundAppearance::Transparent
}
}
/// Sets `window` to what the settings ask when it differs from `shown`; logs the way taken.
pub fn follow(window: &Window, shown: &mut WindowBackgroundAppearance, settings: &Settings) {
let wanted = appearance(settings);
if wanted != *shown {
*shown = wanted;
window.set_background_appearance(wanted);
log::info!("blur: the window is {wanted:?} on {}", std::env::consts::OS);
}
}
#[cfg(test)]
mod tests {
use gpui::WindowBackgroundAppearance::{Blurred, Opaque, Transparent};
use super::*;
#[test]
fn the_desktop_shows_only_through_a_background_it_can_pass() {
let at = |opacity, blur| {
appearance(&Settings {
background_opacity: opacity,
background_blur: blur,
..Settings::default()
})
};
assert_eq!(at(1.0, true), Opaque);
assert_eq!(at(1.0, false), Opaque);
assert_eq!(at(0.88, true), Blurred);
assert_eq!(at(0.3, false), Transparent);
}
}
+1
View File
@@ -1,4 +1,5 @@
pub mod app;
pub mod blur;
pub mod files;
pub mod git;
pub mod sessions;
+4 -1
View File
@@ -357,7 +357,10 @@ impl Render for TerminalView {
.size_full()
.px(px(settings.padding_x))
.py(px(settings.padding_y))
.bg(ink.bg.alpha(settings.background_opacity));
// The window's glass grounds the theme's background; a program's own paints over it.
.when(ink.bg != theme.background, |root| {
root.bg(ink.bg.alpha(settings.background_opacity))
});
let root = [MouseButton::Left, MouseButton::Middle, MouseButton::Right]
.into_iter()
.fold(root, |root, button| {
+17 -12
View File
@@ -4,20 +4,23 @@ use gpui::App;
use super::{TerminalTheme, active};
use crate::settings::SettingsStore;
/// The chrome's palette for a terminal theme; none for Ely's own, which Ely draws.
pub fn palette(theme: &TerminalTheme) -> Option<Palette> {
if theme.ely {
return None;
}
let (bg, fg, ansi) = (theme.background, theme.foreground, theme.ansi);
/// The chrome's palette for a terminal theme, its glass as see-through as the background; Ely's own keep Ely's colors.
pub fn palette(theme: &TerminalTheme, opacity: f32) -> Palette {
let base = if theme.is_dark() {
Palette::dark(false)
} else {
Palette::light(false)
};
if theme.ely {
return Palette {
glass: base.bg.alpha(opacity),
..base
};
}
let (bg, fg, ansi) = (theme.background, theme.foreground, theme.ansi);
let tint = |share: f32| bg.mix(&fg, share);
let wash = |color: gpui::Hsla| bg.mix(&color, 0.18);
Some(Palette {
Palette {
bg,
surface: bg,
sunken: tint(0.03),
@@ -44,7 +47,7 @@ pub fn palette(theme: &TerminalTheme) -> Option<Palette> {
warning_subtle: wash(ansi[3]),
danger_subtle: wash(ansi[1]),
info_subtle: wash(ansi[4]),
glass: bg.alpha(base.glass.a),
glass: bg.alpha(opacity),
tooltip_bg: tint(0.2),
tooltip_fg: fg,
chart: [
@@ -67,18 +70,20 @@ pub fn palette(theme: &TerminalTheme) -> Option<Palette> {
variable: fg,
},
..base
})
}
}
/// Dresses the app in the theme the settings choose for the system's appearance.
pub fn apply(cx: &mut App) {
let theme = active(SettingsStore::get(cx), cx.window_appearance());
let settings = SettingsStore::get(cx);
let theme = active(settings, cx.window_appearance());
let opacity = settings.background_opacity;
let mode = if theme.is_dark() {
Mode::Dark
} else {
Mode::Light
};
Theme::set_palette(mode, palette(theme), cx);
Theme::set_palette(mode, Some(palette(theme, opacity)), cx);
Theme::set_mode_now(mode, cx);
log::info!("theme: {} in {mode:?}", theme.id);
log::info!("theme: {} in {mode:?}, glass at {opacity}", theme.id);
}
+17 -3
View File
@@ -114,11 +114,25 @@ fn the_dark_theme_wins_only_in_dark_mode() {
#[test]
fn the_chrome_wears_the_theme() {
let dracula = find("dracula").expect("dracula");
let chrome = palette(dracula).expect("a mapped palette");
let chrome = palette(dracula, 1.0);
assert_eq!(chrome.bg, dracula.background);
assert_eq!(chrome.fg, dracula.foreground);
assert_eq!(chrome.ansi, dracula.ansi);
assert_eq!(chrome.danger, dracula.ansi[1]);
assert!(chrome.glass.a < 1.0);
assert!(palette(find("ely-dark").expect("ely")).is_none());
let ely = palette(find("ely-dark").expect("ely"), 1.0);
assert_eq!(ely.bg, Palette::dark(false).bg, "Ely's own colors");
}
#[test]
fn the_glass_lets_through_what_the_opacity_leaves() {
for id in ["dracula", "ely-light"] {
let theme = find(id).expect("a theme");
let chrome = palette(theme, 0.4);
assert_eq!(chrome.glass, chrome.bg.alpha(0.4), "{id}");
assert_eq!(
chrome.bg.a, 1.0,
"{id}: the ground under dialogs stays solid"
);
assert_eq!(palette(theme, 1.0).glass, chrome.bg, "{id}");
}
}
+11 -3
View File
@@ -9,10 +9,12 @@ use ely_gpui_component::{
use gpui::{
Action, App, AppContext, Context, Entity, EntityId, FocusHandle, Focusable, InteractiveElement,
IntoElement, KeyBinding, ParentElement, Render, SharedString, StatefulInteractiveElement,
StyleRefinement, Styled, Subscription, Window, actions, div, prelude::FluentBuilder,
StyleRefinement, Styled, Subscription, Window, WindowBackgroundAppearance, actions, div,
prelude::FluentBuilder,
};
use crate::{
blur,
files::Files,
git::panel::{Acted, GitPanel},
sessions::{self, Session},
@@ -84,6 +86,8 @@ pub struct Workspace {
active: usize,
files: Entity<Files>,
git: Entity<GitPanel>,
/// What the window shows of the desktop, as last set.
background: WindowBackgroundAppearance,
_settings: Subscription,
_acted: Subscription,
}
@@ -109,7 +113,11 @@ impl Workspace {
active: 0,
files: cx.new(|_| Files::new(launch.cwd.clone())),
git,
_settings: cx.observe_global::<SettingsStore>(|_, cx| cx.notify()),
background: blur::appearance(SettingsStore::get(cx)),
_settings: cx.observe_global_in::<SettingsStore>(window, |this, window, cx| {
blur::follow(window, &mut this.background, SettingsStore::get(cx));
cx.notify();
}),
_acted: acted,
};
workspace.add(pty, events, launch, window, cx);
@@ -316,7 +324,7 @@ impl Render for Workspace {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let settings = SettingsStore::get(cx);
let width = cx.theme().sidebar_width(false);
let mut shell = ColumnShell::new("workspace");
let mut shell = ColumnShell::new("workspace").glass();
if settings.show_sessions {
let (workspace, home) = (cx.entity(), dirs::home_dir());
let rows = self.sessions.iter().enumerate().map(|(index, session)| {