Revision control

++ // Copyright (C) 2023 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
++
++ /*!
++ * \title Custom Extension
++ * \example custom-extension
++ * \examplecategory {Embedded}
++ * \brief Custom Extension shows how to implement a custom Wayland extension.
++ * \ingroup qtwaylandcompositor-examples
++ *
++ * It's easy to write new extensions for Wayland. They are defined using a XML-based format and
++ * the \c wayland-scanner tool converts this to glue code in C. Qt expands on this with the
++ * \c qtwaylandscanner, which generates additional glue code in Qt and C++.
++ *
++ * \image custom-extension.png {Custom compositor with two client windows
++ * labeled "QML Client" and "C++ Client", with colored panels for spin
++ * and bounce requests}
++ *
++ * The Custom Extension example shows how to use these tools to extend the Wayland protocol and
++ * send custom requests and events between a Wayland client and a server.
++ *
++ * The example consists of four items:
++ * \list
++ * \li The definition of the protocol itself.
++ * \li A compositor that supports the extension.
++ * \li A C++-based client that supports the extension.
++ * \li A QML-based client that supports the extension.
++ * \endlist
++ *
++ * \section1 The Protocol Definition
++ *
++ * The XML file \c custom.xml defines the protocol. The file's base name must match the \c name
++ * attribute of its root (\c protocol) element. It contains an interface called
++ * "qt_example_extension". This is the name which will be broadcast from the server and which the
++ * client will attach to in order to send requests and receive events. This name should be unique,
++ * so it is good to use a prefix that sets it apart from official interfaces.
++ *
++ * An interface typically consists of two types of remote procedure calls:
++ * \e requests and \e events. "Requests" are calls the client makes on the server-side, and
++ * "events" are calls the server makes on the client-side.
++ *
++ * The example extension contains a set of \e requests which instructs the server to apply certain
++ * transforms to the client window. For instance, if the client sends a "bounce" request, then the
++ * server should respond to this by making the window bounce on the screen.
++ *
++ * Similarly, it has a set of \e events which the server can use to provide instructions for the
++ * client. For instance, the "set_font_size" event is an instruction for the client to set its
++ * default font size to a specific size.
++ *
++ * The protocol defines the existence of requests and events, as well as the arguments they
++ * take. When \c qtwaylandscanner is run on it, it will generate the code needed to marshall the
++ * procedure call and its arguments and to transmit this over the connection. On the other end, this
++ * becomes a call to a virtual function which can be implemented to provide the actual response.
++ *
++ * In order to have \c qtwaylandscanner run automatically as part of the build, we use the
++ * CMake functions \l qt_generate_wayland_protocol_server_sources() and
++ * \l qt_generate_wayland_protocol_client_sources() for generating the server-side and
++ * client-side glue code, respectively. (When using \c qmake, the \c WAYLANDSERVERSOURCES and
++ * \c WAYLANDCLIENTSOURCES variables achieve the same.)
++ *
++ * \section1 The Compositor Implementation
++ *
++ * The Compositor application itself is implemented using QML and Qt Quick, but the extension is
++ * implemented in C++.
++ *
++ * The first step is to create a subclass of the glue code generated by \c qtwaylandscanner so
++ * that we can access its functionality. We add the \l QML_ELEMENT macro to the class in order to
++ * make it accessible from QML.
++ *
++ * \snippet custom-extension/compositor/customextension.h CustomExtension
++ *
++ * In addition to inheriting from the generated class, we also inherit the class
++ * \l QWaylandCompositorExtensionTemplate which provides some additional convenience when dealing
++ * with extensions, using the
++ * \l{https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern}{Curiously Recurring Template Pattern}.
++ *
++ * Note that the \l QWaylandCompositorExtensionTemplate must be first in the inheritance list, since
++ * it is a \l{QObject}-based class.
++ *
++ * The subclass has re-implementations of virtual functions in the generated base class, where
++ * we can handle requests issued by a client.
++ *
++ * \snippet custom-extension/compositor/customextension.h example_extension_bounce
++ *
++ * In these re-implementations, we simply translate the request to a \e signal emission, so that we
++ * can handle it in the actual QML code of the compositor.
++ *
++ * \snippet custom-extension/compositor/customextension.cpp example_extension_bounce
++ *
++ * In addition, the subclass defines \e slots for each of the events, so that these can be either
++ * called from QML or be connected to signals. The slots simply call the generated functions which
++ * send the events to the client.
++ *
++ * \snippet custom-extension/compositor/customextension.cpp setFontSize
++ *
++ * Since we added the \l QML_ELEMENT macro to the class definition (and added the corresponding
++ * build steps to the build system files), it can be instantiated in QML.
++ *
++ * We make it a direct child of the \l WaylandCompositor object in order for the compositor to
++ * register it as an extension.
++ *
++ * \snippet custom-extension/compositor/qml/main.qml CustomExtension
++ *
++ * The object has signal handlers for the requests it may get from the client and reacts to them
++ * accordingly. In addition, we can call its slots to send events.
++ *
++ * \snippet custom-extension/compositor/qml/main.qml setFontSize
++ *
++ * \section1 The C++ Client Implementation
++ *
++ * Both clients share the C++ implementation of the interface. Like in the compositor, we make
++ * a subclass of the generated code which also inherits from a template class. In this case,
++ * we inherit QWaylandClientExtensionTemplate.
++ *
++ * \snippet custom-extension/client-common/customextension.h CustomExtension
++ *
++ * The approach is very similar to that of the compositor, except inverted: Requests are implemented
++ * as slots which call the generated functions, and events virtual functions which we re-implement
++ * to emit signals.
++ *
++ * \snippet custom-extension/client-common/customextension.cpp sendBounce
++ *
++ * The client code itself is very simple and only intended to show how to trigger the behavior. In
++ * a custom paint event, it draws a set of rectangles and labels. When any of these are clicked, it
++ * issues requests to the server.
++ *
++ * \snippet custom-extension/cpp-client/main.cpp mousePressEvent
++ *
++ * To update the font size when the \c set_font_size event is received, the signal in our extension
++ * class is connected to a slot.
++ *
++ * \snippet custom-extension/cpp-client/main.cpp connection
++ *
++ * The slot will update the font size and repaint the window.
++ *
++ * \section1 The QML Client Implementation
++ *
++ * The QML client is similar to the C++ client. It relies on the same implementation of the custom
++ * extension as the C++ client, and instantiates this in QML to enable it.
++ *
++ * \snippet custom-extension/qml-client/main.qml CustomExtension
++ *
++ * The UI consists of some clickable rectangles, and uses \l TapHandler to send the corresponding
++ * requests when a rectangle is clicked.
++ *
++ * \snippet custom-extension/qml-client/main.qml sendBounce
++ *
++ * For simplicity, the example has been limited to only demonstrate the \c bounce and \c spin
++ * requests as well as the \c set_font_size event. Adding support for the additional features is
++ * left as an exercise for the reader.
++ */