Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions jay-config/src/_private/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2311,6 +2311,22 @@ impl ConfigClient {
self.send(&ClientMessage::SetWindowMatcherInitialFloatingPosition { matcher, x, y });
}

pub fn set_window_size(&self, window: Window, sized: Resizable, size: Option<i32>) {
self.send(&ClientMessage::SetWindowSize {
window,
sized,
size,
});
}

pub fn set_window_color(&self, window: Window, colorable: Colorable, color: Option<Color>) {
self.send(&ClientMessage::SetWindowColor {
window,
colorable,
color,
});
}

pub fn set_window_matcher_latch_handler(
&self,
matcher: WindowMatcher,
Expand Down
10 changes: 10 additions & 0 deletions jay-config/src/_private/ipc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,16 @@ pub enum ClientMessage<'a> {
target: ContainerTarget,
axis: RelativeAxis,
},
SetWindowSize {
window: Window,
sized: Resizable,
size: Option<i32>,
},
SetWindowColor {
window: Window,
colorable: Colorable,
color: Option<Color>,
},
}

#[derive(Serialize, Deserialize, Debug)]
Expand Down
17 changes: 17 additions & 0 deletions jay-config/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ use crate::Workspace;
use crate::client::Client;
use crate::client::ClientCriterion;
use crate::input::Seat;
use crate::theme::Color;
use crate::theme::colors::Colorable;
use crate::theme::sized::Resizable;
use serde::Deserialize;
use serde::Serialize;
use std::ops::Deref;
Expand Down Expand Up @@ -309,6 +312,20 @@ impl Window {
let (_, _, width, height) = get!((0, 0)).get_window_position(self);
(width, height)
}

/// Overrides a theme size for this window.
///
/// A value of `None` removes the override so that the global theme size is used.
pub fn set_size(self, sized: Resizable, size: Option<i32>) {
get!().set_window_size(self, sized, size);
}

/// Overrides a theme color for this window.
///
/// A value of `None` removes the override so that the global theme color is used.
pub fn set_color(self, colorable: Colorable, color: Option<Color>) {
get!().set_window_color(self, colorable, color);
}
}

/// A window matcher.
Expand Down
60 changes: 60 additions & 0 deletions src/config/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ use crate::state::OutputData;
use crate::state::State;
use crate::tagged_acceptor::TaggedAcceptorError;
use crate::theme::ThemeColored;
use crate::theme::ThemeOverrides;
use crate::theme::ThemeSized;
use crate::tree::ContainerSplit;
use crate::tree::ContainerTarget;
Expand Down Expand Up @@ -2886,6 +2887,40 @@ impl ConfigProxyHandler {
Ok(())
}

fn handle_set_window_size(
&self,
window: Window,
sized: Resizable,
size: Option<i32>,
) -> Result<(), CphError> {
let sized = self.get_sized(sized)?;
if let Some(size) = size
&& (size < sized.min() || size > sized.max())
{
return Err(CphError::InvalidSize(size, sized));
}
let window = self.get_window(window)?;
if update_theme_overrides(window.tl_data(), |o| o.sizes[sized][LiveTL].set(size)) {
self.state.spaces_changed();
}
Ok(())
}

fn handle_set_window_color(
&self,
window: Window,
colorable: Colorable,
color: Option<jay_config::theme::Color>,
) -> Result<(), CphError> {
let colored = self.get_color(colorable)?;
let window = self.get_window(window)?;
let color = color.map(|c| c.into());
if update_theme_overrides(window.tl_data(), |o| o.colors[colored][LiveTL].set(color)) {
self.state.colors_changed();
}
Ok(())
}

fn handle_set_pointer_revert_key(&self, seat: Seat, key: KeySym) -> Result<(), CphError> {
self.get_seat(seat)?.set_pointer_revert_key(key);
Ok(())
Expand Down Expand Up @@ -4011,6 +4046,20 @@ impl ConfigProxyHandler {
ClientMessage::SetWindowMatcherInitialFloatingPosition { matcher, x, y } => self
.handle_set_window_matcher_initial_floating_position(matcher, x, y)
.wrn("set_window_matcher_initial_floating_position")?,
ClientMessage::SetWindowSize {
window,
sized,
size,
} => self
.handle_set_window_size(window, sized, size)
.wrn("set_window_size")?,
ClientMessage::SetWindowColor {
window,
colorable,
color,
} => self
.handle_set_window_color(window, colorable, color)
.wrn("set_window_color")?,
ClientMessage::SetPointerRevertKey { seat, key } => self
.handle_set_pointer_revert_key(seat, key)
.wrn("set_pointer_revert_key")?,
Expand Down Expand Up @@ -4371,6 +4420,17 @@ impl ConfigProxyHandler {
}
}

/// Applies `f` to the theme overrides of `data` and returns whether they changed.
fn update_theme_overrides(data: &ToplevelData, f: impl FnOnce(&mut ThemeOverrides)) -> bool {
let mut new = data.theme_overrides.clone();
f(&mut new);
if data.theme_overrides == new {
return false;
}
data.set_theme_overrides(new);
true
}

#[derive(Debug, Error)]
enum CphError {
#[error("Tried to set an unknown accel profile: {}", (.0).0)]
Expand Down
21 changes: 12 additions & 9 deletions src/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use crate::renderer::renderer_base::RendererBase;
use crate::scale::Scale;
use crate::state::State;
use crate::theme::Color;
use crate::theme::ThemeColored;
use crate::tree::ContainerChildType;
use crate::tree::ContainerNode;
use crate::tree::DisplayNode;
Expand Down Expand Up @@ -339,7 +340,7 @@ impl Renderer<'_> {
let c = self.state.theme.colors.separator.get();
self.base
.fill_boxes2(&rd.underline_rects, &c, srgb, perceptual, x, y);
let c = self.state.theme.focused_border_color();
let c = self.state.theme.focused_border_color(RenderTL);
self.base
.fill_boxes2(&rd.active_border_rects, &c, srgb, perceptual, x, y);
let c = self.state.theme.colors.border.get();
Expand Down Expand Up @@ -646,23 +647,25 @@ impl Renderer<'_> {
_ => return,
};
let pos = ns.position.get();
let theme = &self.state.theme;
let theme = self
.state
.theme_view(Some(&child.tl_data().theme_overrides));
let th = theme.title_height(RenderTL);
let tpuh = theme.title_plus_underline_height(RenderTL);
let tuh = theme.title_underline_height(RenderTL);
let bw = theme.sizes.border_width.get(RenderTL);
let bw = theme.border_width(RenderTL);
let bc = match ns.active.get() {
true => theme.focused_border_color(),
false => theme.colors.border.get(),
true => theme.focused_border_color(RenderTL),
false => theme.color(ThemeColored::border, RenderTL),
};
let tc = if ns.active.get() {
theme.colors.focused_title_background.get()
theme.color(ThemeColored::focused_title_background, RenderTL)
} else if ns.attention_requested.get() {
theme.colors.attention_requested_background.get()
theme.color(ThemeColored::attention_requested_background, RenderTL)
} else {
theme.colors.unfocused_title_background.get()
theme.color(ThemeColored::unfocused_title_background, RenderTL)
};
let uc = theme.colors.separator.get();
let uc = theme.color(ThemeColored::separator, RenderTL);
let borders = [
Rect::new_sized_saturating(x, y, pos.width(), bw),
Rect::new_sized_saturating(x, y + bw, bw, pos.height() - bw),
Expand Down
33 changes: 31 additions & 2 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,9 @@ use crate::theme::Color;
use crate::theme::ContainerBordersSetting;
use crate::theme::Theme;
use crate::theme::ThemeColored;
use crate::theme::ThemeOverrides;
use crate::theme::ThemeSized;
use crate::theme::ThemeView;
use crate::time::Time;
use crate::transactions::TransactionData;
use crate::transactions::Transactionable;
Expand Down Expand Up @@ -1997,6 +1999,32 @@ impl State {
self.config.get()?.initial_tile_state(data)
}

/// Returns a view of the theme through `overrides`.
pub fn theme_view<'a>(&'a self, overrides: Option<&'a ThemeOverrides>) -> ThemeView<'a> {
self.theme.view_with_overrides(overrides)
}

/// Removes the theme overrides of all toplevels.
///
/// The overrides are owned by the config, therefore they must not survive a config
/// reload. The new config re-applies them via its window rules.
fn clear_theme_overrides(self: &Rc<Self>) {
let mut any = false;
for tl in self.toplevels.lock().values() {
if let Some(tl) = tl.upgrade() {
let data = tl.tl_data();
if !data.theme_overrides.is_empty(LiveTL) {
any = true;
data.set_theme_overrides(Default::default());
}
}
}
if any {
self.spaces_changed();
self.colors_changed();
}
}

pub fn update_capabilities(
&self,
data: &Rc<Client>,
Expand Down Expand Up @@ -2149,7 +2177,7 @@ impl State {
}
}

fn colors_changed(self: &Rc<Self>) {
pub fn colors_changed(self: &Rc<Self>) {
self.colors_changed.set(true);
self.theme_changed.trigger();
}
Expand Down Expand Up @@ -2178,6 +2206,7 @@ impl State {
for seat in self.globals.seats.lock().values() {
seat.clear_shortcuts();
}
self.clear_theme_overrides();
}
self.config_locked_shortcuts.set(false);
config.configure(true);
Expand All @@ -2202,7 +2231,7 @@ impl State {
self.trigger_cci(CCI_COMPOSITOR);
}

fn spaces_changed(self: &Rc<Self>) {
pub fn spaces_changed(self: &Rc<Self>) {
self.spaces_changed.set(true);
self.theme_changed.trigger();
}
Expand Down
Loading
Loading