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

snap 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

Weston

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:

Is the code dead? Is the function only being called from other X11-specific sections of code? If so, treat the function as X11-specific (see next section) Is the feature it’s a part of actually providing value to users 2019? Is there an alternative method that uses portable GTK code? Does the app still make sense without the feature the code provides? If so, make the feature X11-only (see next section) 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

at the top Put all X11 includes (including gdk/gdkx.h) behind #ifdef HAVE_X11 s

s Put all X11-specific globals and struct members behind #ifdef HAVE_X11 s

s Put all X11-specific functions and definitions behind #ifdef HAVE_X11 s

s 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

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:

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

Use a GdkMonitor if possible