Egmde: Wayland reboot

Introduction

Mir, among other things, aims to make it easy to develop graphical “desktop environments” for Linux. There’s a lot of features that are common between all designs for desktop environments and, in addition, a lot that is common between the majority of designs. For example, it is common for applications to draw “windows” and for these to be combined onto the screen.

By providing the common features, and for the rest offering both sensible defaults and an easy way to customise them Mir is designed to support a range of possible designs.

This is the first of in a series of articles that illustrate the development of an Example Mir Desktop Environment [egmde].

Wayland

Most current desktop environments for Linux are based on X11. This is the last in a line of protocols for communicating between the applications, and parts of the “desktop environment”. However, the environment in which it works has changed somewhat since the 1980’s. That means many fundamental design decisions needed to be re-evaluated.

The result of this re-evaluation is a new protocol: “Wayland”. This has been implemented for a number of application “toolkits” and desktop environments. Instead of being based on X11 Mir supports the newer Wayland protocol.

For more details on the relationship between Wayland and compositors like Mir, KWin, and Mutter see Ok, so what *is* this Wayland thing, anyway?

Preparation

The code in this article needs Mir 1.2 (or later).

On Ubuntu 18.04 (and later) this is available from the mir-team/release PPA. It is also useful to install the weston package as the example makes use of weston-terminal as a Wayland based terminal application and the Qt toolkit’s Wayland support : qtwayland5. And finally, the g++ compiler and cmake.

$ sudo apt-add-repository ppa:mir-team/release
$ sudo apt install libmiral-dev mir-graphics-drivers-desktop
$ sudo apt install weston qtwayland5 
$ sudo apt install g++ cmake git pkgconf

On Fedora

$ sudo dnf install mir-devel
$ sudo dnf install weston qt5-qtwayland
$ sudo dnf install gcc-c++ cmake

Mir is also available from the Arch AUR and can be built from source for many versions of Linux.

Egmde

This series of articles follow the development of a very simple desktop environment. Because this is an example don’t expect it to be polished to a production level. But it is usable and could be the basis for further work.

Building the example

The full code for this example is available on github:

$ git clone https://github.com/AlanGriffiths/egmde.git
$ git checkout Article-1

Naturally, the code is likely to evolve, so you will find other branches, but the Article-1 branch goes with this article. Assuming that you’ve MirAL installed as described above you can now build egmde as follows:

$ mkdir egmde/build
$ cd egmde/build
$ cmake ..
$ make

Running the example

After this you can start egmde:

$ ./egmde

You should see a black Mir-on-X window with a cursor. You can launch a terminal window with Ctrl-Alt-T (or, if that conflicts with your desktop, Ctrl-Alt-Shift-T).

You should see the same black screen with a weston-terminal window. From this you can run commands and, in particular, start graphical applications. Perhaps qtcreator to examine the code?

You should find that you can do all the normal things – use the keyboard and mouse to switch between and resize windows. If you have a touchscreen, then that will work too.

Running a full desktop type session is also possible, but first I should mention that it is possible to close egmde using the keyboard combination Ctrl-Alt-BkSp. Now switch to a virtual terminal (Ctrl-Alt-F4 for example) log in and run egmde-desktop.

Installing the example

If you install egmde and it will be added to the greeter menu:

$ sudo make install

Depending upon the greeter used on your system it may be necessary to reboot before egmde appears as a login shell.

The example code

A lot of the functionality (default placement of windows, menus etc.) comes with the MirAL library. This means that there’s very little code needed to get this basic shell running:

$ wc -l *.cpp
75 egmde.cpp

The main program for this article is shown below.
This breaks down into three blocks, the first is:

    MirRunner runner{argc, argv};
    ExternalClientLauncher external_client_launcher;

These are two objects from the MirAL library. The runner takes care of running Mir, it takes the command line arguments to handle configuration options. The external_client_launcher is used later to launch the terminal window.

The second block is a lambda - keyboard_shortcuts - that does some basic input handling. For Ctrl-Alt-T it starts a terminal using external_client_launcher, for Ctrl-Alt-BkSp it tells runner to stop the server.

The final block is a call to runner.run_with() which takes a list of customizations applies them to the server and runs it. This is the main way of customizing your server (we’ll be looking at other options next time). The customizations used here include the keyboard_shortcuts and external_client_launcher mentioned above. There are also couple more MirAL library objects: Keymap and MinimalWindowManager which respectively manage the keyboard layout and provide some default window management.

Installing the example

To register applications with desktop environments we install a .desktop file in /usr/share/applications and to register Wayland based desktops with the greeter we install a .desktop file in /usr/share/wayland-sessions/. The content needed for both cases is similar, so for for this example we use the same .desktop file and install it to both places.

Conclusion

This article shows how the Mir library makes it easy to get started with a limited, but working “desktop environment”. From that point it is possible to extend the “desktop” in various ways – for example the MinimalWindowManager can be replaced with one that implements “tiling” (there’s an example in the Mir code that does this).

The next article will continue from this point and add features such as a “wallpaper” background and a “launcher” for selecting applications.

Code listing

using namespace miral;
int main(int argc, char const* argv[])
{
    MirRunner runner{argc, argv};
    ExternalClientLauncher external_client_launcher;

    auto const keyboard_shortcuts = [&](MirEvent const* event)
        {
            if (mir_event_get_type(event) != mir_event_type_input)
                return false;

            MirInputEvent const* input_event = mir_event_get_input_event(event);
            if (mir_input_event_get_type(input_event) != mir_input_event_type_key)
                return false;

            MirKeyboardEvent const* kev = mir_input_event_get_keyboard_event(input_event);
            if (mir_keyboard_event_action(kev) != mir_keyboard_action_down)
                return false;

            MirInputEventModifiers mods = mir_keyboard_event_modifiers(kev);
            if (!(mods & mir_input_event_modifier_alt) || !(mods & mir_input_event_modifier_ctrl))
                return false;

            switch (mir_keyboard_event_scan_code(kev))
            {
            case KEY_BACKSPACE:
                runner.stop();
                return true;

            case KEY_T:
                external_client_launcher.launch({"weston-terminal"});
                return true;

            default:
                return false;
            }
        };

    return runner.run_with(
        {
            set_window_management_policy<MinimalWindowManager>(),
            external_client_launcher,
            AppendEventFilter{keyboard_shortcuts},
            Keymap{},
        });
}

I wonder if freedesktop.org would accept MIR, MirAL and Egmde as an official upstream project under its umbrella.

In an ideal world GNOME-SHELL/Mutter and KWIN would switch to MIR as much as technically feasible and thus share more code between those projects. If MIR sat between mutter and the display stack (wayland/mesa) as some kind of display server (like X was), a lengthy complete gnome-shell rewrite could probably be avoided. This display server idea stems from the GNOME4 proposal (Option B): https://wiki.gnome.org/Initiatives/Wayland/GnomeShell/GnomeShell4

3 Likes


Lots of terminal apps

2 Likes

Here I made a little video on Egmde : https://www.youtube.com/watch?v=e4_SEybCB0M

6 Likes

A user on /r/linux complained about CSD causing inconsistent window styles (which, of course, is not the fault of Mir).

Although not a cure, “gtk3-nocsd” at least restores traditional title bars in some situations. (I’ve only tried “gtk3-nocsd” with Unity.)

Does (or will) “gtk3-nocsd” work similarly under Mir?

The Mir libraries, like the Wayland protocols, are agnostic about SSD or CSD. For example, one Mir server [Unity8] draws decorations server-side, but another[miral-kiosk] doesn’t draw any decorations.

Obviously, it is important that the server and clients agree on either CSD or SSD, or you risk ending up with either zero or two sets of decorations. There is a Wayland protocol proposed that allows the server and client to negotiate agreement. (I’m not sure where the latest version is https://github.com/swaywm/wlroots/pull/638 and https://github.com/KDE/kwayland/blob/master/src/client/protocols/server-decoration.xml are iterations of it.)

I’m not familiar with gtk3-nocsd3, but I imagine that it could prevent GDK applications drawing decorations, but don’t see how it could enable Mir servers to draw them.

1 Like

Thanks much for the reply! If interested, more info about gtk3-nocsd is available here. And here’s a snippet from the “how it works” section for gtk3-nocsd:

$LD_PRELOAD is used to override several Gdk and glib/gobject APIs to intercept related calls Gtk+ 3 uses to setup CSDs. For older versions of Gtk+ 3, while it is trying to initialize CSDs, it is led to believe that there is no compositor available, so CSDs are not added. For later Gtk+ 3 versions (3.16.1+), the gtk_window_set_titlebar method is reimplemented, as tricking Gtk+ 3 into thinking the compositor is disabled has side effects and is not sufficent anymore.

Additionally, as gtk_window_set_titlebar is also called from Gtk+ internally (and LD_PRELOAD cannot override function calls within a library), several other places in Gtk+3 (e.g. buildable interfaces for GtkWindow and GtkDialog) are also overridden to ensure that CSDs are disabled.

I’ve a question: will you add some things to egmde like a top bar with a clock and shortcuts for apps like other des?

Possibly, but don’t expect too much. The point of egmde is to demonstrate how to do things, not to provide production quality implementations.

1 Like