T48: round 1 fix: her height is her own DPI's and her bottom the pane's top whatever the two windows' DPI, where the main window's scale had put her 62 pixels into the terminal or above it; and when a move takes her to a display of another DPI, gpui takes the rect Windows suggests while she keeps her bottom left corner
CI / platforms (windows-latest) (push) Successful in 1m58s
CI / platforms (ubuntu-24.04) (push) Successful in 2m15s
CI / macos (push) Successful in 14m3s

This commit is contained in:
ZacharyZhang-NY committed 2026-10-18 12:55:30 -04:00
1 parent c1cdddf07e
commit 8ddf470f73
3 files changed
+136 -37

No files matched your search

+134 -35
View File
@@ -6,15 +6,15 @@ use anyhow::bail;
use gpui::{Bounds, Pixels, Window};
use raw_window_handle::{HasWindowHandle, RawWindowHandle};
use windows_sys::Win32::{
Foundation::{HWND, LPARAM, LRESULT, WPARAM},
Foundation::{HWND, LPARAM, LRESULT, RECT, WPARAM},
UI::{
HiDpi::GetDpiForWindow,
WindowsAndMessaging::{
CallWindowProcW, GWL_STYLE, GWLP_HWNDPARENT, GWLP_WNDPROC, GetWindowInfo,
GetWindowLongPtrW, HWND_NOTOPMOST, MA_NOACTIVATE, PostMessageW, SWP_FRAMECHANGED,
SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE, SWP_NOZORDER, SetWindowLongPtrW, SetWindowPos,
USER_DEFAULT_SCREEN_DPI, WINDOWINFO, WM_APP, WM_MOUSEACTIVATE, WNDPROC, WS_CAPTION,
WS_POPUP,
GetWindowLongPtrW, GetWindowRect, HWND_NOTOPMOST, MA_NOACTIVATE, PostMessageW,
SWP_FRAMECHANGED, SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE, SWP_NOZORDER,
SetWindowLongPtrW, SetWindowPos, USER_DEFAULT_SCREEN_DPI, WINDOWINFO, WM_APP,
WM_DPICHANGED, WM_MOUSEACTIVATE, WNDPROC, WS_CAPTION, WS_POPUP,
},
},
};
@@ -81,15 +81,7 @@ impl Glue {
anyhow::ensure!(dpi != 0, "pet: her window's DPI does not read");
anyhow::ensure!(read != 0, "pet: the main window's place does not read");
let own = dpi as f32 / USER_DEFAULT_SCREEN_DPI as f32;
let (x, y) = (f32::from(pane.origin.x), f32::from(pane.origin.y));
let at = (
main.rcClient.left + ((x + left(pane.size.width)) * scale).round() as i32,
main.rcClient.top + ((y - HEAD - ROOM) * scale).round() as i32,
);
let size = (
(WIDTH * own).round() as i32,
((HEAD + ROOM) * own).round() as i32,
);
let (at, size) = stand(main.rcClient, scale, own, pane);
let posted = unsafe { PostMessageW(self.pet, PLACE, pack(at), pack(size) as LPARAM) };
anyhow::ensure!(posted != 0, "pet: her place does not post");
log::debug!("pet: Ely is to stand at {at:?}, {size:?} pixels");
@@ -97,28 +89,64 @@ impl Glue {
}
}
/// Her window's procedure: a press does not activate her window; all else is gpui's.
/// Her box at `own` scale, its bottom on `pane` at `scale` over the main window's `client` rect: its place and size in pixels.
fn stand(client: RECT, scale: f32, own: f32, pane: Bounds<Pixels>) -> ((i32, i32), (i32, i32)) {
let size = (
(WIDTH * own).round() as i32,
((HEAD + ROOM) * own).round() as i32,
);
let (x, y) = (f32::from(pane.origin.x), f32::from(pane.origin.y));
let at = (
client.left + ((x + left(pane.size.width)) * scale).round() as i32,
client.top + (y * scale).round() as i32 - size.1,
);
(at, size)
}
/// Her window's procedure: a press does not activate her window, she takes her place, and at a new DPI keeps her corner; all else is gpui's.
unsafe extern "system" fn inactive(
window: HWND,
message: u32,
wparam: WPARAM,
lparam: LPARAM,
) -> LRESULT {
if message == WM_MOUSEACTIVATE {
return MA_NOACTIVATE as LRESULT;
}
if message == PLACE {
let ((x, y), (width, height)) = (unpack(wparam), unpack(lparam as WPARAM));
let flags = SWP_NOZORDER | SWP_NOACTIVATE;
let moved =
unsafe { SetWindowPos(window, std::ptr::null_mut(), x, y, width, height, flags) };
if moved == 0 {
log::error!("pet: her window does not move to {x},{y}");
}
return 0;
}
let gpui: WNDPROC = unsafe { std::mem::transmute(GPUI.load(Ordering::Relaxed)) };
unsafe { CallWindowProcW(gpui, window, message, wparam, lparam) }
match message {
WM_MOUSEACTIVATE => MA_NOACTIVATE as LRESULT,
PLACE => {
let ((x, y), (width, height)) = (unpack(wparam), unpack(lparam as WPARAM));
let flags = SWP_NOZORDER | SWP_NOACTIVATE;
let null = std::ptr::null_mut();
if unsafe { SetWindowPos(window, null, x, y, width, height, flags) } == 0 {
log::error!("pet: her window does not move to {x},{y}");
}
0
}
WM_DPICHANGED => {
// gpui takes the rect Windows suggests, as a move to another display brings.
let (mut before, mut after) = (RECT::default(), RECT::default());
let read = unsafe { GetWindowRect(window, &mut before) };
let answer = unsafe { CallWindowProcW(gpui, window, message, wparam, lparam) };
if read == 0 || unsafe { GetWindowRect(window, &mut after) } == 0 {
log::error!("pet: her window's place does not read at a new DPI");
return answer;
}
let top = before.bottom - (after.bottom - after.top);
let flags = SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE;
let null = std::ptr::null_mut();
if unsafe { SetWindowPos(window, null, before.left, top, 0, 0, flags) } == 0 {
log::error!("pet: her window does not keep its corner at a new DPI");
} else {
log::debug!(
"pet: at a new DPI Ely keeps her corner at {},{}",
before.left,
before.bottom
);
}
answer
}
_ => unsafe { CallWindowProcW(gpui, window, message, wparam, lparam) },
}
}
fn pack((low, high): (i32, i32)) -> WPARAM {
@@ -144,8 +172,9 @@ mod tests {
use gpui::{point, px, size};
use windows_sys::{
Win32::UI::WindowsAndMessaging::{
CW_USEDEFAULT, CreateWindowExW, DestroyWindow, DispatchMessageW, MSG, PM_REMOVE,
PeekMessageW, WS_EX_TOOLWINDOW, WS_EX_TOPMOST, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW, MSG,
PM_REMOVE, PeekMessageW, SendMessageW, WS_EX_TOOLWINDOW, WS_EX_TOPMOST,
WS_OVERLAPPEDWINDOW,
},
w,
};
@@ -183,6 +212,51 @@ mod tests {
info
}
/// gpui's procedure as far as these tests need it: at a new DPI it takes the rect Windows suggests.
unsafe extern "system" fn standin(
window: HWND,
message: u32,
wparam: WPARAM,
lparam: LPARAM,
) -> LRESULT {
if message == WM_DPICHANGED {
let rect = unsafe { *(lparam as *const RECT) };
let (width, height) = (rect.right - rect.left, rect.bottom - rect.top);
let flags = SWP_NOZORDER | SWP_NOACTIVATE;
let null = std::ptr::null_mut();
unsafe { SetWindowPos(window, null, rect.left, rect.top, width, height, flags) };
return 0;
}
unsafe { DefWindowProcW(window, message, wparam, lparam) }
}
#[test]
fn her_bottom_stands_on_the_panes_top_edge_whatever_the_two_windows_dpi() {
let client = RECT {
left: 100,
top: 20,
right: 1300,
bottom: 900,
};
let pane = Bounds::new(point(px(10.), px(8.)), size(px(800.), px(600.)));
for (scale, own) in [(1.0, 1.0), (1.0, 1.5), (1.5, 1.0), (2.0, 1.25)] {
let ((x, y), (width, height)) = stand(client, scale, own, pane);
let own_box = (
(WIDTH * own).round() as i32,
((HEAD + ROOM) * own).round() as i32,
);
let corner = (
100 + ((10.0 + left(px(800.))) * scale).round() as i32,
20 + (8.0 * scale).round() as i32,
);
assert_eq!(
((width, height), (x, y + height)),
(own_box, corner),
"the main window at {scale}, hers at {own}"
);
}
}
#[test]
fn the_large_framed_popup_gpui_makes_stands_bare_in_her_box_on_the_panes_top_edge() {
let main = window(WS_OVERLAPPEDWINDOW, 0);
@@ -193,6 +267,7 @@ mod tests {
WS_CAPTION,
"framed as gpui makes it"
);
unsafe { SetWindowLongPtrW(pet, GWLP_WNDPROC, standin as *const () as isize) };
let glue = Glue::hold(pet, main).expect("held");
let pane = Bounds::new(point(px(0.), px(0.)), size(px(380.), px(280.)));
glue.put(1.0, pane).expect("placed");
@@ -203,6 +278,17 @@ mod tests {
}
let (her, under) = (info(pet), info(main));
let own = unsafe { GetDpiForWindow(pet) } as f32 / 96.0;
// A new DPI, whose rect Windows suggests 30 and 40 pixels off, 100 by 60.
let at = her.rcWindow;
let suggested = RECT {
left: at.left + 30,
top: at.top + 40,
right: at.left + 130,
bottom: at.top + 100,
};
let pointer = &suggested as *const RECT as LPARAM;
unsafe { SendMessageW(pet, WM_DPICHANGED, 144 | 144 << 16, pointer) };
let later = info(pet).rcWindow;
unsafe {
DestroyWindow(pet);
DestroyWindow(main);
@@ -221,17 +307,30 @@ mod tests {
);
let edge = (
under.rcClient.left + left(px(380.)).round() as i32,
under.rcClient.top + (-HEAD - ROOM).round() as i32,
under.rcClient.top,
);
let kept = (
later.left,
later.bottom,
later.right - later.left,
later.bottom - later.top,
);
assert_eq!(
(
her.dwStyle & WS_CAPTION,
frame,
drawn,
(outer.left, outer.top)
(outer.left, outer.bottom),
kept
),
(0, (0, 0, 0, 0), own_box, edge),
"bare, in her own box, on the pane's top edge"
(
0,
(0, 0, 0, 0),
own_box,
edge,
(outer.left, outer.bottom, 100, 60)
),
"bare, in her own box, her bottom on the pane's top edge, kept there at a new DPI"
);
assert_ne!(
(made.right - made.left, made.bottom - made.top),