git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commit99c14cc89eca6dc6a2295b894d99484cfb170597
parenteb7216166c
authorLucas Galante <[email protected]>
date2026-06-27 18:51
Implement standalone Maximized window mode with grid snapping

 src/cce_ctl.rs                      |   4 +-
 src/server/cce_window_management.rs |   2 +-
 src/server/config.rs                |   1 +
 src/server/cursor.rs                |  48 +++++++++++++++++
 src/server/tiling.rs                |   2 +
 src/server/window.rs                |  14 ++++-
 src/server/window_manager.rs        | 101 ++++++++++++++++++++++++++++++++++++
 src/server/xdg_toplevel.rs          |   2 +-
 src/server/xwayland_window.rs       |   2 +-
 9 files changed, 170 insertions(+), 6 deletions(-)

diff --git a/src/cce_ctl.rs b/src/cce_ctl.rs
index 17940aa..c23a0e5 100644
--- a/src/cce_ctl.rs
+++ b/src/cce_ctl.rs
@@ -51,8 +51,8 @@ fn usage(name: &str, to_stderr: bool) {
     print("  pbind <mods> <button> <action>");
     print("  retile");
     print("  set-viewport <1-4>");
-    print("  mode <cascade|grid|fullscreen|floating|popup> <app_id> [title]");
-    print("  viewport-layout <1-4> <cascade|grid|fullscreen|floating|popup>");
+    print("  mode <cascade|grid|fullscreen|floating|popup|maximized> <app_id> [title]");
+    print("  viewport-layout <1-4> <cascade|grid|fullscreen|floating|popup|maximized>");
     print("  pointer-location");
     print("  pointer-move-to <x> <y>");
     print("  pointer-move-by <dx> <dy>");
diff --git a/src/server/cce_window_management.rs b/src/server/cce_window_management.rs
index e88b133..881e716 100644
--- a/src/server/cce_window_management.rs
+++ b/src/server/cce_window_management.rs
@@ -155,7 +155,7 @@ unsafe extern "C" fn toplevel_set_maximized(
     let server = (*data).server;
     let window_key = (*data).window_key;
     if let Some(window) = resolve_window(server, window_key) {
-        (*window).tiling_mode = crate::tiling::TilingMode::Cascade;
+        (*window).tiling_mode = crate::tiling::TilingMode::Maximized;
         (*window).mode_locked = true;
         (*window).wm_scheduled.maximize_requested = crate::window::MaximizeRequest::Maximize;
         (*server).wm.dirty_windowing();
diff --git a/src/server/config.rs b/src/server/config.rs
index 12df8fe..cbd0ac2 100644
--- a/src/server/config.rs
+++ b/src/server/config.rs
@@ -485,6 +485,7 @@ pub fn parse_tiling_mode(s: &str) -> TilingMode {
         "popup" => TilingMode::Popup,
         "sidepanel" | "side_panel" | "side-panel" | "pinned" => TilingMode::Pinned,
         "status" => TilingMode::Status,
+        "maximized" => TilingMode::Maximized,
         _ => TilingMode::Cascade,
     }
 }
diff --git a/src/server/cursor.rs b/src/server/cursor.rs
index 5a4b3ff..eed5ae5 100644
--- a/src/server/cursor.rs
+++ b/src/server/cursor.rs
@@ -669,6 +669,22 @@ unsafe extern "C" fn handle_button(listener: *mut ffi::wl_listener, data: *mut s
                     && (*target_win).tiling_mode != crate::tiling::TilingMode::Fullscreen
                     && (*target_win).tiling_mode != crate::tiling::TilingMode::Pinned
                 {
+                    if (*target_win).was_maximized {
+                        (*target_win).box_geom.width = (*target_win).saved_maximized_width;
+                        (*target_win).box_geom.height = (*target_win).saved_maximized_height;
+                        (*target_win).virtual_x = (*target_win).saved_maximized_virtual_x;
+                        (*target_win).virtual_y = (*target_win).saved_maximized_virtual_y;
+                        (*target_win).was_maximized = false;
+                        
+                        (*target_win).wm_requested.dimensions = Some(crate::window::Dimensions {
+                            width: (*target_win).saved_maximized_width as u32,
+                            height: (*target_win).saved_maximized_height as u32,
+                        });
+                        (*target_win).wm_requested.bounds = crate::window::Dimensions {
+                            width: (*target_win).saved_maximized_width as u32,
+                            height: (*target_win).saved_maximized_height as u32,
+                        };
+                    }
                     (*target_win).tiling_mode = crate::tiling::TilingMode::Floating;
                     (*target_win).mode_locked = true;
                 }
@@ -742,6 +758,22 @@ unsafe extern "C" fn handle_button(listener: *mut ffi::wl_listener, data: *mut s
                 BorderZone::Resize(edges) => {
                     if (*event).button == 0x110 { // BTN_LEFT
                         if initial_mode != crate::tiling::TilingMode::Floating {
+                            if (*border_target_win).was_maximized {
+                                (*border_target_win).box_geom.width = (*border_target_win).saved_maximized_width;
+                                (*border_target_win).box_geom.height = (*border_target_win).saved_maximized_height;
+                                (*border_target_win).virtual_x = (*border_target_win).saved_maximized_virtual_x;
+                                (*border_target_win).virtual_y = (*border_target_win).saved_maximized_virtual_y;
+                                (*border_target_win).was_maximized = false;
+                                
+                                (*border_target_win).wm_requested.dimensions = Some(crate::window::Dimensions {
+                                    width: (*border_target_win).saved_maximized_width as u32,
+                                    height: (*border_target_win).saved_maximized_height as u32,
+                                });
+                                (*border_target_win).wm_requested.bounds = crate::window::Dimensions {
+                                    width: (*border_target_win).saved_maximized_width as u32,
+                                    height: (*border_target_win).saved_maximized_height as u32,
+                                };
+                            }
                             (*border_target_win).tiling_mode = crate::tiling::TilingMode::Floating;
                             (*border_target_win).mode_locked = true;
                         }
@@ -782,6 +814,22 @@ unsafe extern "C" fn handle_button(listener: *mut ffi::wl_listener, data: *mut s
                         if initial_mode != crate::tiling::TilingMode::Floating
                             && initial_mode != crate::tiling::TilingMode::Pinned
                         {
+                            if (*border_target_win).was_maximized {
+                                (*border_target_win).box_geom.width = (*border_target_win).saved_maximized_width;
+                                (*border_target_win).box_geom.height = (*border_target_win).saved_maximized_height;
+                                (*border_target_win).virtual_x = (*border_target_win).saved_maximized_virtual_x;
+                                (*border_target_win).virtual_y = (*border_target_win).saved_maximized_virtual_y;
+                                (*border_target_win).was_maximized = false;
+                                
+                                (*border_target_win).wm_requested.dimensions = Some(crate::window::Dimensions {
+                                    width: (*border_target_win).saved_maximized_width as u32,
+                                    height: (*border_target_win).saved_maximized_height as u32,
+                                });
+                                (*border_target_win).wm_requested.bounds = crate::window::Dimensions {
+                                    width: (*border_target_win).saved_maximized_width as u32,
+                                    height: (*border_target_win).saved_maximized_height as u32,
+                                };
+                            }
                             (*border_target_win).tiling_mode = crate::tiling::TilingMode::Floating;
                             (*border_target_win).mode_locked = true;
                         }
diff --git a/src/server/tiling.rs b/src/server/tiling.rs
index 05e5c28..cb3e799 100644
--- a/src/server/tiling.rs
+++ b/src/server/tiling.rs
@@ -9,6 +9,7 @@ pub enum TilingMode {
     Popup,
     Pinned,
     Status,
+    Maximized,
 }
 
 impl TilingMode {
@@ -21,6 +22,7 @@ impl TilingMode {
             TilingMode::Popup => "Popup",
             TilingMode::Pinned => "Pinned",
             TilingMode::Status => "Status",
+            TilingMode::Maximized => "Maximized",
         }
     }
 }
diff --git a/src/server/window.rs b/src/server/window.rs
index 1c08ca8..174a11b 100644
--- a/src/server/window.rs
+++ b/src/server/window.rs
@@ -235,6 +235,11 @@ pub struct Window {
     pub saved_height: i32,
     pub saved_virtual_x: f64,
     pub saved_virtual_y: f64,
+    pub was_maximized: bool,
+    pub saved_maximized_width: i32,
+    pub saved_maximized_height: i32,
+    pub saved_maximized_virtual_x: f64,
+    pub saved_maximized_virtual_y: f64,
 
     pub wm_scheduled: WmScheduledState,
     pub wm_sent: WmSentState,
@@ -402,6 +407,11 @@ impl Window {
             saved_height: 0,
             saved_virtual_x: 0.0,
             saved_virtual_y: 0.0,
+            was_maximized: false,
+            saved_maximized_width: 0,
+            saved_maximized_height: 0,
+            saved_maximized_virtual_x: 0.0,
+            saved_maximized_virtual_y: 0.0,
             wm_scheduled: WmScheduledState {
                 dimensions_hint: DimensionsHint { min_width: 0, min_height: 0, max_width: 0, max_height: 0 },
                 decoration_hint: ffi::zcce_window_v1_decoration_hint_ZCCE_WINDOW_V1_DECORATION_HINT_ONLY_SUPPORTS_CSD,
@@ -1350,7 +1360,9 @@ impl Window {
         };
         self.wm_requested.dimensions = None;
 
-        let is_maximized_layout = self.tiling_mode == crate::tiling::TilingMode::Cascade || self.tiling_mode == crate::tiling::TilingMode::Grid;
+        let is_maximized_layout = self.tiling_mode == crate::tiling::TilingMode::Cascade
+            || self.tiling_mode == crate::tiling::TilingMode::Grid
+            || self.tiling_mode == crate::tiling::TilingMode::Maximized;
         self.configure_scheduled = Configure {
             width,
             height,
diff --git a/src/server/window_manager.rs b/src/server/window_manager.rs
index 7bc525e..e9f35c0 100644
--- a/src/server/window_manager.rs
+++ b/src/server/window_manager.rs
@@ -1126,6 +1126,63 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
                 }
             }
 
+            // Manage entering/exiting Maximized state for normal windows
+            for &win_ptr in &normal_windows {
+                let mode = (*win_ptr).tiling_mode;
+                if mode == crate::tiling::TilingMode::Maximized && !(*win_ptr).was_maximized {
+                    // Entering Maximized mode
+                    let mut w = (*win_ptr).box_geom.width;
+                    let mut h = (*win_ptr).box_geom.height;
+                    if w <= 0 {
+                        w = if (*win_ptr).wm_scheduled.dimensions_hint.min_width > 32 {
+                            (*win_ptr).wm_scheduled.dimensions_hint.min_width as i32
+                        } else {
+                            800
+                        };
+                    }
+                    if h <= 0 {
+                        h = if (*win_ptr).wm_scheduled.dimensions_hint.min_height > 32 {
+                            (*win_ptr).wm_scheduled.dimensions_hint.min_height as i32
+                        } else {
+                            600
+                        };
+                    }
+                    (*win_ptr).saved_maximized_width = w;
+                    (*win_ptr).saved_maximized_height = h;
+                    (*win_ptr).saved_maximized_virtual_x = (*win_ptr).virtual_x;
+                    (*win_ptr).saved_maximized_virtual_y = (*win_ptr).virtual_y;
+                    (*win_ptr).was_maximized = true;
+                    log::info!("[Maximized] Saved window {:?} geometry: {}x{} at ({}, {})", 
+                        (*win_ptr).get_title_string().as_deref().unwrap_or(""), 
+                        (*win_ptr).saved_maximized_width, (*win_ptr).saved_maximized_height, 
+                        (*win_ptr).saved_maximized_virtual_x, (*win_ptr).saved_maximized_virtual_y
+                    );
+                } else if mode != crate::tiling::TilingMode::Maximized && (*win_ptr).was_maximized {
+                    // Exiting Maximized mode
+                    if (*win_ptr).saved_maximized_width > 0 && (*win_ptr).saved_maximized_height > 0 {
+                        (*win_ptr).box_geom.width = (*win_ptr).saved_maximized_width;
+                        (*win_ptr).box_geom.height = (*win_ptr).saved_maximized_height;
+                        (*win_ptr).virtual_x = (*win_ptr).saved_maximized_virtual_x;
+                        (*win_ptr).virtual_y = (*win_ptr).saved_maximized_virtual_y;
+                        (*win_ptr).was_maximized = false;
+                        
+                        (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions {
+                            width: (*win_ptr).saved_maximized_width as u32,
+                            height: (*win_ptr).saved_maximized_height as u32,
+                        });
+                        (*win_ptr).wm_requested.bounds = crate::window::Dimensions {
+                            width: (*win_ptr).saved_maximized_width as u32,
+                            height: (*win_ptr).saved_maximized_height as u32,
+                        };
+                        log::info!("[Maximized] Restored window {:?} geometry: {}x{} at ({}, {})", 
+                            (*win_ptr).get_title_string().as_deref().unwrap_or(""), 
+                            (*win_ptr).saved_maximized_width, (*win_ptr).saved_maximized_height, 
+                            (*win_ptr).saved_maximized_virtual_x, (*win_ptr).saved_maximized_virtual_y
+                        );
+                    }
+                }
+            }
+
             // Arrange normal windows on the virtual surface
             for &win_ptr in &normal_windows {
                 let mode = (*win_ptr).tiling_mode;
@@ -1175,6 +1232,50 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
                         height: phys_h as u32,
                     };
                     (*win_ptr).wm_requested.tiled = 1 | 2 | 4 | 8;
+                } else if mode == crate::tiling::TilingMode::Maximized {
+                    // Maximized mode: Resizes to fully fill all cells of the desktop grid it is fully/partially inside of.
+                    let scale = self.layout.desktop_grid_scale;
+                    
+                    // Use saved maximized geometry for cell calculation
+                    let x1 = (*win_ptr).saved_maximized_virtual_x;
+                    let y1 = (*win_ptr).saved_maximized_virtual_y;
+                    let w = (*win_ptr).saved_maximized_width as f64;
+                    let h = (*win_ptr).saved_maximized_height as f64;
+                    let x2 = x1 + w;
+                    let y2 = y1 + h;
+                    
+                    let col_min = (x1 / scale).floor() as i32;
+                    let col_max = ((x2 / scale).ceil() as i32 - 1).max(col_min);
+                    let row_min = (y1 / scale).floor() as i32;
+                    let row_max = ((y2 / scale).ceil() as i32 - 1).max(row_min);
+                    
+                    let snapped_x1 = col_min as f64 * scale;
+                    let snapped_x2 = (col_max + 1) as f64 * scale;
+                    let snapped_y1 = row_min as f64 * scale;
+                    let snapped_y2 = (row_max + 1) as f64 * scale;
+                    
+                    let fw = snapped_x2 - snapped_x1;
+                    let fh = snapped_y2 - snapped_y1;
+                    
+                    // Update current virtual position for rendering
+                    (*win_ptr).virtual_x = snapped_x1;
+                    (*win_ptr).virtual_y = snapped_y1;
+                    
+                    let final_x = phys_x + (((*win_ptr).virtual_x - self.desk_pan_x) * self.desk_zoom) as i32;
+                    let final_y = phys_y + (((*win_ptr).virtual_y - self.desk_pan_y) * self.desk_zoom) as i32;
+
+                    (*win_ptr).rendering_requested.x = final_x;
+                    (*win_ptr).rendering_requested.y = final_y;
+                    (*win_ptr).scale = self.desk_zoom;
+
+                    (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions {
+                        width: fw as u32,
+                        height: fh as u32,
+                    });
+                    (*win_ptr).wm_requested.bounds = crate::window::Dimensions {
+                        width: fw as u32,
+                        height: fh as u32,
+                    };
                 } else {
                     // Regular pannable window on the virtual surface
                     let fw = if let Some(resize_size) = self.get_active_resize_dimensions(win_ptr) {
diff --git a/src/server/xdg_toplevel.rs b/src/server/xdg_toplevel.rs
index b2e1098..57d93c0 100644
--- a/src/server/xdg_toplevel.rs
+++ b/src/server/xdg_toplevel.rs
@@ -610,7 +610,7 @@ unsafe extern "C" fn handle_request_maximize(listener: *mut ffi::wl_listener, _d
     let window = (*toplevel).window;
 
     if ffi::river_wlr_xdg_toplevel_get_requested_maximized((*toplevel).wlr_toplevel) {
-        (*window).tiling_mode = crate::tiling::TilingMode::Cascade;
+        (*window).tiling_mode = crate::tiling::TilingMode::Maximized;
         (*window).mode_locked = true;
         (*window).wm_scheduled.maximize_requested = crate::window::MaximizeRequest::Maximize;
     } else {
diff --git a/src/server/xwayland_window.rs b/src/server/xwayland_window.rs
index fabddf4..563152d 100644
--- a/src/server/xwayland_window.rs
+++ b/src/server/xwayland_window.rs
@@ -548,7 +548,7 @@ unsafe extern "C" fn handle_request_maximize(listener: *mut ffi::wl_listener, _d
     let maximized = (*(*xwindow).xsurface).maximized_vert || (*(*xwindow).xsurface).maximized_horz;
     let window = (*xwindow).window;
     if maximized {
-        (*window).tiling_mode = crate::tiling::TilingMode::Cascade;
+        (*window).tiling_mode = crate::tiling::TilingMode::Maximized;
         (*window).mode_locked = true;
     } else {
         (*window).tiling_mode = crate::tiling::TilingMode::Floating;