From abbe94e6e14efa165647b1a0b95ee3e5a98a972f Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Tue, 10 Oct 2023 13:55:34 -0400 Subject: [PATCH] feat: theme integration refactor: only apply updates if there is a change in the theme refactor: include theme in state cleanup: theme integration --- Cargo.lock | 30 ++-- Cargo.toml | 6 +- src/backend/kms/mod.rs | 10 +- src/backend/render/mod.rs | 26 ++-- src/config/mod.rs | 14 -- src/input/mod.rs | 1 - src/main.rs | 5 + src/shell/element/mod.rs | 22 ++- src/shell/element/resize_indicator.rs | 2 + src/shell/element/stack.rs | 13 +- src/shell/element/stack_hover.rs | 3 +- src/shell/element/swap_indicator.rs | 7 +- src/shell/element/window.rs | 10 ++ src/shell/grabs/moving.rs | 16 ++- src/shell/layout/floating/mod.rs | 11 +- src/shell/layout/tiling/grabs/resize.rs | 4 +- src/shell/layout/tiling/mod.rs | 181 ++++++++++++++++-------- src/shell/mod.rs | 78 +++++++--- src/shell/workspace.rs | 10 +- src/state.rs | 4 + src/theme.rs | 77 ++++++++++ src/utils/iced.rs | 8 +- src/wayland/handlers/screencopy.rs | 9 +- src/wayland/handlers/xdg_shell/mod.rs | 1 + 24 files changed, 409 insertions(+), 139 deletions(-) create mode 100644 src/theme.rs diff --git a/Cargo.lock b/Cargo.lock index 79256024..6450d483 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -576,7 +576,7 @@ dependencies = [ [[package]] name = "cosmic-config" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic/?rev=f91287d#f91287dec2297df41a339c1106850c4cf179f67f" +source = "git+https://github.com/pop-os/libcosmic/?branch=theme-dark-light-switching#0a63eaaff3091796e5f59ed0598f7b0616066e78" dependencies = [ "atomicwrites", "calloop 0.12.2", @@ -591,7 +591,7 @@ dependencies = [ [[package]] name = "cosmic-config-derive" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic/?rev=f91287d#f91287dec2297df41a339c1106850c4cf179f67f" +source = "git+https://github.com/pop-os/libcosmic/?branch=theme-dark-light-switching#0a63eaaff3091796e5f59ed0598f7b0616066e78" dependencies = [ "quote", "syn 1.0.109", @@ -632,7 +632,7 @@ dependencies = [ [[package]] name = "cosmic-theme" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic/?rev=f91287d#f91287dec2297df41a339c1106850c4cf179f67f" +source = "git+https://github.com/pop-os/libcosmic/?branch=theme-dark-light-switching#0a63eaaff3091796e5f59ed0598f7b0616066e78" dependencies = [ "almost", "cosmic-config", @@ -1801,7 +1801,7 @@ dependencies = [ [[package]] name = "iced" version = "0.10.0" -source = "git+https://github.com/pop-os/libcosmic/?rev=f91287d#f91287dec2297df41a339c1106850c4cf179f67f" +source = "git+https://github.com/pop-os/libcosmic/?branch=theme-dark-light-switching#0a63eaaff3091796e5f59ed0598f7b0616066e78" dependencies = [ "iced_core", "iced_futures", @@ -1814,7 +1814,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.10.0" -source = "git+https://github.com/pop-os/libcosmic/?rev=f91287d#f91287dec2297df41a339c1106850c4cf179f67f" +source = "git+https://github.com/pop-os/libcosmic/?branch=theme-dark-light-switching#0a63eaaff3091796e5f59ed0598f7b0616066e78" dependencies = [ "bitflags 1.3.2", "instant", @@ -1827,7 +1827,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.7.0" -source = "git+https://github.com/pop-os/libcosmic/?rev=f91287d#f91287dec2297df41a339c1106850c4cf179f67f" +source = "git+https://github.com/pop-os/libcosmic/?branch=theme-dark-light-switching#0a63eaaff3091796e5f59ed0598f7b0616066e78" dependencies = [ "futures", "iced_core", @@ -1839,7 +1839,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.9.0" -source = "git+https://github.com/pop-os/libcosmic/?rev=f91287d#f91287dec2297df41a339c1106850c4cf179f67f" +source = "git+https://github.com/pop-os/libcosmic/?branch=theme-dark-light-switching#0a63eaaff3091796e5f59ed0598f7b0616066e78" dependencies = [ "bitflags 1.3.2", "bytemuck", @@ -1857,7 +1857,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic/?rev=f91287d#f91287dec2297df41a339c1106850c4cf179f67f" +source = "git+https://github.com/pop-os/libcosmic/?branch=theme-dark-light-switching#0a63eaaff3091796e5f59ed0598f7b0616066e78" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -1870,7 +1870,7 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.1.1" -source = "git+https://github.com/pop-os/libcosmic/?rev=f91287d#f91287dec2297df41a339c1106850c4cf179f67f" +source = "git+https://github.com/pop-os/libcosmic/?branch=theme-dark-light-switching#0a63eaaff3091796e5f59ed0598f7b0616066e78" dependencies = [ "iced_core", "iced_futures", @@ -1880,7 +1880,7 @@ dependencies = [ [[package]] name = "iced_style" version = "0.9.0" -source = "git+https://github.com/pop-os/libcosmic/?rev=f91287d#f91287dec2297df41a339c1106850c4cf179f67f" +source = "git+https://github.com/pop-os/libcosmic/?branch=theme-dark-light-switching#0a63eaaff3091796e5f59ed0598f7b0616066e78" dependencies = [ "iced_core", "once_cell", @@ -1890,7 +1890,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic/?rev=f91287d#f91287dec2297df41a339c1106850c4cf179f67f" +source = "git+https://github.com/pop-os/libcosmic/?branch=theme-dark-light-switching#0a63eaaff3091796e5f59ed0598f7b0616066e78" dependencies = [ "bytemuck", "cosmic-text", @@ -1908,7 +1908,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.11.1" -source = "git+https://github.com/pop-os/libcosmic/?rev=f91287d#f91287dec2297df41a339c1106850c4cf179f67f" +source = "git+https://github.com/pop-os/libcosmic/?branch=theme-dark-light-switching#0a63eaaff3091796e5f59ed0598f7b0616066e78" dependencies = [ "bitflags 1.3.2", "bytemuck", @@ -1930,7 +1930,7 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.1.3" -source = "git+https://github.com/pop-os/libcosmic/?rev=f91287d#f91287dec2297df41a339c1106850c4cf179f67f" +source = "git+https://github.com/pop-os/libcosmic/?branch=theme-dark-light-switching#0a63eaaff3091796e5f59ed0598f7b0616066e78" dependencies = [ "iced_renderer", "iced_runtime", @@ -2242,7 +2242,7 @@ checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "libcosmic" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic/?rev=f91287d#f91287dec2297df41a339c1106850c4cf179f67f" +source = "git+https://github.com/pop-os/libcosmic/?branch=theme-dark-light-switching#0a63eaaff3091796e5f59ed0598f7b0616066e78" dependencies = [ "apply", "cosmic-config", @@ -4126,7 +4126,7 @@ dependencies = [ [[package]] name = "taffy" version = "0.3.11" -source = "git+https://github.com/DioxusLabs/taffy#120bb7a2e501822b324fd48de955450ebbba1c1a" +source = "git+https://github.com/DioxusLabs/taffy?rev=65bedf#65bedf128ec8cef40c1a21b6f141f2c771842cca" dependencies = [ "arrayvec", "grid", diff --git a/Cargo.toml b/Cargo.toml index bcaf1e9f..60ee157c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,10 +36,10 @@ libsystemd = { version = "0.6", optional = true } wayland-backend = "0.3.2" wayland-scanner = "0.31.0" cosmic-comp-config = { path = "cosmic-comp-config" } -cosmic-config = { git = "https://github.com/pop-os/libcosmic/", rev = "f91287d", features = ["calloop"] } +cosmic-config = { git = "https://github.com/pop-os/libcosmic/", features = ["calloop", "macro"], branch = "theme-dark-light-switching"} cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", branch = "main", default-features = false, features = ["server"] } -libcosmic = { git = "https://github.com/pop-os/libcosmic/", rev = "f91287d", default-features = false } -iced_tiny_skia = { git = "https://github.com/pop-os/libcosmic/", rev = "f91287d" } +libcosmic = { git = "https://github.com/pop-os/libcosmic/", default-features = false, branch = "theme-dark-light-switching" } +iced_tiny_skia = { git = "https://github.com/pop-os/libcosmic/", branch = "theme-dark-light-switching" } tiny-skia = "0.10" ordered-float = "4.0" glow = "0.12.0" diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index 47df6c33..aad54127 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -3,7 +3,7 @@ #[cfg(feature = "debug")] use crate::backend::render::element::AsGlowRenderer; use crate::{ - backend::render::{workspace_elements, CLEAR_COLOR}, + backend::render::workspace_elements, config::OutputConfig, shell::Shell, state::{BackendData, ClientState, Common, Fps, SurfaceDmabufFeedback}, @@ -1241,8 +1241,12 @@ impl Surface { })?; self.fps.elements(); - let res = - compositor.render_frame::<_, _, GlesTexture>(&mut renderer, &elements, CLEAR_COLOR); + let theme = state.theme.cosmic(); + let res = compositor.render_frame::<_, _, GlesTexture>( + &mut renderer, + &elements, + crate::theme::clear_color(&theme), + ); self.fps.render(); match res { diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index 725c6b9e..5e7796fa 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -78,11 +78,6 @@ pub type GlMultiFrame<'a, 'b, 'frame> = MultiFrame<'a, 'a, 'b, 'frame, GbmGlesBackend, GbmGlesBackend>; pub type GlMultiError = MultiError, GbmGlesBackend>; -pub static CLEAR_COLOR: [f32; 4] = [0.153, 0.161, 0.165, 1.0]; -pub static GROUP_COLOR: [f32; 3] = [0.788, 0.788, 0.788]; -pub static ACTIVE_GROUP_COLOR: [f32; 3] = [0.58, 0.922, 0.922]; -pub static FOCUS_INDICATOR_COLOR: [f32; 3] = [0.580, 0.921, 0.921]; - pub static OUTLINE_SHADER: &str = include_str!("./shaders/rounded_outline.frag"); pub static RECTANGLE_SHADER: &str = include_str!("./shaders/rounded_rectangle.frag"); @@ -164,6 +159,7 @@ impl IndicatorShader { thickness: u8, scale: f64, alpha: f32, + active_window_hint: [f32; 3], ) -> PixelShaderElement { let t = thickness as i32; element_geo.loc -= (t, t).into(); @@ -177,7 +173,7 @@ impl IndicatorShader { thickness * 2, alpha, scale, - FOCUS_INDICATOR_COLOR, + active_window_hint, ) } @@ -413,13 +409,14 @@ where ); } + let theme = state.theme.cosmic(); if let Some(grab_elements) = seat .user_data() .get::() .unwrap() .borrow() .as_ref() - .map(|state| state.render::(renderer, seat, output)) + .map(|state| state.render::(renderer, seat, output, theme)) { elements.extend(grab_elements); } @@ -449,6 +446,7 @@ where #[cfg(feature = "debug")] puffin::profile_function!(); + let theme = state.theme.cosmic(); let mut elements = cursor_elements(renderer, state, output, cursor_mode); #[cfg(feature = "debug")] @@ -544,6 +542,7 @@ where } else { Vec::new() }; + let active_hint = theme.active_hint as u8; let offset = match previous.as_ref() { Some((previous, previous_idx, start)) => { @@ -584,7 +583,8 @@ where (!move_active && is_active_space).then_some(&last_active_seat), overview.clone(), resize_indicator.clone(), - state.config.static_conf.active_hint, + active_hint, + theme, ) .map_err(|_| OutputNoMode)?; elements.extend(p_elements.into_iter().map(|p_element| { @@ -641,7 +641,8 @@ where (!move_active && is_active_space).then_some(&last_active_seat), overview, resize_indicator, - state.config.static_conf.active_hint, + active_hint, + theme, ) .map_err(|_| OutputNoMode)?; elements.extend(p_elements.into_iter().map(|p_element| { @@ -913,7 +914,12 @@ where } renderer.bind(target).map_err(RenderError::Rendering)?; - let res = damage_tracker.render_output(renderer, age, &elements, CLEAR_COLOR); + let res = damage_tracker.render_output( + renderer, + age, + &elements, + crate::theme::clear_color(state.theme.cosmic()), + ); if let Some(fps) = fps.as_mut() { fps.render(); diff --git a/src/config/mod.rs b/src/config/mod.rs index c783a080..8640b6a8 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -50,10 +50,6 @@ pub struct StaticConfig { #[serde(default = "default_workspace_layout")] pub workspace_layout: WorkspaceLayout, pub tiling_enabled: bool, - #[serde(default = "default_active_hint")] - pub active_hint: u8, - #[serde(default = "default_gaps")] - pub gaps: (u8, u8), } #[derive(Debug, Deserialize, Clone, Copy, PartialEq, Eq)] @@ -100,14 +96,6 @@ fn default_enabled() -> bool { true } -fn default_active_hint() -> u8 { - 4 -} - -fn default_gaps() -> (u8, u8) { - (0, 4) -} - fn default_workspace_layout() -> WorkspaceLayout { WorkspaceLayout::Vertical } @@ -219,8 +207,6 @@ impl Config { workspace_amount: WorkspaceAmount::Dynamic, workspace_layout: WorkspaceLayout::Vertical, tiling_enabled: false, - active_hint: default_active_hint(), - gaps: default_gaps(), } } diff --git a/src/input/mod.rs b/src/input/mod.rs index e7bae32b..aeb2658c 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -214,7 +214,6 @@ impl State { ::PointerAxisEvent: 'static, { use smithay::backend::input::Event; - match event { InputEvent::DeviceAdded { device } => { let seat = &mut self.common.last_active_seat(); diff --git a/src/main.rs b/src/main.rs index e87ab39d..732998e4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,7 @@ pub mod shell; pub mod state; #[cfg(feature = "systemd")] pub mod systemd; +pub mod theme; pub mod utils; pub mod wayland; pub mod xwayland; @@ -55,6 +56,10 @@ fn main() -> Result<()> { // potentially tell the session we are setup now session::setup_socket(event_loop.handle(), &state)?; + if let Err(err) = theme::watch_theme(event_loop.handle()) { + warn!(?err, "Failed to watch theme"); + } + // run the event loop event_loop.run(None, &mut state, |state| { // shall we shut down? diff --git a/src/shell/element/mod.rs b/src/shell/element/mod.rs index 78df78ba..ca8b20cf 100644 --- a/src/shell/element/mod.rs +++ b/src/shell/element/mod.rs @@ -501,6 +501,7 @@ impl CosmicMapped { pub fn convert_to_stack<'a>( &mut self, (output, overlap): (&'a Output, Rectangle), + theme: cosmic::Theme, ) { match &self.element { CosmicMappedInternal::Window(window) => { @@ -508,7 +509,7 @@ impl CosmicMapped { let activated = surface.is_activated(true); let handle = window.loop_handle(); - let stack = CosmicStack::new(std::iter::once(surface), handle); + let stack = CosmicStack::new(std::iter::once(surface), handle, theme); if let Some(geo) = self.last_geometry.lock().unwrap().clone() { stack.set_geometry(geo.to_global(&output)); } @@ -527,11 +528,12 @@ impl CosmicMapped { &mut self, surface: CosmicSurface, (output, overlap): (&'a Output, Rectangle), + theme: cosmic::Theme, ) { let handle = self.loop_handle(); surface.try_force_undecorated(false); surface.set_tiled(false); - let window = CosmicWindow::new(surface, handle); + let window = CosmicWindow::new(surface, handle, theme); if let Some(geo) = self.last_geometry.lock().unwrap().clone() { window.set_geometry(geo.to_global(&output)); @@ -764,6 +766,22 @@ impl CosmicMapped { popup_elements.into_iter().map(C::from).collect(), ) } + + pub(crate) fn update_theme(&self, theme: cosmic::Theme) { + match &self.element { + CosmicMappedInternal::Window(w) => w.set_theme(theme), + CosmicMappedInternal::Stack(s) => s.set_theme(theme), + CosmicMappedInternal::_GenericCatcher(_) => {} + } + } + + pub(crate) fn force_redraw(&self) { + match &self.element { + CosmicMappedInternal::Window(w) => w.force_redraw(), + CosmicMappedInternal::Stack(s) => s.force_redraw(), + CosmicMappedInternal::_GenericCatcher(_) => {} + } + } } impl IsAlive for CosmicMapped { diff --git a/src/shell/element/resize_indicator.rs b/src/shell/element/resize_indicator.rs index 4752a68b..e16cff25 100644 --- a/src/shell/element/resize_indicator.rs +++ b/src/shell/element/resize_indicator.rs @@ -23,6 +23,7 @@ pub fn resize_indicator( direction: ResizeDirection, config: &Config, evlh: LoopHandle<'static, crate::state::State>, + theme: cosmic::Theme, ) -> ResizeIndicator { ResizeIndicator::new( ResizeIndicatorInternal { @@ -49,6 +50,7 @@ pub fn resize_indicator( }, Size::from((1, 1)), evlh, + theme, ) } diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index 54478b3a..7cda6936 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -129,6 +129,7 @@ impl CosmicStack { pub fn new>( windows: impl Iterator, handle: LoopHandle<'static, crate::state::State>, + theme: cosmic::Theme, ) -> CosmicStack { let windows = windows.map(Into::into).collect::>(); assert!(!windows.is_empty()); @@ -160,6 +161,7 @@ impl CosmicStack { }, (width, TAB_HEIGHT), handle, + theme, )) } @@ -544,6 +546,14 @@ impl CosmicStack { popup_elements.into_iter().map(C::from).collect(), ) } + + pub(crate) fn set_theme(&self, theme: cosmic::Theme) { + self.0.set_theme(theme); + } + + pub(crate) fn force_redraw(&self) { + self.0.force_redraw(); + } } #[derive(Debug, Clone, Copy)] @@ -1056,11 +1066,12 @@ impl PointerTarget for CosmicStack { let mapped = CosmicMapped::from(CosmicWindow::new( surface, self.0.loop_handle(), + data.common.theme.clone(), )); let elem_geo = workspace.element_geometry(stack_mapped).unwrap(); let indicator_thickness = - data.common.config.static_conf.active_hint; + data.common.theme.cosmic().active_hint as u8; let was_tiled = workspace.is_tiled(stack_mapped); self.remove_idx(dragged_out); diff --git a/src/shell/element/stack_hover.rs b/src/shell/element/stack_hover.rs index a84520d3..1877d123 100644 --- a/src/shell/element/stack_hover.rs +++ b/src/shell/element/stack_hover.rs @@ -18,8 +18,9 @@ pub type StackHover = IcedElement; pub fn stack_hover( evlh: LoopHandle<'static, crate::state::State>, size: Size, + theme: cosmic::Theme, ) -> StackHover { - StackHover::new(StackHoverInternal, size, evlh) + StackHover::new(StackHoverInternal, size, evlh, theme) } pub struct StackHoverInternal; diff --git a/src/shell/element/swap_indicator.rs b/src/shell/element/swap_indicator.rs index 75b011ef..380bf2e6 100644 --- a/src/shell/element/swap_indicator.rs +++ b/src/shell/element/swap_indicator.rs @@ -15,8 +15,11 @@ use smithay::utils::Size; pub type SwapIndicator = IcedElement; -pub fn swap_indicator(evlh: LoopHandle<'static, crate::state::State>) -> SwapIndicator { - SwapIndicator::new(SwapIndicatorInternal, Size::from((1, 1)), evlh) +pub fn swap_indicator( + evlh: LoopHandle<'static, crate::state::State>, + theme: cosmic::Theme, +) -> SwapIndicator { + SwapIndicator::new(SwapIndicatorInternal, Size::from((1, 1)), evlh, theme) } pub struct SwapIndicatorInternal; diff --git a/src/shell/element/window.rs b/src/shell/element/window.rs index 1e45ed0b..ed82aeda 100644 --- a/src/shell/element/window.rs +++ b/src/shell/element/window.rs @@ -114,6 +114,7 @@ impl CosmicWindow { pub fn new( window: impl Into, handle: LoopHandle<'static, crate::state::State>, + theme: cosmic::Theme, ) -> CosmicWindow { let window = window.into(); let width = window.geometry().size.w; @@ -129,6 +130,7 @@ impl CosmicWindow { }, (width, SSD_HEIGHT), handle, + theme, )) } @@ -213,6 +215,14 @@ impl CosmicWindow { popup_elements.into_iter().map(C::from).collect(), ) } + + pub(crate) fn set_theme(&self, theme: cosmic::Theme) { + self.0.set_theme(theme); + } + + pub(crate) fn force_redraw(&self) { + self.0.force_redraw(); + } } #[derive(Debug, Clone, Copy)] diff --git a/src/shell/grabs/moving.rs b/src/shell/grabs/moving.rs index eda33d31..778a5780 100644 --- a/src/shell/grabs/moving.rs +++ b/src/shell/grabs/moving.rs @@ -17,6 +17,7 @@ use crate::{ utils::prelude::*, }; +use cosmic::theme::CosmicTheme; use smithay::{ backend::renderer::{ element::{utils::RescaleRenderElement, AsRenderElements, RenderElement}, @@ -58,7 +59,13 @@ pub struct MoveGrabState { } impl MoveGrabState { - pub fn render(&self, renderer: &mut R, seat: &Seat, output: &Output) -> Vec + pub fn render( + &self, + renderer: &mut R, + seat: &Seat, + output: &Output, + theme: &CosmicTheme, + ) -> Vec where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: 'static, @@ -103,6 +110,7 @@ impl MoveGrabState { + self.window_offset - scaling_offset; + let active_window_hint = crate::theme::active_window_hint(theme); let focus_element = if self.indicator_thickness > 0 { Some( CosmicMappedRenderElement::from(IndicatorShader::focus_element( @@ -121,6 +129,11 @@ impl MoveGrabState { self.indicator_thickness, output_scale.x, alpha, + [ + active_window_hint.red, + active_window_hint.green, + active_window_hint.blue, + ], )) .into(), ) @@ -277,6 +290,7 @@ impl PointerGrab for MoveGrab { let element = stack_hover( state.common.event_loop_handle.clone(), geo.size.as_logical(), + state.common.theme.clone(), ); for output in &self.window_outputs { element.output_enter( diff --git a/src/shell/layout/floating/mod.rs b/src/shell/layout/floating/mod.rs index f4de3793..a06b8458 100644 --- a/src/shell/layout/floating/mod.rs +++ b/src/shell/layout/floating/mod.rs @@ -364,6 +364,7 @@ impl FloatingLayout { &mut self, direction: Direction, seat: &Seat, + theme: cosmic::Theme, ) -> MoveResult { let Some(target) = seat.get_keyboard().unwrap().current_focus() else { return MoveResult::None @@ -388,7 +389,7 @@ impl FloatingLayout { match focused.handle_move(direction) { StackMoveResult::Handled => return MoveResult::Done, StackMoveResult::MoveOut(surface, loop_handle) => { - let mapped: CosmicMapped = CosmicWindow::new(surface, loop_handle).into(); + let mapped: CosmicMapped = CosmicWindow::new(surface, loop_handle, theme).into(); let output = seat.active_output(); let pos = self.space.element_geometry(focused).unwrap().loc + match direction { @@ -464,6 +465,7 @@ impl FloatingLayout { mut resize_indicator: Option<(ResizeMode, ResizeIndicator)>, indicator_thickness: u8, alpha: f32, + theme: &cosmic::theme::CosmicTheme, ) -> ( Vec>, Vec>, @@ -521,6 +523,8 @@ impl FloatingLayout { ); } + let active_window_hint = crate::theme::active_window_hint(theme); + if indicator_thickness > 0 { let element = IndicatorShader::focus_element( renderer, @@ -529,6 +533,11 @@ impl FloatingLayout { indicator_thickness, output_scale, alpha, + [ + active_window_hint.red, + active_window_hint.green, + active_window_hint.blue, + ], ); window_elements.push(element.into()); } diff --git a/src/shell/layout/tiling/grabs/resize.rs b/src/shell/layout/tiling/grabs/resize.rs index db9dbfcb..80e8e4dc 100644 --- a/src/shell/layout/tiling/grabs/resize.rs +++ b/src/shell/layout/tiling/grabs/resize.rs @@ -137,6 +137,8 @@ impl PointerGrab for ResizeForkGrab { if let Some(output) = self.output.upgrade() { let tiling_layer = &mut data.common.shell.active_space_mut(&output).tiling_layer; + let gaps = tiling_layer.gaps(); + let tree = &mut tiling_layer.queue.trees.back_mut().unwrap().0; if tree.get(&self.node).is_ok() { let delta = match self.orientation { @@ -191,7 +193,7 @@ impl PointerGrab for ResizeForkGrab { } self.last_loc = event.location; - let blocker = TilingLayout::update_positions(&output, tree, tiling_layer.gaps); + let blocker = TilingLayout::update_positions(&output, tree, gaps); tiling_layer.pending_blockers.extend(blocker); } else { handle.unset_grab(data, event.serial, event.time); diff --git a/src/shell/layout/tiling/mod.rs b/src/shell/layout/tiling/mod.rs index 7fb4399e..1e6d0207 100644 --- a/src/shell/layout/tiling/mod.rs +++ b/src/shell/layout/tiling/mod.rs @@ -1,10 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::{ - backend::render::{ - element::AsGlowRenderer, BackdropShader, IndicatorShader, Key, Usage, ACTIVE_GROUP_COLOR, - GROUP_COLOR, - }, + backend::render::{element::AsGlowRenderer, BackdropShader, IndicatorShader, Key, Usage}, shell::{ element::{ resize_indicator::ResizeIndicator, @@ -25,6 +22,7 @@ use crate::{ CosmicSurface, Direction, FocusResult, MoveResult, OutputNotMapped, OverviewMode, ResizeDirection, ResizeMode, Trigger, }, + theme::group_color, utils::{prelude::*, tween::EaseRectangle}, wayland::{ handlers::xdg_shell::popup::get_popup_toplevel, @@ -116,13 +114,13 @@ impl TreeQueue { #[derive(Debug, Clone)] pub struct TilingLayout { - gaps: (i32, i32), output: Output, queue: TreeQueue, pending_blockers: Vec, placeholder_id: Id, swapping_stack_surface_id: Id, last_overview_hover: Option<(Option, TargetZone)>, + pub theme: cosmic::Theme, } #[derive(Debug, Clone, PartialEq)] @@ -317,9 +315,8 @@ enum FocusedNodeData { } impl TilingLayout { - pub fn new(gaps: (u8, u8), output: &Output) -> TilingLayout { + pub fn new(theme: cosmic::Theme, output: &Output) -> TilingLayout { TilingLayout { - gaps: (gaps.0 as i32, gaps.1 as i32), queue: TreeQueue { trees: { let mut queue = VecDeque::new(); @@ -333,10 +330,12 @@ impl TilingLayout { placeholder_id: Id::new(), swapping_stack_surface_id: Id::new(), last_overview_hover: None, + theme, } } pub fn set_output(&mut self, output: &Output) { + let gaps = self.gaps(); let mut tree = self.queue.trees.back().unwrap().0.copy_clone(); for node in tree @@ -355,7 +354,7 @@ impl TilingLayout { } } - let blocker = TilingLayout::update_positions(output, &mut tree, self.gaps); + let blocker = TilingLayout::update_positions(output, &mut tree, gaps); self.queue.push_tree(tree, None, blocker); self.output = output.clone(); } @@ -377,9 +376,11 @@ impl TilingLayout { focus_stack: Option + 'a>, direction: Option, ) { + let gaps = self.gaps(); + let mut tree = self.queue.trees.back().unwrap().0.copy_clone(); TilingLayout::map_to_tree(&mut tree, window, &self.output, focus_stack, direction); - let blocker = TilingLayout::update_positions(&self.output, &mut tree, self.gaps); + let blocker = TilingLayout::update_positions(&self.output, &mut tree, gaps); self.queue.push_tree(tree, ANIMATION_DURATION, blocker); } @@ -466,6 +467,7 @@ impl TilingLayout { } pub fn replace_window(&mut self, old: &CosmicMapped, new: &CosmicMapped) { + let gaps = self.gaps(); let Some(old_id) = old.tiling_node_id.lock().unwrap().clone() else { return }; let mut tree = self.queue.trees.back().unwrap().0.copy_clone(); @@ -484,7 +486,7 @@ impl TilingLayout { old.output_leave(&self.output); new.output_enter(&self.output, new.bbox()); - let blocker = TilingLayout::update_positions(&self.output, &mut tree, self.gaps); + let blocker = TilingLayout::update_positions(&self.output, &mut tree, gaps); self.queue.push_tree(tree, ANIMATION_DURATION, blocker); } } @@ -513,7 +515,8 @@ impl TilingLayout { } let mapped: CosmicMapped = - CosmicWindow::new(stack_surface, this_stack.loop_handle()).into(); + CosmicWindow::new(stack_surface, this_stack.loop_handle(), this.theme.clone()) + .into(); if this.output != other.output { mapped.output_leave(&this.output); mapped.output_enter(&other.output, mapped.bbox()); @@ -635,13 +638,15 @@ impl TilingLayout { ); } } + let this_gaps = this.gaps(); + let other_gaps = other.gaps(); let blocker = - TilingLayout::update_positions(&this.output, &mut this_tree, this.gaps); + TilingLayout::update_positions(&this.output, &mut this_tree, this_gaps); this.queue.push_tree(this_tree, ANIMATION_DURATION, blocker); let blocker = - TilingLayout::update_positions(&other.output, &mut other_tree, other.gaps); + TilingLayout::update_positions(&other.output, &mut other_tree, other_gaps); other .queue .push_tree(other_tree, ANIMATION_DURATION, blocker); @@ -900,8 +905,12 @@ impl TilingLayout { } this_stack.remove_window(&this_surface); - let mapped: CosmicMapped = - CosmicWindow::new(this_surface.clone(), this_stack.loop_handle()).into(); + let mapped: CosmicMapped = CosmicWindow::new( + this_surface.clone(), + this_stack.loop_handle(), + this.theme.clone(), + ) + .into(); mapped.set_tiled(true); mapped.refresh(); if this.output != other_output { @@ -977,8 +986,12 @@ impl TilingLayout { } other_stack.remove_window(&other_surface); - let mapped: CosmicMapped = - CosmicWindow::new(other_surface.clone(), other_stack.loop_handle()).into(); + let mapped: CosmicMapped = CosmicWindow::new( + other_surface.clone(), + other_stack.loop_handle(), + this.theme.clone(), + ) + .into(); mapped.set_tiled(true); mapped.refresh(); if this.output != other_output { @@ -1063,15 +1076,17 @@ impl TilingLayout { } } - let blocker = TilingLayout::update_positions(&this.output, &mut this_tree, this.gaps); + let this_gaps = this.gaps(); + let blocker = TilingLayout::update_positions(&this.output, &mut this_tree, this_gaps); this.queue.push_tree(this_tree, ANIMATION_DURATION, blocker); let has_other_tree = other_tree.is_some(); if let Some(mut other_tree) = other_tree { let (other_queue, gaps) = if let Some(other) = other.as_mut() { - (&mut other.queue, other.gaps) + let other_gaps = other.gaps(); + (&mut other.queue, other_gaps) } else { - (&mut this.queue, this.gaps) + (&mut this.queue, this_gaps) }; let blocker = TilingLayout::update_positions(&other_output, &mut other_tree, gaps); other_queue.push_tree(other_tree, ANIMATION_DURATION, blocker); @@ -1144,6 +1159,8 @@ impl TilingLayout { fn unmap_window_internal(&mut self, mapped: &CosmicMapped) -> bool { let tiling_node_id = mapped.tiling_node_id.lock().unwrap().as_ref().cloned(); + let gaps = self.gaps(); + if let Some(node_id) = tiling_node_id { if self .queue @@ -1159,7 +1176,7 @@ impl TilingLayout { TilingLayout::unmap_internal(&mut tree, &node_id); - let blocker = TilingLayout::update_positions(&self.output, &mut tree, self.gaps); + let blocker = TilingLayout::update_positions(&self.output, &mut tree, gaps); self.queue.push_tree(tree, ANIMATION_DURATION, blocker); return true; @@ -1241,6 +1258,8 @@ impl TilingLayout { direction: Direction, seat: &Seat, ) -> MoveResult { + let gaps = self.gaps(); + let mut tree = self.queue.trees.back().unwrap().0.copy_clone(); let Some(target) = seat.get_keyboard().unwrap().current_focus() else { @@ -1257,7 +1276,8 @@ impl TilingLayout { match window.handle_move(direction) { StackMoveResult::Handled => return MoveResult::Done, StackMoveResult::MoveOut(surface, loop_handle) => { - let mapped: CosmicMapped = CosmicWindow::new(surface, loop_handle).into(); + let mapped: CosmicMapped = + CosmicWindow::new(surface, loop_handle, self.theme.clone()).into(); mapped.output_enter(&self.output, mapped.bbox()); let orientation = match direction { Direction::Left | Direction::Right => Orientation::Vertical, @@ -1280,8 +1300,7 @@ impl TilingLayout { .unwrap(); *mapped.tiling_node_id.lock().unwrap() = Some(new_id); - let blocker = - TilingLayout::update_positions(&self.output, &mut tree, self.gaps); + let blocker = TilingLayout::update_positions(&self.output, &mut tree, gaps); self.queue.push_tree(tree, ANIMATION_DURATION, blocker); return MoveResult::ShiftFocus(mapped.into()); } @@ -1357,7 +1376,7 @@ impl TilingLayout { .data_mut() .remove_window(og_idx); - let blocker = TilingLayout::update_positions(&self.output, &mut tree, self.gaps); + let blocker = TilingLayout::update_positions(&self.output, &mut tree, gaps); self.queue.push_tree(tree, ANIMATION_DURATION, blocker); return MoveResult::Done; } @@ -1383,7 +1402,7 @@ impl TilingLayout { .data_mut() .remove_window(og_idx); - let blocker = TilingLayout::update_positions(&self.output, &mut tree, self.gaps); + let blocker = TilingLayout::update_positions(&self.output, &mut tree, gaps); self.queue.push_tree(tree, ANIMATION_DURATION, blocker); return MoveResult::Done; } @@ -1539,7 +1558,7 @@ impl TilingLayout { MoveResult::Done }; - let blocker = TilingLayout::update_positions(&self.output, &mut tree, self.gaps); + let blocker = TilingLayout::update_positions(&self.output, &mut tree, gaps); self.queue.push_tree(tree, ANIMATION_DURATION, blocker); return result; } @@ -1836,6 +1855,8 @@ impl TilingLayout { new_orientation: Option, seat: &Seat, ) { + let gaps = self.gaps(); + let Some(target) = seat.get_keyboard().unwrap().current_focus() else { return; }; @@ -1871,8 +1892,7 @@ impl TilingLayout { *orientation = new_orientation; - let blocker = - TilingLayout::update_positions(&self.output, &mut tree, self.gaps); + let blocker = TilingLayout::update_positions(&self.output, &mut tree, gaps); self.queue.push_tree(tree, ANIMATION_DURATION, blocker); } } @@ -1880,6 +1900,8 @@ impl TilingLayout { } pub fn toggle_stacking<'a>(&mut self, seat: &Seat, mut focus_stack: FocusStackMut) { + let gaps = self.gaps(); + let Some(target) = seat.get_keyboard().unwrap().current_focus() else { return; }; @@ -1894,7 +1916,10 @@ impl TilingLayout { // if it is just a window match tree.get_mut(&last_active).unwrap().data_mut() { Data::Mapped { mapped, .. } => { - mapped.convert_to_stack((&self.output, mapped.bbox())); + mapped.convert_to_stack( + (&self.output, mapped.bbox()), + self.theme.clone(), + ); focus_stack.append(&mapped); } _ => unreachable!(), @@ -1907,7 +1932,11 @@ impl TilingLayout { let handle = match tree.get_mut(&last_active).unwrap().data_mut() { Data::Mapped { mapped, .. } => { let handle = mapped.loop_handle(); - mapped.convert_to_surface(first, (&self.output, mapped.bbox())); + mapped.convert_to_surface( + first, + (&self.output, mapped.bbox()), + self.theme.clone(), + ); focus_stack.append(&mapped); handle } @@ -1918,8 +1947,11 @@ impl TilingLayout { for other in surfaces { other.try_force_undecorated(false); other.set_tiled(false); - let window = - CosmicMapped::from(CosmicWindow::new(other, handle.clone())); + let window = CosmicMapped::from(CosmicWindow::new( + other, + handle.clone(), + self.theme.clone(), + )); window.output_enter(&self.output, window.bbox()); { @@ -1960,7 +1992,7 @@ impl TilingLayout { return; } let handle = handle.unwrap(); - let stack = CosmicStack::new(surfaces.into_iter(), handle); + let stack = CosmicStack::new(surfaces.into_iter(), handle, self.theme.clone()); for child in tree .children_ids(&last_active) @@ -1992,14 +2024,16 @@ impl TilingLayout { } } - let blocker = TilingLayout::update_positions(&self.output, &mut tree, self.gaps); + let blocker = TilingLayout::update_positions(&self.output, &mut tree, gaps); self.queue.push_tree(tree, ANIMATION_DURATION, blocker); } } pub fn recalculate(&mut self) { + let gaps = self.gaps(); + let mut tree = self.queue.trees.back().unwrap().0.copy_clone(); - let blocker = TilingLayout::update_positions(&self.output, &mut tree, self.gaps); + let blocker = TilingLayout::update_positions(&self.output, &mut tree, gaps); self.queue.push_tree(tree, ANIMATION_DURATION, blocker); } @@ -2136,6 +2170,8 @@ impl TilingLayout { edges: ResizeEdge, amount: i32, ) -> bool { + let gaps = self.gaps(); + let mut tree = self.queue.trees.back().unwrap().0.copy_clone(); let Some(root_id) = tree.root_node_id() else { return false }; let Some(mut node_id) = @@ -2214,7 +2250,7 @@ impl TilingLayout { } _ => unreachable!(), } - let blocker = TilingLayout::update_positions(&self.output, &mut tree, self.gaps); + let blocker = TilingLayout::update_positions(&self.output, &mut tree, gaps); self.queue.push_tree(tree, None, blocker); return true; @@ -2234,6 +2270,8 @@ impl TilingLayout { } pub fn cleanup_drag(&mut self) { + let gaps = self.gaps(); + let mut tree = self.queue.trees.back().unwrap().0.copy_clone(); if let Some(root) = tree.root_node_id() { @@ -2252,12 +2290,14 @@ impl TilingLayout { } } - let blocker = TilingLayout::update_positions(&self.output, &mut tree, self.gaps); + let blocker = TilingLayout::update_positions(&self.output, &mut tree, gaps); self.queue.push_tree(tree, ANIMATION_DURATION, blocker); } } pub fn drop_window(&mut self, window: CosmicMapped) -> (CosmicMapped, Point) { + let gaps = self.gaps(); + let mut tree = self.queue.trees.back().unwrap().0.copy_clone(); window.output_enter(&self.output, window.bbox()); @@ -2358,7 +2398,7 @@ impl TilingLayout { Some(TargetZone::WindowStack(window_id, _)) if tree.get(&window_id).is_ok() => { match tree.get_mut(window_id).unwrap().data_mut() { Data::Mapped { mapped, .. } => { - mapped.convert_to_stack((&self.output, mapped.bbox())); + mapped.convert_to_stack((&self.output, mapped.bbox()), self.theme.clone()); let Some(stack) = mapped.stack_ref_mut() else { unreachable!() }; @@ -2399,7 +2439,7 @@ impl TilingLayout { } } - let blocker = TilingLayout::update_positions(&self.output, &mut tree, self.gaps); + let blocker = TilingLayout::update_positions(&self.output, &mut tree, gaps); self.queue.push_tree(tree, ANIMATION_DURATION, blocker); let location = self.element_geometry(&mapped).unwrap().loc; @@ -2728,9 +2768,9 @@ impl TilingLayout { location: Point, overview: OverviewMode, ) -> Option<(PointerFocusTarget, Point)> { + let gaps = self.gaps(); let last_overview_hover = &mut self.last_overview_hover; let placeholder_id = &self.placeholder_id; - let gaps = &self.gaps; let tree = &self.queue.trees.back().unwrap().0; let root = tree.root_node_id()?; let location = location.to_i32_round(); @@ -2850,6 +2890,7 @@ impl TilingLayout { Some(None), None, None, + self.theme.cosmic(), ) .0; @@ -3275,7 +3316,7 @@ impl TilingLayout { let blocker = TilingLayout::update_positions( &self.output, &mut tree, - *gaps, + gaps, ); self.queue.push_tree(tree, duration, blocker); } @@ -3372,6 +3413,8 @@ impl TilingLayout { } pub fn merge(&mut self, mut other: TilingLayout) { + let gaps = self.gaps(); + let src = other.queue.trees.pop_back().unwrap().0; let mut dst = self.queue.trees.back().unwrap().0.copy_clone(); @@ -3381,7 +3424,7 @@ impl TilingLayout { }; TilingLayout::merge_trees(src, &mut dst, orientation); - let blocker = TilingLayout::update_positions(&self.output, &mut dst, self.gaps); + let blocker = TilingLayout::update_positions(&self.output, &mut dst, gaps); self.queue.push_tree(dst, ANIMATION_DURATION, blocker); } @@ -3432,6 +3475,7 @@ impl TilingLayout { overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree>)>), resize_indicator: Option<(ResizeMode, ResizeIndicator)>, indicator_thickness: u8, + theme: &cosmic::theme::CosmicTheme, ) -> Result< ( Vec>, @@ -3502,6 +3546,7 @@ impl TilingLayout { is_mouse_tiling, swap_desc.clone(), overview.1.as_ref().and_then(|(_, tree)| tree.clone()), + theme, )) } else { None @@ -3539,6 +3584,7 @@ impl TilingLayout { is_mouse_tiling, swap_desc.clone(), overview.1.as_ref().and_then(|(_, tree)| tree.clone()), + theme, )) } else { None @@ -3573,6 +3619,7 @@ impl TilingLayout { swap_desc.clone(), &self.swapping_stack_surface_id, &self.placeholder_id, + theme, ); window_elements.extend(w_elements); popup_elements.extend(p_elements); @@ -3584,6 +3631,11 @@ impl TilingLayout { Ok((window_elements, popup_elements)) } + + fn gaps(&self) -> (i32, i32) { + let g = self.theme.cosmic().gaps; + (g.0 as i32, g.1 as i32) + } } const GAP_KEYBOARD: i32 = 8; @@ -3631,6 +3683,7 @@ fn geometries_for_groupview<'a, R>( mouse_tiling: Option>, swap_desc: Option, swap_tree: Option<&Tree>, + theme: &cosmic::theme::CosmicTheme, ) -> ( HashMap>, Vec>, @@ -3788,6 +3841,8 @@ where ) }; + let group_color = group_color(theme); + match data { Data::Group { orientation, @@ -3825,7 +3880,7 @@ where if render_active_child { 16 } else { 8 }, alpha * if render_potential_group { 0.40 } else { 1.0 }, output_scale, - GROUP_COLOR, + group_color, ) .into(), ); @@ -3843,7 +3898,7 @@ where 8, alpha * 0.40, output_scale, - GROUP_COLOR, + group_color, ) .into(), ); @@ -3907,7 +3962,7 @@ where 8, alpha * 0.15, output_scale, - GROUP_COLOR, + group_color, ) .into(), ); @@ -3971,7 +4026,7 @@ where pill_geo, 8., alpha * 0.4, - GROUP_COLOR, + group_color, ) .into(), ); @@ -4001,7 +4056,7 @@ where } else { 0.15 }, - GROUP_COLOR, + group_color, ) .into(), ); @@ -4077,7 +4132,7 @@ where ), 8., alpha * 0.4, - GROUP_COLOR, + group_color, ) .into(), ); @@ -4119,7 +4174,7 @@ where ), 8., alpha * 0.4, - GROUP_COLOR, + group_color, ) .into(), ); @@ -4150,7 +4205,7 @@ where 8, alpha * 0.40, output_scale, - GROUP_COLOR, + group_color, ) .into(), ); @@ -4158,6 +4213,8 @@ where geo.size -= (gap * 2, gap * 2).into(); } + let accent = theme.accent.base; + if focused .as_ref() .map(|focused_id| { @@ -4172,9 +4229,9 @@ where Some(Some(TargetZone::WindowStack(stack_id, _))) if *stack_id == node_id => { - ACTIVE_GROUP_COLOR + [accent.red, accent.green, accent.blue] } - _ => GROUP_COLOR, + _ => group_color, }; geo.loc += (WINDOW_BACKDROP_BORDER, WINDOW_BACKDROP_BORDER).into(); geo.size -= @@ -4189,7 +4246,9 @@ where * if focused .as_ref() .map(|focused_id| focused_id == &node_id) - .unwrap_or(color == ACTIVE_GROUP_COLOR) + .unwrap_or( + color == [accent.red, accent.green, accent.blue], + ) { 0.4 } else { @@ -4243,7 +4302,7 @@ where geo, 8., alpha * 0.4, - GROUP_COLOR, + group_color, ) .into(), ); @@ -4417,6 +4476,7 @@ fn render_new_tree( swap_desc: Option, swapping_stack_surface_id: &Id, placeholder_id: &Id, + theme: &cosmic::theme::CosmicTheme, ) -> ( Vec>, Vec>, @@ -4476,7 +4536,8 @@ where let (swap_indicator, swap_tree) = overview.1.unzip(); let swap_tree = swap_tree.flatten().filter(|_| is_active_output); let swap_desc = swap_desc.filter(|_| is_active_output); - + let window_hint = crate::theme::active_window_hint(theme); + let group_color = group_color(theme); // render placeholder, if we are swapping to an empty workspace if target_tree.root_node_id().is_none() && swap_desc.is_some() { window_elements.push( @@ -4486,7 +4547,7 @@ where focused_geo, 8., transition.unwrap_or(1.0) * 0.4, - GROUP_COLOR, + group_color, ) .into(), ); @@ -4518,6 +4579,7 @@ where 4, output_scale, transition.unwrap_or(1.0), + [window_hint.red, window_hint.green, window_hint.blue], )); let render_loc = @@ -4679,7 +4741,7 @@ where geo, 8., 0.4, - GROUP_COLOR, + group_color, )); } @@ -4706,6 +4768,7 @@ where }, output_scale, 1.0, + [window_hint.red, window_hint.green, window_hint.blue], )); } @@ -4825,7 +4888,7 @@ where geo, 0.0, 0.3, - GROUP_COLOR, + group_color, )), ) } diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 1b57f0c9..a2907e5e 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -163,6 +163,7 @@ pub struct Shell { pub xdg_shell_state: XdgShellState, pub workspace_state: WorkspaceState, + theme: cosmic::Theme, overview_mode: OverviewMode, swap_indicator: Option, resize_mode: ResizeMode, @@ -184,8 +185,8 @@ pub struct WorkspaceSet { group: WorkspaceGroupHandle, idx: usize, tiling_enabled: bool, - gaps: (u8, u8), output: Output, + theme: cosmic::Theme, pub(crate) workspaces: Vec, } @@ -201,7 +202,7 @@ fn create_workspace( group_handle: &WorkspaceGroupHandle, active: bool, tiling: bool, - gaps: (u8, u8), + theme: cosmic::Theme, ) -> Workspace { let workspace_handle = state.create_workspace(&group_handle).unwrap(); if active { @@ -211,7 +212,7 @@ fn create_workspace( &workspace_handle, [WorkspaceCapabilities::Activate].into_iter(), ); - Workspace::new(workspace_handle, output.clone(), tiling, gaps) + Workspace::new(workspace_handle, output.clone(), tiling, theme.clone()) } impl WorkspaceSet { @@ -222,12 +223,18 @@ impl WorkspaceSet { amount: WorkspaceAmount, idx: usize, tiling_enabled: bool, - gaps: (u8, u8), + theme: cosmic::Theme, ) -> WorkspaceSet { let workspaces = match amount { WorkspaceAmount::Dynamic => { - let workspace = - create_workspace(state, output, &group_handle, true, tiling_enabled, gaps); + let workspace = create_workspace( + state, + output, + &group_handle, + true, + tiling_enabled, + theme.clone(), + ); workspace_set_idx(state, 1, idx, &workspace.handle); state.set_workspace_capabilities( &workspace.handle, @@ -243,7 +250,7 @@ impl WorkspaceSet { &group_handle, i == 0, tiling_enabled, - gaps, + theme.clone(), ); workspace_set_idx(state, i + 1, idx, &workspace.handle); state.set_workspace_capabilities( @@ -261,7 +268,7 @@ impl WorkspaceSet { group: group_handle, idx, tiling_enabled, - gaps, + theme, workspaces, output: output.clone(), } @@ -316,7 +323,7 @@ impl WorkspaceSet { &self.group, false, self.tiling_enabled, - self.gaps, + self.theme.clone(), ); workspace_set_idx( state, @@ -411,7 +418,7 @@ impl WorkspaceSet { &self.group, false, self.tiling_enabled, - self.gaps, + self.theme.clone(), ); workspace_set_idx( state, @@ -452,18 +459,18 @@ pub struct Workspaces { amount: WorkspaceAmount, mode: WorkspaceMode, tiling_enabled: bool, - gaps: (u8, u8), + theme: cosmic::Theme, } impl Workspaces { - pub fn new(config: &Config) -> Workspaces { + pub fn new(config: &Config, theme: cosmic::Theme) -> Workspaces { Workspaces { sets: IndexMap::new(), backup_set: None, amount: config.static_conf.workspace_amount, mode: config.static_conf.workspace_mode, tiling_enabled: config.static_conf.tiling_enabled, - gaps: config.static_conf.gaps, + theme, } } @@ -500,7 +507,7 @@ impl Workspaces { self.amount, self.sets.len(), self.tiling_enabled, - self.gaps, + self.theme.clone(), ) }); workspace_state.add_group_output(&set.group, &output); @@ -674,7 +681,7 @@ impl Workspaces { &group, false, config.static_conf.tiling_enabled, - config.static_conf.gaps, + self.theme.clone(), ), ); // Otherwise just update @@ -882,6 +889,24 @@ impl Workspaces { set.update_tiling_status(seat, tiling) } } + + pub fn set_theme(&mut self, theme: cosmic::Theme) { + for (_, s) in &mut self.sets { + s.theme = theme.clone(); + for mut w in &mut s.workspaces { + w.tiling_layer.theme = theme.clone(); + + w.mapped().for_each(|m| { + m.update_theme(theme.clone()); + m.force_redraw(); + }); + + w.refresh(); + w.dirty.store(true, Ordering::Relaxed); + w.recalculate(); + } + } + } } pub struct InvalidWorkspaceIndex; @@ -910,10 +935,11 @@ impl Shell { //|client| client.get_data::().map_or(false, |s| s.privileged), client_has_security_context, ); + let theme = cosmic::theme::system_preference(); Shell { popups: PopupManager::default(), - workspaces: Workspaces::new(config), + workspaces: Workspaces::new(config, theme.clone()), maximize_mode: MaximizeMode::Floating, pending_windows: Vec::new(), @@ -926,6 +952,7 @@ impl Shell { xdg_shell_state, workspace_state, + theme, overview_mode: OverviewMode::None, swap_indicator: None, resize_mode: ResizeMode::None, @@ -1158,7 +1185,7 @@ impl Shell { if let Some(trigger) = enabled { if !matches!(self.overview_mode, OverviewMode::Started(_, _)) { if matches!(trigger, Trigger::KeyboardSwap(_, _)) { - self.swap_indicator = Some(swap_indicator(evlh)); + self.swap_indicator = Some(swap_indicator(evlh, self.theme.clone())); } self.overview_mode = OverviewMode::Started(trigger, Instant::now()); } @@ -1204,7 +1231,12 @@ impl Shell { } else { self.resize_mode = ResizeMode::Started(pattern, Instant::now(), direction); } - self.resize_indicator = Some(resize_indicator(direction, config, evlh)); + self.resize_indicator = Some(resize_indicator( + direction, + config, + evlh, + self.theme.clone(), + )); } else { if let ResizeMode::Started(_, _, direction) = &self.resize_mode { self.resize_mode = ResizeMode::Ended(Instant::now(), *direction); @@ -1338,6 +1370,7 @@ impl Shell { let mapped = CosmicMapped::from(CosmicWindow::new( window.clone(), state.common.event_loop_handle.clone(), + state.common.theme.clone(), )); #[cfg(feature = "debug")] { @@ -1579,12 +1612,13 @@ impl Shell { .find(|(w, _)| w.wl_surface().as_ref() == Some(surface)) .unwrap(); let button = start_data.button; + let active_hint = state.common.theme.cosmic().active_hint as u8; if let Some(grab) = workspace.move_request( &window, &seat, &output, start_data, - state.common.config.static_conf.active_hint, + active_hint as u8, ) { let handle = workspace.handle; state @@ -1684,6 +1718,12 @@ impl Shell { } } } + + pub(crate) fn set_theme(&mut self, theme: cosmic::Theme) { + self.theme = theme.clone(); + self.refresh(); + self.workspaces.set_theme(theme.clone()); + } } fn workspace_set_idx<'a>( diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index 57ce5874..97ce3eb9 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -21,6 +21,7 @@ use crate::{ xwayland::XWaylandState, }; +use cosmic::theme::CosmicTheme; use id_tree::Tree; use indexmap::IndexSet; use keyframe::{ease, functions::EaseInOutCubic}; @@ -210,9 +211,9 @@ impl Workspace { handle: WorkspaceHandle, output: Output, tiling_enabled: bool, - gaps: (u8, u8), + theme: cosmic::Theme, ) -> Workspace { - let tiling_layer = TilingLayout::new(gaps, &output); + let tiling_layer = TilingLayout::new(theme, &output); let floating_layer = FloatingLayout::new(&output); Workspace { @@ -824,7 +825,7 @@ impl Workspace { MoveResult::MoveFurther(KeyboardFocusTarget::Fullscreen(f.surface.clone())) } else { self.floating_layer - .move_current_element(direction, seat) + .move_current_element(direction, seat, self.tiling_layer.theme.clone()) .or_else(|| self.tiling_layer.move_current_node(direction, seat)) } } @@ -838,6 +839,7 @@ impl Workspace { overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree>)>), resize_indicator: Option<(ResizeMode, ResizeIndicator)>, indicator_thickness: u8, + theme: &CosmicTheme, ) -> Result< ( Vec>, @@ -1014,6 +1016,7 @@ impl Workspace { resize_indicator.clone(), indicator_thickness, alpha, + theme, ); popup_elements.extend(p_elements.into_iter().map(WorkspaceRenderElement::from)); window_elements.extend(w_elements.into_iter().map(WorkspaceRenderElement::from)); @@ -1038,6 +1041,7 @@ impl Workspace { overview, resize_indicator, indicator_thickness, + theme, )?; popup_elements.extend(p_elements.into_iter().map(WorkspaceRenderElement::from)); window_elements.extend(w_elements.into_iter().map(WorkspaceRenderElement::from)); diff --git a/src/state.rs b/src/state.rs index 9149684d..07e17e22 100644 --- a/src/state.rs +++ b/src/state.rs @@ -137,6 +137,8 @@ pub struct Common { pub clock: Clock, pub should_stop: bool, + pub theme: cosmic::Theme, + #[cfg(feature = "debug")] pub egui: Egui, @@ -330,6 +332,8 @@ impl State { clock, should_stop: false, + theme: cosmic::theme::system_preference(), + #[cfg(feature = "debug")] egui: Egui { active: false, diff --git a/src/theme.rs b/src/theme.rs new file mode 100644 index 00000000..e6837800 --- /dev/null +++ b/src/theme.rs @@ -0,0 +1,77 @@ +// insert into the event loop, a watcher for the theme & theme mode for changes + +// update a Arc> in the state on change of the theme and mark all interfaces for a redraw. + +use calloop::LoopHandle; +use cosmic::cosmic_theme::{ + palette::{self, Srgba}, + Theme, ThemeMode, +}; + +use crate::state::State; + +pub(crate) fn clear_color(theme: &Theme) -> [f32; 4] { + let neutral_2 = theme.palette.neutral_2; + [ + neutral_2.red, + neutral_2.green, + neutral_2.blue, + neutral_2.alpha, + ] +} + +pub(crate) fn group_color(theme: &Theme) -> [f32; 3] { + let neutral_8 = theme.palette.neutral_8; + [neutral_8.red, neutral_8.green, neutral_8.blue] +} + +pub(crate) fn active_window_hint(theme: &Theme) -> palette::Srgba { + if let Some(hint) = theme.window_hint { + palette::Srgba::from(hint) + } else { + theme.accent_color() + } +} + +pub fn watch_theme(handle: LoopHandle<'_, State>) -> Result<(), cosmic_config::Error> { + let (ping_tx, ping_rx) = calloop::ping::make_ping().unwrap(); + let config_mode_helper = ThemeMode::config()?; + let config_dark_helper = Theme::::dark_config()?; + let config_light_helper = Theme::::light_config()?; + + if let Err(e) = handle.insert_source(ping_rx, move |_, _, state| { + let new_theme = cosmic::theme::system_preference(); + let theme = &mut state.common.theme; + + if theme.theme_type != new_theme.theme_type { + *theme = new_theme; + state.common.shell.set_theme(theme.clone()); + state.common.shell.workspaces.spaces().for_each(|s| { + s.mapped().for_each(|m| { + m.update_theme(theme.clone()); + m.force_redraw(); + }) + }); + } + }) { + tracing::error!("{e}"); + }; + + let ping_tx_clone = ping_tx.clone(); + let theme_watcher_mode = config_mode_helper.watch(move |_, _keys| { + ping_tx_clone.ping(); + })?; + let ping_tx_clone = ping_tx.clone(); + let theme_watcher_light = config_light_helper.watch(move |_, _keys| { + ping_tx_clone.ping(); + })?; + let theme_watcher_dark = config_dark_helper.watch(move |_, _keys| { + ping_tx.ping(); + })?; + + std::mem::forget(theme_watcher_dark); + std::mem::forget(theme_watcher_light); + std::mem::forget(theme_watcher_mode); + + Ok(()) +} diff --git a/src/utils/iced.rs b/src/utils/iced.rs index 614d943d..a3a0cf13 100644 --- a/src/utils/iced.rs +++ b/src/utils/iced.rs @@ -229,6 +229,7 @@ impl IcedElement

{ program: P, size: impl Into>, handle: LoopHandle<'static, crate::state::State>, + theme: cosmic::Theme, ) -> IcedElement

{ let size = size.into(); let mut renderer = @@ -257,7 +258,7 @@ impl IcedElement

{ pending_update: None, size, cursor_pos: None, - theme: Theme::dark(), // TODO + theme, renderer, state, debug, @@ -308,6 +309,11 @@ impl IcedElement

{ self.0.lock().unwrap().update(true); } + pub fn set_theme(&self, theme: cosmic::Theme) { + let mut guard = self.0.lock().unwrap(); + guard.theme = theme.clone(); + } + pub fn force_redraw(&self) { let mut internal = self.0.lock().unwrap(); for (_buffer, ref mut old_primitives) in internal.buffers.values_mut() { diff --git a/src/wayland/handlers/screencopy.rs b/src/wayland/handlers/screencopy.rs index 1aeffcb7..11845d48 100644 --- a/src/wayland/handlers/screencopy.rs +++ b/src/wayland/handlers/screencopy.rs @@ -43,7 +43,7 @@ use crate::{ backend::render::{ cursor, element::{AsGlowRenderer, CosmicElement}, - render_output, render_workspace, CursorMode, CLEAR_COLOR, + render_output, render_workspace, CursorMode, }, shell::{CosmicMappedRenderElement, CosmicSurface, WorkspaceRenderElement}, state::{BackendData, ClientState, Common, State}, @@ -1015,7 +1015,12 @@ pub fn render_window_to_buffer( renderer.bind(render_buffer).map_err(DTError::Rendering)?; } - dt.render_output(renderer, age, &elements, CLEAR_COLOR) + dt.render_output( + renderer, + age, + &elements, + crate::theme::clear_color(common.theme.cosmic()), + ) } let node = node_from_params(¶ms, &mut state.backend, None); diff --git a/src/wayland/handlers/xdg_shell/mod.rs b/src/wayland/handlers/xdg_shell/mod.rs index 88e10fc3..bc8b2390 100644 --- a/src/wayland/handlers/xdg_shell/mod.rs +++ b/src/wayland/handlers/xdg_shell/mod.rs @@ -220,6 +220,7 @@ impl XdgShellHandler for State { CosmicMapped::from(CosmicWindow::new( surface, self.common.event_loop_handle.clone(), + self.common.theme.clone(), )), if workspace.is_tiled(&mapped) { ManagedLayer::Tiling