Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
feat(server): render desktop background using layout low_color config
src/server/config.rs | 33 +++++++++++++++++++++++++++++----
src/server/output.rs | 25 +++++++++++++++++++++++++
src/server/output_manager.rs | 30 ++++++++++++++++++++++++++++++
src/server/window_manager.rs | 13 +++++++++++++
4 files changed, 97 insertions(+), 4 deletions(-)
diff --git a/src/server/config.rs b/src/server/config.rs
index 74456c1..1ba3c81 100644
--- a/src/server/config.rs
+++ b/src/server/config.rs
@@ -38,6 +38,7 @@ pub struct Layout {
pub side_panel_border_gap: i32,
pub side_panel_border_opacity: i32,
pub status_normal_color: String,
+ pub low_color: String,
}
impl Default for Layout {
@@ -59,9 +60,9 @@ impl Default for Layout {
border_g: 0x3E3E3E3Eu32,
border_b: 0x3E3E3E3Eu32,
border_a: 0xFFFFFFFFu32,
- background_r: 0x0A0A0A0Au32,
- background_g: 0x1A1A1A1Au32,
- background_b: 0x0E0E0E0Eu32,
+ background_r: 0x1C1C1C1Cu32,
+ background_g: 0x20202020u32,
+ background_b: 0x20202020u32,
background_a: 0xFFFFFFFFu32,
border_font_size: 11,
transition_duration: 300,
@@ -74,6 +75,7 @@ impl Default for Layout {
side_panel_border_gap: 0,
side_panel_border_opacity: 100,
status_normal_color: "#ccccd8".to_string(),
+ low_color: "#1c2020".to_string(),
}
}
}
@@ -243,6 +245,8 @@ pub struct LayoutConfig {
pub border_color: String,
#[serde(default = "default_background_color")]
pub background_color: String,
+ #[serde(default)]
+ pub low_color: Option<String>,
#[serde(default = "default_border_font_size")]
pub border_font_size: i64,
#[serde(default = "default_transition_duration")]
@@ -284,6 +288,7 @@ impl Default for LayoutConfig {
floating_border_width: default_floating_border_width(),
border_color: default_border_color(),
background_color: default_background_color(),
+ low_color: None,
border_font_size: default_border_font_size(),
transition_duration: default_transition_duration(),
grid_gap: default_grid_gap(),
@@ -597,7 +602,10 @@ pub fn parse_config(path: &str, state: &mut crate::window_manager::WindowManager
state.layout.border_b = (border_color_val & 0xFF) * 0x01010101;
state.layout.border_a = 0xFFFFFFFF;
- let background_color_val = parse_hex_color(&config.layout.background_color);
+ let low_color_str = config.layout.low_color.clone().unwrap_or_else(|| config.layout.background_color.clone());
+ state.layout.low_color = low_color_str.clone();
+
+ let background_color_val = parse_hex_color(&low_color_str);
state.layout.background_r = ((background_color_val >> 16) & 0xFF) * 0x01010101;
state.layout.background_g = ((background_color_val >> 8) & 0xFF) * 0x01010101;
state.layout.background_b = (background_color_val & 0xFF) * 0x01010101;
@@ -710,6 +718,19 @@ pub fn parse_config(path: &str, state: &mut crate::window_manager::WindowManager
state.startup.len()
);
+ unsafe {
+ if !state.server.is_null() {
+ let outputs_head = &mut (*state.server).om.outputs as *mut crate::ffi::wl_list as *mut crate::server::WlList;
+ let mut curr = (*outputs_head).next;
+ while curr != outputs_head {
+ let next = (*curr).next;
+ let output = &mut *crate::container_of!(curr, crate::output::Output, link);
+ output.update_background_color();
+ curr = next;
+ }
+ }
+ }
+
Ok(())
}
@@ -733,6 +754,10 @@ mod tests {
assert_eq!(server.wm.input_config.dwtp, Some(true));
assert_eq!(server.wm.input_config.trackpoint_accel_speed, Some(0.6));
assert_eq!(server.wm.input_config.trackpoint_accel_profile, Some("flat".to_string()));
+ assert_eq!(server.wm.layout.low_color, "#1c2020");
+ assert_eq!(server.wm.layout.background_r, 0x1C1C1C1Cu32);
+ assert_eq!(server.wm.layout.background_g, 0x20202020u32);
+ assert_eq!(server.wm.layout.background_b, 0x20202020u32);
}
}
}
diff --git a/src/server/output.rs b/src/server/output.rs
index 4e642cc..402732e 100644
--- a/src/server/output.rs
+++ b/src/server/output.rs
@@ -140,6 +140,7 @@ pub struct Output {
pub server: *mut Server,
pub wlr_output: *mut ffi::wlr_output,
pub scene_output: *mut ffi::wlr_scene_output,
+ pub background_rect: *mut ffi::wlr_scene_rect,
pub object: *mut ffi::wl_resource, // river_output_v1 resource
pub layer_shell: LayerShellOutput,
pub lock_render_state: LockRenderState,
@@ -301,6 +302,11 @@ impl Output {
if self.scheduled.state == OutputStateValue::Destroying {
assert!(self.wlr_output.is_null());
+ if !self.background_rect.is_null() {
+ ffi::wlr_scene_node_destroy(self.background_rect as *mut ffi::wlr_scene_node);
+ self.background_rect = std::ptr::null_mut();
+ }
+
// remove output from windows fullscreen hint
for &window in (*self.server).wm.windows.iter() {
if let crate::window::FullscreenRequest::Fullscreen(out) = (*window).wm_scheduled.fullscreen_requested {
@@ -357,6 +363,7 @@ impl Output {
server,
wlr_output,
scene_output,
+ background_rect: std::ptr::null_mut(),
object: std::ptr::null_mut(),
layer_shell: LayerShellOutput::default(),
lock_render_state: LockRenderState::Blanked,
@@ -470,6 +477,19 @@ impl Output {
Ok(())
}
+
+ pub unsafe fn update_background_color(&mut self) {
+ if !self.background_rect.is_null() {
+ let wm = &(*self.server).wm;
+ let color: [f32; 4] = [
+ (wm.layout.background_r as f64 / u32::MAX as f64) as f32,
+ (wm.layout.background_g as f64 / u32::MAX as f64) as f32,
+ (wm.layout.background_b as f64 / u32::MAX as f64) as f32,
+ (wm.layout.background_a as f64 / u32::MAX as f64) as f32,
+ ];
+ ffi::wlr_scene_rect_set_color(self.background_rect, color.as_ptr());
+ }
+ }
}
unsafe extern "C" fn handle_destroy(listener: *mut ffi::wl_listener, _data: *mut std::ffi::c_void) {
@@ -483,6 +503,11 @@ unsafe extern "C" fn handle_destroy(listener: *mut ffi::wl_listener, _data: *mut
wl_listener_remove(&mut (*output).frame);
wl_listener_remove(&mut (*output).present);
+ if !(*output).background_rect.is_null() {
+ ffi::wlr_scene_node_destroy((*output).background_rect as *mut ffi::wlr_scene_node);
+ (*output).background_rect = std::ptr::null_mut();
+ }
+
if !(*output).wlr_output.is_null() {
ffi::river_wlr_output_set_data((*output).wlr_output, std::ptr::null_mut());
}
diff --git a/src/server/output_manager.rs b/src/server/output_manager.rs
index 4ac5ac3..043d76f 100644
--- a/src/server/output_manager.rs
+++ b/src/server/output_manager.rs
@@ -199,9 +199,39 @@ impl OutputManager {
output.sent.y,
);
}
+
+ let (width, height) = output.sent.dimensions();
+ let color: [f32; 4] = [
+ ((*server).wm.layout.background_r as f64 / u32::MAX as f64) as f32,
+ ((*server).wm.layout.background_g as f64 / u32::MAX as f64) as f32,
+ ((*server).wm.layout.background_b as f64 / u32::MAX as f64) as f32,
+ ((*server).wm.layout.background_a as f64 / u32::MAX as f64) as f32,
+ ];
+ if output.background_rect.is_null() {
+ output.background_rect = ffi::wlr_scene_rect_create(
+ (*server).scene.layers.background,
+ width,
+ height,
+ color.as_ptr(),
+ );
+ } else {
+ ffi::wlr_scene_rect_set_size(output.background_rect, width, height);
+ ffi::wlr_scene_rect_set_color(output.background_rect, color.as_ptr());
+ }
+ if !output.background_rect.is_null() {
+ ffi::wlr_scene_node_set_position(
+ output.background_rect as *mut ffi::wlr_scene_node,
+ output.sent.x,
+ output.sent.y,
+ );
+ }
}
OutputStateValue::DisabledHard => {
ffi::wlr_output_layout_remove(self.output_layout, wlr_output);
+ if !output.background_rect.is_null() {
+ ffi::wlr_scene_node_destroy(output.background_rect as *mut ffi::wlr_scene_node);
+ output.background_rect = std::ptr::null_mut();
+ }
}
OutputStateValue::Destroying => unreachable!(),
}
diff --git a/src/server/window_manager.rs b/src/server/window_manager.rs
index c705c96..44fff9a 100644
--- a/src/server/window_manager.rs
+++ b/src/server/window_manager.rs
@@ -1493,6 +1493,19 @@ impl WindowManager {
self.execute_action(&crate::config::Action::Exit, None);
"ok\n".to_string()
}
+ "reload" => {
+ if let Some(path) = crate::config::default_config_path() {
+ match crate::config::parse_config(&path, self) {
+ Ok(()) => {
+ self.dirty_windowing();
+ "ok\n".to_string()
+ }
+ Err(e) => format!("error: failed to reload config: {}\n", e),
+ }
+ } else {
+ "error: no config file found\n".to_string()
+ }
+ }
"retile" => {
self.dirty_windowing();
"ok\n".to_string()