Skip to main content

libappindicator_zbus/
dbusmenu.rs

1//! # D-Bus interface proxy for: `com.canonical.dbusmenu`
2//!
3//! This code was generated by `zbus-xmlgen` `5.1.0` from D-Bus introspection data.
4//! Source: `Interface '/MenuBar' from service ':1.9087' on system bus`.
5//!
6//! You may prefer to adapt it, instead of using it verbatim.
7//!
8//! More information can be found in the [Writing a client proxy] section of the zbus
9//! documentation.
10//!
11//! This type implements the [D-Bus standard interfaces], (`org.freedesktop.DBus.*`) for which the
12//! following zbus API can be used:
13//!
14//! * [`zbus::fdo::PropertiesProxy`]
15//! * [`zbus::fdo::IntrospectableProxy`]
16//! * [`zbus::fdo::PeerProxy`]
17//!
18//! Consequently `zbus-xmlgen` did not generate code for the above interfaces.
19//!
20//! [Writing a client proxy]: https://dbus2.github.io/zbus/client.html
21//! [D-Bus standard interfaces]: https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces,
22use std::ops::Deref;
23use std::sync::atomic::{self, AtomicI32};
24
25use serde::{Deserialize, Serialize};
26use zbus::zvariant::{self, OwnedValue, Type, Value, as_value::optional};
27
28use zbus::{interface, object_server::SignalEmitter};
29
30pub mod event_types;
31
32pub use event_types::*;
33
34#[derive(Type, Debug, Serialize, Deserialize, Default, OwnedValue, Value, Clone)]
35/// Specified options for a [`Screencast::create_session`] request.
36#[zvariant(signature = "dict")]
37pub struct MenuProperty {
38    #[serde(with = "optional", skip_serializing_if = "Option::is_none", default)]
39    pub label: Option<String>,
40    #[serde(with = "optional", skip_serializing_if = "Option::is_none", default)]
41    #[zvariant(rename = "icon-name")]
42    pub icon_name: Option<String>,
43    #[serde(with = "optional", skip_serializing_if = "Option::is_none", default)]
44    pub enabled: Option<bool>,
45    #[serde(with = "optional", skip_serializing_if = "Option::is_none", default)]
46    #[zvariant(rename = "toggle-type")]
47    pub toggle_type: Option<ToggleType>,
48    #[serde(with = "optional", skip_serializing_if = "Option::is_none", default)]
49    #[zvariant(rename = "toggle-state")]
50    pub toggle_state: Option<ToggleState>,
51    #[serde(with = "optional", skip_serializing_if = "Option::is_none", default)]
52    #[zvariant(rename = "children-display")]
53    pub children_display: Option<String>,
54}
55
56impl MenuProperty {
57    /// Key name
58    pub const LABEL: &str = "label";
59    pub const ICON_NAME: &str = "icon-name";
60    pub const ENABLED: &str = "enabled";
61    pub const TOGGLE_TYPE: &str = "toggle-type";
62    pub const TOGGLE_STATE: &str = "toggle-state";
63    pub const CHILDREN_DISPLAY: &str = "children-display";
64}
65
66impl MenuProperty {
67    pub fn root() -> Self {
68        MenuProperty {
69            label: Some("root".to_owned()),
70            children_display: Some("submenu".to_owned()),
71            ..Default::default()
72        }
73    }
74    pub fn submenu(label: String) -> Self {
75        MenuProperty {
76            label: Some(label),
77            children_display: Some("submenu".to_owned()),
78            ..Default::default()
79        }
80    }
81}
82
83#[derive(
84    Type, Debug, Serialize, Deserialize, OwnedValue, Value, Clone, Copy, PartialEq, PartialOrd,
85)]
86pub struct Id(i32);
87
88static COUNT: AtomicI32 = AtomicI32::new(1);
89
90impl Id {
91    pub const MAIN: Self = Id(0);
92    /// Creates a new unique window [`Id`].
93    pub fn unique() -> Id {
94        Id(COUNT.fetch_add(1, atomic::Ordering::Relaxed))
95    }
96}
97
98impl Deref for Id {
99    type Target = i32;
100    fn deref(&self) -> &Self::Target {
101        &self.0
102    }
103}
104
105#[allow(unused)]
106#[derive(Debug, Clone)]
107pub enum MenuType {
108    Root,
109    SubMenu,
110    Button,
111    RadioGroup,
112}
113
114#[derive(Debug, Clone)]
115pub enum MenuUnit<Message: Clone> {
116    StandardButton {
117        id: Id,
118        options: ButtonOptions,
119        message: Message,
120    },
121    Root {
122        sub_menus: Vec<MenuUnit<Message>>,
123    },
124    SubMenu {
125        id: Id,
126        label: String,
127        sub_menus: Vec<MenuUnit<Message>>,
128    },
129    RadioGroup {
130        selections: Vec<MenuUnit<Message>>,
131    },
132    RadioButton {
133        id: Id,
134        options: RadioOptions,
135        message: Message,
136    },
137}
138
139#[derive(Debug, Clone)]
140pub struct MenuTree<Message: Clone>(MenuUnit<Message>);
141
142impl<Message: Clone> Default for MenuTree<Message> {
143    fn default() -> Self {
144        Self::new()
145    }
146}
147
148impl<Message: Clone> MenuTree<Message> {
149    pub fn new() -> Self {
150        Self(MenuUnit::root())
151    }
152    pub fn push_sub_menu(mut self, menu: MenuUnit<Message>) -> Self {
153        self.0 = self.0.push_sub_menu(menu);
154        self
155    }
156    fn get_unit_mut(&mut self) -> &mut MenuUnit<Message> {
157        &mut self.0
158    }
159    pub fn get_unit(&self) -> &MenuUnit<Message> {
160        &self.0
161    }
162}
163
164impl<Message: Clone> From<&MenuTree<Message>> for MenuItem {
165    fn from(value: &MenuTree<Message>) -> Self {
166        (&value.0).into()
167    }
168}
169#[derive(Debug, Clone, Default)]
170pub struct ButtonOptions {
171    pub label: String,
172    pub enabled: bool,
173    pub icon_name: String,
174}
175
176#[derive(Debug, Clone, Default)]
177pub struct RadioOptions {
178    pub label: String,
179    pub enabled: bool,
180    pub icon_name: String,
181    pub toggle_type: ToggleType,
182    pub toggle_state: ToggleState,
183}
184
185#[derive(Debug, Clone)]
186pub struct RadioInitOption<Message: Clone> {
187    pub options: RadioOptions,
188    pub message: Message,
189}
190
191impl<Message: Clone> From<&MenuUnit<Message>> for MenuItem {
192    fn from(value: &MenuUnit<Message>) -> Self {
193        let IdOrGroup::Id(id) = value.id_or_ids() else {
194            panic!("RadioGroup should not be here");
195        };
196        let mut output = MenuItem {
197            id,
198            property: value.get_property().expect("RadioGroup should not be here"),
199            sub_menus: vec![],
200        };
201        let Some(sub_menus) = value.sub_menus() else {
202            return output;
203        };
204        for sub_menu in sub_menus {
205            if let MenuUnit::RadioGroup { selections, .. } = sub_menu {
206                for selection in selections {
207                    output = output.push_sub_menu(selection.into());
208                }
209            } else {
210                output = output.push_sub_menu(sub_menu.into());
211            }
212        }
213        output
214    }
215}
216
217enum IdOrGroup {
218    Id(Id),
219    Groups(Vec<Id>),
220}
221
222impl IdOrGroup {
223    fn contains_id(&self, id: i32) -> bool {
224        let id = Id(id);
225        match self {
226            IdOrGroup::Id(oid) => *oid == id,
227            IdOrGroup::Groups(ids) => ids.contains(&id),
228        }
229    }
230}
231
232impl<Message: Clone> MenuUnit<Message> {
233    pub fn try_change_label(&mut self, new_label: String) {
234        match self {
235            Self::RadioButton {
236                options: RadioOptions { label, .. },
237                ..
238            }
239            | Self::SubMenu { label, .. }
240            | Self::StandardButton {
241                options: ButtonOptions { label, .. },
242                ..
243            } => {
244                *label = new_label;
245            }
246            _ => {}
247        }
248    }
249    fn message(&self, id: i32) -> Option<Message> {
250        let fid = Id(id);
251        match self {
252            Self::RadioGroup { selections } => {
253                for selection in selections {
254                    let IdOrGroup::Id(oid) = selection.id_or_ids() else {
255                        continue;
256                    };
257                    if oid == fid {
258                        return selection.message(id);
259                    }
260                }
261            }
262            Self::RadioButton { id, message, .. } | Self::StandardButton { id, message, .. } => {
263                if fid == *id {
264                    return Some(message.clone());
265                }
266            }
267            _ => {}
268        }
269        None
270    }
271    fn get_property(&self) -> Option<MenuProperty> {
272        match self {
273            Self::Root { .. } => Some(MenuProperty::root()),
274            Self::SubMenu { label, .. } => Some(MenuProperty::submenu(label.clone())),
275            Self::StandardButton {
276                options:
277                    ButtonOptions {
278                        label,
279                        enabled,
280                        icon_name,
281                    },
282                ..
283            } => Some(MenuProperty {
284                label: Some(label.clone()),
285                icon_name: Some(icon_name.clone()),
286                enabled: Some(*enabled),
287                ..Default::default()
288            }),
289            Self::RadioButton {
290                options:
291                    RadioOptions {
292                        label,
293                        enabled,
294                        icon_name,
295                        toggle_state,
296                        toggle_type,
297                    },
298                ..
299            } => Some(MenuProperty {
300                label: Some(label.clone()),
301                icon_name: Some(icon_name.clone()),
302                enabled: Some(*enabled),
303                toggle_type: Some(*toggle_type),
304                toggle_state: Some(*toggle_state),
305                ..Default::default()
306            }),
307            Self::RadioGroup { .. } => None,
308        }
309    }
310    pub fn sub_menus(&self) -> Option<&Vec<Self>> {
311        match self {
312            Self::Root { sub_menus } | Self::SubMenu { sub_menus, .. } => Some(sub_menus),
313            _ => None,
314        }
315    }
316    pub fn sub_menus_mut(&mut self) -> Option<&mut Vec<Self>> {
317        match self {
318            Self::Root { sub_menus } | Self::SubMenu { sub_menus, .. } => Some(sub_menus),
319            _ => None,
320        }
321    }
322    fn id_or_ids(&self) -> IdOrGroup {
323        match self {
324            Self::Root { .. } => IdOrGroup::Id(Id::MAIN),
325            Self::SubMenu { id, .. }
326            | Self::StandardButton { id, .. }
327            | Self::RadioButton { id, .. } => IdOrGroup::Id(*id),
328            Self::RadioGroup { selections, .. } => {
329                let mut groups = vec![];
330                for selection in selections {
331                    match selection.id_or_ids() {
332                        IdOrGroup::Id(id) => groups.push(id),
333                        IdOrGroup::Groups(mut ids) => {
334                            groups.append(&mut ids);
335                        }
336                    }
337                }
338                IdOrGroup::Groups(groups)
339            }
340        }
341    }
342    pub fn button(options: ButtonOptions, message: Message) -> Self {
343        Self::StandardButton {
344            id: Id::unique(),
345            options,
346            message,
347        }
348    }
349    pub fn root() -> Self {
350        Self::Root { sub_menus: vec![] }
351    }
352    pub fn sub_menu(label: String) -> Self {
353        Self::SubMenu {
354            id: Id::unique(),
355            label,
356            sub_menus: vec![],
357        }
358    }
359
360    pub fn toggle_group(init_options: Vec<RadioInitOption<Message>>) -> Self {
361        let selections = init_options
362            .into_iter()
363            .map(
364                |RadioInitOption { options, message }| MenuUnit::RadioButton {
365                    id: Id::unique(),
366                    options,
367                    message,
368                },
369            )
370            .collect();
371        Self::RadioGroup { selections }
372    }
373
374    pub fn push_sub_menu(mut self, menu: Self) -> Self {
375        let Some(sub_menus) = self.sub_menus_mut() else {
376            return self;
377        };
378        sub_menus.push(menu);
379        self
380    }
381
382    pub fn unit_type(&self) -> MenuType {
383        match self {
384            MenuUnit::Root { .. } => MenuType::Root,
385            MenuUnit::SubMenu { .. } => MenuType::SubMenu,
386            MenuUnit::RadioGroup { .. } => MenuType::RadioGroup,
387            MenuUnit::StandardButton { .. } | MenuUnit::RadioButton { .. } => MenuType::Button,
388        }
389    }
390
391    pub fn find_menu_by_id(&self, id: i32) -> Option<&Self> {
392        if self.id_or_ids().contains_id(id) {
393            return Some(self);
394        }
395        let sub_menus = self.sub_menus()?;
396        for menu in sub_menus {
397            if let Some(menu) = menu.find_menu_by_id(id) {
398                return Some(menu);
399            }
400        }
401        None
402    }
403    pub fn find_menu_by_id_mut(&mut self, id: i32) -> Option<&mut Self> {
404        if self.id_or_ids().contains_id(id) {
405            return Some(self);
406        }
407        let sub_menus = self.sub_menus_mut()?;
408        for menu in sub_menus {
409            if let Some(menu) = menu.find_menu_by_id_mut(id) {
410                return Some(menu);
411            }
412        }
413        None
414    }
415    fn find_menu_and_message_by_id_mut(&mut self, id: i32) -> Option<(&mut Self, Message)> {
416        if self.id_or_ids().contains_id(id) {
417            let message = self.message(id)?;
418            return Some((self, message));
419        }
420        let sub_menus = self.sub_menus_mut()?;
421        for menu in sub_menus {
422            if let Some(menu) = menu.find_menu_and_message_by_id_mut(id) {
423                return Some(menu);
424            }
425        }
426        None
427    }
428}
429
430#[derive(Type, Debug, Serialize, Deserialize, OwnedValue, Value, Clone)]
431#[zvariant(signature = "(ia{sv}av)")]
432pub struct MenuItem {
433    pub id: Id,
434    pub property: MenuProperty,
435    pub sub_menus: Vec<zvariant::OwnedValue>,
436}
437
438#[derive(Clone, PartialEq, Type, Serialize, Deserialize, OwnedValue, Value, Debug, Default)]
439#[zvariant(signature = "s", rename_all = "lowercase")]
440pub enum MenuStatus {
441    #[default]
442    Normal,
443    Notice,
444    Disabled,
445}
446
447impl Default for MenuItem {
448    fn default() -> Self {
449        MenuItem {
450            id: Id::unique(),
451            property: MenuProperty::root(),
452            sub_menus: vec![],
453        }
454    }
455}
456
457impl MenuItem {
458    pub fn new(property: MenuProperty) -> Self {
459        MenuItem {
460            id: Id::unique(),
461            property,
462            sub_menus: vec![],
463        }
464    }
465
466    #[allow(unused)]
467    #[allow(clippy::only_used_in_recursion)]
468    pub fn get_filiter(
469        &self,
470        parent_id: i32,
471        recursion_depth: i32,
472        property_names: &[&str],
473    ) -> Option<MenuItem> {
474        if *self.id == parent_id {
475            let mut new_menu = MenuItem {
476                id: self.id,
477                property: self.property.clone(),
478                sub_menus: vec![],
479            };
480
481            let next_reversion_depth = recursion_depth - 1;
482            if next_reversion_depth != 0 {
483                for menu in self.sub_menus.as_slice() {
484                    let menu: MenuItem = menu.clone().try_into().unwrap();
485                    let next_menu = menu.filiter(next_reversion_depth, property_names);
486                    new_menu = new_menu.push_sub_menu(next_menu);
487                }
488            }
489            return Some(new_menu);
490        }
491        None
492    }
493
494    #[allow(unused)]
495    #[allow(clippy::only_used_in_recursion)]
496    fn filiter(&self, recursion_depth: i32, property_names: &[&str]) -> MenuItem {
497        let mut new_menu = MenuItem {
498            id: self.id,
499            property: self.property.clone(),
500            sub_menus: vec![],
501        };
502
503        let next_reversion_depth = recursion_depth - 1;
504        for menu in self.sub_menus.as_slice() {
505            let menu: MenuItem = menu.clone().try_into().unwrap();
506            let next_menu = menu.filiter(next_reversion_depth, property_names);
507            new_menu = new_menu.push_sub_menu(next_menu);
508        }
509
510        new_menu
511    }
512
513    pub fn push_sub_menu(mut self, menu: MenuItem) -> Self {
514        self.sub_menus.push(OwnedValue::try_from(menu).unwrap());
515        self
516    }
517
518    pub fn get_property(&self, id: i32, name: String) -> Option<PropertyItem> {
519        if *self.id == id {
520            return Some(PropertyItem {
521                id,
522                item: self.property.clone(),
523            });
524        }
525        let sub_menus: Vec<MenuItem> = self
526            .sub_menus
527            .iter()
528            .map(|submenu| submenu.clone().try_into().unwrap())
529            .collect();
530
531        for sub_menu in sub_menus {
532            let property = sub_menu.get_property(id, name.clone());
533            if property.is_some() {
534                return property;
535            }
536        }
537
538        None
539    }
540
541    pub fn get_property_groups(
542        &self,
543        ids: Vec<i32>,
544        _property_names: Vec<String>,
545    ) -> Vec<PropertyItem> {
546        let mut output = vec![];
547        for id in ids {
548            if let Some(property) = self.get_property(id, "".to_string()) {
549                output.push(property);
550            }
551        }
552
553        output
554    }
555}
556
557#[derive(Type, Debug, Default, Serialize, Deserialize)]
558pub struct PropertyItem {
559    pub id: i32,
560    pub item: MenuProperty,
561}
562
563pub trait DBusMenuItem {
564    type State;
565    type Message: Clone;
566
567    fn boot(&self) -> Self::State;
568
569    fn menu(&self) -> MenuTree<Self::Message>;
570
571    fn revision(&self, state: &Self::State) -> u32;
572
573    #[allow(unused)]
574    fn about_to_show(&self, state: &mut Self::State, id: i32) -> zbus::fdo::Result<bool> {
575        Err(zbus::fdo::Error::Failed("Unimplemented".to_string()))
576    }
577
578    /// AboutToShowGroup method
579    #[allow(unused)]
580    fn about_to_show_group(
581        &self,
582        state: &mut Self::State,
583        ids: Vec<i32>,
584    ) -> zbus::fdo::Result<(Vec<i32>, Vec<i32>)> {
585        Err(zbus::fdo::Error::Failed("Unimplemented".to_string()))
586    }
587
588    fn status(&self, _state: &Self::State) -> zbus::fdo::Result<MenuStatus> {
589        Ok(MenuStatus::Normal)
590    }
591
592    #[allow(unused)]
593    fn on_clicked(
594        &self,
595        state: &mut Self::State,
596        button: &mut MenuUnit<Self::Message>,
597        message: Self::Message,
598        timestamp: u32,
599    ) -> EventUpdate {
600        EventUpdate::None
601    }
602
603    #[allow(unused)]
604    fn text_direction(&self, state: &Self::State) -> TextDirection {
605        TextDirection::Inherit
606    }
607
608    #[allow(unused)]
609    fn icon_theme_path(&self, state: &Self::State) -> Vec<String> {
610        vec![]
611    }
612}
613
614pub struct DBusMenuInstance<State, Message>
615where
616    Message: Clone,
617{
618    pub(crate) program: Box<dyn DBusMenuItem<State = State, Message = Message> + Send + Sync>,
619    pub(crate) state: State,
620    pub(crate) menu_tree: MenuTree<Message>,
621}
622
623pub trait DBusMenuBootFn<State> {
624    fn boot(&self) -> State;
625}
626
627impl<T, State> DBusMenuBootFn<State> for T
628where
629    T: Fn() -> State,
630{
631    fn boot(&self) -> State {
632        self()
633    }
634}
635
636pub trait MenuBootFn<Message: Clone> {
637    fn menu(&self) -> MenuTree<Message>;
638}
639
640impl<Message> MenuBootFn<Message> for MenuTree<Message>
641where
642    Message: Clone,
643{
644    fn menu(&self) -> MenuTree<Message> {
645        self.clone()
646    }
647}
648
649impl<T, Message> MenuBootFn<Message> for T
650where
651    Message: Clone,
652    T: Fn() -> MenuTree<Message>,
653{
654    fn menu(&self) -> MenuTree<Message> {
655        self()
656    }
657}
658
659pub trait MenuStatusFn<State> {
660    fn status(&self, state: &State) -> MenuStatus;
661}
662
663impl<T, State> MenuStatusFn<State> for T
664where
665    T: Fn(&State) -> MenuStatus,
666{
667    fn status(&self, state: &State) -> MenuStatus {
668        self(state)
669    }
670}
671pub trait AboutToShowFn<State> {
672    fn about_to_show(&self, state: &mut State, id: i32) -> bool;
673}
674
675impl<T, State> AboutToShowFn<State> for T
676where
677    T: Fn(&mut State, i32) -> bool,
678{
679    fn about_to_show(&self, state: &mut State, id: i32) -> bool {
680        self(state, id)
681    }
682}
683
684#[derive(Debug)]
685pub enum EventUpdate {
686    None,
687    UpdateCurrent,
688    UpdateAll,
689}
690
691pub trait RevisionFn<State> {
692    fn revision(&self, state: &State) -> u32;
693}
694
695impl<State, F> RevisionFn<State> for F
696where
697    F: Fn(&State) -> u32,
698{
699    fn revision(&self, state: &State) -> u32 {
700        self(state)
701    }
702}
703
704impl<State> RevisionFn<State> for u32 {
705    fn revision(&self, _state: &State) -> u32 {
706        *self
707    }
708}
709
710pub trait OnClickedFn<State, Message: Clone> {
711    fn on_clicked(
712        &self,
713        state: &mut State,
714        button: &mut MenuUnit<Message>,
715        message: Message,
716        timestamp: u32,
717    ) -> EventUpdate;
718}
719
720impl<T, State, Message> OnClickedFn<State, Message> for T
721where
722    T: Fn(&mut State, &mut MenuUnit<Message>, Message, u32) -> EventUpdate,
723    Message: Clone,
724{
725    fn on_clicked(
726        &self,
727        state: &mut State,
728        button: &mut MenuUnit<Message>,
729        message: Message,
730        timestamp: u32,
731    ) -> EventUpdate {
732        self(state, button, message, timestamp)
733    }
734}
735
736pub trait TextDirectionFn<State> {
737    fn text_direction(&self, state: &State) -> TextDirection;
738}
739
740impl<State> TextDirectionFn<State> for TextDirection {
741    fn text_direction(&self, _state: &State) -> TextDirection {
742        *self
743    }
744}
745
746impl<T, State> TextDirectionFn<State> for T
747where
748    T: Fn(&State) -> TextDirection,
749{
750    fn text_direction(&self, state: &State) -> TextDirection {
751        self(state)
752    }
753}
754
755pub trait IconThemePathFn<State> {
756    fn icon_theme_path(&self, state: &State) -> Vec<String>;
757}
758
759impl<State> IconThemePathFn<State> for Vec<String> {
760    fn icon_theme_path(&self, _state: &State) -> Vec<String> {
761        self.clone()
762    }
763}
764
765impl<T, State> IconThemePathFn<State> for T
766where
767    T: Fn(&State) -> Vec<String>,
768{
769    fn icon_theme_path(&self, state: &State) -> Vec<String> {
770        self(state)
771    }
772}
773
774pub trait AboutToShowGroupFn<State> {
775    fn about_to_show_group(
776        &self,
777        state: &mut State,
778        ids: Vec<i32>,
779    ) -> zbus::fdo::Result<(Vec<i32>, Vec<i32>)>;
780}
781
782impl<T, State> AboutToShowGroupFn<State> for T
783where
784    T: Fn(&mut State, Vec<i32>) -> zbus::fdo::Result<(Vec<i32>, Vec<i32>)>,
785{
786    fn about_to_show_group(
787        &self,
788        state: &mut State,
789        ids: Vec<i32>,
790    ) -> zbus::fdo::Result<(Vec<i32>, Vec<i32>)> {
791        self(state, ids)
792    }
793}
794
795#[interface(name = "com.canonical.dbusmenu")]
796impl<State, Message> DBusMenuInstance<State, Message>
797where
798    State: 'static + Send + Sync,
799    Message: 'static + Send + Sync + Clone,
800{
801    fn about_to_show(&mut self, id: i32) -> zbus::fdo::Result<bool> {
802        self.program.about_to_show(&mut self.state, id)
803    }
804
805    /// AboutToShowGroup method
806    fn about_to_show_group(&mut self, ids: Vec<i32>) -> zbus::fdo::Result<(Vec<i32>, Vec<i32>)> {
807        self.program.about_to_show_group(&mut self.state, ids)
808    }
809
810    // NOTE: this should not implemented by user
811    /// GetLayout method
812    fn get_layout(
813        &mut self,
814        parent_id: i32,
815        recursion_depth: i32,
816        property_names: Vec<String>,
817    ) -> zbus::fdo::Result<(u32, MenuItem)> {
818        let property_names: Vec<&str> = property_names.iter().map(|name| name.as_str()).collect();
819        let menuitem: MenuItem = (&self.menu_tree).into();
820        Ok((
821            self.program.revision(&self.state),
822            menuitem
823                .get_filiter(parent_id, recursion_depth, &property_names)
824                .ok_or(zbus::fdo::Error::Failed("UnFounded".to_string()))?,
825        ))
826    }
827
828    fn get_group_properties(
829        &mut self,
830        ids: Vec<i32>,
831        property_names: Vec<String>,
832    ) -> zbus::fdo::Result<Vec<PropertyItem>> {
833        let menuitem: MenuItem = (&self.menu_tree).into();
834        Ok(menuitem.get_property_groups(ids, property_names))
835    }
836
837    fn get_property(&mut self, id: i32, name: String) -> zbus::fdo::Result<PropertyItem> {
838        let menuitem: MenuItem = (&self.menu_tree).into();
839        menuitem
840            .get_property(id, name)
841            .ok_or(zbus::fdo::Error::Failed("Unfounded".to_string()))
842    }
843
844    /// Version property
845    #[zbus(property)]
846    fn version(&self) -> u32 {
847        2
848    }
849
850    /// Status property
851    #[zbus(property)]
852    fn status(&self) -> zbus::fdo::Result<MenuStatus> {
853        self.program.status(&self.state)
854    }
855
856    /// Event method
857    async fn event(
858        &mut self,
859        id: i32,
860        event_id: String,
861        _data: zbus::zvariant::OwnedValue,
862        timestamp: u32,
863        #[zbus(signal_emitter)] cxts: SignalEmitter<'_>,
864    ) -> zbus::fdo::Result<()> {
865        let menu = self.menu_tree.get_unit_mut();
866
867        let Some((button, message)) = menu.find_menu_and_message_by_id_mut(id) else {
868            return Ok(());
869        };
870        let need_update = match event_id.as_str() {
871            "clicked" => {
872                if !matches!(button.unit_type(), MenuType::Button | MenuType::RadioGroup) {
873                    return Ok(());
874                }
875                self.program
876                    .on_clicked(&mut self.state, button, message, timestamp)
877            }
878            _ => EventUpdate::None,
879        };
880
881        let revision = self.program.revision(&self.state);
882        match need_update {
883            EventUpdate::UpdateCurrent => {
884                let _ =
885                    DBusMenuInstance::<State, Message>::layout_updated(&cxts, revision, id).await;
886            }
887            EventUpdate::UpdateAll => {
888                let _ =
889                    DBusMenuInstance::<State, Message>::layout_updated(&cxts, revision, *Id::MAIN)
890                        .await;
891            }
892            _ => {}
893        }
894
895        Ok(())
896    }
897
898    /// EventGroup method
899    async fn event_group(
900        &mut self,
901        events: Vec<(i32, String, zbus::zvariant::OwnedValue, u32)>,
902        #[zbus(signal_emitter)] cxts: SignalEmitter<'_>,
903    ) -> zbus::fdo::Result<Vec<i32>> {
904        let mut output = vec![];
905        let mut update_all = false;
906        let mut update_parents: Vec<i32> = vec![];
907        for (id, event_id, _data, timestamp) in events {
908            let menu = self.menu_tree.get_unit_mut();
909            let Some((button, message)) = menu.find_menu_and_message_by_id_mut(id) else {
910                continue;
911            };
912
913            let need_update = match event_id.as_str() {
914                "clicked" => {
915                    if !matches!(button.unit_type(), MenuType::Button | MenuType::RadioGroup) {
916                        continue;
917                    }
918                    self.program
919                        .on_clicked(&mut self.state, button, message, timestamp)
920                }
921                _ => {
922                    continue;
923                }
924            };
925            match need_update {
926                EventUpdate::None => {
927                    continue;
928                }
929                EventUpdate::UpdateAll => {
930                    update_all = true;
931                }
932                EventUpdate::UpdateCurrent => {
933                    if let IdOrGroup::Id(id) = menu.id_or_ids() {
934                        update_parents.push(*id);
935                    }
936                }
937            };
938            output.push(id);
939        }
940        let revision = self.program.revision(&self.state);
941        if update_all {
942            let _ = DBusMenuInstance::<State, Message>::layout_updated(&cxts, revision, *Id::MAIN)
943                .await;
944        } else {
945            for id in update_parents {
946                let _ =
947                    DBusMenuInstance::<State, Message>::layout_updated(&cxts, revision, id).await;
948            }
949        }
950        Ok(output)
951    }
952
953    /// TextDirection property
954    #[zbus(property)]
955    fn text_direction(&self) -> TextDirection {
956        self.program.text_direction(&self.state)
957    }
958
959    #[zbus(property)]
960    fn icon_theme_path(&self) -> Vec<String> {
961        self.program.icon_theme_path(&self.state)
962    }
963
964    /// ItemActivationRequested signal
965    #[zbus(signal)]
966    pub async fn item_activation_requested(
967        ctxt: &SignalEmitter<'_>,
968        id: i32,
969        timestamp: u32,
970    ) -> zbus::Result<()>;
971
972    /// ItemsPropertiesUpdated signal
973    #[zbus(signal)]
974    pub async fn items_properties_updated(
975        ctxt: &SignalEmitter<'_>,
976        updated_props: Vec<(i32, MenuProperty)>,
977        removed_props: Vec<(i32, Vec<&str>)>,
978    ) -> zbus::Result<()>;
979
980    /// LayoutUpdated signal
981    #[zbus(signal)]
982    pub async fn layout_updated(
983        ctxt: &SignalEmitter<'_>,
984        revision: u32,
985        parent: i32,
986    ) -> zbus::Result<()>;
987}