Egmde: A touch of touch support

Introduction

A couple of conversations yesterday got me thinking about touch support for egmde. The “launcher” already supported touch to the extent that the selected app could be launched by touching the middle of the screen or changed by touching above or below. But there was no touch based way of invoking the launcher.

This was fairly simple to add: This article covers adding a “swipe from left” gesture to bring up the launcher and a “swipe to left” to dismiss it.

The egmde snap

The functionality described here is already available from the “edge” egmde snap (which also uses the current Mir “release candidate”):

snap install --edge --classic egmde

This will install egmde and a “.desktop” file that enables it as an option in the greeter.

The rest of the article describes the code needed for this and building that code.

Preparation

The code in this article needs Mir. The version in the Ubuntu 18.04 archive is adequate (and also the version in Fedora) but I recommend using the latest Mir release from the mir-team/release PPA.

On Ubuntu use:

$ sudo apt-add-repository --update ppa:mir-team/release
$ 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

The full code for this example is available on github:

$ git clone https://github.com/AlanGriffiths/egmde.git
$ git checkout article-5

Naturally, the code is likely to evolve, so you will find other branches, but this branch goes with this article.

Invoking the launcher

I added a “lambda” in main() (egmde.cpp) that looks for a swipe from the left and invokes the launcher, most of the code is ignoring “uninteresting” events. Probably the only non-obvious point is that once the gesture has started we continue to “use” events until the gesture ends (that is necessary in server input event handling to avoid clients getting incomplete gestures):

    auto touch_shortcuts = [&, gesture = false](MirEvent const* event) mutable
    {
            if (mir_event_get_type(event) != mir_event_type_input)
                return false;

            auto const* input_event = mir_event_get_input_event(event);
            if (mir_input_event_get_type(input_event) != mir_input_event_type_touch)
                return false;

            auto const* tev = mir_input_event_get_touch_event(input_event);

            if (gesture)
            {
                if (mir_touch_event_action(tev, 0) == mir_touch_action_up)
                    gesture = false;
                return true;
            }

            if (mir_touch_event_point_count(tev) != 1)
                return false;

            if (mir_touch_event_action(tev, 0) != mir_touch_action_down)
                return false;

            if (mir_touch_event_axis_value(tev, 0, mir_touch_axis_x) >= 5)
                return false;

            launcher.show();
            gesture = true;
            return true;
        };

And further down main() we add this to the “runner.run_with()” list:

            AppendEventFilter{touch_shortcuts},

Dismissing the launcher

We also need a way to dismiss the launcher without selecting an application. That is also a few lines of code, this time in eglauncher.cpp:

        if (mir_touch_event_axis_value(event, 0, mir_touch_axis_x) < 5)
        {
            std::lock_guard<decltype(mutex)> lock{mutex};
            stopping = true;
            cv.notify_one();
            return;
        }

Here’s where it is added:

void egmde::Launcher::Self::handle_touch(MirTouchEvent const* event)
{
    auto const count = mir_touch_event_point_count(event);

    if (count == 1 && mir_touch_event_action(event, 0) == mir_touch_action_up)
    {
        if (mir_touch_event_axis_value(event, 0, mir_touch_axis_x) < 5)
        {
            std::lock_guard<decltype(mutex)> lock{mutex};
            stopping = true;
            cv.notify_one();
            return;
        }

        auto const y = mir_touch_event_axis_value(event, 0, mir_touch_axis_y);

        std::lock_guard<decltype(mutex)> lock{mutex};
        if (y < height/3)
            prev_app();
        else if (y > (2*height)/3)
            next_app();
        else
            run_app();
    }
}

Building the code

Assuming that you’ve MirAL installed as described above you can now build egmde as follows:

$ mkdir egmde/build
$ cd egmde/build
$ cmake …
$ make
$ sudo make install

This will install egmde and a “.desktop” file that enables it as an option in the greeter.

2 Likes