Aus Linux-Magazin 01/2017

GTK+-Anwendungen unter Wayland

© Maksim Kostenko, 123RF

Dass X11 abgewählt ist und alle Linux-Welt ins Wayland oder nach Mir aufbricht, kann an GTK+- und somit Gnome-Anwendungen nicht spurlos vorbeigehen. Der folgende Umsteiger-Leifaden eines GTK+-Maintainers zeigt den Weg, eigene oder fremde Programme fit für Wayland und Xwayland zu machen.

In Fedora Workstation, Version 25, hat der Displayserver Wayland schon X11 ersetzt, auch andere Distributionen stehen an dieser Schwelle oder haben sie schon überschritten. Den meisten GTK+-APIs ist es glücklicherweise gleichgültig, welchen Displayserver die darunterliegende Plattform benutzt. Viele GTK-Anwendungen brauchen daher keine oder nur kleine Änderungen, um mit Wayland genauso gut zu funktionieren wie mit X11. Doch es gibt Ausnahmen, bei denen der Code innige Beziehungen zu Portierungs-problematischen X11-APIs pflegt.

Die Anfänge von GTK gehen in die Mitte der 90er Jahre zurück. Damals war X11 das einzige Backend von Belang. So war es nur natürlich, dass viele X11-spezifischen Konzepte ihren Weg auch ins GTK+-API gefunden haben: Visual, Screen, Rootwindow, Windowmanager, Grab und so weiter. Viele davon waren wichtig zu einer Zeit, in der Grafikkarten nur 256 Farben gleichzeitig darstellten und Videospeicher in Kilo- und nicht in Gigabyte zu beziffern war.

Das Wayland-Protokoll (und auch Mir) werfen viele dieser historischen Spezialitäten über Bord und sind von daher in vielerlei Hinsicht einfacher als X11. Aus dem gleichen Grunde lassen sich manche GTK+-APIs unter Wayland leider nicht implementieren: Wenn das Displaysystem keine Grabs kennt, dann kann das Toolkit sie höchstens mehr schlecht als recht simulieren.

Die aktuelle Entwicklungsversion von GTK+, die auf GTK+ 4 zuläuft, ersetzt bereits viele der X11-nahen APIs durch Wayland-kompatible. In der momentan stabilen GTK+-Version 3.22 müssen die Anwendungsentwickler dagegen darauf achten, problematische APIs zu vermeiden. Dieser Artikel will auch dabei behilflich sein.

Erkennungsdienst

Der erste Schritt beim Portieren einer GTK+-Anwendung nach Wayland ist es, Backend-spezifische Aufrufe zu finden und sie nur dann weiterhin zu nutzen, wenn der ausführende Host das zuständige Backend verwendet. Ein offensichtliches Beispiel sind die »gdk_x11_…()«-APIs, die explizit für X11 gedacht sind. Ein weiteres Beispiel sind »GtkPlug« und »GtkSocket« (die ein Widget in einen anderen Prozess einbinden, [1]); sie verwenden das nur X11 eigene XEmbed-Protokoll [2].

Listing 1 zeigt eine bequeme Möglichkeit auf, das verwendete Backend herauszufinden, indem es den Typ des »GdkDisplay«-Objekts testet. Da GTK+ auf den einzelnen Zielplattformen mit verschiedenen Backends konfiguriert sein kann, ist es ratsam, auch einen »ifdef«-Test auf das Backend auszuführen, wie es im Listing geschieht. Der Test hilft sicherzustellen, dass die Anwendung immer kompiliert, auch wenn die lokale GTK+-Installation nicht alle Backends unterstützt. GTK+ definiert zu diesem Zweck ein »GDK_WINDOWING_…«-Symbol für jedes verfügbare Backend.

Listing 1

Plattform-Erkennung in GTK+

01 #include <gtk/gtk.h>
02 #ifdef GDK_WINDOWING_X11
03 #include <gdk/gdkx.h>
04 #endif
05 #ifdef GDK_WINDOWING_WAYLAND
06 #include <gdk/gdkwayland.h>
07 #endif
08
09 int main (int argc, char *argv[])
10 {
11   GdkDisplay *display;
12
13   gtk_init (&argc, &argv);
14
15   display = gdk_display_get_default ();
16
17 #ifdef GDK_WINDOWING_X11
18   if (GDK_IS_X11_DISPLAY (display))
19     {
20       g_print ("This code is running under X11");
21     }
22 #endif
23 #ifdef GDK_WINDOWING_WAYLAND
24   if (GDK_IS_WAYLAND_DISPLAY (display))
25     {
26       g_print ("This code is running under Wayland");
27     }
28 #endif
29
30   return 0;
31 }

Zeit stempeln

GTK+ macht es einfach, in Anwendungen Backend-spezifischen Code zu finden. Da diese Aufrufe nicht in »gtk.h« deklariert sind, sondern in den separaten Headerdateien »gdkx.h« und »gtkx.h«, kann der Entwickler einfach nach allen Dateien suchen, die diesen Header verwenden, um problematische Codebestandteile einzukreisen.

Ein typisches Beispiel für X11-spezifischen Code ist der Aufruf von »gtk_window_present_with_time()«[3] mit einem Zeitstempel, der vom X-Server stammt – siehe Listing 2. Der alternative Code in Listing 3 veranlasst einen Type-Check mit dem »GtkWindow«-Objekt und repariert so die Abhängigkeit.

Listing 2

X11-spezifischer Code …

01 static void
02 present_window (GtkWidget *window)
03 {
04   guint32 timestamp;
05
06   timestamp = gdk_x11_get_server_time (gtk_widget_get_window (window));
07   gtk_window_present_with_time (GTK_WINDOW (window), timestamp);
08 }

Listing 3

… nach Wayland portiert

01 static void
02 present_window (GtkWidget *window)
03 {
04 #ifdef GDK_WINDOWING_X11
05   if (GDK_IS_X11_WINDOW (window))
06     {
07       guint32 timestamp;
08
09       timestamp = gdk_x11_get_server_time (gtk_widget_get_window (window));
10       gtk_window_present_with_time (GTK_WINDOW (window), timestamp);
11     }
12   else
13 #endif
14     gtk_window_present (GTK_WINDOW (window));
15 }

Mitspracherecht bei der Backend-Auswahl

GTK+ erlaubt es dem Entwickler und auch dem User, zu beeinflussen, welches der auf der Zielplattform lauffähigen Backends GTK+ benutzen soll. Wenn nun eine Anwendung nicht für Wayland vorbereitet ist, kann der Entwickler mit dem Eintrag

gdk_set_allowed_backends ("x11");

GTK+ mitteilen, dafür nur X11 zu verwenden [4]. Trifft die Anwendung auf eine Wayland-Session, kümmert sich das System darum, sie unter dem Xwayland-X-Server auszuführen. Für den Anwender eines solchen Systems bedeutet das keinen großen Unterschied.

Der Benutzer seinerseits kann die »GDK_BACKEND«-Umgebungsvariable setzen [5], um die normale Auswahl des Backends zu überschreiben. So zwingt

GDK_BACKEND=x11 some-app

die Anwendung, das X11-Backend zu verwenden, auch wenn das Wayland-Backend bestens funktionieren würde. Als kleines Extra kann der Anwender »GDK_BACKEND=help« setzen, um herauszufinden, welche Backends die installierte GTK+-Version unterstützt.

Überhaupt ist es für Bediener einfach, zur Laufzeit herauszufinden, welches Backend gerade in Benutzung ist: Der GTK+ Inspektor [6], der sich mit der Tastenkombination [Ctrl]+[Shift]+[I] öffnet, zeigt diese Information an (siehe Abbildung 1).

Abbildung 1: GTK+ Inspektor zeigt das benutzte Backend an.

Abbildung 1: GTK+ Inspektor zeigt das benutzte Backend an.

Ein Zoo voller Anwendungen

Unter X11 haben Applikationsentwickler viel Kreativität gezeigt, um nicht einfach nur normale Anwendungen zu schreiben. Da gibt es Applets, Desklets, Widgets und einen ganzen Zoo anderer Spezialitäten. Selbst unter einem nativen X11 funktionieren manche dieser Arten oft nur mit bestimmten Windowmanagern.

Für Wayland ist es im Allgemeinen einfach nicht möglich, dies alles zu implementieren. Das Wayland-Protokoll isoliert Anwendungen (und ihre Fenster) nämlich voneinander und Anwendungen dürfen ihre Fenster nicht selbst in einem globalen Koordinatensystem positionieren. Es ist weiterhin unmöglich, Fenster in andere Anwendungen einzubetten, weswegen »GtkPlug« und »GtkSocket« (wie erwähnt) und »GtkStatusIcon« unter Wayland nicht funktionieren. Von daher darf als Devise für Wayland-kompatible Anwendungen gelten: Es sollte ein normales Fenster sein.

Fenster: Positionen und Dekorationen

Wenn die präzise Positionierung von Fenstern ein essenzieller Bestandteil einer Applikation ist (ein Beispiel wäre etwa ein Drop-down-Terminal), dann muss man die Anwendung vielleicht als X11-spezifisch betrachten. Wayland behandelt solche Spezialfälle typischerweise mit Zusatzprotokollen, was natürlich den Nachteil hat, dass die Anwendung dann nur mit solchen Wayland-Servern funktioniert, die das entsprechende Protokoll beherrschen.

Der beste Rat, was Fensterpositionen unter Wayland angeht, ist daher: Anwendungen sollten sich nicht darum kümmern, Fensterpositionen gehören unter der Kontrolle des Benutzers und des Wayland-Servers.

Im Gegensatz zu X11 sind Anwendungen unter Wayland selbst dafür verantwortlich, ihre Fensterdekorationen zu zeichnen. Dieser Unterschied zwischen X11 und Wayland ist kontrovers und hat zu hitzigen Diskussionen geführt. In der Praxis bereitet er aber wenig Probleme, GTK+ und andere Tookits kümmern sich um das Aussehen der Fenster.

Eine Stelle, an der Anwendungsentwickler diesen Unterschied aber beachten müssen, ist das Zeichnen direkt auf dem Fenster. Wer hierbei nicht vorsichtig ist (Listing 4), dem kann es passieren, dass der Fensterinhalt die Dekorationen übermalt (Abbildung 2). Um diesem Problem nachhaltig zu begegnen, ist es am besten, wenn die eigenen Anwendungen alle grafischen Konstrukte auf einem anderen Widget malen, beispielsweise auf einer »GtkDrawingArea«[7], und nicht auf dem Fenster selbst (Listing 5).

Abbildung 2: Links: Die Anwendung malt fatalerweise direkt auf dem Fenster. Rechts: Die gleiche Anwendung benutzt das <code>GtkDrawingArea</code>-Widget und kann keine Fensterdekoration zerst&ouml;ren.

Abbildung 2: Links: Die Anwendung malt fatalerweise direkt auf dem Fenster. Rechts: Die gleiche Anwendung benutzt das »GtkDrawingArea«-Widget und kann keine Fensterdekoration zerstören.

Listing 4

Direktes Malen auf dem Fenster

01 static gboolean
02 on_draw (GtkWidget *widget,
03          cairo_t   *cr)
04 {
05   /* draw something here */
06   return FALSE;
07 }
08
09 int main (int argc, char *argv[])
10 {
11   GtkWidget *window;
12
13   gtk_init (&argc, &argv);
14
15   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
16   gtk_window_set_default_size (GTK_WINDOW (window), 300, 300);
17   g_signal_connect (window, "draw", G_CALLBACK (on_draw), NULL);
18
19   gtk_widget_show_all (window);
20   gtk_main ();
21
22   return 0;
23 }

Listing 5

Malen per GtkDrawingArea

01 static gboolean
02 on_draw (GtkWidget *widget,
03          cairo_t   *cr)
04 {
05   /* draw something here */
06   return FALSE;
07 }
08
09 int main (int argc, char *argv[])
10 {
11   GtkWidget *window, *da;
12
13   gtk_init (&argc, &argv);
14
15   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
16   gtk_window_set_default_size (GTK_WINDOW (window), 300, 300);
17   da = gtk_drawing_area_new ();
18   gtk_container_add (GTK_CONTAINER (window), da);
19   g_signal_connect (da, "draw", G_CALLBACK (on_draw), NULL);
20
21   gtk_widget_show_all (window);
22   gtk_main ();
23
24   return 0;
25 }

Behandlung von Events

Die Event-Struktur in GTK+ (»GdkEvent«, »GdkEventAny«, »GdkEventKey«, … [8]) weist Felder für globale Koordinaten auf. Da Wayland sich aber diese Koordinaten nicht besorgen kann, bekommt GTK+ die Felder nicht mit vernünftigen Werten gefüllt – auch der Entwickler sollte sie besser ignorieren.

Außerdem sollten Anwendungen es vermeiden, Device-Positionen oder Device-Status (von Zeigegeräten, Zweittastaturen und so weiter) abzufragen, da Wayland diese Information ebenfalls nicht bereitstellt, wenn der Benutzer nicht gerade zufällig das Device über dem Fenster positioniert hat. Im Einzelnen betrifft diese Warnung die Funktionen:

  • »gdk_device_get_state()«
  • »gdk_device_get_position()«
  • »gdk_device_get_position_double()«
  • »gdk_device_get_window_at_position()«

Normalerweise sollte es aber auch nicht nötig sein, die systemweite Device-Position zu ermitteln, da bereits Events die aktuelle Device-Position und den Device-Status enthalten.

Fazit

Für die Programmierer und Betreuer vorhandener GTK+-Anwendungen hält dieser Artikel eine gute Nachricht bereit: Das Desktop-Framework in der aktuellen Version 3.22 unterstützt Wayland schon recht gut – viele neuere GTK+-Anwendungen funktionieren einfach wie gewohnt weiter. Ist das nicht der Fall, dann sind die problematischen Codeabschnitte leicht zu finden und die nötigen Änderungen im Allgemeinen einfach durchzuführen – dieser Artikel hat einen Leitfaden dafür gesponnen.

Noch bessere Nachrichten hält die Zukunft bereit: GTK+ 4 wird viele der X11-spezifischen APIs von Haus aus durch Wayland-kompatible ersetzen und damit die Anwendungsmigration zum Kinderspiel machen.

Der Autor

Matthias Clasen arbeitet als Manager im Desktop Team von Red Hat und lebt mit seiner Familie in Massachusetts. Er ist als Mitglied im Gnome Release Team tätig und bei Red Hat der Maintainer von GTK+.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 4 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Nach oben