T55: a drag moves Ely along the edge she stands on, which the owner asked for after 0.1.5: on macOS, Windows and X11 her window follows the pointer's place on the screen, on Wayland her popup opens again where she is let go; she moves by whole points inside the pane, and the settings keep where she stands as ely_left, 140 by default
CI / platforms (ubuntu-24.04) (push) Successful in 1m11s
CI / platforms (windows-latest) (push) Successful in 1m33s
CI / macos (push) Canceled after 11m8s

This commit is contained in:
ZacharyZhang-NY committed 2026-10-19 10:30:19 -04:00
1 parent 3759cf8825
commit 17e91aafef
13 files changed
+181 -57

No files matched your search

+10 -4
View File
@@ -3,7 +3,7 @@
use anyhow::bail;
use gpui::Window;
use objc::{
msg_send,
class, msg_send,
runtime::{NO, Object, YES},
sel, sel_impl,
};
@@ -64,8 +64,8 @@ impl Glue {
Ok(Self { pet, main })
}
/// Stands her on the main window's top edge while her box fits under the top of its screen's visible frame, else on its bottom edge, as far in as its width allows, and gives the edge.
pub fn place(&self, _: &Window) -> anyhow::Result<Edge> {
/// Stands her on the main window's top edge while her box fits under the top of its screen's visible frame, else on its bottom edge, `at` in as far as its width allows, and gives the edge.
pub fn place(&self, _: &Window, at: f32) -> anyhow::Result<Edge> {
unsafe {
let frame: Rect = msg_send![self.main, frame];
let screen: *mut Object = msg_send![self.main, screen];
@@ -74,7 +74,7 @@ impl Glue {
let top = frame.origin.y + frame.height;
let edge = edge((visible.origin.y + visible.height - top) as f32);
let at = Point {
x: frame.origin.x + f64::from(left(gpui::px(frame.width as f32))),
x: frame.origin.x + f64::from(left(gpui::px(frame.width as f32), at)),
y: match edge {
Edge::Top => top,
Edge::Bottom => frame.origin.y,
@@ -84,6 +84,12 @@ impl Glue {
Ok(edge)
}
}
/// The pointer's x on the screen, in points.
pub fn pointer(&self, _: f32) -> anyhow::Result<f32> {
let at: Point = unsafe { msg_send![class!(NSEvent), mouseLocation] };
Ok(at.x as f32)
}
}
/// The NSWindow gpui made for `window`.
+12 -4
View File
@@ -1,5 +1,7 @@
use std::time::Duration;
use gpui::WindowId;
use super::{look::Mark, *};
/// Her, `mood` since `since`, come long before.
@@ -15,6 +17,9 @@ fn ely(mood: Mood, since: Instant) -> Pet {
eased: None,
edge: Edge::Top,
anchor: None,
at: 140.0,
drag: None,
main: WindowHandle::new(WindowId::from(1)),
glue: None,
_watch: Vec::new(),
}
@@ -98,11 +103,14 @@ fn she_stands_on_the_top_edge_while_her_box_fits_above_it() {
}
#[test]
fn she_holds_the_edge_of_any_pane() {
assert_eq!(left(px(1200.)), LEFT);
assert_eq!(left(px(200.)), 200.0 - WIDTH);
fn she_holds_the_edge_of_any_pane_where_a_drag_left_her() {
assert_eq!(left(px(1200.), 140.0), 140.0);
assert_eq!(left(px(1200.), 900.0), 900.0, "dragged right");
assert_eq!(left(px(1200.), 0.0), 0.0, "dragged to its left end");
assert_eq!(left(px(600.), 900.0), 600.0 - WIDTH, "a narrower pane");
assert_eq!(left(px(200.), 140.0), 200.0 - WIDTH);
assert_eq!(
left(px(100.)),
left(px(100.), 140.0),
0.0,
"narrower than she is, she stands at its left"
);
+20 -12
View File
@@ -9,14 +9,14 @@ use anyhow::bail;
use gpui::{Bounds, Pixels, Window};
use raw_window_handle::{HasWindowHandle, RawWindowHandle};
use windows_sys::Win32::{
Foundation::{HWND, LPARAM, LRESULT, RECT, WPARAM},
Foundation::{HWND, LPARAM, LRESULT, POINT, RECT, WPARAM},
Graphics::Gdi::{
GetMonitorInfoW, MONITOR_DEFAULTTONEAREST, MONITORINFO, MonitorFromRect, MonitorFromWindow,
},
UI::{
HiDpi::{GetDpiForMonitor, GetDpiForWindow, MDT_EFFECTIVE_DPI},
WindowsAndMessaging::{
CallWindowProcW, GWL_STYLE, GWLP_HWNDPARENT, GWLP_WNDPROC, GetWindowInfo,
CallWindowProcW, GWL_STYLE, GWLP_HWNDPARENT, GWLP_WNDPROC, GetCursorPos, 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_DPICHANGED, WM_MOUSEACTIVATE, WNDPROC,
@@ -77,13 +77,21 @@ impl Glue {
Ok(Self { pet, main })
}
/// Stands her on the main window's top edge while her box fits under the top of its display's work area, else on its bottom edge, as far in as its width allows, and gives the edge.
pub fn place(&self, main: &Window) -> anyhow::Result<Edge> {
self.put(main.scale_factor(), pane(main))
/// Stands her on the main window's top edge while her box fits under the top of its display's work area, else on its bottom edge, `at` in as far as its width allows, and gives the edge.
pub fn place(&self, main: &Window, at: f32) -> anyhow::Result<Edge> {
self.put(main.scale_factor(), pane(main), at)
}
/// Posts her bottom left corner on an edge of `pane` at `scale`, in the main window's points; her window sizes her at the DPI it has when the place lands, as gpui did not when it opened her off the display.
fn put(&self, scale: f32, pane: Bounds<Pixels>) -> anyhow::Result<Edge> {
/// The pointer's x on the screen, in points at `scale`.
pub fn pointer(&self, scale: f32) -> anyhow::Result<f32> {
let mut at = POINT::default();
let read = unsafe { GetCursorPos(&mut at) };
anyhow::ensure!(read != 0, "pet: the pointer's place does not read");
Ok(at.x as f32 / scale)
}
/// Posts her bottom left corner on an edge of `pane` at `scale`, `at` points in, in the main window's points; her window sizes her at the DPI it has when the place lands, as gpui did not when it opened her off the display.
fn put(&self, scale: f32, pane: Bounds<Pixels>, at: f32) -> anyhow::Result<Edge> {
let mut main = WINDOWINFO {
cbSize: size_of::<WINDOWINFO>() as u32,
..Default::default()
@@ -97,9 +105,9 @@ impl Glue {
let monitor = unsafe { MonitorFromWindow(self.main, MONITOR_DEFAULTTONEAREST) };
let read = unsafe { GetMonitorInfoW(monitor, &mut display) };
anyhow::ensure!(read != 0, "pet: the main window's display does not read");
let (_, top) = stand(main.rcClient, scale, pane, Edge::Top);
let (_, top) = stand(main.rcClient, scale, pane, Edge::Top, at);
let edge = edge((top - display.rcWork.top) as f32 / scale);
let corner = stand(main.rcClient, scale, pane, edge);
let corner = stand(main.rcClient, scale, pane, edge, at);
let posted = unsafe { PostMessageW(self.pet, PLACE, pack(corner), 0) };
anyhow::ensure!(posted != 0, "pet: her place does not post");
log::debug!("pet: Ely is to stand on {corner:?}, the pane's {edge:?} edge");
@@ -107,13 +115,13 @@ impl Glue {
}
}
/// Her bottom left corner on `edge` of `pane` at `scale` over the main window's `client` rect, in pixels.
fn stand(client: RECT, scale: f32, pane: Bounds<Pixels>, edge: Edge) -> (i32, i32) {
/// Her bottom left corner on `edge` of `pane`, `at` points in, at `scale` over the main window's `client` rect, in pixels.
fn stand(client: RECT, scale: f32, pane: Bounds<Pixels>, edge: Edge, at: f32) -> (i32, i32) {
let y = match edge {
Edge::Top => pane.origin.y,
Edge::Bottom => pane.bottom(),
};
let x = f32::from(pane.origin.x) + left(pane.size.width);
let x = f32::from(pane.origin.x) + left(pane.size.width, at);
(
client.left + (x * scale).round() as i32,
client.top + (f32::from(y) * scale).round() as i32,
+5 -5
View File
@@ -102,14 +102,14 @@ fn her_bottom_stands_on_either_edge_of_the_pane_whatever_the_two_windows_dpi() {
let pane = Bounds::new(point(px(10.), px(8.)), size(px(800.), px(600.)));
for (scale, dpi) in [(1.0, 96), (1.0, 144), (1.5, 96), (2.0, 120)] {
for (edge, y) in [(Edge::Top, 8.0), (Edge::Bottom, 608.0)] {
let her = boxed(stand(client, scale, pane, edge), dpi);
let her = boxed(stand(client, scale, pane, edge, 140.0), dpi);
let own = dpi as f32 / 96.0;
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,
100 + ((10.0 + left(px(800.), 140.0)) * scale).round() as i32,
20 + (y * scale).round() as i32,
);
assert_eq!(
@@ -272,7 +272,7 @@ fn the_large_framed_popup_gpui_makes_stands_bare_in_her_box_on_an_edge_of_the_pa
let work = work_area(main);
move_main(main, (work.left + 200, work.top + 400));
let pane = Bounds::new(point(px(0.), px(0.)), size(px(380.), px(280.)));
let roomy = glue.put(1.0, pane).expect("placed");
let roomy = glue.put(1.0, pane, 140.0).expect("placed");
let made = info(pet).rcWindow;
deliver(pet);
let (her, under) = (info(pet), info(main));
@@ -297,7 +297,7 @@ fn the_large_framed_popup_gpui_makes_stands_bare_in_her_box_on_an_edge_of_the_pa
let (suggested, taken, stood) = change(display + 48);
// At the work area's top the main window leaves her no room above it.
move_main(main, (work.left + 200, work.top));
let cramped = glue.put(1.0, pane).expect("placed again");
let cramped = glue.put(1.0, pane, 140.0).expect("placed again");
deliver(pet);
let (inside, low) = (info(pet).rcWindow, info(main).rcClient);
unsafe {
@@ -317,7 +317,7 @@ fn the_large_framed_popup_gpui_makes_stands_bare_in_her_box_on_an_edge_of_the_pa
((HEAD + ROOM) * own).round() as i32,
);
let edge = (
under.rcClient.left + left(px(380.)).round() as i32,
under.rcClient.left + left(px(380.), 140.0).round() as i32,
under.rcClient.top,
);
let rect = |rect: RECT| (rect.left, rect.top, rect.right, rect.bottom);
+20 -11
View File
@@ -49,20 +49,29 @@ impl Glue {
Ok(glue)
}
/// Stands her on the main window's pane, on its top edge while her box fits under the top of the monitor holding most of the pane, or of the work area where that lies lower, else on its bottom edge, as far in as its width allows, stacked just above the main window's frame, and gives the edge.
pub fn place(&self, main: &Window) -> anyhow::Result<Edge> {
self.put(main.scale_factor(), pane(main))
/// Stands her on the main window's pane, on its top edge while her box fits under the top of the monitor holding most of the pane, or of the work area where that lies lower, else on its bottom edge, `at` in as far as its width allows, stacked just above the main window's frame, and gives the edge.
pub fn place(&self, main: &Window, at: f32) -> anyhow::Result<Edge> {
self.put(main.scale_factor(), pane(main), at)
}
/// The pointer's x on the screen, in points at `scale`.
pub fn pointer(&self, scale: f32) -> anyhow::Result<f32> {
let reply = (self.connection)
.query_pointer(self.pet)?
.reply()
.context("pet: the pointer's place")?;
Ok(f32::from(reply.root_x) / scale)
}
/// Places her at `scale` on an edge of `pane`, in the main window's points.
fn put(&self, scale: f32, pane: Bounds<Pixels>) -> anyhow::Result<Edge> {
fn put(&self, scale: f32, pane: Bounds<Pixels>, at: f32) -> anyhow::Result<Edge> {
let (root, frame) = self.frame()?;
let at = (self.connection)
let origin = (self.connection)
.translate_coordinates(self.main, root, 0, 0)?
.reply()
.context("pet: the main window's place")?;
let down = |y: Pixels| i32::from(at.dst_y) + (f32::from(y) * scale).round() as i32;
let across = |x: Pixels| i32::from(at.dst_x) + (f32::from(x) * scale).round() as i32;
let down = |y: Pixels| i32::from(origin.dst_y) + (f32::from(y) * scale).round() as i32;
let across = |x: Pixels| i32::from(origin.dst_x) + (f32::from(x) * scale).round() as i32;
let (west, top) = (across(pane.origin.x), down(pane.origin.y));
let rect = [
west,
@@ -77,7 +86,7 @@ impl Glue {
Edge::Bottom => pane.bottom(),
});
let aux = ConfigureWindowAux::new()
.x(across(pane.origin.x + px(left(pane.size.width))))
.x(across(pane.origin.x + px(left(pane.size.width, at))))
.y(bottom - ((HEAD + ROOM) * scale).round() as i32)
.sibling(frame)
.stack_mode(StackMode::ABOVE);
@@ -269,7 +278,7 @@ mod tests {
workarea,
};
let pane = Bounds::new(point(px(10.), px(10.)), size(px(380.), px(280.)));
let roomy = glue.put(2.0, pane).expect("she is placed");
let roomy = glue.put(2.0, pane, 140.0).expect("she is placed");
let check = x11rb::connect(Some(&xvfb.display))
.expect("the check connects")
.0;
@@ -280,7 +289,7 @@ mod tests {
.expect("her place");
let tall = ((HEAD + ROOM) * 2.0).round() as i32;
let stands = (
100 + ((10.0 + left(px(380.))) * 2.0).round() as i32,
100 + ((10.0 + left(px(380.), 140.0)) * 2.0).round() as i32,
440 - tall,
);
assert_eq!(
@@ -322,7 +331,7 @@ mod tests {
.expect("the request")
.check()
.expect("a work area");
let cramped = glue.put(2.0, pane).expect("she is placed again");
let cramped = glue.put(2.0, pane, 140.0).expect("she is placed again");
let low = check
.get_geometry(pet)
.expect("the request")