From 4c799a2bedeacc4bc06b4827b30a345fd543fc96 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Thu, 26 Aug 2021 16:09:25 -0700 Subject: [PATCH] WIP code for getting layout from menu --- src/status_area.rs | 90 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 79 insertions(+), 11 deletions(-) diff --git a/src/status_area.rs b/src/status_area.rs index 39ea8bca..c3a3463d 100644 --- a/src/status_area.rs +++ b/src/status_area.rs @@ -11,7 +11,7 @@ use gtk4::{ subclass::prelude::*, }; use once_cell::unsync::OnceCell; -use std::{cell::RefCell, collections::HashMap}; +use std::{borrow::Cow, cell::RefCell, collections::HashMap}; use crate::deref_cell::DerefCell; @@ -98,6 +98,10 @@ impl StatusArea { let image = gtk4::Image::from_icon_name(item.icon_name().as_deref()); self.inner().box_.append(&image); + if let Some(menu) = item.menu() { + println!("{:?}", menu.get_layout(0, -1, &[]).await); + } + self.item_unregistered(name); self.inner() .icons @@ -115,23 +119,88 @@ impl StatusArea { } } -struct StatusNotifierItem(gio::DBusProxy); +#[derive(Debug)] +struct Layout(i32, HashMap, Vec); -impl StatusNotifierItem { - async fn new(name: &str) -> Result { - let idx = name.find('/').unwrap(); +impl glib::StaticVariantType for Layout { + fn static_variant_type() -> Cow<'static, glib::VariantTy> { + glib::VariantTy::new("(ia{sv}av)").unwrap().into() + } +} + +impl glib::FromVariant for Layout { + fn from_variant(variant: &glib::Variant) -> Option { + let (id, props, children) = variant.get::<(_, _, Vec)>()?; + let children = children.iter().filter_map(Self::from_variant).collect(); + Some(Self(id, props, children)) + } +} + +#[derive(Clone)] +struct DBusMenu(gio::DBusProxy); + +impl DBusMenu { + async fn new(dest: &str, path: &str) -> Result { let proxy = gio::DBusProxy::for_bus_future( gio::BusType::Session, gio::DBusProxyFlags::NONE, None, - &name[..idx], - &name[idx..], - "org.kde.StatusNotifierItem", + dest, + path, + "com.canonical.dbusmenu", ) .await?; Ok(Self(proxy)) } + async fn get_layout( + &self, + parent: i32, + depth: i32, + properties: &[&str], + ) -> Result<(u32, Layout), glib::Error> { + // XXX unwrap + Ok(self + .0 + .call_future( + "GetLayout", + Some(&(parent, depth, properties).to_variant()), + gio::DBusCallFlags::NONE, + 1000, + ) + .await? + .get() + .unwrap()) + } +} + +struct StatusNotifierItem(gio::DBusProxy, Option); + +impl StatusNotifierItem { + async fn new(name: &str) -> Result { + let idx = name.find('/').unwrap(); + let dest = &name[..idx]; + let path = &name[idx..]; + let proxy = gio::DBusProxy::for_bus_future( + gio::BusType::Session, + gio::DBusProxyFlags::NONE, + None, + dest, + path, + "org.kde.StatusNotifierItem", + ) + .await?; + let menu_path = proxy + .cached_property("Menu") + .and_then(|x| x.get::()); + let menu = if let Some(menu_path) = menu_path { + Some(DBusMenu::new(dest, &menu_path).await?) + } else { + None + }; + Ok(Self(proxy, menu)) + } + fn property(&self, prop: &str) -> Option { self.0.cached_property(prop)?.get() } @@ -141,9 +210,8 @@ impl StatusNotifierItem { self.property("IconName") } - fn menu(&self) -> Option { - // TODO: Return menu rather than just string - self.property("Menu") + fn menu(&self) -> Option { + self.1.clone() } }