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
This commit is contained in:
13 files changed
+181
-57
No files matched your search
+10
-4
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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")
|
||||
|
||||
Reference in new issue
Block a user