You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Given that I've never implemented that specific D-Bus API using PyQt5 (my API of choice for my own creations at the moment), I got nerd-sniped and decided to implement a Python proof of concept for practice with the API.
It's bedtime, but I've successfully exercised most of the functionality on offer. Granted, two of the parts that are left are important to what SDL would want, but they're more things I don't have time for tonight than things I anticipate having trouble with:
Passing icons as pixmaps rather than names to be looked up in the system icon theme (There isn't a ton of example code for how QtDBus's interaction with Qt's type meta-system translates from C++ to Python and I'll need to spend more time reading how it expects me to specify compound data types for D-Bus properties.)
Defining menus to be rendered by the desktop rather than just having D-Bus call the ContextMenu(x, y) method. (Shouldn't be difficult... just a bit time-consuming since I don't have a "D-Bus XML schema to PyQt5 QDBus" boilerplate generator, so I need to transcribe the relevant bits of the com.canonical.dbusmenu schema by hand first.)
(According to ubuntu/gnome-shell-extension-appindicator, rich tooltips, which also need compound data types, were never implemented by libappindicator or Unity to begin with and I doubt SDL has a pressing need for overlay icons or custom-animated "needs attention" tray icon states.)
I have, however, already discovered something relevant. It looks like the FreeDesktop version of the spec stalled once it became clear that GNOME had no interest in implementing tray icons of any kind.
My Kubuntu Linux 22.04 LTS doesn't implement org.freedesktop.StatusNotifierItem and does implement org.kde.StatusNotifierItem and the interface definition in ubuntu/gnome-shell-extension-appindicator also uses that interface name though, so far, aside from org.kde instead of org.freedesktop, I have produced interfaces my Plasma 5.x is OK with by following what is described on FreeDesktop.org.
...so, yeah. If anyone has any questions about implementing the StatusNotifierItem API, I'm now in a better position to answer them.
I'm not sure what details you consider significant, but I'm certainly willing to give it a shot.
At the highest level, the gist of how it works is:
You register a service on the session bus which implements the org.kde.StatusNotifierItem interface, with properties like Category (set it to "ApplicationStatus") to define the icon's appearance and behaviour, and with methods like Action and Scroll which will be called by the SNI host when the user interacts with it.
You then call the org.kde.StatusNotifierWatcher.RegisterStatusNotifierItem method under /StatusNotifierWatcher on org.kde.StatusNotifierWatcher (the name the active SNI host will claim) and it takes the service name you registered in step 1 as a string as its only argument.
The SNI host will then use the D-Bus introspection interface to retrieve the contents of all of the org.kde.StatusNotifierItem.* properties you implemented and to get a listing of which methods have been implemented and will create an icon based on what it finds. (eg. whether left-clicking and right-clicking do the same thing depends on whether you've registered separate handlers for Action and ContextMenu and whether the ItemIsMenu boolean property is true or false.)
When the program disconnects from the bus, the host will automatically remove the icon.
This XML schema is what ubuntu/gnome-shell-extension-appindicator is feeding to GDBusProxy to describe what it expects to find while the FreeDesktop document goes into more detail on what the argument values should be but doesn't touch on "not standard, but widely implemented" extensions to the API.
As far as tooling goes, here are the tools I used which I'd highly recommend:
qdbusviewer from Qt's development tools (eg. qttools5-dev-tools for Qt 5 on *buntu Linux) provides a great interactive browser for D-Bus introspection, as well as being a GUI for interactively querying properties and calling methods with sufficiently simple type signatures. The dialog that pops up when double-clicking a method is also a great way to check what type signature you're exporting. (I made good use of it to verify that I was exporting the API that I thought I was.)
dbus-monitor is a non-graphical tool for logging what's flowing over the bus to diagnose things which tends to be part of the same package as the D-Bus daemon itself. (eg. Very useful for stuff like seeing which error messages the D-Bus daemon is returning to the SNI Host when your type signatures aren't quite right on stuff it's supposed to call.)
Bustle is a graphical frontend for dbus-monitor which is much more amenable to exclusion-based filtering than bare dbus-monitor if you want to look at "everything except the irrelevant cruft that Workrave, Yakuake, and Pidgin are flooding the bus with". It also, in my experience, presents the argument lists for method calls in a format that's cleaner for lining up and comparing when you have a working SNI implementation and a buggy SNI implementation side-by-side. (D-Bus will tell you there's no such method if the signatures don't match. I haven't checked if that's because it supports method overloading, but I've never seen any APIs use that if it does.)
Also, in case you want to poke at a working implementation for basically everything relevant except for the IconThemePath property (a non-standard-but-commonly-implemented extension for amending the search path for IconName), the IconPixmap property, and the Menu property (For describing a menu for the panel host to render, as opposed to the ContextMenu method where you draw it yourself at the specified x,y coordinates), here's the current state of my PyQt5+QtDBus practice piece as I left it last night:
Leaving a note here that I'm currently in the process of learning DBus, and I plan to at least try to implement the system tray with it. I'm not sure how much time it'll take me; if someone more familiar with DBus than me would like to take the torch, just let me know so I can shift my efforts on something else :)
Also, shouldn't the title of the issue be "DBus implementation" rather than "AppIndicator"?
slouken
changed the title
Appindicator implementation of system tray support
D-Bus implementation of system tray support
Dec 24, 2024
We've had to recently switch from libappindicator to a manual DBus implementation due to the GTK4 migration, as you can't load both GTK3 and 4 in a single process. This was implemented here: slgobinath/SafeEyes#558, but needed to be adjusted to also include some non-standard attributes like slgobinath/SafeEyes#646 since desktop environments expect it, it seems.
In short, our implementation seems to work well at this point, even if the missing standardization is somewhat of a mess.
Given that I've never implemented that specific D-Bus API using PyQt5 (my API of choice for my own creations at the moment), I got nerd-sniped and decided to implement a Python proof of concept for practice with the API.
It's bedtime, but I've successfully exercised most of the functionality on offer. Granted, two of the parts that are left are important to what SDL would want, but they're more things I don't have time for tonight than things I anticipate having trouble with:
ContextMenu(x, y)
method. (Shouldn't be difficult... just a bit time-consuming since I don't have a "D-Bus XML schema to PyQt5 QDBus" boilerplate generator, so I need to transcribe the relevant bits of thecom.canonical.dbusmenu
schema by hand first.)(According to ubuntu/gnome-shell-extension-appindicator, rich tooltips, which also need compound data types, were never implemented by libappindicator or Unity to begin with and I doubt SDL has a pressing need for overlay icons or custom-animated "needs attention" tray icon states.)
I have, however, already discovered something relevant. It looks like the FreeDesktop version of the spec stalled once it became clear that GNOME had no interest in implementing tray icons of any kind.
My Kubuntu Linux 22.04 LTS doesn't implement
org.freedesktop.StatusNotifierItem
and does implementorg.kde.StatusNotifierItem
and the interface definition in ubuntu/gnome-shell-extension-appindicator also uses that interface name though, so far, aside fromorg.kde
instead oforg.freedesktop
, I have produced interfaces my Plasma 5.x is OK with by following what is described on FreeDesktop.org....so, yeah. If anyone has any questions about implementing the StatusNotifierItem API, I'm now in a better position to answer them.
I'm not sure what details you consider significant, but I'm certainly willing to give it a shot.
At the highest level, the gist of how it works is:
org.kde.StatusNotifierItem
interface, with properties likeCategory
(set it to "ApplicationStatus") to define the icon's appearance and behaviour, and with methods likeAction
andScroll
which will be called by the SNI host when the user interacts with it.org.kde.StatusNotifierWatcher.RegisterStatusNotifierItem
method under/StatusNotifierWatcher
onorg.kde.StatusNotifierWatcher
(the name the active SNI host will claim) and it takes the service name you registered in step 1 as a string as its only argument.org.kde.StatusNotifierItem.*
properties you implemented and to get a listing of which methods have been implemented and will create an icon based on what it finds. (eg. whether left-clicking and right-clicking do the same thing depends on whether you've registered separate handlers forAction
andContextMenu
and whether theItemIsMenu
boolean property is true or false.)This XML schema is what
ubuntu/gnome-shell-extension-appindicator
is feeding toGDBusProxy
to describe what it expects to find while the FreeDesktop document goes into more detail on what the argument values should be but doesn't touch on "not standard, but widely implemented" extensions to the API.As far as tooling goes, here are the tools I used which I'd highly recommend:
qdbusviewer
from Qt's development tools (eg.qttools5-dev-tools
for Qt 5 on *buntu Linux) provides a great interactive browser for D-Bus introspection, as well as being a GUI for interactively querying properties and calling methods with sufficiently simple type signatures. The dialog that pops up when double-clicking a method is also a great way to check what type signature you're exporting. (I made good use of it to verify that I was exporting the API that I thought I was.)dbus-monitor
is a non-graphical tool for logging what's flowing over the bus to diagnose things which tends to be part of the same package as the D-Bus daemon itself. (eg. Very useful for stuff like seeing which error messages the D-Bus daemon is returning to the SNI Host when your type signatures aren't quite right on stuff it's supposed to call.)dbus-monitor
which is much more amenable to exclusion-based filtering than baredbus-monitor
if you want to look at "everything except the irrelevant cruft that Workrave, Yakuake, and Pidgin are flooding the bus with". It also, in my experience, presents the argument lists for method calls in a format that's cleaner for lining up and comparing when you have a working SNI implementation and a buggy SNI implementation side-by-side. (D-Bus will tell you there's no such method if the signatures don't match. I haven't checked if that's because it supports method overloading, but I've never seen any APIs use that if it does.)Also, in case you want to poke at a working implementation for basically everything relevant except for the
IconThemePath
property (a non-standard-but-commonly-implemented extension for amending the search path forIconName
), theIconPixmap
property, and theMenu
property (For describing a menu for the panel host to render, as opposed to theContextMenu
method where you draw it yourself at the specified x,y coordinates), here's the current state of my PyQt5+QtDBus practice piece as I left it last night:https://gist.github.com/ssokolow/1cbe7d9341d6b4401b17c0f7eebbd2b8
(I'll update it when I make more time to keep working on it.)
Beyond that, I'll wait for you to ask further questions.
Originally posted by @ssokolow in #10873 (comment)
The text was updated successfully, but these errors were encountered: