status-area: Use ItemIsMenu correctly

The comment that was previously here assumed that `ItemIsMenu` should be
defined for any status item that has a menu, but the FreeDesktop spec
rather defines it as an item that "only supports the context menu", so
we should open the menu instead of trying to call `Activate`.

This change won't affect behavior if `ItemIsMenu` is true, but `Activate`
errors, except by opening the menu without having to wait for that
errror first. It will fix the left click to open menu behavior if any
client defines that method to not error, but does set `ItemIsMenu`.
This commit is contained in:
Ian Douglas Scott 2026-01-28 18:44:05 -08:00
parent c24b769acd
commit fe0e4bf409
2 changed files with 23 additions and 21 deletions

View file

@ -543,6 +543,9 @@ fn activate(
item: &StatusNotifierItem,
activation_token: Option<String>,
) -> Task<cosmic::Action<Msg>> {
if item.is_menu() {
return Task::done(cosmic::action::app(Msg::TogglePopup(id)));
}
let item_proxy = item.item_proxy().clone();
Task::future(async move {
if let Some(t) = activation_token {

View file

@ -10,6 +10,7 @@ use zbus::zvariant::{self, OwnedValue};
#[derive(Clone, Debug)]
pub struct StatusNotifierItem {
name: String,
is_menu: bool,
item_proxy: StatusNotifierItemProxy<'static>,
menu_proxy: Option<DBusMenuProxy<'static>>,
}
@ -44,32 +45,25 @@ impl StatusNotifierItem {
.build()
.await?;
// XX: some items will not implement this but have a menu anyway
let is_menu = item_proxy.item_is_menu().await;
let is_menu = item_proxy.item_is_menu().await.unwrap_or(false);
let menu_path = item_proxy.menu().await;
// Why would an item say it has no menu but provide a menu path? Slack does this.
let is_menu = menu_path.is_ok() || is_menu.unwrap_or(false);
if !is_menu {
return Ok(Self {
name,
item_proxy,
menu_proxy: None,
});
}
let menu_path = menu_path?;
let menu_proxy = DBusMenuProxy::builder(connection)
.destination(dest.to_string())?
.path(menu_path)?
.build()
.await?;
let menu_proxy = if let Ok(menu_path) = item_proxy.menu().await {
Some(
DBusMenuProxy::builder(connection)
.destination(dest.to_string())?
.path(menu_path)?
.build()
.await?,
)
} else {
None
};
Ok(Self {
name,
is_menu,
item_proxy,
menu_proxy: Some(menu_proxy),
menu_proxy,
})
}
@ -126,6 +120,11 @@ impl StatusNotifierItem {
)
}
/// Item is only a menu, with no `Activate` action
pub fn is_menu(&self) -> bool {
self.is_menu
}
pub fn menu_proxy(&self) -> Option<&DBusMenuProxy<'static>> {
self.menu_proxy.as_ref()
}