diff options
| author | cashmere <cashmere@autistici.org> | 2026-07-21 14:07:42 +0200 |
|---|---|---|
| committer | cashmere <cashmere@autistici.org> | 2026-07-21 14:07:42 +0200 |
| commit | 198f374a18b5c8a0e21f7d41125393aa89523f5c (patch) | |
| tree | ad8d32cc498b1b2715a5e71e5f438bf4bacfca53 /src/bar.rs | |
| parent | 85f0a9e875eee768766d7bdd24272d348f6b1e33 (diff) | |
| download | i3bar-mango-198f374a18b5c8a0e21f7d41125393aa89523f5c.tar.gz | |
mango: show focused window next to tags, fix mmsg lookup, 0.15.x compat
- new focused-window block ({icon} {app_id} - {title}) driven by the
active_client field of mmsg watch all-monitors (mangowm >= 0.14)
- resolve program icons via freedesktop icon themes/.desktop files
(new icon module, cairo png feature, cached per app_id)
- new show_focused_window config option (default true)
- run mmsg from PATH instead of hardcoded /usr/bin/mmsg (broken on NixOS)
- handle null active_client fields (no focused client) without failing
to parse the whole event
- drop stale TODO comment and unused variable in mango provider
- add .justfile run recipe exporting MANGO_INSTANCE_SIGNATURE
Diffstat (limited to 'src/bar.rs')
| -rw-r--r-- | src/bar.rs | 64 |
1 files changed, 63 insertions, 1 deletions
@@ -14,7 +14,7 @@ use crate::protocol::*; use crate::shared_state::SharedState; use crate::state::State; use crate::text::{self, ComputedText, RenderOptions}; -use crate::wm_info_provider::Tag; +use crate::wm_info_provider::{FocusedWindow, Tag}; pub struct Bar { pub output: Output, @@ -33,10 +33,12 @@ pub struct Bar { tags: Vec<Tag>, layout_name: Option<String>, mode_name: Option<String>, + focused_window: Option<FocusedWindow>, tags_btns: ButtonManager<u32>, tags_computed: Vec<(u32, ColorPair, ComputedText)>, layout_name_computed: Option<ComputedText>, mode_computed: Option<ComputedText>, + focused_window_computed: Option<ComputedText>, } #[derive(Debug, PartialEq)] @@ -79,10 +81,12 @@ impl Bar { tags: Vec::new(), layout_name: None, mode_name: None, + focused_window: None, tags_btns: Default::default(), tags_computed: Vec::new(), layout_name_computed: None, mode_computed: None, + focused_window_computed: None, } } @@ -112,6 +116,11 @@ impl Bar { self.mode_computed = None; } + pub fn set_focused_window(&mut self, focused_window: Option<FocusedWindow>) { + self.focused_window = focused_window; + self.focused_window_computed = None; + } + pub fn click( &mut self, conn: &mut Connection<State>, @@ -287,6 +296,59 @@ impl Bar { } } + // Display focused window + if ss.config.show_focused_window + && let Some(focused_window) = &self.focused_window + { + if let Some(icon) = ss.icon_cache.get(&focused_window.app_id, self.height) { + let icon_size = height_f - 4.0; + let scale = icon_size / (icon.width() as f64).max(icon.height() as f64); + let icon_w = icon.width() as f64 * scale; + let icon_h = icon.height() as f64 * scale; + cairo_ctx.save().unwrap(); + cairo_ctx.translate( + offset_left + (icon_size - icon_w) / 2.0, + (height_f - icon_h) / 2.0, + ); + cairo_ctx.scale(scale, scale); + cairo_ctx.set_source_surface(icon, 0.0, 0.0).unwrap(); + cairo_ctx.paint().unwrap(); + cairo_ctx.restore().unwrap(); + offset_left += icon_size + 5.0; + } + let text = self.focused_window_computed.get_or_insert_with(|| { + let label = if focused_window.title.is_empty() { + focused_window.app_id.clone() + } else { + format!("{} - {}", focused_window.app_id, focused_window.title) + }; + ComputedText::new( + &label, + text::Attributes { + font: &ss.config.font, + padding_left: 10.0, + padding_right: 10.0, + min_width: None, + align: Default::default(), + markup: false, + }, + ) + }); + text.render( + &cairo_ctx, + RenderOptions { + x_offset: offset_left, + bar_height: height_f, + fg_color: ss.config.tag_inactive_fg, + bg_color: None, + r_left: 0.0, + r_right: 0.0, + overlap: 0.0, + }, + ); + offset_left += text.width; + } + // Display mode if ss.config.show_mode { if let Some(mode) = &self.mode_name { |
