1use serde::{Deserialize, Serialize};
24use zbus::{
25 interface,
26 object_server::SignalEmitter,
27 zvariant::{ObjectPath, OwnedValue, Type, Value},
28};
29
30#[derive(Clone, PartialEq, Type, OwnedValue, Value, Debug, Default)]
31pub struct IconPixmap {
32 pub width: i32,
33 pub height: i32,
34 pub data: Vec<u8>,
35}
36
37#[derive(Clone, PartialEq, Type, OwnedValue, Value, Default, Debug)]
38pub struct ToolTip {
39 pub icon: String,
40 pub data: Vec<IconPixmap>,
41 pub title: String,
42 pub description: String,
43}
44
45#[derive(Clone, PartialEq, Type, OwnedValue, Value, Debug, Default, Serialize, Deserialize)]
46#[zvariant(signature = "s")]
47pub enum NotifierStatus {
48 #[default]
49 Active,
50 Passive,
51 NeedsAttention,
52}
53
54const MENU_PATH: ObjectPath = ObjectPath::from_static_str_unchecked("/MenuBar");
55
56#[derive(
57 Clone, Copy, PartialEq, Type, OwnedValue, Value, Debug, Default, Serialize, Deserialize,
58)]
59#[zvariant(signature = "s")]
60pub enum Category {
61 #[default]
67 ApplicationStatus,
68 Communications,
71 SystemServices,
75 Hardware,
78}
79
80pub trait StatusNotifierItem {
81 type State;
82 fn boot(&self) -> Self::State;
83 fn id(&self) -> String;
84 #[allow(unused)]
85 fn activate(&self, state: &mut Self::State, x: i32, y: i32) -> zbus::fdo::Result<()> {
86 Ok(())
87 }
88 fn context_menu(&self, _state: &mut Self::State, _x: i32, _y: i32) -> zbus::fdo::Result<()> {
89 Err(zbus::fdo::Error::NotSupported("Error".to_owned()))
90 }
91 fn scroll(
92 &self,
93 _state: &mut Self::State,
94 _delta: i32,
95 _orientation: &str,
96 ) -> zbus::fdo::Result<()> {
97 Err(zbus::fdo::Error::NotSupported("Error".to_owned()))
98 }
99 fn secondary_activate(
100 &self,
101 _state: &mut Self::State,
102 _x: i32,
103 _y: i32,
104 ) -> zbus::fdo::Result<()> {
105 Err(zbus::fdo::Error::NotSupported("Error".to_owned()))
106 }
107
108 #[allow(unused)]
109 fn tool_tip(&self, state: &Self::State) -> zbus::fdo::Result<ToolTip> {
110 Err(zbus::fdo::Error::NotSupported("Unimplemented".to_string()))
111 }
112
113 #[allow(unused)]
114 fn icon_theme_path(&self, state: &Self::State) -> zbus::fdo::Result<String> {
115 Err(zbus::fdo::Error::NotSupported("Unimplemented".to_string()))
116 }
117
118 #[allow(unused)]
119 fn icon_name(&self, state: &Self::State) -> zbus::fdo::Result<String> {
120 Err(zbus::fdo::Error::NotSupported("Unimplemented".to_string()))
121 }
122
123 #[allow(unused)]
124 fn icon_pixmap(&self, state: &Self::State) -> zbus::fdo::Result<Vec<IconPixmap>> {
125 Err(zbus::fdo::Error::NotSupported("Unimplemented".to_string()))
126 }
127
128 #[allow(unused)]
129 fn attention_icon_name(&self, state: &Self::State) -> zbus::fdo::Result<String> {
130 Err(zbus::fdo::Error::NotSupported("Unimplemented".to_string()))
131 }
132
133 #[allow(unused)]
134 fn attention_icon_pixmap(&self, state: &Self::State) -> zbus::fdo::Result<Vec<IconPixmap>> {
135 Err(zbus::fdo::Error::NotSupported("Unimplemented".to_string()))
136 }
137
138 #[allow(unused)]
139 fn overlay_icon_name(&self, state: &Self::State) -> zbus::fdo::Result<String> {
140 Err(zbus::fdo::Error::NotSupported("Unimplemented".to_string()))
141 }
142
143 #[allow(unused)]
144 fn overlay_icon_pixmap(&self, state: &Self::State) -> zbus::fdo::Result<Vec<IconPixmap>> {
145 Err(zbus::fdo::Error::NotSupported("Unimplemented".to_string()))
146 }
147
148 #[allow(unused)]
149 fn attention_movie_name(&self, state: &Self::State) -> zbus::fdo::Result<String> {
150 Err(zbus::fdo::Error::NotSupported("Unimplemented".to_string()))
151 }
152
153 fn category(&self) -> Category {
154 Category::SystemServices
155 }
156
157 fn title(&self, state: &Self::State) -> zbus::fdo::Result<String>;
158
159 #[allow(unused)]
160 fn status(&self, state: &Self::State) -> zbus::fdo::Result<NotifierStatus> {
161 Ok(NotifierStatus::Active)
162 }
163
164 #[allow(unused)]
165 fn item_is_menu(&self, state: &Self::State) -> bool {
166 false
167 }
168
169 #[allow(unused)]
170 fn window_id(&self, state: &Self::State) -> zbus::fdo::Result<i32> {
171 Err(zbus::fdo::Error::NotSupported("Unimplemented".to_string()))
172 }
173}
174
175pub trait NotifierBootFn<State> {
176 fn boot(&self) -> State;
177}
178
179impl<T, State> NotifierBootFn<State> for T
180where
181 T: Fn() -> State,
182{
183 fn boot(&self) -> State {
184 self()
185 }
186}
187
188pub trait IdFn {
189 fn id(&self) -> String;
190}
191
192impl<T> IdFn for T
193where
194 T: Fn() -> String,
195{
196 fn id(&self) -> String {
197 self()
198 }
199}
200
201impl IdFn for &str {
202 fn id(&self) -> String {
203 self.to_string()
204 }
205}
206
207impl IdFn for String {
208 fn id(&self) -> String {
209 self.clone()
210 }
211}
212
213pub trait CategoryFn {
214 fn category(&self) -> Category;
215}
216
217impl<T> CategoryFn for T
218where
219 T: Fn() -> Category,
220{
221 fn category(&self) -> Category {
222 self()
223 }
224}
225
226impl CategoryFn for Category {
227 fn category(&self) -> Category {
228 *self
229 }
230}
231
232pub trait ActivateFn<State> {
233 fn activate(&self, state: &mut State, x: i32, y: i32) -> zbus::fdo::Result<()>;
234}
235
236impl<T, State> ActivateFn<State> for T
237where
238 T: Fn(&mut State, i32, i32) -> zbus::fdo::Result<()>,
239{
240 fn activate(&self, state: &mut State, x: i32, y: i32) -> zbus::fdo::Result<()> {
241 self(state, x, y)
242 }
243}
244pub trait ScrollFn<State> {
245 fn scroll(&self, state: &mut State, delta: i32, orientation: &str) -> zbus::fdo::Result<()>;
246}
247
248impl<T, State> ScrollFn<State> for T
249where
250 T: Fn(&mut State, i32, &str) -> zbus::fdo::Result<()>,
251{
252 fn scroll(&self, state: &mut State, delta: i32, orientation: &str) -> zbus::fdo::Result<()> {
253 self(state, delta, orientation)
254 }
255}
256pub trait SecondaryActivateFn<State> {
257 fn secondary_activate(&self, state: &mut State, x: i32, y: i32) -> zbus::fdo::Result<()>;
258}
259
260impl<T, State> SecondaryActivateFn<State> for T
261where
262 T: Fn(&mut State, i32, i32) -> zbus::fdo::Result<()>,
263{
264 fn secondary_activate(&self, state: &mut State, x: i32, y: i32) -> zbus::fdo::Result<()> {
265 self(state, x, y)
266 }
267}
268
269pub trait ContextMenuFn<State> {
270 fn context_menu(&self, state: &mut State, x: i32, y: i32) -> zbus::fdo::Result<()>;
271}
272
273impl<T, State> ContextMenuFn<State> for T
274where
275 T: Fn(&mut State, i32, i32) -> zbus::fdo::Result<()>,
276{
277 fn context_menu(&self, state: &mut State, x: i32, y: i32) -> zbus::fdo::Result<()> {
278 self(state, x, y)
279 }
280}
281
282pub trait TitleFn<State> {
283 fn title(&self, state: &State) -> zbus::fdo::Result<String>;
284}
285
286impl<State> TitleFn<State> for &str {
287 fn title(&self, _state: &State) -> zbus::fdo::Result<String> {
288 Ok(self.to_string())
289 }
290}
291
292impl<State> TitleFn<State> for String {
293 fn title(&self, _state: &State) -> zbus::fdo::Result<String> {
294 Ok(self.clone())
295 }
296}
297
298impl<State, T> TitleFn<State> for T
299where
300 T: Fn(&State) -> zbus::fdo::Result<String>,
301{
302 fn title(&self, state: &State) -> zbus::fdo::Result<String> {
303 self(state)
304 }
305}
306
307pub trait IconThemePathNotifierFn<State> {
308 fn icon_theme_path(&self, state: &State) -> zbus::fdo::Result<String>;
309}
310
311impl<State> IconThemePathNotifierFn<State> for &str {
312 fn icon_theme_path(&self, _state: &State) -> zbus::fdo::Result<String> {
313 Ok(self.to_string())
314 }
315}
316
317impl<State> IconThemePathNotifierFn<State> for String {
318 fn icon_theme_path(&self, _state: &State) -> zbus::fdo::Result<String> {
319 Ok(self.clone())
320 }
321}
322
323impl<State, T> IconThemePathNotifierFn<State> for T
324where
325 T: Fn(&State) -> zbus::fdo::Result<String>,
326{
327 fn icon_theme_path(&self, state: &State) -> zbus::fdo::Result<String> {
328 self(state)
329 }
330}
331
332pub trait IconNameFn<State> {
333 fn icon_name(&self, state: &State) -> zbus::fdo::Result<String>;
334}
335
336impl<State> IconNameFn<State> for &str {
337 fn icon_name(&self, _state: &State) -> zbus::fdo::Result<String> {
338 Ok(self.to_string())
339 }
340}
341
342impl<State> IconNameFn<State> for String {
343 fn icon_name(&self, _state: &State) -> zbus::fdo::Result<String> {
344 Ok(self.clone())
345 }
346}
347
348impl<State, T> IconNameFn<State> for T
349where
350 T: Fn(&State) -> zbus::fdo::Result<String>,
351{
352 fn icon_name(&self, state: &State) -> zbus::fdo::Result<String> {
353 self(state)
354 }
355}
356
357pub trait IconPixmapFn<State> {
358 fn icon_pixmap(&self, state: &State) -> zbus::fdo::Result<Vec<IconPixmap>>;
359}
360
361impl<State, T> IconPixmapFn<State> for T
362where
363 T: Fn(&State) -> zbus::fdo::Result<Vec<IconPixmap>>,
364{
365 fn icon_pixmap(&self, state: &State) -> zbus::fdo::Result<Vec<IconPixmap>> {
366 self(state)
367 }
368}
369
370pub trait AttentionIconNameFn<State> {
371 fn attention_icon_name(&self, state: &State) -> zbus::fdo::Result<String>;
372}
373
374impl<State> AttentionIconNameFn<State> for &str {
375 fn attention_icon_name(&self, _state: &State) -> zbus::fdo::Result<String> {
376 Ok(self.to_string())
377 }
378}
379
380impl<State> AttentionIconNameFn<State> for String {
381 fn attention_icon_name(&self, _state: &State) -> zbus::fdo::Result<String> {
382 Ok(self.clone())
383 }
384}
385
386impl<State, T> AttentionIconNameFn<State> for T
387where
388 T: Fn(&State) -> zbus::fdo::Result<String>,
389{
390 fn attention_icon_name(&self, state: &State) -> zbus::fdo::Result<String> {
391 self(state)
392 }
393}
394
395pub trait AttentionIconPixmapFn<State> {
396 fn attention_icon_pixmap(&self, state: &State) -> zbus::fdo::Result<Vec<IconPixmap>>;
397}
398
399impl<State, T> AttentionIconPixmapFn<State> for T
400where
401 T: Fn(&State) -> zbus::fdo::Result<Vec<IconPixmap>>,
402{
403 fn attention_icon_pixmap(&self, state: &State) -> zbus::fdo::Result<Vec<IconPixmap>> {
404 self(state)
405 }
406}
407pub trait AttentionMovieNameFn<State> {
408 fn attention_movie_name(&self, state: &State) -> zbus::fdo::Result<String>;
409}
410
411impl<State> AttentionMovieNameFn<State> for &str {
412 fn attention_movie_name(&self, _state: &State) -> zbus::fdo::Result<String> {
413 Ok(self.to_string())
414 }
415}
416
417impl<State> AttentionMovieNameFn<State> for String {
418 fn attention_movie_name(&self, _state: &State) -> zbus::fdo::Result<String> {
419 Ok(self.clone())
420 }
421}
422
423impl<State, T> AttentionMovieNameFn<State> for T
424where
425 T: Fn(&State) -> zbus::fdo::Result<String>,
426{
427 fn attention_movie_name(&self, state: &State) -> zbus::fdo::Result<String> {
428 self(state)
429 }
430}
431
432pub trait OverlayIconNameFn<State> {
433 fn overlay_icon_name(&self, state: &State) -> zbus::fdo::Result<String>;
434}
435
436impl<State> OverlayIconNameFn<State> for &str {
437 fn overlay_icon_name(&self, _state: &State) -> zbus::fdo::Result<String> {
438 Ok(self.to_string())
439 }
440}
441
442impl<State> OverlayIconNameFn<State> for String {
443 fn overlay_icon_name(&self, _state: &State) -> zbus::fdo::Result<String> {
444 Ok(self.clone())
445 }
446}
447
448impl<State, T> OverlayIconNameFn<State> for T
449where
450 T: Fn(&State) -> zbus::fdo::Result<String>,
451{
452 fn overlay_icon_name(&self, state: &State) -> zbus::fdo::Result<String> {
453 self(state)
454 }
455}
456
457pub trait OverlayIconPixmapFn<State> {
458 fn overlay_icon_pixmap(&self, state: &State) -> zbus::fdo::Result<Vec<IconPixmap>>;
459}
460
461impl<State, T> OverlayIconPixmapFn<State> for T
462where
463 T: Fn(&State) -> zbus::fdo::Result<Vec<IconPixmap>>,
464{
465 fn overlay_icon_pixmap(&self, state: &State) -> zbus::fdo::Result<Vec<IconPixmap>> {
466 self(state)
467 }
468}
469
470pub trait NotifierStatusFn<State> {
471 fn status(&self, state: &State) -> NotifierStatus;
472}
473
474impl<State, T> NotifierStatusFn<State> for T
475where
476 T: Fn(&State) -> NotifierStatus,
477{
478 fn status(&self, state: &State) -> NotifierStatus {
479 self(state)
480 }
481}
482pub trait ItemIsMenuFn<State> {
483 fn item_is_menu(&self, state: &State) -> bool;
484}
485
486impl<State, T> ItemIsMenuFn<State> for T
487where
488 T: Fn(&State) -> bool,
489{
490 fn item_is_menu(&self, state: &State) -> bool {
491 self(state)
492 }
493}
494
495impl<State> ItemIsMenuFn<State> for bool {
496 fn item_is_menu(&self, _state: &State) -> bool {
497 *self
498 }
499}
500
501pub trait ToolTipFn<State> {
502 fn tool_tip(&self, state: &State) -> zbus::fdo::Result<ToolTip>;
503}
504
505impl<State, T> ToolTipFn<State> for T
506where
507 T: Fn(&State) -> zbus::fdo::Result<ToolTip>,
508{
509 fn tool_tip(&self, state: &State) -> zbus::fdo::Result<ToolTip> {
510 self(state)
511 }
512}
513
514pub trait WindowIdFn<State> {
515 fn window_id(&self, state: &State) -> i32;
516}
517
518impl<State> WindowIdFn<State> for i32 {
519 fn window_id(&self, _state: &State) -> i32 {
520 *self
521 }
522}
523
524impl<State, T> WindowIdFn<State> for T
525where
526 T: Fn(&State) -> i32,
527{
528 fn window_id(&self, state: &State) -> i32 {
529 self(state)
530 }
531}
532
533pub struct StatusNotifierInstance<State> {
534 pub(crate) program: Box<dyn StatusNotifierItem<State = State> + Send + Sync>,
535 pub(crate) state: State,
536}
537
538#[interface(name = "org.kde.StatusNotifierItem")]
539impl<State> StatusNotifierInstance<State>
540where
541 State: 'static + Send + Sync,
542{
543 fn activate(&mut self, x: i32, y: i32) -> zbus::fdo::Result<()> {
544 self.program.activate(&mut self.state, x, y)
545 }
546
547 fn context_menu(&mut self, x: i32, y: i32) -> zbus::fdo::Result<()> {
549 self.program.context_menu(&mut self.state, x, y)
550 }
551
552 fn scroll(&mut self, delta: i32, orientation: &str) -> zbus::fdo::Result<()> {
553 self.program.scroll(&mut self.state, delta, orientation)
554 }
555
556 fn secondary_activate(&mut self, x: i32, y: i32) -> zbus::fdo::Result<()> {
557 self.program.secondary_activate(&mut self.state, x, y)
558 }
559
560 #[zbus(signal)]
562 async fn new_attention_icon(ctxt: &SignalEmitter<'_>) -> zbus::Result<()>;
563
564 #[zbus(signal)]
566 pub async fn new_icon(ctxt: &SignalEmitter<'_>) -> zbus::Result<()>;
567
568 #[zbus(signal)]
570 pub async fn new_menu(ctxt: &SignalEmitter<'_>) -> zbus::Result<()>;
571
572 #[zbus(signal)]
574 pub async fn new_overlay_icon(ctxt: &SignalEmitter<'_>) -> zbus::Result<()>;
575
576 #[zbus(signal)]
578 pub async fn new_status(ctxt: &SignalEmitter<'_>, status: &str) -> zbus::Result<()>;
579
580 #[zbus(signal)]
582 pub async fn new_title(ctxt: &SignalEmitter<'_>) -> zbus::Result<()>;
583
584 #[zbus(signal)]
586 pub async fn new_tool_tip(ctxt: &SignalEmitter<'_>) -> zbus::Result<()>;
587
588 #[zbus(property)]
590 fn menu(&self) -> zbus::zvariant::OwnedObjectPath {
591 MENU_PATH.into()
592 }
593
594 #[zbus(property)]
596 fn tool_tip(&self) -> zbus::fdo::Result<ToolTip> {
597 self.program.tool_tip(&self.state)
598 }
599
600 #[zbus(property)]
602 fn icon_theme_path(&self) -> zbus::fdo::Result<String> {
603 self.program.icon_theme_path(&self.state)
604 }
605
606 #[zbus(property)]
608 fn icon_name(&self) -> zbus::fdo::Result<String> {
609 self.program.icon_name(&self.state)
610 }
611
612 #[zbus(property)]
614 fn icon_pixmap(&self) -> zbus::fdo::Result<Vec<IconPixmap>> {
615 self.program.icon_pixmap(&self.state)
616 }
617
618 #[zbus(property)]
620 fn attention_icon_name(&self) -> zbus::fdo::Result<String> {
621 self.program.attention_icon_name(&self.state)
622 }
623
624 #[zbus(property)]
626 fn attention_icon_pixmap(&self) -> zbus::fdo::Result<Vec<IconPixmap>> {
627 self.program.attention_icon_pixmap(&self.state)
628 }
629
630 #[zbus(property)]
632 fn attention_movie_name(&self) -> zbus::fdo::Result<String> {
633 self.program.attention_movie_name(&self.state)
634 }
635
636 #[zbus(property)]
638 fn overlay_icon_name(&self) -> zbus::fdo::Result<String> {
639 self.program.overlay_icon_name(&self.state)
640 }
641
642 #[zbus(property)]
644 fn overlay_icon_pixmap(&self) -> zbus::fdo::Result<Vec<IconPixmap>> {
645 self.program.overlay_icon_pixmap(&self.state)
646 }
647
648 #[zbus(property)]
650 fn category(&self) -> Category {
651 self.program.category()
652 }
653
654 #[zbus(property)]
656 fn id(&self) -> zbus::fdo::Result<String> {
657 Ok(self.program.id())
658 }
659
660 #[zbus(property)]
662 fn status(&self) -> zbus::fdo::Result<NotifierStatus> {
663 self.program.status(&self.state)
664 }
665
666 #[zbus(property)]
668 fn title(&self) -> zbus::fdo::Result<String> {
669 self.program.title(&self.state)
670 }
671
672 #[zbus(property)]
674 fn item_is_menu(&self) -> zbus::fdo::Result<bool> {
675 Ok(self.program.item_is_menu(&self.state))
676 }
677
678 #[zbus(property)]
679 fn window_id(&self) -> zbus::fdo::Result<i32> {
680 self.program.window_id(&self.state)
681 }
682}