Fancy Compositor
Fancy Compositorは、純粋なQMLで洗練されたWaylandコンポジターを作成する方法を示すサンプルです。
はじめに
Fancy Compositorは、デスクトップスタイルの小さなWaylandコンポジターのサンプルであり、 Qt Wayland Compositor QML APIのパワーと使いやすさを示す、小さなデスクトップスタイルのWaylandコンポジターのサンプルです。
Fancy Compositor のサンプルは、Minimal QML のサンプルと同様に、QML コードのみを使用して実装された本格的な Wayland コンポジターです。
コンポジターの初期化
「Minimal Qml」のサンプルと同様に、「Fancy Compositor」は 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)
}これらは、WaylandCompositor の子としてインスタンス化され、自動的にサポートされているインターフェースのリストに追加されます。このリストは、サーバーからクライアントにブロードキャストされます。
接続されたクライアントがサーフェスを作成し、それをシェル拡張機能のいずれかにバインドすると、対応するシグナルが発信されます。これにより、カスタムWaylandOutput クラス内のメソッドが呼び出され、ShellSurface がListModel に追加されます。
function handleShellSurface(shellSurface) {
shellSurfaces.append({shellSurface: shellSurface});
}このモデルは、コンポジターのWaylandOutput 内にShellSurfaceItems を作成するRepeater のソースとして使用されます。これにより、Qt Quick シーンにサーフェスのビューが追加されます。これはShellSurfaceItem であるため、使用中のシェル拡張機能に応じて、コンポジターのユーザー向けの特定のインタラクションオプションも提供されます。
Repeater {
model: output.shellSurfaces
// Chrome displays a shell surface on the screen (See Chrome.qml)
Chrome {
shellSurface: modelData
onDestroyAnimationFinished: output.shellSurfaces.remove(index)
}
}キーボード
基本的なウィンドウシステム機能に加え、Fancy Compositor は、プロセス内で動作するオプションのオンスクリーンキーボードもサポートしています。これは Qt Virtual Keyboard モジュールを使用しており、モジュールが利用可能な場合は有効になります。
import QtQuick
import QtQuick.VirtualKeyboard
InputPanel {
visible: active
y: active ? parent.height - height : parent.height
anchors.left: parent.left
anchors.right: parent.right
}コードは単純です。出力の最下部にInputPanel をインスタンス化し、それが現在アクティブな場合にのみ表示されるようにします。
Loader {
anchors.fill: parent
source: "Keyboard.qml"
}その後、Loader 要素を使用して、キーボードをWaylandOutput に追加します。ここでLoader を使用するのは、 Qt Virtual Keyboard モジュールへのハードな依存関係を避けるために、xml-ph-0002@deepl.internalが使用されています。読み込みに失敗した場合、コンポジターは通常通り動作を続けますが、画面上のキーボードはサポートされなくなります。
最後に、コンポジターがテキスト入力をクライアントに伝達する手段が必要です。これはtext-input 拡張機能を通じて行われます。Fancy Compositorのサンプルでは、text_input_unstable_v2 プロトコルとQtのqt_text_input_method_unstable_v1 プロトコルの両方をサポートしています。
qt_text_input_method_unstable_v1 拡張機能は、QtTextInputMethodManager をWaylandCompositor の子としてインスタンス化することでコンポジターに追加され、TextInputManager はtext_input_unstable_v2 を追加します。
新しいQtアプリケーションは、qt_text_input_method_unstable_v1 が利用可能な場合はそれを優先しますが、その他のクライアントはtext_input_unstable_v2 を使用できます。
遷移
基本的な機能に加え、Fancy Compositor のサンプルでは、状態間のアニメーションによる遷移も実演しています。
その最初の例が、アクティベーションの遷移です。これは、XdgShell でのみサポートされています。これは、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 }
}
}XdgShell プロトコル下でクライアントウィンドウがアクティブになると、200 ミリ秒間ウィンドウが「飛び出す」ようなアニメーションをトリガーします。
Fancy Compositorは、破棄アニメーションもサポートしています。これは、クライアントが正常にウィンドウを閉じた場合でも、クラッシュした場合でも、ウィンドウが閉じられサーフェスが破棄されるたびにトリガーされます。
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() }
}アニメーションの再生中、コンテンツが確実に存在し続けるようにするため、まずバッファをロックします。これにより、クライアントによってレンダリングされた最後のフレームは、処理が完了するまでメモリ内に保持されます。
ここでも、アイテムのスケールに合わせてアニメーションをトリガーします。このアニメーションは、CRT ディスプレイの電源を切る様子を模しており、ウィンドウが単に跡形もなく消えたのではなく、閉じつつあることをユーザーに視覚的に伝えます。
このような状態変化には、Qt Quick の全機能を活用して、あらゆる種類のアニメーション効果を使用できます。
© 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.