Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
Implement status hide mode with configurable preview height
src/server/config.rs | 9 ++++++++
src/server/layer_shell.rs | 49 ++++++++++++++++++++++++++++++--------------
src/server/window_manager.rs | 33 ++++++++++++++++++++++++-----
3 files changed, 71 insertions(+), 20 deletions(-)
diff --git a/src/server/config.rs b/src/server/config.rs
index 1e7acc6..75ec41c 100644
--- a/src/server/config.rs
+++ b/src/server/config.rs
@@ -53,6 +53,7 @@ pub struct Layout {
pub scenefx_optimized_blur: bool,
pub status_backdrop_blur_ignore_transparent: bool,
pub window_backdrop_blur_ignore_transparent: bool,
+ pub status_module_hide_mode_preview: i64,
}
impl Default for Layout {
@@ -104,6 +105,7 @@ impl Default for Layout {
scenefx_optimized_blur: true,
status_backdrop_blur_ignore_transparent: true,
window_backdrop_blur_ignore_transparent: true,
+ status_module_hide_mode_preview: 4,
}
}
}
@@ -441,6 +443,8 @@ pub struct LayoutConfig {
pub status_backdrop_blur_ignore_transparent: bool,
#[serde(default = "default_window_backdrop_blur_ignore_transparent")]
pub window_backdrop_blur_ignore_transparent: bool,
+ #[serde(default = "default_status_module_hide_mode_preview")]
+ pub status_module_hide_mode_preview: i64,
}
impl Default for LayoutConfig {
@@ -465,6 +469,7 @@ impl Default for LayoutConfig {
window_opacity: default_window_opacity(),
status_backdrop_blur_ignore_transparent: default_status_backdrop_blur_ignore_transparent(),
window_backdrop_blur_ignore_transparent: default_window_backdrop_blur_ignore_transparent(),
+ status_module_hide_mode_preview: default_status_module_hide_mode_preview(),
}
}
}
@@ -487,6 +492,8 @@ fn default_status_normal_color() -> String { "#ccccd8".to_string() }
fn default_status_background_blur() -> f64 { 0.8 }
fn default_window_opacity() -> bool { true }
fn default_status_backdrop_blur_ignore_transparent() -> bool { true }
+
+fn default_status_module_hide_mode_preview() -> i64 { 4 }
fn default_window_backdrop_blur_ignore_transparent() -> bool { true }
#[derive(Debug, Deserialize)]
@@ -1022,6 +1029,7 @@ fn parse_kdl_config(content: &str) -> Result<Config, String> {
layout.status_normal_color = get_nested_prop_string(node, "status", "normal_color", &default_status_normal_color());
layout.status_background_blur = get_nested_prop_f64(node, "status", "background_blur", default_status_background_blur());
layout.status_backdrop_blur_ignore_transparent = get_nested_prop_bool(node, "status", "backdrop_blur_ignore_transparent", default_status_backdrop_blur_ignore_transparent());
+ layout.status_module_hide_mode_preview = get_nested_prop_i64(node, "status", "module_hide_mode_preview", default_status_module_hide_mode_preview());
}
// 2. env
@@ -1446,6 +1454,7 @@ pub fn parse_config(path: &str, state: &mut crate::window_manager::WindowManager
state.layout.scenefx_optimized_blur = config.output.as_ref().map(|o| o.scenefx_optimized_blur).unwrap_or(true);
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;
for (key, val) in &config.env {
let expanded = expand_env_vars(val);
diff --git a/src/server/layer_shell.rs b/src/server/layer_shell.rs
index da7c5d3..e665589 100644
--- a/src/server/layer_shell.rs
+++ b/src/server/layer_shell.rs
@@ -648,6 +648,7 @@ unsafe extern "C" fn handle_layer_surface_commit(listener: *mut ffi::wl_listener
let mut parent_x = None;
let mut parent_y = None;
let mut parent_w = 0;
+
for &win_ptr in (*server).wm.windows.iter() {
if win_ptr.is_null() || (*win_ptr).closed {
continue;
@@ -663,25 +664,43 @@ unsafe extern "C" fn handle_layer_surface_commit(listener: *mut ffi::wl_listener
}
if let (Some(px), Some(py)) = (parent_x, parent_y) {
- let wlr_box = (*output).sent.box_layout();
- let output_x = wlr_box.x;
- let output_y = wlr_box.y;
- let output_w = wlr_box.width;
+ let wlr_output = (*wlr_layer_surface).output;
+ if !wlr_output.is_null() {
+ let mut output_x = 0;
+ let mut output_y = 0;
+ let mut output_w = 0;
+ let outputs_list = &mut (*server).om.outputs as *mut ffi::wl_list as *mut WlList;
+ let mut curr_out = (*outputs_list).next;
+ while curr_out != outputs_list {
+ let output = crate::container_of!(curr_out, crate::output::Output, link);
+ if (*output).wlr_output == wlr_output {
+ let wlr_box = (*output).sent.box_layout();
+ output_x = wlr_box.x;
+ output_y = wlr_box.y;
+ output_w = wlr_box.width;
+ break;
+ }
+ curr_out = (*curr_out).next;
+ }
- let relative_parent_x = px - output_x;
- let relative_parent_y = py - output_y;
+ let relative_parent_x = px - output_x;
+ let relative_parent_y = py - output_y;
- let anchor = (*wlr_layer_surface).current.anchor;
- let is_align_right = (anchor & ffi::zwlr_layer_surface_v1_anchor_ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) != 0;
+ let anchor = (*wlr_layer_surface).current.anchor;
+ let is_align_right = (anchor & ffi::zwlr_layer_surface_v1_anchor_ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) != 0;
- if is_align_right {
- (*wlr_layer_surface).current.margin.right = (output_w - relative_parent_x - parent_w) + (*wlr_layer_surface).current.margin.right;
- } else {
- (*wlr_layer_surface).current.margin.left = relative_parent_x + (*wlr_layer_surface).current.margin.left;
- }
- (*wlr_layer_surface).current.margin.top = relative_parent_y + (*wlr_layer_surface).current.margin.top;
+ if is_align_right {
+ (*wlr_layer_surface).pending.margin.right = (output_w - relative_parent_x - parent_w) + (*wlr_layer_surface).pending.margin.right;
+ (*wlr_layer_surface).current.margin.right = (*wlr_layer_surface).pending.margin.right;
+ } else {
+ (*wlr_layer_surface).pending.margin.left = relative_parent_x + (*wlr_layer_surface).pending.margin.left;
+ (*wlr_layer_surface).current.margin.left = (*wlr_layer_surface).pending.margin.left;
+ }
+ (*wlr_layer_surface).pending.margin.top = relative_parent_y + (*wlr_layer_surface).pending.margin.top;
+ (*wlr_layer_surface).current.margin.top = (*wlr_layer_surface).pending.margin.top;
- (*layer_surface).parent_offset_applied = true;
+ (*layer_surface).parent_offset_applied = true;
+ }
}
}
}
diff --git a/src/server/window_manager.rs b/src/server/window_manager.rs
index c5bd076..29eb74b 100644
--- a/src/server/window_manager.rs
+++ b/src/server/window_manager.rs
@@ -108,6 +108,7 @@ pub struct WindowManager {
pub input_rules: Vec<crate::config::InputDeviceConfigRule>,
pub input_config: crate::config::InputConfig,
pub last_status_update: std::cell::RefCell<Option<crate::status_server::StatusUpdate>>,
+ pub status_hide_mode: bool,
pub restore_queue: Vec<SavedWindowState>,
pub last_window_states: Vec<SavedWindowState>,
pub shutting_down: bool,
@@ -193,6 +194,7 @@ impl WindowManager {
self.input_rules = Vec::new();
self.input_config = crate::config::InputConfig::default();
self.last_status_update = std::cell::RefCell::new(None);
+ self.status_hide_mode = false;
ffi::wl_list_init(&mut self.sent.outputs);
ffi::wl_list_init(&mut self.sent.seats);
@@ -1591,14 +1593,21 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
let spacing = 12;
let margin = 12;
+ let status_y = if self.status_hide_mode {
+ let preview = self.layout.status_module_hide_mode_preview as i32;
+ wlr_box.y - (bar_h as i32 - preview)
+ } else {
+ wlr_box.y
+ };
+
// Layout Left status windows
let mut cur_left_x = wlr_box.x + margin;
for win_ptr in left_status {
let w = if (*win_ptr).box_geom.width > 0 { (*win_ptr).box_geom.width as u32 } else { 100 };
let app_id = (*win_ptr).get_app_id_string().unwrap_or_default();
- log::info!("[ArrangeStatus] Left module app_id={} x={} y={} w={}", app_id, cur_left_x, wlr_box.y, w);
+ log::info!("[ArrangeStatus] Left module app_id={} x={} y={} w={}", app_id, cur_left_x, status_y, w);
(*win_ptr).rendering_requested.x = cur_left_x;
- (*win_ptr).rendering_requested.y = wlr_box.y;
+ (*win_ptr).rendering_requested.y = status_y;
(*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions {
width: w,
height: bar_h,
@@ -1617,9 +1626,9 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
let w = if actual_w > 0 { actual_w as u32 } else { 100 };
let x = cur_right_x - w as i32;
let app_id = (*win_ptr).get_app_id_string().unwrap_or_default();
- log::info!("[ArrangeStatus] Right module app_id={} actual_box_w={} x={} y={} w={}", app_id, actual_w, x, wlr_box.y, w);
+ log::info!("[ArrangeStatus] Right module app_id={} actual_box_w={} x={} y={} w={}", app_id, actual_w, x, status_y, w);
(*win_ptr).rendering_requested.x = x;
- (*win_ptr).rendering_requested.y = wlr_box.y;
+ (*win_ptr).rendering_requested.y = status_y;
(*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions {
width: w,
height: bar_h,
@@ -1634,7 +1643,7 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
// Layout Full/Legacy status windows
for win_ptr in full_status {
(*win_ptr).rendering_requested.x = wlr_box.x;
- (*win_ptr).rendering_requested.y = wlr_box.y;
+ (*win_ptr).rendering_requested.y = status_y;
(*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions {
width: wlr_box.width as u32,
height: bar_h,
@@ -2369,6 +2378,20 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
self.stop_panning_animation();
}
match action {
+ "status-hide-mode" => {
+ let enable = if parts.len() >= 2 {
+ match parts[1] {
+ "true" | "on" | "enable" | "1" => true,
+ "false" | "off" | "disable" | "0" => false,
+ _ => !self.status_hide_mode,
+ }
+ } else {
+ !self.status_hide_mode
+ };
+ self.status_hide_mode = enable;
+ self.dirty_windowing();
+ return format!("ok {}\n", enable);
+ }
"view" => {
if parts.len() < 2 { return "error: missing tag\n".to_string(); }
if let Ok(tag) = parts[1].parse::<i32>() {