-
Notifications
You must be signed in to change notification settings - Fork 86
Developing
As the future of the project is uncertain, I want to leave here something that will help event if this project stop working: documentation. I think that that was the most challenging of doing this, the “research” which was a trial and error on all the possibilities. Is really stressful to develop this way, so I hope this helps with the future developer of similar projects.
DBus is a messaging system that can be used to communicate between processes. Is generally used when some program wants to expose some state or capability to be used from the outside, for example, to inhibit suspension or to enable some actions with the media keys.
A bus from a program is described by three things: a name (in the form of reverse-DNS or application ID, which the bus sever will resolve to a a unique name like :1.27
), an object path (of the form /org/freedesktop/UPower
, which are containers for interfaces) and an interface (of the form org.freedesktop.UPower
).
The interfaces are the ones that provide the communication through methods, properties and signals. I won’t go in-depth, but basically, they are what they sound like, methods are functions that accept parameters and return a value, properties have an internal state that can be set or obtained, and you can subscribe to signal to know when a certain event has happened.
For more information I recommend this post from Andy Holmes.
The actions that are triggered by each menu are special. They are not just a simple function, they are an object that is exported through DBus, and that’s what we care about. These can be retrieved and activated from the outside, like a global menu or a HUD.
So, how does one knows the unique dbus address of an app? In the case of Gtk apps and almost any other app, the window has some special properties, among which the _GTK_UNIQUE_BUS_NAME
has the value that we are looking for. Is possible to get this property through Bamf, a daemon created by canonical to interact with the windows. Since, it’s getting obsolete on Wayland, it was necessary to create a gnome extension to get access to all these variables and to know when the user switches windows. With this address now with need to check in which path the app export its menu, for that we need to check the variables _GTK_MENUBAR_OBJECT_PATH
and _GTK_APP_MENU_OBJECT_PATH
. Once we got the dbus object, we get the menus on the interface org.gtk.Menus
with Start()
# Getting the menus on a Gtk app
bus_name = window['_GTK_UNIQUE_BUS_NAME']
paths = [window['_GTK_MENUBAR_OBJECT_PATH'], window['_GTK_APP_MENU_OBJECT_PATH']]
for path in paths:
if path is None:
continue
object = self.session.get_object(bus_name, path)
iface = dbus.Interface(object, dbus_interface='org.gtk.Menus')
menus = iface.Start([x for x in range(1024)])
The process to get the dbus address for Qt apps is different. They register the address and path to a dbus process created for this purpose, called com.canonical.AppMenu.Registrar
. I think that it can have a different name, but there’s no much documentation about it. We can get the dbus information of the window with its xid through this service (we again need the extension the get the xid on Wayland). To get the menu we need to use the interface com.canonical.dbusmenu
on the obtained address.
bus_name = 'com.canonical.AppMenu.Registrar'
bus_path = '/com/canonical/AppMenu/Registrar'
object = session.get_object(bus_name, bus_path)
interface = dbus.Interface(object, bus_name)
name, path = interface.GetMenuForWindow(self.window.get_xid())
object = session.get_object(name, path)
interface = dbus.Interface(object, 'com.canonical.dbusmenu')
menus = interface.GetLayout(0, -1, dbus.Array(signature="s"))
Keep in mind that even tough I name the process belonging to “Qt” and “Gtk” apps but there’s nothing avoiding an app to use whatever way to export the menus it wants. I use that naming scheme because that is what happen on most cases. And for the rest of apps, they tend to use the Gtk method, but again, I don’t know who choses what method to follow.
// TODO
A big part of developing is the tools that one used. Those apps or knowledge that you “wish have known before”. Some projects to read and someone to copy are also always useful. So here are some useful names and links:
- gnomehud — has a HUD but not a global menu
- Gnome-Global-AppMenu — A deprecated gnome shell extension that added a global menu
- D-Feet — app to view and interact with the DBus
-
dbus-send
anddbus-monitor
— command line tools to send and monitor the bus, respectively
For gnome extensions:
- Gnome extensions web — Copying others is always a good way to learn
- Gjs API docs
- The Gnome Sheel itself
- View output of print commands — the old print/log, it never fails
Gtk: