Skip to content

Commit c3e34cc

Browse files
committed
Add support for special theme for unfocused outputs
I use multiple outputs, and as such often need to remember which output is currently focused. Fortunately, river tells us which output is currently in focus. Therefore, we can track this in river's info provider, and then use this value to decide which theme to use when drawing the bar. For users that do not need or want this extra differentiation, setting the `[theme.palette]` values, will result in the previous behaviour as the `[theme.unfocused_palette]` will inherit them if not set. By default, that is with `[theme.palette]` unset, we will use a darker white for the `unfocused_palette`'s foreground, to signify that this output is unfocused. I am not familiar enough with niri or hyprland to know if they can support something like this too. As such, both of their information providers do not override the default `is_output_focused` method. In the future moving even more values to the themes might be a viable approach (i.e., the font), but with the current values most workflows should be possible (e.g., hiding inactive tags on the unfocused output, whilst showing them on the focused one or simply setting darker colours).
1 parent 73446ca commit c3e34cc

6 files changed

Lines changed: 299 additions & 83 deletions

File tree

src/bar.rs

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ use wayrs_utils::shm_alloc::BufferSpec;
66
use crate::blocks_cache::ComputedBlock;
77
use crate::button_manager::ButtonManager;
88
use crate::color::Color;
9-
use crate::config::{Config, Position};
9+
use crate::config::Position;
1010
use crate::i3bar_protocol;
1111
use crate::output::Output;
1212
use crate::pointer_btn::PointerBtn;
1313
use crate::protocol::*;
14-
use crate::shared_state::SharedState;
14+
use crate::shared_state::{SharedState, sfo};
1515
use crate::state::State;
1616
use crate::text::{self, ComputedText, RenderOptions};
1717
use crate::wm_info_provider::Tag;
@@ -194,36 +194,60 @@ impl Bar {
194194
let cairo_ctx = cairo::Context::new(&cairo_surf).expect("cairo context");
195195
cairo_ctx.scale(scale_f, scale_f);
196196

197-
if !ss.config.blend {
197+
if !sfo!(ss, &self.output, blend) {
198198
cairo_ctx.set_operator(cairo::Operator::Source);
199199
}
200200

201201
// Background
202-
if ss.config.blend {
202+
if sfo!(ss, &self.output, blend) {
203203
cairo_ctx.save().unwrap();
204204
cairo_ctx.set_operator(cairo::Operator::Source);
205205
}
206-
ss.config.background.apply(&cairo_ctx);
206+
sfo!(ss, &self.output, background).apply(&cairo_ctx);
207207
cairo_ctx.paint().unwrap();
208-
if ss.config.blend {
208+
if sfo!(ss, &self.output, blend) {
209209
cairo_ctx.restore().unwrap();
210210
}
211211

212212
// Compute tags
213-
if ss.config.show_tags && self.tags_computed.is_empty() {
213+
if sfo!(ss, &self.output, show_tags) && self.tags_computed.is_empty() {
214214
for tag in &self.tags {
215215
let (bg, fg) = if tag.is_urgent {
216-
(ss.config.tag_urgent_bg, ss.config.tag_urgent_fg)
216+
(
217+
sfo!(ss, &self.output, tag_urgent_bg),
218+
sfo!(ss, &self.output, tag_urgent_fg),
219+
)
217220
} else if tag.is_focused {
218-
(ss.config.tag_focused_bg, ss.config.tag_focused_fg)
221+
(
222+
sfo!(ss, &self.output, tag_focused_bg),
223+
sfo!(ss, &self.output, tag_focused_fg),
224+
)
219225
} else if tag.is_active {
220-
(ss.config.tag_bg, ss.config.tag_fg)
221-
} else if !ss.config.hide_inactive_tags {
222-
(ss.config.tag_inactive_bg, ss.config.tag_inactive_fg)
226+
(
227+
sfo!(ss, &self.output, tag_bg),
228+
sfo!(ss, &self.output, tag_fg),
229+
)
230+
} else if !sfo!(ss, &self.output, hide_inactive_tags) {
231+
(
232+
sfo!(ss, &self.output, tag_inactive_bg),
233+
sfo!(ss, &self.output, tag_inactive_fg),
234+
)
223235
} else {
224236
continue;
225237
};
226-
let comp = compute_tag_label(&tag.name, &ss.config);
238+
let comp = {
239+
ComputedText::new(
240+
&tag.name,
241+
text::Attributes {
242+
font: &ss.config.font,
243+
padding_left: ss.config.tags_padding,
244+
padding_right: ss.config.tags_padding,
245+
min_width: None,
246+
align: Default::default(),
247+
markup: false,
248+
},
249+
)
250+
};
227251
self.tags_computed
228252
.push((tag.id, ColorPair { bg, fg }, comp));
229253
}
@@ -256,7 +280,7 @@ impl Bar {
256280
}
257281

258282
// Display layout name
259-
if ss.config.show_layout_name {
283+
if sfo!(ss, &self.output, show_layout_name) {
260284
if let Some(layout_name) = &self.layout_name {
261285
let text = self.layout_name_computed.get_or_insert_with(|| {
262286
ComputedText::new(
@@ -276,7 +300,7 @@ impl Bar {
276300
RenderOptions {
277301
x_offset: offset_left,
278302
bar_height: height_f,
279-
fg_color: ss.config.tag_inactive_fg,
303+
fg_color: sfo!(ss, &self.output, tag_inactive_fg),
280304
bg_color: None,
281305
r_left: 0.0,
282306
r_right: 0.0,
@@ -288,7 +312,7 @@ impl Bar {
288312
}
289313

290314
// Display mode
291-
if ss.config.show_mode {
315+
if sfo!(ss, &self.output, show_mode) {
292316
if let Some(mode) = &self.mode_name {
293317
let text = self.mode_computed.get_or_insert_with(|| {
294318
ComputedText::new(
@@ -308,8 +332,8 @@ impl Bar {
308332
RenderOptions {
309333
x_offset: offset_left,
310334
bar_height: height_f,
311-
fg_color: ss.config.tag_urgent_fg,
312-
bg_color: Some(ss.config.tag_urgent_bg),
335+
fg_color: sfo!(ss, &self.output, tag_urgent_fg),
336+
bg_color: Some(sfo!(ss, &self.output, tag_urgent_bg)),
313337
r_left: ss.config.tags_r,
314338
r_right: ss.config.tags_r,
315339
overlap: 0.0,
@@ -322,7 +346,8 @@ impl Bar {
322346
// Display the blocks
323347
render_blocks(
324348
&cairo_ctx,
325-
&ss.config,
349+
ss,
350+
&self.output,
326351
ss.blocks_cache.get_computed(),
327352
&mut self.blocks_btns,
328353
offset_left,
@@ -360,24 +385,25 @@ impl Bar {
360385

361386
self.hidden = false;
362387

363-
let config = &shared_state.config;
388+
let ss = shared_state;
364389

365-
self.layer_surface.set_size(conn, 0, config.height);
366-
self.layer_surface.set_anchor(conn, config.position.into());
390+
self.layer_surface.set_size(conn, 0, ss.config.height);
391+
self.layer_surface
392+
.set_anchor(conn, ss.config.position.into());
367393
self.layer_surface.set_margin(
368394
conn,
369-
config.margin_top,
370-
config.margin_right,
371-
config.margin_bottom,
372-
config.margin_left,
395+
ss.config.margin_top,
396+
ss.config.margin_right,
397+
ss.config.margin_bottom,
398+
ss.config.margin_left,
373399
);
374400
self.layer_surface.set_exclusive_zone(
375401
conn,
376-
(shared_state.config.height) as i32
377-
+ if config.position == Position::Top {
378-
shared_state.config.margin_bottom
402+
(ss.config.height) as i32
403+
+ if ss.config.position == Position::Top {
404+
ss.config.margin_bottom
379405
} else {
380-
shared_state.config.margin_top
406+
ss.config.margin_top
381407
},
382408
);
383409

@@ -395,7 +421,8 @@ impl Bar {
395421
#[allow(clippy::too_many_arguments)]
396422
fn render_blocks(
397423
context: &cairo::Context,
398-
config: &Config,
424+
ss: &SharedState,
425+
output: &Output,
399426
blocks: &[ComputedBlock],
400427
buttons: &mut ButtonManager<(Option<String>, Option<String>)>,
401428
offset_left: f64,
@@ -501,11 +528,15 @@ fn render_blocks(
501528
RenderOptions {
502529
x_offset: full_width - blocks_width,
503530
bar_height: full_height,
504-
fg_color: block.color.unwrap_or(config.color),
531+
fg_color: block.color.unwrap_or(sfo!(ss, &output, color)),
505532
bg_color: block.background,
506-
r_left: if i == 0 { config.blocks_r } else { 0.0 },
507-
r_right: if i + 1 == s_len { config.blocks_r } else { 0.0 },
508-
overlap: config.blocks_overlap,
533+
r_left: if i == 0 { ss.config.blocks_r } else { 0.0 },
534+
r_right: if i + 1 == s_len {
535+
ss.config.blocks_r
536+
} else {
537+
0.0
538+
},
539+
overlap: ss.config.blocks_overlap,
509540
},
510541
);
511542
buttons.push(
@@ -517,10 +548,10 @@ fn render_blocks(
517548
}
518549

519550
let separator_block_width = series.separator_block_width as f64;
520-
if series.separator && config.separator_width > 0.0 {
551+
if series.separator && ss.config.separator_width > 0.0 {
521552
let x = full_width - blocks_width + separator_block_width * 0.5;
522-
config.separator.apply(context);
523-
context.set_line_width(config.separator_width);
553+
sfo!(ss, &output, separator).apply(context);
554+
context.set_line_width(ss.config.separator_width);
524555
context.move_to(x, full_height * 0.1);
525556
context.line_to(x, full_height * 0.9);
526557
context.stroke().unwrap();
@@ -531,20 +562,6 @@ fn render_blocks(
531562
context.reset_clip();
532563
}
533564

534-
pub fn compute_tag_label(label: &str, config: &Config) -> ComputedText {
535-
ComputedText::new(
536-
label,
537-
text::Attributes {
538-
font: &config.font.0,
539-
padding_left: config.tags_padding,
540-
padding_right: config.tags_padding,
541-
min_width: None,
542-
align: Default::default(),
543-
markup: false,
544-
},
545-
)
546-
}
547-
548565
fn layer_surface_cb(ctx: EventCtx<State, ZwlrLayerSurfaceV1>) {
549566
match ctx.event {
550567
zwlr_layer_surface_v1::Event::Configure(args) => {

src/config.rs renamed to src/config/mod.rs

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,26 @@
11
use crate::color::Color;
2+
use crate::config::theme::Theme;
23
use crate::protocol::{zwlr_layer_shell_v1, zwlr_layer_surface_v1};
4+
35
use anyhow::{Context, Result};
46
use pangocairo::pango::FontDescription;
57
use serde::{Deserialize, de};
8+
69
use std::collections::HashMap;
710
use std::fs::read_to_string;
811
use std::ops::Deref;
912
use std::path::{Path, PathBuf};
1013
use std::{env, fmt};
1114

15+
mod theme;
16+
1217
#[derive(Deserialize, Debug)]
1318
#[serde(deny_unknown_fields, default)]
1419
pub struct Config {
15-
// command
1620
pub command: Option<String>,
17-
// colors
18-
pub background: Color,
19-
pub color: Color,
20-
pub separator: Color,
21-
pub tag_fg: Color,
22-
pub tag_bg: Color,
23-
pub tag_focused_fg: Color,
24-
pub tag_focused_bg: Color,
25-
pub tag_urgent_fg: Color,
26-
pub tag_urgent_bg: Color,
27-
pub tag_inactive_fg: Color,
28-
pub tag_inactive_bg: Color,
21+
22+
pub theme: Theme,
23+
2924
// font and size
3025
pub font: Font,
3126
pub height: u32,
@@ -39,27 +34,46 @@ pub struct Config {
3934
pub tags_margin: f64,
4035
pub blocks_r: f64,
4136
pub blocks_overlap: f64,
37+
4238
// misc
4339
pub position: Position,
4440
pub layer: Layer,
45-
pub hide_inactive_tags: bool,
4641
pub invert_touchpad_scrolling: bool,
47-
pub show_tags: bool,
48-
pub show_layout_name: bool,
49-
pub blend: bool,
50-
pub show_mode: bool,
5142
pub start_hidden: bool,
43+
5244
// wm-specific
5345
pub wm: WmConfig,
46+
5447
// overrides
5548
pub output: HashMap<String, OutputOverrides>,
5649
}
5750

58-
impl Default for Config {
51+
#[derive(Debug)]
52+
pub struct Palette {
53+
// colors
54+
pub background: Color,
55+
pub color: Color,
56+
pub separator: Color,
57+
pub tag_fg: Color,
58+
pub tag_bg: Color,
59+
pub tag_focused_fg: Color,
60+
pub tag_focused_bg: Color,
61+
pub tag_urgent_fg: Color,
62+
pub tag_urgent_bg: Color,
63+
pub tag_inactive_fg: Color,
64+
pub tag_inactive_bg: Color,
65+
66+
// Additional shown stuff
67+
pub hide_inactive_tags: bool,
68+
pub show_tags: bool,
69+
pub show_layout_name: bool,
70+
pub blend: bool,
71+
pub show_mode: bool,
72+
}
73+
74+
impl Default for Palette {
5975
fn default() -> Self {
6076
Self {
61-
command: None,
62-
6377
// A kind of gruvbox theme
6478
background: Color::from_rgba_hex(0x282828ff),
6579
color: Color::from_rgba_hex(0xffffffff),
@@ -73,6 +87,22 @@ impl Default for Config {
7387
tag_inactive_fg: Color::from_rgba_hex(0xd79921ff),
7488
tag_inactive_bg: Color::from_rgba_hex(0x282828ff),
7589

90+
hide_inactive_tags: true,
91+
show_layout_name: true,
92+
show_tags: true,
93+
blend: true,
94+
show_mode: true,
95+
}
96+
}
97+
}
98+
99+
impl Default for Config {
100+
fn default() -> Self {
101+
Self {
102+
command: None,
103+
104+
theme: Theme::default(),
105+
76106
font: Font::new("monospace 10"),
77107
height: 24,
78108
margin_top: 0,
@@ -88,12 +118,7 @@ impl Default for Config {
88118

89119
position: Position::Top,
90120
layer: Layer::Top,
91-
hide_inactive_tags: true,
92121
invert_touchpad_scrolling: true,
93-
show_tags: true,
94-
show_layout_name: true,
95-
blend: true,
96-
show_mode: true,
97122
start_hidden: false,
98123

99124
wm: WmConfig {

0 commit comments

Comments
 (0)