feat: theme integration

refactor: only apply updates if there is a change in the theme

refactor: include theme in state

cleanup: theme integration
This commit is contained in:
Ashley Wulber 2023-10-10 13:55:34 -04:00 committed by Victoria Brekenfeld
parent c16b86d1bf
commit abbe94e6e1
24 changed files with 409 additions and 139 deletions

30
Cargo.lock generated
View file

@ -576,7 +576,7 @@ dependencies = [
[[package]] [[package]]
name = "cosmic-config" name = "cosmic-config"
version = "0.1.0" 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 = [ dependencies = [
"atomicwrites", "atomicwrites",
"calloop 0.12.2", "calloop 0.12.2",
@ -591,7 +591,7 @@ dependencies = [
[[package]] [[package]]
name = "cosmic-config-derive" name = "cosmic-config-derive"
version = "0.1.0" 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 = [ dependencies = [
"quote", "quote",
"syn 1.0.109", "syn 1.0.109",
@ -632,7 +632,7 @@ dependencies = [
[[package]] [[package]]
name = "cosmic-theme" name = "cosmic-theme"
version = "0.1.0" 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 = [ dependencies = [
"almost", "almost",
"cosmic-config", "cosmic-config",
@ -1801,7 +1801,7 @@ dependencies = [
[[package]] [[package]]
name = "iced" name = "iced"
version = "0.10.0" 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 = [ dependencies = [
"iced_core", "iced_core",
"iced_futures", "iced_futures",
@ -1814,7 +1814,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_core" name = "iced_core"
version = "0.10.0" 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 = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"instant", "instant",
@ -1827,7 +1827,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_futures" name = "iced_futures"
version = "0.7.0" 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 = [ dependencies = [
"futures", "futures",
"iced_core", "iced_core",
@ -1839,7 +1839,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_graphics" name = "iced_graphics"
version = "0.9.0" 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 = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"bytemuck", "bytemuck",
@ -1857,7 +1857,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_renderer" name = "iced_renderer"
version = "0.1.0" 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 = [ dependencies = [
"iced_graphics", "iced_graphics",
"iced_tiny_skia", "iced_tiny_skia",
@ -1870,7 +1870,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_runtime" name = "iced_runtime"
version = "0.1.1" 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 = [ dependencies = [
"iced_core", "iced_core",
"iced_futures", "iced_futures",
@ -1880,7 +1880,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_style" name = "iced_style"
version = "0.9.0" 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 = [ dependencies = [
"iced_core", "iced_core",
"once_cell", "once_cell",
@ -1890,7 +1890,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_tiny_skia" name = "iced_tiny_skia"
version = "0.1.0" 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 = [ dependencies = [
"bytemuck", "bytemuck",
"cosmic-text", "cosmic-text",
@ -1908,7 +1908,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_wgpu" name = "iced_wgpu"
version = "0.11.1" 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 = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"bytemuck", "bytemuck",
@ -1930,7 +1930,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_widget" name = "iced_widget"
version = "0.1.3" 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 = [ dependencies = [
"iced_renderer", "iced_renderer",
"iced_runtime", "iced_runtime",
@ -2242,7 +2242,7 @@ checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
[[package]] [[package]]
name = "libcosmic" name = "libcosmic"
version = "0.1.0" 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 = [ dependencies = [
"apply", "apply",
"cosmic-config", "cosmic-config",
@ -4126,7 +4126,7 @@ dependencies = [
[[package]] [[package]]
name = "taffy" name = "taffy"
version = "0.3.11" version = "0.3.11"
source = "git+https://github.com/DioxusLabs/taffy#120bb7a2e501822b324fd48de955450ebbba1c1a" source = "git+https://github.com/DioxusLabs/taffy?rev=65bedf#65bedf128ec8cef40c1a21b6f141f2c771842cca"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"grid", "grid",

View file

@ -36,10 +36,10 @@ libsystemd = { version = "0.6", optional = true }
wayland-backend = "0.3.2" wayland-backend = "0.3.2"
wayland-scanner = "0.31.0" wayland-scanner = "0.31.0"
cosmic-comp-config = { path = "cosmic-comp-config" } 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"] } 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 } 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/", rev = "f91287d" } iced_tiny_skia = { git = "https://github.com/pop-os/libcosmic/", branch = "theme-dark-light-switching" }
tiny-skia = "0.10" tiny-skia = "0.10"
ordered-float = "4.0" ordered-float = "4.0"
glow = "0.12.0" glow = "0.12.0"

View file

@ -3,7 +3,7 @@
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
use crate::backend::render::element::AsGlowRenderer; use crate::backend::render::element::AsGlowRenderer;
use crate::{ use crate::{
backend::render::{workspace_elements, CLEAR_COLOR}, backend::render::workspace_elements,
config::OutputConfig, config::OutputConfig,
shell::Shell, shell::Shell,
state::{BackendData, ClientState, Common, Fps, SurfaceDmabufFeedback}, state::{BackendData, ClientState, Common, Fps, SurfaceDmabufFeedback},
@ -1241,8 +1241,12 @@ impl Surface {
})?; })?;
self.fps.elements(); self.fps.elements();
let res = let theme = state.theme.cosmic();
compositor.render_frame::<_, _, GlesTexture>(&mut renderer, &elements, CLEAR_COLOR); let res = compositor.render_frame::<_, _, GlesTexture>(
&mut renderer,
&elements,
crate::theme::clear_color(&theme),
);
self.fps.render(); self.fps.render();
match res { match res {

View file

@ -78,11 +78,6 @@ pub type GlMultiFrame<'a, 'b, 'frame> =
MultiFrame<'a, 'a, 'b, 'frame, GbmGlesBackend<GlowRenderer>, GbmGlesBackend<GlowRenderer>>; MultiFrame<'a, 'a, 'b, 'frame, GbmGlesBackend<GlowRenderer>, GbmGlesBackend<GlowRenderer>>;
pub type GlMultiError = MultiError<GbmGlesBackend<GlowRenderer>, GbmGlesBackend<GlowRenderer>>; pub type GlMultiError = MultiError<GbmGlesBackend<GlowRenderer>, GbmGlesBackend<GlowRenderer>>;
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 OUTLINE_SHADER: &str = include_str!("./shaders/rounded_outline.frag");
pub static RECTANGLE_SHADER: &str = include_str!("./shaders/rounded_rectangle.frag"); pub static RECTANGLE_SHADER: &str = include_str!("./shaders/rounded_rectangle.frag");
@ -164,6 +159,7 @@ impl IndicatorShader {
thickness: u8, thickness: u8,
scale: f64, scale: f64,
alpha: f32, alpha: f32,
active_window_hint: [f32; 3],
) -> PixelShaderElement { ) -> PixelShaderElement {
let t = thickness as i32; let t = thickness as i32;
element_geo.loc -= (t, t).into(); element_geo.loc -= (t, t).into();
@ -177,7 +173,7 @@ impl IndicatorShader {
thickness * 2, thickness * 2,
alpha, alpha,
scale, scale,
FOCUS_INDICATOR_COLOR, active_window_hint,
) )
} }
@ -413,13 +409,14 @@ where
); );
} }
let theme = state.theme.cosmic();
if let Some(grab_elements) = seat if let Some(grab_elements) = seat
.user_data() .user_data()
.get::<SeatMoveGrabState>() .get::<SeatMoveGrabState>()
.unwrap() .unwrap()
.borrow() .borrow()
.as_ref() .as_ref()
.map(|state| state.render::<E, R>(renderer, seat, output)) .map(|state| state.render::<E, R>(renderer, seat, output, theme))
{ {
elements.extend(grab_elements); elements.extend(grab_elements);
} }
@ -449,6 +446,7 @@ where
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
puffin::profile_function!(); puffin::profile_function!();
let theme = state.theme.cosmic();
let mut elements = cursor_elements(renderer, state, output, cursor_mode); let mut elements = cursor_elements(renderer, state, output, cursor_mode);
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
@ -544,6 +542,7 @@ where
} else { } else {
Vec::new() Vec::new()
}; };
let active_hint = theme.active_hint as u8;
let offset = match previous.as_ref() { let offset = match previous.as_ref() {
Some((previous, previous_idx, start)) => { Some((previous, previous_idx, start)) => {
@ -584,7 +583,8 @@ where
(!move_active && is_active_space).then_some(&last_active_seat), (!move_active && is_active_space).then_some(&last_active_seat),
overview.clone(), overview.clone(),
resize_indicator.clone(), resize_indicator.clone(),
state.config.static_conf.active_hint, active_hint,
theme,
) )
.map_err(|_| OutputNoMode)?; .map_err(|_| OutputNoMode)?;
elements.extend(p_elements.into_iter().map(|p_element| { elements.extend(p_elements.into_iter().map(|p_element| {
@ -641,7 +641,8 @@ where
(!move_active && is_active_space).then_some(&last_active_seat), (!move_active && is_active_space).then_some(&last_active_seat),
overview, overview,
resize_indicator, resize_indicator,
state.config.static_conf.active_hint, active_hint,
theme,
) )
.map_err(|_| OutputNoMode)?; .map_err(|_| OutputNoMode)?;
elements.extend(p_elements.into_iter().map(|p_element| { elements.extend(p_elements.into_iter().map(|p_element| {
@ -913,7 +914,12 @@ where
} }
renderer.bind(target).map_err(RenderError::Rendering)?; 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() { if let Some(fps) = fps.as_mut() {
fps.render(); fps.render();

View file

@ -50,10 +50,6 @@ pub struct StaticConfig {
#[serde(default = "default_workspace_layout")] #[serde(default = "default_workspace_layout")]
pub workspace_layout: WorkspaceLayout, pub workspace_layout: WorkspaceLayout,
pub tiling_enabled: bool, 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)] #[derive(Debug, Deserialize, Clone, Copy, PartialEq, Eq)]
@ -100,14 +96,6 @@ fn default_enabled() -> bool {
true true
} }
fn default_active_hint() -> u8 {
4
}
fn default_gaps() -> (u8, u8) {
(0, 4)
}
fn default_workspace_layout() -> WorkspaceLayout { fn default_workspace_layout() -> WorkspaceLayout {
WorkspaceLayout::Vertical WorkspaceLayout::Vertical
} }
@ -219,8 +207,6 @@ impl Config {
workspace_amount: WorkspaceAmount::Dynamic, workspace_amount: WorkspaceAmount::Dynamic,
workspace_layout: WorkspaceLayout::Vertical, workspace_layout: WorkspaceLayout::Vertical,
tiling_enabled: false, tiling_enabled: false,
active_hint: default_active_hint(),
gaps: default_gaps(),
} }
} }

View file

@ -214,7 +214,6 @@ impl State {
<B as InputBackend>::PointerAxisEvent: 'static, <B as InputBackend>::PointerAxisEvent: 'static,
{ {
use smithay::backend::input::Event; use smithay::backend::input::Event;
match event { match event {
InputEvent::DeviceAdded { device } => { InputEvent::DeviceAdded { device } => {
let seat = &mut self.common.last_active_seat(); let seat = &mut self.common.last_active_seat();

View file

@ -25,6 +25,7 @@ pub mod shell;
pub mod state; pub mod state;
#[cfg(feature = "systemd")] #[cfg(feature = "systemd")]
pub mod systemd; pub mod systemd;
pub mod theme;
pub mod utils; pub mod utils;
pub mod wayland; pub mod wayland;
pub mod xwayland; pub mod xwayland;
@ -55,6 +56,10 @@ fn main() -> Result<()> {
// potentially tell the session we are setup now // potentially tell the session we are setup now
session::setup_socket(event_loop.handle(), &state)?; 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 // run the event loop
event_loop.run(None, &mut state, |state| { event_loop.run(None, &mut state, |state| {
// shall we shut down? // shall we shut down?

View file

@ -501,6 +501,7 @@ impl CosmicMapped {
pub fn convert_to_stack<'a>( pub fn convert_to_stack<'a>(
&mut self, &mut self,
(output, overlap): (&'a Output, Rectangle<i32, Logical>), (output, overlap): (&'a Output, Rectangle<i32, Logical>),
theme: cosmic::Theme,
) { ) {
match &self.element { match &self.element {
CosmicMappedInternal::Window(window) => { CosmicMappedInternal::Window(window) => {
@ -508,7 +509,7 @@ impl CosmicMapped {
let activated = surface.is_activated(true); let activated = surface.is_activated(true);
let handle = window.loop_handle(); 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() { if let Some(geo) = self.last_geometry.lock().unwrap().clone() {
stack.set_geometry(geo.to_global(&output)); stack.set_geometry(geo.to_global(&output));
} }
@ -527,11 +528,12 @@ impl CosmicMapped {
&mut self, &mut self,
surface: CosmicSurface, surface: CosmicSurface,
(output, overlap): (&'a Output, Rectangle<i32, Logical>), (output, overlap): (&'a Output, Rectangle<i32, Logical>),
theme: cosmic::Theme,
) { ) {
let handle = self.loop_handle(); let handle = self.loop_handle();
surface.try_force_undecorated(false); surface.try_force_undecorated(false);
surface.set_tiled(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() { if let Some(geo) = self.last_geometry.lock().unwrap().clone() {
window.set_geometry(geo.to_global(&output)); window.set_geometry(geo.to_global(&output));
@ -764,6 +766,22 @@ impl CosmicMapped {
popup_elements.into_iter().map(C::from).collect(), 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 { impl IsAlive for CosmicMapped {

View file

@ -23,6 +23,7 @@ pub fn resize_indicator(
direction: ResizeDirection, direction: ResizeDirection,
config: &Config, config: &Config,
evlh: LoopHandle<'static, crate::state::State>, evlh: LoopHandle<'static, crate::state::State>,
theme: cosmic::Theme,
) -> ResizeIndicator { ) -> ResizeIndicator {
ResizeIndicator::new( ResizeIndicator::new(
ResizeIndicatorInternal { ResizeIndicatorInternal {
@ -49,6 +50,7 @@ pub fn resize_indicator(
}, },
Size::from((1, 1)), Size::from((1, 1)),
evlh, evlh,
theme,
) )
} }

View file

@ -129,6 +129,7 @@ impl CosmicStack {
pub fn new<I: Into<CosmicSurface>>( pub fn new<I: Into<CosmicSurface>>(
windows: impl Iterator<Item = I>, windows: impl Iterator<Item = I>,
handle: LoopHandle<'static, crate::state::State>, handle: LoopHandle<'static, crate::state::State>,
theme: cosmic::Theme,
) -> CosmicStack { ) -> CosmicStack {
let windows = windows.map(Into::into).collect::<Vec<_>>(); let windows = windows.map(Into::into).collect::<Vec<_>>();
assert!(!windows.is_empty()); assert!(!windows.is_empty());
@ -160,6 +161,7 @@ impl CosmicStack {
}, },
(width, TAB_HEIGHT), (width, TAB_HEIGHT),
handle, handle,
theme,
)) ))
} }
@ -544,6 +546,14 @@ impl CosmicStack {
popup_elements.into_iter().map(C::from).collect(), 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)] #[derive(Debug, Clone, Copy)]
@ -1056,11 +1066,12 @@ impl PointerTarget<State> for CosmicStack {
let mapped = CosmicMapped::from(CosmicWindow::new( let mapped = CosmicMapped::from(CosmicWindow::new(
surface, surface,
self.0.loop_handle(), self.0.loop_handle(),
data.common.theme.clone(),
)); ));
let elem_geo = let elem_geo =
workspace.element_geometry(stack_mapped).unwrap(); workspace.element_geometry(stack_mapped).unwrap();
let indicator_thickness = 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); let was_tiled = workspace.is_tiled(stack_mapped);
self.remove_idx(dragged_out); self.remove_idx(dragged_out);

View file

@ -18,8 +18,9 @@ pub type StackHover = IcedElement<StackHoverInternal>;
pub fn stack_hover( pub fn stack_hover(
evlh: LoopHandle<'static, crate::state::State>, evlh: LoopHandle<'static, crate::state::State>,
size: Size<i32, Logical>, size: Size<i32, Logical>,
theme: cosmic::Theme,
) -> StackHover { ) -> StackHover {
StackHover::new(StackHoverInternal, size, evlh) StackHover::new(StackHoverInternal, size, evlh, theme)
} }
pub struct StackHoverInternal; pub struct StackHoverInternal;

View file

@ -15,8 +15,11 @@ use smithay::utils::Size;
pub type SwapIndicator = IcedElement<SwapIndicatorInternal>; pub type SwapIndicator = IcedElement<SwapIndicatorInternal>;
pub fn swap_indicator(evlh: LoopHandle<'static, crate::state::State>) -> SwapIndicator { pub fn swap_indicator(
SwapIndicator::new(SwapIndicatorInternal, Size::from((1, 1)), evlh) evlh: LoopHandle<'static, crate::state::State>,
theme: cosmic::Theme,
) -> SwapIndicator {
SwapIndicator::new(SwapIndicatorInternal, Size::from((1, 1)), evlh, theme)
} }
pub struct SwapIndicatorInternal; pub struct SwapIndicatorInternal;

View file

@ -114,6 +114,7 @@ impl CosmicWindow {
pub fn new( pub fn new(
window: impl Into<CosmicSurface>, window: impl Into<CosmicSurface>,
handle: LoopHandle<'static, crate::state::State>, handle: LoopHandle<'static, crate::state::State>,
theme: cosmic::Theme,
) -> CosmicWindow { ) -> CosmicWindow {
let window = window.into(); let window = window.into();
let width = window.geometry().size.w; let width = window.geometry().size.w;
@ -129,6 +130,7 @@ impl CosmicWindow {
}, },
(width, SSD_HEIGHT), (width, SSD_HEIGHT),
handle, handle,
theme,
)) ))
} }
@ -213,6 +215,14 @@ impl CosmicWindow {
popup_elements.into_iter().map(C::from).collect(), 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)] #[derive(Debug, Clone, Copy)]

View file

@ -17,6 +17,7 @@ use crate::{
utils::prelude::*, utils::prelude::*,
}; };
use cosmic::theme::CosmicTheme;
use smithay::{ use smithay::{
backend::renderer::{ backend::renderer::{
element::{utils::RescaleRenderElement, AsRenderElements, RenderElement}, element::{utils::RescaleRenderElement, AsRenderElements, RenderElement},
@ -58,7 +59,13 @@ pub struct MoveGrabState {
} }
impl MoveGrabState { impl MoveGrabState {
pub fn render<I, R>(&self, renderer: &mut R, seat: &Seat<State>, output: &Output) -> Vec<I> pub fn render<I, R>(
&self,
renderer: &mut R,
seat: &Seat<State>,
output: &Output,
theme: &CosmicTheme,
) -> Vec<I>
where where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
<R as Renderer>::TextureId: 'static, <R as Renderer>::TextureId: 'static,
@ -103,6 +110,7 @@ impl MoveGrabState {
+ self.window_offset + self.window_offset
- scaling_offset; - scaling_offset;
let active_window_hint = crate::theme::active_window_hint(theme);
let focus_element = if self.indicator_thickness > 0 { let focus_element = if self.indicator_thickness > 0 {
Some( Some(
CosmicMappedRenderElement::from(IndicatorShader::focus_element( CosmicMappedRenderElement::from(IndicatorShader::focus_element(
@ -121,6 +129,11 @@ impl MoveGrabState {
self.indicator_thickness, self.indicator_thickness,
output_scale.x, output_scale.x,
alpha, alpha,
[
active_window_hint.red,
active_window_hint.green,
active_window_hint.blue,
],
)) ))
.into(), .into(),
) )
@ -277,6 +290,7 @@ impl PointerGrab<State> for MoveGrab {
let element = stack_hover( let element = stack_hover(
state.common.event_loop_handle.clone(), state.common.event_loop_handle.clone(),
geo.size.as_logical(), geo.size.as_logical(),
state.common.theme.clone(),
); );
for output in &self.window_outputs { for output in &self.window_outputs {
element.output_enter( element.output_enter(

View file

@ -364,6 +364,7 @@ impl FloatingLayout {
&mut self, &mut self,
direction: Direction, direction: Direction,
seat: &Seat<State>, seat: &Seat<State>,
theme: cosmic::Theme,
) -> MoveResult { ) -> MoveResult {
let Some(target) = seat.get_keyboard().unwrap().current_focus() else { let Some(target) = seat.get_keyboard().unwrap().current_focus() else {
return MoveResult::None return MoveResult::None
@ -388,7 +389,7 @@ impl FloatingLayout {
match focused.handle_move(direction) { match focused.handle_move(direction) {
StackMoveResult::Handled => return MoveResult::Done, StackMoveResult::Handled => return MoveResult::Done,
StackMoveResult::MoveOut(surface, loop_handle) => { 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 output = seat.active_output();
let pos = self.space.element_geometry(focused).unwrap().loc let pos = self.space.element_geometry(focused).unwrap().loc
+ match direction { + match direction {
@ -464,6 +465,7 @@ impl FloatingLayout {
mut resize_indicator: Option<(ResizeMode, ResizeIndicator)>, mut resize_indicator: Option<(ResizeMode, ResizeIndicator)>,
indicator_thickness: u8, indicator_thickness: u8,
alpha: f32, alpha: f32,
theme: &cosmic::theme::CosmicTheme,
) -> ( ) -> (
Vec<CosmicMappedRenderElement<R>>, Vec<CosmicMappedRenderElement<R>>,
Vec<CosmicMappedRenderElement<R>>, Vec<CosmicMappedRenderElement<R>>,
@ -521,6 +523,8 @@ impl FloatingLayout {
); );
} }
let active_window_hint = crate::theme::active_window_hint(theme);
if indicator_thickness > 0 { if indicator_thickness > 0 {
let element = IndicatorShader::focus_element( let element = IndicatorShader::focus_element(
renderer, renderer,
@ -529,6 +533,11 @@ impl FloatingLayout {
indicator_thickness, indicator_thickness,
output_scale, output_scale,
alpha, alpha,
[
active_window_hint.red,
active_window_hint.green,
active_window_hint.blue,
],
); );
window_elements.push(element.into()); window_elements.push(element.into());
} }

View file

@ -137,6 +137,8 @@ impl PointerGrab<State> for ResizeForkGrab {
if let Some(output) = self.output.upgrade() { if let Some(output) = self.output.upgrade() {
let tiling_layer = &mut data.common.shell.active_space_mut(&output).tiling_layer; 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; let tree = &mut tiling_layer.queue.trees.back_mut().unwrap().0;
if tree.get(&self.node).is_ok() { if tree.get(&self.node).is_ok() {
let delta = match self.orientation { let delta = match self.orientation {
@ -191,7 +193,7 @@ impl PointerGrab<State> for ResizeForkGrab {
} }
self.last_loc = event.location; 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); tiling_layer.pending_blockers.extend(blocker);
} else { } else {
handle.unset_grab(data, event.serial, event.time); handle.unset_grab(data, event.serial, event.time);

View file

@ -1,10 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use crate::{ use crate::{
backend::render::{ backend::render::{element::AsGlowRenderer, BackdropShader, IndicatorShader, Key, Usage},
element::AsGlowRenderer, BackdropShader, IndicatorShader, Key, Usage, ACTIVE_GROUP_COLOR,
GROUP_COLOR,
},
shell::{ shell::{
element::{ element::{
resize_indicator::ResizeIndicator, resize_indicator::ResizeIndicator,
@ -25,6 +22,7 @@ use crate::{
CosmicSurface, Direction, FocusResult, MoveResult, OutputNotMapped, OverviewMode, CosmicSurface, Direction, FocusResult, MoveResult, OutputNotMapped, OverviewMode,
ResizeDirection, ResizeMode, Trigger, ResizeDirection, ResizeMode, Trigger,
}, },
theme::group_color,
utils::{prelude::*, tween::EaseRectangle}, utils::{prelude::*, tween::EaseRectangle},
wayland::{ wayland::{
handlers::xdg_shell::popup::get_popup_toplevel, handlers::xdg_shell::popup::get_popup_toplevel,
@ -116,13 +114,13 @@ impl TreeQueue {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct TilingLayout { pub struct TilingLayout {
gaps: (i32, i32),
output: Output, output: Output,
queue: TreeQueue, queue: TreeQueue,
pending_blockers: Vec<TilingBlocker>, pending_blockers: Vec<TilingBlocker>,
placeholder_id: Id, placeholder_id: Id,
swapping_stack_surface_id: Id, swapping_stack_surface_id: Id,
last_overview_hover: Option<(Option<Instant>, TargetZone)>, last_overview_hover: Option<(Option<Instant>, TargetZone)>,
pub theme: cosmic::Theme,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -317,9 +315,8 @@ enum FocusedNodeData {
} }
impl TilingLayout { impl TilingLayout {
pub fn new(gaps: (u8, u8), output: &Output) -> TilingLayout { pub fn new(theme: cosmic::Theme, output: &Output) -> TilingLayout {
TilingLayout { TilingLayout {
gaps: (gaps.0 as i32, gaps.1 as i32),
queue: TreeQueue { queue: TreeQueue {
trees: { trees: {
let mut queue = VecDeque::new(); let mut queue = VecDeque::new();
@ -333,10 +330,12 @@ impl TilingLayout {
placeholder_id: Id::new(), placeholder_id: Id::new(),
swapping_stack_surface_id: Id::new(), swapping_stack_surface_id: Id::new(),
last_overview_hover: None, last_overview_hover: None,
theme,
} }
} }
pub fn set_output(&mut self, output: &Output) { pub fn set_output(&mut self, output: &Output) {
let gaps = self.gaps();
let mut tree = self.queue.trees.back().unwrap().0.copy_clone(); let mut tree = self.queue.trees.back().unwrap().0.copy_clone();
for node in tree 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.queue.push_tree(tree, None, blocker);
self.output = output.clone(); self.output = output.clone();
} }
@ -377,9 +376,11 @@ impl TilingLayout {
focus_stack: Option<impl Iterator<Item = &'a CosmicMapped> + 'a>, focus_stack: Option<impl Iterator<Item = &'a CosmicMapped> + 'a>,
direction: Option<Direction>, direction: Option<Direction>,
) { ) {
let gaps = self.gaps();
let mut tree = self.queue.trees.back().unwrap().0.copy_clone(); let mut tree = self.queue.trees.back().unwrap().0.copy_clone();
TilingLayout::map_to_tree(&mut tree, window, &self.output, focus_stack, direction); 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); self.queue.push_tree(tree, ANIMATION_DURATION, blocker);
} }
@ -466,6 +467,7 @@ impl TilingLayout {
} }
pub fn replace_window(&mut self, old: &CosmicMapped, new: &CosmicMapped) { 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 Some(old_id) = old.tiling_node_id.lock().unwrap().clone() else { return };
let mut tree = self.queue.trees.back().unwrap().0.copy_clone(); let mut tree = self.queue.trees.back().unwrap().0.copy_clone();
@ -484,7 +486,7 @@ impl TilingLayout {
old.output_leave(&self.output); old.output_leave(&self.output);
new.output_enter(&self.output, new.bbox()); 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); self.queue.push_tree(tree, ANIMATION_DURATION, blocker);
} }
} }
@ -513,7 +515,8 @@ impl TilingLayout {
} }
let mapped: CosmicMapped = 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 { if this.output != other.output {
mapped.output_leave(&this.output); mapped.output_leave(&this.output);
mapped.output_enter(&other.output, mapped.bbox()); 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 = 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); this.queue.push_tree(this_tree, ANIMATION_DURATION, blocker);
let blocker = let blocker =
TilingLayout::update_positions(&other.output, &mut other_tree, other.gaps); TilingLayout::update_positions(&other.output, &mut other_tree, other_gaps);
other other
.queue .queue
.push_tree(other_tree, ANIMATION_DURATION, blocker); .push_tree(other_tree, ANIMATION_DURATION, blocker);
@ -900,8 +905,12 @@ impl TilingLayout {
} }
this_stack.remove_window(&this_surface); this_stack.remove_window(&this_surface);
let mapped: CosmicMapped = let mapped: CosmicMapped = CosmicWindow::new(
CosmicWindow::new(this_surface.clone(), this_stack.loop_handle()).into(); this_surface.clone(),
this_stack.loop_handle(),
this.theme.clone(),
)
.into();
mapped.set_tiled(true); mapped.set_tiled(true);
mapped.refresh(); mapped.refresh();
if this.output != other_output { if this.output != other_output {
@ -977,8 +986,12 @@ impl TilingLayout {
} }
other_stack.remove_window(&other_surface); other_stack.remove_window(&other_surface);
let mapped: CosmicMapped = let mapped: CosmicMapped = CosmicWindow::new(
CosmicWindow::new(other_surface.clone(), other_stack.loop_handle()).into(); other_surface.clone(),
other_stack.loop_handle(),
this.theme.clone(),
)
.into();
mapped.set_tiled(true); mapped.set_tiled(true);
mapped.refresh(); mapped.refresh();
if this.output != other_output { 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); this.queue.push_tree(this_tree, ANIMATION_DURATION, blocker);
let has_other_tree = other_tree.is_some(); let has_other_tree = other_tree.is_some();
if let Some(mut other_tree) = other_tree { if let Some(mut other_tree) = other_tree {
let (other_queue, gaps) = if let Some(other) = other.as_mut() { 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 { } else {
(&mut this.queue, this.gaps) (&mut this.queue, this_gaps)
}; };
let blocker = TilingLayout::update_positions(&other_output, &mut other_tree, gaps); let blocker = TilingLayout::update_positions(&other_output, &mut other_tree, gaps);
other_queue.push_tree(other_tree, ANIMATION_DURATION, blocker); other_queue.push_tree(other_tree, ANIMATION_DURATION, blocker);
@ -1144,6 +1159,8 @@ impl TilingLayout {
fn unmap_window_internal(&mut self, mapped: &CosmicMapped) -> bool { fn unmap_window_internal(&mut self, mapped: &CosmicMapped) -> bool {
let tiling_node_id = mapped.tiling_node_id.lock().unwrap().as_ref().cloned(); 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 let Some(node_id) = tiling_node_id {
if self if self
.queue .queue
@ -1159,7 +1176,7 @@ impl TilingLayout {
TilingLayout::unmap_internal(&mut tree, &node_id); 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); self.queue.push_tree(tree, ANIMATION_DURATION, blocker);
return true; return true;
@ -1241,6 +1258,8 @@ impl TilingLayout {
direction: Direction, direction: Direction,
seat: &Seat<State>, seat: &Seat<State>,
) -> MoveResult { ) -> MoveResult {
let gaps = self.gaps();
let mut tree = self.queue.trees.back().unwrap().0.copy_clone(); let mut tree = self.queue.trees.back().unwrap().0.copy_clone();
let Some(target) = seat.get_keyboard().unwrap().current_focus() else { let Some(target) = seat.get_keyboard().unwrap().current_focus() else {
@ -1257,7 +1276,8 @@ impl TilingLayout {
match window.handle_move(direction) { match window.handle_move(direction) {
StackMoveResult::Handled => return MoveResult::Done, StackMoveResult::Handled => return MoveResult::Done,
StackMoveResult::MoveOut(surface, loop_handle) => { 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()); mapped.output_enter(&self.output, mapped.bbox());
let orientation = match direction { let orientation = match direction {
Direction::Left | Direction::Right => Orientation::Vertical, Direction::Left | Direction::Right => Orientation::Vertical,
@ -1280,8 +1300,7 @@ impl TilingLayout {
.unwrap(); .unwrap();
*mapped.tiling_node_id.lock().unwrap() = Some(new_id); *mapped.tiling_node_id.lock().unwrap() = Some(new_id);
let blocker = let blocker = TilingLayout::update_positions(&self.output, &mut tree, gaps);
TilingLayout::update_positions(&self.output, &mut tree, self.gaps);
self.queue.push_tree(tree, ANIMATION_DURATION, blocker); self.queue.push_tree(tree, ANIMATION_DURATION, blocker);
return MoveResult::ShiftFocus(mapped.into()); return MoveResult::ShiftFocus(mapped.into());
} }
@ -1357,7 +1376,7 @@ impl TilingLayout {
.data_mut() .data_mut()
.remove_window(og_idx); .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); self.queue.push_tree(tree, ANIMATION_DURATION, blocker);
return MoveResult::Done; return MoveResult::Done;
} }
@ -1383,7 +1402,7 @@ impl TilingLayout {
.data_mut() .data_mut()
.remove_window(og_idx); .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); self.queue.push_tree(tree, ANIMATION_DURATION, blocker);
return MoveResult::Done; return MoveResult::Done;
} }
@ -1539,7 +1558,7 @@ impl TilingLayout {
MoveResult::Done 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); self.queue.push_tree(tree, ANIMATION_DURATION, blocker);
return result; return result;
} }
@ -1836,6 +1855,8 @@ impl TilingLayout {
new_orientation: Option<Orientation>, new_orientation: Option<Orientation>,
seat: &Seat<State>, seat: &Seat<State>,
) { ) {
let gaps = self.gaps();
let Some(target) = seat.get_keyboard().unwrap().current_focus() else { let Some(target) = seat.get_keyboard().unwrap().current_focus() else {
return; return;
}; };
@ -1871,8 +1892,7 @@ impl TilingLayout {
*orientation = new_orientation; *orientation = new_orientation;
let blocker = let blocker = TilingLayout::update_positions(&self.output, &mut tree, gaps);
TilingLayout::update_positions(&self.output, &mut tree, self.gaps);
self.queue.push_tree(tree, ANIMATION_DURATION, blocker); self.queue.push_tree(tree, ANIMATION_DURATION, blocker);
} }
} }
@ -1880,6 +1900,8 @@ impl TilingLayout {
} }
pub fn toggle_stacking<'a>(&mut self, seat: &Seat<State>, mut focus_stack: FocusStackMut) { pub fn toggle_stacking<'a>(&mut self, seat: &Seat<State>, mut focus_stack: FocusStackMut) {
let gaps = self.gaps();
let Some(target) = seat.get_keyboard().unwrap().current_focus() else { let Some(target) = seat.get_keyboard().unwrap().current_focus() else {
return; return;
}; };
@ -1894,7 +1916,10 @@ impl TilingLayout {
// if it is just a window // if it is just a window
match tree.get_mut(&last_active).unwrap().data_mut() { match tree.get_mut(&last_active).unwrap().data_mut() {
Data::Mapped { mapped, .. } => { 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); focus_stack.append(&mapped);
} }
_ => unreachable!(), _ => unreachable!(),
@ -1907,7 +1932,11 @@ impl TilingLayout {
let handle = match tree.get_mut(&last_active).unwrap().data_mut() { let handle = match tree.get_mut(&last_active).unwrap().data_mut() {
Data::Mapped { mapped, .. } => { Data::Mapped { mapped, .. } => {
let handle = mapped.loop_handle(); 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); focus_stack.append(&mapped);
handle handle
} }
@ -1918,8 +1947,11 @@ impl TilingLayout {
for other in surfaces { for other in surfaces {
other.try_force_undecorated(false); other.try_force_undecorated(false);
other.set_tiled(false); other.set_tiled(false);
let window = let window = CosmicMapped::from(CosmicWindow::new(
CosmicMapped::from(CosmicWindow::new(other, handle.clone())); other,
handle.clone(),
self.theme.clone(),
));
window.output_enter(&self.output, window.bbox()); window.output_enter(&self.output, window.bbox());
{ {
@ -1960,7 +1992,7 @@ impl TilingLayout {
return; return;
} }
let handle = handle.unwrap(); 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 for child in tree
.children_ids(&last_active) .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); self.queue.push_tree(tree, ANIMATION_DURATION, blocker);
} }
} }
pub fn recalculate(&mut self) { pub fn recalculate(&mut self) {
let gaps = self.gaps();
let mut tree = self.queue.trees.back().unwrap().0.copy_clone(); 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); self.queue.push_tree(tree, ANIMATION_DURATION, blocker);
} }
@ -2136,6 +2170,8 @@ impl TilingLayout {
edges: ResizeEdge, edges: ResizeEdge,
amount: i32, amount: i32,
) -> bool { ) -> bool {
let gaps = self.gaps();
let mut tree = self.queue.trees.back().unwrap().0.copy_clone(); let mut tree = self.queue.trees.back().unwrap().0.copy_clone();
let Some(root_id) = tree.root_node_id() else { return false }; let Some(root_id) = tree.root_node_id() else { return false };
let Some(mut node_id) = let Some(mut node_id) =
@ -2214,7 +2250,7 @@ impl TilingLayout {
} }
_ => unreachable!(), _ => 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); self.queue.push_tree(tree, None, blocker);
return true; return true;
@ -2234,6 +2270,8 @@ impl TilingLayout {
} }
pub fn cleanup_drag(&mut self) { pub fn cleanup_drag(&mut self) {
let gaps = self.gaps();
let mut tree = self.queue.trees.back().unwrap().0.copy_clone(); let mut tree = self.queue.trees.back().unwrap().0.copy_clone();
if let Some(root) = tree.root_node_id() { 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); self.queue.push_tree(tree, ANIMATION_DURATION, blocker);
} }
} }
pub fn drop_window(&mut self, window: CosmicMapped) -> (CosmicMapped, Point<i32, Local>) { pub fn drop_window(&mut self, window: CosmicMapped) -> (CosmicMapped, Point<i32, Local>) {
let gaps = self.gaps();
let mut tree = self.queue.trees.back().unwrap().0.copy_clone(); let mut tree = self.queue.trees.back().unwrap().0.copy_clone();
window.output_enter(&self.output, window.bbox()); 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() => { Some(TargetZone::WindowStack(window_id, _)) if tree.get(&window_id).is_ok() => {
match tree.get_mut(window_id).unwrap().data_mut() { match tree.get_mut(window_id).unwrap().data_mut() {
Data::Mapped { mapped, .. } => { 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 { let Some(stack) = mapped.stack_ref_mut() else {
unreachable!() 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); self.queue.push_tree(tree, ANIMATION_DURATION, blocker);
let location = self.element_geometry(&mapped).unwrap().loc; let location = self.element_geometry(&mapped).unwrap().loc;
@ -2728,9 +2768,9 @@ impl TilingLayout {
location: Point<f64, Local>, location: Point<f64, Local>,
overview: OverviewMode, overview: OverviewMode,
) -> Option<(PointerFocusTarget, Point<i32, Local>)> { ) -> Option<(PointerFocusTarget, Point<i32, Local>)> {
let gaps = self.gaps();
let last_overview_hover = &mut self.last_overview_hover; let last_overview_hover = &mut self.last_overview_hover;
let placeholder_id = &self.placeholder_id; let placeholder_id = &self.placeholder_id;
let gaps = &self.gaps;
let tree = &self.queue.trees.back().unwrap().0; let tree = &self.queue.trees.back().unwrap().0;
let root = tree.root_node_id()?; let root = tree.root_node_id()?;
let location = location.to_i32_round(); let location = location.to_i32_round();
@ -2850,6 +2890,7 @@ impl TilingLayout {
Some(None), Some(None),
None, None,
None, None,
self.theme.cosmic(),
) )
.0; .0;
@ -3275,7 +3316,7 @@ impl TilingLayout {
let blocker = TilingLayout::update_positions( let blocker = TilingLayout::update_positions(
&self.output, &self.output,
&mut tree, &mut tree,
*gaps, gaps,
); );
self.queue.push_tree(tree, duration, blocker); self.queue.push_tree(tree, duration, blocker);
} }
@ -3372,6 +3413,8 @@ impl TilingLayout {
} }
pub fn merge(&mut self, mut other: TilingLayout) { pub fn merge(&mut self, mut other: TilingLayout) {
let gaps = self.gaps();
let src = other.queue.trees.pop_back().unwrap().0; let src = other.queue.trees.pop_back().unwrap().0;
let mut dst = self.queue.trees.back().unwrap().0.copy_clone(); let mut dst = self.queue.trees.back().unwrap().0.copy_clone();
@ -3381,7 +3424,7 @@ impl TilingLayout {
}; };
TilingLayout::merge_trees(src, &mut dst, orientation); 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); self.queue.push_tree(dst, ANIMATION_DURATION, blocker);
} }
@ -3432,6 +3475,7 @@ impl TilingLayout {
overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree<Data>>)>), overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree<Data>>)>),
resize_indicator: Option<(ResizeMode, ResizeIndicator)>, resize_indicator: Option<(ResizeMode, ResizeIndicator)>,
indicator_thickness: u8, indicator_thickness: u8,
theme: &cosmic::theme::CosmicTheme,
) -> Result< ) -> Result<
( (
Vec<CosmicMappedRenderElement<R>>, Vec<CosmicMappedRenderElement<R>>,
@ -3502,6 +3546,7 @@ impl TilingLayout {
is_mouse_tiling, is_mouse_tiling,
swap_desc.clone(), swap_desc.clone(),
overview.1.as_ref().and_then(|(_, tree)| tree.clone()), overview.1.as_ref().and_then(|(_, tree)| tree.clone()),
theme,
)) ))
} else { } else {
None None
@ -3539,6 +3584,7 @@ impl TilingLayout {
is_mouse_tiling, is_mouse_tiling,
swap_desc.clone(), swap_desc.clone(),
overview.1.as_ref().and_then(|(_, tree)| tree.clone()), overview.1.as_ref().and_then(|(_, tree)| tree.clone()),
theme,
)) ))
} else { } else {
None None
@ -3573,6 +3619,7 @@ impl TilingLayout {
swap_desc.clone(), swap_desc.clone(),
&self.swapping_stack_surface_id, &self.swapping_stack_surface_id,
&self.placeholder_id, &self.placeholder_id,
theme,
); );
window_elements.extend(w_elements); window_elements.extend(w_elements);
popup_elements.extend(p_elements); popup_elements.extend(p_elements);
@ -3584,6 +3631,11 @@ impl TilingLayout {
Ok((window_elements, popup_elements)) 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; const GAP_KEYBOARD: i32 = 8;
@ -3631,6 +3683,7 @@ fn geometries_for_groupview<'a, R>(
mouse_tiling: Option<Option<&TargetZone>>, mouse_tiling: Option<Option<&TargetZone>>,
swap_desc: Option<NodeDesc>, swap_desc: Option<NodeDesc>,
swap_tree: Option<&Tree<Data>>, swap_tree: Option<&Tree<Data>>,
theme: &cosmic::theme::CosmicTheme,
) -> ( ) -> (
HashMap<NodeId, Rectangle<i32, Local>>, HashMap<NodeId, Rectangle<i32, Local>>,
Vec<CosmicMappedRenderElement<R>>, Vec<CosmicMappedRenderElement<R>>,
@ -3788,6 +3841,8 @@ where
) )
}; };
let group_color = group_color(theme);
match data { match data {
Data::Group { Data::Group {
orientation, orientation,
@ -3825,7 +3880,7 @@ where
if render_active_child { 16 } else { 8 }, if render_active_child { 16 } else { 8 },
alpha * if render_potential_group { 0.40 } else { 1.0 }, alpha * if render_potential_group { 0.40 } else { 1.0 },
output_scale, output_scale,
GROUP_COLOR, group_color,
) )
.into(), .into(),
); );
@ -3843,7 +3898,7 @@ where
8, 8,
alpha * 0.40, alpha * 0.40,
output_scale, output_scale,
GROUP_COLOR, group_color,
) )
.into(), .into(),
); );
@ -3907,7 +3962,7 @@ where
8, 8,
alpha * 0.15, alpha * 0.15,
output_scale, output_scale,
GROUP_COLOR, group_color,
) )
.into(), .into(),
); );
@ -3971,7 +4026,7 @@ where
pill_geo, pill_geo,
8., 8.,
alpha * 0.4, alpha * 0.4,
GROUP_COLOR, group_color,
) )
.into(), .into(),
); );
@ -4001,7 +4056,7 @@ where
} else { } else {
0.15 0.15
}, },
GROUP_COLOR, group_color,
) )
.into(), .into(),
); );
@ -4077,7 +4132,7 @@ where
), ),
8., 8.,
alpha * 0.4, alpha * 0.4,
GROUP_COLOR, group_color,
) )
.into(), .into(),
); );
@ -4119,7 +4174,7 @@ where
), ),
8., 8.,
alpha * 0.4, alpha * 0.4,
GROUP_COLOR, group_color,
) )
.into(), .into(),
); );
@ -4150,7 +4205,7 @@ where
8, 8,
alpha * 0.40, alpha * 0.40,
output_scale, output_scale,
GROUP_COLOR, group_color,
) )
.into(), .into(),
); );
@ -4158,6 +4213,8 @@ where
geo.size -= (gap * 2, gap * 2).into(); geo.size -= (gap * 2, gap * 2).into();
} }
let accent = theme.accent.base;
if focused if focused
.as_ref() .as_ref()
.map(|focused_id| { .map(|focused_id| {
@ -4172,9 +4229,9 @@ where
Some(Some(TargetZone::WindowStack(stack_id, _))) Some(Some(TargetZone::WindowStack(stack_id, _)))
if *stack_id == node_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.loc += (WINDOW_BACKDROP_BORDER, WINDOW_BACKDROP_BORDER).into();
geo.size -= geo.size -=
@ -4189,7 +4246,9 @@ where
* if focused * if focused
.as_ref() .as_ref()
.map(|focused_id| focused_id == &node_id) .map(|focused_id| focused_id == &node_id)
.unwrap_or(color == ACTIVE_GROUP_COLOR) .unwrap_or(
color == [accent.red, accent.green, accent.blue],
)
{ {
0.4 0.4
} else { } else {
@ -4243,7 +4302,7 @@ where
geo, geo,
8., 8.,
alpha * 0.4, alpha * 0.4,
GROUP_COLOR, group_color,
) )
.into(), .into(),
); );
@ -4417,6 +4476,7 @@ fn render_new_tree<R>(
swap_desc: Option<NodeDesc>, swap_desc: Option<NodeDesc>,
swapping_stack_surface_id: &Id, swapping_stack_surface_id: &Id,
placeholder_id: &Id, placeholder_id: &Id,
theme: &cosmic::theme::CosmicTheme,
) -> ( ) -> (
Vec<CosmicMappedRenderElement<R>>, Vec<CosmicMappedRenderElement<R>>,
Vec<CosmicMappedRenderElement<R>>, Vec<CosmicMappedRenderElement<R>>,
@ -4476,7 +4536,8 @@ where
let (swap_indicator, swap_tree) = overview.1.unzip(); let (swap_indicator, swap_tree) = overview.1.unzip();
let swap_tree = swap_tree.flatten().filter(|_| is_active_output); let swap_tree = swap_tree.flatten().filter(|_| is_active_output);
let swap_desc = swap_desc.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 // render placeholder, if we are swapping to an empty workspace
if target_tree.root_node_id().is_none() && swap_desc.is_some() { if target_tree.root_node_id().is_none() && swap_desc.is_some() {
window_elements.push( window_elements.push(
@ -4486,7 +4547,7 @@ where
focused_geo, focused_geo,
8., 8.,
transition.unwrap_or(1.0) * 0.4, transition.unwrap_or(1.0) * 0.4,
GROUP_COLOR, group_color,
) )
.into(), .into(),
); );
@ -4518,6 +4579,7 @@ where
4, 4,
output_scale, output_scale,
transition.unwrap_or(1.0), transition.unwrap_or(1.0),
[window_hint.red, window_hint.green, window_hint.blue],
)); ));
let render_loc = let render_loc =
@ -4679,7 +4741,7 @@ where
geo, geo,
8., 8.,
0.4, 0.4,
GROUP_COLOR, group_color,
)); ));
} }
@ -4706,6 +4768,7 @@ where
}, },
output_scale, output_scale,
1.0, 1.0,
[window_hint.red, window_hint.green, window_hint.blue],
)); ));
} }
@ -4825,7 +4888,7 @@ where
geo, geo,
0.0, 0.0,
0.3, 0.3,
GROUP_COLOR, group_color,
)), )),
) )
} }

View file

@ -163,6 +163,7 @@ pub struct Shell {
pub xdg_shell_state: XdgShellState, pub xdg_shell_state: XdgShellState,
pub workspace_state: WorkspaceState<State>, pub workspace_state: WorkspaceState<State>,
theme: cosmic::Theme,
overview_mode: OverviewMode, overview_mode: OverviewMode,
swap_indicator: Option<SwapIndicator>, swap_indicator: Option<SwapIndicator>,
resize_mode: ResizeMode, resize_mode: ResizeMode,
@ -184,8 +185,8 @@ pub struct WorkspaceSet {
group: WorkspaceGroupHandle, group: WorkspaceGroupHandle,
idx: usize, idx: usize,
tiling_enabled: bool, tiling_enabled: bool,
gaps: (u8, u8),
output: Output, output: Output,
theme: cosmic::Theme,
pub(crate) workspaces: Vec<Workspace>, pub(crate) workspaces: Vec<Workspace>,
} }
@ -201,7 +202,7 @@ fn create_workspace(
group_handle: &WorkspaceGroupHandle, group_handle: &WorkspaceGroupHandle,
active: bool, active: bool,
tiling: bool, tiling: bool,
gaps: (u8, u8), theme: cosmic::Theme,
) -> Workspace { ) -> Workspace {
let workspace_handle = state.create_workspace(&group_handle).unwrap(); let workspace_handle = state.create_workspace(&group_handle).unwrap();
if active { if active {
@ -211,7 +212,7 @@ fn create_workspace(
&workspace_handle, &workspace_handle,
[WorkspaceCapabilities::Activate].into_iter(), [WorkspaceCapabilities::Activate].into_iter(),
); );
Workspace::new(workspace_handle, output.clone(), tiling, gaps) Workspace::new(workspace_handle, output.clone(), tiling, theme.clone())
} }
impl WorkspaceSet { impl WorkspaceSet {
@ -222,12 +223,18 @@ impl WorkspaceSet {
amount: WorkspaceAmount, amount: WorkspaceAmount,
idx: usize, idx: usize,
tiling_enabled: bool, tiling_enabled: bool,
gaps: (u8, u8), theme: cosmic::Theme,
) -> WorkspaceSet { ) -> WorkspaceSet {
let workspaces = match amount { let workspaces = match amount {
WorkspaceAmount::Dynamic => { WorkspaceAmount::Dynamic => {
let workspace = let workspace = create_workspace(
create_workspace(state, output, &group_handle, true, tiling_enabled, gaps); state,
output,
&group_handle,
true,
tiling_enabled,
theme.clone(),
);
workspace_set_idx(state, 1, idx, &workspace.handle); workspace_set_idx(state, 1, idx, &workspace.handle);
state.set_workspace_capabilities( state.set_workspace_capabilities(
&workspace.handle, &workspace.handle,
@ -243,7 +250,7 @@ impl WorkspaceSet {
&group_handle, &group_handle,
i == 0, i == 0,
tiling_enabled, tiling_enabled,
gaps, theme.clone(),
); );
workspace_set_idx(state, i + 1, idx, &workspace.handle); workspace_set_idx(state, i + 1, idx, &workspace.handle);
state.set_workspace_capabilities( state.set_workspace_capabilities(
@ -261,7 +268,7 @@ impl WorkspaceSet {
group: group_handle, group: group_handle,
idx, idx,
tiling_enabled, tiling_enabled,
gaps, theme,
workspaces, workspaces,
output: output.clone(), output: output.clone(),
} }
@ -316,7 +323,7 @@ impl WorkspaceSet {
&self.group, &self.group,
false, false,
self.tiling_enabled, self.tiling_enabled,
self.gaps, self.theme.clone(),
); );
workspace_set_idx( workspace_set_idx(
state, state,
@ -411,7 +418,7 @@ impl WorkspaceSet {
&self.group, &self.group,
false, false,
self.tiling_enabled, self.tiling_enabled,
self.gaps, self.theme.clone(),
); );
workspace_set_idx( workspace_set_idx(
state, state,
@ -452,18 +459,18 @@ pub struct Workspaces {
amount: WorkspaceAmount, amount: WorkspaceAmount,
mode: WorkspaceMode, mode: WorkspaceMode,
tiling_enabled: bool, tiling_enabled: bool,
gaps: (u8, u8), theme: cosmic::Theme,
} }
impl Workspaces { impl Workspaces {
pub fn new(config: &Config) -> Workspaces { pub fn new(config: &Config, theme: cosmic::Theme) -> Workspaces {
Workspaces { Workspaces {
sets: IndexMap::new(), sets: IndexMap::new(),
backup_set: None, backup_set: None,
amount: config.static_conf.workspace_amount, amount: config.static_conf.workspace_amount,
mode: config.static_conf.workspace_mode, mode: config.static_conf.workspace_mode,
tiling_enabled: config.static_conf.tiling_enabled, tiling_enabled: config.static_conf.tiling_enabled,
gaps: config.static_conf.gaps, theme,
} }
} }
@ -500,7 +507,7 @@ impl Workspaces {
self.amount, self.amount,
self.sets.len(), self.sets.len(),
self.tiling_enabled, self.tiling_enabled,
self.gaps, self.theme.clone(),
) )
}); });
workspace_state.add_group_output(&set.group, &output); workspace_state.add_group_output(&set.group, &output);
@ -674,7 +681,7 @@ impl Workspaces {
&group, &group,
false, false,
config.static_conf.tiling_enabled, config.static_conf.tiling_enabled,
config.static_conf.gaps, self.theme.clone(),
), ),
); );
// Otherwise just update // Otherwise just update
@ -882,6 +889,24 @@ impl Workspaces {
set.update_tiling_status(seat, tiling) 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; pub struct InvalidWorkspaceIndex;
@ -910,10 +935,11 @@ impl Shell {
//|client| client.get_data::<ClientState>().map_or(false, |s| s.privileged), //|client| client.get_data::<ClientState>().map_or(false, |s| s.privileged),
client_has_security_context, client_has_security_context,
); );
let theme = cosmic::theme::system_preference();
Shell { Shell {
popups: PopupManager::default(), popups: PopupManager::default(),
workspaces: Workspaces::new(config), workspaces: Workspaces::new(config, theme.clone()),
maximize_mode: MaximizeMode::Floating, maximize_mode: MaximizeMode::Floating,
pending_windows: Vec::new(), pending_windows: Vec::new(),
@ -926,6 +952,7 @@ impl Shell {
xdg_shell_state, xdg_shell_state,
workspace_state, workspace_state,
theme,
overview_mode: OverviewMode::None, overview_mode: OverviewMode::None,
swap_indicator: None, swap_indicator: None,
resize_mode: ResizeMode::None, resize_mode: ResizeMode::None,
@ -1158,7 +1185,7 @@ impl Shell {
if let Some(trigger) = enabled { if let Some(trigger) = enabled {
if !matches!(self.overview_mode, OverviewMode::Started(_, _)) { if !matches!(self.overview_mode, OverviewMode::Started(_, _)) {
if matches!(trigger, Trigger::KeyboardSwap(_, _)) { 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()); self.overview_mode = OverviewMode::Started(trigger, Instant::now());
} }
@ -1204,7 +1231,12 @@ impl Shell {
} else { } else {
self.resize_mode = ResizeMode::Started(pattern, Instant::now(), direction); 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 { } else {
if let ResizeMode::Started(_, _, direction) = &self.resize_mode { if let ResizeMode::Started(_, _, direction) = &self.resize_mode {
self.resize_mode = ResizeMode::Ended(Instant::now(), *direction); self.resize_mode = ResizeMode::Ended(Instant::now(), *direction);
@ -1338,6 +1370,7 @@ impl Shell {
let mapped = CosmicMapped::from(CosmicWindow::new( let mapped = CosmicMapped::from(CosmicWindow::new(
window.clone(), window.clone(),
state.common.event_loop_handle.clone(), state.common.event_loop_handle.clone(),
state.common.theme.clone(),
)); ));
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
{ {
@ -1579,12 +1612,13 @@ impl Shell {
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface)) .find(|(w, _)| w.wl_surface().as_ref() == Some(surface))
.unwrap(); .unwrap();
let button = start_data.button; let button = start_data.button;
let active_hint = state.common.theme.cosmic().active_hint as u8;
if let Some(grab) = workspace.move_request( if let Some(grab) = workspace.move_request(
&window, &window,
&seat, &seat,
&output, &output,
start_data, start_data,
state.common.config.static_conf.active_hint, active_hint as u8,
) { ) {
let handle = workspace.handle; let handle = workspace.handle;
state 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>( fn workspace_set_idx<'a>(

View file

@ -21,6 +21,7 @@ use crate::{
xwayland::XWaylandState, xwayland::XWaylandState,
}; };
use cosmic::theme::CosmicTheme;
use id_tree::Tree; use id_tree::Tree;
use indexmap::IndexSet; use indexmap::IndexSet;
use keyframe::{ease, functions::EaseInOutCubic}; use keyframe::{ease, functions::EaseInOutCubic};
@ -210,9 +211,9 @@ impl Workspace {
handle: WorkspaceHandle, handle: WorkspaceHandle,
output: Output, output: Output,
tiling_enabled: bool, tiling_enabled: bool,
gaps: (u8, u8), theme: cosmic::Theme,
) -> Workspace { ) -> Workspace {
let tiling_layer = TilingLayout::new(gaps, &output); let tiling_layer = TilingLayout::new(theme, &output);
let floating_layer = FloatingLayout::new(&output); let floating_layer = FloatingLayout::new(&output);
Workspace { Workspace {
@ -824,7 +825,7 @@ impl Workspace {
MoveResult::MoveFurther(KeyboardFocusTarget::Fullscreen(f.surface.clone())) MoveResult::MoveFurther(KeyboardFocusTarget::Fullscreen(f.surface.clone()))
} else { } else {
self.floating_layer 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)) .or_else(|| self.tiling_layer.move_current_node(direction, seat))
} }
} }
@ -838,6 +839,7 @@ impl Workspace {
overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree<Data>>)>), overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree<Data>>)>),
resize_indicator: Option<(ResizeMode, ResizeIndicator)>, resize_indicator: Option<(ResizeMode, ResizeIndicator)>,
indicator_thickness: u8, indicator_thickness: u8,
theme: &CosmicTheme,
) -> Result< ) -> Result<
( (
Vec<WorkspaceRenderElement<R>>, Vec<WorkspaceRenderElement<R>>,
@ -1014,6 +1016,7 @@ impl Workspace {
resize_indicator.clone(), resize_indicator.clone(),
indicator_thickness, indicator_thickness,
alpha, alpha,
theme,
); );
popup_elements.extend(p_elements.into_iter().map(WorkspaceRenderElement::from)); popup_elements.extend(p_elements.into_iter().map(WorkspaceRenderElement::from));
window_elements.extend(w_elements.into_iter().map(WorkspaceRenderElement::from)); window_elements.extend(w_elements.into_iter().map(WorkspaceRenderElement::from));
@ -1038,6 +1041,7 @@ impl Workspace {
overview, overview,
resize_indicator, resize_indicator,
indicator_thickness, indicator_thickness,
theme,
)?; )?;
popup_elements.extend(p_elements.into_iter().map(WorkspaceRenderElement::from)); popup_elements.extend(p_elements.into_iter().map(WorkspaceRenderElement::from));
window_elements.extend(w_elements.into_iter().map(WorkspaceRenderElement::from)); window_elements.extend(w_elements.into_iter().map(WorkspaceRenderElement::from));

View file

@ -137,6 +137,8 @@ pub struct Common {
pub clock: Clock<Monotonic>, pub clock: Clock<Monotonic>,
pub should_stop: bool, pub should_stop: bool,
pub theme: cosmic::Theme,
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
pub egui: Egui, pub egui: Egui,
@ -330,6 +332,8 @@ impl State {
clock, clock,
should_stop: false, should_stop: false,
theme: cosmic::theme::system_preference(),
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
egui: Egui { egui: Egui {
active: false, active: false,

77
src/theme.rs Normal file
View file

@ -0,0 +1,77 @@
// insert into the event loop, a watcher for the theme & theme mode for changes
// update a Arc<Mutex<Theme>> 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<Srgba>) -> [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<Srgba>) -> [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<Srgba>) -> 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::<palette::Srgba>::dark_config()?;
let config_light_helper = Theme::<palette::Srgba>::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(())
}

View file

@ -229,6 +229,7 @@ impl<P: Program + Send + 'static> IcedElement<P> {
program: P, program: P,
size: impl Into<Size<i32, Logical>>, size: impl Into<Size<i32, Logical>>,
handle: LoopHandle<'static, crate::state::State>, handle: LoopHandle<'static, crate::state::State>,
theme: cosmic::Theme,
) -> IcedElement<P> { ) -> IcedElement<P> {
let size = size.into(); let size = size.into();
let mut renderer = let mut renderer =
@ -257,7 +258,7 @@ impl<P: Program + Send + 'static> IcedElement<P> {
pending_update: None, pending_update: None,
size, size,
cursor_pos: None, cursor_pos: None,
theme: Theme::dark(), // TODO theme,
renderer, renderer,
state, state,
debug, debug,
@ -308,6 +309,11 @@ impl<P: Program + Send + 'static> IcedElement<P> {
self.0.lock().unwrap().update(true); 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) { pub fn force_redraw(&self) {
let mut internal = self.0.lock().unwrap(); let mut internal = self.0.lock().unwrap();
for (_buffer, ref mut old_primitives) in internal.buffers.values_mut() { for (_buffer, ref mut old_primitives) in internal.buffers.values_mut() {

View file

@ -43,7 +43,7 @@ use crate::{
backend::render::{ backend::render::{
cursor, cursor,
element::{AsGlowRenderer, CosmicElement}, element::{AsGlowRenderer, CosmicElement},
render_output, render_workspace, CursorMode, CLEAR_COLOR, render_output, render_workspace, CursorMode,
}, },
shell::{CosmicMappedRenderElement, CosmicSurface, WorkspaceRenderElement}, shell::{CosmicMappedRenderElement, CosmicSurface, WorkspaceRenderElement},
state::{BackendData, ClientState, Common, State}, state::{BackendData, ClientState, Common, State},
@ -1015,7 +1015,12 @@ pub fn render_window_to_buffer(
renderer.bind(render_buffer).map_err(DTError::Rendering)?; 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(&params, &mut state.backend, None); let node = node_from_params(&params, &mut state.backend, None);

View file

@ -220,6 +220,7 @@ impl XdgShellHandler for State {
CosmicMapped::from(CosmicWindow::new( CosmicMapped::from(CosmicWindow::new(
surface, surface,
self.common.event_loop_handle.clone(), self.common.event_loop_handle.clone(),
self.common.theme.clone(),
)), )),
if workspace.is_tiled(&mapped) { if workspace.is_tiled(&mapped) {
ManagedLayer::Tiling ManagedLayer::Tiling