mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-26 20:32:22 +03:00
linux/x11: Fix gap when tiling windows side by side (#13859)
By leveraging the `_GTK_EDGE_CONSTRAINTS` atom we can get all four booleans for the `Tiling` struct and figure out which side is free when the window is tiled to half of the screen. For the logic behind the `_GTK_EDGE_CONSTRAINTS` see: -8e9d13aa3b/src/x11/window-x11.c (L65-L75)
-8e9d13aa3b/src/x11/window-x11.c (L1205-L1231)
(I used Claude 3.5 Sonnet with our code and these pieces from `mutter` to generate the Rust code, that was pretty sweet) This fixes the gap in the middle when a GPUI window is tiled to the left and another window to the right. It's not _perfect_ but it looks a lot better. Here's a diff that makes it look better: ```diff diff --git a/crates/gpui/examples/window_shadow.rs b/crates/gpui/examples/window_shadow.rs index 122231f6b..7fa29dadc 100644 --- a/crates/gpui/examples/window_shadow.rs +++ b/crates/gpui/examples/window_shadow.rs @@ -72,8 +72,8 @@ impl Render for WindowShadow { .when(!(tiling.top || tiling.left), |div| div.rounded_tl(rounding)) .when(!tiling.top, |div| div.pt(shadow_size)) .when(!tiling.bottom, |div| div.pb(shadow_size)) - .when(!tiling.left, |div| div.pl(shadow_size)) - .when(!tiling.right, |div| div.pr(shadow_size)) + .when(!tiling.left, |div| div.pl(shadow_size - border_size)) + .when(!tiling.right, |div| div.pr(shadow_size - border_size)) .on_mouse_move(|_e, cx| cx.refresh()) .on_mouse_down(MouseButton::Left, move |e, cx| { let size = cx.window_bounds().get_bounds().size; ``` But that makes it look weird on Wayland, so I didn't do it. I think it's fine for now. Chromium looks bad and has a gap, so we're already better. ## Before ![before_1](https://github.com/zed-industries/zed/assets/1185253/875c5cdd-c0be-4295-beb0-bb9ba5beaa52) ![before_2](https://github.com/zed-industries/zed/assets/1185253/0b96be70-4c34-4e99-aeb2-ab741171ad14) ## After ![after_1](https://github.com/zed-industries/zed/assets/1185253/aa51da77-daf1-4ef8-a33f-a83731e0c7e1) ![after_2](https://github.com/zed-industries/zed/assets/1185253/8ce7902d-90b6-4f06-ba2c-626e643abe56) Release Notes: - N/A
This commit is contained in:
parent
c4dbe32f20
commit
e69f9d6cf9
@ -86,6 +86,49 @@ impl ResizeEdge {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct EdgeConstraints {
|
||||
top_tiled: bool,
|
||||
#[allow(dead_code)]
|
||||
top_resizable: bool,
|
||||
|
||||
right_tiled: bool,
|
||||
#[allow(dead_code)]
|
||||
right_resizable: bool,
|
||||
|
||||
bottom_tiled: bool,
|
||||
#[allow(dead_code)]
|
||||
bottom_resizable: bool,
|
||||
|
||||
left_tiled: bool,
|
||||
#[allow(dead_code)]
|
||||
left_resizable: bool,
|
||||
}
|
||||
|
||||
impl EdgeConstraints {
|
||||
fn from_atom(atom: u32) -> Self {
|
||||
EdgeConstraints {
|
||||
top_tiled: (atom & (1 << 0)) != 0,
|
||||
top_resizable: (atom & (1 << 1)) != 0,
|
||||
right_tiled: (atom & (1 << 2)) != 0,
|
||||
right_resizable: (atom & (1 << 3)) != 0,
|
||||
bottom_tiled: (atom & (1 << 4)) != 0,
|
||||
bottom_resizable: (atom & (1 << 5)) != 0,
|
||||
left_tiled: (atom & (1 << 6)) != 0,
|
||||
left_resizable: (atom & (1 << 7)) != 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_tiling(&self) -> Tiling {
|
||||
Tiling {
|
||||
top: self.top_tiled,
|
||||
right: self.right_tiled,
|
||||
bottom: self.bottom_tiled,
|
||||
left: self.left_tiled,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Visual {
|
||||
id: xproto::Visualid,
|
||||
@ -198,6 +241,7 @@ pub struct X11WindowState {
|
||||
active: bool,
|
||||
fullscreen: bool,
|
||||
decorations: WindowDecorations,
|
||||
edge_constraints: Option<EdgeConstraints>,
|
||||
pub handle: AnyWindowHandle,
|
||||
last_insets: [u32; 4],
|
||||
}
|
||||
@ -497,6 +541,7 @@ impl X11WindowState {
|
||||
destroyed: false,
|
||||
decorations: WindowDecorations::Server,
|
||||
last_insets: [0, 0, 0, 0],
|
||||
edge_constraints: None,
|
||||
counter_id: sync_request_counter,
|
||||
last_sync_counter: None,
|
||||
refresh_rate,
|
||||
@ -686,10 +731,32 @@ impl X11WindowStatePtr {
|
||||
|
||||
pub fn property_notify(&self, event: xproto::PropertyNotifyEvent) {
|
||||
let mut state = self.state.borrow_mut();
|
||||
if event.atom == state.atoms._NET_WM_STATE
|
||||
|| event.atom == state.atoms._GTK_EDGE_CONSTRAINTS
|
||||
{
|
||||
if event.atom == state.atoms._NET_WM_STATE {
|
||||
self.set_wm_properties(state);
|
||||
} else if event.atom == state.atoms._GTK_EDGE_CONSTRAINTS {
|
||||
self.set_edge_constraints(state);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_edge_constraints(&self, mut state: std::cell::RefMut<X11WindowState>) {
|
||||
let reply = self
|
||||
.xcb_connection
|
||||
.get_property(
|
||||
false,
|
||||
self.x_window,
|
||||
state.atoms._GTK_EDGE_CONSTRAINTS,
|
||||
xproto::AtomEnum::CARDINAL,
|
||||
0,
|
||||
4,
|
||||
)
|
||||
.unwrap()
|
||||
.reply()
|
||||
.unwrap();
|
||||
|
||||
if reply.value_len != 0 {
|
||||
let atom = u32::from_ne_bytes(reply.value[0..4].try_into().unwrap());
|
||||
let edge_constraints = EdgeConstraints::from_atom(atom);
|
||||
state.edge_constraints.replace(edge_constraints);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1194,15 +1261,19 @@ impl PlatformWindow for X11Window {
|
||||
match state.decorations {
|
||||
WindowDecorations::Server => Decorations::Server,
|
||||
WindowDecorations::Client => {
|
||||
// https://source.chromium.org/chromium/chromium/src/+/main:ui/ozone/platform/x11/x11_window.cc;l=2519;drc=1f14cc876cc5bf899d13284a12c451498219bb2d
|
||||
Decorations::Client {
|
||||
tiling: Tiling {
|
||||
let tiling = if let Some(edge_constraints) = &state.edge_constraints {
|
||||
edge_constraints.to_tiling()
|
||||
} else {
|
||||
// https://source.chromium.org/chromium/chromium/src/+/main:ui/ozone/platform/x11/x11_window.cc;l=2519;drc=1f14cc876cc5bf899d13284a12c451498219bb2d
|
||||
Tiling {
|
||||
top: state.maximized_vertical,
|
||||
bottom: state.maximized_vertical,
|
||||
left: state.maximized_horizontal,
|
||||
right: state.maximized_horizontal,
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Decorations::Client { tiling }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1212,17 +1283,26 @@ impl PlatformWindow for X11Window {
|
||||
|
||||
let dp = (inset.0 * state.scale_factor) as u32;
|
||||
|
||||
let (left, right) = if state.maximized_horizontal {
|
||||
(0, 0)
|
||||
let insets = if let Some(edge_constraints) = &state.edge_constraints {
|
||||
let left = if edge_constraints.left_tiled { 0 } else { dp };
|
||||
let top = if edge_constraints.top_tiled { 0 } else { dp };
|
||||
let right = if edge_constraints.right_tiled { 0 } else { dp };
|
||||
let bottom = if edge_constraints.bottom_tiled { 0 } else { dp };
|
||||
|
||||
[left, right, top, bottom]
|
||||
} else {
|
||||
(dp, dp)
|
||||
let (left, right) = if state.maximized_horizontal {
|
||||
(0, 0)
|
||||
} else {
|
||||
(dp, dp)
|
||||
};
|
||||
let (top, bottom) = if state.maximized_vertical {
|
||||
(0, 0)
|
||||
} else {
|
||||
(dp, dp)
|
||||
};
|
||||
[left, right, top, bottom]
|
||||
};
|
||||
let (top, bottom) = if state.maximized_vertical {
|
||||
(0, 0)
|
||||
} else {
|
||||
(dp, dp)
|
||||
};
|
||||
let insets = [left, right, top, bottom];
|
||||
|
||||
if state.last_insets != insets {
|
||||
state.last_insets = insets;
|
||||
|
@ -6491,6 +6491,8 @@ pub fn client_side_decorations(element: impl IntoElement, cx: &mut WindowContext
|
||||
cx.set_client_inset(theme::CLIENT_SIDE_DECORATION_SHADOW);
|
||||
}
|
||||
|
||||
println!("decorations: {:?}", decorations);
|
||||
|
||||
struct GlobalResizeEdge(ResizeEdge);
|
||||
impl Global for GlobalResizeEdge {}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user