Auf dieser Seite

QtShell Compositor

QtShell Compositor zeigt, wie die Shell-Erweiterung „ QtShell “ verwendet wird.

QtShell „Compositor“ ist ein Beispiel für einen Wayland-Compositor im Desktop-Stil, der eine vollständige „ Qt Wayland Compositor “ implementiert, die das spezielle Shell-Erweiterungsprotokoll namens „ QtShell “ nutzt.

QtShell-Compositor mit zwei Client-Fenstern

Der Compositor wurde mit „ Qt Quick “ und QML implementiert.

Herstellen der Verbindung

Das Beispiel listet „ QtShell “ als einzige Erweiterung des „ WaylandCompositor “-Objekts auf. Das bedeutet, dass jeder Client, der eine Verbindung zum Server herstellt, diese Erweiterung ebenfalls unterstützen muss; es sollte sich also um Qt-Anwendungen handeln, die mit derselben Qt-Version laufen wie der Compositor.

QtShell {
    onQtShellSurfaceCreated: (qtShellSurface) => screen.handleShellSurface(qtShellSurface)
}

Wenn ein Client eine Verbindung zur Schnittstelle „ QtShell “ herstellt, erstellt er ein „ QtShellSurface “. Der Compositor wird darüber durch die Emission des Signals „ qtShellSurfaceCreated “ benachrichtigt. Das Beispiel fügt die Shell-Oberfläche anschließend einem „ ListModel “ hinzu, um später einen einfachen Zugriff zu ermöglichen.

property ListModel shellSurfaces: ListModel {}
function handleShellSurface(shellSurface) {
    shellSurfaces.append({shellSurface: shellSurface});
}

Die ` ListModel ` dient als Vorlage für eine ` Repeater `, die die für die Anzeige der Client-Inhalte auf dem Bildschirm erforderlichen ` Qt Quick `-Elemente erstellt.

Repeater {
    id: chromeRepeater
    model: output.shellSurfaces
    // Chrome displays a shell surface on the screen (See Chrome.qml)
    Chrome {
        shellSurface: modelData
        onShellSurfaceChanged: {
            if (!shellSurface)
                output.shellSurfaces.remove(index)
        }
    }
}

Dabei wird der lokale Typ „ Chrome “ verwendet, der Fensterstatus und Dekorationen verwaltet.

Chrome

Das „ Chrome “ ist der Typ, der sicherstellt, dass die Client-Inhalte sichtbar sind, und der zudem den Fensterstatus, die Position, die Größe usw. verwaltet. Es nutzt das integrierte „ QtShellChrome “ als Grundlage, das den Fensterstatus (maximiert, minimiert, Vollbild) und die Fensteraktivierung (sodass jeweils nur ein Fenster aktiv ist) automatisch verwaltet.

Sein Verhalten lässt sich bis zu einem gewissen Grad anpassen, es ist jedoch auch möglich, die „ Chrome “-Funktionalität von Grund auf neu zu schreiben und stattdessen auf einem einfachen „ Item “-Typ aufzubauen. „ QtShellChrome “ ist eine Komfortklasse, die typisches Compositor-Verhalten bereitstellt und uns im Beispiel die Zeit für die Implementierung dieser Logik erspart.

Unabhängig davon, wie der „ Chrome “ geschrieben ist, sollte er über einen „ ShellSurfaceItem “ verfügen, um die Inhalte des Clients aufzunehmen.

ShellSurfaceItem {
    id: shellSurfaceItemId
    anchors.top: titleBar.bottom
    anchors.bottom: bottomResizeHandle.top
    anchors.left: leftResizeHandle.right
    anchors.right: rightResizeHandle.left

    moveItem: chrome

    staysOnBottom: shellSurface.windowFlags & Qt.WindowStaysOnBottomHint
    staysOnTop: !staysOnBottom && shellSurface.windowFlags & Qt.WindowStaysOnTopHint
}
shellSurfaceItem: shellSurfaceItemId

Der „ ShellSurfaceItem “ ist die visuelle Darstellung des Client-Inhalts in der „ Qt Quick “-Szene. Seine Größe sollte in der Regel der Größe des Client-Puffers entsprechen, da er sonst gestreckt oder gestaucht aussehen könnte. „ QtShellChrome “ wird automatisch an die „ windowGeometry “ des „ QtShellSurface “ angepasst, die der Größe des Client-Puffers zuzüglich der Größe der Rahmenränder entspricht. Die Rahmenränder sind reservierte Bereiche an den Seiten des „ Chrome “, die zur Darstellung von Fensterdekorationen genutzt werden können.

Der „ ShellSurfaceItem “ wird daher an den Fensterdekorationen verankert, um den für den Client-Puffer reservierten Bereich auszufüllen.

Fensterdekorationen

Die Fensterdekoration ist in der Regel ein Rahmen um den Inhalt eines Clients, der Informationen (wie beispielsweise einen Fenstertitel) und die Möglichkeit zur Benutzerinteraktion (wie das Ändern der Größe, das Schließen oder das Verschieben des Fensters usw.) bereitstellt.

Bei „ QtShell “ werden Fensterdekorationen immer vom Compositor und nicht vom Client gezeichnet. Damit Größen und Positionen korrekt übermittelt werden können, muss „ QtShell “ außerdem wissen, wie viel Platz im Fenster für diese Dekorationen reserviert ist. Dies kann automatisch über „ QtShellChrome “ oder manuell durch Setzen von „ frameMarginLeft “, „ frameMarginRight “, „ frameMarginTop “ und „ frameMarginBottom “ erfolgen.

In typischen Fällen, in denen sich Größenänderungsgriffe um das Fenster herum und oben eine Titelleiste befinden, ist es praktischer, sich auf die Standard-Rahmenränder zu verlassen. Das Beispiel „ QtShell “ des Compositors tut genau dies.

Zunächst erstellen wir „ Qt Quick “-Elemente, um die verschiedenen Teile der Fensterdekoration darzustellen. Auf der linken Seite sollte sich beispielsweise ein Größenänderungsgriff befinden, den der Benutzer anfassen und ziehen kann, um die Größe des Fensters anzupassen.

Rectangle {
    id: leftResizeHandle
    color: "gray"
    width: visible ? 5 : 0
    anchors.topMargin: 5
    anchors.bottomMargin: 5
    anchors.left: parent.left
    anchors.top: parent.top
    anchors.bottom: parent.bottom
}

Im Beispiel gestalten wir dies einfach als fünf Pixel breites Rechteck, das am oberen, unteren und linken Rand des „ Chrome “ verankert ist.

Ebenso fügen wir „ Qt Quick “-Elemente hinzu, die die Größenänderungsgriffe für rechts, oben, unten, oben links, oben rechts, unten links und unten rechts darstellen. Außerdem fügen wir eine Titelleiste hinzu. Wenn die Dekorationen erstellt und korrekt an den Seiten des „ Chrome “ verankert wurden, setzen wir die entsprechenden Eigenschaften in „ QtShellChrome “.

leftResizeHandle: leftResizeHandle
rightResizeHandle: rightResizeHandle
topResizeHandle: topResizeHandle
bottomResizeHandle: bottomResizeHandle
bottomLeftResizeHandle: bottomLeftResizeHandle
bottomRightResizeHandle: bottomRightResizeHandle
topLeftResizeHandle: topLeftResizeHandle
topRightResizeHandle: topRightResizeHandle
titleBar: titleBar

Sobald die Eigenschaften der Dekorationen festgelegt sind, wird das Standardverhalten für die Größenänderung und Neupositionierung automatisch hinzugefügt. Der Benutzer kann mit den Größenänderungsgriffen interagieren, um die Größe des Fensters anzupassen, und die Titelleiste ziehen, um das Fenster neu zu positionieren. Die Rahmenränder des „ QtShellSurface “ werden ebenfalls automatisch angepasst, um die Größe der Dekorationen zu berücksichtigen (sofern keine der Eigenschaften für die Rahmenränder explizit festgelegt wurde).

Die Sichtbarkeit der Dekorationen wird vom ` QtShellChrome ` automatisch auf der Grundlage der Fensterflags des ` QtShellSurface` verwaltet.

Fensterverwaltung

Als Teil der Dekorationen ist es üblich, Schaltflächen zu haben, die den Fensterzustand und die Lebensdauer verwalten. Im Beispiel werden diese zur Titelleiste hinzugefügt.

RowLayout {
    id: rowLayout
    anchors.right: parent.right
    anchors.rightMargin: 5

    ToolButton {
        text: "-"
        Layout.margins: 5
        visible: (chrome.windowFlags & Qt.WindowMinimizeButtonHint) != 0
        onClicked: {
            chrome.toggleMinimized()
        }
    }

    ToolButton {
        text: "+"
        Layout.margins: 5
        visible: (chrome.windowFlags & Qt.WindowMaximizeButtonHint) != 0
        onClicked: {
            chrome.toggleMaximized()
        }
    }

    ToolButton {
        id: xButton
        text: "X"
        Layout.margins: 5
        visible: (chrome.windowFlags & Qt.WindowCloseButtonHint) != 0
        onClicked: shellSurface.sendClose()
    }
}

Die Sichtbarkeit jeder Schaltfläche hängt vom Fensterflag für diese Schaltfläche ab, und wenn auf eine davon geklickt wird, rufen wir einfach die entsprechende Methode in ` QtShellChrome` auf. Eine Ausnahme bildet die Schaltfläche „Schließen“, die die Methode ` sendClose()` in ` QtShellSurface` aufruft. Dies weist den Client an, sich selbst zu schließen, und gewährleistet ein ordnungsgemäßes Herunterfahren der Anwendung.

Row {
    id: taskbar
    height: 40
    anchors.left: parent.left
    anchors.right: parent.right
    anchors.bottom: parent.bottom

    Repeater {
        anchors.fill: parent
        model: output.shellSurfaces

        ToolButton {
            anchors.verticalCenter: parent.verticalCenter
            text: modelData.windowTitle
            onClicked: {
                var item = chromeRepeater.itemAt(index)
                if ((item.windowState & Qt.WindowMinimized) != 0)
                    item.toggleMinimized()
                chromeRepeater.itemAt(index).activate()
            }
        }
    }
}

Als zusätzliches Werkzeug zur Fensterverwaltung verfügt das Beispiel über eine „Taskleiste“. Dabei handelt es sich lediglich um eine Reihe von Schaltflächen am unteren Rand, die die Fenstertitel anzeigen. Durch Anklicken dieser Schaltflächen können Anwendungen aus dem minimierten Zustand wieder herangeholt und in den Vordergrund gebracht werden, falls sie von anderen Fenstern verdeckt sind. Ähnlich wie bei der „ Chrome “ verwenden wir eine „ Repeater “ zum Erstellen der Schaltflächen und nutzen dabei die Shell-Oberflächenliste als Vorlage. Der Einfachheit halber enthält das Beispiel keine Behandlung von Überlaufsituationen (wenn zu viele Anwendungen für die Taskleiste vorhanden sind), doch in einem vollwertigen Compositor sollte auch dies berücksichtigt werden.

Um schließlich zu verhindern, dass maximierte Anwendungen den von der Taskleiste eingenommenen Bereich ausfüllen, erstellen wir ein spezielles Element zur Verwaltung der Teile des „ WaylandOutput “-Bereichs, die für Client-Fenster verfügbar sind.

Item {
    id: usableArea
    anchors.top: parent.top
    anchors.left: parent.left
    anchors.right: parent.right
    anchors.bottom: taskbar.top
}

Es ist einfach an den Seiten des „ WaylandOutput “ verankert, seine untere Verankerung befindet sich jedoch am oberen Rand der Taskleiste.

Im „ Chrome “ nutzen wir diesen Bereich, um die „ maximizedRect “ des Fensters zu definieren.

maximizedRect: Qt.rect(usableArea.x,
                       usableArea.y,
                       usableArea.width,
                       usableArea.height)

Standardmäßig entspricht diese Eigenschaft dem gesamten „ WaylandOutput “. In unserem Fall möchten wir jedoch die Taskleiste nicht in den verfügbaren Bereich einbeziehen, daher überschreiben wir die Standardeinstellung.

Beispielprojekt @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.