Egmde: integrating a launcher


I recently (re)introduced a simple shell based on Mir: egmde. This shell is just the code needed to illustrate these articles and, maybe, inspire others to build on it but it is not intended to be a product.

At the end of the last article we could run egmde as a desktop and run and start Wayland based applications from a terminal. We could also select the keyboard layout and cusomize the wallpaper.

In this article we provide an integrated “launcher” to start applications so that applications do not need to be launched from the terminal.


The code in this article needs Mir 0.31 or later. This exists in Ubuntu 18.04 and Fedora 28 but it is recommended to use the mir-team/release PPA.

On Ubuntu use:

$ sudo apt-add-repository ppa:mir-team/release
$ sudo apt update
$ sudo apt install g++ cmake pkg-config
$ sudo apt install libmiral-dev mir-graphics-drivers-desktop libfreetype6-dev libboost-all-dev
$ sudo apt install qtwayland5 

Or, if using Fedora, use:

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

The full code for this example is available on github:
$ git clone
$ git checkout article-3
Naturally, the code is likely to evolve, so you will find other branches, but this 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

After this you can start a basic egmde based desktop. This will use VT4, so first switch to VT4 (Ctrl-Alt-F4) to sign in and switch back again. Then type:

$ ./egmde-desktop

You should see a simple gradient wallpaper with simple instructions:

If you press Ctrl-Alt-A then the launcher appears on top of whatever you are currently running (initially nothing) and updated instructions:

That should be enough of a clue to get you started.

Other changes since last time

There’s also a small change to the wallpaper I introduced in the previous article, it is now possible to customize both the top and bottom colour for the gradient. This followed from some “corridor testing” by my wife who found the previous option and default colour unappealing.

This allows a “better brighter wallpaper” (as well as my choice):

Here’s the corresponding .config file:

$ cat ~/.config/egmde.config 

Another small change is that I found a way to pick up the current keyboard and added that to the miral-desktop launch script so that it doesn’t need to be set by hand.

The example code


I’ll first deal quickly with the wallpaper changes these options are provided by:

        CommandLineOption{[&](auto& option) {;},
                          "wallpaper-top",    "Colour of wallpaper RGB", "0x000000"},
        CommandLineOption{[&](auto& option) { wallpaper.bottom(option);},
                          "wallpaper-bottom", "Colour of wallpaper RGB", "0x92006a"},

The corresponding changes to the Wallpaper class are easy to follow.


The main addition to the code os the “launcher”. I’ll concentrate on the changes to egmde.cpp as the Launcher class itself is a “legacy” Mir client. It is on my list to support “internal” Wayland clients in Mir, but that hasn’t happened yet.
The first update to the main program is adding this:

    ExternalClientLauncher external_client_launcher;
    egmde::Launcher launcher{external_client_launcher};

Note: If you look at the real code at the time of writing you’ll see there’s a bit of preprocessor magic to support the released version of Mir which doesn’t have ExternalClientLauncher. I’m going to ignore this (and another workaround for the lack of logind support) as these will be addressed by a Mir update in the near future.

Next, there’s a piece of code or handling keyboard input and showing the 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_A:
            return true;

        case KEY_BACKSPACE:
            return true;

            return false;

This is a lambda that is later added to the Mir event processing and looks for either Ctrl-Alt-A or Ctrl-Alt-BkSp and shows the launcher or stops the runner accordingly.

Finally, as promised, these are added to the “run_with()” list which now looks as follows:

return runner.run_with(
        StartupInternalClient{"launcher", std::ref(launcher)},

A final word

The MirAL API is designed so that keeping separate things separate is easy: the launcher code doesn’t have any inter-dependency with the wallpaper or the the window management code. So we could replace any of these without affecting the others.

That makes it easy to understand the individual components and customise them to build a server to suit your requirements.


cmake …
– Checking for module ‘freetype2’
– No package ‘freetype2’ found
CMake Error at /usr/share/cmake-3.5/Modules/FindPkgConfig.cmake:367 (message):
A required package was not found
Call Stack (most recent call first):
/usr/share/cmake-3.5/Modules/FindPkgConfig.cmake:532 (_pkg_check_modules_internal)
CMakeLists.txt:12 (pkg_check_modules)

– Configuring incomplete, errors occurred!
See also “/home/pixel/egmde/build/CMakeFiles/CMakeOutput.log”.

so maybe "apt install libfreetype6-dev?"

cmake …
– Checking for module ‘freetype2’
– Found freetype2, version 18.1.12
CMake Warning at /usr/share/cmake-3.5/Modules/FindBoost.cmake:725 (message):
Imported targets not available for Boost version
Call Stack (most recent call first):
/usr/share/cmake-3.5/Modules/FindBoost.cmake:763 (_Boost_COMPONENT_DEPENDENCIES)
/usr/share/cmake-3.5/Modules/FindBoost.cmake:1332 (_Boost_MISSING_DEPENDENCIES)
CMakeLists.txt:13 (find_package)

CMake Error at /usr/share/cmake-3.5/Modules/FindBoost.cmake:1677 (message):
Unable to find the requested Boost libraries.

Unable to find the Boost header files. Please set BOOST_ROOT to the root
directory containing Boost or BOOST_INCLUDEDIR to the directory containing
Boost’s headers.
Call Stack (most recent call first):
CMakeLists.txt:13 (find_package)

CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
used as include directory in directory /home/pixel/egmde

– Configuring incomplete, errors occurred!
See also “/home/pixel/egmde/build/CMakeFiles/CMakeOutput.log”.

do i need a newer version of CMake? o_O
i haz apt list cmake
Listing… Done
cmake/xenial-updates,now 3.5.1-1ubuntu3 amd64 [installed]
N: There is 1 additional version. Please use the ‘-a’ switch to see it


cmake …
CMake Error at /usr/share/cmake-3.5/Modules/FindBoost.cmake:1677 (message):
Unable to find the requested Boost libraries.

Boost version: 1.58.0

Boost include path: /usr/include

Could not find the following Boost libraries:


Some (but not all) of the required Boost libraries were found. You may
need to install these additional Boost libraries. Alternatively, set
BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT
to the location of Boost.
Call Stack (most recent call first):
CMakeLists.txt:13 (find_package)

– Configuring incomplete, errors occurred!
See also “/home/pixel/egmde/build/CMakeFiles/CMakeOutput.log”.

apt install libboost-all-dev?

so yeah…

sudo apt install libmiral-dev mir-graphics-drivers-desktop qtwayland5 g++ cmake
sudo apt install libfreetype6-dev pkg-config libboost-all-dev

$ git clone
$ cd egmde
$ git checkout article-3
$ mkdir build
$ cd build
$ cmake ..
$ make

$ ./egmde-desktop

seems to work but when i quit it freezes muh PC…


Yes, there are a few more dependencies to install. I’ll update the post.

The freeze on exit is likely that’s fixed in Mir release 0.31.2, so you can avoid it with:

$ sudo apt-add-repository ppa:mir-team/release
$ sudo apt update
$ sudo apt upgrade

You can also use the latest Mir development version (ppa/:mir-team/dev), where a lot of other improvements are being prepared.


videoh with launcher

to screencast

mirscreencast --stdout -m /run/user/1000/egmde_socket -s 1920 1080 --cap-interval 2 | ffmpeg -f rawvideo -pix_fmt bgra -s 1920x1080 -r 30 -i - -c:v libx264 -preset ultrafast -f matroska cast_full.mkv

not sure why it’s not recording them mouse cursor

To get cursor recorded you need to add “–cursor software” when starting egmde, but that was broken on bionic until very recently. (It is fixed in mir-team/dev)

1 Like

I have an Intel based laptop running Ubuntu Core 16. Is it possible to build this into a snap so I can “snap install” it and spin up a graphical environment there?

Yes, it should be possible, and something I was considering for a later article.

However, it’s a year since I worked with snaps and it used to be that the app toolkits were very confused by the unusual locations of files.

@greyback any thoughts on how feasible this is? Or pointers?


@alan_g that should be quite possible, I’d start off with the mir-kiosk snapcraft:

1 Like

The correct install command for Fedora is the following:

$ sudo dnf install gcc-c++ cmake mir-devel freetype-devel qt5-qtwayland boost-devel
1 Like

Thanks, fixed. One day I’ll cut & paste the from the right place.)

yay! --cursor software + the mir dev seems to work

kate is a acting a bit weird 1:23

Sadly, at the moment, kate and other Qt applications don’t always work perfectly with Mir’s Wayland support.

In those cases I’ve checked the same happens when forcing them to use Gnome’s Wayland support too. Login using Gnome/Wayland and start kate with:

    $ QT_QPA_PLATFORM=wayland kate

It is on my list to investigate further and file bugs as appropriate.

1 Like

Which ubuntu core image did you use to install it on a pc? I want to do the same thing on an old netbook

I just grabbed the latest core x86_64 image. I copied the file, uncompressed onto a USB stick and then booted the computer off a different live USB stick. I plugged in the non-live stick containing the core image, and used ddrescue to splat the image over the internal hard disk. Reboot, done.

1 Like