Wie verlasse ich eine X11-Ereignisschleife ordnungsgemäß?

Lesezeit: 5 Minuten

Benutzeravatar von TheBuzzSaw
Die BuzzSaw

Fast jedes Tutorial, das ich finde, fordert mich auf, dies für meine Ereignisschleife zu tun:

XEvent event;

while (true)
{
    XNextEvent(display, &event);

    switch (event.type)
    {
        case Expose:
            printf("Expose\n");
            break;

        default:
            break;
    }
}

Wenn Sie jedoch auf das X klicken, um das Programm zu schließen, wird diese Meldung angezeigt.

XIO:  fatal IO error 11 (Resource temporarily unavailable) on X server ":0"
after 10 requests (10 known processed) with 0 events remaining.

Es ist in der Tat seltsam für mich, dass die Beispiele die Verwendung einer Endlosschleife nahelegen. Das klingt nicht natürlich, und meine anderen X11-Programme tun das nicht. Also suchte ich herum. Ich habe herausgefunden, wie man das Ereignis zum Schließen des Fensters erfasst.

Atom wmDeleteMessage = XInternAtom(mDisplay, "WM_DELETE_WINDOW", False);
XSetWMProtocols(display, window, &wmDeleteMessage, 1);

XEvent event;
bool running = true;

while (running)
{
    XNextEvent(display, &event);

    switch (event.type)
    {
        case Expose:
            printf("Expose\n");
            break;

        case ClientMessage:
            if (event.xclient.data.l[0] == wmDeleteMessage)
                running = false;
            break;

        default:
            break;
    }
}

Das funktioniert. Es wird ohne Fehler beendet. … Aber ich weigere mich zu glauben, dass dies der normale Weg ist, Dinge zu tun. Ich meine, ist dies die einzige Möglichkeit, eine X11-App ordnungsgemäß zu beenden? Es scheint eine Menge Arbeit zu sein, nur das nahe Ereignis festzuhalten. Wie erstelle ich eine “richtige” Ereignisschleife? Warum ist das nahe Ereignis so tief begraben? Was vermisse ich?

  • Wenn Sie denken, dass das “viel Arbeit” ist, warten Sie, bis Sie an den Punkt kommen, an dem Sie versuchen, irgendetwas Nützliches in X zu tun … 🙂

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    29. Mai 2012 um 3:01 Uhr

  • Nun, es ist nicht so sehr die “Arbeit”, wegen der ich mich betone. Ich denke, es ist gerechter: Warum ist diese spezielle Funktion so obskur? Wie gewähre ich der Exit-Schaltfläche “Standardverhalten”?

    – TheBuzzSaw

    29. Mai 2012 um 5:23 Uhr

  • Die gesamte X11-Bibliothek ist Dunkelheit über Dunkelheit, mehrere Ebenen tief. Es ist, als hätte jemand Dantes Inferno genommen und es in eine C-API umgeschrieben. Ich denke, als es fertig war, übertraf seine Benutzerfreundlichkeit immer noch seine Vorgänger.

    – Kuba hat Monica nicht vergessen

    2. August 2014 um 16:29 Uhr

  • Musste den Inferno-Witz von Dante kommentieren. Zum ersten Mal lese ich diese Referenz und die C-API im selben Satz

    – CristianDonosoC

    28. April 2016 um 13:56 Uhr

Das Problem liegt in der Kommunikation zwischen X Server und dem Window Manager.

Wenn du anrufst XCreateWindow oder XCreateSimpleWindowerstellt der X-Server Ihr Fenster (zeigt es erst an, wenn Sie es explizit auf dem Bildschirm abbilden, indem Sie es aufrufen XMapWindow), und dann ist der Fenstermanager dafür verantwortlich, alle Dekorationen und Schaltflächen und das Systemmenü um Ihr Fenster herum anzubringen.

Du kannst anrufen XDestroyWindow selbst, um das Fenster zu entfernen, und das bedeutet normalerweise, dass es einfach vom Bildschirm verschwindet, aber Ihr Programm läuft noch und die Verbindung zum X-Server ist noch offen, sodass Sie ihm weitere Anfragen senden können.

Das Problem beginnt, wenn der Benutzer so wenig klickt X Schaltfläche, die vom Fenstermanager an Ihr Fenster angehängt wurde, da sie nicht vom X-Server erstellt wird und es nicht seine Sache ist, zu entscheiden, was dann zu tun ist. Jetzt liegt alles in den Händen von Window Manager.

Wird der Fenstermanager einfach aufgerufen XDestroyWindow In Ihrem Fenster würde es ein Problem verursachen, wenn Ihre Anwendung das Schließereignis erfassen möchte, um etwas zu tun, bevor das Fenster zerstört wird. Daher wurde zwischen dem X-Server und den Window-Managern eine Vereinbarung getroffen, um diesen Prozess zu handhaben.

Das Standardverhalten der meisten Fenstermanager ist to Zerstöre das Fenster und nah dran die Verbindung mit dem X-Server, denn das würden die meisten Benutzer von Fenstermanagern erwarten: Wenn sie das Fenster schließen, wird das Programm beendet (und die Verbindung zum X-Server wird mit dem geschlossenen Fenster geschlossen). Und dann, wenn Sie versuchen anzurufen XCloseDisplay(display)wird es den von Ihnen erwähnten IO-Fehler verursachen, da die Verbindung zum Server bereits geschlossen ist und die display Struktur ist ungültig.

Hier ein Auszug aus der Xlib-Dokumentation was das erklärt:

Kunden, die sich dafür entscheiden, nicht einzuschließen WM_DELETE_WINDOW in dem WM_PROTOCOLS -Eigenschaft kann vom Server getrennt werden, wenn der Benutzer verlangt, dass eines der Fenster der obersten Ebene des Clients gelöscht wird.

Ja, es wäre toll, wenn sie es nicht so tief in ihren Dokumenten verstecken würden 😛 Aber wenn du es schon findest, gibt es zum Glück auch Hinweise auf die Lösung.

Wenn Sie ein anderes Verhalten wünschen (d. h. das Schließereignis aus dem Fenstermanager erfassen), müssen Sie die verwenden WM_DESTROY_WINDOW Protokoll.

Noch ein Auszug aus der Doku:

Clients, normalerweise solche mit mehreren Top-Level-Fenstern, deren Serververbindung das Löschen einiger ihrer Top-Level-Fenster überleben muss, sollten das Atom enthalten WM_DELETE_WINDOW in dem WM_PROTOCOLS Eigenschaft auf jedem dieser Fenster. Sie erhalten eine ClientMessage Veranstaltung wie oben beschrieben, deren data[0] Feld ist WM_DELETE_WINDOW.

Ich hatte den gleichen Fehler und wollte genau wissen, was ihn verursacht und warum. Ich habe einige Zeit gebraucht, um es herauszufinden und die richtige Erklärung im Dokument zu finden, also habe ich meine Erklärung hier eingefügt, um anderen Unwissenden Zeit zu sparen.

  • Gute Antwort. Vielen Dank für Ihre Zeit!

    – Benutzer18490

    18. Juni 2014 um 14:02 Uhr

In X11 gibt es keine “Beenden-Schaltfläche” oder “Anwendung” oder “Ereignis schließen”. Dies ist beabsichtigt.

Fensterdekorationen, Ausgangstasten und viele andere Dinge, auf die wir angewiesen sind, sind nicht in X11 integriert. Sie werden stattdessen auf dem Core X11 implementiert. Der Name des bestimmten Satzes von Konventionen, für den er verantwortlich ist wmDeleteMessage ist ICCCM, schlagen Sie nach.

Xlib befasst sich nur mit dem zentralen X11-Protokoll. Dort gibt es kein eingebautes Schließereignis.

Es gibt Toolkits, die den Umgang mit ICCCM und allen anderen Dingen, die nicht in X11 integriert sind, erleichtern (GTK, wxWindows, Qt, …). Wahrscheinlich möchten Sie eines davon verwenden.

  • Deshalb ist es so obskur, ein Fenster zu schließen. X ist nicht darauf ausgelegt, sich um solche Dinge zu kümmern – es ist die Aufgabe des Fenstermanagers. Aus diesem Grund verwenden die meisten Leute Toolkits wie GTK oder Qt.

    – SevenBits

    28. August 2013 um 19:19 Uhr

1402440cookie-checkWie verlasse ich eine X11-Ereignisschleife ordnungsgemäß?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy