Comment 11 for bug 522152

Revision history for this message
Sami Jaktholm (sjakthol) wrote :

There's a way to work around this problem in unity session but the workaround is not nice.

The Unity Panel Service sends a signal called 'EntryActivated' via dbus[1] every time a menu is shown/hidden/changed in the panel. These signals can be used to determine whether our menu is open or not.

Along with the signal, two properties are sent: entry_id and geometry. The entry_id uniquely identifies the menu that has just been made visible. So if the entry_id is the same as the ID of our menu, it's pretty safe to say that our menu is visible and if it's something else, our menu should not be visible. But there's a catch: ASFAIK there's no reliable way to get the entry_id via libappindicator. So we have to resort in another ugly hack and once again rely on Unity Panel Service.

Unity Panel Service DBus interface[1] has a method called Sync that returns details about all items in the panel. Here's one example:
 ('libmessaging.so', '0x7f1d44004d68', 'indicator-messages' ...

So to get the ID for our indicator, we need to find the entry with the name of our indicator and grab the second item from the tuple. Then it's just a matter of implementing the logic to figure out whether the menu is visible or not.

The solution is not optimal and is likely to cause unforeseen problems but it should make the situation a little better than it currently is.

----

As another point, I've been trying to figure out how this could be implemented inside the library. As I know very little about C programming, I can't help much with the implementation itself but have investigated how this could possibly be achieved.

There's this mysterious 'visible' property[2] in the DBusMenuItem. If this property value tells us what the name means, then we should just connect to the 'property-changed' of the root menu item inside 'setup_dbusmenu' and tell the clients that visibility has changed when needed. However the documentation states '...whether the menuitem _should_ be shown or not'. So is the property enough to tell that the menu is actually visible on the screen or is it just telling Unity that 'Could you please show the menu now' and Unity might show it (normal) - or not (something has gone very wrong)...

And when it comes to the StatusIcon fallback, implementing this is nothing more than emitting signal inside 'status_icon_activate' which actually pops the menu when user clicks the icon. Catching the hide event is a bit trickier but it may be possible by catching 'visibility-notify-event' of the menu inherited from gtk_widget (dunno exactly how the fallback is supposed to work but this seems logical :)).

If any of my thoughts are anywhere near being correct, this doesn't seem to be so hard thing to implement. Maybe it's just that when this library isn't used by the default indicators (they all implement their own DBusMenuServers), it doesn't get that much attention from the devs as it should...

----

[1]
 DBus Name: com.canonical.Unity.Panel.Service
 DBus Object Path: /com/canonical/Unity/Panel/Service
 DBus Interface: com.canonical.Unity.Panel.Service
 Introspection XML: http://bazaar.launchpad.net/~unity-team/unity/trunk/view/head:/services/panel-main.c

[2] http://developer.ubuntu.com/api/ubuntu-12.04/c/dbusmenu/libdbusmenu-glib-DbusmenuMenuitem.html#DBUSMENU-MENUITEM-PROP-VISIBLE:CAPS