1
0
Fork 0
forked from wry/wry

theme: add bar-separator-width setting

This commit is contained in:
Stipe Kotarac 2025-12-01 18:15:11 +01:00
parent f5ed6f8fac
commit a6e629dd2f
16 changed files with 163 additions and 31 deletions

View file

@ -76,7 +76,7 @@ impl Color {
Self::BLACK
} else if r > a || g > a || b > a {
log::warn!(
"f32 values {:?} are not valid valid for a premultiplied color. Using solid black instead.",
"f32 values {:?} are not valid for a premultiplied color. Using solid black instead.",
[r, g, b, a]
);
Self::BLACK
@ -359,5 +359,9 @@ pub mod sized {
///
/// Default: 17
const 03 => BAR_HEIGHT,
/// The width of the bar's separator.
///
/// Default: 1
const 04 => BAR_SEPARATOR_WIDTH,
}
}

View file

@ -736,8 +736,8 @@ fn create_dummy_output(state: &Rc<State>) {
non_exclusive_rect_rel: Default::default(),
bar_rect: Default::default(),
bar_rect_rel: Default::default(),
bar_rect_with_underline: Default::default(),
underline_rect_rel: Default::default(),
bar_rect_with_separator: Default::default(),
bar_separator_rect_rel: Default::default(),
non_exclusive_rect: Default::default(),
render_data: Default::default(),
state: state.clone(),

View file

@ -2399,6 +2399,7 @@ impl ConfigProxyHandler {
TITLE_HEIGHT => ThemeSized::title_height,
BORDER_WIDTH => ThemeSized::border_width,
BAR_HEIGHT => ThemeSized::bar_height,
BAR_SEPARATOR_WIDTH => ThemeSized::bar_separator_width,
_ => return Err(CphError::UnknownSized(sized.0)),
};
Ok(sized)

View file

@ -16,6 +16,7 @@ use {
Axis, Direction,
input::{InputDevice, Seat},
keyboard::{Keymap, ModifiedKeySym},
theme::{BarPosition, sized::BAR_SEPARATOR_WIDTH},
video::{Connector, Transform},
},
std::{cell::Cell, ops::Deref, ptr, rc::Rc, time::Duration},
@ -301,6 +302,27 @@ impl TestConfig {
transform,
})
}
pub fn set_bar_separator_width(&self, width: i32) -> TestResult {
self.send(ClientMessage::SetSize {
sized: BAR_SEPARATOR_WIDTH,
size: width,
})
}
pub fn set_bar_position(&self, position: BarPosition) -> TestResult {
self.send(ClientMessage::SetBarPosition { position })
}
pub fn set_show_bar(&self, show: bool) -> TestResult {
self.send(ClientMessage::SetShowBar { show })
}
pub fn get_show_bar(&self) -> Result<bool, TestError> {
let reply = self.send_with_reply(ClientMessage::GetShowBar)?;
get_response!(reply, GetShowBar { show });
Ok(show)
}
}
impl Drop for TestConfig {

View file

@ -82,6 +82,7 @@ mod t0048_frame_callback;
mod t0049_surface_damage_backend;
mod t0050_fifo;
mod t0051_pointer_warp;
mod t0052_bar;
pub trait TestCase: Sync {
fn name(&self) -> &'static str;
@ -152,5 +153,6 @@ pub fn tests() -> Vec<&'static dyn TestCase> {
t0049_surface_damage_backend,
t0050_fifo,
t0051_pointer_warp,
t0052_bar,
}
}

67
src/it/tests/t0052_bar.rs Normal file
View file

@ -0,0 +1,67 @@
use {
crate::{
it::{test_error::TestError, testrun::TestRun},
tree::OutputNode,
},
jay_config::theme::BarPosition,
std::rc::Rc,
};
testcase!();
async fn test(run: Rc<TestRun>) -> Result<(), TestError> {
let setup = run.create_default_setup().await?;
test_bar(&run, &setup.output, 0).await?;
test_bar(&run, &setup.output, 1).await?;
test_bar(&run, &setup.output, 20).await?;
test_bar(&run, &setup.output, 100).await?;
Ok(())
}
async fn test_bar(
run: &TestRun,
output: &OutputNode,
separator_width: i32,
) -> Result<(), TestError> {
let output_rect = output.global.pos.get();
run.cfg.set_bar_separator_width(separator_width)?;
run.cfg.set_bar_position(BarPosition::Top)?;
run.sync().await;
let bar_height = run.state.theme.sizes.bar_height();
tassert_eq!(run.state.theme.sizes.bar_separator_width(), separator_width);
let bar_total_height = bar_height + separator_width;
let bar_rect = output.bar_rect_with_separator.get();
let ws_rect = output.workspace_rect.get();
tassert_eq!(bar_rect.y1(), output_rect.y1());
tassert_eq!(bar_rect.height(), bar_total_height);
tassert_eq!(ws_rect.y1(), output_rect.y1() + bar_total_height);
tassert_eq!(ws_rect.height(), output_rect.height() - bar_total_height);
run.cfg.set_bar_position(BarPosition::Bottom)?;
run.sync().await;
let bar_rect = output.bar_rect_with_separator.get();
let ws_rect = output.workspace_rect.get();
tassert_eq!(bar_rect.y2(), output_rect.y2());
tassert_eq!(bar_rect.height(), bar_total_height);
tassert_eq!(ws_rect.y2(), output_rect.y2() - bar_total_height);
tassert_eq!(ws_rect.height(), output_rect.height() - bar_total_height);
run.cfg.set_show_bar(false)?;
run.sync().await;
tassert_eq!(run.cfg.get_show_bar()?, false);
tassert_eq!(output.workspace_rect.get(), output_rect);
tassert_eq!(output.bar_rect_with_separator.get().is_empty(), true);
run.cfg.set_show_bar(true)?;
run.sync().await;
Ok(())
}

View file

@ -110,7 +110,7 @@ impl Renderer<'_> {
}
let c = theme.colors.separator.get();
self.base
.fill_boxes2(slice::from_ref(&rd.underline), &c, srgb, x, y);
.fill_boxes2(slice::from_ref(&rd.bar_separator), &c, srgb, x, y);
let c = theme.colors.unfocused_title_background.get();
self.base
.fill_boxes2(&rd.inactive_workspaces, &c, srgb, x, y);

View file

@ -233,8 +233,8 @@ impl ConnectorHandler {
non_exclusive_rect_rel: Default::default(),
bar_rect: Default::default(),
bar_rect_rel: Default::default(),
bar_rect_with_underline: Default::default(),
underline_rect_rel: Default::default(),
bar_rect_with_separator: Default::default(),
bar_separator_rect_rel: Default::default(),
render_data: Default::default(),
state: self.state.clone(),
is_dummy: false,

View file

@ -450,12 +450,17 @@ impl ThemeSizes {
self.title_height.val.get()
}
}
pub fn bar_separator_width(&self) -> i32 {
self.bar_separator_width.get()
}
}
sizes! {
title_height = (0, 1000, 17),
bar_height = (0, 1000, 17),
border_width = (0, 1000, 4),
bar_separator_width = (0, 1000, 1),
}
pub const DEFAULT_FONT: &str = "monospace 8";

View file

@ -95,8 +95,8 @@ pub struct OutputNode {
pub non_exclusive_rect_rel: Cell<Rect>,
pub bar_rect: Cell<Rect>,
pub bar_rect_rel: Cell<Rect>,
pub bar_rect_with_underline: Cell<Rect>,
pub underline_rect_rel: Cell<Rect>,
pub bar_rect_with_separator: Cell<Rect>,
pub bar_separator_rect_rel: Cell<Rect>,
pub render_data: RefCell<OutputRenderData>,
pub state: Rc<State>,
pub is_dummy: bool,
@ -593,8 +593,8 @@ impl OutputNode {
None
};
let active_id = self.workspace.get().map(|w| w.id);
rd.underline = self
.underline_rect_rel
rd.bar_separator = self
.bar_separator_rect_rel
.get()
.move_(-non_exclusive_rect_rel.x1(), -non_exclusive_rect_rel.y1());
for ws in self.workspaces.iter() {
@ -657,7 +657,7 @@ impl OutputNode {
}
}
let old_full_area = rd.full_area;
rd.full_area = self.bar_rect_with_underline.get();
rd.full_area = self.bar_rect_with_separator.get();
if self.title_visible.get() {
self.state.damage(rd.full_area.union(old_full_area));
}
@ -790,6 +790,7 @@ impl OutputNode {
pub fn update_rects(self: &Rc<Self>) {
let rect = self.global.pos.get();
let bh = self.state.theme.sizes.bar_height();
let bsw = self.state.theme.sizes.bar_separator_width();
let exclusive = self.exclusive_zones.get();
let y1 = rect.y1() + exclusive.top;
let x2 = rect.x2() - exclusive.right;
@ -802,39 +803,44 @@ impl OutputNode {
Rect::new_sized_unchecked(exclusive.left, exclusive.top, width, height);
let mut bar_rect = Rect::default();
let mut bar_rect_rel = Rect::default();
let mut bar_rect_with_underline = Rect::default();
let mut underline_rect_rel = Rect::default();
let mut bar_rect_with_separator = Rect::default();
let mut bar_separator_rect_rel = Rect::default();
let mut workspace_rect = non_exclusive_rect;
let mut workspace_rect_rel = non_exclusive_rect_rel;
if self.state.show_bar.get() {
let underline_rect;
let bar_separator_rect;
match self.state.theme.bar_position.get() {
BarPosition::Bottom => {
workspace_rect =
Rect::new_sized_unchecked(x1, y1, width, (height - bh - 1).max(0));
bar_rect_with_underline =
Rect::new_sized_unchecked(x1, y1 + height - bh - 1, width, bh + 1);
underline_rect = Rect::new_sized_unchecked(x1, y1 + height - bh - 1, width, 1);
Rect::new_sized_unchecked(x1, y1, width, (height - bh - bsw).max(0));
bar_rect_with_separator =
Rect::new_sized_unchecked(x1, y1 + height - bh - bsw, width, bh + bsw);
bar_separator_rect =
Rect::new_sized_unchecked(x1, y1 + height - bh - bsw, width, bsw);
bar_rect = Rect::new_sized_unchecked(x1, y1 + height - bh, width, bh);
}
BarPosition::Top | _ => {
bar_rect = Rect::new_sized_unchecked(x1, y1, width, bh);
underline_rect = Rect::new_sized_unchecked(x1, y1 + bh, width, 1);
bar_rect_with_underline = Rect::new_sized_unchecked(x1, y1, width, bh + 1);
workspace_rect =
Rect::new_sized_unchecked(x1, y1 + bh + 1, width, (height - bh - 1).max(0));
bar_separator_rect = Rect::new_sized_unchecked(x1, y1 + bh, width, bsw);
bar_rect_with_separator = Rect::new_sized_unchecked(x1, y1, width, bh + bsw);
workspace_rect = Rect::new_sized_unchecked(
x1,
y1 + bh + bsw,
width,
(height - bh - bsw).max(0),
);
}
}
bar_rect_rel = bar_rect.move_(-rect.x1(), -rect.y1());
underline_rect_rel = underline_rect.move_(-rect.x1(), -rect.y1());
bar_separator_rect_rel = bar_separator_rect.move_(-rect.x1(), -rect.y1());
workspace_rect_rel = workspace_rect.move_(-rect.x1(), -rect.y1());
}
self.non_exclusive_rect.set(non_exclusive_rect);
self.non_exclusive_rect_rel.set(non_exclusive_rect_rel);
self.bar_rect.set(bar_rect);
self.bar_rect_rel.set(bar_rect_rel);
self.bar_rect_with_underline.set(bar_rect_with_underline);
self.underline_rect_rel.set(underline_rect_rel);
self.bar_rect_with_separator.set(bar_rect_with_separator);
self.bar_separator_rect_rel.set(bar_separator_rect_rel);
self.workspace_rect.set(workspace_rect);
self.workspace_rect_rel.set(workspace_rect_rel);
self.update_tray_positions();
@ -1294,8 +1300,8 @@ impl OutputNode {
if ws.fullscreen.is_some() {
return None;
}
let bar_rect_with_underline = self.bar_rect_with_underline.get();
if bar_rect_with_underline.contains(x_abs, y_abs) {
let bar_rect_with_separator = self.bar_rect_with_separator.get();
if bar_rect_with_separator.contains(x_abs, y_abs) {
let rd = &*self.render_data.borrow();
let bar_rect = self.bar_rect.get();
let (x, _) = bar_rect.translate(x_abs, y_abs);
@ -1350,8 +1356,8 @@ impl OutputNode {
if !self.state.show_bar.get() {
return None;
}
let bar_rect_with_underline = self.bar_rect_with_underline.get();
if bar_rect_with_underline.not_contains(x_abs, y_abs) {
let bar_rect_with_separator = self.bar_rect_with_separator.get();
if bar_rect_with_separator.not_contains(x_abs, y_abs) {
return None;
}
let bar_rect = self.bar_rect.get();
@ -1508,7 +1514,7 @@ pub struct OutputWorkspaceRenderData {
pub struct OutputRenderData {
pub full_area: Rect,
pub active_workspace: Option<OutputWorkspaceRenderData>,
pub underline: Rect,
pub bar_separator: Rect,
pub inactive_workspaces: Vec<Rect>,
pub attention_requested_workspaces: Vec<Rect>,
pub captured_inactive_workspaces: Vec<Rect>,

View file

@ -209,6 +209,7 @@ pub struct Theme {
pub title_font: Option<String>,
pub bar_font: Option<String>,
pub bar_position: Option<BarPosition>,
pub bar_separator_width: Option<i32>,
}
#[derive(Debug, Clone)]

View file

@ -63,7 +63,7 @@ impl Parser for ThemeParser<'_> {
font,
title_font,
),
(bar_font, bar_position_val),
(bar_font, bar_position_val, bar_separator_width),
) = ext.extract((
(
opt(val("attention-requested-bg-color")),
@ -92,6 +92,7 @@ impl Parser for ThemeParser<'_> {
(
recover(opt(str("bar-font"))),
recover(opt(str("bar-position"))),
recover(opt(s32("bar-separator-width"))),
),
))?;
macro_rules! color {
@ -144,6 +145,7 @@ impl Parser for ThemeParser<'_> {
title_font: title_font.map(|f| f.value.to_string()),
bar_font: bar_font.map(|f| f.value.to_string()),
bar_position,
bar_separator_width: bar_separator_width.despan(),
})
}
}

View file

@ -976,6 +976,7 @@ impl State {
size!(BORDER_WIDTH, border_width);
size!(TITLE_HEIGHT, title_height);
size!(BAR_HEIGHT, bar_height);
size!(BAR_SEPARATOR_WIDTH, bar_separator_width);
macro_rules! font {
($fun:ident, $field:ident) => {
if let Some(font) = &theme.$field {

View file

@ -2012,6 +2012,11 @@
"description": "The position of the bar. Defaults to `top` if not set.",
"$ref": "#/$defs/BarPosition"
},
"bar-separator-width": {
"type": "integer",
"description": "The width of the bar's separator. Defaults to 1.",
"minimum": 0.0
},
"font": {
"type": "string",
"description": "The name of the font to use."

View file

@ -4577,6 +4577,16 @@ The table has the following fields:
The value of this field should be a [BarPosition](#types-BarPosition).
- `bar-separator-width` (optional):
The width of the bar's separator. Defaults to 1.
The value of this field should be a number.
The numbers should be integers.
The numbers should be greater than or equal to 0.
- `font` (optional):
The name of the font to use.

View file

@ -2228,6 +2228,12 @@ Theme:
ref: BarPosition
required: false
description: The position of the bar. Defaults to `top` if not set.
bar-separator-width:
kind: number
integer_only: true
minimum: 0
required: false
description: The width of the bar's separator. Defaults to 1.
font:
kind: string
required: false