Supporting Wayland extensions on Mir servers

Context

Within the Mir team we’ve been discussing a number of extensions to support different uses of Mir.

These are some notes for discussion about the way in which these extensions should be managed. (Not about any specific extensions.)

The need to manage Wayland extensions

There are a large and growing number of Wayland extensions. For some of these it is clear that Mir should support them “out of the box”. However, there are others that are useful in some scenarios and the opposite in others.

If we are to pursue Mir’s goal of being a great library for developing multiple shells that means any shell based on Mir needs to have control over the Wayland extensions offered to its clients.

Selecting extensions at runtime

While much of Mir can be configured independently of the shell, I think the need for shells to participate in the implementation of these extensions means this should be decided by the shell developer. While this could be done at build time, I think a runtime option will be easier to manage. Something along the lines of:

class WaylandExtensions {
...
    bool enable(std::string const& extension, int version);
    bool disable(std::string const& extension);
...
};

Implementing extensions

Wayland extensions should be implemented in the libmirserver library. We will have to curate a sensible set of default extensions.

As with the rest of Mir sensible default behaviors should be provided leaving shell developers free to customize for their particular needs. To do this some extensions will require more involvement from the shell than is currently supported by libmiral. To support these we will need to either add properties to existing types (e.g. miral::Window) or introduce new abstractions.

We have experience of adding facilities to libmiral without breaking ABI, and we should continue to maintain backward compatibility going forwards.

The community

If anyone outside the Mir team is considering a need for Mir to offer Wayland extensions that are not currently supported, this should help give a feel for the criteria that would be applied.

4 Likes

As might be expected, I Have Thoughts.

Extension FIltering

I think there are three relevant classes of extensions here:

  1. Extensions which require the active participation of the shell. These are ones for which there is no sensible default behaviour, or which provides extra information to the shell which Mir doesn’t otherwise use. An example of this might be the (prototype) xdg_session_manager extension which requires integration with the way the session launches applications.
  2. Extensions which either have sensible default implementations (idle-inhibit, keyboard-shortcuts-inhibit) or which are entirely hidden from the shell (presentation-time, xdg-foreign).
  3. (Maybe) Extensions which we want to require support for; core things like wl_subcompositor, or xdg-shell.

Extensions of type 1 are easy - a shell which doesn’t wish to export them need only fail to register the required code and they won’t be exported.

Extensions of type 2 are trickier, and require some explicit mechanism to handle.

Rather than have a global opt-in, however, I think we might want to piggy-back on some different infrastructure. Some extensions - surface-layers, for example, or a screen-capture extension - want to be restricted to a subset of clients.

libwayland-server has a mechanism for this - wl_display_set_global_filter(). It registers a callback that recieves the wl_client that’s going to have the global exposed to and the wl_global that’s going to be exposed, and returns false if that global should be hidden from the client.

Since Wayland extensions only exist for the cilent if the corresponding global is advertised, this has the result of selectively disabling extensions on a per-client basis.

class miral::ExtensionAuthorizer
{
...
    bool extension_is_allowed(Application const& app, wl_global const* global) = 0;
...
};

The default implementation would always return true, shells can easily use this to implement extensions whitelists/blacklists on a global or per-client basis, and any extensions we think should never be disabled we can simply not call the filter for.

And, for the second part.

Implementing custom Wayland extensions

I think that ultimately we’ll want to get out of the way of shell authors here, and expose a way to get the corresponding Wayland object out of a Mir object, and visa-versa:

std::optional<wl_client*> client_for_application(miral::Application const& app)
miral::Application const& application_for_client(wl_client* client);

and so on.

That’s maximally expressive for shell authors, while probably being the least overall effort for us.

Ideally people would contribute broadly-useful custom Wayland protocol implementations as PRs to the Mir repository, and I don’t think we want to spend too much effort making doing something else easy.

Agreed: We should make the “right way” easier than the “wong way”.