#264 Work on a new appindicator protocol
Opened 4 months ago by mclasen. Modified 4 months ago

This is a follow-up from https://pagure.io/fedora-workstation/issue/246

When we discussed this ticket in the WG meeting on 01-11-2022, the sentiment
was that we should have some idea for how to support app indicators / status notifiers upstream before we go the "just use the extension" route. Since the
existing appindicator protocol is deemed unacceptable upstream, we need a
suggestion for a protocol that would, even if we end up supporting the existing appindicator protocol with a proxy (or directly).

Here is some prior work by Patrick on this: https://blog.tingping.se/2019/09/07/how-to-design-a-modern-status-icon.html

The concrete task here is to form a working group for this task, and report back with results.

Candidates for such a working group: Matthias, Florian, somebody from the KDE side, somebody from Canonical


Patrick's blog post is missing a reference to https://ayatanaindicators.github.io/code/, which is a fifth incompatible indicator spec, but I understand this one has not achieved much adoption anywhere. Our goal should be to design a sixth incompatible spec to replace the first five, in the true spirit of https://xkcd.com/927/.

A contributor has provided us with a draft spec based on the KDE status notifiers as a starting point. There are a couple TODOs regarding icon and menu serialization, most importantly how to build a GMenu from Qt. If Canonical or KDE don't want to change how the menus work, then we should be willing to compromise on the menus first, because messy menus are more a wart than a blocker. (I have not investigated libdbusmenu to see why it is so disliked.)

Removing X11-isms and removing sandboxing mistakes like "app must own entire org.kde D-Bus namespace to create an indicator" or "app must use PID namespace of host system" should be the main priorities.

<?xml version="1.0"?>
<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
  <!--
      This spec describes a way for applications to export a status icon
      and an associated menu.
      How this is used:
      1. Application creates a dbus object implementing the org.freedesktop.StatusIcon interface and exports it.
      2. Application watches for the bus name org.freedesktop.portal.StatusIconService
      3. Whenever it appears it subscribes to the StatusIconStateChanged signal
      4. It calls AddStatusIcon()
      5. Based on the StatusIconStateChanged changes, and the bus name disappearing, the application will always
         be up to date on the visibility of the status icon
      THIS IS A DRAFT!
      Notable differences from the org.kde.StatusNotifier specs:
      - Category has been removed. In practice these were not used in a meaningful way?
      - WindowId has been removed. This was an X11 detail.
      - IconThemePath has been removed. Filesystem paths aren't useful for sandboxed applications.
      - All New*() signals have been removed. org.freedesktop.DBus.Properties handles property change notifications.
      - Status was turned into an enum instead of strings and more clearly defined as the State property.
      - Activate/SecondaryActivate no longer has x,y arguments: These are details that don't make sense without X11.
      - All Attention properties removed: This has no distinction and you can change the normal Icon at any time.
      - ToolTip was simplified to text only.
      - Scroll removes orientation argument: Horizontal scrolling isn't commonly handled or supported.
      - ContextMenu method is removed: This only makes sense on X11.
      - Menu property changed to org.gtk.Menus: This is more simple than DBusMenu.
      - No well known dbus names are recommended for exporting your status icon. This means it works in a sandbox.
        The `org.kde.StatusNotifierItem-PID-ID` naming was broken on multiple levels:
        - PID's are useless in pid-namespaced sandboxes
          Real world apps are broken here, they all try to own the PID `2` because they are all the same in every sandbox
        - Bus name ownership is explicitly forbidden unless a permission is granted to the flatpak
          Even worse `org.kde.StatusNotifierItem-PID-ID` is not namespaced so you must grant ownership permissions to all of `org.kde.*` for it to work in flatpak.
          This means *all* KDE flatpaks can pretend to be *any* KDE service. All security is currently lost.
        - The watchers bus name is hardcoded to be `org.kde.StatusNotifierWatcher`. DBus talk permissions are forbidden to this namespace unless explicitly granted.
      - The Id property is removed. This is now passed when you register the status icon. It doesn't make sense to be a
        changable property.
      - All visibility tracking is kept to one StatusIconStateChanged signal. Instead of tracking if your icon was
        registered, unregistered, and if the StatusNotifierHost is registered or not.
  -->

  <!--
      org.freedesktop.StatusIcon:
      @short_description: Interface for application exposed status icons
   -->
  <interface name="org.freedesktop.StatusIcon">
    <!-- Descriptive title for the application, this MAY be shown by the host -->
    <property name="Title" type="s" access="read"/>
    <!-- Tooltip text to show on hover, this MAY be shown by the host -->
    <property name="ToolTip" type="s" access="read"/>
    <!-- Name referring to the icon to show as-per icon-theme-spec -->
    <property name="IconName" type="s" access="read"/>
    <!-- Name referring to an icon to overlay as-per icon-theme-spec -->
    <property name="OverlayIconName" type="s" access="read"/>
    <!-- Item has a valid Menu property -->
    <property name="ItemIsMenu" type="b" access="read"/>
    <!-- Exported org.gtk.Menus object
         https://wiki.gnome.org/Projects/GLib/GApplication/DBusAPI#org.gtk.Menus
         TODO: This needs to have a good Qt story.
               Something exists here: https://github.com/KDE/plasma-workspace/tree/master/gmenu-dbusmenu-proxy
      -->
    <property name="Menu" type="o" access="read"/>

    <!-- TODO: Binary formats for icons. Note these must be handled safely by the host and must handle scaling. -->

    <!--
        State: The state of the StatusIcon
        Currently defined states are:
        <simplelist>
          <member>0: HIDDEN</member>
          <member>1: VISIBLE</member>
        </simplelist>
        When set to HIDDEN the host MUST not show the status icon.
        When set to VISIBLE the host MUST show the status icon.
    -->
    <property name="State" type="u" access="read"/>

    <!--
        Activate: Emitted when the icon received a primary click.
        QUESTION: Single and double click are inconsistant?
    -->
    <method name="Activate"/>
    <!--
        SecondaryActivate: Emitted when the icon received a secondary click.
        QUESTION: Should we actually keep this, it seems intended for showing your own menus
                  which can't be done.
    -->
    <method name="SecondaryActivate"/>
    <!--
        Scroll: Emitted on mouse scroll while over the icon.
    -->
    <method name="Scroll">
        <arg name="delta" type="i" direction="in"/>
    </method>
  </interface>


  <!--
      org.freedesktop.portal.StatusIconService:
      @short_description: Portal interface that registers status icons.
   -->
  <interface name="org.freedesktop.portal.StatusIconService">
    <!--
        Internally how this is implemented is undefined.
        It would be very possible for `xdg-desktop-portal-kde` to simply
        use the existing infrastructure for status icons. This is effectively
        the old StatusNotifierWatcher, the StatusNotifierHost is still external.
        The menu translation really being the only tricky part if that changes.
        GNOME and others would need its own internal interface for this.
     -->

    <!--
        AddStatusIcon: Registers a new status icon.
        @id: Unique identifier for the icon
        @path: The path for the exported icon
    -->
    <method name="AddStatusIcon">
      <arg type="s" name="id" direction="in"/>
      <arg type="o" name="path" direction="in"/>
    </method>

    <!--
        RemoveStatusIcon: Removes status icon.
        @id: Unique identifier for the icon
    -->
    <method name="RemoveStatusIcon">
      <arg type="s" name="id" direction="in"/>
    </method>

    <!--
        StatusIconStateChanged:
        @app_id: App id of the application
        @id: the application-provided ID for the status icon
        @state: The state of the status icon
        Send to the application when the visibility of a status
        icon changes.
        Currently defined states are:
        <simplelist>
          <member>0: HIDDEN</member>
          <member>1: VISIBLE</member>
        </simplelist>
    -->
    <signal name="StatusIconStateChanged">
      <arg type="s" name="app_id"/>
      <arg type="s" name="id"/>
      <arg type="u" name="state"/>
    </signal>

    <!--
        ActionInvoked:
        @app_id: App id of the application
        @id: the application-provided ID for the status icon
        @action: the name of the action
        @parameter: array which will contain the target parameter
          for the action, if one was specified
        Send to the application when a non-exported action is
        activated.
    -->
    <signal name="ActionInvoked">
      <arg type="s" name="app_id"/>
      <arg type="s" name="id"/>
      <arg type="s" name="action"/>
      <arg type="av" name="parameter"/>
    </signal>
  </interface>
</node>

Our goal should be to design a sixth incompatible spec to replace the first five, in the true spirit of https://xkcd.com/927/.

It might be pragmatic to couch this as a backwards-incompatible update to one of the existing standards, rather than an entirely new thing (even though it really is).

Candidates for such a working group: Matthias, Florian, somebody from the KDE side, somebody from Canonical

I suggest we invite Ayatana and xapp to each send a developer. That would cover every current status icon implementation.

From the KDE side, at least @ngraham has expressed interest in helping. @apol may be interested too, though he's a bit busy right now.

I think it'd be wise to discuss this somewhere agnostic like xdg@lists.freedesktop.org

I think it'd be wise to discuss this somewhere agnostic like xdg@lists.freedesktop.org

Once we have a draft spec, yes, we'd probably want to do that. This doesn't even count as a draft yet.

Metadata Update from @ngompa:
- Issue tagged with: experience

4 months ago

I think it'd be wise to discuss this somewhere agnostic like xdg@lists.freedesktop.org

I agree it would be nice to move this to freedesktop.org somehow. That said, it shouldn't require joining a mailing list. Maybe an issue report at https://gitlab.freedesktop.org/xdg/xdg-specs/-/issues would be a good place to work?

Things that are missing from the draft:

An intro: There needs to be some text that explains what this spec is about, the scope and
relevant parties. The initial comment is a good start.

UX and behavior guidelines:

  • What can users of the API expect from compositors implementing it? Does the icon have to be permanently visible on screen, or is it fine for the compositor to e,g, hide it away in some drawer?
  • How should menus be exposed ? Does it have to be right click on the icon?
  • What are the expectations for the client ? Is it ok to ignore the activate call, or should the app provide some clearly visible user feedback?
  • How is this icon overlaying supposed to work ? Are the icons the same size ? What if they aren't?

Lacking these is a big part of why the original spec isn't adequate.

Information about required and optional parts, and acceptable use of the api:

  • What happens if I leave the icon-name property empty?
  • Is it ok to change the icon-name after registering?
  • Can I add or remove menu items or submenus?
  • What does HIDDEN vs VISIBLE indicate, exactly? If the statusicons are packed into a drawer or submenu, does that count as HIDDEN until the drawer is opened?

Consistency with other specs, and internally:

  • For notifications, icons are generally sent as image data. Should that be done here too?
  • We already have dbus interfaces for activating actions - why does this spec need to add another?
  • What is the point of the unique ID? Why is the path not sufficient?
  • The Scroll handling seems inadequate. Scroll events come in different flavors. The may be discrete, or they may have x/y deltas

I think it'd be wise to discuss this somewhere agnostic like xdg@lists.freedesktop.org

I agree it would be nice to move this to freedesktop.org somehow. That said, it shouldn't require joining a mailing list. Maybe an issue report at https://gitlab.freedesktop.org/xdg/xdg-specs/-/issues would be a good place to work?

That makes sense to me.

Just some comments that can get added back into the draft:

How is this icon overlaying supposed to work ? Are the icons the same size ? What if they aren't?

Maybe it is worth just removing this property. In practice applications can often include premade icons with overlays and in the advanced case its not hard to composite them client side. This removes any implementation doubts of how it would look.

Is it ok to change the icon-name after registering?

The pattern for all trays is they can change the icon whenever. This does have some questions about security and performance (the host should cache a few icons in case it changes frequently?).

Can I add or remove menu items or submenus?

Both GMenu and DBusmenu support dynamically changing menus. Hosts should support this.

What does HIDDEN vs VISIBLE indicate, exactly? If the statusicons are packed into a drawer or submenu, does that count as HIDDEN until the drawer is opened?

So this is overloaded by two ideas and maybe shouldn't be:

Previously it was possible to set a statusnotifier to "Active" or "Passive". I found this wording more clear but I guess not clear enough. The idea is just that a tray can be registered but set to not be shown at all. Maybe this is a mis-feature. Toggling on and off shouldn't be common and the fact a tray exists has meaning (an application is effectively running in the background).

I also used this property to indicate that the host has finally shown the icon in their tray. As-in the application can start making assumptions that the user sees it and its safe to do something like hide a main window.

For notifications, icons are generally sent as image data. Should that be done here too?

I wouldn't say that is true, I believe by icon-name is the most common. I do think sending data should be supported and often recommended.

I've updated this to be the same serialized format we use for org.freedesktop.portal.Notifications.

We already have dbus interfaces for activating actions - why does this spec need to add another?

org.freedesktop.Portal.Notifications already has this pattern. It exists for private actions or applications that don't support exporting actions, as I understand it.

What is the point of the unique ID? Why is the path not sufficient?

Good idea :thumbsup:.

The Scroll handling seems inadequate. Scroll events come in different flavors. The may be discrete, or they may have x/y deltas

As implemented in GNOME. It is either +1 for each scroll event up and -1 for each scroll event down.

UX and behavior guidelines:

On that broad topic my thoughts:

  • Left click always activates the Activate signal. (We should actually get rid of SecondaryActivate as the comment above says). In GNOME currently this is emitted from double left click and middle click. Double clicking is terrible as the first click opens the menu.
  • Middle click can continue to work as Activate.
  • Right click either does nothing or renders a pop-up menu.
    • Menus must support: submenus, toggle menus, and radio menus all with just text labels. I think we should avoid all other features. DBusmenu is designed to support effectively everything since its original purpose was to move complex application menubars around, but we only need a subset.
  • Icons
    • I'm not certain of sizes but I think we should limit scope to 24/32/48px icons*.
    • *We must expose DPI scaling though. Maybe the host service exposes this and clients do the right thing?
    • Handling of symbolic icons needs to be done on the host.

Thanks, all of that sounds right to me

Let's move upstream work to: https://gitlab.freedesktop.org/xdg/xdg-specs/-/issues/84

This issue should remain open for downstream tracking purposes.

Login to comment on this ticket.

Metadata