diff options
19 files changed, 565 insertions, 138 deletions
diff --git a/examples/wayland/custom-extension/compositor/qml/Screen.qml b/examples/wayland/custom-extension/compositor/qml/Screen.qml index a6d5fbc7..7a87951b 100644 --- a/examples/wayland/custom-extension/compositor/qml/Screen.qml +++ b/examples/wayland/custom-extension/compositor/qml/Screen.qml @@ -45,6 +45,7 @@ import QtWayland.Compositor 1.0 WaylandOutput { id: output property alias surfaceArea: background + sizeFollowsWindow: true window: Window { id: screen diff --git a/examples/wayland/minimal-cpp/compositor.cpp b/examples/wayland/minimal-cpp/compositor.cpp index 5e46895c..5a6249c9 100644 --- a/examples/wayland/minimal-cpp/compositor.cpp +++ b/examples/wayland/minimal-cpp/compositor.cpp @@ -67,8 +67,11 @@ Compositor::~Compositor() void Compositor::create() { - new QWaylandOutput(this, m_window); + QWaylandOutput *output = new QWaylandOutput(this, m_window); + QWaylandOutputMode mode(QSize(800, 600), 60000); + output->addMode(mode, true); QWaylandCompositor::create(); + output->setCurrentMode(mode); connect(this, &QWaylandCompositor::surfaceCreated, this, &Compositor::onSurfaceCreated); } diff --git a/examples/wayland/minimal-qml/main.qml b/examples/wayland/minimal-qml/main.qml index 3d6c3b7b..d44d0c6a 100644 --- a/examples/wayland/minimal-qml/main.qml +++ b/examples/wayland/minimal-qml/main.qml @@ -47,6 +47,7 @@ WaylandCompositor { // The output defines the screen. WaylandOutput { compositor: wlcompositor + sizeFollowsWindow: true window: Window { width: 1024 height: 768 diff --git a/examples/wayland/multi-output/qml/GridScreen.qml b/examples/wayland/multi-output/qml/GridScreen.qml index 3dab99d0..2a48cf16 100644 --- a/examples/wayland/multi-output/qml/GridScreen.qml +++ b/examples/wayland/multi-output/qml/GridScreen.qml @@ -46,6 +46,7 @@ WaylandOutput { id: output property alias gridSurfaces: listModel + sizeFollowsWindow: true window: Window { width: 1024 height: 760 diff --git a/examples/wayland/multi-output/qml/ShellScreen.qml b/examples/wayland/multi-output/qml/ShellScreen.qml index 9a612211..7b8a48ff 100644 --- a/examples/wayland/multi-output/qml/ShellScreen.qml +++ b/examples/wayland/multi-output/qml/ShellScreen.qml @@ -46,6 +46,7 @@ WaylandOutput { id: output property alias surfaceArea: background + sizeFollowsWindow: true window: Window { width: 1024 height: 760 diff --git a/examples/wayland/pure-qml/qml/Screen.qml b/examples/wayland/pure-qml/qml/Screen.qml index 0920a8b9..a12f387f 100644 --- a/examples/wayland/pure-qml/qml/Screen.qml +++ b/examples/wayland/pure-qml/qml/Screen.qml @@ -45,6 +45,7 @@ import QtWayland.Compositor 1.0 WaylandOutput { id: output property alias surfaceArea: background + sizeFollowsWindow: true window: Window { id: screen diff --git a/examples/wayland/qwindow-compositor/compositor.cpp b/examples/wayland/qwindow-compositor/compositor.cpp index a55bb3b7..4878c373 100644 --- a/examples/wayland/qwindow-compositor/compositor.cpp +++ b/examples/wayland/qwindow-compositor/compositor.cpp @@ -139,8 +139,11 @@ Compositor::~Compositor() void Compositor::create() { - new QWaylandOutput(this, m_window); + QWaylandOutput *output = new QWaylandOutput(this, m_window); + QWaylandOutputMode mode(QSize(800, 600), 60000); + output->addMode(mode, true); QWaylandCompositor::create(); + output->setCurrentMode(mode); connect(this, &QWaylandCompositor::surfaceCreated, this, &Compositor::onSurfaceCreated); connect(defaultSeat(), &QWaylandSeat::cursorSurfaceRequest, this, &Compositor::adjustCursorSurface); diff --git a/examples/wayland/server-buffer/compositor/main.cpp b/examples/wayland/server-buffer/compositor/main.cpp index 9c5ee42a..8c43ce5c 100644 --- a/examples/wayland/server-buffer/compositor/main.cpp +++ b/examples/wayland/server-buffer/compositor/main.cpp @@ -86,15 +86,13 @@ public: m_view.setColor(Qt::black); m_view.create(); m_output = new QWaylandQuickOutput(this, &m_view); + m_output->setSizeFollowsWindow(true); connect(&m_view, &QQuickView::afterRendering, this, &QmlCompositor::sendCallbacks); connect(&m_view, &QQuickView::sceneGraphInitialized, this, &QmlCompositor::initiateServerBuffer,Qt::DirectConnection); connect(this, &QmlCompositor::serverBuffersCreated, this, &QmlCompositor::createServerBufferItems); - connect(&m_view, &QWindow::widthChanged, this, &QmlCompositor::sizeAdjusted); - connect(&m_view, &QWindow::heightChanged, this, &QmlCompositor::sizeAdjusted); - connect(this, SIGNAL(windowAdded(QVariant)), m_view.rootObject(), SLOT(windowAdded(QVariant))); connect(this, SIGNAL(windowResized(QVariant)), m_view.rootObject(), SLOT(windowResized(QVariant))); connect(this, SIGNAL(serverBufferItemCreated(QVariant)), m_view.rootObject(), SLOT(serverBufferItemCreated(QVariant))); @@ -211,11 +209,6 @@ private slots: } } protected: - void sizeAdjusted() - { - defaultOutput()->setGeometry(QRect(QPoint(0, 0), m_view.size())); - } - void onSurfaceCreated(QWaylandSurface *surface) { QWaylandQuickItem *item = new QWaylandQuickItem(); item->setSurface(surface); diff --git a/examples/wayland/spanning-screens/main.qml b/examples/wayland/spanning-screens/main.qml index 00bf517f..32dc11f3 100644 --- a/examples/wayland/spanning-screens/main.qml +++ b/examples/wayland/spanning-screens/main.qml @@ -47,6 +47,7 @@ WaylandCompositor { WaylandOutput { compositor: wlcompositor + sizeFollowsWindow: true window: Window { id: topSurfaceArea width: 1024 @@ -59,6 +60,7 @@ WaylandCompositor { WaylandOutput { compositor: wlcompositor + sizeFollowsWindow: true window: Window { id: bottomSurfaceArea width: 1024 diff --git a/src/compositor/compositor_api/compositor_api.pri b/src/compositor/compositor_api/compositor_api.pri index 0f70773c..0253cd0e 100644 --- a/src/compositor/compositor_api/compositor_api.pri +++ b/src/compositor/compositor_api/compositor_api.pri @@ -17,6 +17,8 @@ HEADERS += \ compositor_api/qwaylandtouch.h \ compositor_api/qwaylandtouch_p.h \ compositor_api/qwaylandoutput.h \ + compositor_api/qwaylandoutputmode.h \ + compositor_api/qwaylandoutputmode_p.h \ compositor_api/qwaylanddrag.h \ compositor_api/qwaylandbufferref.h \ compositor_api/qwaylanddestroylistener.h \ @@ -26,7 +28,8 @@ HEADERS += \ compositor_api/qwaylandresource.h \ compositor_api/qwaylandsurfacegrabber.h \ compositor_api/qwaylandinputmethodcontrol.h \ - compositor_api/qwaylandinputmethodcontrol_p.h + compositor_api/qwaylandinputmethodcontrol_p.h \ + compositor_api/qwaylandoutputmode_p.h SOURCES += \ compositor_api/qwaylandcompositor.cpp \ @@ -38,6 +41,7 @@ SOURCES += \ compositor_api/qwaylandpointer.cpp \ compositor_api/qwaylandtouch.cpp \ compositor_api/qwaylandoutput.cpp \ + compositor_api/qwaylandoutputmode.cpp \ compositor_api/qwaylanddrag.cpp \ compositor_api/qwaylandbufferref.cpp \ compositor_api/qwaylanddestroylistener.cpp \ diff --git a/src/compositor/compositor_api/qwaylandoutput.cpp b/src/compositor/compositor_api/qwaylandoutput.cpp index 40cd9798..19e17bb3 100644 --- a/src/compositor/compositor_api/qwaylandoutput.cpp +++ b/src/compositor/compositor_api/qwaylandoutput.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014-2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Copyright (C) 2014-2016 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> ** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). ** Contact: http://www.qt.io/licensing/ ** @@ -48,6 +48,7 @@ #include <QtCore/QtMath> #include <QtGui/QWindow> #include <QtGui/QExposeEvent> +#include <QtGui/QScreen> #include <private/qobject_p.h> QT_BEGIN_NAMESPACE @@ -102,16 +103,14 @@ QWaylandOutputPrivate::QWaylandOutputPrivate() : QtWaylandServer::wl_output() , compositor(Q_NULLPTR) , window(Q_NULLPTR) + , currentMode(-1) + , preferredMode(-1) , subpixel(QWaylandOutput::SubpixelUnknown) , transform(QWaylandOutput::TransformNormal) , scaleFactor(1) - , sizeFollowsWindow(true) + , sizeFollowsWindow(false) , initialized(false) { - mode.size = QSize(); - mode.refreshRate = 60; - - qRegisterMetaType<QWaylandOutput::Mode>("WaylandOutput::Mode"); } QWaylandOutputPrivate::~QWaylandOutputPrivate() @@ -120,15 +119,10 @@ QWaylandOutputPrivate::~QWaylandOutputPrivate() void QWaylandOutputPrivate::output_bind_resource(Resource *resource) { - send_geometry(resource->handle, - position.x(), position.y(), - physicalSize.width(), physicalSize.height(), - toWlSubpixel(subpixel), manufacturer, model, - toWlTransform(transform)); + sendGeometry(resource); - send_mode(resource->handle, mode_current | mode_preferred, - mode.size.width(), mode.size.height(), - mode.refreshRate * 1000); + for (const QWaylandOutputMode &mode : modes) + sendMode(resource, mode); if (resource->version() >= 2) { send_scale(resource->handle, scaleFactor); @@ -136,19 +130,46 @@ void QWaylandOutputPrivate::output_bind_resource(Resource *resource) } } +void QWaylandOutputPrivate::sendGeometry(const Resource *resource) +{ + send_geometry(resource->handle, + position.x(), position.y(), + physicalSize.width(), physicalSize.height(), + toWlSubpixel(subpixel), manufacturer, model, + toWlTransform(transform)); +} + void QWaylandOutputPrivate::sendGeometryInfo() { - Q_FOREACH (Resource *resource, resourceMap().values()) { - send_geometry(resource->handle, - position.x(), position.y(), - physicalSize.width(), physicalSize.height(), - toWlSubpixel(subpixel), manufacturer, model, - toWlTransform(transform)); + for (const Resource *resource : resourceMap().values()) { + sendGeometry(resource); if (resource->version() >= 2) send_done(resource->handle); } } +void QWaylandOutputPrivate::sendMode(const Resource *resource, const QWaylandOutputMode &mode) +{ + quint32 flags = 0; + if (currentMode == modes.indexOf(mode)) + flags |= QtWaylandServer::wl_output::mode_current; + if (preferredMode == modes.indexOf(mode)) + flags |= QtWaylandServer::wl_output::mode_preferred; + + send_mode(resource->handle, flags, + mode.size().width(), mode.size().height(), + mode.refreshRate()); +} + +void QWaylandOutputPrivate::sendModesInfo() +{ + for (const Resource *resource : resourceMap().values()) { + for (const QWaylandOutputMode &mode : modes) + sendMode(resource, mode); + if (resource->version() >= 2) + send_done(resource->handle); + } +} void QWaylandOutputPrivate::addView(QWaylandView *view, QWaylandSurface *surface) { @@ -252,16 +273,23 @@ void QWaylandOutput::initialize() Q_ASSERT(d->compositor); Q_ASSERT(d->compositor->isCreated()); - if (d->window) - d->mode.size = d->window->size(); - else - d->sizeFollowsWindow = false; + // Replace modes with one that follows the window size and refresh rate, + // but only if window size is valid + if (d->window && d->sizeFollowsWindow) { + QWaylandOutputMode mode(d->window->size(), + qFloor(d->window->screen()->refreshRate() * 1000)); + if (mode.isValid()) { + d->modes.clear(); + addMode(mode, true); + setCurrentMode(mode); + } + } QWaylandCompositorPrivate::get(d->compositor)->addOutput(this); if (d->window) { - QObject::connect(d->window, &QWindow::widthChanged, this, &QWaylandOutput::setWidth); - QObject::connect(d->window, &QWindow::heightChanged, this, &QWaylandOutput::setHeight); + QObject::connect(d->window, &QWindow::widthChanged, this, &QWaylandOutput::handleSetWidth); + QObject::connect(d->window, &QWindow::heightChanged, this, &QWaylandOutput::handleSetHeight); QObject::connect(d->window, &QObject::destroyed, this, &QWaylandOutput::handleWindowDestroyed); } @@ -431,39 +459,75 @@ void QWaylandOutput::setPosition(const QPoint &pt) } /*! - * \property QWaylandOutput::mode - * - * This property holds the output's size in pixels and refresh rate in Hz. + * Returns the list of modes. */ -QWaylandOutput::Mode QWaylandOutput::mode() const +QList<QWaylandOutputMode> QWaylandOutput::modes() const { - return d_func()->mode; + Q_D(const QWaylandOutput); + return d->modes.toList(); } -void QWaylandOutput::setMode(const Mode &mode) +/*! + * Adds the mode \a mode to the output and mark it as preferred + * if \a preferred is \c true. + * Please note there can only be one preferred mode. + */ +void QWaylandOutput::addMode(const QWaylandOutputMode &mode, bool preferred) { Q_D(QWaylandOutput); - if (d->mode.size == mode.size && d->mode.refreshRate == mode.refreshRate) + + if (!mode.isValid()) { + qWarning("Cannot add an invalid mode"); return; + } - d->mode = mode; + d->modes.append(mode); - Q_FOREACH (QWaylandOutputPrivate::Resource *resource, d->resourceMap().values()) { - d->send_mode(resource->handle, d->mode_current, - d->mode.size.width(), d->mode.size.height(), - d->mode.refreshRate * 1000); - if (resource->version() >= 2) - d->send_done(resource->handle); + if (preferred) + d->preferredMode = d->modes.indexOf(mode); + + emit modeAdded(); +} + +/*! + * Returns the output's size in pixels and refresh rate in mHz. + * If the current mode is not set it will return an invalid mode. + * + * \sa QWaylandOutput::modes + * \sa QWaylandOutputMode + */ +QWaylandOutputMode QWaylandOutput::currentMode() const +{ + Q_D(const QWaylandOutput); + + if (d->currentMode >= 0 && d->currentMode <= d->modes.size() - 1) + return d->modes.at(d->currentMode); + return QWaylandOutputMode(); +} + +/*! + * Sets the current mode. + * The mode \a mode must have been previously added. + * + * \sa QWaylandOutput::modes + * \sa QWaylandOutputMode + */ +void QWaylandOutput::setCurrentMode(const QWaylandOutputMode &mode) +{ + Q_D(QWaylandOutput); + + int index = d->modes.indexOf(mode); + if (index < 0) { + qWarning("Cannot set an unknown QWaylandOutput mode as current"); + return; } - Q_EMIT modeChanged(); + d->currentMode = index; + + Q_EMIT currentModeChanged(); Q_EMIT geometryChanged(); - if (d->window) { - d->window->resize(mode.size); - d->window->setMinimumSize(mode.size); - d->window->setMaximumSize(mode.size); - } + d->sendModesInfo(); } /*! @@ -477,37 +541,12 @@ void QWaylandOutput::setMode(const Mode &mode) * * This property holds the geometry of the QWaylandOutput. * - * \sa QWaylandOutput::mode + * \sa QWaylandOutput::currentMode */ QRect QWaylandOutput::geometry() const { Q_D(const QWaylandOutput); - return QRect(d->position, d->mode.size); -} - -void QWaylandOutput::setGeometry(const QRect &geometry) -{ - Q_D(QWaylandOutput); - if (d->position == geometry.topLeft() && d->mode.size == geometry.size()) - return; - - d->position = geometry.topLeft(); - d->mode.size = geometry.size(); - - Q_FOREACH (QWaylandOutputPrivate::Resource *resource, d->resourceMap().values()) { - d->send_geometry(resource->handle, - d->position.x(), d->position.y(), - d->physicalSize.width(), d->physicalSize.height(), - toWlSubpixel(d->subpixel), d->manufacturer, d->model, - toWlTransform(d->transform)); - d->send_mode(resource->handle, d->mode_current, - d->mode.size.width(), d->mode.size.height(), - d->mode.refreshRate * 1000); - if (resource->version() >= 2) - d->send_done(resource->handle); - } - Q_EMIT positionChanged(); - Q_EMIT modeChanged(); + return QRect(d->position, currentMode().size()); } /*! @@ -527,13 +566,14 @@ void QWaylandOutput::setGeometry(const QRect &geometry) * The available geometry is in output coordinates space, starts from 0,0 and it's as big * as the output by default. * - * \sa QWaylandOutput::mode, QWaylandOutput::geometry + * \sa QWaylandOutput::currentMode, QWaylandOutput::geometry */ QRect QWaylandOutput::availableGeometry() const { Q_D(const QWaylandOutput); + if (!d->availableGeometry.isValid()) - return QRect(QPoint(0, 0), d->mode.size); + return QRect(QPoint(0, 0), currentMode().size()); return d->availableGeometry; } @@ -565,7 +605,7 @@ void QWaylandOutput::setAvailableGeometry(const QRect &availableGeometry) * * This property holds the physical size of the QWaylandOutput in millimeters. * - * \sa QWaylandOutput::geometry, QWaylandOutput::mode + * \sa QWaylandOutput::geometry, QWaylandOutput::currentMode */ QSize QWaylandOutput::physicalSize() const { @@ -755,7 +795,10 @@ void QWaylandOutput::setScaleFactor(int scale) * This property controls whether the size of the WaylandOutput matches the * size of its window. * - * The default is \c true if this WaylandOutput has a window. + * If this property is true, all modes previously added are replaced by a + * mode that matches window size and screen refresh rate. + * + * The default is false. */ /*! @@ -764,7 +807,10 @@ void QWaylandOutput::setScaleFactor(int scale) * This property controls whether the size of the QWaylandOutput matches the * size of its window. * - * The default is \c true if this QWaylandOutput has a window. + * If this property is true, all modes previously added are replaced by a + * mode that matches window size and screen refresh rate. + * + * The default is false. */ bool QWaylandOutput::sizeFollowsWindow() const { @@ -781,13 +827,6 @@ void QWaylandOutput::setSizeFollowsWindow(bool follow) } if (follow != d->sizeFollowsWindow) { - if (follow) { - QObject::connect(d->window, &QWindow::widthChanged, this, &QWaylandOutput::setWidth); - QObject::connect(d->window, &QWindow::heightChanged, this, &QWaylandOutput::setHeight); - } else { - QObject::disconnect(d->window, &QWindow::widthChanged, this, &QWaylandOutput::setWidth); - QObject::disconnect(d->window, &QWindow::heightChanged, this, &QWaylandOutput::setHeight); - } d->sizeFollowsWindow = follow; Q_EMIT sizeFollowsWindowChanged(); } @@ -882,35 +921,63 @@ void QWaylandOutput::surfaceLeave(QWaylandSurface *surface) } /*! - * Sets the width of this QWaylandOutput to \a newWidth. - * - * \sa setHeight, QWaylandOutput::geometry + * \internal */ -void QWaylandOutput::setWidth(int newWidth) +void QWaylandOutput::handleSetWidth(int newWidth) { Q_D(QWaylandOutput); - if (d->mode.size.width() == newWidth) + + if (!d->window || !d->sizeFollowsWindow) return; - QSize s = d->mode.size; - s.setWidth(newWidth); - setGeometry(QRect(d->position, s)); + if (d->currentMode <= d->modes.size() - 1) { + if (d->currentMode >= 0) { + QWaylandOutputMode mode = d->modes.at(d->currentMode); + mode.setWidth(newWidth); + d->modes.replace(d->currentMode, mode); + d->sendModesInfo(); + } else { + // We didn't add a mode during the initialization because the window + // size was invalid, let's add it now + QWaylandOutputMode mode(d->window->size(), + qFloor(d->window->screen()->refreshRate() * 1000)); + if (mode.isValid()) { + d->modes.clear(); + addMode(mode, true); + setCurrentMode(mode); + } + } + } } /*! - * Sets the height of this QWaylandOutput to \a newHeight. - * - * \sa setWidth, QWaylandOutput::geometry + * \internal */ -void QWaylandOutput::setHeight(int newHeight) +void QWaylandOutput::handleSetHeight(int newHeight) { Q_D(QWaylandOutput); - if (d->mode.size.height() == newHeight) + + if (!d->window || !d->sizeFollowsWindow) return; - QSize s = d->mode.size; - s.setHeight(newHeight); - setGeometry(QRect(d->position, s)); + if (d->currentMode <= d->modes.size() - 1) { + if (d->currentMode >= 0) { + QWaylandOutputMode mode = d->modes.at(d->currentMode); + mode.setHeight(newHeight); + d->modes.replace(d->currentMode, mode); + d->sendModesInfo(); + } else { + // We didn't add a mode during the initialization because the window + // size was invalid, let's add it now + QWaylandOutputMode mode(d->window->size(), + qFloor(d->window->screen()->refreshRate() * 1000)); + if (mode.isValid()) { + d->modes.clear(); + addMode(mode, true); + setCurrentMode(mode); + } + } + } } /*! diff --git a/src/compositor/compositor_api/qwaylandoutput.h b/src/compositor/compositor_api/qwaylandoutput.h index e4cbb610..190231c1 100644 --- a/src/compositor/compositor_api/qwaylandoutput.h +++ b/src/compositor/compositor_api/qwaylandoutput.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014-2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Copyright (C) 2014-2016 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> ** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). ** Contact: http://www.qt.io/licensing/ ** @@ -39,6 +39,7 @@ #define QWAYLANDOUTPUT_H #include <QtWaylandCompositor/qwaylandcompositorextension.h> +#include <QtWaylandCompositor/QWaylandOutputMode> #include <QtCore/QObject> #include <QObject> @@ -66,7 +67,6 @@ class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandOutput : public QWaylandObject Q_PROPERTY(QString manufacturer READ manufacturer WRITE setManufacturer NOTIFY manufacturerChanged) Q_PROPERTY(QString model READ model WRITE setModel NOTIFY modelChanged) Q_PROPERTY(QPoint position READ position WRITE setPosition NOTIFY positionChanged) - Q_PROPERTY(QWaylandOutput::Mode mode READ mode WRITE setMode NOTIFY modeChanged) Q_PROPERTY(QRect geometry READ geometry NOTIFY geometryChanged) Q_PROPERTY(QRect availableGeometry READ availableGeometry WRITE setAvailableGeometry NOTIFY availableGeometryChanged) Q_PROPERTY(QSize physicalSize READ physicalSize WRITE setPhysicalSize NOTIFY physicalSizeChanged) @@ -99,12 +99,6 @@ public: }; Q_ENUM(Transform) - struct Mode - { - QSize size; - qreal refreshRate; - }; - QWaylandOutput(); QWaylandOutput(QWaylandCompositor *compositor, QWindow *window); ~QWaylandOutput(); @@ -127,13 +121,14 @@ public: QPoint position() const; void setPosition(const QPoint &pt); - Mode mode() const; - void setMode(const Mode &mode); + QList<QWaylandOutputMode> modes() const; + + void addMode(const QWaylandOutputMode &mode, bool preferred = false); + + QWaylandOutputMode currentMode() const; + void setCurrentMode(const QWaylandOutputMode &mode); QRect geometry() const; - void setGeometry(const QRect &geometry); - void setWidth(int newWidth); - void setHeight(int newHeight); QRect availableGeometry() const; void setAvailableGeometry(const QRect &availableGeometry); @@ -169,7 +164,8 @@ Q_SIGNALS: void windowChanged(); void positionChanged(); void geometryChanged(); - void modeChanged(); + void modeAdded(); + void currentModeChanged(); void availableGeometryChanged(); void physicalSizeChanged(); void scaleFactorChanged(); @@ -182,6 +178,8 @@ Q_SIGNALS: void windowDestroyed(); private Q_SLOTS: + void handleSetWidth(int newWidth); + void handleSetHeight(int newHeight); void handleWindowDestroyed(); protected: @@ -192,6 +190,4 @@ protected: QT_END_NAMESPACE -Q_DECLARE_METATYPE(QWaylandOutput::Mode) - #endif // QWAYLANDOUTPUT_H diff --git a/src/compositor/compositor_api/qwaylandoutput_p.h b/src/compositor/compositor_api/qwaylandoutput_p.h index 9b6ba907..ea8e7bcd 100644 --- a/src/compositor/compositor_api/qwaylandoutput_p.h +++ b/src/compositor/compositor_api/qwaylandoutput_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014-2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Copyright (C) 2014-2016 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> ** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ @@ -102,19 +102,25 @@ public: void addView(QWaylandView *view, QWaylandSurface *surface); void removeView(QWaylandView *view, QWaylandSurface *surface); + + void sendGeometry(const Resource *resource); void sendGeometryInfo(); + void sendMode(const Resource *resource, const QWaylandOutputMode &mode); + void sendModesInfo(); + protected: void output_bind_resource(Resource *resource) Q_DECL_OVERRIDE; - private: QWaylandCompositor *compositor; QWindow *window; QString manufacturer; QString model; QPoint position; - QWaylandOutput::Mode mode; + QVector<QWaylandOutputMode> modes; + int currentMode; + int preferredMode; QRect availableGeometry; QVector<QWaylandSurfaceViewMapper> surfaceViews; QSize physicalSize; diff --git a/src/compositor/compositor_api/qwaylandoutputmode.cpp b/src/compositor/compositor_api/qwaylandoutputmode.cpp new file mode 100644 index 00000000..463b984a --- /dev/null +++ b/src/compositor/compositor_api/qwaylandoutputmode.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "qwaylandoutputmode.h" +#include "qwaylandoutputmode_p.h" + +/*! + \class QWaylandOutputMode + \inmodule QtWaylandCompositor + \since 5.8 + \brief The QWaylandOutputMode class holds the resolution and refresh rate of an output. + + QWaylandOutputMode holds the resolution and refresh rate of an output. + Resolution is expressed in pixels and refresh rate is measured in mHz. + + \sa QWaylandOutput +*/ + +QWaylandOutputMode::QWaylandOutputMode() + : d(new QWaylandOutputModePrivate) +{ +} + +QWaylandOutputMode::QWaylandOutputMode(const QSize &size, int refreshRate) + : d(new QWaylandOutputModePrivate) +{ + d->size = size; + d->refreshRate = refreshRate; +} + +QWaylandOutputMode::QWaylandOutputMode(const QWaylandOutputMode &other) + : d(new QWaylandOutputModePrivate) +{ + d->size = other.size(); + d->refreshRate = other.refreshRate(); +} + +QWaylandOutputMode::~QWaylandOutputMode() +{ + delete d; +} + +QWaylandOutputMode &QWaylandOutputMode::operator=(const QWaylandOutputMode &other) +{ + d->size = other.size(); + d->refreshRate = other.refreshRate(); + return *this; +} + +/*! + Returns \c true if this mode is equal to \a other, + otherwise returns \c false. +*/ +bool QWaylandOutputMode::operator==(const QWaylandOutputMode &other) const +{ + return size() == other.size() && refreshRate() == refreshRate(); +} + +/*! + Returns \c true if this mode is not equal to \a other, + otherwise returns \c false. +*/ +bool QWaylandOutputMode::operator!=(const QWaylandOutputMode &other) const +{ + return size() != other.size() || refreshRate() != refreshRate(); +} + +/*! + Returns whether this mode contains a valid resolution and refresh rate. +*/ +bool QWaylandOutputMode::isValid() const +{ + return !d->size.isEmpty() && d->refreshRate > 0; +} + +/*! + Returns the resolution in pixels. +*/ +QSize QWaylandOutputMode::size() const +{ + return d->size; +} + +/*! + Returns the refresh rate in mHz. +*/ +int QWaylandOutputMode::refreshRate() const +{ + return d->refreshRate; +} + +/*! + * \internal + */ +void QWaylandOutputMode::setWidth(int width) +{ + d->size.setWidth(width); +} + +/*! + * \internal + */ +void QWaylandOutputMode::setHeight(int height) +{ + d->size.setHeight(height); +} diff --git a/src/compositor/compositor_api/qwaylandoutputmode.h b/src/compositor/compositor_api/qwaylandoutputmode.h new file mode 100644 index 00000000..4ef57f2e --- /dev/null +++ b/src/compositor/compositor_api/qwaylandoutputmode.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 QWAYLANDOUTPUTMODE_H +#define QWAYLANDOUTPUTMODE_H + +#include <QtWaylandCompositor/qwaylandexport.h> +#include <QtCore/QSize> + +QT_BEGIN_NAMESPACE + +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandOutputMode +{ +public: + explicit QWaylandOutputMode(); + QWaylandOutputMode(const QSize &size, int refreshRate); + QWaylandOutputMode(const QWaylandOutputMode &other); + ~QWaylandOutputMode(); + + QWaylandOutputMode &operator=(const QWaylandOutputMode &other); + bool operator==(const QWaylandOutputMode &other) const; + bool operator!=(const QWaylandOutputMode &other) const; + + bool isValid() const; + + QSize size() const; + int refreshRate() const; + +private: + class QWaylandOutputModePrivate *const d; + friend class QWaylandOutput; + + void setWidth(int width); + void setHeight(int height); +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDOUTPUTMODE_H diff --git a/src/compositor/compositor_api/qwaylandoutputmode_p.h b/src/compositor/compositor_api/qwaylandoutputmode_p.h new file mode 100644 index 00000000..e9a0eaa3 --- /dev/null +++ b/src/compositor/compositor_api/qwaylandoutputmode_p.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 QWAYLANDOUTPUTMODE_P_H +#define QWAYLANDOUTPUTMODE_P_H + +#include <QtWaylandCompositor/QWaylandOutput> + +// +// 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 QWaylandOutputModePrivate +{ +public: + QWaylandOutputModePrivate() {} + + QSize size; + int refreshRate = 60000; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDOUTPUTMODE_P_H diff --git a/tests/auto/compositor/compositor/mockclient.cpp b/tests/auto/compositor/compositor/mockclient.cpp index f2fbc5de..da1096fb 100644 --- a/tests/auto/compositor/compositor/mockclient.cpp +++ b/tests/auto/compositor/compositor/mockclient.cpp @@ -52,6 +52,7 @@ MockClient::MockClient() , wlshell(0) , xdgShell(nullptr) , iviApplication(nullptr) + , refreshRate(-1) , error(0 /* means no error according to spec */) , protocolError({0, 0, nullptr}) { @@ -102,10 +103,22 @@ void MockClient::outputGeometryEvent(void *data, wl_output *, resolve(data)->geometry.moveTopLeft(QPoint(x, y)); } -void MockClient::outputModeEvent(void *data, wl_output *, uint32_t, - int w, int h, int) +void MockClient::outputModeEvent(void *data, wl_output *, uint32_t flags, + int w, int h, int refreshRate) { - resolve(data)->geometry.setSize(QSize(w, h)); + QWaylandOutputMode mode(QSize(w, h), refreshRate); + + if (flags & WL_OUTPUT_MODE_CURRENT) { + resolve(data)->geometry.setSize(QSize(w, h)); + resolve(data)->resolution = QSize(w, h); + resolve(data)->refreshRate = refreshRate; + resolve(data)->currentMode = mode; + } + + if (flags & WL_OUTPUT_MODE_PREFERRED) + resolve(data)->preferredMode = mode; + + resolve(data)->modes.append(mode); } void MockClient::outputDone(void *, wl_output *) diff --git a/tests/auto/compositor/compositor/mockclient.h b/tests/auto/compositor/compositor/mockclient.h index ed9319af..1881393a 100644 --- a/tests/auto/compositor/compositor/mockclient.h +++ b/tests/auto/compositor/compositor/mockclient.h @@ -34,6 +34,7 @@ #include <QImage> #include <QRect> #include <QList> +#include <QWaylandOutputMode> class MockSeat; @@ -73,6 +74,11 @@ public: QList<MockSeat *> m_seats; QRect geometry; + QSize resolution; + int refreshRate; + QWaylandOutputMode currentMode; + QWaylandOutputMode preferredMode; + QList<QWaylandOutputMode> modes; int fd; int error; @@ -106,7 +112,7 @@ private: uint32_t flags, int width, int height, - int refresh); + int refreshRate); static void outputDone(void *data, wl_output *output); static void outputScale(void *data, wl_output *output, int factor); diff --git a/tests/auto/compositor/compositor/tst_compositor.cpp b/tests/auto/compositor/compositor/tst_compositor.cpp index 16aedd8e..393b9f5b 100644 --- a/tests/auto/compositor/compositor/tst_compositor.cpp +++ b/tests/auto/compositor/compositor/tst_compositor.cpp @@ -35,6 +35,7 @@ #include "qwaylandbufferref.h" #include "qwaylandseat.h" +#include <QtGui/QScreen> #include <QtWaylandCompositor/QWaylandXdgShellV5> #include <QtWaylandCompositor/QWaylandIviApplication> #include <QtWaylandCompositor/QWaylandIviSurface> @@ -58,6 +59,8 @@ private slots: void singleClient(); void multipleClients(); void geometry(); + void modes(); + void sizeFollowsWindow(); void mapSurface(); void frameCallback(); @@ -202,12 +205,61 @@ void tst_WaylandCompositor::geometry() TestCompositor compositor; compositor.create(); - QRect geometry(0, 0, 4096, 3072); - compositor.defaultOutput()->setGeometry(geometry); + QWaylandOutputMode mode(QSize(4096, 3072), 60000); + compositor.defaultOutput()->setPosition(QPoint(1024, 0)); + compositor.defaultOutput()->addMode(mode, true); + compositor.defaultOutput()->setCurrentMode(mode); MockClient client; - QTRY_COMPARE(client.geometry, geometry); + QTRY_COMPARE(client.geometry, QRect(QPoint(1024, 0), QSize(4096, 3072))); + QTRY_COMPARE(client.resolution, QSize(4096, 3072)); + QTRY_COMPARE(client.refreshRate, 60000); +} + +void tst_WaylandCompositor::modes() +{ + TestCompositor compositor; + compositor.create(); + + // mode3 is current, mode4 is preferred + QWaylandOutputMode mode1(QSize(800, 600), 120000); + QWaylandOutputMode mode2(QSize(1024, 768), 100000); + QWaylandOutputMode mode3(QSize(1920, 1080), 60000); + QWaylandOutputMode mode4(QSize(2560, 1440), 59000); + compositor.defaultOutput()->addMode(mode1); + compositor.defaultOutput()->addMode(mode2, true); + compositor.defaultOutput()->addMode(mode3); + compositor.defaultOutput()->addMode(mode4, true); + compositor.defaultOutput()->setCurrentMode(mode3); + + MockClient client; + + QTRY_COMPARE(client.modes.size(), 4); + QTRY_COMPARE(client.currentMode, mode3); + QTRY_COMPARE(client.preferredMode, mode4); + QTRY_COMPARE(client.geometry, QRect(QPoint(0, 0), QSize(1920, 1080))); +} + +void tst_WaylandCompositor::sizeFollowsWindow() +{ + TestCompositor compositor; + + QWindow window; + window.resize(800, 600); + + auto output = new QWaylandOutput(&compositor, &window); + output->setSizeFollowsWindow(true); + + compositor.create(); + + QWaylandOutputMode mode(window.size(), qFloor(window.screen()->refreshRate() * 1000)); + + MockClient client; + + QTRY_COMPARE(client.modes.size(), 1); + QTRY_COMPARE(client.currentMode, mode); + QTRY_COMPARE(client.preferredMode, mode); } void tst_WaylandCompositor::mapSurface() |