1use crate::{
3 Result,
4 bar::widgets::{Text, TextStyle, Widget},
5 core::Context,
6};
7use penrose::{
8 core::{State, conn::Conn},
9 pure::geometry::Rect,
10 x::{Atom, XConn, XEvent, event::PropertyEvent},
11};
12
13#[derive(Clone, Debug, PartialEq)]
15pub struct RootWindowName {
16 inner: Text,
17}
18
19impl RootWindowName {
20 pub fn new(style: TextStyle, is_greedy: bool, right_justified: bool) -> Self {
22 Self {
23 inner: Text::new("penrose", style, is_greedy, right_justified),
24 }
25 }
26}
27
28impl<X: XConn> Widget<X> for RootWindowName {
29 fn draw(&mut self, ctx: &mut Context<'_>, s: usize, f: bool, w: u32, h: u32) -> Result<()> {
30 Widget::<X>::draw(&mut self.inner, ctx, s, f, w, h)
31 }
32
33 fn current_extent(&mut self, ctx: &mut Context<'_>, h: u32) -> Result<(u32, u32)> {
34 Widget::<X>::current_extent(&mut self.inner, ctx, h)
35 }
36
37 fn is_greedy(&self) -> bool {
38 Widget::<X>::is_greedy(&self.inner)
39 }
40
41 fn require_draw(&self) -> bool {
42 Widget::<X>::require_draw(&self.inner)
43 }
44
45 fn on_event(&mut self, event: &XEvent, _: &mut State<X>, x: &mut X) -> Result<()> {
46 let name_props = [Atom::NetWmName.as_ref(), Atom::WmName.as_ref()];
47
48 match event {
49 XEvent::PropertyNotify(PropertyEvent {
50 id, atom, is_root, ..
51 }) if *is_root && name_props.contains(&atom.as_ref()) => {
52 self.inner.set_text(x.client_title(*id)?)
53 }
54
55 _ => (),
56 }
57
58 Ok(())
59 }
60}
61
62#[derive(Clone, Debug, PartialEq)]
64pub struct ActiveWindowName {
65 inner: Text,
66 max_chars: usize,
67}
68
69impl ActiveWindowName {
70 pub fn new(max_chars: usize, style: TextStyle, is_greedy: bool, right_justified: bool) -> Self {
74 Self {
75 inner: Text::new("", style, is_greedy, right_justified),
76 max_chars: max_chars.max(3),
77 }
78 }
79
80 fn set_text(&mut self, txt: &str) {
81 if txt.chars().count() <= self.max_chars {
82 self.inner.set_text(txt);
83 } else {
84 let s: String = txt.chars().take(self.max_chars - 3).collect();
85 self.inner.set_text(format!("{}...", s));
86 }
87 }
88}
89
90impl<X: XConn> Widget<X> for ActiveWindowName {
91 fn draw(&mut self, ctx: &mut Context<'_>, s: usize, f: bool, w: u32, h: u32) -> Result<()> {
92 if f {
93 Widget::<X>::draw(&mut self.inner, ctx, s, f, w, h)
94 } else {
95 ctx.fill_bg(Rect::new(0, 0, w, h))
96 }
97 }
98
99 fn current_extent(&mut self, ctx: &mut Context<'_>, h: u32) -> Result<(u32, u32)> {
100 Widget::<X>::current_extent(&mut self.inner, ctx, h)
101 }
102
103 fn is_greedy(&self) -> bool {
104 Widget::<X>::is_greedy(&self.inner)
105 }
106
107 fn require_draw(&self) -> bool {
108 Widget::<X>::require_draw(&self.inner)
109 }
110
111 fn on_refresh(&mut self, state: &mut State<X>, x: &mut X) -> Result<()> {
112 if let Some(id) = state.client_set.current_client() {
113 self.set_text(&x.client_title(*id)?)
114 } else {
115 self.set_text("")
116 }
117
118 Ok(())
119 }
120
121 fn on_event(&mut self, event: &XEvent, state: &mut State<X>, x: &mut X) -> Result<()> {
122 let name_props = [Atom::NetWmName.as_ref(), Atom::WmName.as_ref()];
123
124 if let Some(focused) = state.client_set.current_client() {
125 match event {
126 XEvent::PropertyNotify(PropertyEvent { id, atom, .. })
127 if id == focused && name_props.contains(&atom.as_ref()) =>
128 {
129 self.set_text(&x.client_title(*id)?)
130 }
131
132 _ => (),
133 }
134 }
135
136 Ok(())
137 }
138}
139
140#[derive(Clone, Debug, PartialEq)]
142pub struct CurrentLayout {
143 inner: Text,
144}
145
146impl CurrentLayout {
147 pub fn new(style: TextStyle) -> Self {
149 Self {
150 inner: Text::new("", style, false, false),
151 }
152 }
153}
154
155impl<X: XConn> Widget<X> for CurrentLayout {
156 fn draw(&mut self, ctx: &mut Context<'_>, s: usize, f: bool, w: u32, h: u32) -> Result<()> {
157 Widget::<X>::draw(&mut self.inner, ctx, s, f, w, h)
158 }
159
160 fn current_extent(&mut self, ctx: &mut Context<'_>, h: u32) -> Result<(u32, u32)> {
161 Widget::<X>::current_extent(&mut self.inner, ctx, h)
162 }
163
164 fn is_greedy(&self) -> bool {
165 Widget::<X>::is_greedy(&self.inner)
166 }
167
168 fn require_draw(&self) -> bool {
169 Widget::<X>::require_draw(&self.inner)
170 }
171
172 fn on_refresh(&mut self, state: &mut State<X>, _: &mut X) -> Result<()> {
173 let layout_name = state.client_set.current_workspace().layout_name();
174 self.inner.set_text(format!("[{layout_name}]"));
175
176 Ok(())
177 }
178}