summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPier Luigi Fiorini <pierluigi.fiorini@gmail.com>2015-04-10 17:52:49 +0200
committerPier Luigi Fiorini <pierluigi.fiorini@hawaiios.org>2016-10-03 15:15:58 +0000
commit7ee4be6af2c92c345539bb4950dd48d7a740847d (patch)
tree2acbcfb9fd0a2dbc995cb0d700e7e14ad4afd759
parent59c8598958959de943a0782093f020ae1c348edf (diff)
Add mode support to QWaylandOutput
Outputs usually have more than one mode, add an API to support them. When sizeFollowsWindow is true, modes are replaced by one with the window size and refresh rate. In that circumstance the mode changes when the window is resized. The sizeFollowsWindow property default value is no longer true. The setGeometry() method is gone as it doesn't make sense now, the setWidth() and setHeight() methods are now private slots to resize the resolution as the window resizes (and sizeFollowsWindow is true). Refresh rate is expressed in mHz rather than Hz just like the Wayland protocol. A compositor implementation may choose to add modes if it has access to hardware information, it will call addMode() for each mode and then invoke the setCurrentMode() method that sends the modes list to the client. The preferred mode is indicated with a boolean parameter to the addMode() method. Change-Id: Iffed4784ccef695c276ebd800172957f4cff3324 Task-number: QTBUG-49814 Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io> Reviewed-by: Johan Helsing <johan.helsing@qt.io>
-rw-r--r--examples/wayland/custom-extension/compositor/qml/Screen.qml1
-rw-r--r--examples/wayland/minimal-cpp/compositor.cpp5
-rw-r--r--examples/wayland/minimal-qml/main.qml1
-rw-r--r--examples/wayland/multi-output/qml/GridScreen.qml1
-rw-r--r--examples/wayland/multi-output/qml/ShellScreen.qml1
-rw-r--r--examples/wayland/pure-qml/qml/Screen.qml1
-rw-r--r--examples/wayland/qwindow-compositor/compositor.cpp5
-rw-r--r--examples/wayland/server-buffer/compositor/main.cpp9
-rw-r--r--examples/wayland/spanning-screens/main.qml2
-rw-r--r--src/compositor/compositor_api/compositor_api.pri6
-rw-r--r--src/compositor/compositor_api/qwaylandoutput.cpp269
-rw-r--r--src/compositor/compositor_api/qwaylandoutput.h28
-rw-r--r--src/compositor/compositor_api/qwaylandoutput_p.h12
-rw-r--r--src/compositor/compositor_api/qwaylandoutputmode.cpp139
-rw-r--r--src/compositor/compositor_api/qwaylandoutputmode.h72
-rw-r--r--src/compositor/compositor_api/qwaylandoutputmode_p.h66
-rw-r--r--tests/auto/compositor/compositor/mockclient.cpp19
-rw-r--r--tests/auto/compositor/compositor/mockclient.h8
-rw-r--r--tests/auto/compositor/compositor/tst_compositor.cpp58
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()