// 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 * * 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. 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}{qt_generate_wayland_protocol_server_sources()} and * \l{qt_generate_wayland_protocol_client_sources}{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. */