Porting MATE Apps to Wayland

As some of you may know, the Mir team and the MATE Desktop team have been working together for some time to bring MATE to Wayland with Mir. We’ve demonstrated a proof of concept (which you can try with the mate-wayland snap), but there’s still considerable work to be done before we have a MATE session suitable for daily use.

One of the largest pieces of work is arguably the simplest: porting the normal applications. The functionality of Caja, MATE Terminal, Pluma, etc should all be possible using only portable GTK3 code. Unfortunately, they have been implemented using X11-specific functionality which now needs to be removed or at least made optional. This is a large amount of work only due to the number of applications and the volume of code that needs to be looked at. This document is a technical guide for whoever is doing that work.

Setting up

Development environment

Since you don’t need support for any fancy protocols, any modern Wayland compositor will do. Good options include:

  • Mir via the mate-wayland snap
    • $ sudo snap install --classic --edge mate-wayland
    • $ mate-wayland.mirco (Just plain $ mate-wayland will try to spin up a panel and background)
    • You can run it from a TTY, or nested inside your normal session
  • Sway
    • You’ve got to figure out how to get it or build it on your distro
    • Can also be run either from a TTY or nested
  • GNOME-on-Wayland
    • If you’re already running GNOME, may be easiest to get
    • Can’t run nested, so only use if you’re using or willing to switch to using Wayland for your standard session
    • EDIT: Mutter (the compositor) can run nested with mutter --nested --wayland --no-x11. Thanks to Reddit user jadahl for pointing this out
  • NOT Weston
    • The version shipped by most distros still doesn’t support XDG Shell stable

Running apps in Wayland

The MATE Wayland snap uses wayland-mate for its Wayland display. Other compositors (including other Mir-based compositors) generally use wayland-0. To launch an app in a compositor simply run something like $ WAYLAND_DISPLAY=wayland-mate lxterminal.

If a GTK3 app completely refuses to run on Wayland, it may be because gdk_set_allowed_backends ("x11") is being called. Comment it out for now.

configure.​ac

If backend-specific code is required for an app, both X11 and Wayland should be able to be enabled or disabled at build time. Add --enable-wayland and --enable-x11 options that work independently. See the MATE Panel configure.ac for an example. The configure.​ac should define HAVE_X11 and HAVE_WAYLAND macros that are used in the code.

Set allowed backends

If all backend-specific calls can be removed from an app,
gdk_set_allowed_backends () does not need to be called. Otherwise, do something like this in initialization:

#if defined(HAVE_X11) && defined(HAVE_WAYLAND)
    gdk_set_allowed_backends ("wayland,x11");
#elif defined(HAVE_WAYLAND)
    gdk_set_allowed_backends ("wayland");
#else
    gdk_set_allowed_backends ("x11");
#endif

Removing X11-specific code

How did we get here?

From what I know, there are a number of reasons X11 is being used directly. Some of them include:

  • Legacy code has not been ported to modern GTK3
  • X11 functions have been used indiscriminately to fix minor issues
  • In some places GTK does not provide a portable way to implement desired features (for example, the desktop background)

Try the easy options first

It’s useful to ask the following questions when encountering X11-specific code:

  1. Is the code dead?
  2. Is the function only being called from other X11-specific sections of code?
    • If so, treat the function as X11-specific (see next section)
  3. Is the feature it’s a part of actually providing value to users 2019?
  4. Is there an alternative method that uses portable GTK code?
  5. Does the app still make sense without the feature the code provides?
    • If so, make the feature X11-only (see next section)
  6. Is this a critical part of a really important feature with no portable alternative?
    • This is when we may need to use Wayland-specific code and/or a protocol extension GTK doesn’t support

Making code X11-only

Ideally as much functionality as possible should be portable. There are, however, some cases where you need different behavior between X11 and Wayland. To make some code in a file X11-only, follow the following steps:

  • Make sure the file includes config.h at the top
  • Put all X11 includes (including gdk/gdkx.h) behind #ifdef HAVE_X11s
  • Put all X11-specific globals and struct members behind #ifdef HAVE_X11s
  • Put all X11-specific functions and definitions behind #ifdef HAVE_X11s
  • Put all calls from portable functions into X11-specific functions behind both #ifdef HAVE_X11 and if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) checks
  • To provide a fallback, put an else after the if block just before the #endif // HAVE_X11, and add the fallback in a following block. For example:
#ifdef HAVE_X11
    if (GDK_IS_X11_DISPLAY (gdk_display_get_default ()))
    {
        // X11 code
    }
    else
#endif // HAVE_X11
    { // Not using X11
        // Fallback code
    }

To make entire files X11-only:

  • Put this at the top of source files
#ifdef PACKAGE_NAME // only check HAVE_X11 if config.h has been included
#ifndef HAVE_X11
#error file should only be included when HAVE_X11 is enabled
#endif
#endif
  • Put this at the top of header files
#ifndef HAVE_X11
#error file should only be built when HAVE_X11 is enabled
#endif
  • Hide file behind a Makefile.​am if like so

GdkScreen

GdkScreen is going away in GTK4, and it’s generally not needed in modern GTK3. A GdkScreen does not represent a physical monitor/output (that’s what GdkMonitor is for). Instead it represents the strange and deprecated concept of an X11 screen (which conceptually sits between GdkMonitor and GdkDisplay). As of GTK 3.10, There is always exactly one screen per display and we don’t attempt to support multiple displays. MATE apps support 3.22 and up so we can assume all multi-screen logic is legacy and should be removed. gdk_x11_screen_get_screen_number () can be assumed to always return 0. A more complete explanation of display vs screen vs monitor can be found here, and an example of a PR removing multi-screen logic is here.

What this means is that storing or passing around a GdkScreen is generally not useful. It doesn’t need to be completely removed yet, but it is being phased out. This is relevant to porting to Wayland because when GdkScreen functions were deprecated and removed, MATE often jumped to X11-specific alternatives instead of refactoring properly.

There is a particular liking of the WidthOfScreen (gdk_x11_screen_get_xscreen (screen) pattern. Unfortunately there is no single drop-in replacement for this logic. The screen size is not available on Wayland because Wayland doesn’t guarantee compositors place windows in a 2D area of a fixed size. Generally, the steps to resolve instances of this pattern are:

  1. Check that it’s actually needed on Wayland
  • If it’s already behind an X11 check, leave it as-is
  • If it’s in a function that’s only called from inside an X11 check, make the function X11-only
  1. Use a GdkMonitor if possible
5 Likes

Sway is in Eoan!

Not sure about this wayland craziness. Wayland is stlll a alpha stage product. That’s why Ubuntu’s default session is xorg and gtk4 hasn’t released yet. Without gdkscreen mate-panel (and most other apps I have seen trying to be wayland compatible) now complains “no default display found”? Though it works.

When I try to run nested mate-wayland.mirco it flashes up a black window that immediately disappears, and I see this on the terminal:

al@al-desktop:~$ mate-wayland.mirco
[2019-09-21 21:00:22.940472] <information> mirserver: Starting
[2019-09-21 21:00:22.940618] < - debug - > mirserver: Not trying logind: "DISPLAY" is set and X need not have claimed the VT
[2019-09-21 21:00:22.940782] < - debug - > mirserver: Not using Linux VT subsystem for session management: Failed to open current VT
[2019-09-21 21:00:22.940806] < - debug - > mirserver: No session management supported
[2019-09-21 21:00:22.940827] <information> VT switch key handler: No VT switching support available: MinimalConsoleServices does not support VT switching
[2019-09-21 21:00:22.941001] <information> mircommon: Loading modules from: /snap/mate-wayland/242/usr/lib/x86_64-linux-gnu/mir/server-platform
[2019-09-21 21:00:22.941041] <information> mircommon: Loading module: /snap/mate-wayland/242/usr/lib/x86_64-linux-gnu/mir/server-platform/graphics-mesa-kms.so.16
[2019-09-21 21:00:22.941057] <information> mircommon: Loading module: /snap/mate-wayland/242/usr/lib/x86_64-linux-gnu/mir/server-platform/server-mesa-x11.so.16
[2019-09-21 21:00:22.941069] <information> mircommon: Loading module: /snap/mate-wayland/242/usr/lib/x86_64-linux-gnu/mir/server-platform/input-evdev.so.7
[2019-09-21 21:00:22.944614] <information> mesa-kms: EGL platform does not support EGL_KHR_platform_gbm extension
[2019-09-21 21:00:22.944839] <information> mesa-kms: Device /dev/dri/card0 does not support KMS
[2019-09-21 21:00:22.944867] <information> mirplatform: Found graphics driver: mir:mesa-kms (version 1.3.0) Support priority: 0
[2019-09-21 21:00:22.945638] <information> mirplatform: Found graphics driver: mir:mesa-x11 (version 1.3.0) Support priority: 128
[2019-09-21 21:00:22.945757] <information> mirserver: Selected driver: mir:mesa-x11 (version 1.3.0)
libEGL warning: DRI2: failed to authenticate
[2019-09-21 21:00:22.985887] <information> display: Screen resolution = 4480x1200
[2019-09-21 21:00:22.985913] <information> display: 1 visual(s) found
[2019-09-21 21:00:22.985918] <information> display: Using the first one :
[2019-09-21 21:00:22.985922] <information> display: ID		:	33
[2019-09-21 21:00:22.985926] <information> display: screen	:	0
[2019-09-21 21:00:22.985930] <information> display: depth		:	24
[2019-09-21 21:00:22.985934] <information> display: red_mask	:	0xFF0000
[2019-09-21 21:00:22.985940] <information> display: green_mask	:	0xFF00
[2019-09-21 21:00:22.985944] <information> display: blue_mask	:	0xFF
[2019-09-21 21:00:22.985949] <information> display: colormap_size	:	256
[2019-09-21 21:00:22.985953] <information> display: bits_per_rgb	:	11
[2019-09-21 21:00:22.999900] <information> mirserver: Using software cursor
mirco: ../src/egl/main/eglapi.c:2195: eglBindWaylandDisplayWL: Assertion `disp->Extensions.WL_bind_wayland_display' failed.

Over in Xfce we’ve already ported all the apps to Gtk3 and removed as much of the deprecated stuff as we can. There might be some left, as testing on Wayland is not a priority. We need guidance on porting the desktop components like xfdesktop, xfce4-panel (needs libwnck, struts, GdkScreen, absolute positioning), display settings (needs XRandR) etc. And then there is stuff like xfce4-screenshooter.

1 Like

I can’t tell exactly why from the logs, but the EGL errors suggest a compatibility problem with your graphics drivers. What is the system where you see this?

Ubuntu 18.04 with nvidia-435.21

Thanks! That tells me enough.

There are problems creating snaps for Nvidia graphics and you’ve encountered the effect (it is something there are plans to fix).

Mir based servers will work with Nvidia, but, for now, they need to be installed with .debs. Building mirco is a bit more elaborate, but here’s a start:

sudo apt-add-repository ppa:mir-team/release
sudo apt install mir-demos mir-graphics-drivers-nvidia
miral-shell

(Forgive any autocorrect errors my phone inflicted - I caught most of them)

[Edit]

Correction: the notes above are sufficient to run Mir on a VT on the Nvidia drivers. However, running Mir-on-X on the desktop won’t be fixed by them.