opensuse Leap 15.6 KDE Wayland - Programmierung

#7997873
Lesenswert?
• ▲
▼

Josef G. schrieb:

Hat jemand eine Idee für Abhilfe?

Irgendwo geht die Information zu Wayland verloren.

Teste "echo $WAYLAND_DISPLAY" an der Konsole. Wenn das nix ausgibt, hast du an der Stelle kein Wayland.

Ansonsten enthält "$WAYLAND_DISPLAY" den Namen eines Sockets im "$XDG_RUNTIME_DIR" (also z.B. /run/user/1000/wayland-0). Diese Datei muss für dein Programm auch erreichbar und benutzbar sein.

Wenn diese Environment-Variablen nicht gesetzt sind, könntest du den Pfad zum Socket auch als Parameter zu wl_display_connect angeben, ist aber meist eine schlechte Idee.

Environment-Variablen vererben sich nicht (automatisch) durch sudo, su, docker-container usw.

OP Persönliche Seite #7997976
Lesenswert?
• ▲
▼

Εrnst B. schrieb:

Teste "echo $WAYLAND_DISPLAY" an der Konsole. Wenn das nix ausgibt, hast du an der Stelle kein Wayland.

Hat nichts ausgegeben, obwohl ich bei der Anmeldung (erstmals) Wayland ausgewählt hatte. Habe mich jetzt nochmal abgemeldet und wieder angemeldet. Jetzt klappt es. "echo $WAYLAND_DISPLAY" liefert jetzt "wayland-0" und das Programm "Connection established!".

Allerdings wird jetzt immer wieder mal der Bildschirm etwa eine Sekunde lang schwarz. Aber erst mal Danke. Werde vermutlich noch weitere Fragen haben.

OP Persönliche Seite #7999418
Lesenswert?
• ▲
▼

Habe den Code etwas umgeschrieben und erweitert:

1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <wayland-client.h>
4
#include <wayland-egl.h>
5

6
int main(){ struct wl_display *display;
7
            struct wl_surface *surface;
8
            struct wl_egl_window *egl_window;
9

10
    display = wl_display_connect(NULL);
11
    if (!display) { printf("Failed\n"); return(0);}
12

13
    egl_window = wl_egl_window_create(surface,480,360);
14
    wl_egl_window_destroy(egl_window);
15

16
    wl_display_disconnect(display);
17
    return(0);}

Versuch zu Compilieren mittels

1
gcc -o wltest wltest.c -lwayland-client

liefert die Fehlermeldungen

undefined reference to wl_egl_window_create' undefined reference to wl_egl_window_destroy'

Weiss jemand warum? Was fehlt in der #include-Liste?

OP Persönliche Seite #8096791
Lesenswert?
• ▲
▼

!!! Weitere Frage nach längerer Pause !!!

Habe diesen Beispielcode gefunden:

https://bugaevc.gitbooks.io/writing-wayland-clients/content/black-square/the-complete-code.html

Der Code lässt sich compilieren mit

1
gcc -o square square.c -lwayland-client

Starten mit ./square führt zu Abbruch mit Speicherzugriffsfehler.

Bei sukzessivem Löschen einzelner Anweisungen vom Ende her verschwindet der Fehler nach Löschen von Zeile 56:

1
struct wl_shell_surface *shell_surface = wl_shell_get_shell_surface(shell, surface);

Hat jemand eine Idee, woran es liegen könnte?

: Bearbeitet durch User
#8096802
Lesenswert?
• ▲
▼

Josef G. schrieb:

Hat jemand eine Idee, woran es liegen könnte?

"wl_shell_*" war ursprünglich nur als simple Test-Option gedacht, wurde nie von allen Compositors unterstützt, ist vor vielen Jahren aus KDE rausgeflogen.

Entweder du nimmst einen alten Weston, oder passt den Code an, "xdg_shell" statt "wl_shell".

https://wayland.app/protocols/wayland#wl_shell

Note! This protocol is deprecated and not intended for production use. For desktop-style user interfaces, use xdg_shell. Compositors and clients should not implement this interface.

sh. Anhang.

Angehängte Dateien:
OP Persönliche Seite #8106930
Lesenswert?
• ▲
▼

Mit Leap 15.6 bin ich nicht weitergekommen. Mit Tumbleweed/Gnome hat nun alles geklappt. Habe dann das Programm erweitert und eine eigene Grafik in den Datenbuffer geschrieben und ausgegeben. Zum Ausgeben habe ich verwendet:

1
   wl_surface_damage(surface,0,0,4096,512);
2
   wl_surface_commit(surface);
3
   wl_display_dispatch(display);

Auch das hat geklappt. Ich wollte nun Zeichen von der Tastatur einlesen und die Grafik modifizieren. An Wayland-Keyboard-Events habe ich mich bisher nicht herangetraut. Stattdessen habe ich bei geöffneter Grafik das Konsolenfenster in den Vordergrund geholt und ncurses verwndet.

Das funktioniert ansatzweise. Ich kann ein oder zwei Zeichen einlesen und die Grafik modifizieren, dann hängt das Programm. Wenn man den Mauszeiger in das Grafikfenster bewegt, erscheint nach ein paar Sekunden eine Meldung, dass das Fenster nicht antwortet, und es wird angeboten, das Fenster zwangsweise zu schließen.

Kann mein Ansatz, die Tastatur mittels ncurses einzulesen, überhaupt funktionieren, und wenn ja, was kann ich tun, um das Hängen des Programms zu vermeiden?

: Bearbeitet durch User
#8106958
Lesenswert?
• ▲
▼

Josef G. schrieb:

Das funktioniert ansatzweise. Ich kann ein oder zwei Zeichen einlesen und die Grafik modifizieren, dann hängt das Programm. Wenn man den Mauszeiger in das Grafikfenster bewegt, erscheint nach ein paar Sekunden eine Meldung, dass das Fenster nicht antwortet, und es wird angeboten, das Fenster zwangsweise zu schließen.

Problem, vermutlich:

Du wartest blocking auf eine Taste in ncurses. (getch() & co)

Das geht nicht, deine Wayland-Loop muss durchlaufen, (also wl_display_dispatch regelmäßig aufgerufen werden). Du kannst nicht zwischendurch pausieren bis eine Taste gedrückt wird.

Kann mein Ansatz, die Tastatur mittels ncurses einzulesen, überhaupt funktionieren,

Ja

und wenn ja, was kann ich tun, um das Hängen des Programms zu vermeiden?

Nonblocking auf die Taste warten (timeout(0); getch() gibt dann ERR zurück, wenn keine Taste gedrückt)

Oder Multithreading, eigener Thread für ncurses. (Overkill, eher weniger für Anfänger)

Ansonsten sind die Keyboard-Events jetzt auch nicht so kompliziert...

1
void keyboard_key_handler
2
(
3
    void *data,
4
    struct wl_keyboard *keyboard,
5
    uint32_t serial,
6
    uint32_t time,
7
    uint32_t key,
8
    uint32_t state
9
) {
10
    if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
11
        printf("key %u pressed\n", key);
12
        paint(something);
13
    }
14
}
15

16
void keyboard_noop() {}
17

18
const struct wl_keyboard_listener keyboard_listener = {
19
    .keymap      = (void *)keyboard_noop,
20
    .enter       = (void *)keyboard_noop,
21
    .leave       = (void *)keyboard_noop,
22
    .key         = keyboard_key_handler,
23
    .modifiers   = (void *)keyboard_noop,
24
    .repeat_info = (void *)keyboard_noop,
25
};

Ansonsten im registry-handler "wl_seat" binden (seat = wl_registry_bind(registry, name, &wl_seat_interface, 1);), und dann

1
    if (seat) {
2
        struct wl_keyboard *keyboard = wl_seat_get_keyboard(seat);
3
        wl_keyboard_add_listener(keyboard, &keyboard_listener, NULL);
4
    }
#8106964
Lesenswert?
• ▲
▼

Hab das mal alles zusammen in eine KI geworfen.

vielleicht kannst du dir was abschauen.

in's compile.sh von oben:

1
gcc -g -o pong pong.c xdg-shell-protocol.c -l wayland-client -lm

die "poll()"-Loop ist vmtl. nicht zwingend nötig, aber praktisch wenn du weitere FDs (Netzwerk-Socket z.B) mit überwachen willst.

Angehängte Dateien:
OP Persönliche Seite #8107259
Lesenswert?
• ▲
▼

Εrnst B. schrieb:

Problem, vermutlich:

Habe jetzt deinen Vorschlag timeout(0) für getch() umgesetzt. Der Code ist bis Zeile 152 initscr() dein unveränderter Code (nur die Integer-Vereinbarung i gleich nach main(void) sowie die Werte für width und height sind neu).

Das Programm soll ein Rechteck ausgeben. Bei den ersten 4 Tastendrücken soll das Rechteck von oben her sukzessive weiss werden. Beim fünften Tastendruck soll das Programm enden.

Das tut es auch. Im Prinzip. Leider reagiert die Grafik aber jeweils erst, wenn man den Mauszeiger über der Grafik bewegt. ???

Angehängte Dateien:
: Bearbeitet durch User
#8107268
Lesenswert?
• ▲
▼

Josef G. schrieb:

Leider reagiert die Grafik aber jeweils erst, wenn man den Mauszeiger über der Grafik bewegt. ???

"wl_display_dispatch(display)" blockiert normalerweise bis ein neues Event vom Compositor kommt.

d.H. statt in getch() hängt dein Programm jetzt dort, wenn du eine Taste im Terminal drückst, läuft das nächste ncurses/getch() trotzdem erst nach dem nächsten Wayland-Event, z.B. einem Mouse-Move.

wl_display_dispatch ist eine Abkürzung für ein flush+dispatch_pending (Pending Events raussenden&verarbeiten), ein Poll mit Timeout infinite auf dem Wayland-Socket, read_events (Neue Events vom Socket lesen), und nochmal dispatch_pending um die gleich zu verarbeiten.

Wenn dein Programm selber Animationen abspielen soll, oder auf externe Ereignisse reagieren muss (Netzwerk, ncurses-getch, ...) kannst du das nicht verwenden.

Stattdessen musst du die Einzelschritte aus dem wl_display_dispatch selber schreiben, also eine eigene Event-Loop aufbauen.

Da kannst du dann entweder mit einem kurzen Timeout im poll arbeiten (sh. das "pong.c"-Beispiel) und/oder auch den STDIN-Filedescriptor mit in das poll aufnehmen.

in etwa:

1
#include <poll.h>   // zusätzlich zu den bestehenden Includes
2

3
...
4

5
// Drop-in-Ersatz für wl_display_dispatch(): verarbeitet Wayland-Events,
6
// kehrt aber auch zurück, sobald auf stdin etwas anliegt (Tastendruck im
7
// Terminal). Gleiche Signatur wie wl_display_dispatch, also einfach den
8
// Namen in den while-Schleifen ersetzen.
9
int dispatch_or_stdin(struct wl_display *display)
10
{
11
    // Falls bereits Events in der lokalen Queue liegen, erst die abarbeiten.
12
    // prepare_read schlaegt in dem Fall fehl (Rueckgabe != 0).
13
    while (wl_display_prepare_read(display) != 0)
14
        wl_display_dispatch_pending(display);
15

16
    // Alle ausstehenden Requests rausschreiben, sonst koennte der Compositor
17
    // auf etwas warten, das wir noch nicht gesendet haben (Deadlock-Gefahr).
18
    wl_display_flush(display);
19

20
    // Auf BEIDE fds warten: Wayland-Socket UND stdin.
21
    struct pollfd fds[2] = {
22
        { .fd = wl_display_get_fd(display), .events = POLLIN },
23
        { .fd = STDIN_FILENO,               .events = POLLIN }
24
    };
25
    poll(fds, 2, -1);   // -1 = blockieren bis irgendein fd bereit ist. Sonst timeout in ms
26

27
    // Wayland-fd bereit -> Events einlesen und verarbeiten.
28
    // Sonst den zuvor "scharf gemachten" read wieder zuruecknehmen.
29
    if (fds[0].revents & POLLIN)
30
        wl_display_read_events(display);
31
    else
32
        wl_display_cancel_read(display);
33

34
    wl_display_dispatch_pending(display);
35

36
    // Rueckgabe wie bei wl_display_dispatch (Anzahl verarbeiteter Events ist
37
    // hier nicht wichtig; die while-Schleifen pruefen nur getch()).
38
    return 0;
39
}
40

41
...
42
while (getch()==ERR) dispatch_or_stdin(display);
#8107272
Lesenswert?
• ▲
▼

Nachtrag:

Kann sein, dass du den Buffer auch jedesmal neu Attachen musst:

1
    wl_surface_attach(surface, buffer, 0, 0);
2
    wl_surface_damage(surface,0,0,2048,256);
3
    wl_surface_commit(surface);

Hängt vom Compositor ab. Ist zwar "Shared Memory", aber der Compositor kann trotzdem eine Kopie davon machen (z.B. als Textur im Grafikspeicher), die die Änderungen dann nicht mitbekommt.

OP Persönliche Seite #8107676
Lesenswert?
• ▲
▼

Mir ist gerade ein grundsätzliches Problem des Verfahrens eingefallen.

Bei meiner Anwendung wird das Grafikfenster 1024 mal 512 Pixel groß sein. Ich hatte geplant, zum Beenden der Grafik die Escape-Taste vorzusehen. Wenn man nun vergisst, vor dem Start der Grafik das Konsolenfenster nach unten zu schieben, kann es im Extremfall dazu kommen, dass das Grafikfenster das Konsolenfenster komplett verdeckt, so dass man das Konsolenfenster nicht in den Vordergrund holen kann. Dann bleibt die Escape-Taste wirkunglos, und man kann die Grafik nicht mehr beenden.

Vielleicht fällt dir auch dazu noch eine Lösung ein. Schön wäre es, das Programm durch einen Klick ins Grafikfenster beenden zu können.

Notfalls werde ich im Event-Loop mittels gettimeofday() das Programm per timeout beenden.

: Bearbeitet durch User
#8107686
Lesenswert?
• ▲
▼

Du kannst doch sicher Fenster per Alt-Tab durchwechseln, und deine Konsole wieder nach vorne holen.

Oder, je nach Window-Manager, das Fenster mit Alt+Maustaste oder Meta+Maustaste oder "Verschieben"-Aktion in der Taskleiste verschieben.

Ansonsten: Trau dich an die Keyboard-Event-Handler. Das "pong.c"-Beispielprogramm von oben beendet sich mit ESC.

Auf Maus-Events (also den Klick) im Programm zu reagieren ist da sehr ähnlich.

Statt

1
        struct wl_keyboard *keyboard = wl_seat_get_keyboard(seat);
2
        wl_keyboard_add_listener(keyboard, &keyboard_listener, NULL);

eben dasselbe mit Suchen&Ersetzen "keyboard" -> "pointer", im pointer_listener deinen Callback für ".button" eintragen (andere/ungenutzte auf No-Op)

1
void my_mouse_button_handler(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
2
               uint32_t time, uint32_t button, uint32_t state) {
3

4
  // button ist die Mausknopf-Nummer, state der Zustand
5
  if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED) {
6
    printf("Mausknopf...
7
}

Hier gibt's was dazu zu lesen:

https://wayland-book.com/seat/example.html

#8109451
Lesenswert?
• ▲
▼

Josef G. schrieb:

Mir ist gerade ein grundsätzliches Problem des Verfahrens eingefallen.

Mir auch. Wayland wird nicht in die Tonne geworfen, hat keine Standardisierung drauf, keine Optimierhintergründe und kann X, obwohl man es loswerden möchte, nicht eben total ersetzen. Ja und sich mit X auseinanderzusetzen, und da mal nach Optimierungen schauen - da hat scheinbar keiner Bock drauf. Und dann auch noch bei Wayland eigene Grafikschnittstellen importieren müssen..[->Zensur<-] Hinsichtlich dessen sollte man lieber Geld sammeln und professionelle Entwickler an den Übergang setzen. Das ist einfach unerträglich bei dieser Community dass da die dümmlichsten Hypes durch die Upgrades und Updates gepeitscht werden.

#8109456
Lesenswert?
• ▲
▼

Ach ja... "Alles was neu ist, muss schlecht sein"...

Rbx schrieb:

Mir auch. Wayland wird nicht in die Tonne geworfen,

Warum sollte man?

hat keine Standardisierung drauf,

Doch, sogar schön gelöst.

keine Optimierhintergründe

Eigentlich "Nur Optimierungshintergründe".

und kann X, obwohl man es loswerden möchte, nicht eben total ersetzen.

Muss es auch nicht, Xwayland existiert.

Ja und sich mit X auseinanderzusetzen, und da mal nach Optimierungen schauen - da hat scheinbar keiner Bock drauf.

Doch, hatten Leute. Die haben dann erstmal mit Xshm, Xcb, composite-extension, usw. versucht was "Wayland-Ähnliches" in den X-Server reinzufrickeln. Als klar wurde, dass das eine Sackgasse wird, parallel mit Wayland angefangen.

Und dann auch noch bei Wayland eigene Grafikschnittstellen importieren müssen..[->Zensur<-]

machen fast alle X11-Programme auch. Wann hast du das letzte Mal X11-Software benutzt, die nur die originalen X11-Primitives verwendet? xterm? xeyes?

Hinsichtlich dessen sollte man lieber Geld sammeln und professionelle Entwickler an den Übergang setzen.

IBM, Intel, AMD, Google, Valve reicht nicht? (Obwohl. NVIDIA täte etwas Wayland-Engagement gut)

Das ist einfach unerträglich bei dieser Community dass da die dümmlichsten Hypes durch die Upgrades und Updates gepeitscht werden.

Die letzten "dümmlichen Hypes" kamen in letzter Zeit alle aus der X11-Ecke, z.B. mit X11-Neuimplementierungen in Rust (YServer), Zig, ASM, Brainfuck... natürlich alle 100% Vibe-Coded.

Allein schon auf die Idee zu kommen, C-Source-Code nicht mittels Compiler sondern mittels Claude in ASM zu übersetzen... "Aber Hey, wir machen jetzt auch was mit KI"...

#8109461
Lesenswert?
• ▲
▼

Εrnst B. schrieb:

Ja und sich mit X auseinanderzusetzen, und da mal nach Optimierungen schauen - da hat scheinbar keiner Bock drauf.

Doch, hatten Leute. Die haben dann erstmal mit Xshm, Xcb, composite-extension, usw. versucht was "Wayland-Ähnliches" in den X-Server reinzufrickeln. Als klar wurde, dass das eine Sackgasse wird, parallel mit Wayland angefangen.

Definiert mal, was ihr für Optimierungen wollt, je nach Metrik ist X11 um einiges besser: https://www.phoronix.com/news/Wayland-X11-Performance-PorteuX

#8109466
Lesenswert?
• ▲
▼

Daniel A. schrieb:

je nach Metrik ist X11 um einiges besser

Wär halt schön, wenn da nicht Äpfel mit Birnen verglichen werden.

fvwm/x11 gegen Gnome/wayland, und dann die X11-Server Rechenzeit ignorieren macht halt wenig Sinn.

Dieser Benchmark vergleicht KDE/X11 mit KDE/Wayland und lässt den Rest identisch, das ist eher relevant:

https://www.phoronix.com/review/plasma-67-wayland-cachyos

Aber eben ein Gaming-Benchmark...

: Bearbeitet durch User
#8109532
Lesenswert?
• ▲
▼

Daniel A. schrieb:

aber nicht CPU oder Energieverbrauch. Die anderen Metriken.

Auch da findest du Benchmarks, die eben nicht zwei komplett verschiedene Window-Manager miteinander vergleichen:

z.B:

https://www.phoronix.com/news/KDE-Plasma-Wayland-Power

Like with GNOME on Wayland, the KDE Plasma Wayland results also showed a ~3 Watt battery power consumption reduction compared to the X.Org desktop session.

Ist aber von 2021, seitdem hat sich auf X11-Seite nicht viel geändert, auf KDE&Wayland-Seite schon...

Ob zum Besseren oder Schlechteren müsste ein neuer Vergleich zeigen.

#8110107
Lesenswert?
• ▲
▼

Frank D. schrieb:

Wie geht denn eigentlich sowas wie ssh -X unter Wayland?

Entweder genauso (Programm auf dem Zielrechner spricht auch X11, machen die meisten die eine GUI-Bibliothek verwenden und nicht "bare metal" das Wayland-Protokoll implementieren, und der Host hat XWayland laufen)

Oder mit waypipe. Das transferiert das Wayland-Protokoll über ssh und synchronisiert darüber auch das Shared-Memory.

Je nach Anwendung kann (optional!) waypipe die DMA-BUFs auch h.264-Komprimieren, mit Hardware-Beschleunigung, wenn verfügbar. Wär dann verlustbehaftet, aber bei wenig Bandbreite deutlich besser als X11.

Nachteil: Ist nicht so schön in ssh integriert wie das X11-Forwarding, und wird es auch wohl nie. Das OpenSSH-Team will die Codebasis minimieren, um die Angriffsfläche klein zu halten. Also fliegt eher X11-Forwarding aus SSH raus als dass Wayland-Forwarding rein kommt.

d.H. waypipe ssh servername programmname

gerade getestet, firefox über X11 oder waypipe forwarding/ssh im lokalen gigabit-Netz: Geht beides, wayland fühlt sich aber etwas "snappier" an.

mit ssh zu einem Rechner hinter 50/10Mbit DSL: beim X11-Forwarding kannst du zuschauen, wie das Fenster langsam von oben nach unten gezeichnet wird, waypipe läuft zwar auch ruckelig, aber um Welten besser.

: Bearbeitet durch User

Antwort schreiben

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.