Auf dieser Seite

Fancy Compositor

Fancy Compositor ist ein Beispiel, das zeigt, wie man einen ausgefallenen Wayland-Compositor in reinem QML schreibt.

Einführung

Fancy Compositor ist ein kleines Beispiel für einen Wayland-Compositor im Desktop-Stil, das die Leistungsfähigkeit und Einfachheit der Qt Wayland Compositor QML-APIs veranschaulicht.

Das Beispiel „Fancy Compositor“ ähnelt dem Beispiel „Minimal QML“, da es sich um einen vollwertigen Wayland-Compositor handelt, der ausschließlich mit QML-Code implementiert ist.

Initialisierung des Compositors

Wie das „Minimal Qml“-Beispiel unterstützt auch der „Fancy Compositor“ die wichtigsten Shell-Erweiterungen, die von Qt unterstützt werden.

// Shell surface extension. Needed to provide a window concept for Wayland clients.
// I.e. requests and events for maximization, minimization, resizing, closing etc.
XdgShell {
    onToplevelCreated: (toplevel, xdgSurface) => screen.handleShellSurface(xdgSurface)
}

// Minimalistic shell extension. Mainly used for embedded applications.
IviApplication {
    onIviSurfaceCreated: (iviSurface) => screen.handleShellSurface(iviSurface)
}

// Deprecated shell extension, still used by some clients
WlShell {
    onWlShellSurfaceCreated: (shellSurface) => screen.handleShellSurface(shellSurface)
}

Diese werden als untergeordnete Elemente von ` WaylandCompositor ` instanziiert, das sie automatisch zur Liste der unterstützten Schnittstellen hinzufügt, die vom Server an die Clients gesendet wird.

Wenn ein verbundener Client eine Oberfläche erstellt und diese an eine der Shell-Erweiterungen bindet, wird das entsprechende Signal ausgelöst. Dies ruft dann eine Methode innerhalb unserer benutzerdefinierten „ WaylandOutput “-Klasse auf, die die „ ShellSurface “ an eine „ ListModel “ anhängt.

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

Dieses Modell dient als Quelle für eine „ Repeater “, die „ ShellSurfaceItems “ innerhalb des „ WaylandOutput “ des Compositors erstellt. Dadurch wird eine Ansicht der Oberfläche in die „ Qt Quick “-Szene eingefügt. Da es sich um eine „ ShellSurfaceItem “ handelt, stehen dem Benutzer des Compositors je nach verwendeter Shell-Erweiterung bestimmte Interaktionsmöglichkeiten zur Verfügung.

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

Tastatur

Zusätzlich zu den grundlegenden Funktionen des Fenstersystems unterstützt der Fancy Compositor auch eine optionale Bildschirmtastatur, die prozessintern ausgeführt wird. Diese nutzt das Qt Virtual Keyboard Modul und wird aktiviert, sofern das Modul verfügbar ist.

import QtQuick
import QtQuick.VirtualKeyboard

InputPanel {
    visible: active
    y: active ? parent.height - height : parent.height
    anchors.left: parent.left
    anchors.right: parent.right
}

Der Code ist einfach. Wir instanziieren ein ` InputPanel ` am unteren Rand der Ausgabe und stellen sicher, dass es genau dann sichtbar ist, wenn es gerade aktiv ist.

Loader {
    anchors.fill: parent
    source: "Keyboard.qml"
}

Die Tastatur wird dann mithilfe eines „ Loader “-Elements zur „ WaylandOutput “ hinzugefügt. Das „ Loader “ wird hier verwendet, um eine feste Abhängigkeit vom Qt Virtual Keyboard Moduls zu vermeiden. Sollte das Laden fehlschlagen, arbeitet der Compositor normal weiter, allerdings ohne Unterstützung für eine Bildschirmtastatur.

Schließlich benötigen wir eine Möglichkeit, wie der Compositor die Texteingabe an seine Clients weiterleiten kann. Dies geschieht über eine „ text-input “-Erweiterung. Das „Fancy Compositor“-Beispiel unterstützt sowohl das „ text_input_unstable_v2 “-Protokoll als auch das „ qt_text_input_method_unstable_v1 “-Protokoll von Qt.

Die „ qt_text_input_method_unstable_v1 “-Erweiterung wird dem Compositor hinzugefügt, indem „ QtTextInputMethodManager “ als Kind von „ WaylandCompositor “ instanziiert wird, und „ TextInputManager “ fügt „ text_input_unstable_v2 “ hinzu.

Neuere Qt-Anwendungen wählen „ qt_text_input_method_unstable_v1 “, sofern diese verfügbar ist, während andere Clients „ text_input_unstable_v2 “ verwenden können.

Übergänge

Zusätzlich zu den Grundfunktionen demonstriert das Beispiel „Fancy Compositor“ auch animierte Übergänge zwischen Zuständen.

Der erste davon ist der Aktivierungsübergang. Dieser wird nur auf dem „ XdgShell “ unterstützt, da dies die einzige Shell-Erweiterung ist, die über einen „ activated “-Zustand verfügt.

Connections {
    target: shellSurface.toplevel !== undefined ? shellSurface.toplevel : null

    // some signals are not available on wl_shell, so let's ignore them
    ignoreUnknownSignals: true

    function onActivatedChanged() { // xdg_shell only
        if (shellSurface.toplevel.activated) {
            receivedFocusAnimation.start();
        }
    }
}

SequentialAnimation {
    id: receivedFocusAnimation

    ParallelAnimation {
        NumberAnimation { target: scaleTransform; property: "yScale"; to: 1.02; duration: 100; easing.type: Easing.OutQuad }
        NumberAnimation { target: scaleTransform; property: "xScale"; to: 1.02; duration: 100; easing.type: Easing.OutQuad }
    }
    ParallelAnimation {
        NumberAnimation { target: scaleTransform; property: "yScale"; to: 1; duration: 100; easing.type: Easing.InOutQuad }
        NumberAnimation { target: scaleTransform; property: "xScale"; to: 1; duration: 100; easing.type: Easing.InOutQuad }
    }
}

Wenn ein Client-Fenster unter dem „ XdgShell “-Protokoll aktiviert wird, lösen wir eine Animation aus, bei der das Fenster 200 ms lang „herausspringt“.

Der Fancy Compositor unterstützt zudem eine Löschanimation. Diese wird immer dann ausgelöst, wenn das Fenster geschlossen und die Oberfläche gelöscht wird – unabhängig davon, ob der Client sein Fenster ordnungsgemäß geschlossen hat oder ob es zu einem Absturz gekommen ist.

onSurfaceDestroyed: {
    bufferLocked = true;
    destroyAnimation.start();
}

SequentialAnimation {
    id: destroyAnimation

    ParallelAnimation {
        NumberAnimation { target: scaleTransform; property: "yScale"; to: 2/height; duration: 150 }
        NumberAnimation { target: scaleTransform; property: "xScale"; to: 0.4; duration: 150 }
        NumberAnimation { target: chrome; property: "opacity"; to: chrome.isChild ? 0 : 1; duration: 150 }
    }
    NumberAnimation { target: scaleTransform; property: "xScale"; to: 0; duration: 150 }
    ScriptAction { script: destroyAnimationFinished() }
}

Um sicherzustellen, dass der Inhalt für die Dauer der Animation vorhanden ist, sperren wir zunächst den Puffer. Das bedeutet, dass der letzte vom Client gerenderte Frame im Speicher verbleibt, bis wir damit fertig sind.

Auch hier lösen wir eine Animation aus, deren Umfang sich nach dem Element richtet. Die betreffende Animation ahmt das Ausschalten eines CRT-Bildschirms nach und gibt dem Benutzer einen visuellen Hinweis darauf, dass das Fenster geschlossen wird und nicht einfach in Luft aufgelöst ist.

Für solche Zustandsänderungen können beliebige Animationseffekte verwendet werden, wobei Ihnen die gesamte Bandbreite von „ Qt Quick “ zur Verfügung steht.

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.