Fancy Compositor
Fancy Compositor est un exemple qui montre comment écrire un compositeur Wayland sophistiqué en QML pur.
Introduction
Fancy Compositor est un petit exemple de compositeur Wayland de type bureau qui illustre la puissance et la simplicité d’utilisation des Qt Wayland Compositor API QML.
L'exemple Fancy Compositor est similaire à l'exemple Minimal QML, en ce sens qu'il s'agit d'un compositeur Wayland à part entière, implémenté uniquement à l'aide de code QML.
Initialisation du compositeur
Tout comme l’exemple Minimal Qml, Fancy Compositor prend en charge les principales extensions de shell prises en charge par Qt.
// 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)
}Celles-ci sont instanciées en tant qu’enfants de la classe ` WaylandCompositor `, qui les ajoute automatiquement à la liste des interfaces prises en charge, laquelle est diffusée aux clients depuis le serveur.
Lorsqu’un client connecté crée une surface et la lie à l’une des extensions du shell, le signal correspondant est émis. Cela appelle alors une méthode au sein de notre classe personnalisée ` WaylandOutput `, qui ajoute l’ ShellSurface à un ` ListModel`.
function handleShellSurface(shellSurface) {
shellSurfaces.append({shellSurface: shellSurface});
}Ce modèle sert de source à une ` Repeater ` qui crée des ` ShellSurfaceItems ` au sein de la ` WaylandOutput` du compositeur. Cela ajoute une vue de la surface dans la scène ` Qt Quick `. Comme il s’agit d’une ` ShellSurfaceItem`, elle offre également certaines options d’interaction à l’utilisateur du compositeur, en fonction de l’extension de shell utilisée.
Repeater {
model: output.shellSurfaces
// Chrome displays a shell surface on the screen (See Chrome.qml)
Chrome {
shellSurface: modelData
onDestroyAnimationFinished: output.shellSurfaces.remove(index)
}
}Clavier
Outre les fonctions de base du système de fenêtrage, le Fancy Compositor prend également en charge un clavier virtuel optionnel fonctionnant en interne. Celui-ci utilise le Qt Virtual Keyboard module et sera activé si ce dernier est disponible.
import QtQuick
import QtQuick.VirtualKeyboard
InputPanel {
visible: active
y: active ? parent.height - height : parent.height
anchors.left: parent.left
anchors.right: parent.right
}Le code est simple. Nous instancions un ` InputPanel ` au bas de la sortie, et nous nous assurons qu’il soit visible si et seulement s’il est actuellement actif.
Loader {
anchors.fill: parent
source: "Keyboard.qml"
}Le clavier est ensuite ajouté à l’ WaylandOutput à l’aide d’un élément Loader. L’ Loader est utilisé ici pour éviter une dépendance stricte vis-à-vis du Qt Virtual Keyboard module. Si le chargement échoue, le compositeur continuera de fonctionner normalement, mais sans prise en charge du clavier à l’écran.
Enfin, il faut permettre au compositeur de communiquer la saisie de texte à ses clients. Cela s’effectue via une extension « text-input ». L’exemple Fancy Compositor prend en charge à la fois le protocole « text_input_unstable_v2 » et le protocole « qt_text_input_method_unstable_v1 » de Qt.
L’extension qt_text_input_method_unstable_v1 est ajoutée au compositeur en instanciant QtTextInputMethodManager en tant qu’enfant de WaylandCompositor, et TextInputManager ajoute text_input_unstable_v2.
Les applications Qt plus récentes choisiront qt_text_input_method_unstable_v1 lorsqu’elle est disponible, tandis que les autres clients peuvent utiliser text_input_unstable_v2.
Transitions
Outre les fonctionnalités de base, l’exemple Fancy Compositor illustre également des transitions animées entre les différents états.
La première d’entre elles est la transition d’activation. Celle-ci n’est prise en charge que sur XdgShell, car c’est la seule extension de shell disposant d’un état activated.
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 }
}
}Lorsqu’une fenêtre cliente est activée dans le cadre du protocole XdgShell, nous déclenchons une animation qui fait « ressortir » la fenêtre pendant 200 ms.
Fancy Compositor prend également en charge une animation de destruction. Celle-ci se déclenche chaque fois que la fenêtre se ferme et que la surface est détruite, que ce soit parce que le client a fermé sa fenêtre de manière normale ou même en cas de plantage.
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() }
}Pour garantir que le contenu soit présent pendant toute la durée de l’animation, nous commençons par verrouiller le tampon. Cela signifie que la dernière image rendue par le client restera en mémoire jusqu’à ce que nous en ayons terminé avec elle.
Là encore, nous déclenchons une animation à l’échelle de l’élément. L’animation en question imite la mise hors tension d’un écran CRT, donnant ainsi à l’utilisateur un indice visuel indiquant que la fenêtre se ferme et qu’elle ne s’est pas simplement évaporée dans les airs.
Tout type d’effet animé peut être utilisé pour des changements d’état comme ceux-ci, avec toute la gamme d’ Qt Quick s à votre disposition.
© 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.