Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

D-Bus implementation of system tray support #11703

Open
slouken opened this issue Dec 24, 2024 · 2 comments
Open

D-Bus implementation of system tray support #11703

slouken opened this issue Dec 24, 2024 · 2 comments
Milestone

Comments

@slouken
Copy link
Collaborator

slouken commented Dec 24, 2024

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:

  1. 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.
  2. 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.
  3. 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.)
  4. 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:

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)

@slouken slouken added this to the 3.2.0 milestone Dec 24, 2024
@Semphriss
Copy link
Contributor

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 slouken changed the title Appindicator implementation of system tray support D-Bus implementation of system tray support Dec 24, 2024
@deltragon
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants