Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
feat(server): add desktop grid configuration controls (color, scale, line width)
src/server/config.rs | 65 ++++++++++++++++++++++++++++++++++++++++++++
src/server/output.rs | 10 +++----
src/server/window_manager.rs | 13 +++++++++
3 files changed, 83 insertions(+), 5 deletions(-)
diff --git a/src/server/config.rs b/src/server/config.rs
index cfba380..8e8da2a 100644
--- a/src/server/config.rs
+++ b/src/server/config.rs
@@ -41,6 +41,9 @@ pub struct Layout {
pub desktop_background: String,
pub transparency_opacity: f32,
pub window_opacity: bool,
+ pub desktop_grid_color: [f32; 4],
+ pub desktop_grid_scale: f64,
+ pub desktop_line_width: i32,
}
impl Default for Layout {
@@ -80,6 +83,9 @@ impl Default for Layout {
desktop_background: "#000000".to_string(),
transparency_opacity: 0.9,
window_opacity: true,
+ desktop_grid_color: [1.0, 1.0, 1.0, 0.05],
+ desktop_grid_scale: 100.0,
+ desktop_line_width: 1,
}
}
}
@@ -230,12 +236,21 @@ pub struct TransparencyConfig {
pub struct SurfacesConfig {
#[serde(default = "default_desktop_background")]
pub desktop_background: String,
+ #[serde(default = "default_desktop_grid_color")]
+ pub desktop_grid_color: String,
+ #[serde(default = "default_desktop_grid_scale")]
+ pub desktop_grid_scale: i64,
+ #[serde(default = "default_desktop_line_width")]
+ pub desktop_line_width: i64,
}
impl Default for SurfacesConfig {
fn default() -> Self {
Self {
desktop_background: default_desktop_background(),
+ desktop_grid_color: default_desktop_grid_color(),
+ desktop_grid_scale: default_desktop_grid_scale(),
+ desktop_line_width: default_desktop_line_width(),
}
}
}
@@ -244,6 +259,18 @@ fn default_desktop_background() -> String {
"#000000".to_string()
}
+fn default_desktop_grid_color() -> String {
+ "#ffffff0d".to_string()
+}
+
+fn default_desktop_grid_scale() -> i64 {
+ 100
+}
+
+fn default_desktop_line_width() -> i64 {
+ 1
+}
+
#[derive(Debug, Deserialize)]
pub struct Config {
@@ -421,6 +448,40 @@ pub fn parse_hex_color(hex_str: &str) -> u32 {
}
}
+pub fn parse_hex_color_rgba(hex_str: &str) -> [f32; 4] {
+ let hex = hex_str.trim_matches(|c| c == '"' || c == '\'' || c == ' ');
+ let hex = hex.trim_start_matches('#');
+ if hex.len() == 8 {
+ if let (Ok(r), Ok(g), Ok(b), Ok(a)) = (
+ u8::from_str_radix(&hex[0..2], 16),
+ u8::from_str_radix(&hex[2..4], 16),
+ u8::from_str_radix(&hex[4..6], 16),
+ u8::from_str_radix(&hex[6..8], 16),
+ ) {
+ return [
+ r as f32 / 255.0,
+ g as f32 / 255.0,
+ b as f32 / 255.0,
+ a as f32 / 255.0,
+ ];
+ }
+ } else if hex.len() == 6 {
+ if let (Ok(r), Ok(g), Ok(b)) = (
+ u8::from_str_radix(&hex[0..2], 16),
+ u8::from_str_radix(&hex[2..4], 16),
+ u8::from_str_radix(&hex[4..6], 16),
+ ) {
+ return [
+ r as f32 / 255.0,
+ g as f32 / 255.0,
+ b as f32 / 255.0,
+ 1.0,
+ ];
+ }
+ }
+ [1.0, 1.0, 1.0, 0.05] // fallback default (5% white)
+}
+
pub fn parse_tiling_mode(s: &str) -> TilingMode {
match s.to_lowercase().as_str() {
"floating" => TilingMode::Floating,
@@ -685,6 +746,10 @@ pub fn parse_config(path: &str, state: &mut crate::window_manager::WindowManager
state.layout.background_b = (background_color_val & 0xFF) * 0x01010101;
state.layout.background_a = 0xFFFFFFFF;
+ state.layout.desktop_grid_color = parse_hex_color_rgba(&config.surfaces.desktop_grid_color);
+ state.layout.desktop_grid_scale = config.surfaces.desktop_grid_scale as f64;
+ state.layout.desktop_line_width = config.surfaces.desktop_line_width as i32;
+
state.layout.border_font_size = config.layout.border_font_size as i32;
state.layout.transition_duration = config.layout.transition_duration as i32;
state.layout.grid_gap = config.layout.grid_gap as i32;
diff --git a/src/server/output.rs b/src/server/output.rs
index 986c586..1ca10e0 100644
--- a/src/server/output.rs
+++ b/src/server/output.rs
@@ -521,7 +521,7 @@ impl Output {
let zoom = wm.desk_zoom;
// Dynamic spacing based on zoom to avoid rendering too many lines (LOD)
- let mut grid_spacing = 100.0;
+ let mut grid_spacing = wm.layout.desktop_grid_scale;
while grid_spacing * zoom < 40.0 {
grid_spacing *= 2.0;
}
@@ -531,8 +531,8 @@ impl Output {
let min_y = wm.desk_pan_y;
let max_y = wm.desk_pan_y + (viewport_h as f64) / zoom;
- // Subtle semi-transparent grid color (e.g. 5% white)
- let grid_color: [f32; 4] = [1.0, 1.0, 1.0, 0.05];
+ // Subtle semi-transparent grid color from layout config
+ let grid_color: [f32; 4] = wm.layout.desktop_grid_color;
// Draw vertical lines
let mut x_val = (min_x / grid_spacing).ceil() * grid_spacing;
@@ -540,7 +540,7 @@ impl Output {
let rel_x = ((x_val - wm.desk_pan_x) * zoom) as i32;
let line_rect = ffi::wlr_scene_rect_create(
self.grid_tree,
- 1, // width of line
+ wm.layout.desktop_line_width, // width of line
viewport_h,
grid_color.as_ptr(),
);
@@ -561,7 +561,7 @@ impl Output {
let line_rect = ffi::wlr_scene_rect_create(
self.grid_tree,
viewport_w,
- 1, // height of line
+ wm.layout.desktop_line_width, // height of line
grid_color.as_ptr(),
);
if !line_rect.is_null() {
diff --git a/src/server/window_manager.rs b/src/server/window_manager.rs
index c889ee4..741a36c 100644
--- a/src/server/window_manager.rs
+++ b/src/server/window_manager.rs
@@ -2026,6 +2026,19 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
}
}
}
+ "desktop_grid_color" => {
+ self.layout.desktop_grid_color = crate::config::parse_hex_color_rgba(val);
+ }
+ "desktop_grid_scale" => {
+ if let Ok(v) = val.parse::<f64>() {
+ self.layout.desktop_grid_scale = v;
+ }
+ }
+ "desktop_line_width" => {
+ if let Ok(v) = val.parse::<i32>() {
+ self.layout.desktop_line_width = v;
+ }
+ }
"gap" => { if let Ok(v) = val.parse::<i32>() { self.layout.gap = v; } }
"gap_top" => { if let Ok(v) = val.parse::<i32>() { self.layout.gap_top = v; } }
"gap_left" => { if let Ok(v) = val.parse::<i32>() { self.layout.gap_left = v; } }