diff options
author | Pier Luigi Fiorini <pierluigi.fiorini@liri.io> | 2019-01-16 08:34:11 +0100 |
---|---|---|
committer | Pier Luigi Fiorini <pierluigi.fiorini@liri.io> | 2019-08-26 09:31:32 +0200 |
commit | 8b3a2124c97358d1e57089fc86818965e9a28497 (patch) | |
tree | abac6c8a96a9821ec57af04601553a45b130624f | |
parent | 622b55e918bfc877c10f8885754b30b593d334a5 (diff) | |
download | qtwayland-8b3a2124c97358d1e57089fc86818965e9a28497.tar.gz |
Compositor: Add xdg-output unstable v1 support
We already have a client-side implementation in the QPA plugin,
and now we add the server-side implementation.
In order to have a nice declarative API, we let users create a
XdgOutputV1 instance and then associate it with the zxdg_output_v1
object when it is requested by the client.
If the user forgets to create XdgOutputV1 beforehand we post an error to
the client.
To anticipate protocol version 3, we send zxdg_output_v1.done when we
send wl_output.done.
The multi-output example is extended using this protocol.
[ChangeLog][Compositor] Added support for xdg-output unstable v1
Wayland extension.
Change-Id: I1ec5913d8330cc01d7d634d05a289f4dc8b4fd22
Reviewed-by: Johan Helsing <johan.helsing@qt.io>
20 files changed, 1228 insertions, 7 deletions
diff --git a/examples/wayland/multi-output/qml/GridScreen.qml b/examples/wayland/multi-output/qml/GridScreen.qml index 340291af..a59cb8fb 100644 --- a/examples/wayland/multi-output/qml/GridScreen.qml +++ b/examples/wayland/multi-output/qml/GridScreen.qml @@ -50,7 +50,7 @@ import QtQuick 2.0 import QtQuick.Window 2.2 -import QtWayland.Compositor 1.0 +import QtWayland.Compositor 1.14 WaylandOutput { id: output @@ -93,4 +93,12 @@ WaylandOutput { } } } + + XdgOutputV1 { + name: "WL-2" + description: "Overview screen" + logicalPosition: output.position + logicalSize: Qt.size(output.geometry.width / output.scaleFactor, + output.geometry.height / output.scaleFactor) + } } diff --git a/examples/wayland/multi-output/qml/ShellScreen.qml b/examples/wayland/multi-output/qml/ShellScreen.qml index 4482e6e8..aa9b4b29 100644 --- a/examples/wayland/multi-output/qml/ShellScreen.qml +++ b/examples/wayland/multi-output/qml/ShellScreen.qml @@ -50,7 +50,7 @@ import QtQuick 2.0 import QtQuick.Window 2.2 -import QtWayland.Compositor 1.0 +import QtWayland.Compositor 1.14 WaylandOutput { id: output @@ -84,4 +84,12 @@ WaylandOutput { } } } + + XdgOutputV1 { + name: "WL-1" + description: "Screen with window management" + logicalPosition: output.position + logicalSize: Qt.size(output.geometry.width / output.scaleFactor, + output.geometry.height / output.scaleFactor) + } } diff --git a/examples/wayland/multi-output/qml/main.qml b/examples/wayland/multi-output/qml/main.qml index d01def55..45f91fd6 100644 --- a/examples/wayland/multi-output/qml/main.qml +++ b/examples/wayland/multi-output/qml/main.qml @@ -49,7 +49,7 @@ ****************************************************************************/ import QtQuick 2.0 -import QtWayland.Compositor 1.0 +import QtWayland.Compositor 1.14 WaylandCompositor { id: comp @@ -91,6 +91,8 @@ WaylandCompositor { } } + XdgOutputManagerV1 {} + WlShell { id: defaultShell diff --git a/src/3rdparty/protocol/qt_attribution.json b/src/3rdparty/protocol/qt_attribution.json index e6f90698..c49ead4f 100644 --- a/src/3rdparty/protocol/qt_attribution.json +++ b/src/3rdparty/protocol/qt_attribution.json @@ -127,8 +127,9 @@ Copyright (c) 2013 BMW Car IT GmbH" "Id": "wayland-xdg-output-protocol", "Name": "Wayland XDG Output Protocol", "QDocModule": "qtwaylandcompositor", - "QtUsage": "Used in the Qt Wayland platform plugin.", + "QtUsage": "Used in the Qt Wayland Compositor API, and the Qt Wayland platform plugin.", "Files": "xdg-output-unstable-v1.xml", + "Description": "The XDG Output protocol is an extended way to describe output regions under Wayland", "Homepage": "https://wayland.freedesktop.org", "Version": "unstable v1, version 2", diff --git a/src/compositor/compositor_api/qwaylandoutput.cpp b/src/compositor/compositor_api/qwaylandoutput.cpp index 7a02d4ca..601f692a 100644 --- a/src/compositor/compositor_api/qwaylandoutput.cpp +++ b/src/compositor/compositor_api/qwaylandoutput.cpp @@ -48,6 +48,7 @@ #include <QtWaylandCompositor/private/qwaylandcompositor_p.h> #include <QtWaylandCompositor/private/qwaylandview_p.h> #include <QtWaylandCompositor/private/qwaylandutils_p.h> +#include <QtWaylandCompositor/private/qwaylandxdgoutputv1_p.h> #include <QtCore/QCoreApplication> #include <QtCore/QtMath> @@ -162,6 +163,9 @@ void QWaylandOutputPrivate::sendGeometryInfo() if (resource->version() >= 2) send_done(resource->handle); } + + if (xdgOutput) + QWaylandXdgOutputV1Private::get(xdgOutput)->sendDone(); } void QWaylandOutputPrivate::sendMode(const Resource *resource, const QWaylandOutputMode &mode) @@ -185,6 +189,9 @@ void QWaylandOutputPrivate::sendModesInfo() if (resource->version() >= 2) send_done(resource->handle); } + + if (xdgOutput) + QWaylandXdgOutputV1Private::get(xdgOutput)->sendDone(); } void QWaylandOutputPrivate::handleWindowPixelSizeChanged() @@ -840,6 +847,9 @@ void QWaylandOutput::setScaleFactor(int scale) } Q_EMIT scaleFactorChanged(); + + if (d->xdgOutput) + QWaylandXdgOutputV1Private::get(d->xdgOutput)->sendDone(); } /*! diff --git a/src/compositor/compositor_api/qwaylandoutput_p.h b/src/compositor/compositor_api/qwaylandoutput_p.h index 4badd379..58188ac3 100644 --- a/src/compositor/compositor_api/qwaylandoutput_p.h +++ b/src/compositor/compositor_api/qwaylandoutput_p.h @@ -57,6 +57,7 @@ #include <QtWaylandCompositor/QWaylandOutput> #include <QtWaylandCompositor/QWaylandClient> #include <QtWaylandCompositor/QWaylandSurface> +#include <QtWaylandCompositor/QWaylandXdgOutputV1> #include <QtWaylandCompositor/private/qwayland-server-wayland.h> @@ -110,6 +111,8 @@ public: void handleWindowPixelSizeChanged(); + QPointer<QWaylandXdgOutputV1> xdgOutput; + protected: void output_bind_resource(Resource *resource) override; @@ -137,6 +140,8 @@ private: Q_DECLARE_PUBLIC(QWaylandOutput) Q_DISABLE_COPY(QWaylandOutputPrivate) + + friend class QWaylandXdgOutputManagerV1Private; }; diff --git a/src/compositor/extensions/extensions.pri b/src/compositor/extensions/extensions.pri index c1a9f788..61ab043e 100644 --- a/src/compositor/extensions/extensions.pri +++ b/src/compositor/extensions/extensions.pri @@ -14,6 +14,7 @@ WAYLANDSERVERSOURCES += \ ../3rdparty/protocol/xdg-shell-unstable-v6.xml \ ../3rdparty/protocol/xdg-shell.xml \ ../3rdparty/protocol/xdg-decoration-unstable-v1.xml \ + ../3rdparty/protocol/xdg-output-unstable-v1.xml \ ../3rdparty/protocol/ivi-application.xml \ ../3rdparty/protocol/idle-inhibit-unstable-v1.xml \ @@ -42,6 +43,8 @@ HEADERS += \ extensions/qwaylandxdgshell_p.h \ extensions/qwaylandxdgdecorationv1.h \ extensions/qwaylandxdgdecorationv1_p.h \ + extensions/qwaylandxdgoutputv1.h \ + extensions/qwaylandxdgoutputv1_p.h \ extensions/qwaylandshellsurface.h \ extensions/qwaylandidleinhibitv1.h \ extensions/qwaylandidleinhibitv1_p.h \ @@ -64,6 +67,7 @@ SOURCES += \ extensions/qwaylandxdgshellv6.cpp \ extensions/qwaylandxdgshell.cpp \ extensions/qwaylandxdgdecorationv1.cpp \ + extensions/qwaylandxdgoutputv1.cpp \ extensions/qwaylandshellsurface.cpp \ extensions/qwaylandidleinhibitv1.cpp \ extensions/qwaylandiviapplication.cpp \ @@ -76,6 +80,7 @@ qtHaveModule(quick) { extensions/qwaylandquickshellsurfaceitem_p.h \ extensions/qwaylandivisurfaceintegration_p.h \ extensions/qwaylandwlshellintegration_p.h \ + extensions/qwaylandquickxdgoutputv1.h \ extensions/qwaylandxdgshellv5integration_p.h \ extensions/qwaylandxdgshellv6integration_p.h \ extensions/qwaylandxdgshellintegration_p.h \ @@ -85,6 +90,7 @@ qtHaveModule(quick) { extensions/qwaylandquickshellsurfaceitem.cpp \ extensions/qwaylandivisurfaceintegration.cpp \ extensions/qwaylandwlshellintegration.cpp \ + extensions/qwaylandquickxdgoutputv1.cpp \ extensions/qwaylandxdgshellv5integration.cpp \ extensions/qwaylandxdgshellv6integration.cpp \ extensions/qwaylandxdgshellintegration.cpp \ diff --git a/src/compositor/extensions/qwaylandquickxdgoutputv1.cpp b/src/compositor/extensions/qwaylandquickxdgoutputv1.cpp new file mode 100644 index 00000000..eb6717a7 --- /dev/null +++ b/src/compositor/extensions/qwaylandquickxdgoutputv1.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QWaylandCompositor> +#include <QWaylandOutput> + +#include "qwaylandquickxdgoutputv1.h" +#include "qwaylandxdgoutputv1_p.h" + +QWaylandQuickXdgOutputV1::QWaylandQuickXdgOutputV1() + : QWaylandXdgOutputV1() +{ +} + +void QWaylandQuickXdgOutputV1::componentComplete() +{ + // Try to find the manager from the compositor extensions + if (!manager()) { + for (auto *p = parent(); p != nullptr; p = p->parent()) { + if (auto *c = qobject_cast<QWaylandCompositor *>(p)) { + for (auto *extension : c->extensions()) { + if (auto *m = qobject_cast<QWaylandXdgOutputManagerV1 *>(extension)) { + QWaylandXdgOutputV1Private::get(this)->setManager(m); + break; + } + } + } + } + } + + // Try to find the output from the parents + if (!output()) { + for (auto *p = parent(); p != nullptr; p = p->parent()) { + if (auto *o = qobject_cast<QWaylandOutput *>(p)) { + QWaylandXdgOutputV1Private::get(this)->setOutput(o); + break; + } + } + } +} diff --git a/src/compositor/extensions/qwaylandquickxdgoutputv1.h b/src/compositor/extensions/qwaylandquickxdgoutputv1.h new file mode 100644 index 00000000..c8b16ab8 --- /dev/null +++ b/src/compositor/extensions/qwaylandquickxdgoutputv1.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDQUICKXDGOUTPUT_V1 +#define QWAYLANDQUICKXDGOUTPUT_V1 + +#include <QtQml/QQmlListProperty> +#include <QtQml/QQmlParserStatus> +#include <QtWaylandCompositor/QWaylandXdgOutputV1> + +QT_BEGIN_NAMESPACE + +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandQuickXdgOutputV1 + : public QWaylandXdgOutputV1 + , public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) +public: + explicit QWaylandQuickXdgOutputV1(); + +protected: + void classBegin() override {} + void componentComplete() override; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDQUICKXDGOUTPUT_V1 diff --git a/src/compositor/extensions/qwaylandxdgoutputv1.cpp b/src/compositor/extensions/qwaylandxdgoutputv1.cpp new file mode 100644 index 00000000..2ab26c16 --- /dev/null +++ b/src/compositor/extensions/qwaylandxdgoutputv1.cpp @@ -0,0 +1,595 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QWaylandCompositor> + +#include "qwaylandxdgoutputv1_p.h" +#include "qwaylandoutput_p.h" + +#include <wayland-server.h> + +QT_BEGIN_NAMESPACE + +/*! + * \qmltype XdgOutputManagerV1 + * \inqmlmodule QtWayland.Compositor + * \since 5.14 + * \brief Provides an extension for describing outputs in a desktop oriented fashion + * + * The XdgOutputManagerV1 extension provides a way for a compositor to describe outputs in a way + * that is more in line with the concept of an output on desktop oriented systems. + * + * Some information may not make sense in other applications such as IVI systems. + * + * Typically the global compositor space on a desktop system is made of a + * contiguous or overlapping set of rectangular regions. + * + * XdgOutputManagerV1 corresponds to the Wayland interface, \c zxdg_output_manager_v1. + * + * To provide the functionality of the extension in a compositor, create an instance of the + * XdgOutputManagerV1 component and add it to the list of extensions supported by the compositor, + * and associated each XdgOutputV1 with its WaylandOutput: + * + * \qml \QtMinorVersion + * import QtWayland.Compositor 1.\1 + * + * WaylandCompositor { + * XdgOutputManagerV1 { + * WaylandOutput { + * id: output1 + * + * position: Qt.point(0, 0) + * window: Window {} + * + * XdgOutputV1 { + * name: "WL-1" + * logicalPosition: output1.position + * logicalSize: Qt.size(output1.geometry.width / output1.scaleFactor, + * output1.geometry.height / output1.scaleFactor) + * } + * } + * + * WaylandOutput { + * id: output2 + * + * position: Qt.point(800, 0) + * window: Window {} + * + * XdgOutputV1 { + * name: "WL-2" + * logicalPosition: output2.position + * logicalSize: Qt.size(output2.geometry.width / output2.scaleFactor, + * output2.geometry.height / output2.scaleFactor) + * } + * } + * } + * } + * \endqml + */ + +/*! + * \class QWaylandXdgOutputManagerV1 + * \inmodule QtWaylandCompositor + * \since 5.14 + * \brief Provides an extension for describing outputs in a desktop oriented fashion + * + * The QWaylandXdgOutputManagerV1 extension provides a way for a compositor to describe outputs in a way + * that is more in line with the concept of an output on desktop oriented systems. + * + * Some information may not make sense in other applications such as IVI systems. + * + * QWaylandXdgOutputManagerV1 corresponds to the Wayland interface, \c zxdg_output_manager_v1. + */ + +/*! + * Constructs a QWaylandXdgOutputManagerV1 object. + */ +QWaylandXdgOutputManagerV1::QWaylandXdgOutputManagerV1() + : QWaylandCompositorExtensionTemplate<QWaylandXdgOutputManagerV1>(*new QWaylandXdgOutputManagerV1Private()) +{ +} + +/*! + * Constructs a QWaylandXdgOutputManagerV1 object for the provided \a compositor. + */ +QWaylandXdgOutputManagerV1::QWaylandXdgOutputManagerV1(QWaylandCompositor *compositor) + : QWaylandCompositorExtensionTemplate<QWaylandXdgOutputManagerV1>(compositor, *new QWaylandXdgOutputManagerV1Private()) +{ +} + +// QWaylandXdgOutputManagerV1Private + +/*! + * Initializes the extension. + */ +void QWaylandXdgOutputManagerV1::initialize() +{ + Q_D(QWaylandXdgOutputManagerV1); + + QWaylandCompositorExtensionTemplate::initialize(); + QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer()); + if (!compositor) { + qCWarning(qLcWaylandCompositor) << "Failed to find QWaylandCompositor when initializing QWaylandXdgOutputManagerV1"; + return; + } + d->init(compositor->display(), d->interfaceVersion()); +} + +/*! + * Returns the Wayland interface for QWaylandXdgOutputManagerV1. + */ +const wl_interface *QWaylandXdgOutputManagerV1::interface() +{ + return QWaylandXdgOutputManagerV1Private::interface(); +} + +// QWaylandXdgOutputManagerV1Private + +void QWaylandXdgOutputManagerV1Private::registerXdgOutput(QWaylandOutput *output, QWaylandXdgOutputV1 *xdgOutput) +{ + if (!xdgOutputs.contains(output)) { + xdgOutputs[output] = xdgOutput; + QWaylandOutputPrivate::get(output)->xdgOutput = xdgOutput; + } +} + +void QWaylandXdgOutputManagerV1Private::unregisterXdgOutput(QWaylandOutput *output) +{ + xdgOutputs.remove(output); +} + +void QWaylandXdgOutputManagerV1Private::zxdg_output_manager_v1_get_xdg_output(Resource *resource, + uint32_t id, + wl_resource *outputResource) +{ + Q_Q(QWaylandXdgOutputManagerV1); + + // Verify if the associated output exist + auto *output = QWaylandOutput::fromResource(outputResource); + if (!output) { + qCWarning(qLcWaylandCompositor, + "The client is requesting a QWaylandXdgOutputV1 for a " + "QWaylandOutput that doesn't exist"); + wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "output not found"); + return; + } + + // Do we have a QWaylandXdgOutputV1 for this output? + if (!xdgOutputs.contains(output)) { + qCWarning(qLcWaylandCompositor, + "The client is requesting a QWaylandXdgOutputV1 that the compositor " + "didn't create before"); + wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, + "compositor didn't create a QWaylandXdgOutputV1 for this zxdg_output_v1 object"); + return; + } + + // Bind QWaylandXdgOutputV1 and initialize + auto *xdgOutput = xdgOutputs[output]; + auto *xdgOutputPrivate = QWaylandXdgOutputV1Private::get(xdgOutput); + Q_ASSERT(xdgOutputPrivate); + xdgOutputPrivate->setManager(q); + xdgOutputPrivate->setOutput(output); + xdgOutputPrivate->add(resource->client(), id, qMin(resource->version(), QWaylandXdgOutputV1Private::interfaceVersion())); +} + +// QWaylandXdgOutputV1 + +QWaylandXdgOutputV1::QWaylandXdgOutputV1() + : QObject(*new QWaylandXdgOutputV1Private) +{ +} + +QWaylandXdgOutputV1::QWaylandXdgOutputV1(QWaylandOutput *output, QWaylandXdgOutputManagerV1 *manager) + : QObject(*new QWaylandXdgOutputV1Private) +{ + Q_D(QWaylandXdgOutputV1); + + // Set members before emitting changed signals so that handlers will + // see both already set and not nullptr, avoiding potential crashes + d->manager = manager; + d->output = output; + + QWaylandXdgOutputManagerV1Private::get(d->manager)->registerXdgOutput(output, this); + + emit managerChanged(); + emit outputChanged(); +} + +QWaylandXdgOutputV1::~QWaylandXdgOutputV1() +{ + Q_D(QWaylandXdgOutputV1); + + if (d->manager) + QWaylandXdgOutputManagerV1Private::get(d->manager)->unregisterXdgOutput(d->output); +} + +/*! + * \qmlproperty XdgOutputManagerV1 QtWaylandCompositor::XdgOutputV1::manager + * \readonly + * + * This property holds the object that manages this XdgOutputV1. + */ +/*! + * \property QWaylandXdgOutputV1::manager + * \readonly + * + * This property holds the object that manages this QWaylandXdgOutputV1. + */ +QWaylandXdgOutputManagerV1 *QWaylandXdgOutputV1::manager() const +{ + Q_D(const QWaylandXdgOutputV1); + return d->manager; +} + +/*! + * \qmlproperty WaylandOutput QtWaylandCompositor::XdgOutputV1::output + * \readonly + * + * This property holds the WaylandOutput associated with this XdgOutputV1. + */ +/*! + * \property QWaylandXdgOutputV1::output + * \readonly + * + * This property holds the QWaylandOutput associated with this QWaylandXdgOutputV1. + */ +QWaylandOutput *QWaylandXdgOutputV1::output() const +{ + Q_D(const QWaylandXdgOutputV1); + return d->output; +} + +/*! + * \qmlproperty string QtWaylandCompositor::XdgOutputV1::name + * + * This property holds the name of this output. + * + * The naming convention is compositor defined, but limited to alphanumeric + * characters and dashes ("-"). Each name is unique and will also remain + * consistent across sessions with the same hardware and software configuration. + * + * Examples of names include "HDMI-A-1", "WL-1", "X11-1" etc... + * However don't assume the name reflects the underlying technology. + * + * Changing this property after initialization doesn't take effect. + */ +/*! + * \property QWaylandXdgOutputV1::name + * + * This property holds the name of this output. + * + * The naming convention is compositor defined, but limited to alphanumeric + * characters and dashes ("-"). Each name is unique and will also remain + * consistent across sessions with the same hardware and software configuration. + * + * Examples of names include "HDMI-A-1", "WL-1", "X11-1" etc... + * However don't assume the name reflects the underlying technology. + * + * Changing this property after initialization doesn't take effect. + */ +QString QWaylandXdgOutputV1::name() const +{ + Q_D(const QWaylandXdgOutputV1); + return d->name; +} + +void QWaylandXdgOutputV1::setName(const QString &name) +{ + Q_D(QWaylandXdgOutputV1); + + if (d->name == name) + return; + + // Can't change after clients bound to xdg-output + if (d->initialized) { + qCWarning(qLcWaylandCompositor, "QWaylandXdgOutputV1::name cannot be changed after initialization"); + return; + } + + d->name = name; + emit nameChanged(); +} + +/*! + * \qmlproperty string QtWaylandCompositor::XdgOutputV1::description + * + * This property holds the description of this output. + * + * No convention is defined for the description. + * + * Changing this property after initialization doesn't take effect. + */ +/*! + * \property QWaylandXdgOutputV1::description + * + * This property holds the description of this output. + * + * No convention is defined for the description. + * + * Changing this property after initialization doesn't take effect. + */ +QString QWaylandXdgOutputV1::description() const +{ + Q_D(const QWaylandXdgOutputV1); + return d->description; +} + +void QWaylandXdgOutputV1::setDescription(const QString &description) +{ + Q_D(QWaylandXdgOutputV1); + + if (d->description == description) + return; + + // Can't change after clients bound to xdg-output + if (d->initialized) { + qCWarning(qLcWaylandCompositor, "QWaylandXdgOutputV1::description cannot be changed after initialization"); + return; + } + + d->description = description; + emit descriptionChanged(); +} + +/*! + * \qmlproperty point QtWaylandCompositor::XdgOutputV1::logicalPosition + * + * This property holds the coordinates of the output within the global compositor space. + * + * The default value is 0,0. + */ +/*! + * \property QWaylandXdgOutputV1::logicalPosition + * + * This property holds the coordinates of the output within the global compositor space. + * + * The default value is 0,0. + */ +QPoint QWaylandXdgOutputV1::logicalPosition() const +{ + Q_D(const QWaylandXdgOutputV1); + return d->logicalPos; +} + +void QWaylandXdgOutputV1::setLogicalPosition(const QPoint &position) +{ + Q_D(QWaylandXdgOutputV1); + + if (d->logicalPos == position) + return; + + d->logicalPos = position; + if (d->initialized) { + d->sendLogicalPosition(position); + d->sendDone(); + } + emit logicalPositionChanged(); + emit logicalGeometryChanged(); +} + +/*! + * \qmlproperty size QtWaylandCompositor::XdgOutputV1::logicalSize + * + * This property holds the size of the output in the global compositor space. + * + * The default value is -1,-1 which is invalid. + * + * Please remember that this is the logical size, not the physical size. + * For example, for a WaylandOutput mode 3840x2160 and a scale factor 2: + * \list + * \li A compositor not scaling the surface buffers, will report a logical size of 3840x2160. + * \li A compositor automatically scaling the surface buffers, will report a logical size of 1920x1080. + * \li A compositor using a fractional scale of 1.5, will report a logical size of 2560x1620. + * \endlist + */ +/*! + * \property QWaylandXdgOutputV1::logicalSize + * + * This property holds the size of the output in the global compositor space. + * + * The default value is -1,-1 which is invalid. + * + * Please remember that this is the logical size, not the physical size. + * For example, for a WaylandOutput mode 3840x2160 and a scale factor 2: + * \list + * \li A compositor not scaling the surface buffers, will report a logical size of 3840x2160. + * \li A compositor automatically scaling the surface buffers, will report a logical size of 1920x1080. + * \li A compositor using a fractional scale of 1.5, will report a logical size of 2560x1620. + * \endlist + */ +QSize QWaylandXdgOutputV1::logicalSize() const +{ + Q_D(const QWaylandXdgOutputV1); + return d->logicalSize; +} + +void QWaylandXdgOutputV1::setLogicalSize(const QSize &size) +{ + Q_D(QWaylandXdgOutputV1); + + if (d->logicalSize == size) + return; + + d->logicalSize = size; + if (d->initialized) { + d->sendLogicalSize(size); + d->sendDone(); + } + emit logicalSizeChanged(); + emit logicalGeometryChanged(); +} + +/*! + * \qmlproperty rect QtWaylandCompositor::XdgOutputV1::logicalGeometry + * \readonly + * + * This property holds the position and size of the output in the global compositor space. + * It's the combination of the logical position and logical size. + * + * \sa XdgOutputV1::logicalPosition + * \sa XdgOutputV1::logicalSize + */ +/*! + * \property QWaylandXdgOutputV1::logicalGeometry + * \readonly + * + * This property holds the position and size of the output in the global compositor space. + * It's the combination of the logical position and logical size. + * + * \sa QWaylandXdgOutputV1::logicalPosition + * \sa QWaylandXdgOutputV1::logicalSize + */ +QRect QWaylandXdgOutputV1::logicalGeometry() const +{ + Q_D(const QWaylandXdgOutputV1); + return QRect(d->logicalPos, d->logicalSize); +} + +// QWaylandXdgOutputV1Private + +void QWaylandXdgOutputV1Private::sendLogicalPosition(const QPoint &position) +{ + const auto values = resourceMap().values(); + for (auto *resource : values) + send_logical_position(resource->handle, position.x(), position.y()); + needToSendDone = true; +} + +void QWaylandXdgOutputV1Private::sendLogicalSize(const QSize &size) +{ + const auto values = resourceMap().values(); + for (auto *resource : values) + send_logical_size(resource->handle, size.width(), size.height()); + needToSendDone = true; +} + +void QWaylandXdgOutputV1Private::sendDone() +{ + if (needToSendDone) { + const auto values = resourceMap().values(); + for (auto *resource : values) { + if (resource->version() < 3) + send_done(resource->handle); + } + needToSendDone = false; + } +} + +void QWaylandXdgOutputV1Private::setManager(QWaylandXdgOutputManagerV1 *_manager) +{ + Q_Q(QWaylandXdgOutputV1); + + if (!_manager) { + qCWarning(qLcWaylandCompositor, + "Cannot associate a null QWaylandXdgOutputManagerV1 to QWaylandXdgOutputV1 %p", this); + return; + } + + if (manager == _manager) + return; + + if (manager) { + qCWarning(qLcWaylandCompositor, + "Cannot associate a different QWaylandXdgOutputManagerV1 to QWaylandXdgOutputV1 %p " + "after initialization", this); + return; + } + + manager = _manager; + emit q->managerChanged(); +} + +void QWaylandXdgOutputV1Private::setOutput(QWaylandOutput *_output) +{ + Q_Q(QWaylandXdgOutputV1); + + if (!_output) { + qCWarning(qLcWaylandCompositor, + "Cannot associate a null QWaylandOutput to QWaylandXdgOutputV1 %p", this); + return; + } + + if (output == _output) + return; + + if (output) { + qCWarning(qLcWaylandCompositor, + "Cannot associate a different QWaylandOutput to QWaylandXdgOutputV1 %p " + "after initialization", this); + return; + } + + // Assign output above manager, to make both values valid in handlers + output = _output; + + if (!manager) { + // Try to find the manager from the output parents + for (auto *p = output->parent(); p != nullptr; p = p->parent()) { + if (auto *m = qobject_cast<QWaylandXdgOutputManagerV1 *>(p)) { + manager = m; + emit q->managerChanged(); + break; + } + } + } + + emit q->outputChanged(); + + // Register the output + if (manager) + QWaylandXdgOutputManagerV1Private::get(manager)->registerXdgOutput(output, q); +} + +void QWaylandXdgOutputV1Private::zxdg_output_v1_bind_resource(Resource *resource) +{ + send_logical_position(resource->handle, logicalPos.x(), logicalPos.y()); + send_logical_size(resource->handle, logicalSize.width(), logicalSize.height()); + if (resource->version() >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) + send_name(resource->handle, name); + if (resource->version() >= ZXDG_OUTPUT_V1_DESCRIPTION_SINCE_VERSION) + send_description(resource->handle, description); + send_done(resource->handle); + + initialized = true; +} + +void QWaylandXdgOutputV1Private::zxdg_output_v1_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +QT_END_NAMESPACE diff --git a/src/compositor/extensions/qwaylandxdgoutputv1.h b/src/compositor/extensions/qwaylandxdgoutputv1.h new file mode 100644 index 00000000..c5f03758 --- /dev/null +++ b/src/compositor/extensions/qwaylandxdgoutputv1.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDXDGOUTPUTV1_H +#define QWAYLANDXDGOUTPUTV1_H + +#include <QRect> +#include <QWaylandCompositorExtension> +#include <QtWaylandCompositor/qwaylandquickchildren.h> + +QT_BEGIN_NAMESPACE + +class QWaylandOutput; + +class QWaylandXdgOutputManagerV1Private; +class QWaylandXdgOutputV1Private; + +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgOutputManagerV1 + : public QWaylandCompositorExtensionTemplate<QWaylandXdgOutputManagerV1> +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QWaylandXdgOutputManagerV1) +public: + explicit QWaylandXdgOutputManagerV1(); + QWaylandXdgOutputManagerV1(QWaylandCompositor *compositor); + + void initialize() override; + + static const wl_interface *interface(); +}; + +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgOutputV1 : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QWaylandXdgOutputV1) + Q_WAYLAND_COMPOSITOR_DECLARE_QUICK_CHILDREN(QWaylandXdgOutputV1) + Q_PROPERTY(QWaylandXdgOutputManagerV1 *manager READ manager NOTIFY managerChanged) + Q_PROPERTY(QWaylandOutput *output READ output NOTIFY outputChanged) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged) + Q_PROPERTY(QPoint logicalPosition READ logicalPosition WRITE setLogicalPosition NOTIFY logicalPositionChanged) + Q_PROPERTY(QSize logicalSize READ logicalSize WRITE setLogicalSize NOTIFY logicalSizeChanged) + Q_PROPERTY(QRect logicalGeometry READ logicalGeometry NOTIFY logicalGeometryChanged) +public: + QWaylandXdgOutputV1(); + QWaylandXdgOutputV1(QWaylandOutput *output, QWaylandXdgOutputManagerV1 *manager); + ~QWaylandXdgOutputV1() override; + + QWaylandXdgOutputManagerV1 *manager() const; + QWaylandOutput *output() const; + + QString name() const; + void setName(const QString &name); + + QString description() const; + void setDescription(const QString &name); + + QPoint logicalPosition() const; + void setLogicalPosition(const QPoint &position); + + QSize logicalSize() const; + void setLogicalSize(const QSize &size); + + QRect logicalGeometry() const; + +Q_SIGNALS: + void managerChanged(); + void outputChanged(); + void logicalPositionChanged(); + void logicalSizeChanged(); + void logicalGeometryChanged(); + void nameChanged(); + void descriptionChanged(); +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDXDGOUTPUTV1_H diff --git a/src/compositor/extensions/qwaylandxdgoutputv1_p.h b/src/compositor/extensions/qwaylandxdgoutputv1_p.h new file mode 100644 index 00000000..2e8a6fff --- /dev/null +++ b/src/compositor/extensions/qwaylandxdgoutputv1_p.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDXDGOUTPUTV1_P_H +#define QWAYLANDXDGOUTPUTV1_P_H + +#include <QWaylandOutput> +#include <QWaylandXdgOutputV1> +#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h> +#include <QtWaylandCompositor/private/qwayland-server-xdg-output-unstable-v1.h> + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgOutputManagerV1Private + : public QWaylandCompositorExtensionPrivate + , public QtWaylandServer::zxdg_output_manager_v1 +{ + Q_DECLARE_PUBLIC(QWaylandXdgOutputManagerV1) +public: + explicit QWaylandXdgOutputManagerV1Private() = default; + + void registerXdgOutput(QWaylandOutput *output, QWaylandXdgOutputV1 *xdgOutput); + void unregisterXdgOutput(QWaylandOutput *output); + + static QWaylandXdgOutputManagerV1Private *get(QWaylandXdgOutputManagerV1 *manager) { return manager ? manager->d_func() : nullptr; } + +protected: + void zxdg_output_manager_v1_get_xdg_output(Resource *resource, uint32_t id, + wl_resource *outputResource) override; + +private: + QHash<QWaylandOutput *, QWaylandXdgOutputV1 *> xdgOutputs; +}; + +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgOutputV1Private + : public QObjectPrivate + , public QtWaylandServer::zxdg_output_v1 +{ + Q_DECLARE_PUBLIC(QWaylandXdgOutputV1) +public: + explicit QWaylandXdgOutputV1Private() = default; + + void sendLogicalPosition(const QPoint &position); + void sendLogicalSize(const QSize &size); + void sendDone(); + + void setManager(QWaylandXdgOutputManagerV1 *manager); + void setOutput(QWaylandOutput *output); + + static QWaylandXdgOutputV1Private *get(QWaylandXdgOutputV1 *xdgOutput) { return xdgOutput ? xdgOutput->d_func() : nullptr; } + + bool initialized = false; + QWaylandOutput *output = nullptr; + QWaylandXdgOutputManagerV1 *manager = nullptr; + QPoint logicalPos; + QSize logicalSize; + QString name; + QString description; + bool needToSendDone = false; + +protected: + void zxdg_output_v1_bind_resource(Resource *resource) override; + void zxdg_output_v1_destroy(Resource *resource) override; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDXDGOUTPUTV1_P_H diff --git a/src/imports/compositor/qwaylandquickcompositorplugin.cpp b/src/imports/compositor/qwaylandquickcompositorplugin.cpp index cd049331..223ca0bc 100644 --- a/src/imports/compositor/qwaylandquickcompositorplugin.cpp +++ b/src/imports/compositor/qwaylandquickcompositorplugin.cpp @@ -67,6 +67,7 @@ #include <QtWaylandCompositor/QWaylandXdgShell> #include <QtWaylandCompositor/QWaylandXdgDecorationManagerV1> #include <QtWaylandCompositor/QWaylandIdleInhibitManagerV1> +#include <QtWaylandCompositor/QWaylandQuickXdgOutputV1> #include <QtWaylandCompositor/QWaylandIviApplication> #include <QtWaylandCompositor/QWaylandIviSurface> @@ -87,6 +88,7 @@ Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandXdgShellV5) Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandXdgShellV6) Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandXdgShell) Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandXdgDecorationManagerV1) +Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandXdgOutputManagerV1) Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandTextInputManager) class QmlUrlResolver @@ -193,6 +195,9 @@ public: #endif qmlRegisterType<QWaylandIdleInhibitManagerV1QuickExtension>(uri, 1, 14, "IdleInhibitManagerV1"); + + qmlRegisterType<QWaylandXdgOutputManagerV1QuickExtension>(uri, 1, 14, "XdgOutputManagerV1"); + qmlRegisterType<QWaylandQuickXdgOutputV1>(uri, 1, 14, "XdgOutputV1"); } }; //![class decl] diff --git a/sync.profile b/sync.profile index be25721f..5c7ada91 100644 --- a/sync.profile +++ b/sync.profile @@ -68,6 +68,7 @@ "^qwayland-server-touch-extension.h", "^qwayland-server-viewporter.h", "^qwayland-server-xdg-decoration-unstable-v1.h", + "^qwayland-server-xdg-output-unstable-v1.h", "^qwayland-server-xdg-shell-unstable-v6.h", "^qwayland-server-xdg-shell.h", "^wayland-hardware-integration-server-protocol.h", @@ -83,6 +84,7 @@ "^wayland-touch-extension-server-protocol.h", "^wayland-wayland-server-protocol.h", "^wayland-xdg-decoration-unstable-v1-server-protocol.h", + "^wayland-xdg-output-unstable-v1-server-protocol.h", "^wayland-xdg-shell-server-protocol.h", "^wayland-xdg-shell-unstable-v6-server-protocol.h", ], diff --git a/tests/auto/compositor/compositor/compositor.pro b/tests/auto/compositor/compositor/compositor.pro index 8a364e52..27001659 100644 --- a/tests/auto/compositor/compositor/compositor.pro +++ b/tests/auto/compositor/compositor/compositor.pro @@ -15,7 +15,8 @@ WAYLANDCLIENTSOURCES += \ ../../../../src/3rdparty/protocol/wayland.xml \ ../../../../src/3rdparty/protocol/xdg-shell.xml \ ../../../../src/3rdparty/protocol/viewporter.xml \ - ../../../../src/3rdparty/protocol/idle-inhibit-unstable-v1.xml + ../../../../src/3rdparty/protocol/idle-inhibit-unstable-v1.xml \ + ../../../../src/3rdparty/protocol/xdg-output-unstable-v1.xml SOURCES += \ tst_compositor.cpp \ @@ -25,7 +26,8 @@ SOURCES += \ mockseat.cpp \ testseat.cpp \ mockkeyboard.cpp \ - mockpointer.cpp + mockpointer.cpp \ + mockxdgoutputv1.cpp HEADERS += \ testcompositor.h \ @@ -34,4 +36,5 @@ HEADERS += \ mockseat.h \ testseat.h \ mockkeyboard.h \ - mockpointer.h + mockpointer.h \ + mockxdgoutputv1.h diff --git a/tests/auto/compositor/compositor/mockclient.cpp b/tests/auto/compositor/compositor/mockclient.cpp index 4ae04998..27d1eed8 100644 --- a/tests/auto/compositor/compositor/mockclient.cpp +++ b/tests/auto/compositor/compositor/mockclient.cpp @@ -186,11 +186,17 @@ void MockClient::handleGlobal(uint32_t id, const QByteArray &interface) m_seats << new MockSeat(s); } else if (interface == "zwp_idle_inhibit_manager_v1") { idleInhibitManager = static_cast<zwp_idle_inhibit_manager_v1 *>(wl_registry_bind(registry, id, &zwp_idle_inhibit_manager_v1_interface, 1)); + } else if (interface == "zxdg_output_manager_v1") { + xdgOutputManager = new QtWayland::zxdg_output_manager_v1(registry, id, 2); } } void MockClient::handleGlobalRemove(uint32_t id) { + auto *output = m_outputs[id]; + if (m_xdgOutputs.contains(output)) + delete m_xdgOutputs.take(output); + m_outputs.remove(id); } @@ -234,6 +240,13 @@ zwp_idle_inhibitor_v1 *MockClient::createIdleInhibitor(wl_surface *surface) return idleInhibitor; } +MockXdgOutputV1 *MockClient::createXdgOutput(wl_output *output) +{ + auto *xdgOutput = new MockXdgOutputV1(xdgOutputManager->get_xdg_output(output)); + m_xdgOutputs[output] = xdgOutput; + return xdgOutput; +} + ShmBuffer::ShmBuffer(const QSize &size, wl_shm *shm) { int stride = size.width() * 4; diff --git a/tests/auto/compositor/compositor/mockclient.h b/tests/auto/compositor/compositor/mockclient.h index aa20a7ac..69a0e47c 100644 --- a/tests/auto/compositor/compositor/mockclient.h +++ b/tests/auto/compositor/compositor/mockclient.h @@ -38,6 +38,8 @@ #include <QList> #include <QWaylandOutputMode> +#include "mockxdgoutputv1.h" + class MockSeat; class ShmBuffer @@ -65,10 +67,12 @@ public: xdg_toplevel *createXdgToplevel(xdg_surface *xdgSurface); ivi_surface *createIviSurface(wl_surface *surface, uint iviId); zwp_idle_inhibitor_v1 *createIdleInhibitor(wl_surface *surface); + MockXdgOutputV1 *createXdgOutput(wl_output *output); wl_display *display = nullptr; wl_compositor *compositor = nullptr; QMap<uint, wl_output *> m_outputs; + QMap<wl_output *, MockXdgOutputV1 *> m_xdgOutputs; wl_shm *shm = nullptr; wl_registry *registry = nullptr; wl_shell *wlshell = nullptr; @@ -76,6 +80,7 @@ public: wp_viewporter *viewporter = nullptr; ivi_application *iviApplication = nullptr; zwp_idle_inhibit_manager_v1 *idleInhibitManager = nullptr; + QtWayland::zxdg_output_manager_v1 *xdgOutputManager = nullptr; QList<MockSeat *> m_seats; diff --git a/tests/auto/compositor/compositor/mockxdgoutputv1.cpp b/tests/auto/compositor/compositor/mockxdgoutputv1.cpp new file mode 100644 index 00000000..eebc55bb --- /dev/null +++ b/tests/auto/compositor/compositor/mockxdgoutputv1.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mockxdgoutputv1.h" + +MockXdgOutputV1::MockXdgOutputV1(struct ::zxdg_output_v1 *object) + : QtWayland::zxdg_output_v1(object) +{ +} + +MockXdgOutputV1::~MockXdgOutputV1() +{ + destroy(); +} + +void MockXdgOutputV1::zxdg_output_v1_logical_position(int32_t x, int32_t y) +{ + pending.logicalPosition = QPoint(x, y); +} + +void MockXdgOutputV1::zxdg_output_v1_logical_size(int32_t width, int32_t height) +{ + pending.logicalSize = QSize(width, height); +} + +void MockXdgOutputV1::zxdg_output_v1_done() +{ + // In version 3 we'll have to do this for wl_output.done as well + name = pending.name; + description = pending.description; + logicalPosition = pending.logicalPosition; + logicalSize = pending.logicalSize; +} + +void MockXdgOutputV1::zxdg_output_v1_name(const QString &name) +{ + pending.name = name; +} + +void MockXdgOutputV1::zxdg_output_v1_description(const QString &description) +{ + pending.description = description; +} diff --git a/tests/auto/compositor/compositor/mockxdgoutputv1.h b/tests/auto/compositor/compositor/mockxdgoutputv1.h new file mode 100644 index 00000000..db582069 --- /dev/null +++ b/tests/auto/compositor/compositor/mockxdgoutputv1.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MOCKXDGOUTPUTV1_H +#define MOCKXDGOUTPUTV1_H + +#include <QPoint> +#include <QSize> +#include <QString> + +#include "qwayland-xdg-output-unstable-v1.h" + +class MockXdgOutputV1 : public QtWayland::zxdg_output_v1 +{ +public: + explicit MockXdgOutputV1(struct ::zxdg_output_v1 *object); + ~MockXdgOutputV1(); + + QString name; + QString description; + QPoint logicalPosition; + QSize logicalSize; + + struct { + QString name; + QString description; + QPoint logicalPosition; + QSize logicalSize; + } pending; + +protected: + void zxdg_output_v1_logical_position(int32_t x, int32_t y) override; + void zxdg_output_v1_logical_size(int32_t width, int32_t height) override; + void zxdg_output_v1_done() override; + void zxdg_output_v1_name(const QString &name) override; + void zxdg_output_v1_description(const QString &description) override; +}; + +#endif // MOCKXDGOUTPUTV1_H diff --git a/tests/auto/compositor/compositor/tst_compositor.cpp b/tests/auto/compositor/compositor/tst_compositor.cpp index 28ec6c3e..f4f63228 100644 --- a/tests/auto/compositor/compositor/tst_compositor.cpp +++ b/tests/auto/compositor/compositor/tst_compositor.cpp @@ -29,6 +29,7 @@ #include "mockclient.h" #include "mockseat.h" #include "mockpointer.h" +#include "mockxdgoutputv1.h" #include "testcompositor.h" #include "testkeyboardgrabber.h" #include "testseat.h" @@ -48,8 +49,10 @@ #include <QtWaylandCompositor/QWaylandKeymap> #include <QtWaylandCompositor/QWaylandViewporter> #include <QtWaylandCompositor/QWaylandIdleInhibitManagerV1> +#include <QtWaylandCompositor/QWaylandXdgOutputManagerV1> #include <qwayland-xdg-shell.h> #include <qwayland-ivi-application.h> +#include <QtWaylandCompositor/private/qwaylandoutput_p.h> #include <QtWaylandCompositor/private/qwaylandsurface_p.h> #include <QtTest/QtTest> @@ -116,6 +119,8 @@ private slots: void viewportHiDpi(); void idleInhibit(); + + void xdgOutput(); }; void tst_WaylandCompositor::init() { @@ -1793,5 +1798,68 @@ void tst_WaylandCompositor::idleInhibit() QTRY_COMPARE(changedSpy.count(), 1); } +class XdgOutputCompositor : public TestCompositor +{ + Q_OBJECT +public: + XdgOutputCompositor() : xdgOutputManager(this) {} + QWaylandXdgOutputManagerV1 xdgOutputManager; +}; + +void tst_WaylandCompositor::xdgOutput() +{ + XdgOutputCompositor compositor; + compositor.create(); + + QWaylandOutputMode mode(QSize(1024, 768), 60000); + compositor.defaultOutput()->addMode(mode, true); + compositor.defaultOutput()->setCurrentMode(mode); + + MockClient client; + QTRY_VERIFY(client.xdgOutputManager); + QTRY_COMPARE(client.m_outputs.size(), 1); + + auto *wlOutput = client.m_outputs.first(); + QVERIFY(wlOutput); + + // Output is not associated yet + QCOMPARE(QWaylandOutputPrivate::get(compositor.defaultOutput())->xdgOutput.isNull(), true); + + // Create xdg-output on the server + auto *xdgOutputServer = new QWaylandXdgOutputV1(compositor.defaultOutput(), &compositor.xdgOutputManager); + QVERIFY(xdgOutputServer); + xdgOutputServer->setName(QStringLiteral("OUTPUT1")); + xdgOutputServer->setDescription(QStringLiteral("This is a test output")); + + // Create it on the client + auto *xdgOutput = client.createXdgOutput(wlOutput); + QVERIFY(xdgOutput); + QVERIFY(client.m_xdgOutputs.contains(wlOutput)); + + // Now it should be associated + QCOMPARE(QWaylandOutputPrivate::get(compositor.defaultOutput())->xdgOutput.isNull(), false); + + // Verify initial values + QTRY_COMPARE(xdgOutput->name, "OUTPUT1"); + QTRY_COMPARE(xdgOutput->logicalPosition, QPoint()); + QTRY_COMPARE(xdgOutput->logicalSize, QSize()); + + // Change properties + xdgOutputServer->setName(QStringLiteral("OUTPUT2")); + xdgOutputServer->setDescription(QStringLiteral("New description")); + xdgOutputServer->setLogicalPosition(QPoint(100, 100)); + xdgOutputServer->setLogicalSize(QSize(1000, 1000)); + compositor.flushClients(); + + // Name and description can't be changed after initialization, + // so we expect them to be the same + // TODO: With protocol version 3 the description will be allowed to change, + // but we implement version 2 now + QTRY_COMPARE(xdgOutput->name, "OUTPUT1"); + QTRY_COMPARE(xdgOutput->description, "This is a test output"); + QTRY_COMPARE(xdgOutput->logicalPosition, QPoint(100, 100)); + QTRY_COMPARE(xdgOutput->logicalSize, QSize(1000, 1000)); +} + #include <tst_compositor.moc> QTEST_MAIN(tst_WaylandCompositor); |