T46: round 1 fixes: Ely's window never takes the keys, a panel key only if needed on macOS and on Windows a window that answers a press's activation with none; she opens with the sessions' mood; she stands 140 points in or less on a narrow pane, so she holds its edge at any width, and on Wayland, whose popup keeps the place it opened at, she opens again when a new width moves her
This commit is contained in:
7 files changed
+165
-70
No files matched your search
+6
-5
@@ -4,12 +4,12 @@ use anyhow::bail;
|
||||
use gpui::Window;
|
||||
use objc::{
|
||||
msg_send,
|
||||
runtime::{NO, Object},
|
||||
runtime::{NO, Object, YES},
|
||||
sel, sel_impl,
|
||||
};
|
||||
use raw_window_handle::{HasWindowHandle, RawWindowHandle};
|
||||
|
||||
use super::LEFT;
|
||||
use super::left;
|
||||
|
||||
/// AppKit's `NSWindowAbove`.
|
||||
const ABOVE: isize = 1;
|
||||
@@ -36,7 +36,7 @@ pub struct Glue {
|
||||
}
|
||||
|
||||
impl Glue {
|
||||
/// Makes her window the main window's child, at its level and in its Spaces, with no shadow.
|
||||
/// Makes her window the main window's child, at its level and in its Spaces, with no shadow and never key, so a press leaves the keys with the terminal.
|
||||
pub fn new(pet: &Window, main: &Window) -> anyhow::Result<Self> {
|
||||
let (pet, main) = (native(pet)?, native(main)?);
|
||||
unsafe {
|
||||
@@ -45,17 +45,18 @@ impl Glue {
|
||||
let spaces: usize = msg_send![main, collectionBehavior];
|
||||
let _: () = msg_send![pet, setCollectionBehavior: spaces];
|
||||
let _: () = msg_send![pet, setHasShadow: NO];
|
||||
let _: () = msg_send![pet, setBecomesKeyOnlyIfNeeded: YES];
|
||||
let _: () = msg_send![main, addChildWindow: pet ordered: ABOVE];
|
||||
}
|
||||
Ok(Self { pet, main })
|
||||
}
|
||||
|
||||
/// Stands her on the main window's top edge, `LEFT` points in from its left.
|
||||
/// Stands her on the main window's top edge, as far in as its width allows.
|
||||
pub fn place(&self, _: &Window) -> anyhow::Result<()> {
|
||||
unsafe {
|
||||
let frame: Rect = msg_send![self.main, frame];
|
||||
let at = Point {
|
||||
x: frame.origin.x + f64::from(LEFT),
|
||||
x: frame.origin.x + f64::from(left(gpui::px(frame.width as f32))),
|
||||
y: frame.origin.y + frame.height,
|
||||
};
|
||||
let _: () = msg_send![self.pet, setFrameOrigin: at];
|
||||
|
||||
+32
-8
@@ -1,17 +1,23 @@
|
||||
//! Ely's window on Windows: owned by the main window, so it stays above it and hides with it, and moved as it moves.
|
||||
|
||||
use std::sync::atomic::{AtomicIsize, Ordering};
|
||||
|
||||
use anyhow::bail;
|
||||
use gpui::Window;
|
||||
use gpui::{Window, px};
|
||||
use raw_window_handle::{HasWindowHandle, RawWindowHandle};
|
||||
use windows_sys::Win32::{
|
||||
Foundation::{HWND, RECT},
|
||||
Foundation::{HWND, LPARAM, LRESULT, RECT, WPARAM},
|
||||
UI::WindowsAndMessaging::{
|
||||
GWLP_HWNDPARENT, GetWindowRect, HWND_NOTOPMOST, SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE,
|
||||
SWP_NOZORDER, SetWindowLongPtrW, SetWindowPos,
|
||||
CallWindowProcW, GWLP_HWNDPARENT, GWLP_WNDPROC, GetWindowRect, HWND_NOTOPMOST,
|
||||
MA_NOACTIVATE, SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE, SWP_NOZORDER, SetWindowLongPtrW,
|
||||
SetWindowPos, WM_MOUSEACTIVATE, WNDPROC,
|
||||
},
|
||||
};
|
||||
|
||||
use super::{HEAD, LEFT, ROOM};
|
||||
use super::{HEAD, ROOM, left};
|
||||
|
||||
/// gpui's window procedure, which hers passes every message on to but a press's activation.
|
||||
static GPUI: AtomicIsize = AtomicIsize::new(0);
|
||||
|
||||
/// Her window and the main one.
|
||||
pub struct Glue {
|
||||
@@ -20,11 +26,14 @@ pub struct Glue {
|
||||
}
|
||||
|
||||
impl Glue {
|
||||
/// Gives her window the main window as owner, and takes away the topmost place gpui gives a popup.
|
||||
/// Gives her window the main window as owner, takes away the topmost place gpui gives a popup, and keeps a press from activating it, so the keys stay with the terminal.
|
||||
pub fn new(pet: &Window, main: &Window) -> anyhow::Result<Self> {
|
||||
let (pet, main) = (native(pet)?, native(main)?);
|
||||
unsafe {
|
||||
SetWindowLongPtrW(pet, GWLP_HWNDPARENT, main as isize);
|
||||
let gpui = SetWindowLongPtrW(pet, GWLP_WNDPROC, inactive as *const () as isize);
|
||||
anyhow::ensure!(gpui != 0, "pet: her window's procedure does not read");
|
||||
GPUI.store(gpui, Ordering::Relaxed);
|
||||
let flags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE;
|
||||
anyhow::ensure!(
|
||||
SetWindowPos(pet, HWND_NOTOPMOST, 0, 0, 0, 0, flags) != 0,
|
||||
@@ -34,7 +43,7 @@ impl Glue {
|
||||
Ok(Self { pet, main })
|
||||
}
|
||||
|
||||
/// Stands her on the main window's top edge, `LEFT` points in from its left.
|
||||
/// Stands her on the main window's top edge, as far in as its width allows.
|
||||
pub fn place(&self, main: &Window) -> anyhow::Result<()> {
|
||||
let scale = main.scale_factor();
|
||||
let mut frame = RECT::default();
|
||||
@@ -43,7 +52,8 @@ impl Glue {
|
||||
GetWindowRect(self.main, &mut frame) != 0,
|
||||
"pet: the main window's place does not read"
|
||||
);
|
||||
let x = frame.left + (LEFT * scale).round() as i32;
|
||||
let width = px((frame.right - frame.left) as f32 / scale);
|
||||
let x = frame.left + (left(width) * scale).round() as i32;
|
||||
let y = frame.top - ((HEAD + ROOM) * scale).round() as i32;
|
||||
let flags = SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE;
|
||||
anyhow::ensure!(
|
||||
@@ -55,6 +65,20 @@ impl Glue {
|
||||
}
|
||||
}
|
||||
|
||||
/// Her window's procedure: a press does not activate her window; 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;
|
||||
}
|
||||
let gpui: WNDPROC = unsafe { std::mem::transmute(GPUI.load(Ordering::Relaxed)) };
|
||||
unsafe { CallWindowProcW(gpui, window, message, wparam, lparam) }
|
||||
}
|
||||
|
||||
/// The HWND gpui made for `window`.
|
||||
fn native(window: &Window) -> anyhow::Result<HWND> {
|
||||
let handle = HasWindowHandle::window_handle(window)
|
||||
|
||||
+16
-12
@@ -1,14 +1,14 @@
|
||||
//! Ely's window on X11: gpui's popup, which no window manager places, put on the main window's top edge and just above it.
|
||||
|
||||
use anyhow::{Context as _, bail};
|
||||
use gpui::Window;
|
||||
use gpui::{Bounds, Pixels, Window};
|
||||
use raw_window_handle::{HasWindowHandle, RawWindowHandle};
|
||||
use x11rb::{
|
||||
protocol::xproto::{ConfigureWindowAux, ConnectionExt as _, StackMode},
|
||||
rust_connection::RustConnection,
|
||||
};
|
||||
|
||||
use super::{HEAD, LEFT, ROOM, top_inset};
|
||||
use super::{HEAD, ROOM, left, pane};
|
||||
|
||||
/// Her X window, the main one, and a connection of her own to their server.
|
||||
pub struct Glue {
|
||||
@@ -29,21 +29,22 @@ impl Glue {
|
||||
})
|
||||
}
|
||||
|
||||
/// Stands her on the main window's pane, `LEFT` points in, stacked just above the main window's frame.
|
||||
/// Stands her on the main window's pane, as far in as its width allows, stacked just above the main window's frame.
|
||||
pub fn place(&self, main: &Window) -> anyhow::Result<()> {
|
||||
self.put(main.scale_factor(), f32::from(top_inset(main)))
|
||||
self.put(main.scale_factor(), pane(main))
|
||||
}
|
||||
|
||||
/// Places her at `scale` over a pane `inset` points into the main window.
|
||||
fn put(&self, scale: f32, inset: f32) -> anyhow::Result<()> {
|
||||
/// Places her at `scale` over `pane`, in the main window's points.
|
||||
fn put(&self, scale: f32, pane: Bounds<Pixels>) -> anyhow::Result<()> {
|
||||
let (x, y) = (f32::from(pane.origin.x), f32::from(pane.origin.y));
|
||||
let (root, frame) = self.frame()?;
|
||||
let at = (self.connection)
|
||||
.translate_coordinates(self.main, root, 0, 0)?
|
||||
.reply()
|
||||
.context("pet: the main window's place")?;
|
||||
let aux = ConfigureWindowAux::new()
|
||||
.x(i32::from(at.dst_x) + ((LEFT + inset) * scale).round() as i32)
|
||||
.y(i32::from(at.dst_y) + ((inset - HEAD - ROOM) * scale).round() as i32)
|
||||
.x(i32::from(at.dst_x) + ((x + left(pane.size.width)) * scale).round() as i32)
|
||||
.y(i32::from(at.dst_y) + ((y - HEAD - ROOM) * scale).round() as i32)
|
||||
.sibling(frame)
|
||||
.stack_mode(StackMode::ABOVE);
|
||||
(self.connection)
|
||||
@@ -95,6 +96,8 @@ mod tests {
|
||||
protocol::xproto::{CreateWindowAux, MapState, WindowClass},
|
||||
};
|
||||
|
||||
use gpui::{point, px, size};
|
||||
|
||||
use super::*;
|
||||
use crate::testx11::Xvfb;
|
||||
|
||||
@@ -146,7 +149,8 @@ mod tests {
|
||||
pet,
|
||||
main,
|
||||
};
|
||||
glue.put(2.0, 10.0).expect("she is placed");
|
||||
let pane = Bounds::new(point(px(10.), px(10.)), size(px(380.), px(280.)));
|
||||
glue.put(2.0, pane).expect("she is placed");
|
||||
let check = x11rb::connect(Some(&xvfb.display))
|
||||
.expect("the check connects")
|
||||
.0;
|
||||
@@ -155,11 +159,11 @@ mod tests {
|
||||
.expect("the request")
|
||||
.reply()
|
||||
.expect("her place");
|
||||
let left = (
|
||||
100 + ((LEFT + 10.0) * 2.0).round() as i32,
|
||||
let stands = (
|
||||
100 + ((10.0 + left(px(380.))) * 2.0).round() as i32,
|
||||
100 + ((10.0 - HEAD - ROOM) * 2.0).round() as i32,
|
||||
);
|
||||
assert_eq!((i32::from(at.x), i32::from(at.y)), left);
|
||||
assert_eq!((i32::from(at.x), i32::from(at.y)), stands);
|
||||
let order = check
|
||||
.query_tree(root)
|
||||
.expect("the request")
|
||||
|
||||
Reference in new issue
Block a user