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

commit8ab1d4d8a5c72e201b973986282be1487b1151fe
parent354bb167f8
authorLucas Galante <[email protected]>
date2026-07-04 16:00
feat: add style.surface.cloud.position_default config key

 src/server/config.rs         | 38 ++++++++++++++++++++++++++++++++++++++
 src/server/window_manager.rs | 25 +++++++++++++++++++++++--
 2 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/src/server/config.rs b/src/server/config.rs
index 4c4675b..f349cc8 100644
--- a/src/server/config.rs
+++ b/src/server/config.rs
@@ -54,6 +54,7 @@ pub struct Layout {
     pub status_backdrop_blur_ignore_transparent: bool,
     pub window_backdrop_blur_ignore_transparent: bool,
     pub status_module_hide_mode_preview: i64,
+    pub cloud_position_default: Option<[i32; 2]>,
 }
 
 impl Default for Layout {
@@ -106,6 +107,7 @@ impl Default for Layout {
             status_backdrop_blur_ignore_transparent: true,
             window_backdrop_blur_ignore_transparent: true,
             status_module_hide_mode_preview: 4,
+            cloud_position_default: None,
         }
     }
 }
@@ -300,6 +302,8 @@ pub struct SurfaceConfig {
     pub backplate_blur: f64,
     #[serde(default = "default_backplate_corner_radius")]
     pub backplate_corner_radius: i64,
+    #[serde(default = "default_cloud_position_default")]
+    pub cloud_position_default: Option<[i32; 2]>,
 }
 
 impl Default for SurfaceConfig {
@@ -317,11 +321,17 @@ impl Default for SurfaceConfig {
             backplate_color: default_backplate_color(),
             backplate_blur: default_backplate_blur(),
             backplate_corner_radius: default_backplate_corner_radius(),
+            cloud_position_default: default_cloud_position_default(),
         }
      }
 }
 
+fn default_cloud_position_default() -> Option<[i32; 2]> {
+    None
+}
+
 fn default_desktop_gap_color() -> String {
+
     "#000000".to_string()
 }
 
@@ -816,6 +826,26 @@ fn get_child_arg_f64_opt(node: &kdl::KdlNode, child_name: &str) -> Option<f64> {
     None
 }
 
+fn get_child_arg_vec2i_opt(node: &kdl::KdlNode, child_name: &str) -> Option<[i32; 2]> {
+    if let Some(children) = node.children() {
+        for child in children.nodes() {
+            if child.name().value() == child_name {
+                let entries = child.entries();
+                if entries.len() >= 2 {
+                    let has_tag = entries.first().and_then(|e| e.ty()).map_or(false, |t| t.value() == "vec2i");
+                    if has_tag {
+                        let x = entries[0].value().as_i64()? as i32;
+                        let y = entries[1].value().as_i64()? as i32;
+                        return Some([x, y]);
+                    }
+                }
+            }
+        }
+    }
+    None
+}
+
+
 fn get_child_arg_string_opt(node: &kdl::KdlNode, child_name: &str) -> Option<String> {
     if let Some(children) = node.children() {
         for child in children.nodes() {
@@ -1411,6 +1441,12 @@ fn parse_kdl_config(content: &str) -> Result<Config, String> {
                             }
                         }
                     }
+                    if let Some(cloud_node) = surface_children.nodes().iter().find(|n| n.name().value() == "cloud") {
+                        found_nested = true;
+                        if let Some(pos) = get_child_arg_vec2i_opt(cloud_node, "position_default") {
+                            surface.cloud_position_default = Some(pos);
+                        }
+                    }
                 }
             }
         }
@@ -1429,6 +1465,7 @@ fn parse_kdl_config(content: &str) -> Result<Config, String> {
             surface.backplate_color = get_child_arg_string(node, "backplate_color", &default_backplate_color());
             surface.backplate_blur = get_child_arg_f64(node, "backplate_blur", default_backplate_blur());
             surface.backplate_corner_radius = get_child_arg_i64(node, "backplate_corner_radius", default_backplate_corner_radius());
+            surface.cloud_position_default = get_child_arg_vec2i_opt(node, "cloud_position_default");
         }
     }
 
@@ -1543,6 +1580,7 @@ pub fn parse_config(path: &str, state: &mut crate::window_manager::WindowManager
     state.layout.status_backdrop_blur_ignore_transparent = config.layout.status_backdrop_blur_ignore_transparent;
     state.layout.window_backdrop_blur_ignore_transparent = config.layout.window_backdrop_blur_ignore_transparent;
     state.layout.status_module_hide_mode_preview = config.layout.status_module_hide_mode_preview;
+    state.layout.cloud_position_default = config.surface.cloud_position_default;
 
     for (key, val) in &config.env {
         let expanded = expand_env_vars(val);
diff --git a/src/server/window_manager.rs b/src/server/window_manager.rs
index bebfc1b..f1d26e5 100644
--- a/src/server/window_manager.rs
+++ b/src/server/window_manager.rs
@@ -1307,11 +1307,15 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
             let dec_h = std::cmp::max(bw, 16);
             for (sp_idx, &win_ptr) in overlay_windows.iter().enumerate() {
                 if sp_idx == 0 {
+                    let app_id = (*win_ptr).get_app_id_string();
+                    let is_cce_cloud = app_id.as_deref().map_or(false, |id| id.starts_with("cce-cloud"));
+
                     let mut sp_x = (*win_ptr).box_geom.x;
                     let mut sp_y = (*win_ptr).box_geom.y;
                     let mut sp_w = (*win_ptr).box_geom.width as i32;
                     let mut sp_h = (*win_ptr).box_geom.height as i32;
 
+
                     if sp_w == 0 || sp_h == 0 {
                         sp_w = if (*win_ptr).wm_scheduled.dimensions_hint.min_width > 32 {
                             std::cmp::max(self.layout.overlay_width, (*win_ptr).wm_scheduled.dimensions_hint.min_width as i32)
@@ -1331,12 +1335,21 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
                         (*win_ptr).box_geom.y = sp_y;
                         (*win_ptr).box_geom.width = sp_w;
                         (*win_ptr).box_geom.height = sp_h;
+                    } else if is_cce_cloud {
+                        if let Some(pos) = self.layout.cloud_position_default {
+                            sp_x = usable_x + pos[0];
+                            sp_y = usable_y + pos[1];
+                            (*win_ptr).box_geom.x = sp_x;
+                            (*win_ptr).box_geom.y = sp_y;
+                        }
                     }
 
                     (*win_ptr).rendering_requested.x = sp_x;
                     (*win_ptr).rendering_requested.y = sp_y;
                     (*win_ptr).scale = 1.0;
 
+
+
                     let vx = self.desk_pan_x + (sp_x - phys_x) as f64 / self.desk_zoom;
                     let vy = self.desk_pan_y + (sp_y - phys_y) as f64 / self.desk_zoom;
                     (*win_ptr).virtual_x = vx;
@@ -1461,12 +1474,20 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
                     } else {
                         100
                     };
-                    let fx = usable_x + usable_w - fw - self.layout.gap_right;
-                    let fy = usable_y + self.layout.gap_top;
+                    let app_id = (*win_ptr).get_app_id_string();
+                    let is_cce_cloud = app_id.as_deref().map_or(false, |id| id.starts_with("cce-cloud"));
+
+                    let (fx, fy) = if is_cce_cloud && self.layout.cloud_position_default.is_some() {
+                        let pos = self.layout.cloud_position_default.unwrap();
+                        (usable_x + pos[0], usable_y + pos[1])
+                    } else {
+                        (usable_x + usable_w - fw - self.layout.gap_right, usable_y + self.layout.gap_top)
+                    };
 
                     (*win_ptr).rendering_requested.x = fx;
                     (*win_ptr).rendering_requested.y = fy;
                     (*win_ptr).scale = 1.0;
+
                     (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions {
                         width: fw as u32,
                         height: fh as u32,