Sur cette page

QtShell Compositor

QtShell Compositor montre comment utiliser l'extension de shell « QtShell ».

QtShell Compositor est un exemple de compositeur Wayland de type bureau qui met en œuvre un compositeur complet ( Qt Wayland Compositor ) utilisant le protocole d’extension de shell spécialisé appelé « QtShell ».

Compositeur QtShell avec deux fenêtres clientes

Le compositeur est implémenté avec Qt Quick et QML.

Établissement de la connexion

L’exemple répertorie QtShell comme seule extension de l’objet WaylandCompositor. Cela signifie que tout client se connectant au serveur doit également prendre en charge cette extension ; il doit donc s’agir d’applications Qt fonctionnant avec la même version de Qt que le compositeur.

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

Lorsqu’un client se connecte à l’interface ` QtShell `, il crée un ` QtShellSurface`. Le compositeur en est informé par l’émission du signal ` qtShellSurfaceCreated `. L’exemple ajoute ensuite la surface shell à un ` ListModel ` pour faciliter son accès ultérieur.

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

L’ ListModel sert de modèle à un Repeater qui crée les éléments Qt Quick nécessaires à l’affichage du contenu du client à l’écran.

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)
        }
    }
}

Il utilise le type « local Chrome », qui gère les états et les décorations de la fenêtre.

Chrome

L'Chrome est le type qui garantit la visibilité du contenu client et gère également l'état, la position, la taille de la fenêtre, etc. Il s'appuie sur l'QtShellChrome intégré, qui gère automatiquement l'état de la fenêtre (agrandie, réduite, plein écran) et son activation (en veillant à ce qu'une seule fenêtre soit active à la fois).

Son comportement peut être personnalisé dans une certaine mesure, mais il est également possible d'écrire la fonctionnalité de l'Chrome e à partir de zéro, en s'appuyant sur un type « Item » de base. QtShellChrome est une classe pratique qui fournit un comportement de compositeur typique et nous évite de devoir implémenter cette logique dans l'exemple.

Quelle que soit la manière dont l’ Chrome est écrit, il doit disposer d’un ShellSurfaceItem pour contenir le contenu du client.

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

L’ ShellSurfaceItem est la représentation visuelle du contenu du client dans la scène de l’ Qt Quick. Sa taille doit généralement correspondre à celle du tampon du client, sinon le contenu risque d’apparaître étiré ou compressé. QtShellChrome s’adaptera automatiquement à la taille de l’ QtShellSurface( windowGeometry), qui correspond à la taille du tampon du client plus celle des marges du cadre. Les marges de l’image sont des zones réservées sur les côtés de l’ Chrome, qui peuvent être utilisées pour contenir les décorations de la fenêtre.

L’ ShellSurfaceItem est donc ancré aux décorations de la fenêtre afin de remplir la zone réservée au tampon client.

Décorations de fenêtre

La décoration de fenêtre est généralement un cadre entourant le contenu d’un client qui ajoute des informations (telles que le titre de la fenêtre) et offre la possibilité d’une interaction avec l’utilisateur (telle que le redimensionnement, la fermeture ou le déplacement de la fenêtre, etc.).

Avec ` QtShell`, les décorations de fenêtre sont toujours dessinées par le compositeur et non par le client. Pour que les tailles et les positions soient communiquées correctement, ` QtShell ` doit également connaître la partie de la fenêtre réservée à ces décorations. Cela peut être géré automatiquement par ` QtShellChrome`, ou manuellement, en définissant ` frameMarginLeft`, ` frameMarginRight`, ` frameMarginTop ` et ` frameMarginBottom`.

Dans les cas classiques où la fenêtre comporte des poignées de redimensionnement et une barre de titre en haut, il est plus pratique de s’en tenir aux marges par défaut du cadre. C’est ce que fait l’exemple « QtShell » du compositeur.

Tout d’abord, nous créons des éléments « Qt Quick » pour représenter les différentes parties des décorations de la fenêtre. Sur le côté gauche, par exemple, il devrait y avoir une poignée de redimensionnement que l’utilisateur peut saisir et faire glisser afin de redimensionner la fenêtre.

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
}

Dans cet exemple, nous créons simplement un rectangle de cinq pixels de large, ancré en haut, en bas et à gauche de l’ Chrome.

De la même manière, nous ajoutons des éléments « Qt Quick » représentant les poignées de redimensionnement situées à droite, en haut, en bas, en haut à gauche, en haut à droite, en bas à gauche et en bas à droite. Nous ajoutons également une barre de titre. Une fois les décorations créées et correctement ancrées aux côtés de l’ Chrome, nous définissons les propriétés correspondantes dans QtShellChrome.

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

Une fois les propriétés de décoration définies, le comportement par défaut de redimensionnement et de repositionnement sera automatiquement ajouté. L’utilisateur pourra interagir avec les poignées de redimensionnement pour redimensionner la fenêtre, et faire glisser la barre de titre pour la repositionner. Les marges du cadre de l’ QtShellSurface seront également définies automatiquement pour tenir compte de la taille des décorations (à condition qu’aucune des propriétés de marges du cadre n’ait été définie explicitement).

La visibilité des décorations sera gérée automatiquement par l’ QtShellChrome en fonction des indicateurs de fenêtre de l’ QtShellSurface.

Gestion des fenêtres

Dans le cadre des décorations, il est courant d’avoir des boutons d’outils qui gèrent l’état et la durée de vie de la fenêtre. Dans l’exemple, ceux-ci sont ajoutés à la barre de titre.

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()
    }
}

La visibilité de chaque bouton dépend de l'indicateur de fenêtre associé à ce bouton, et lorsque l'on clique sur l'un d'entre eux, on appelle simplement la méthode correspondante dans ` QtShellChrome`. La seule exception est le bouton « Fermer », qui appelle la méthode ` sendClose()` dans ` QtShellSurface`. Cela ordonne au client de se fermer et garantit un arrêt en douceur de l'application.

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()
            }
        }
    }
}

En tant qu’outil supplémentaire de gestion des fenêtres, l’exemple dispose d’une « barre des tâches ». Il s’agit simplement d’une rangée de boutons d’outils située en bas de l’écran, accompagnée des titres des fenêtres. On peut cliquer sur ces boutons pour redimensionner les applications et les ramener au premier plan si elles sont masquées par d’autres fenêtres. À l’instar de l’ Chrome, nous utilisons une Repeater pour créer les boutons d’outils et nous nous basons sur la liste des surfaces du shell comme modèle. Par souci de simplicité, l’exemple ne gère pas les situations de débordement (lorsqu’il y a trop d’applications pour la barre des tâches), mais dans un compositeur digne de ce nom, cet aspect devrait également être pris en compte.

Enfin, pour éviter que les applications agrandies à l’écran ne s’étendent jusqu’à occuper l’espace couvert par la barre des tâches, nous créons un élément spécial chargé de gérer les parties de l’espace de l’ WaylandOutput disponibles pour les fenêtres clientes.

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

Il est simplement ancré aux côtés de l’ WaylandOutput, mais son ancrage inférieur se trouve en haut de la barre des tâches.

Dans l’ Chrome, nous utilisons cette zone pour définir l’ maximizedRect de la fenêtre.

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

Par défaut, cette propriété correspond à l’ WaylandOutput e complète. Dans notre cas, cependant, nous ne souhaitons pas inclure la barre des tâches dans la zone disponible ; nous remplaçons donc la valeur par défaut.

Exemple de projet @ 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.