diff --git a/crates/gpui/src/platform/linux/x11/window.rs b/crates/gpui/src/platform/linux/x11/window.rs index 3539f97338..d81de2a48e 100644 --- a/crates/gpui/src/platform/linux/x11/window.rs +++ b/crates/gpui/src/platform/linux/x11/window.rs @@ -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, 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) { + 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; diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index ba8476fbb4..c8bcd2c993 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -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 {}