From 1d346f87002b72bced7c5522742e5c282d65a802 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 11 May 2021 12:44:34 +0200 Subject: doc: Expand documentation of Pure QML example Add details about what customizations are specific to this example. Task-number: QTBUG-91674 Change-Id: Icf2dd4fb2bcbd230bbadbb01e5a57f481ad178eb Reviewed-by: Paul Olav Tvete Reviewed-by: Eskil Abrahamsen Blomfeldt (cherry picked from commit ea929b6fa5a90602e6f1fb597e3edfed9e6de3a7) Reviewed-by: Paul Wicking --- examples/wayland/pure-qml/doc/src/pure-qml.qdoc | 101 ++++++++++++++++++++- examples/wayland/pure-qml/qml/Chrome.qml | 28 +++--- examples/wayland/pure-qml/qml/CompositorScreen.qml | 6 ++ examples/wayland/pure-qml/qml/Keyboard.qml | 2 + examples/wayland/pure-qml/qml/main.qml | 4 + src/compositor/doc/qtwaylandcompositor.qdocconf | 2 +- 6 files changed, 127 insertions(+), 16 deletions(-) diff --git a/examples/wayland/pure-qml/doc/src/pure-qml.qdoc b/examples/wayland/pure-qml/doc/src/pure-qml.qdoc index 06a938bed..90aa9d1d5 100644 --- a/examples/wayland/pure-qml/doc/src/pure-qml.qdoc +++ b/examples/wayland/pure-qml/doc/src/pure-qml.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -31,6 +31,101 @@ \brief Pure QML is an example that demonstrates how to write a Wayland compositor in pure QML. \ingroup qtwaylandcompositor-examples - Pure QML is a small desktop-style Wayland compositor example that demonstrates the power and ease - of the Qt Wayland Compositor QML APIs. + \section1 Introduction + + Pure QML is a small desktop-style Wayland compositor example that demonstrates the power and + ease of the \l{Qt Wayland Compositor} QML APIs. + + The Pure QML example is similar to the + \l{Qt Wayland Compositor Examples - Minimal QML}{Minimal QML example}, in that it is a + full-blown Wayland compositor, implemented only using QML code. + + \section1 Initializing the Compositor + + Like the \l{Qt Wayland Compositor Examples - Minimal QML}{Minimal QML example}, Pure QML + supports the main \l{Shell Extensions - Qt Wayland Compositor}{shell extensions} that are + supported by Qt. + + \snippet pure-qml/qml/main.qml shell extensions + + These are instantiated as children of the \l{WaylandCompositor} which automatically adds + them to the list of supported interfaces which is broadcasted to clients from the server. + + When a connected client creates a surface and binds it to one of the shell extensions, the + corresponding signal is emitted. This then calls a method inside our custom \l WaylandOutput + class, which appends the \l ShellSurface to a \l{ListModel}. + + \snippet pure-qml/qml/CompositorScreen.qml handleShellSurface + + This model is used as the source for a \l Repeater which creates + \l{ShellSurfaceItem}{ShellSurfaceItems} inside the compositor's \l WaylandOutput. This adds a + view of the surface in the Qt Quick scene. Since it is a \l{ShellSurfaceItem}, it also has + certain interaction options for the user of the compositor, depending on which shell extension + is in use. + + \snippet pure-qml/qml/CompositorScreen.qml repeater + + \section1 Keyboard + + In addition to the basic windowing system functions, the Pure QML compositor also supports an + optional on-screen keyboard running in-process. This uses the \l{Qt Virtual Keyboard} module, + and will be enabled if the module is available. + + \snippet pure-qml/qml/Keyboard.qml keyboard + + The code is simple. We instantiate an \l InputPanel in the bottom of the output, and make sure + it is visible if and only if it is currently active. + + \snippet pure-qml/qml/CompositorScreen.qml keyboard + + The keyboard is then added to the \l WaylandOutput using a \l Loader element. The \l Loader is + used here to avoid having a hard dependency on the \l{Qt Virtual Keyboard} module. If loading + fails, then the compositor will continue operating normally, but without support for an + on-screen keyboard. + + Finally, we need a way for the compositor to communicate the text input to its clients. This + is done via a \c{text-input} extension. The Pure QML example only supports the + \c{qt_text_input_method_unstable_v1} protocol. + + \snippet pure-qml/qml/main.qml text input + + The extension is added to the compositor by instantiating the \l QtTextInputMethodManager as + a child of the \l{WaylandCompositor}. + + In order for the on-screen keyboard to work, this protocol must also be supported by the client. + Therefore, the \l QtTextInputMethodManager is most useful if the clients are also Qt + applications. + + \note Qt also supports \l{TextInputManager}, which is an implementation of the + \c{text_input_unstable_v2} protocol. + + \section1 Transitions + + In addition to the basic functionality, the Pure QML example also demonstrates animated + transitions between states. + + The first of these is the \e{activation} transition. This is only supported on the \l{XdgShell}, + since this is the only shell extension which has an \l{XdgTopLevel::activated}{activated} state. + + \snippet pure-qml/qml/Chrome.qml activation + + When a client window becomes activated under the \l XdgShell protocol, we trigger an animation + which makes the window "pop out" for 200 ms. + + The Pure QML compositor also supports a \e{destruction} animation. This triggers whenever the + window closes and surface is destroyed, whether this was because the client gracefully closed + its window, or even if it crashes. + + \snippet pure-qml/qml/Chrome.qml destruction + + To ensure that the content exists for the duration of the animation, we start by locking the + buffer. This means the final frame rendered by the client will remain in memory until we are + done with it. + + Again, we trigger an animation on the scale of the item. The animation in question imitates + turning off the power on a CRT screen, giving a visual clue to the user that the window is + closing, and didn't just vanish into thin air. + + Any sort of animated effect may be used for state changes such as these, with the full range + of Qt Quick at your disposal. */ diff --git a/examples/wayland/pure-qml/qml/Chrome.qml b/examples/wayland/pure-qml/qml/Chrome.qml index d9ff038c0..201fa5241 100644 --- a/examples/wayland/pure-qml/qml/Chrome.qml +++ b/examples/wayland/pure-qml/qml/Chrome.qml @@ -58,11 +58,25 @@ ShellSurfaceItem { signal destroyAnimationFinished + // ![destruction] 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() } + } + // ![destruction] + transform: [ Scale { id: scaleTransform @@ -71,6 +85,7 @@ ShellSurfaceItem { } ] + // ![activation] Connections { target: shellSurface.toplevel !== undefined ? shellSurface.toplevel : null @@ -84,18 +99,6 @@ ShellSurfaceItem { } } - 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() } - } - SequentialAnimation { id: receivedFocusAnimation @@ -108,4 +111,5 @@ ShellSurfaceItem { NumberAnimation { target: scaleTransform; property: "xScale"; to: 1; duration: 100; easing.type: Easing.InOutQuad } } } + // ![activation] } diff --git a/examples/wayland/pure-qml/qml/CompositorScreen.qml b/examples/wayland/pure-qml/qml/CompositorScreen.qml index 79dee6a2f..ba61f2053 100644 --- a/examples/wayland/pure-qml/qml/CompositorScreen.qml +++ b/examples/wayland/pure-qml/qml/CompositorScreen.qml @@ -58,9 +58,11 @@ WaylandOutput { property ListModel shellSurfaces: ListModel {} property bool isNestedCompositor: Qt.platform.pluginName.startsWith("wayland") || Qt.platform.pluginName === "xcb" + // ![handleShellSurface] function handleShellSurface(shellSurface) { shellSurfaces.append({shellSurface: shellSurface}); } + // ![handleShellSurface] // During development, it can be useful to start the compositor inside X11 or // another Wayland compositor. In such cases, set sizeFollowsWindow to true to @@ -91,6 +93,7 @@ WaylandOutput { source: "qrc:/images/background.jpg" smooth: true + // ![repeater] Repeater { model: output.shellSurfaces // Chrome displays a shell surface on the screen (See Chrome.qml) @@ -99,13 +102,16 @@ WaylandOutput { onDestroyAnimationFinished: output.shellSurfaces.remove(index) } } + // ![repeater] } // Virtual Keyboard + // ![keyboard] Loader { anchors.fill: parent source: "Keyboard.qml" } + // ![keyboard] // Draws the mouse cursor for a given Wayland seat WaylandCursorItem { diff --git a/examples/wayland/pure-qml/qml/Keyboard.qml b/examples/wayland/pure-qml/qml/Keyboard.qml index 9f336e942..aedc6e620 100644 --- a/examples/wayland/pure-qml/qml/Keyboard.qml +++ b/examples/wayland/pure-qml/qml/Keyboard.qml @@ -48,6 +48,7 @@ ** ****************************************************************************/ +// ![keyboard] import QtQuick import QtQuick.VirtualKeyboard @@ -57,4 +58,5 @@ InputPanel { anchors.left: parent.left anchors.right: parent.right } +// ![keyboard] diff --git a/examples/wayland/pure-qml/qml/main.qml b/examples/wayland/pure-qml/qml/main.qml index dffb81b3e..5a0f324ec 100644 --- a/examples/wayland/pure-qml/qml/main.qml +++ b/examples/wayland/pure-qml/qml/main.qml @@ -59,6 +59,7 @@ WaylandCompositor { CompositorScreen { id: screen; compositor: waylandCompositor } + // ![shell extensions] // Shell surface extension. Needed to provide a window concept for Wayland clients. // I.e. requests and events for maximization, minimization, resizing, closing etc. XdgShell { @@ -74,7 +75,10 @@ WaylandCompositor { WlShell { onWlShellSurfaceCreated: screen.handleShellSurface(shellSurface) } + // ![shell extensions] // Extension for Input Method (QT_IM_MODULE) support at compositor-side + // ![text input] QtTextInputMethodManager {} + // ![text input] } diff --git a/src/compositor/doc/qtwaylandcompositor.qdocconf b/src/compositor/doc/qtwaylandcompositor.qdocconf index 67dae52b7..62f9bd90e 100644 --- a/src/compositor/doc/qtwaylandcompositor.qdocconf +++ b/src/compositor/doc/qtwaylandcompositor.qdocconf @@ -31,7 +31,7 @@ qhp.QtWaylandCompositor.subprojects.examples.indexTitle = Qt Wayland Composi qhp.QtWaylandCompositor.subprojects.examples.selectors = fake:example qhp.QtWaylandCompositor.subprojects.examples.sortPages = true -depends += qtcore qtqml qtquick qtdoc qtquickcontrols qmake qtgui qtqmlmodels qtwidgets +depends += qtcore qtqml qtquick qtdoc qtquickcontrols qmake qtgui qtqmlmodels qtwidgets qtvirtualkeyboard exampledirs += ../../../examples/wayland headerdirs += .. -- cgit v1.2.3