What the bespoke Wayland extensions API might look like

We’ve discussed supporting shell specific Wayland extensions in the past (here and here).

My view following those discussions is that we should encourage “broadly useful” Wayland protocol extensions to be submitted as PRs to the Mir repository. As many such protocols will need to interact with Mir internal APIs this will ensure they can access these features.

However, there are also some plausible protocol extensions that will be specific to particular shells. For example, before Unity8 can transition to Wayland they will need something to replace the “Trusted Prompt Sessions” provided by the libmirclient API.

I’ve now started seriously thinking about how to implement a MirAL API to enable this. There are (at least) three aspects of this API to consider:

  1. Enabling a shell to register and implement a protocol extension;
  2. Supporting integration with other abstractions exposed by the MirAL API; and,
  3. Allowing the shell to control which protocols are available to specific clients.

I’ve sketched out what the API for the first of these might look like in a PR (https://github.com/MirServer/wlcs/pull/77). The API parts are the “MirAL 2.5” parts of this:

class WaylandExtensions
    /// Provide the default extensions supported by Mir

    /// Provide a custom set of default extensions (colon separated list)
    /// \note This can only be a subset of supported_extensions().
    explicit WaylandExtensions(std::string const& default_value);

    /// \remark Since MirAL 2.5
    using Executor = std::function<void(std::function<void()>&& work)>;

    /// A Builder creates and registers an extension protocol.
    /// The Builder is provided the wl_display so that the extension can be registered and
    /// an executor that allows server initiated code to be executed on the Wayland mainloop.
    /// It returns a shared pointer to the implementation. Mir will manage the lifetime.
    /// \remark Since MirAL 2.5
    using Builder  = std::function<std::shared_ptr<void>(wl_display* display, Executor const& run_on_wayland_mainloop)>;


/// Add a bespoke Wayland extension.
/// \remark Since MirAL 2.5
auto with_extension(
    WaylandExtensions const& wayland_extensions,
    std::string const& name, WaylandExtensions::Builder const& builder) -> WaylandExtensions;

/// Add multiple bespoke Wayland extensiona.
/// \remark Since MirAL 2.5
template<typename... Extensions>
auto with_extension(WaylandExtensions const& wayland_extensions,
    std::string const& name, WaylandExtensions::Builder const& builder,
    Extensions... extensions) -> WaylandExtensions
    return with_extension(with_extension(wayland_extensions, name, builder), extensions...);

This bare minimum API provides the extension implementation to access the wl_display for registering the protocol and provides an executor so that code can be run on the Wayland mainloop.

    auto const server_exit_status = runner.run_with({
            "xdg_decoration_unstable_v1", &xdg_decoration_unstable_v1,
            "some_other_extension", &some_other_extension),

I believe this to be enough to implement some protocols. Obviously, I have something like xdg_decoration_unstable_v1 in mind.

As far as I can see, support for items 2 and 3 in my list above can be added in a later iteration.

Hi Alan,

one design question: is the shell sharing the same process with mir, i.e. the Unity8 shell would use Mir as a library?
The API would suggest so as it would be called by the shell to inject its server-side decoration code, right?

Yes, Mir is a library for writing shells. Window management, compositing etc. all take place in-process.

So if I understand correctly Mir would expose the autogenerated interface from src/server/frontend_wayland/generated/.h leaving to the shell the actual implementation by subclassing it. The implementation can use the Mir API to realise the extension’s functionality.

Sorry, I’ve been working on this project so long that I can sometimes forget the signposts that are needed by someone coming to it anew.

Mir, as it is on master supports a number of Wayland extension protocols internally. These have the protocol definitions in src/server/frontend_wayland/protocol/.xml, generated C++ interfaces and “boilerplate” in src/server/frontend_wayland/generated/.h, implementations in src/server/frontend_wayland/.h,.cpp.

At present, servers written using Mir can only can configure these internally supported Wayland protocols to the extent of switching then on or off (via miral/wayland_extensions.h.).

However, not every Wayland protocol is suitable to be incorporated directly into Mir. Some might be specific to a particular shell and it makes sense for Mir to provide a way for shells to implement these without needing to upstream the protocol definition and supporting code to Mir. In this case, the protocol won’t be in the Mir tree, nor will the generated code.

I know from the Unity8 Telegram group that you’re interested in implementing xdg_decoration_unstable_v1 for Unity8, and it is unfortunate that I confused you by using it as an example of a protocol that doesn’t need integration with Mir internals and could therefore be implemented downstream using the API I propose here.

The route I steered you towards there was to implement this protocol in Mir using the src/server/frontend_wayland tree. For this to work you will also need to expose a MirAL API for servers to select decoration options, but we’ve not discussed that yet.

Hypothetically, if and when an API like the one proposed here is available, then there will be an alternative for you: to implement the xdg_decoration_unstable_v1 protocol downstream (in QtMir). That would require adding the protocol definition, any code generation and the implementation to QtMir.

I hope that is clearer.

Having had a closer look at the xdg_decoration_unstable_v1 protocol I realize that it depends on xdg-shell - and therefore can NOT be implemented using the API I’m proposing anyway. (At least, now without further APIs to expose protocol extension implemented within Mir.)

Similarly, the precursor server_decoration protocol depends on wl_shell. Maybe this API isn’t going to be enough do do anything useful.

Ok, got it. I would move discussions on the decoration protocol to the github issue https://github.com/MirServer/mir/issues/664. For the time being I have forked the repository and created a branch on it where I have added the generated empty classes.

WRT to your suggested API, I guess it depends on how much context the shell encapsulates in the Builder(s) and Executor(s): if those have access to the Mir API and know about each other they could have sufficient information, but admittedly my knowledge of Mir internals is definitely not enough to judge it.