T65: on Windows 10 a blurred window's acrylic clears while it moves or sizes, which a user asked for in issue #3, where a drag trailed the pointer by seconds: below build 22000 the main window's procedure takes gpui's clear accent at WM_ENTERSIZEMOVE and its acrylic again at WM_EXITSIZEMOVE; Windows 11 keeps its acrylic

This commit is contained in:
ZacharyZhang-NY committed 2026-10-19 19:37:10 -04:00
1 parent d51823988e
commit 1384ef5dbe
6 files changed
+192 -6

No files matched your search

+3 -2
View File
@@ -9,7 +9,7 @@ ELYTerminal. A terminal on GPUI and Ely components. `PRD.md` says what it does;
- `alacritty_terminal` 0.26: grid, parser, pseudo-terminal, event loop. - `alacritty_terminal` 0.26: grid, parser, pseudo-terminal, event loop.
- `serde`, `serde_json`: settings. `dirs`: the config folder. `base64`, the version alacritty pulls in for OSC 52: OSC 7501's text. `log`, `env_logger`: logs to stderr. `unicode-normalization`, on macOS: Git's marks in composed form. - `serde`, `serde_json`: settings. `dirs`: the config folder. `base64`, the version alacritty pulls in for OSC 52: OSC 7501's text. `log`, `env_logger`: logs to stderr. `unicode-normalization`, on macOS: Git's marks in composed form.
- On Linux, `wayland-client`, `wayland-backend` and `wayland-protocols` (staging) ask the compositor for `ext_background_effect_v1` on gpui's own connection; `wayland-server` hosts a compositor in the tests. `x11rb` sets `_KDE_NET_WM_BLUR_BEHIND_REGION`; its test runs Xvfb. - On Linux, `wayland-client`, `wayland-backend` and `wayland-protocols` (staging) ask the compositor for `ext_background_effect_v1` on gpui's own connection; `wayland-server` hosts a compositor in the tests. `x11rb` sets `_KDE_NET_WM_BLUR_BEHIND_REGION`; its test runs Xvfb.
- On Windows, `sysinfo` reads herdr's client's arguments and variables; `windows-sys`, the version the Windows build already holds, lists processes, waits on herdr's pipe, reads the keyboard for win32-input-mode, and keeps Ely's window on the main one, which `raw-window-handle` finds. - On Windows, `sysinfo` reads herdr's client's arguments and variables; `windows-sys`, the version the Windows build already holds, lists processes, waits on herdr's pipe, reads the keyboard for win32-input-mode, keeps Ely's window on the main one, which `raw-window-handle` finds, and on Windows 10 reads the build and clears the main window's acrylic while it moves.
- `resvg`, a dev dependency at the version gpui uses, renders the icon's SVG for the macOS app and the Windows `.ico`. `embed-resource`, a build dependency at the version gpui uses, puts the icon into the Windows executable. - `resvg`, a dev dependency at the version gpui uses, renders the icon's SVG for the macOS app and the Windows `.ico`. `embed-resource`, a build dependency at the version gpui uses, puts the icon into the Windows executable.
## Commands ## Commands
@@ -34,7 +34,7 @@ ELYTerminal. A terminal on GPUI and Ely components. `PRD.md` says what it does;
## Layout ## Layout
- `build.rs`: on Windows, the icon into the executable as resource 1, through `assets/icons/elyterminal.rc`. `.cargo/config.toml`: Windows builds carry the C runtime. `rust-toolchain.toml`: the toolchain rustup installs. - `build.rs`: on Windows, the icon into the executable as resource 1, through `assets/icons/elyterminal.rc`. `.cargo/config.toml`: Windows builds carry the C runtime. `rust-toolchain.toml`: the toolchain rustup installs.
- `src/main.rs`: start. `src/lib.rs`: the modules, public so tests and examples reach them. `src/app.rs`: fonts, settings, integration, then the main window, at the size the settings keep, which it keeps as it settles. `src/menus.rs`: the menu bar, the keys of Quit, the font's size and Minimize, and what they do. `src/blur.rs`: what the window shows of the desktop, from the opacity and blur settings, set as they change; `blur/macos` gives gpui's NSVisualEffectView a material that blurs; `blur/wayland` asks a Wayland compositor for blur behind the window's surface through `ext_background_effect_v1`; `blur/x11` names the window's pane in `_KDE_NET_WM_BLUR_BEHIND_REGION`. `src/workspace.rs`: the window's content, Ely's `ColumnShell` with the sessions, terminal and right columns, their toggles, the right column's Git and Files switch, the title, and the sessions' lifecycle. `src/workspace/widths.rs`: the side columns' widths, which a drag on their border sets and the settings keep once it rests. `src/workspace/rename.rs`: a session renamed in place. `src/workspace/events.rs`: what a session's terminal reports: title, folder, bell, the state its row shows, the program's exit; and a press on a notification a session posted. `src/sessions.rs`: a session and its row, with the mark of its status and what hover shows of it; `sessions/orb` draws the mark, 3 by 3 dots on one clock. `src/files.rs`: the Files panel, the shown session's folder as Ely's `Tree` with Git's marks. `src/git.rs`: git through its command line: Files' marks, and the Git panel's status, stage, unstage, discard, commit and log; `src/git/diff.rs` reads git's diff into Ely's stretches. `src/git/panel.rs`: the Git panel's state and actions; `src/git/panel/view.rs`: how it draws. `src/updates.rs`: checks for a newer release through `curl` and Gitea's API, at start and once a day while the settings ask, and when Settings › Terminal asks. - `src/main.rs`: start. `src/lib.rs`: the modules, public so tests and examples reach them. `src/app.rs`: fonts, settings, integration, then the main window, at the size the settings keep, which it keeps as it settles. `src/menus.rs`: the menu bar, the keys of Quit, the font's size and Minimize, and what they do. `src/blur.rs`: what the window shows of the desktop, from the opacity and blur settings, set as they change; `blur/macos` gives gpui's NSVisualEffectView a material that blurs; `blur/wayland` asks a Wayland compositor for blur behind the window's surface through `ext_background_effect_v1`; `blur/x11` names the window's pane in `_KDE_NET_WM_BLUR_BEHIND_REGION`. `blur/windows`, on Windows 10, clears a blurred window's acrylic while it moves or sizes. `src/workspace.rs`: the window's content, Ely's `ColumnShell` with the sessions, terminal and right columns, their toggles, the right column's Git and Files switch, the title, and the sessions' lifecycle. `src/workspace/widths.rs`: the side columns' widths, which a drag on their border sets and the settings keep once it rests. `src/workspace/rename.rs`: a session renamed in place. `src/workspace/events.rs`: what a session's terminal reports: title, folder, bell, the state its row shows, the program's exit; and a press on a notification a session posted. `src/sessions.rs`: a session and its row, with the mark of its status and what hover shows of it; `sessions/orb` draws the mark, 3 by 3 dots on one clock. `src/files.rs`: the Files panel, the shown session's folder as Ely's `Tree` with Git's marks. `src/git.rs`: git through its command line: Files' marks, and the Git panel's status, stage, unstage, discard, commit and log; `src/git/diff.rs` reads git's diff into Ely's stretches. `src/git/panel.rs`: the Git panel's state and actions; `src/git/panel/view.rs`: how it draws. `src/updates.rs`: checks for a newer release through `curl` and Gitea's API, at start and once a day while the settings ask, and when Settings › Terminal asks.
- `src/pet.rs`: Ely, peeking over the main window's top edge from a window of her own while the settings want her, or up from its bottom edge where no room lies above it; she draws at every frame the display gives her window; `pet/rig` draws her from the icon's paths in layers of one color, each moved by a matrix of its own, as the films rig her; `pet/look` reads her mood from the sessions' marks and her pose at each moment of it, `look/curves` the timings of her moves; and `pet/macos`, `pet/windows` and `pet/x11` keep her window on the main window's edge where the platform does not. - `src/pet.rs`: Ely, peeking over the main window's top edge from a window of her own while the settings want her, or up from its bottom edge where no room lies above it; she draws at every frame the display gives her window; `pet/rig` draws her from the icon's paths in layers of one color, each moved by a matrix of its own, as the films rig her; `pet/look` reads her mood from the sessions' marks and her pose at each moment of it, `look/curves` the timings of her moves; and `pet/macos`, `pet/windows` and `pet/x11` keep her window on the main window's edge where the platform does not.
- `src/settings`: the model, its ranges, and `SettingsStore`, the global that loads, checks and saves `settings.json`; `window` is the settings window, `window/appearance` its Appearance page, `window/terminal` its Terminal page. `tests/fonts.rs` brings its own main: gpui builds its Mac platform only on the main thread. - `src/settings`: the model, its ranges, and `SettingsStore`, the global that loads, checks and saves `settings.json`; `window` is the settings window, `window/appearance` its Appearance page, `window/terminal` its Terminal page. `tests/fonts.rs` brings its own main: gpui builds its Mac platform only on the main thread.
- `src/themes`: built-in terminal themes, the chrome palette each maps to, and `apply`, which dresses the app for the system's appearance; `omarchy`, on Linux, wears Omarchy 4's current theme and follows its switches. - `src/themes`: built-in terminal themes, the chrome palette each maps to, and `apply`, which dresses the app for the system's appearance; `omarchy`, on Linux, wears Omarchy 4's current theme and follows its switches.
@@ -121,3 +121,4 @@ ELYTerminal. A terminal on GPUI and Ely components. `PRD.md` says what it does;
- 2026-10-19: a user found the IME's candidate box jumping on Windows after 0.1.6. gpui places it, through `ImmSetCompositionWindow` and `ImmSetCandidateWindow`, only when a composition starts, at the caret the terminal reports, the grid cursor's cell from the last frame, hidden or not. On the owner's PC, WeType under powershell.exe and under a status line redrawn every 100 ms put the box at the caret in 23 compositions out of 23, so the owner closed it unreproduced. The terminal logs each caret the input method asks for, at debug, and each move of the caret, at trace, so the next report carries where the box was told to go. - 2026-10-19: a user found the IME's candidate box jumping on Windows after 0.1.6. gpui places it, through `ImmSetCompositionWindow` and `ImmSetCandidateWindow`, only when a composition starts, at the caret the terminal reports, the grid cursor's cell from the last frame, hidden or not. On the owner's PC, WeType under powershell.exe and under a status line redrawn every 100 ms put the box at the caret in 23 compositions out of 23, so the owner closed it unreproduced. The terminal logs each caret the input method asks for, at debug, and each move of the caret, at trace, so the next report carries where the box was told to go.
- 2026-10-19: Ely's shirt and back hair run on below the edge she holds, which a user asked for after 0.1.6, where a hop lifted her whole figure off the window and showed a gap under her collar and hands: both continue down to 340 in the icon's units, 54 below the edge at 286, past her highest lift, a hop of 31 with a press's 0.6 of one on it, so a hop shows more of her and never the gap; at rest the part below the edge lies outside her window and does not show. The shirt moves with her body, the hair with her head, as before; the hair behind her hands fills under them as she lifts. - 2026-10-19: Ely's shirt and back hair run on below the edge she holds, which a user asked for after 0.1.6, where a hop lifted her whole figure off the window and showed a gap under her collar and hands: both continue down to 340 in the icon's units, 54 below the edge at 286, past her highest lift, a hop of 31 with a press's 0.6 of one on it, so a hop shows more of her and never the gap; at rest the part below the edge lies outside her window and does not show. The shirt moves with her body, the hair with her head, as before; the hair behind her hands fills under them as she lifts.
- 2026-10-19: a double press on a session's row renames it, which a user asked for after 0.1.6. Ely's `ListItem::editor`, added to Ely for this, draws Ely's text field in the title's place; the row's first press selects the session, as ever, and its second opens the field, holding what the session is called, selected, with the focus. Enter keeps what it holds, Escape drops it, and a blur keeps it, as Windows Terminal's tab rename does; whenever the field closes while it still holds the window's focus, the shown terminal takes it, and a press that took the focus elsewhere keeps it there. A window that goes inactive blurs the field and keeps its focus there, so a field closed by that blur, focus handed to nothing, left the terminal deaf to keys once the window came back. A press inside the open field stays the field's: the row would select its session, which takes the focus to the terminal and ends the rename. The name, its ends trimmed, stands over the program's title in the row, the terminal's header and the window's title until renamed again, a program's later titles passing under it; an empty one gives the title back to the program. It lives as long as the session, and notifications keep the program's title. Each program title, each rename and its end are logged. - 2026-10-19: a double press on a session's row renames it, which a user asked for after 0.1.6. Ely's `ListItem::editor`, added to Ely for this, draws Ely's text field in the title's place; the row's first press selects the session, as ever, and its second opens the field, holding what the session is called, selected, with the focus. Enter keeps what it holds, Escape drops it, and a blur keeps it, as Windows Terminal's tab rename does; whenever the field closes while it still holds the window's focus, the shown terminal takes it, and a press that took the focus elsewhere keeps it there. A window that goes inactive blurs the field and keeps its focus there, so a field closed by that blur, focus handed to nothing, left the terminal deaf to keys once the window came back. A press inside the open field stays the field's: the row would select its session, which takes the focus to the terminal and ends the rename. The name, its ends trimmed, stands over the program's title in the row, the terminal's header and the window's title until renamed again, a program's later titles passing under it; an empty one gives the title back to the program. It lives as long as the session, and notifications keep the program's title. Each program title, each rename and its end are logged.
- 2026-10-19: on Windows 10 a blurred window's acrylic clears while the window moves or sizes, which a user asked for in issue #3 after 0.1.5, where dragging the window trailed the pointer by seconds: that DWM samples the acrylic again at each step of the move loop, while gpui draws through it every 10 ms, so the moves pile up; Windows 11's DWM does not, and keeps its acrylic. At start `RtlGetVersion` reads the build; below 22000 the main window's procedure is ELYTerminal's own, passing every message on to gpui's: at `WM_ENTERSIZEMOVE` a blurred window takes the accent gpui gives Transparent, a clear gradient, and at `WM_EXITSIZEMOVE` gpui's acrylic again, `SWP_FRAMECHANGED` telling DWM, both through `SetWindowCompositionAttribute` as gpui calls it. A window property marks the window blurred, set as the blur setting changes, so an opaque or clear window moves as it is. The log names which way the build goes and each switch. On Windows 11, with the build check raised, a drag by the terminal's header logged both switches and showed the glass clear mid-drag and blurred at rest; Windows 10 itself went untested, the fix following the issue's own trial.
+1 -1
View File
@@ -61,7 +61,7 @@ image = { version = "0.25", default-features = false, features = ["png"] }
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
raw-window-handle = "0.6" raw-window-handle = "0.6"
sysinfo = { version = "0.39", default-features = false, features = ["system"] } sysinfo = { version = "0.39", default-features = false, features = ["system"] }
windows-sys = { version = "0.61", features = ["Win32_Foundation", "Win32_Graphics_Gdi", "Win32_Storage_FileSystem", "Win32_System_Console", "Win32_System_Diagnostics_ToolHelp", "Win32_System_Pipes", "Win32_UI_HiDpi", "Win32_UI_Input_KeyboardAndMouse", "Win32_UI_WindowsAndMessaging"] } windows-sys = { version = "0.61", features = ["Wdk_System_SystemServices", "Win32_Foundation", "Win32_Graphics_Gdi", "Win32_Storage_FileSystem", "Win32_System_Console", "Win32_System_Diagnostics_ToolHelp", "Win32_System_LibraryLoader", "Win32_System_Pipes", "Win32_System_SystemInformation", "Win32_UI_HiDpi", "Win32_UI_Input_KeyboardAndMouse", "Win32_UI_WindowsAndMessaging"] }
[target.'cfg(windows)'.dev-dependencies] [target.'cfg(windows)'.dev-dependencies]
windows-sys = { version = "0.61", features = ["Win32_Security", "Win32_System_IO"] } windows-sys = { version = "0.61", features = ["Win32_Security", "Win32_System_IO"] }
+1 -1
View File
@@ -129,7 +129,7 @@ Cmd-, opens it; on Windows and Linux, which have no menu bar, so does a gear in
## 11. Background blur ## 11. Background blur
- macOS: gpui's `WindowBackgroundAppearance::Blurred` (NSVisualEffectView). - macOS: gpui's `WindowBackgroundAppearance::Blurred` (NSVisualEffectView).
- Windows: gpui's `Blurred` (acrylic accent). - Windows: gpui's `Blurred` (acrylic accent). On Windows 10, whose DWM drags an acrylic window seconds behind the pointer, the glass clears while the window moves or sizes and blurs again when it rests; Windows 11 keeps its acrylic throughout.
- Wayland: gpui's `Blurred` speaks `org_kde_kwin_blur`; ELYTerminal adds `ext_background_effect_v1` on the window's surface, which GNOME 51, Plasma 6.7 and Hyprland support. Hyprland honors it only while its own blur is on, which Omarchy 4.0.4 turns off. - Wayland: gpui's `Blurred` speaks `org_kde_kwin_blur`; ELYTerminal adds `ext_background_effect_v1` on the window's surface, which GNOME 51, Plasma 6.7 and Hyprland support. Hyprland honors it only while its own blur is on, which Omarchy 4.0.4 turns off.
- X11: ELYTerminal sets `_KDE_NET_WM_BLUR_BEHIND_REGION` (CARDINAL, 32) on the window, as Ghostty does; removes it when blur turns off. - X11: ELYTerminal sets `_KDE_NET_WM_BLUR_BEHIND_REGION` (CARDINAL, 32) on the window, as Ghostty does; removes it when blur turns off.
- A compositor with neither protocol shows transparency without blur. The app logs which path it took. - A compositor with neither protocol shows transparency without blur. The app logs which path it took.
+19 -2
View File
@@ -6,6 +6,8 @@ use crate::settings::Settings;
mod macos; mod macos;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
mod wayland; mod wayland;
#[cfg(windows)]
mod windows;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
mod x11; mod x11;
@@ -27,6 +29,8 @@ pub struct Blur {
wayland: Option<wayland::Effect>, wayland: Option<wayland::Effect>,
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
x11: Option<x11::Effect>, x11: Option<x11::Effect>,
#[cfg(windows)]
moves: Option<windows::Moves>,
} }
impl Blur { impl Blur {
@@ -37,14 +41,23 @@ impl Blur {
if shown == WindowBackgroundAppearance::Blurred { if shown == WindowBackgroundAppearance::Blurred {
macos::blur(window); macos::blur(window);
} }
#[cfg(not(any(target_os = "linux", target_os = "macos")))] #[cfg(windows)]
let _ = window; let moves = windows::Moves::on(window).unwrap_or_else(|error| {
log::error!("{error:#}");
None
});
#[cfg(windows)]
if let Some(moves) = &moves {
moves.blurred(shown == WindowBackgroundAppearance::Blurred);
}
Self { Self {
shown, shown,
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
wayland: wayland::Effect::on(window), wayland: wayland::Effect::on(window),
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
x11: x11::Effect::on(window), x11: x11::Effect::on(window),
#[cfg(windows)]
moves,
} }
} }
@@ -66,6 +79,10 @@ impl Blur {
if wanted == WindowBackgroundAppearance::Blurred { if wanted == WindowBackgroundAppearance::Blurred {
macos::blur(window); macos::blur(window);
} }
#[cfg(windows)]
if let Some(moves) = &self.moves {
moves.blurred(wanted == WindowBackgroundAppearance::Blurred);
}
} }
/// Keeps a Linux compositor's blur on the window's pane while Blurred; each frame, sending only a change. /// Keeps a Linux compositor's blur on the window's pane while Blurred; each frame, sending only a change.
+167
View File
@@ -0,0 +1,167 @@
//! On Windows 10 a blurred window's acrylic clears while it moves or sizes: that DWM samples the blur again at each step, and the window trails the pointer by seconds.
use std::sync::atomic::{AtomicIsize, Ordering};
use anyhow::{Context as _, bail};
use gpui::Window;
use raw_window_handle::{HasWindowHandle, RawWindowHandle};
use windows_sys::{
Wdk::System::SystemServices::RtlGetVersion,
Win32::{
Foundation::{HWND, LPARAM, LRESULT, WPARAM},
System::{
LibraryLoader::{GetModuleHandleW, GetProcAddress},
SystemInformation::OSVERSIONINFOW,
},
UI::WindowsAndMessaging::{
CallWindowProcW, GWLP_WNDPROC, GetPropW, RemovePropW, SWP_FRAMECHANGED, SWP_NOACTIVATE,
SWP_NOMOVE, SWP_NOSIZE, SWP_NOZORDER, SetPropW, SetWindowLongPtrW, SetWindowPos,
WM_ENTERSIZEMOVE, WM_EXITSIZEMOVE, WM_NCDESTROY, WNDPROC,
},
},
core::{BOOL, PCWSTR},
s, w,
};
/// Windows 11's first build, whose DWM moves an acrylic window as fast as a clear one.
const ELEVEN: u32 = 22000;
/// gpui's window procedure, which the main windows' pass every message on to.
static GPUI: AtomicIsize = AtomicIsize::new(0);
/// A window's property while it is blurred, which its moves read.
const BLURRED: PCWSTR = w!("ElyTerminalBlurred");
/// gpui's accents: acrylic for Blurred, a clear gradient for Transparent.
const ACRYLIC: u32 = 4;
const CLEAR: u32 = 2;
/// A main window on Windows 10, whose moves clear its acrylic.
pub struct Moves {
window: HWND,
}
impl Moves {
/// Takes the window's moves on Windows 10; none on 11 and later.
pub fn on(window: &Window) -> anyhow::Result<Option<Self>> {
let build = build()?;
if build >= ELEVEN {
log::info!("blur: Windows build {build} moves acrylic as it is");
return Ok(None);
}
let window = native(window)?;
let gpui = unsafe { SetWindowLongPtrW(window, GWLP_WNDPROC, moving as *const () as isize) };
anyhow::ensure!(gpui != 0, "blur: the window's procedure does not read");
let kept = GPUI.swap(gpui, Ordering::Relaxed);
anyhow::ensure!(
kept == 0 || kept == gpui,
"blur: gpui's windows have two procedures"
);
log::info!("blur: on Windows build {build} acrylic clears while the window moves");
Ok(Some(Self { window }))
}
/// Notes whether the window is blurred, as its moves read it.
pub fn blurred(&self, on: bool) {
if on {
if unsafe { SetPropW(self.window, BLURRED, 1 as _) } == 0 {
log::error!("blur: the window's blurred mark does not set");
}
} else {
unsafe { RemovePropW(self.window, BLURRED) };
}
}
}
/// The window's procedure: a blurred window clears its acrylic while it moves; all else is gpui's.
unsafe extern "system" fn moving(
window: HWND,
message: u32,
wparam: WPARAM,
lparam: LPARAM,
) -> LRESULT {
let gpui: WNDPROC = unsafe { std::mem::transmute(GPUI.load(Ordering::Relaxed)) };
let blurred = !unsafe { GetPropW(window, BLURRED) }.is_null();
match message {
WM_ENTERSIZEMOVE if blurred => match accent(window, CLEAR) {
Ok(()) => log::debug!("blur: the window moves clear"),
Err(error) => log::error!("{error:#}"),
},
WM_EXITSIZEMOVE if blurred => {
match accent(window, ACRYLIC) {
Ok(()) => log::debug!("blur: the window rests blurred again"),
Err(error) => log::error!("{error:#}"),
}
let flags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED;
if unsafe { SetWindowPos(window, std::ptr::null_mut(), 0, 0, 0, 0, flags) } == 0 {
log::error!("blur: DWM hears of no new frame after the move");
}
}
WM_NCDESTROY => {
unsafe { RemovePropW(window, BLURRED) };
}
_ => {}
}
unsafe { CallWindowProcW(gpui, window, message, wparam, lparam) }
}
#[repr(C)]
struct AccentPolicy {
state: u32,
flags: u32,
color: u32,
animation: u32,
}
#[repr(C)]
struct CompositionData {
attribute: u32,
data: *mut AccentPolicy,
size: usize,
}
/// Sets the window's accent as gpui's `set_window_composition_attribute` sets it.
fn accent(window: HWND, state: u32) -> anyhow::Result<()> {
type Set = unsafe extern "system" fn(HWND, *mut CompositionData) -> BOOL;
let user32 = unsafe { GetModuleHandleW(w!("user32.dll")) };
anyhow::ensure!(!user32.is_null(), "blur: user32.dll is not loaded");
let found = unsafe { GetProcAddress(user32, s!("SetWindowCompositionAttribute")) }
.context("blur: user32.dll has no SetWindowCompositionAttribute")?;
let set: Set = unsafe { std::mem::transmute(found) };
let acrylic = state == ACRYLIC;
let mut policy = AccentPolicy {
state,
flags: if acrylic { 0 } else { 2 },
color: if acrylic { 1 << 24 } else { 0 },
animation: 0,
};
let mut data = CompositionData {
attribute: 0x13,
data: &mut policy,
size: size_of::<AccentPolicy>(),
};
anyhow::ensure!(
unsafe { set(window, &mut data) } != 0,
"blur: the window's accent {state} does not set"
);
Ok(())
}
/// The running Windows' build.
fn build() -> anyhow::Result<u32> {
let mut version: OSVERSIONINFOW = unsafe { std::mem::zeroed() };
version.dwOSVersionInfoSize = size_of::<OSVERSIONINFOW>() as u32;
let status = unsafe { RtlGetVersion(&mut version) };
anyhow::ensure!(status == 0, "blur: RtlGetVersion fails with {status:#x}");
Ok(version.dwBuildNumber)
}
/// The HWND gpui made for `window`.
fn native(window: &Window) -> anyhow::Result<HWND> {
let handle = HasWindowHandle::window_handle(window)
.map_err(|error| anyhow::anyhow!("blur: no native handle: {error:?}"))?;
let RawWindowHandle::Win32(win32) = handle.as_raw() else {
bail!("blur: not a Win32 window");
};
Ok(win32.hwnd.get() as HWND)
}
+1
View File
@@ -73,6 +73,7 @@ What no check reached: no real KWin drew the blur; of Wayland desktops, only Hyp
| OSC 8 and plain links on Cmd-press, Ctrl-press off macOS; inside herdr, herdr opens them whole | T09, T45 | `term::links` tests; on macOS with real herdr 0.9.5 and a stand-in `open` on its PATH, Cmd-press on a URL herdr wraps, on its wrapped tail, on an OSC 8 link and on a URL over three rows opened the whole URL and the OSC 8 target, where before the app opened `.../ELYTermin` and nothing; Cmd-hover underlined the long URL across its rows; outside herdr the app opened the URL itself; an OSC 8 link whose label holds `file:///etc/hosts` and whose target is a web page opened the page through herdr, which keeps the target from the terminal while it takes the mouse; Shift-Cmd-press on a plain `file:///etc/hosts` inside herdr the app opened itself, caught by an `NSWorkspace` stand-in | Pass | | OSC 8 and plain links on Cmd-press, Ctrl-press off macOS; inside herdr, herdr opens them whole | T09, T45 | `term::links` tests; on macOS with real herdr 0.9.5 and a stand-in `open` on its PATH, Cmd-press on a URL herdr wraps, on its wrapped tail, on an OSC 8 link and on a URL over three rows opened the whole URL and the OSC 8 target, where before the app opened `.../ELYTermin` and nothing; Cmd-hover underlined the long URL across its rows; outside herdr the app opened the URL itself; an OSC 8 link whose label holds `file:///etc/hosts` and whose target is a web page opened the page through herdr, which keeps the target from the terminal while it takes the mouse; Shift-Cmd-press on a plain `file:///etc/hosts` inside herdr the app opened itself, caught by an `NSWorkspace` stand-in | Pass |
| Focus reporting, title, scrollback limit, find | T10 | `term::find` tests; round 3 failed at the cap, its fix stands on a red-green test | Pass | | Focus reporting, title, scrollback limit, find | T10 | `term::find` tests; round 3 failed at the cap, its fix stands on a red-green test | Pass |
| A scrollbar over the history: a drag on its thumb scrolls, whatever the program does with the wheel | T58 | `term::scrollbar` test: the thumb's share and place follow the history and the view's offset, and a place past either end of the track holds at it; under Xorg's dummy screen, after `seq 1 500`, the thumb stood at the bottom right, a drag to the top showed the first prompt and lines 1 to 39, and one back down lines 220 to 259; with mouse tracking on, the wheel went to the program as reports and did not scroll, while a drag on the thumb showed lines 245 to 284 | Pass | | A scrollbar over the history: a drag on its thumb scrolls, whatever the program does with the wheel | T58 | `term::scrollbar` test: the thumb's share and place follow the history and the view's offset, and a place past either end of the track holds at it; under Xorg's dummy screen, after `seq 1 500`, the thumb stood at the bottom right, a drag to the top showed the first prompt and lines 1 to 39, and one back down lines 220 to 259; with mouse tracking on, the wheel went to the program as reports and did not scroll, while a drag on the thumb showed lines 245 to 284 | Pass |
| Windows 10: dragging a blurred window follows the pointer, its acrylic clear while it moves | T65 | on the owner's Windows 11 PC (build 26300) the release path logged `blur: Windows build 26300 moves acrylic as it is`; a probe build with the build check raised logged `acrylic clears while the window moves`, and a drag by the terminal's header moved the window 180 by 90 pixels, logged `the window moves clear` and `the window rests blurred again`, and pictured clear glass mid-drag and acrylic at rest; Windows 10 went untested | Pass |
| IME on Windows: the candidate box at the caret | T61 | on the owner's Windows 11 PC at 150%, WeType under powershell.exe: 23 compositions, on one line, on lines below, begun again at once after a commit, and under a status line redrawn every 100 ms, each logged `the input method asks for the caret` at the cursor's cell and drew the box under it; the user's jump did not reproduce and the owner closed it | Closed | | IME on Windows: the candidate box at the caret | T61 | on the owner's Windows 11 PC at 150%, WeType under powershell.exe: 23 compositions, on one line, on lines below, begun again at once after a commit, and under a status line redrawn every 100 ms, each logged `the input method asks for the caret` at the cursor's cell and drew the box under it; the user's jump did not reproduce and the owner closed it | Closed |
| Drop: files dropped on the terminal type their paths at the cursor, kept literal for the session's shell, each followed by a space | T66 | `term::drop` tests: a POSIX path escapes what a shell reads specially, spaces, quotes, parentheses, `&`, `$`, `^`, `~` and `#` among them, CJK kept, each path followed by a space; a PowerShell path is single-quoted with its quotes doubled, curly ones too; a cmd path is double-quoted, and one holding `%` types nothing; a path with a control character types nothing; `term::shell` test: zsh, fish and other shells take POSIX quoting, pwsh and powershell PowerShell's, cmd cmd's; round 1 of T66's review found Windows' quotes around a spaced path alone leaving `$(...)` and `;` live in PowerShell, and `^` unescaped under zsh's `extendedglob`: the formatter, extracted, typed 22 hard names that zsh with and without `extendedglob`, bash with `extglob`, fish and PowerShell each read back exactly, `it's`, `$HOME`, `$(1+1)`, `a;Write-Output(42)` and curly quotes among them, and cmd on the owner's PC echoed `&`, `|`, `<`, `>` and `^` inside its quotes back as text while it expanded `%PATH%`; round 2 found cmd's `/v:on` expanding `!` inside quotes, and `"C:\"` read by a program as one argument with the next: a `!` now stops a cmd drop, and the backslashes ending a path are doubled, so node, run from a cmd batch line on the owner's PC, received `C:\`, `D:\clip.mp4`, `C:\My Files\a&b^c.txt`, `C:\x|y<z>(1).txt`, `C:\dir with space\` and `C:\tmp\a;b,c=d.txt` exactly; on macOS `shot` dropped `/tmp/my file.png`, `/Users/x/it's (1).txt` and `/a/中文 b` on zsh after a pointer move, and the log read `3 paths dropped` and `pastes 53 characters, bracketed`; without the move, after typing, gpui passed the drop by, as AGENTS records | Pass | | Drop: files dropped on the terminal type their paths at the cursor, kept literal for the session's shell, each followed by a space | T66 | `term::drop` tests: a POSIX path escapes what a shell reads specially, spaces, quotes, parentheses, `&`, `$`, `^`, `~` and `#` among them, CJK kept, each path followed by a space; a PowerShell path is single-quoted with its quotes doubled, curly ones too; a cmd path is double-quoted, and one holding `%` types nothing; a path with a control character types nothing; `term::shell` test: zsh, fish and other shells take POSIX quoting, pwsh and powershell PowerShell's, cmd cmd's; round 1 of T66's review found Windows' quotes around a spaced path alone leaving `$(...)` and `;` live in PowerShell, and `^` unescaped under zsh's `extendedglob`: the formatter, extracted, typed 22 hard names that zsh with and without `extendedglob`, bash with `extglob`, fish and PowerShell each read back exactly, `it's`, `$HOME`, `$(1+1)`, `a;Write-Output(42)` and curly quotes among them, and cmd on the owner's PC echoed `&`, `|`, `<`, `>` and `^` inside its quotes back as text while it expanded `%PATH%`; round 2 found cmd's `/v:on` expanding `!` inside quotes, and `"C:\"` read by a program as one argument with the next: a `!` now stops a cmd drop, and the backslashes ending a path are doubled, so node, run from a cmd batch line on the owner's PC, received `C:\`, `D:\clip.mp4`, `C:\My Files\a&b^c.txt`, `C:\x|y<z>(1).txt`, `C:\dir with space\` and `C:\tmp\a;b,c=d.txt` exactly; on macOS `shot` dropped `/tmp/my file.png`, `/Users/x/it's (1).txt` and `/a/中文 b` on zsh after a pointer move, and the log read `3 paths dropped` and `pastes 53 characters, bracketed`; without the move, after typing, gpui passed the drop by, as AGENTS records | Pass |
| Click to move: a plain click on the line the shell reads, past its prompt, moves its cursor there, the press itself to a shell that takes clicks, else arrows | T59 | `term::marks` test: A's `click_events=1` and `2` read as a press at the screen's row or counted from the prompt; `term::click` tests: a shell that takes clicks hears an SGR left press at the clicked cell, a row below the prompt too, none before the prompt, in the history or on the alternate screen; B reads the line its prompt started; a click on the typed line counts the characters to it, left or right, past the end means the end, a wide character takes one arrow, soft-wrapped rows are one line, trailing spaces count up to the cursor, and a click on the prompt, another line, a line no prompt shows, output without marks or the alternate screen moves nothing; on macOS `shot` ran zsh with a marked prompt: after `echo hello` a click on the `h` logged `moves the cursor -5`, and `X` typed then ran `echo Xhello`; a drag sent nothing, and clicks on the prompt and on output logged `off the input`; round 1 of T59's review found fish 4.9 a code point per Left, so a count put `X` inside `é`, and its redraw dropped the wrap flag a count followed: with fish's own `click_events=1` the press goes to fish, which then typed `echo Xéabc`, and a second click on the redrawn wrapped line put `Y` at row 2, column 3; zsh still counted 4 arrows; a press let go in another cell and one whose program turned on tracking before the release sent nothing; round 2 found a click on fish's `$` sent to fish, which moved its cursor to the start: a press now goes only past the prompt's last cell before the cursor and never on a prompt cell, so clicks on `$` and its space logged `off the input` and `X` still ended `echo helloX`; round 3 found that a prompt whose only cells lie after the cursor, fish's empty left prompt beside a marked right one, crashed the press: with no prompt cell before the cursor the input starts at the prompt's first row, and a click on `o` there put `X` at `echXo`; round 3 found that a prompt that prints nothing left no cells to find the input by, so clicks on fish's typed line did nothing: B now stamps the typed line with a link of its own, numbered by the commands ended, so fish's empty prompt gave `abcXdef`, with a plain or no right prompt too, a click on the output above moved nothing, and fish's right prompt drawn again at each key kept the typed line's number, `echXo`; `term::prompts` test: input carries the commands ended before it, through a prompt drawn again; `term::click` tests: a prompt that prints nothing starts the input at its first typed cell, the output and the line run before refused; round 4 found the newest typed line taken by its place: after `printf '\e[H'` fish drew its prompt at the top over older lines, and a click on its typed line did nothing; the newest line is now the one of the highest number, and a press goes no lower than its last row or the cursor's, so that click gave `abcXdef`, the reviewer's scene sent `ESC[<0;6;1M`, and a click on the older text below moved nothing, where fish had moved its cursor | Pass | | Click to move: a plain click on the line the shell reads, past its prompt, moves its cursor there, the press itself to a shell that takes clicks, else arrows | T59 | `term::marks` test: A's `click_events=1` and `2` read as a press at the screen's row or counted from the prompt; `term::click` tests: a shell that takes clicks hears an SGR left press at the clicked cell, a row below the prompt too, none before the prompt, in the history or on the alternate screen; B reads the line its prompt started; a click on the typed line counts the characters to it, left or right, past the end means the end, a wide character takes one arrow, soft-wrapped rows are one line, trailing spaces count up to the cursor, and a click on the prompt, another line, a line no prompt shows, output without marks or the alternate screen moves nothing; on macOS `shot` ran zsh with a marked prompt: after `echo hello` a click on the `h` logged `moves the cursor -5`, and `X` typed then ran `echo Xhello`; a drag sent nothing, and clicks on the prompt and on output logged `off the input`; round 1 of T59's review found fish 4.9 a code point per Left, so a count put `X` inside `é`, and its redraw dropped the wrap flag a count followed: with fish's own `click_events=1` the press goes to fish, which then typed `echo Xéabc`, and a second click on the redrawn wrapped line put `Y` at row 2, column 3; zsh still counted 4 arrows; a press let go in another cell and one whose program turned on tracking before the release sent nothing; round 2 found a click on fish's `$` sent to fish, which moved its cursor to the start: a press now goes only past the prompt's last cell before the cursor and never on a prompt cell, so clicks on `$` and its space logged `off the input` and `X` still ended `echo helloX`; round 3 found that a prompt whose only cells lie after the cursor, fish's empty left prompt beside a marked right one, crashed the press: with no prompt cell before the cursor the input starts at the prompt's first row, and a click on `o` there put `X` at `echXo`; round 3 found that a prompt that prints nothing left no cells to find the input by, so clicks on fish's typed line did nothing: B now stamps the typed line with a link of its own, numbered by the commands ended, so fish's empty prompt gave `abcXdef`, with a plain or no right prompt too, a click on the output above moved nothing, and fish's right prompt drawn again at each key kept the typed line's number, `echXo`; `term::prompts` test: input carries the commands ended before it, through a prompt drawn again; `term::click` tests: a prompt that prints nothing starts the input at its first typed cell, the output and the line run before refused; round 4 found the newest typed line taken by its place: after `printf '\e[H'` fish drew its prompt at the top over older lines, and a click on its typed line did nothing; the newest line is now the one of the highest number, and a press goes no lower than its last row or the cursor's, so that click gave `abcXdef`, the reviewer's scene sent `ESC[<0;6;1M`, and a click on the older text below moved nothing, where fish had moved its cursor | Pass |