Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
feat: adjust CSD geometry calculations and resolve layout gaps on transitions
src/server/ipc_server.rs | 12 +++++------
src/server/run_server.rs | 4 ++--
src/server/status_server.rs | 12 +++++------
src/server/window.rs | 50 +++++++++++++++++++++++++++++++++++++-------
src/server/window_manager.rs | 48 ++++++++++++++++++++++++++++--------------
src/server/xdg_toplevel.rs | 7 +++++++
6 files changed, 96 insertions(+), 37 deletions(-)
diff --git a/src/server/ipc_server.rs b/src/server/ipc_server.rs
index 22491f4..f1b3515 100644
--- a/src/server/ipc_server.rs
+++ b/src/server/ipc_server.rs
@@ -9,29 +9,29 @@ pub struct IpcRequest {
pub reply_tx: mpsc::Sender<String>,
}
-fn get_ipc_socket_path() -> String {
- if let Ok(display) = std::env::var("WAYLAND_DISPLAY") {
+fn get_ipc_socket_path(display_socket: Option<&str>) -> String {
+ if let Some(display) = display_socket {
format!("/tmp/cce-client-{}.sock", display)
} else {
"/tmp/cce-client.sock".to_string()
}
}
-pub fn spawn_ipc_server() -> mpsc::Receiver<IpcRequest> {
+pub fn spawn_ipc_server(display_socket: Option<String>) -> mpsc::Receiver<IpcRequest> {
let (tx, rx) = mpsc::channel::<IpcRequest>();
thread::Builder::new()
.name("cce-ipc-server".to_string())
.spawn(move || {
- ipc_server_main(tx);
+ ipc_server_main(tx, display_socket);
})
.expect("Failed to spawn CCE IPC server thread");
rx
}
-fn ipc_server_main(tx: mpsc::Sender<IpcRequest>) {
- let socket_path = get_ipc_socket_path();
+fn ipc_server_main(tx: mpsc::Sender<IpcRequest>, display_socket: Option<String>) {
+ let socket_path = get_ipc_socket_path(display_socket.as_deref());
let _ = std::fs::remove_file(&socket_path);
let listener = match UnixListener::bind(&socket_path) {
diff --git a/src/server/run_server.rs b/src/server/run_server.rs
index f496475..9328a6f 100644
--- a/src/server/run_server.rs
+++ b/src/server/run_server.rs
@@ -169,9 +169,9 @@ pub fn run_server() {
std::env::set_var("WAYLAND_DISPLAY", &socket_str);
- server.wm.start_ipc();
+ server.wm.start_ipc(Some(socket_str.clone()));
- let status_sender = crate::status_server::spawn_status_server();
+ let status_sender = crate::status_server::spawn_status_server(Some(socket_str.clone()));
server.wm.status_sender = Some(status_sender);
diff --git a/src/server/status_server.rs b/src/server/status_server.rs
index 334e730..b59e017 100644
--- a/src/server/status_server.rs
+++ b/src/server/status_server.rs
@@ -61,8 +61,8 @@ impl StatusSender {
}
}
-pub fn get_status_socket_path() -> String {
- if let Ok(display) = std::env::var("WAYLAND_DISPLAY") {
+pub fn get_status_socket_path(display_socket: Option<&str>) -> String {
+ if let Some(display) = display_socket {
format!("/tmp/cce-client-status-{}.sock", display)
} else {
"/tmp/cce-client-status.sock".to_string()
@@ -70,21 +70,21 @@ pub fn get_status_socket_path() -> String {
}
/// Spawn the status server thread. Returns a StatusSender for the main loop.
-pub fn spawn_status_server() -> StatusSender {
+pub fn spawn_status_server(display_socket: Option<String>) -> StatusSender {
let (tx, rx) = mpsc::channel::<StatusUpdate>();
std::thread::Builder::new()
.name("cce-status-server".into())
.spawn(move || {
- status_server_main(rx);
+ status_server_main(rx, display_socket);
})
.expect("failed to spawn status server thread");
StatusSender { tx }
}
-fn status_server_main(rx: mpsc::Receiver<StatusUpdate>) {
- let socket_path = get_status_socket_path();
+fn status_server_main(rx: mpsc::Receiver<StatusUpdate>, display_socket: Option<String>) {
+ let socket_path = get_status_socket_path(display_socket.as_deref());
// Remove stale socket
let _ = std::fs::remove_file(&socket_path);
diff --git a/src/server/window.rs b/src/server/window.rs
index 5fa49d8..1d4741f 100644
--- a/src/server/window.rs
+++ b/src/server/window.rs
@@ -234,6 +234,8 @@ pub struct Window {
pub box_geom: ffi::wlr_box,
pub margin_x: i32,
pub margin_y: i32,
+ pub last_decor_w: i32,
+ pub last_decor_h: i32,
pub foreign_toplevel_handle: *mut ffi::wlr_ext_foreign_toplevel_handle_v1,
pub wlr_toplevel_handle: *mut ffi::wlr_foreign_toplevel_handle_v1,
}
@@ -393,6 +395,8 @@ impl Window {
box_geom: ffi::wlr_box { x: 0, y: 0, width: 0, height: 0 },
margin_x: 0,
margin_y: 0,
+ last_decor_w: 0,
+ last_decor_h: 0,
foreign_toplevel_handle: std::ptr::null_mut(),
wlr_toplevel_handle: std::ptr::null_mut(),
});
@@ -739,6 +743,33 @@ impl Window {
}
}
+ pub unsafe fn get_decorations_size(&self) -> (i32, i32) {
+ if self.wm_requested.ssd {
+ return (0, 0);
+ }
+ let surface = self.root_surface();
+ if surface.is_null() {
+ return (0, 0);
+ }
+ let surf_w = ffi::river_wlr_surface_get_width(surface);
+ let surf_h = ffi::river_wlr_surface_get_height(surface);
+
+ let (geom_w, geom_h) = match self.impl_type {
+ WindowImpl::Toplevel(toplevel) => {
+ if toplevel.is_null() {
+ (surf_w, surf_h)
+ } else {
+ ((*toplevel).geometry.width, (*toplevel).geometry.height)
+ }
+ }
+ _ => (surf_w, surf_h),
+ };
+
+ let dec_w = (surf_w - geom_w).max(0);
+ let dec_h = (surf_h - geom_h).max(0);
+ (dec_w, dec_h)
+ }
+
pub unsafe fn send_frame_done(&self) {
assert_eq!(self.state, WindowState::Mapped);
if !matches!(self.impl_type, WindowImpl::Destroying) {
@@ -1121,7 +1152,8 @@ impl Window {
- let is_cascade = (*self.server).wm.get_mode_for_window(self as *mut Window) == crate::tiling::TilingMode::Cascade;
+ let mode = (*self.server).wm.get_mode_for_window(self as *mut Window);
+ let is_maximized_layout = mode == crate::tiling::TilingMode::Cascade || mode == crate::tiling::TilingMode::Grid;
self.configure_scheduled = Configure {
width,
height,
@@ -1130,7 +1162,7 @@ impl Window {
ssd: self.wm_requested.ssd,
tiled: self.wm_requested.tiled,
capabilities: self.wm_requested.capabilities,
- maximized: self.wm_requested.maximized || is_cascade,
+ maximized: self.wm_requested.maximized || is_maximized_layout,
inform_fullscreen: self.wm_requested.inform_fullscreen,
resizing: self.wm_requested.resizing,
};
@@ -1439,6 +1471,13 @@ impl Window {
x = 0;
y = 0;
}
+ // For tiled CSD windows, do not shift the surfaces tree
+ if !self.wm_requested.ssd &&
+ self.tiling_mode != crate::tiling::TilingMode::Floating &&
+ self.tiling_mode != crate::tiling::TilingMode::Popup {
+ x = 0;
+ y = 0;
+ }
(x, y)
}
}
@@ -1662,7 +1701,7 @@ impl Window {
let children_head = ffi::river_scene_tree_get_children(self.surfaces.tree) as *mut WlList;
if (*children_head).next != children_head {
- ffi::wlr_scene_subsurface_tree_set_clip(self.surfaces.tree as *mut ffi::wlr_scene_node, &surface_clip);
+ ffi::wlr_scene_subsurface_tree_set_clip(self.surfaces.tree as *mut ffi::wlr_scene_node, std::ptr::null());
}
}
}
@@ -2444,10 +2483,7 @@ impl Decoration {
let children_head = ffi::river_scene_tree_get_children(self.surfaces.tree) as *mut WlList;
if (*children_head).next != children_head {
- let mut clip = *window_clip;
- clip.x -= self.rendering_requested.offset_x;
- clip.y -= self.rendering_requested.offset_y;
- ffi::wlr_scene_subsurface_tree_set_clip(self.surfaces.tree as *mut ffi::wlr_scene_node, &clip);
+ ffi::wlr_scene_subsurface_tree_set_clip(self.surfaces.tree as *mut ffi::wlr_scene_node, std::ptr::null());
}
}
}
diff --git a/src/server/window_manager.rs b/src/server/window_manager.rs
index 723d621..7c47de7 100644
--- a/src/server/window_manager.rs
+++ b/src/server/window_manager.rs
@@ -167,9 +167,9 @@ impl WindowManager {
Ok(())
}
- pub fn start_ipc(&mut self) {
+ pub fn start_ipc(&mut self, display_socket: Option<String>) {
if self.ipc_rx.is_none() {
- let rx = crate::ipc_server::spawn_ipc_server();
+ let rx = crate::ipc_server::spawn_ipc_server(display_socket);
self.ipc_rx = Some(rx);
}
}
@@ -899,16 +899,24 @@ impl WindowManager {
(*win_ptr).rendering_requested.y = final_y;
if !self.expose_active {
+ let mut target_w = w;
+ let mut target_h = h;
+ if !(*win_ptr).wm_requested.ssd {
+ let (dec_w, dec_h) = (*win_ptr).get_decorations_size();
+ target_w = (w - dec_w).max(1);
+ target_h = (h - dec_h).max(1);
+ }
(*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions {
- width: w as u32,
- height: h as u32,
+ width: target_w as u32,
+ height: target_h as u32,
});
(*win_ptr).wm_requested.bounds = crate::window::Dimensions {
- width: w as u32,
- height: h as u32,
+ width: target_w as u32,
+ height: target_h as u32,
};
- let is_cascade = self.get_mode_for_window(win_ptr) == crate::tiling::TilingMode::Cascade;
- (*win_ptr).wm_requested.tiled = if is_cascade { 0 } else { 1 | 2 | 4 | 8 };
+ let mode = self.get_mode_for_window(win_ptr);
+ let is_maximized_layout = mode == crate::tiling::TilingMode::Cascade || mode == crate::tiling::TilingMode::Grid;
+ (*win_ptr).wm_requested.tiled = if is_maximized_layout { 0 } else { 1 | 2 | 4 | 8 };
}
let is_focused = win_ptr == focused_window;
@@ -965,13 +973,20 @@ impl WindowManager {
(*win_ptr).rendering_requested.x = sp_x;
(*win_ptr).rendering_requested.y = sp_y;
+ let mut sp_target_w = sp_w;
+ let mut sp_target_h = sp_h;
+ if !(*win_ptr).wm_requested.ssd {
+ let (dec_w, dec_h) = (*win_ptr).get_decorations_size();
+ sp_target_w = (sp_w - dec_w).max(1);
+ sp_target_h = (sp_h - dec_h).max(1);
+ }
(*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions {
- width: sp_w as u32,
- height: sp_h as u32,
+ width: sp_target_w as u32,
+ height: sp_target_h as u32,
});
(*win_ptr).wm_requested.bounds = crate::window::Dimensions {
- width: sp_w as u32,
- height: sp_h as u32,
+ width: sp_target_w as u32,
+ height: sp_target_h as u32,
};
(*win_ptr).wm_requested.tiled = 1 | 2 | 4 | 8;
@@ -1087,10 +1102,11 @@ impl WindowManager {
usable_y + gap_left + fbw + bar_height + gap_top + cascade_offset * idx_floating
};
- let min_x = usable_x + gap_left;
- let max_x = usable_x + usable_w - gap_right - fw;
- let min_y = usable_y + bar_height + gap_top;
- let max_y = usable_y + usable_h - gap_bottom - fh;
+ let min_visible = 64;
+ let min_x = usable_x + gap_left - fw + fw.min(min_visible);
+ let max_x = usable_x + usable_w - gap_right - fw.min(min_visible);
+ let min_y = usable_y + bar_height + gap_top - fh + fh.min(min_visible);
+ let max_y = usable_y + usable_h - gap_bottom - fh.min(min_visible);
fx = fx.clamp(min_x, max_x.max(min_x));
fy = fy.clamp(min_y, max_y.max(min_y));
diff --git a/src/server/xdg_toplevel.rs b/src/server/xdg_toplevel.rs
index 3fdaffe..efc2e98 100644
--- a/src/server/xdg_toplevel.rs
+++ b/src/server/xdg_toplevel.rs
@@ -484,6 +484,13 @@ unsafe extern "C" fn handle_commit(listener: *mut ffi::wl_listener, _data: *mut
(*window).rendering_scheduled.width = new_geometry.width as u32;
(*window).rendering_scheduled.height = new_geometry.height as u32;
+ let (dec_w, dec_h) = (*window).get_decorations_size();
+ if dec_w != (*window).last_decor_w || dec_h != (*window).last_decor_h {
+ (*window).last_decor_w = dec_w;
+ (*window).last_decor_h = dec_h;
+ (*(*window).server).wm.dirty_windowing();
+ }
+
match (*toplevel).configure_state {
ConfigureState::Acked => {
(*toplevel).configure_state = ConfigureState::Committed;