summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--.qmake.conf2
-rw-r--r--config.tests/dmabuf_client_buffer/dmabuf_client_buffer.pro1
-rw-r--r--config.tests/dmabuf_client_buffer/main.cpp71
-rw-r--r--config.tests/wayland/main.cpp10
-rw-r--r--examples/wayland/minimal-cpp/compositor.h4
-rw-r--r--examples/wayland/minimal-cpp/window.cpp2
-rw-r--r--examples/wayland/qwindow-compositor/compositor.cpp4
-rw-r--r--examples/wayland/qwindow-compositor/compositor.h2
-rw-r--r--examples/wayland/qwindow-compositor/window.cpp2
-rw-r--r--features/wayland-scanner-client-wayland-protocol-include.prf53
-rw-r--r--src/3rdparty/protocol/fullscreen-shell-unstable-v1.xml245
-rw-r--r--src/3rdparty/protocol/linux-dmabuf-unstable-v1.xml348
-rw-r--r--src/3rdparty/protocol/qt_attribution.json51
-rw-r--r--src/3rdparty/protocol/viewporter.xml186
-rw-r--r--src/client/client.pro7
-rw-r--r--src/client/configure.json41
-rw-r--r--src/client/qwaylandabstractdecoration.cpp4
-rw-r--r--src/client/qwaylandabstractdecoration_p.h4
-rw-r--r--src/client/qwaylandbuffer_p.h3
-rw-r--r--src/client/qwaylanddisplay.cpp13
-rw-r--r--src/client/qwaylanddisplay_p.h2
-rw-r--r--src/client/qwaylandextendedsurface_p.h1
-rw-r--r--src/client/qwaylandinputcontext_p.h3
-rw-r--r--src/client/qwaylandinputdevice.cpp14
-rw-r--r--src/client/qwaylandinputdevice_p.h5
-rw-r--r--src/client/qwaylandintegration.cpp77
-rw-r--r--src/client/qwaylandintegration_p.h2
-rw-r--r--src/client/qwaylandshellsurface_p.h5
-rw-r--r--src/client/qwaylandshmbackingstore.cpp3
-rw-r--r--src/client/qwaylandsubsurface_p.h2
-rw-r--r--src/client/qwaylandwindow.cpp18
-rw-r--r--src/client/qwaylandwindowmanagerintegration_p.h1
-rw-r--r--src/compositor/compositor_api/qwaylandclient.cpp2
-rw-r--r--src/compositor/compositor_api/qwaylanddestroylistener_p.h2
-rw-r--r--src/compositor/compositor_api/qwaylandoutput.cpp5
-rw-r--r--src/compositor/compositor_api/qwaylandpointer.cpp6
-rw-r--r--src/compositor/compositor_api/qwaylandquickcompositor.cpp6
-rw-r--r--src/compositor/compositor_api/qwaylandquickitem.cpp34
-rw-r--r--src/compositor/compositor_api/qwaylandquickitem.h1
-rw-r--r--src/compositor/compositor_api/qwaylandseat.cpp5
-rw-r--r--src/compositor/compositor_api/qwaylandsurface.cpp127
-rw-r--r--src/compositor/compositor_api/qwaylandsurface.h20
-rw-r--r--src/compositor/compositor_api/qwaylandsurface_p.h6
-rw-r--r--src/compositor/configure.json11
-rw-r--r--src/compositor/extensions/extensions.pri4
-rw-r--r--src/compositor/extensions/pregenerated/3rdparty/qwayland-server-xdg-shell-unstable-v5_p.h3
-rw-r--r--src/compositor/extensions/pregenerated/3rdparty/wayland-xdg-shell-unstable-v5-server-protocol_p.h2
-rw-r--r--src/compositor/extensions/qwaylandivisurface.cpp9
-rw-r--r--src/compositor/extensions/qwaylandviewporter.cpp243
-rw-r--r--src/compositor/extensions/qwaylandviewporter.h63
-rw-r--r--src/compositor/extensions/qwaylandviewporter_p.h93
-rw-r--r--src/compositor/extensions/qwaylandwlshell.cpp6
-rw-r--r--src/compositor/extensions/qwaylandwlshell_p.h2
-rw-r--r--src/compositor/extensions/qwaylandwlshellintegration.cpp12
-rw-r--r--src/compositor/extensions/qwaylandxdgshell.cpp20
-rw-r--r--src/compositor/extensions/qwaylandxdgshellintegration.cpp22
-rw-r--r--src/compositor/extensions/qwaylandxdgshellv5.cpp19
-rw-r--r--src/compositor/extensions/qwaylandxdgshellv5integration.cpp24
-rw-r--r--src/compositor/extensions/qwaylandxdgshellv6.cpp16
-rw-r--r--src/compositor/extensions/qwaylandxdgshellv6integration.cpp22
-rw-r--r--src/compositor/global/global.pri1
-rw-r--r--src/compositor/global/qwaylandcompositorextension.cpp2
-rw-r--r--src/compositor/global/qwaylandutils_p.h73
-rw-r--r--src/compositor/hardware_integration/qwlclientbufferintegration_p.h2
-rw-r--r--src/compositor/wayland_wrapper/qwlclientbuffer.cpp2
-rw-r--r--src/compositor/wayland_wrapper/qwlclientbuffer_p.h4
-rw-r--r--src/compositor/wayland_wrapper/qwldatasource.cpp3
-rw-r--r--src/compositor/wayland_wrapper/qwlregion.cpp6
-rw-r--r--src/compositor/wayland_wrapper/wayland_wrapper.pri4
-rw-r--r--src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglintegration.h2
-rw-r--r--src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglwindow.cpp1
-rw-r--r--src/hardwareintegration/client/wayland-egl/qwaylandeglclientbufferintegration.cpp10
-rw-r--r--src/hardwareintegration/client/wayland-egl/qwaylandeglinclude.h2
-rw-r--r--src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h2
-rw-r--r--src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglclientbufferintegration.cpp2
-rw-r--r--src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglclientbufferintegration.h5
-rw-r--r--src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxintegration.cpp2
-rw-r--r--src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxintegration.h5
-rw-r--r--src/hardwareintegration/client/xcomposite_share/qwaylandxcompositebuffer.cpp1
-rw-r--r--src/hardwareintegration/client/xcomposite_share/xcomposite_share.pri2
-rw-r--r--src/hardwareintegration/compositor/brcm-egl/brcmbuffer.h3
-rw-r--r--src/hardwareintegration/compositor/libhybris-egl-server/libhybriseglserverbufferintegration.cpp2
-rw-r--r--src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pri16
-rw-r--r--src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.cpp332
-rw-r--r--src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.h162
-rw-r--r--src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp501
-rw-r--r--src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.h138
-rw-r--r--src/hardwareintegration/compositor/xcomposite_share/xcompositebuffer.h5
-rw-r--r--src/hardwareintegration/compositor/xcomposite_share/xcompositehandler.h2
-rw-r--r--src/plugins/decorations/bradient/main.cpp16
-rw-r--r--src/plugins/hardwareintegration/compositor/compositor.pro2
-rw-r--r--src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.json3
-rw-r--r--src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pro12
-rw-r--r--src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/main.cpp63
-rw-r--r--src/plugins/shellintegration/fullscreen-shell-v1/fullscreen-shell-v1.json3
-rw-r--r--src/plugins/shellintegration/fullscreen-shell-v1/fullscreen-shell-v1.pro23
-rw-r--r--src/plugins/shellintegration/fullscreen-shell-v1/main.cpp69
-rw-r--r--src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.cpp71
-rw-r--r--src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.h67
-rw-r--r--src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.cpp61
-rw-r--r--src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.h67
-rw-r--r--src/plugins/shellintegration/shellintegration.pro14
-rw-r--r--src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration_p.h1
-rw-r--r--src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp15
-rw-r--r--src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface_p.h5
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/qwayland-xdg-shell-unstable-v5.cpp1
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/qwayland-xdg-shell-unstable-v5_p.h2
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/wayland-xdg-shell-unstable-v5-client-protocol_p.h2
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h2
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5_p.h2
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp17
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5_p.h7
-rw-r--r--src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp21
-rw-r--r--src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6_p.h8
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp21
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h8
-rw-r--r--src/qtwaylandscanner/qtwaylandscanner.cpp24
-rw-r--r--sync.profile6
-rw-r--r--tests/auto/client/client.pro8
-rw-r--r--tests/auto/client/client/client.pro2
-rw-r--r--tests/auto/client/fullscreenshellv1/fullscreenshellv1.pro4
-rw-r--r--tests/auto/client/fullscreenshellv1/tst_fullscreenshellv1.cpp111
-rw-r--r--tests/auto/client/iviapplication/iviapplication.pro2
-rw-r--r--tests/auto/client/seatv4/seatv4.pro4
-rw-r--r--tests/auto/client/seatv4/tst_seatv4.cpp289
-rw-r--r--tests/auto/client/shared/corecompositor.cpp140
-rw-r--r--tests/auto/client/shared/corecompositor.h209
-rw-r--r--tests/auto/client/shared/coreprotocol.cpp322
-rw-r--r--tests/auto/client/shared/coreprotocol.h313
-rw-r--r--tests/auto/client/shared/mockcompositor.cpp517
-rw-r--r--tests/auto/client/shared/mockcompositor.h290
-rw-r--r--tests/auto/client/shared/shared.pri40
-rw-r--r--tests/auto/client/shared/xdgshell.cpp186
-rw-r--r--tests/auto/client/shared/xdgshell.h127
-rw-r--r--tests/auto/client/shared_old/mockcompositor.cpp520
-rw-r--r--tests/auto/client/shared_old/mockcompositor.h290
-rw-r--r--tests/auto/client/shared_old/mockfullscreenshellv1.cpp43
-rw-r--r--tests/auto/client/shared_old/mockfullscreenshellv1.h58
-rw-r--r--tests/auto/client/shared_old/mockinput.cpp (renamed from tests/auto/client/shared/mockinput.cpp)0
-rw-r--r--tests/auto/client/shared_old/mockinput.h (renamed from tests/auto/client/shared/mockinput.h)0
-rw-r--r--tests/auto/client/shared_old/mockiviapplication.cpp (renamed from tests/auto/client/shared/mockiviapplication.cpp)0
-rw-r--r--tests/auto/client/shared_old/mockiviapplication.h (renamed from tests/auto/client/shared/mockiviapplication.h)0
-rw-r--r--tests/auto/client/shared_old/mockoutput.cpp (renamed from tests/auto/client/shared/mockoutput.cpp)0
-rw-r--r--tests/auto/client/shared_old/mockoutput.h (renamed from tests/auto/client/shared/mockoutput.h)0
-rw-r--r--tests/auto/client/shared_old/mocksurface.cpp (renamed from tests/auto/client/shared/mocksurface.cpp)0
-rw-r--r--tests/auto/client/shared_old/mocksurface.h (renamed from tests/auto/client/shared/mocksurface.h)0
-rw-r--r--tests/auto/client/shared_old/mockwlshell.cpp (renamed from tests/auto/client/shared/mockwlshell.cpp)0
-rw-r--r--tests/auto/client/shared_old/mockwlshell.h (renamed from tests/auto/client/shared/mockwlshell.h)0
-rw-r--r--tests/auto/client/shared_old/mockxdgshellv6.cpp (renamed from tests/auto/client/shared/mockxdgshellv6.cpp)0
-rw-r--r--tests/auto/client/shared_old/mockxdgshellv6.h (renamed from tests/auto/client/shared/mockxdgshellv6.h)0
-rw-r--r--tests/auto/client/shared_old/shared_old.pri34
-rw-r--r--tests/auto/client/surface/surface.pro5
-rw-r--r--tests/auto/client/surface/tst_surface.cpp158
-rw-r--r--tests/auto/client/xdgshell/tst_xdgshell.cpp269
-rw-r--r--tests/auto/client/xdgshell/xdgshell.pro5
-rw-r--r--tests/auto/client/xdgshellv6/xdgshellv6.pro2
-rw-r--r--tests/auto/compositor/compositor/compositor.pro2
-rw-r--r--tests/auto/compositor/compositor/mockclient.cpp2
-rw-r--r--tests/auto/compositor/compositor/mockclient.h4
-rw-r--r--tests/auto/compositor/compositor/mockkeyboard.h2
-rw-r--r--tests/auto/compositor/compositor/mockpointer.h2
-rw-r--r--tests/auto/compositor/compositor/mockseat.h2
-rw-r--r--tests/auto/compositor/compositor/testcompositor.cpp2
-rw-r--r--tests/auto/compositor/compositor/tst_compositor.cpp460
165 files changed, 7252 insertions, 1051 deletions
diff --git a/.gitignore b/.gitignore
index bb3819ca3..b1a806210 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,8 +65,11 @@ src/plugins/shellintegration/ivi-shell/qwayland-ivi-application.h
src/plugins/shellintegration/ivi-shell/qwayland-ivi-application.cpp
src/plugins/shellintegration/ivi-shell/qwayland-ivi-controller.h
src/plugins/shellintegration/ivi-shell/qwayland-ivi-controller.cpp
+src/plugins/shellintegration/fullscreen-shell-v1/qwayland-fullscreen-shell-unstable-v1.cpp
+src/plugins/shellintegration/fullscreen-shell-v1/qwayland-fullscreen-shell-unstable-v1.h
src/imports/compositor/compositor.qrc
tests/auto/client/client/tst_client
+tests/auto/client/fullscreenshellv1/tst_client_fullscreenshell1
tests/auto/compositor/compositor/tst_compositor
tests/auto/compositor/compositor/qwayland-*.cpp
tests/auto/compositor/compositor/qwayland-*.h
diff --git a/.qmake.conf b/.qmake.conf
index 097d8b948..f8cda0e7d 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,3 +1,3 @@
load(qt_build_config)
-MODULE_VERSION = 5.12.0
+MODULE_VERSION = 5.13.0
diff --git a/config.tests/dmabuf_client_buffer/dmabuf_client_buffer.pro b/config.tests/dmabuf_client_buffer/dmabuf_client_buffer.pro
new file mode 100644
index 000000000..28dcadcbf
--- /dev/null
+++ b/config.tests/dmabuf_client_buffer/dmabuf_client_buffer.pro
@@ -0,0 +1 @@
+SOURCES += main.cpp
diff --git a/config.tests/dmabuf_client_buffer/main.cpp b/config.tests/dmabuf_client_buffer/main.cpp
new file mode 100644
index 000000000..71447dc8e
--- /dev/null
+++ b/config.tests/dmabuf_client_buffer/main.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Compositor.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+//If libdrm is available, the following files should exist
+#include "drm_mode.h"
+#include "drm_fourcc.h"
+
+int main()
+{
+// test if DMA BUF is supported
+#ifndef EGL_LINUX_DMA_BUF_EXT
+#error DMA BUF Extension not available
+#endif
+
+// test if DMA BUF import modifier extension is supported
+#ifndef EGL_EXT_image_dma_buf_import_modifiers
+#error DMA BUF Import modifier extension not available
+#endif
+
+ return 0;
+}
diff --git a/config.tests/wayland/main.cpp b/config.tests/wayland/main.cpp
index 9e0002db5..8cab379bf 100644
--- a/config.tests/wayland/main.cpp
+++ b/config.tests/wayland/main.cpp
@@ -53,15 +53,15 @@
int main()
{
#if WAYLAND_VERSION_MAJOR < 1
-# error Wayland 1.6.0 or higher required
+# error Wayland 1.8.0 or higher required
#endif
#if WAYLAND_VERSION_MAJOR == 1
-# if WAYLAND_VERSION_MINOR < 6
-# error Wayland 1.6.0 or higher required
+# if WAYLAND_VERSION_MINOR < 8
+# error Wayland 1.8.0 or higher required
# endif
-# if WAYLAND_VERSION_MINOR == 6
+# if WAYLAND_VERSION_MINOR == 8
# if WAYLAND_VERSION_MICRO < 0
-# error Wayland 1.6.0 or higher required
+# error Wayland 1.8.0 or higher required
# endif
# endif
#endif
diff --git a/examples/wayland/minimal-cpp/compositor.h b/examples/wayland/minimal-cpp/compositor.h
index f06421320..3c0c80e0e 100644
--- a/examples/wayland/minimal-cpp/compositor.h
+++ b/examples/wayland/minimal-cpp/compositor.h
@@ -71,11 +71,11 @@ public:
QOpenGLTexture *getTexture();
int iviId() const { return m_iviId; }
- QRect globalGeometry() const { return QRect(globalPosition(), surface()->size()); }
+ QRect globalGeometry() const { return QRect(globalPosition(), surface()->destinationSize()); }
void setGlobalPosition(const QPoint &globalPos) { m_pos = globalPos; m_positionSet = true; }
QPoint globalPosition() const { return m_pos; }
QPoint mapToLocal(const QPoint &globalPos) const;
- QSize size() const { return surface() ? surface()->size() : QSize(); }
+ QSize size() const { return surface() ? surface()->destinationSize() : QSize(); }
void initPosition(const QSize &screenSize, const QSize &surfaceSize);
diff --git a/examples/wayland/minimal-cpp/window.cpp b/examples/wayland/minimal-cpp/window.cpp
index 673e15fd8..f345bd51f 100644
--- a/examples/wayland/minimal-cpp/window.cpp
+++ b/examples/wayland/minimal-cpp/window.cpp
@@ -95,7 +95,7 @@ void Window::paintGL()
GLuint textureId = texture->textureId();
QWaylandSurface *surface = view->surface();
if (surface && surface->hasContent()) {
- QSize s = surface->size();
+ QSize s = surface->destinationSize();
view->initPosition(size(), s);
QPointF pos = view->globalPosition();
QRectF surfaceGeometry(pos, s);
diff --git a/examples/wayland/qwindow-compositor/compositor.cpp b/examples/wayland/qwindow-compositor/compositor.cpp
index f25e67d87..199de22e2 100644
--- a/examples/wayland/qwindow-compositor/compositor.cpp
+++ b/examples/wayland/qwindow-compositor/compositor.cpp
@@ -79,7 +79,7 @@ QOpenGLTexture *View::getTexture()
if (newContent) {
m_texture = buf.toOpenGLTexture();
if (surface()) {
- m_size = surface()->size();
+ m_size = surface()->destinationSize();
m_origin = buf.origin() == QWaylandSurface::OriginTopLeft
? QOpenGLTextureBlitter::OriginTopLeft
: QOpenGLTextureBlitter::OriginBottomLeft;
@@ -96,7 +96,7 @@ QOpenGLTextureBlitter::Origin View::textureOrigin() const
QSize View::size() const
{
- return surface() ? surface()->size() : m_size;
+ return surface() ? surface()->destinationSize() : m_size;
}
bool View::isCursor() const
diff --git a/examples/wayland/qwindow-compositor/compositor.h b/examples/wayland/qwindow-compositor/compositor.h
index 2a395a1ab..8f18dc53d 100644
--- a/examples/wayland/qwindow-compositor/compositor.h
+++ b/examples/wayland/qwindow-compositor/compositor.h
@@ -82,7 +82,7 @@ public:
void setParentView(View *parent) { m_parentView = parent; }
View *parentView() const { return m_parentView; }
QPointF parentPosition() const { return m_parentView ? (m_parentView->position() + m_parentView->parentPosition()) : QPointF(); }
- QSize windowSize() { return m_xdgSurface ? m_xdgSurface->windowGeometry().size() : surface() ? surface()->size() : m_size; }
+ QSize windowSize() { return m_xdgSurface ? m_xdgSurface->windowGeometry().size() : surface() ? surface()->destinationSize() : m_size; }
QPoint offset() const { return m_offset; }
qreal animationFactor() const {return m_animationFactor; }
diff --git a/examples/wayland/qwindow-compositor/window.cpp b/examples/wayland/qwindow-compositor/window.cpp
index 80aeec4c3..b8b8e52ec 100644
--- a/examples/wayland/qwindow-compositor/window.cpp
+++ b/examples/wayland/qwindow-compositor/window.cpp
@@ -180,7 +180,7 @@ void Window::startResize(int edge, bool anchored)
m_grabState = ResizeGrab;
m_resizeEdge = edge;
m_resizeAnchored = anchored;
- m_resizeAnchorPosition = getAnchorPosition(m_mouseView->position(), edge, m_mouseView->surface()->size());
+ m_resizeAnchorPosition = getAnchorPosition(m_mouseView->position(), edge, m_mouseView->surface()->destinationSize());
}
void Window::startDrag(View *dragIcon)
diff --git a/features/wayland-scanner-client-wayland-protocol-include.prf b/features/wayland-scanner-client-wayland-protocol-include.prf
new file mode 100644
index 000000000..9c5d2d1ed
--- /dev/null
+++ b/features/wayland-scanner-client-wayland-protocol-include.prf
@@ -0,0 +1,53 @@
+# Special version of WAYLANDCLIENTSOURCES to be used with protocols that
+# have requests that create objects with interfaces defined in the core
+# wayland protocol.
+#
+# E.g. the xcomposite protocol has a request which creates a wl_buffer. With
+# the regular wayland-scanner.prf compilation would fail because
+# wl_buffer_interface is not defined.
+#
+# This version solves the problem by prepending
+# #include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
+# to the wayland-scanner generated files.
+
+isEmpty(QMAKE_WAYLAND_SCANNER):error("QMAKE_WAYLAND_SCANNER not defined for this mkspec")
+
+!isEmpty(MODULE_INCNAME) {
+ WAYLAND_INCLUDE_DIR = $$MODULE_INCNAME/private
+}
+
+wayland_client_header.name = wayland ${QMAKE_FILE_BASE}
+wayland_client_header.input = WAYLANDCLIENTSOURCES
+wayland_client_header.variable_out = HEADERS
+wayland_client_header.output = wayland-${QMAKE_FILE_BASE}-client-protocol$${first(QMAKE_EXT_H)}
+# XXX: Prepend the necessary include in the generated header
+wayland_client_header.commands = echo \"$${LITERAL_HASH}include <QtWaylandClient/private/wayland-wayland-client-protocol.h>\" > ${QMAKE_FILE_OUT} && $$QMAKE_WAYLAND_SCANNER --include-core-only client-header < ${QMAKE_FILE_IN} >> ${QMAKE_FILE_OUT}
+QMAKE_EXTRA_COMPILERS += wayland_client_header
+
+wayland_code.name = wayland ${QMAKE_FILE_BASE}
+wayland_code.input = WAYLANDCLIENTSOURCES
+wayland_code.variable_out = SOURCES
+wayland_code.output = wayland-${QMAKE_FILE_BASE}-protocol.c
+wayland_code.commands = $$QMAKE_WAYLAND_SCANNER --include-core-only code < ${QMAKE_FILE_IN} > ${QMAKE_FILE_OUT}
+silent:wayland_code.commands = @echo Wayland code header ${QMAKE_FILE_IN} && $$wayland_code.commands
+QMAKE_EXTRA_COMPILERS += wayland_code
+
+qtPrepareTool(QMAKE_QTWAYLANDSCANNER, qtwaylandscanner)
+
+qtwayland_client_header.name = qtwayland ${QMAKE_FILE_BASE}
+qtwayland_client_header.input = WAYLANDCLIENTSOURCES
+qtwayland_client_header.variable_out = HEADERS
+qtwayland_client_header.depends += $$QMAKE_QTWAYLANDSCANNER_EXE wayland-${QMAKE_FILE_BASE}-client-protocol$${first(QMAKE_EXT_H)}
+qtwayland_client_header.output = qwayland-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)}
+qtwayland_client_header.commands = $$QMAKE_QTWAYLANDSCANNER client-header ${QMAKE_FILE_IN} $$WAYLAND_INCLUDE_DIR > ${QMAKE_FILE_OUT}
+silent:qtwayland_client_header.commands = @echo QtWayland client header ${QMAKE_FILE_IN} && $$qtwayland_client_header.commands
+QMAKE_EXTRA_COMPILERS += qtwayland_client_header
+
+qtwayland_client_code.name = qtwayland ${QMAKE_FILE_BASE}
+qtwayland_client_code.input = WAYLANDCLIENTSOURCES
+qtwayland_client_code.variable_out = SOURCES
+qtwayland_client_code.depends += $$QMAKE_QTWAYLANDSCANNER_EXE qwayland-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)}
+qtwayland_client_code.output = qwayland-${QMAKE_FILE_BASE}.cpp
+qtwayland_client_code.commands = $$QMAKE_QTWAYLANDSCANNER client-code ${QMAKE_FILE_IN} $$WAYLAND_INCLUDE_DIR > ${QMAKE_FILE_OUT}
+silent:qtwayland_client_code.commands = @echo QtWayland client code ${QMAKE_FILE_IN} && $$qtwayland_client_code.commands
+QMAKE_EXTRA_COMPILERS += qtwayland_client_code
diff --git a/src/3rdparty/protocol/fullscreen-shell-unstable-v1.xml b/src/3rdparty/protocol/fullscreen-shell-unstable-v1.xml
new file mode 100644
index 000000000..1bca7b7c7
--- /dev/null
+++ b/src/3rdparty/protocol/fullscreen-shell-unstable-v1.xml
@@ -0,0 +1,245 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="fullscreen_shell_unstable_v1">
+
+ <copyright>
+ Copyright © 2016 Yong Bakos
+ Copyright © 2015 Jason Ekstrand
+ Copyright © 2015 Jonas Ådahl
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+ </copyright>
+
+ <interface name="zwp_fullscreen_shell_v1" version="1">
+ <description summary="displays a single surface per output">
+ Displays a single surface per output.
+
+ This interface provides a mechanism for a single client to display
+ simple full-screen surfaces. While there technically may be multiple
+ clients bound to this interface, only one of those clients should be
+ shown at a time.
+
+ To present a surface, the client uses either the present_surface or
+ present_surface_for_mode requests. Presenting a surface takes effect
+ on the next wl_surface.commit. See the individual requests for
+ details about scaling and mode switches.
+
+ The client can have at most one surface per output at any time.
+ Requesting a surface to be presented on an output that already has a
+ surface replaces the previously presented surface. Presenting a null
+ surface removes its content and effectively disables the output.
+ Exactly what happens when an output is "disabled" is
+ compositor-specific. The same surface may be presented on multiple
+ outputs simultaneously.
+
+ Once a surface is presented on an output, it stays on that output
+ until either the client removes it or the compositor destroys the
+ output. This way, the client can update the output's contents by
+ simply attaching a new buffer.
+
+ Warning! The protocol described in this file is experimental and
+ backward incompatible changes may be made. Backward compatible changes
+ may be added together with the corresponding interface version bump.
+ Backward incompatible changes are done by bumping the version number in
+ the protocol and interface names and resetting the interface version.
+ Once the protocol is to be declared stable, the 'z' prefix and the
+ version number in the protocol and interface names are removed and the
+ interface version number is reset.
+ </description>
+
+ <request name="release" type="destructor">
+ <description summary="release the wl_fullscreen_shell interface">
+ Release the binding from the wl_fullscreen_shell interface.
+
+ This destroys the server-side object and frees this binding. If
+ the client binds to wl_fullscreen_shell multiple times, it may wish
+ to free some of those bindings.
+ </description>
+ </request>
+
+ <enum name="capability">
+ <description summary="capabilities advertised by the compositor">
+ Various capabilities that can be advertised by the compositor. They
+ are advertised one-at-a-time when the wl_fullscreen_shell interface is
+ bound. See the wl_fullscreen_shell.capability event for more details.
+
+ ARBITRARY_MODES:
+ This is a hint to the client that indicates that the compositor is
+ capable of setting practically any mode on its outputs. If this
+ capability is provided, wl_fullscreen_shell.present_surface_for_mode
+ will almost never fail and clients should feel free to set whatever
+ mode they like. If the compositor does not advertise this, it may
+ still support some modes that are not advertised through wl_global.mode
+ but it is less likely.
+
+ CURSOR_PLANE:
+ This is a hint to the client that indicates that the compositor can
+ handle a cursor surface from the client without actually compositing.
+ This may be because of a hardware cursor plane or some other mechanism.
+ If the compositor does not advertise this capability then setting
+ wl_pointer.cursor may degrade performance or be ignored entirely. If
+ CURSOR_PLANE is not advertised, it is recommended that the client draw
+ its own cursor and set wl_pointer.cursor(NULL).
+ </description>
+ <entry name="arbitrary_modes" value="1" summary="compositor is capable of almost any output mode"/>
+ <entry name="cursor_plane" value="2" summary="compositor has a separate cursor plane"/>
+ </enum>
+
+ <event name="capability">
+ <description summary="advertises a capability of the compositor">
+ Advertises a single capability of the compositor.
+
+ When the wl_fullscreen_shell interface is bound, this event is emitted
+ once for each capability advertised. Valid capabilities are given by
+ the wl_fullscreen_shell.capability enum. If clients want to take
+ advantage of any of these capabilities, they should use a
+ wl_display.sync request immediately after binding to ensure that they
+ receive all the capability events.
+ </description>
+ <arg name="capability" type="uint"/>
+ </event>
+
+ <enum name="present_method">
+ <description summary="different method to set the surface fullscreen">
+ Hints to indicate to the compositor how to deal with a conflict
+ between the dimensions of the surface and the dimensions of the
+ output. The compositor is free to ignore this parameter.
+ </description>
+ <entry name="default" value="0" summary="no preference, apply default policy"/>
+ <entry name="center" value="1" summary="center the surface on the output"/>
+ <entry name="zoom" value="2" summary="scale the surface, preserving aspect ratio, to the largest size that will fit on the output" />
+ <entry name="zoom_crop" value="3" summary="scale the surface, preserving aspect ratio, to fully fill the output cropping if needed" />
+ <entry name="stretch" value="4" summary="scale the surface to the size of the output ignoring aspect ratio" />
+ </enum>
+
+ <request name="present_surface">
+ <description summary="present surface for display">
+ Present a surface on the given output.
+
+ If the output is null, the compositor will present the surface on
+ whatever display (or displays) it thinks best. In particular, this
+ may replace any or all surfaces currently presented so it should
+ not be used in combination with placing surfaces on specific
+ outputs.
+
+ The method parameter is a hint to the compositor for how the surface
+ is to be presented. In particular, it tells the compositor how to
+ handle a size mismatch between the presented surface and the
+ output. The compositor is free to ignore this parameter.
+
+ The "zoom", "zoom_crop", and "stretch" methods imply a scaling
+ operation on the surface. This will override any kind of output
+ scaling, so the buffer_scale property of the surface is effectively
+ ignored.
+ </description>
+ <arg name="surface" type="object" interface="wl_surface" allow-null="true"/>
+ <arg name="method" type="uint"/>
+ <arg name="output" type="object" interface="wl_output" allow-null="true"/>
+ </request>
+
+ <request name="present_surface_for_mode">
+ <description summary="present surface for display at a particular mode">
+ Presents a surface on the given output for a particular mode.
+
+ If the current size of the output differs from that of the surface,
+ the compositor will attempt to change the size of the output to
+ match the surface. The result of the mode-switch operation will be
+ returned via the provided wl_fullscreen_shell_mode_feedback object.
+
+ If the current output mode matches the one requested or if the
+ compositor successfully switches the mode to match the surface,
+ then the mode_successful event will be sent and the output will
+ contain the contents of the given surface. If the compositor
+ cannot match the output size to the surface size, the mode_failed
+ will be sent and the output will contain the contents of the
+ previously presented surface (if any). If another surface is
+ presented on the given output before either of these has a chance
+ to happen, the present_cancelled event will be sent.
+
+ Due to race conditions and other issues unknown to the client, no
+ mode-switch operation is guaranteed to succeed. However, if the
+ mode is one advertised by wl_output.mode or if the compositor
+ advertises the ARBITRARY_MODES capability, then the client should
+ expect that the mode-switch operation will usually succeed.
+
+ If the size of the presented surface changes, the resulting output
+ is undefined. The compositor may attempt to change the output mode
+ to compensate. However, there is no guarantee that a suitable mode
+ will be found and the client has no way to be notified of success
+ or failure.
+
+ The framerate parameter specifies the desired framerate for the
+ output in mHz. The compositor is free to ignore this parameter. A
+ value of 0 indicates that the client has no preference.
+
+ If the value of wl_output.scale differs from wl_surface.buffer_scale,
+ then the compositor may choose a mode that matches either the buffer
+ size or the surface size. In either case, the surface will fill the
+ output.
+ </description>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ <arg name="output" type="object" interface="wl_output"/>
+ <arg name="framerate" type="int"/>
+ <arg name="feedback" type="new_id" interface="zwp_fullscreen_shell_mode_feedback_v1"/>
+ </request>
+
+ <enum name="error">
+ <description summary="wl_fullscreen_shell error values">
+ These errors can be emitted in response to wl_fullscreen_shell requests.
+ </description>
+ <entry name="invalid_method" value="0" summary="present_method is not known"/>
+ </enum>
+ </interface>
+
+ <interface name="zwp_fullscreen_shell_mode_feedback_v1" version="1">
+ <event name="mode_successful">
+ <description summary="mode switch succeeded">
+ This event indicates that the attempted mode switch operation was
+ successful. A surface of the size requested in the mode switch
+ will fill the output without scaling.
+
+ Upon receiving this event, the client should destroy the
+ wl_fullscreen_shell_mode_feedback object.
+ </description>
+ </event>
+
+ <event name="mode_failed">
+ <description summary="mode switch failed">
+ This event indicates that the attempted mode switch operation
+ failed. This may be because the requested output mode is not
+ possible or it may mean that the compositor does not want to allow it.
+
+ Upon receiving this event, the client should destroy the
+ wl_fullscreen_shell_mode_feedback object.
+ </description>
+ </event>
+
+ <event name="present_cancelled">
+ <description summary="mode switch cancelled">
+ This event indicates that the attempted mode switch operation was
+ cancelled. Most likely this is because the client requested a
+ second mode switch before the first one completed.
+
+ Upon receiving this event, the client should destroy the
+ wl_fullscreen_shell_mode_feedback object.
+ </description>
+ </event>
+ </interface>
+
+</protocol>
diff --git a/src/3rdparty/protocol/linux-dmabuf-unstable-v1.xml b/src/3rdparty/protocol/linux-dmabuf-unstable-v1.xml
new file mode 100644
index 000000000..154afe23e
--- /dev/null
+++ b/src/3rdparty/protocol/linux-dmabuf-unstable-v1.xml
@@ -0,0 +1,348 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="linux_dmabuf_unstable_v1">
+
+ <copyright>
+ Copyright © 2014, 2015 Collabora, Ltd.
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+ </copyright>
+
+ <interface name="zwp_linux_dmabuf_v1" version="3">
+ <description summary="factory for creating dmabuf-based wl_buffers">
+ Following the interfaces from:
+ https://www.khronos.org/registry/egl/extensions/EXT/EGL_EXT_image_dma_buf_import.txt
+ and the Linux DRM sub-system's AddFb2 ioctl.
+
+ This interface offers ways to create generic dmabuf-based
+ wl_buffers. Immediately after a client binds to this interface,
+ the set of supported formats and format modifiers is sent with
+ 'format' and 'modifier' events.
+
+ The following are required from clients:
+
+ - Clients must ensure that either all data in the dma-buf is
+ coherent for all subsequent read access or that coherency is
+ correctly handled by the underlying kernel-side dma-buf
+ implementation.
+
+ - Don't make any more attachments after sending the buffer to the
+ compositor. Making more attachments later increases the risk of
+ the compositor not being able to use (re-import) an existing
+ dmabuf-based wl_buffer.
+
+ The underlying graphics stack must ensure the following:
+
+ - The dmabuf file descriptors relayed to the server will stay valid
+ for the whole lifetime of the wl_buffer. This means the server may
+ at any time use those fds to import the dmabuf into any kernel
+ sub-system that might accept it.
+
+ To create a wl_buffer from one or more dmabufs, a client creates a
+ zwp_linux_dmabuf_params_v1 object with a zwp_linux_dmabuf_v1.create_params
+ request. All planes required by the intended format are added with
+ the 'add' request. Finally, a 'create' or 'create_immed' request is
+ issued, which has the following outcome depending on the import success.
+
+ The 'create' request,
+ - on success, triggers a 'created' event which provides the final
+ wl_buffer to the client.
+ - on failure, triggers a 'failed' event to convey that the server
+ cannot use the dmabufs received from the client.
+
+ For the 'create_immed' request,
+ - on success, the server immediately imports the added dmabufs to
+ create a wl_buffer. No event is sent from the server in this case.
+ - on failure, the server can choose to either:
+ - terminate the client by raising a fatal error.
+ - mark the wl_buffer as failed, and send a 'failed' event to the
+ client. If the client uses a failed wl_buffer as an argument to any
+ request, the behaviour is compositor implementation-defined.
+
+ Warning! The protocol described in this file is experimental and
+ backward incompatible changes may be made. Backward compatible changes
+ may be added together with the corresponding interface version bump.
+ Backward incompatible changes are done by bumping the version number in
+ the protocol and interface names and resetting the interface version.
+ Once the protocol is to be declared stable, the 'z' prefix and the
+ version number in the protocol and interface names are removed and the
+ interface version number is reset.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="unbind the factory">
+ Objects created through this interface, especially wl_buffers, will
+ remain valid.
+ </description>
+ </request>
+
+ <request name="create_params">
+ <description summary="create a temporary object for buffer parameters">
+ This temporary object is used to collect multiple dmabuf handles into
+ a single batch to create a wl_buffer. It can only be used once and
+ should be destroyed after a 'created' or 'failed' event has been
+ received.
+ </description>
+ <arg name="params_id" type="new_id" interface="zwp_linux_buffer_params_v1"
+ summary="the new temporary"/>
+ </request>
+
+ <event name="format">
+ <description summary="supported buffer format">
+ This event advertises one buffer format that the server supports.
+ All the supported formats are advertised once when the client
+ binds to this interface. A roundtrip after binding guarantees
+ that the client has received all supported formats.
+
+ For the definition of the format codes, see the
+ zwp_linux_buffer_params_v1::create request.
+
+ Warning: the 'format' event is likely to be deprecated and replaced
+ with the 'modifier' event introduced in zwp_linux_dmabuf_v1
+ version 3, described below. Please refrain from using the information
+ received from this event.
+ </description>
+ <arg name="format" type="uint" summary="DRM_FORMAT code"/>
+ </event>
+
+ <event name="modifier" since="3">
+ <description summary="supported buffer format modifier">
+ This event advertises the formats that the server supports, along with
+ the modifiers supported for each format. All the supported modifiers
+ for all the supported formats are advertised once when the client
+ binds to this interface. A roundtrip after binding guarantees that
+ the client has received all supported format-modifier pairs.
+
+ For the definition of the format and modifier codes, see the
+ zwp_linux_buffer_params_v1::create request.
+ </description>
+ <arg name="format" type="uint" summary="DRM_FORMAT code"/>
+ <arg name="modifier_hi" type="uint"
+ summary="high 32 bits of layout modifier"/>
+ <arg name="modifier_lo" type="uint"
+ summary="low 32 bits of layout modifier"/>
+ </event>
+ </interface>
+
+ <interface name="zwp_linux_buffer_params_v1" version="3">
+ <description summary="parameters for creating a dmabuf-based wl_buffer">
+ This temporary object is a collection of dmabufs and other
+ parameters that together form a single logical buffer. The temporary
+ object may eventually create one wl_buffer unless cancelled by
+ destroying it before requesting 'create'.
+
+ Single-planar formats only require one dmabuf, however
+ multi-planar formats may require more than one dmabuf. For all
+ formats, an 'add' request must be called once per plane (even if the
+ underlying dmabuf fd is identical).
+
+ You must use consecutive plane indices ('plane_idx' argument for 'add')
+ from zero to the number of planes used by the drm_fourcc format code.
+ All planes required by the format must be given exactly once, but can
+ be given in any order. Each plane index can be set only once.
+ </description>
+
+ <enum name="error">
+ <entry name="already_used" value="0"
+ summary="the dmabuf_batch object has already been used to create a wl_buffer"/>
+ <entry name="plane_idx" value="1"
+ summary="plane index out of bounds"/>
+ <entry name="plane_set" value="2"
+ summary="the plane index was already set"/>
+ <entry name="incomplete" value="3"
+ summary="missing or too many planes to create a buffer"/>
+ <entry name="invalid_format" value="4"
+ summary="format not supported"/>
+ <entry name="invalid_dimensions" value="5"
+ summary="invalid width or height"/>
+ <entry name="out_of_bounds" value="6"
+ summary="offset + stride * height goes out of dmabuf bounds"/>
+ <entry name="invalid_wl_buffer" value="7"
+ summary="invalid wl_buffer resulted from importing dmabufs via
+ the create_immed request on given buffer_params"/>
+ </enum>
+
+ <request name="destroy" type="destructor">
+ <description summary="delete this object, used or not">
+ Cleans up the temporary data sent to the server for dmabuf-based
+ wl_buffer creation.
+ </description>
+ </request>
+
+ <request name="add">
+ <description summary="add a dmabuf to the temporary set">
+ This request adds one dmabuf to the set in this
+ zwp_linux_buffer_params_v1.
+
+ The 64-bit unsigned value combined from modifier_hi and modifier_lo
+ is the dmabuf layout modifier. DRM AddFB2 ioctl calls this the
+ fb modifier, which is defined in drm_mode.h of Linux UAPI.
+ This is an opaque token. Drivers use this token to express tiling,
+ compression, etc. driver-specific modifications to the base format
+ defined by the DRM fourcc code.
+
+ This request raises the PLANE_IDX error if plane_idx is too large.
+ The error PLANE_SET is raised if attempting to set a plane that
+ was already set.
+ </description>
+ <arg name="fd" type="fd" summary="dmabuf fd"/>
+ <arg name="plane_idx" type="uint" summary="plane index"/>
+ <arg name="offset" type="uint" summary="offset in bytes"/>
+ <arg name="stride" type="uint" summary="stride in bytes"/>
+ <arg name="modifier_hi" type="uint"
+ summary="high 32 bits of layout modifier"/>
+ <arg name="modifier_lo" type="uint"
+ summary="low 32 bits of layout modifier"/>
+ </request>
+
+ <enum name="flags">
+ <entry name="y_invert" value="1" summary="contents are y-inverted"/>
+ <entry name="interlaced" value="2" summary="content is interlaced"/>
+ <entry name="bottom_first" value="4" summary="bottom field first"/>
+ </enum>
+
+ <request name="create">
+ <description summary="create a wl_buffer from the given dmabufs">
+ This asks for creation of a wl_buffer from the added dmabuf
+ buffers. The wl_buffer is not created immediately but returned via
+ the 'created' event if the dmabuf sharing succeeds. The sharing
+ may fail at runtime for reasons a client cannot predict, in
+ which case the 'failed' event is triggered.
+
+ The 'format' argument is a DRM_FORMAT code, as defined by the
+ libdrm's drm_fourcc.h. The Linux kernel's DRM sub-system is the
+ authoritative source on how the format codes should work.
+
+ The 'flags' is a bitfield of the flags defined in enum "flags".
+ 'y_invert' means the that the image needs to be y-flipped.
+
+ Flag 'interlaced' means that the frame in the buffer is not
+ progressive as usual, but interlaced. An interlaced buffer as
+ supported here must always contain both top and bottom fields.
+ The top field always begins on the first pixel row. The temporal
+ ordering between the two fields is top field first, unless
+ 'bottom_first' is specified. It is undefined whether 'bottom_first'
+ is ignored if 'interlaced' is not set.
+
+ This protocol does not convey any information about field rate,
+ duration, or timing, other than the relative ordering between the
+ two fields in one buffer. A compositor may have to estimate the
+ intended field rate from the incoming buffer rate. It is undefined
+ whether the time of receiving wl_surface.commit with a new buffer
+ attached, applying the wl_surface state, wl_surface.frame callback
+ trigger, presentation, or any other point in the compositor cycle
+ is used to measure the frame or field times. There is no support
+ for detecting missed or late frames/fields/buffers either, and
+ there is no support whatsoever for cooperating with interlaced
+ compositor output.
+
+ The composited image quality resulting from the use of interlaced
+ buffers is explicitly undefined. A compositor may use elaborate
+ hardware features or software to deinterlace and create progressive
+ output frames from a sequence of interlaced input buffers, or it
+ may produce substandard image quality. However, compositors that
+ cannot guarantee reasonable image quality in all cases are recommended
+ to just reject all interlaced buffers.
+
+ Any argument errors, including non-positive width or height,
+ mismatch between the number of planes and the format, bad
+ format, bad offset or stride, may be indicated by fatal protocol
+ errors: INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS,
+ OUT_OF_BOUNDS.
+
+ Dmabuf import errors in the server that are not obvious client
+ bugs are returned via the 'failed' event as non-fatal. This
+ allows attempting dmabuf sharing and falling back in the client
+ if it fails.
+
+ This request can be sent only once in the object's lifetime, after
+ which the only legal request is destroy. This object should be
+ destroyed after issuing a 'create' request. Attempting to use this
+ object after issuing 'create' raises ALREADY_USED protocol error.
+
+ It is not mandatory to issue 'create'. If a client wants to
+ cancel the buffer creation, it can just destroy this object.
+ </description>
+ <arg name="width" type="int" summary="base plane width in pixels"/>
+ <arg name="height" type="int" summary="base plane height in pixels"/>
+ <arg name="format" type="uint" summary="DRM_FORMAT code"/>
+ <arg name="flags" type="uint" summary="see enum flags"/>
+ </request>
+
+ <event name="created">
+ <description summary="buffer creation succeeded">
+ This event indicates that the attempted buffer creation was
+ successful. It provides the new wl_buffer referencing the dmabuf(s).
+
+ Upon receiving this event, the client should destroy the
+ zlinux_dmabuf_params object.
+ </description>
+ <arg name="buffer" type="new_id" interface="wl_buffer"
+ summary="the newly created wl_buffer"/>
+ </event>
+
+ <event name="failed">
+ <description summary="buffer creation failed">
+ This event indicates that the attempted buffer creation has
+ failed. It usually means that one of the dmabuf constraints
+ has not been fulfilled.
+
+ Upon receiving this event, the client should destroy the
+ zlinux_buffer_params object.
+ </description>
+ </event>
+
+ <request name="create_immed" since="2">
+ <description summary="immediately create a wl_buffer from the given
+ dmabufs">
+ This asks for immediate creation of a wl_buffer by importing the
+ added dmabufs.
+
+ In case of import success, no event is sent from the server, and the
+ wl_buffer is ready to be used by the client.
+
+ Upon import failure, either of the following may happen, as seen fit
+ by the implementation:
+ - the client is terminated with one of the following fatal protocol
+ errors:
+ - INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, OUT_OF_BOUNDS,
+ in case of argument errors such as mismatch between the number
+ of planes and the format, bad format, non-positive width or
+ height, or bad offset or stride.
+ - INVALID_WL_BUFFER, in case the cause for failure is unknown or
+ plaform specific.
+ - the server creates an invalid wl_buffer, marks it as failed and
+ sends a 'failed' event to the client. The result of using this
+ invalid wl_buffer as an argument in any request by the client is
+ defined by the compositor implementation.
+
+ This takes the same arguments as a 'create' request, and obeys the
+ same restrictions.
+ </description>
+ <arg name="buffer_id" type="new_id" interface="wl_buffer"
+ summary="id for the newly created wl_buffer"/>
+ <arg name="width" type="int" summary="base plane width in pixels"/>
+ <arg name="height" type="int" summary="base plane height in pixels"/>
+ <arg name="format" type="uint" summary="DRM_FORMAT code"/>
+ <arg name="flags" type="uint" summary="see enum flags"/>
+ </request>
+
+ </interface>
+
+</protocol>
diff --git a/src/3rdparty/protocol/qt_attribution.json b/src/3rdparty/protocol/qt_attribution.json
index e5bf91e10..477293118 100644
--- a/src/3rdparty/protocol/qt_attribution.json
+++ b/src/3rdparty/protocol/qt_attribution.json
@@ -1,5 +1,24 @@
[
{
+ "Id": "wayland-fullscreen-protocol",
+ "Name": "Wayland Fullscreen Shell Protocol",
+ "QDocModule": "qtwaylandcompositor",
+ "QtUsage": "Used in the Qt Wayland platform plugin.",
+ "Files": "fullscreen-shell-unstable-v1.xml",
+
+ "Description": "A Wayland shell for displaying a single surface per output",
+ "Homepage": "https://wayland.freedesktop.org",
+ "Version": "unstable v1",
+ "DownloadLocation": "https://cgit.freedesktop.org/wayland/wayland-protocols",
+ "LicenseId": "MIT",
+ "License": "MIT License",
+ "LicenseFile": "MIT_LICENSE.txt",
+ "Copyright": "Copyright © 2016 Yong Bakos
+Copyright © 2015 Jason Ekstrand
+Copyright © 2015 Jonas Ådahl"
+ },
+
+ {
"Id": "wayland-protocol",
"Name": "Wayland Protocol",
"QDocModule": "qtwaylandcompositor",
@@ -37,6 +56,23 @@ Copyright (c) 2013 BMW Car IT GmbH"
},
{
+ "Id": "wayland-viewporter-protocol",
+ "Name": "Wayland Viewporter Protocol",
+ "QDocModule": "qtwaylandcompositor",
+ "QtUsage": "Used in the Qt Wayland Compositor API",
+ "Files": "viewporter.xml",
+
+ "Description": "The Wayland viewporter extension allows a client to scale or crop a surface without modifying the buffer",
+ "Homepage": "https://wayland.freedesktop.org",
+ "Version": "1",
+ "DownloadLocation": "https://cgit.freedesktop.org/wayland/wayland-protocols/plain/stable/viewporter/viewporter.xml",
+ "LicenseId": "MIT",
+ "License": "MIT License",
+ "LicenseFile": "MIT_LICENSE.txt",
+ "Copyright": "Copyright © 2013-2016 Collabora, Ltd."
+ },
+
+ {
"Id": "wayland-xdg-decoration-protocol",
"Name": "Wayland xdg-decoration Protocol",
"QDocModule": "qtwaylandcompositor",
@@ -103,5 +139,20 @@ Copyright © 2010-2013 Intel Corporation"
"LicenseFile": "HPND_LICENSE.txt",
"Copyright": "Copyright © 2012, 2013 Intel Corporation
Copyright © 2015, 2016 Jan Arne Petersen"
+ },
+
+ {
+ "Id": "wayland-linux-dmabuf-unstable-v1",
+ "Name": "Wayland Linux Dmabuf Unstable V1 Protocol",
+ "QDocModule": "qtwaylandcompositor",
+ "QtUsage": "Used in the Qt Wayland Compositor",
+ "Files": "linux-dmabuf-unstable-v1.xml",
+
+ "Description": "The linux dmabuf protocol is a way to create dmabuf-based wl_buffers",
+ "Homepage": "https://wayland.freedesktop.org",
+ "LicenseId": "MIT",
+ "License": "MIT License",
+ "LicenseFile": "MIT_LICENSE.txt",
+ "Copyright": "Copyright © 2014, 2015 Collabora, Ltd."
}
]
diff --git a/src/3rdparty/protocol/viewporter.xml b/src/3rdparty/protocol/viewporter.xml
new file mode 100644
index 000000000..c732d8c35
--- /dev/null
+++ b/src/3rdparty/protocol/viewporter.xml
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="viewporter">
+
+ <copyright>
+ Copyright © 2013-2016 Collabora, Ltd.
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+ </copyright>
+
+ <interface name="wp_viewporter" version="1">
+ <description summary="surface cropping and scaling">
+ The global interface exposing surface cropping and scaling
+ capabilities is used to instantiate an interface extension for a
+ wl_surface object. This extended interface will then allow
+ cropping and scaling the surface contents, effectively
+ disconnecting the direct relationship between the buffer and the
+ surface size.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="unbind from the cropping and scaling interface">
+ Informs the server that the client will not be using this
+ protocol object anymore. This does not affect any other objects,
+ wp_viewport objects included.
+ </description>
+ </request>
+
+ <enum name="error">
+ <entry name="viewport_exists" value="0"
+ summary="the surface already has a viewport object associated"/>
+ </enum>
+
+ <request name="get_viewport">
+ <description summary="extend surface interface for crop and scale">
+ Instantiate an interface extension for the given wl_surface to
+ crop and scale its content. If the given wl_surface already has
+ a wp_viewport object associated, the viewport_exists
+ protocol error is raised.
+ </description>
+ <arg name="id" type="new_id" interface="wp_viewport"
+ summary="the new viewport interface id"/>
+ <arg name="surface" type="object" interface="wl_surface"
+ summary="the surface"/>
+ </request>
+ </interface>
+
+ <interface name="wp_viewport" version="1">
+ <description summary="crop and scale interface to a wl_surface">
+ An additional interface to a wl_surface object, which allows the
+ client to specify the cropping and scaling of the surface
+ contents.
+
+ This interface works with two concepts: the source rectangle (src_x,
+ src_y, src_width, src_height), and the destination size (dst_width,
+ dst_height). The contents of the source rectangle are scaled to the
+ destination size, and content outside the source rectangle is ignored.
+ This state is double-buffered, and is applied on the next
+ wl_surface.commit.
+
+ The two parts of crop and scale state are independent: the source
+ rectangle, and the destination size. Initially both are unset, that
+ is, no scaling is applied. The whole of the current wl_buffer is
+ used as the source, and the surface size is as defined in
+ wl_surface.attach.
+
+ If the destination size is set, it causes the surface size to become
+ dst_width, dst_height. The source (rectangle) is scaled to exactly
+ this size. This overrides whatever the attached wl_buffer size is,
+ unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
+ has no content and therefore no size. Otherwise, the size is always
+ at least 1x1 in surface local coordinates.
+
+ If the source rectangle is set, it defines what area of the wl_buffer is
+ taken as the source. If the source rectangle is set and the destination
+ size is not set, then src_width and src_height must be integers, and the
+ surface size becomes the source rectangle size. This results in cropping
+ without scaling. If src_width or src_height are not integers and
+ destination size is not set, the bad_size protocol error is raised when
+ the surface state is applied.
+
+ The coordinate transformations from buffer pixel coordinates up to
+ the surface-local coordinates happen in the following order:
+ 1. buffer_transform (wl_surface.set_buffer_transform)
+ 2. buffer_scale (wl_surface.set_buffer_scale)
+ 3. crop and scale (wp_viewport.set*)
+ This means, that the source rectangle coordinates of crop and scale
+ are given in the coordinates after the buffer transform and scale,
+ i.e. in the coordinates that would be the surface-local coordinates
+ if the crop and scale was not applied.
+
+ If src_x or src_y are negative, the bad_value protocol error is raised.
+ Otherwise, if the source rectangle is partially or completely outside of
+ the non-NULL wl_buffer, then the out_of_buffer protocol error is raised
+ when the surface state is applied. A NULL wl_buffer does not raise the
+ out_of_buffer error.
+
+ The x, y arguments of wl_surface.attach are applied as normal to
+ the surface. They indicate how many pixels to remove from the
+ surface size from the left and the top. In other words, they are
+ still in the surface-local coordinate system, just like dst_width
+ and dst_height are.
+
+ If the wl_surface associated with the wp_viewport is destroyed,
+ all wp_viewport requests except 'destroy' raise the protocol error
+ no_surface.
+
+ If the wp_viewport object is destroyed, the crop and scale
+ state is removed from the wl_surface. The change will be applied
+ on the next wl_surface.commit.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="remove scaling and cropping from the surface">
+ The associated wl_surface's crop and scale state is removed.
+ The change is applied on the next wl_surface.commit.
+ </description>
+ </request>
+
+ <enum name="error">
+ <entry name="bad_value" value="0"
+ summary="negative or zero values in width or height"/>
+ <entry name="bad_size" value="1"
+ summary="destination size is not integer"/>
+ <entry name="out_of_buffer" value="2"
+ summary="source rectangle extends outside of the content area"/>
+ <entry name="no_surface" value="3"
+ summary="the wl_surface was destroyed"/>
+ </enum>
+
+ <request name="set_source">
+ <description summary="set the source rectangle for cropping">
+ Set the source rectangle of the associated wl_surface. See
+ wp_viewport for the description, and relation to the wl_buffer
+ size.
+
+ If all of x, y, width and height are -1.0, the source rectangle is
+ unset instead. Any other set of values where width or height are zero
+ or negative, or x or y are negative, raise the bad_value protocol
+ error.
+
+ The crop and scale state is double-buffered state, and will be
+ applied on the next wl_surface.commit.
+ </description>
+ <arg name="x" type="fixed" summary="source rectangle x"/>
+ <arg name="y" type="fixed" summary="source rectangle y"/>
+ <arg name="width" type="fixed" summary="source rectangle width"/>
+ <arg name="height" type="fixed" summary="source rectangle height"/>
+ </request>
+
+ <request name="set_destination">
+ <description summary="set the surface size for scaling">
+ Set the destination size of the associated wl_surface. See
+ wp_viewport for the description, and relation to the wl_buffer
+ size.
+
+ If width is -1 and height is -1, the destination size is unset
+ instead. Any other pair of values for width and height that
+ contains zero or negative values raises the bad_value protocol
+ error.
+
+ The crop and scale state is double-buffered state, and will be
+ applied on the next wl_surface.commit.
+ </description>
+ <arg name="width" type="int" summary="surface width"/>
+ <arg name="height" type="int" summary="surface height"/>
+ </request>
+ </interface>
+
+</protocol>
diff --git a/src/client/client.pro b/src/client/client.pro
index 30f32dd7e..38d0ac3e1 100644
--- a/src/client/client.pro
+++ b/src/client/client.pro
@@ -18,6 +18,9 @@ CONFIG += link_pkgconfig wayland-scanner
qtConfig(xkbcommon): \
QMAKE_USE_PRIVATE += xkbcommon
+qtHaveModule(linuxaccessibility_support_private): \
+ QT += linuxaccessibility_support_private
+
QMAKE_USE += wayland-client
INCLUDEPATH += $$PWD/../shared
@@ -29,9 +32,7 @@ WAYLANDCLIENTSOURCES += \
../extensions/qt-windowmanager.xml \
../3rdparty/protocol/text-input-unstable-v2.xml \
../3rdparty/protocol/xdg-output-unstable-v1.xml \
-
-WAYLANDCLIENTSOURCES_SYSTEM += \
- ../3rdparty/protocol/wayland.xml \
+ ../3rdparty/protocol/wayland.xml
SOURCES += qwaylandintegration.cpp \
qwaylandnativeinterface.cpp \
diff --git a/src/client/configure.json b/src/client/configure.json
index 1f86a4936..b5146680e 100644
--- a/src/client/configure.json
+++ b/src/client/configure.json
@@ -87,6 +87,36 @@
"condition": "features.draganddrop || features.clipboard",
"output": [ "privateFeature" ]
},
+ "wayland-client-fullscreen-shell-v1": {
+ "label": "fullscreen-shell-v1",
+ "condition": "features.wayland-client",
+ "output": [ "privateFeature" ]
+ },
+ "wayland-client-ivi-shell": {
+ "label": "ivi-shell",
+ "condition": "features.wayland-client",
+ "output": [ "privateFeature" ]
+ },
+ "wayland-client-wl-shell": {
+ "label": "wl-shell (deprecated)",
+ "condition": "features.wayland-client",
+ "output": [ "privateFeature" ]
+ },
+ "wayland-client-xdg-shell": {
+ "label": "xdg-shell",
+ "condition": "features.wayland-client",
+ "output": [ "privateFeature" ]
+ },
+ "wayland-client-xdg-shell-v5": {
+ "label": "xdg-shell unstable v5 (deprecated)",
+ "condition": "features.wayland-client",
+ "output": [ "privateFeature" ]
+ },
+ "wayland-client-xdg-shell-v6": {
+ "label": "xdg-shell unstable v6",
+ "condition": "features.wayland-client",
+ "output": [ "privateFeature" ]
+ },
"wayland-egl": {
"label": "EGL",
"condition": "features.wayland-client && features.opengl && features.egl && libs.wayland-egl",
@@ -151,6 +181,17 @@
"wayland-shm-emulation-server-buffer"
]
},
+ {
+ "section": "Qt Wayland Client Shell Integrations",
+ "condition": "features.wayland-client",
+ "entries": [
+ "wayland-client-xdg-shell",
+ "wayland-client-xdg-shell-v5",
+ "wayland-client-xdg-shell-v6",
+ "wayland-client-ivi-shell",
+ "wayland-client-wl-shell"
+ ]
+ },
"wayland-client"
]
}
diff --git a/src/client/qwaylandabstractdecoration.cpp b/src/client/qwaylandabstractdecoration.cpp
index 6a8f1d92d..3196af3b0 100644
--- a/src/client/qwaylandabstractdecoration.cpp
+++ b/src/client/qwaylandabstractdecoration.cpp
@@ -146,11 +146,11 @@ void QWaylandAbstractDecoration::setMouseButtons(Qt::MouseButtons mb)
d->m_mouseButtons = mb;
}
-void QWaylandAbstractDecoration::startResize(QWaylandInputDevice *inputDevice, enum wl_shell_surface_resize resize, Qt::MouseButtons buttons)
+void QWaylandAbstractDecoration::startResize(QWaylandInputDevice *inputDevice, Qt::Edges edges, Qt::MouseButtons buttons)
{
Q_D(QWaylandAbstractDecoration);
if (isLeftClicked(buttons) && d->m_wayland_window->shellSurface()) {
- d->m_wayland_window->shellSurface()->resize(inputDevice, resize);
+ d->m_wayland_window->shellSurface()->resize(inputDevice, edges);
inputDevice->removeMouseButtonFromState(Qt::LeftButton);
}
}
diff --git a/src/client/qwaylandabstractdecoration_p.h b/src/client/qwaylandabstractdecoration_p.h
index 84a6d4dd7..f5b1854dd 100644
--- a/src/client/qwaylandabstractdecoration_p.h
+++ b/src/client/qwaylandabstractdecoration_p.h
@@ -61,8 +61,6 @@
#include <QtGui/QImage>
#include <QtWaylandClient/qtwaylandclientglobal.h>
-#include <wayland-client.h>
-
#include <QtCore/QDebug>
QT_BEGIN_NAMESPACE
@@ -105,7 +103,7 @@ protected:
void setMouseButtons(Qt::MouseButtons mb);
- void startResize(QWaylandInputDevice *inputDevice,enum wl_shell_surface_resize resize, Qt::MouseButtons buttons);
+ void startResize(QWaylandInputDevice *inputDevice, Qt::Edges edges, Qt::MouseButtons buttons);
void startMove(QWaylandInputDevice *inputDevice, Qt::MouseButtons buttons);
bool isLeftClicked(Qt::MouseButtons newMouseButtonState);
diff --git a/src/client/qwaylandbuffer_p.h b/src/client/qwaylandbuffer_p.h
index eea090f35..945f1279a 100644
--- a/src/client/qwaylandbuffer_p.h
+++ b/src/client/qwaylandbuffer_p.h
@@ -56,8 +56,7 @@
#include <QtCore/QSize>
#include <QtCore/QRect>
-#include <wayland-client.h>
-#include <wayland-client-protocol.h>
+#include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
QT_BEGIN_NAMESPACE
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
index a2957e0dd..91c1d4115 100644
--- a/src/client/qwaylanddisplay.cpp
+++ b/src/client/qwaylanddisplay.cpp
@@ -236,8 +236,6 @@ void QWaylandDisplay::waitForScreens()
void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uint32_t version)
{
- Q_UNUSED(version);
-
struct ::wl_registry *registry = object();
if (interface == QStringLiteral("wl_output")) {
@@ -272,10 +270,13 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
inputDevice->setTextInput(new QWaylandTextInput(this, mTextInputManager->get_text_input(inputDevice->wl_seat())));
}
} else if (interface == QStringLiteral("qt_hardware_integration")) {
- mHardwareIntegration.reset(new QWaylandHardwareIntegration(registry, id));
- // make a roundtrip here since we need to receive the events sent by
- // qt_hardware_integration before creating windows
- forceRoundTrip();
+ bool disableHardwareIntegration = qEnvironmentVariableIntValue("QT_WAYLAND_DISABLE_HW_INTEGRATION");
+ if (!disableHardwareIntegration) {
+ mHardwareIntegration.reset(new QWaylandHardwareIntegration(registry, id));
+ // make a roundtrip here since we need to receive the events sent by
+ // qt_hardware_integration before creating windows
+ forceRoundTrip();
+ }
} else if (interface == QLatin1String("zxdg_output_manager_v1")) {
mXdgOutputManager.reset(new QtWayland::zxdg_output_manager_v1(registry, id, 1));
for (auto *screen : qAsConst(mScreens))
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
index 43ccc0a96..e9439d1be 100644
--- a/src/client/qwaylanddisplay_p.h
+++ b/src/client/qwaylanddisplay_p.h
@@ -59,8 +59,6 @@
#include <QtCore/QWaitCondition>
#include <QtCore/QLoggingCategory>
-#include <wayland-client.h>
-
#include <QtWaylandClient/private/qwayland-wayland.h>
#include <QtWaylandClient/private/qtwaylandclientglobal_p.h>
#include <QtWaylandClient/private/qwaylandshm_p.h>
diff --git a/src/client/qwaylandextendedsurface_p.h b/src/client/qwaylandextendedsurface_p.h
index cd604f342..d71ac6be9 100644
--- a/src/client/qwaylandextendedsurface_p.h
+++ b/src/client/qwaylandextendedsurface_p.h
@@ -56,7 +56,6 @@
#include <QtWaylandClient/qtwaylandclientglobal.h>
-#include <wayland-client.h>
#include <QtWaylandClient/private/qwayland-surface-extension.h>
QT_BEGIN_NAMESPACE
diff --git a/src/client/qwaylandinputcontext_p.h b/src/client/qwaylandinputcontext_p.h
index 93300e1f5..10132dfe1 100644
--- a/src/client/qwaylandinputcontext_p.h
+++ b/src/client/qwaylandinputcontext_p.h
@@ -62,6 +62,9 @@
#include <QtWaylandClient/private/qwayland-text-input-unstable-v2.h>
#include <qwaylandinputmethodeventbuilder_p.h>
+struct wl_callback;
+struct wl_callback_listener;
+
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(qLcQpaInputMethods)
diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp
index 90e138a3d..2dff4b6c3 100644
--- a/src/client/qwaylandinputdevice.cpp
+++ b/src/client/qwaylandinputdevice.cpp
@@ -238,7 +238,6 @@ void QWaylandInputDevice::seat_capabilities(uint32_t caps)
if (caps & WL_SEAT_CAPABILITY_POINTER && !mPointer) {
mPointer = createPointer(this);
mPointer->init(get_pointer());
- pointerSurface = mQDisplay->createSurface(this);
} else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && mPointer) {
delete mPointer;
mPointer = nullptr;
@@ -419,6 +418,9 @@ void QWaylandInputDevice::setCursor(struct wl_buffer *buffer, const QPoint &hotS
return;
}
+ if (!pointerSurface)
+ pointerSurface = mQDisplay->createSurface(this);
+
mPointer->set_cursor(mPointer->mEnterSerial, pointerSurface,
hotSpot.x(), hotSpot.y());
wl_surface_attach(pointerSurface, buffer, 0, 0);
@@ -787,7 +789,7 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time,
#if QT_CONFIG(xkbcommon)
mRepeatSym = sym;
#endif
- mRepeatTimer.setInterval(400);
+ mRepeatTimer.setInterval(mRepeatDelay);
mRepeatTimer.start();
} else if (mRepeatCode == code) {
mRepeatTimer.stop();
@@ -802,7 +804,7 @@ void QWaylandInputDevice::Keyboard::repeatKey()
return;
}
- mRepeatTimer.setInterval(25);
+ mRepeatTimer.setInterval(mRepeatRate);
sendKey(mFocus->window(), mRepeatTime, QEvent::KeyRelease, mRepeatKey, modifiers(), mRepeatCode,
#if QT_CONFIG(xkbcommon)
mRepeatSym, mNativeModifiers,
@@ -842,6 +844,12 @@ void QWaylandInputDevice::Keyboard::keyboard_modifiers(uint32_t serial,
#endif
}
+void QWaylandInputDevice::Keyboard::keyboard_repeat_info(int32_t rate, int32_t delay)
+{
+ mRepeatRate = rate;
+ mRepeatDelay = delay;
+}
+
void QWaylandInputDevice::Touch::touch_down(uint32_t serial,
uint32_t time,
struct wl_surface *surface,
diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h
index 7aa86539b..f27f329be 100644
--- a/src/client/qwaylandinputdevice_p.h
+++ b/src/client/qwaylandinputdevice_p.h
@@ -61,8 +61,6 @@
#include <qpa/qplatformscreen.h>
#include <qpa/qwindowsysteminterface.h>
-#include <wayland-client.h>
-
#include <QtWaylandClient/private/qwayland-wayland.h>
#if QT_CONFIG(xkbcommon)
@@ -206,6 +204,7 @@ public:
uint32_t mods_latched,
uint32_t mods_locked,
uint32_t group) override;
+ void keyboard_repeat_info(int32_t rate, int32_t delay) override;
QWaylandInputDevice *mParent = nullptr;
QPointer<QWaylandWindow> mFocus;
@@ -221,6 +220,8 @@ public:
int mRepeatKey;
uint32_t mRepeatCode;
uint32_t mRepeatTime;
+ int mRepeatRate = 25;
+ int mRepeatDelay = 400;
QString mRepeatText;
#if QT_CONFIG(xkbcommon)
xkb_keysym_t mRepeatSym;
diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp
index e935ef31f..1ffaf3c89 100644
--- a/src/client/qwaylandintegration.cpp
+++ b/src/client/qwaylandintegration.cpp
@@ -86,6 +86,10 @@
#include "qwaylandinputdeviceintegration_p.h"
#include "qwaylandinputdeviceintegrationfactory_p.h"
+#ifndef QT_NO_ACCESSIBILITY_ATSPI_BRIDGE
+#include <QtLinuxAccessibilitySupport/private/bridge_p.h>
+#endif
+
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
@@ -129,9 +133,6 @@ QWaylandIntegration::QWaylandIntegration()
: mFontDb(new QGenericUnixFontDatabase())
#endif
, mNativeInterface(new QWaylandNativeInterface(this))
-#if QT_CONFIG(accessibility)
- , mAccessibility(new QPlatformAccessibility())
-#endif
{
initializeInputDeviceIntegration();
mDisplay.reset(new QWaylandDisplay(this));
@@ -277,6 +278,15 @@ QVariant QWaylandIntegration::styleHint(StyleHint hint) const
#if QT_CONFIG(accessibility)
QPlatformAccessibility *QWaylandIntegration::accessibility() const
{
+ if (!mAccessibility) {
+#ifndef QT_NO_ACCESSIBILITY_ATSPI_BRIDGE
+ Q_ASSERT_X(QCoreApplication::eventDispatcher(), "QXcbIntegration",
+ "Initializing accessibility without event-dispatcher!");
+ mAccessibility.reset(new QSpiAccessibleBridge());
+#else
+ mAccessibility.reset(new QPlatformAccessibility());
+#endif
+ }
return mAccessibility.data();
}
#endif
@@ -329,16 +339,15 @@ void QWaylandIntegration::initializeClientBufferIntegration()
{
mClientBufferIntegrationInitialized = true;
- QString targetKey;
- bool disableHardwareIntegration = qEnvironmentVariableIsSet("QT_WAYLAND_DISABLE_HW_INTEGRATION");
- disableHardwareIntegration = disableHardwareIntegration || !mDisplay->hardwareIntegration();
- if (disableHardwareIntegration) {
- QByteArray clientBufferIntegrationName = qgetenv("QT_WAYLAND_CLIENT_BUFFER_INTEGRATION");
- if (clientBufferIntegrationName.isEmpty())
- clientBufferIntegrationName = QByteArrayLiteral("wayland-egl");
- targetKey = QString::fromLocal8Bit(clientBufferIntegrationName);
- } else {
- targetKey = mDisplay->hardwareIntegration()->clientBufferIntegration();
+ QString targetKey = QString::fromLocal8Bit(qgetenv("QT_WAYLAND_CLIENT_BUFFER_INTEGRATION"));
+
+ if (targetKey.isEmpty()) {
+ if (mDisplay->hardwareIntegration()
+ && mDisplay->hardwareIntegration()->clientBufferIntegration() != QLatin1String("linux-dmabuf-unstable-v1")) {
+ targetKey = mDisplay->hardwareIntegration()->clientBufferIntegration();
+ } else {
+ targetKey = QLatin1Literal("wayland-egl");
+ }
}
if (targetKey.isEmpty()) {
@@ -347,29 +356,28 @@ void QWaylandIntegration::initializeClientBufferIntegration()
}
QStringList keys = QWaylandClientBufferIntegrationFactory::keys();
- if (keys.contains(targetKey)) {
+ qCDebug(lcQpaWayland) << "Available client buffer integrations:" << keys;
+
+ if (keys.contains(targetKey))
mClientBufferIntegration.reset(QWaylandClientBufferIntegrationFactory::create(targetKey, QStringList()));
- }
- if (mClientBufferIntegration)
+
+ if (mClientBufferIntegration) {
+ qCDebug(lcQpaWayland) << "Initializing client buffer integration" << targetKey;
mClientBufferIntegration->initialize(mDisplay.data());
- else
- qWarning("Failed to load client buffer integration: %s\n", qPrintable(targetKey));
+ } else {
+ qCWarning(lcQpaWayland) << "Failed to load client buffer integration:" << targetKey;
+ qCWarning(lcQpaWayland) << "Available client buffer integrations:" << keys;
+ }
}
void QWaylandIntegration::initializeServerBufferIntegration()
{
mServerBufferIntegrationInitialized = true;
- QString targetKey;
+ QString targetKey = QString::fromLocal8Bit(qgetenv("QT_WAYLAND_SERVER_BUFFER_INTEGRATION"));
- bool disableHardwareIntegration = qEnvironmentVariableIsSet("QT_WAYLAND_DISABLE_HW_INTEGRATION");
- disableHardwareIntegration = disableHardwareIntegration || !mDisplay->hardwareIntegration();
- if (disableHardwareIntegration) {
- QByteArray serverBufferIntegrationName = qgetenv("QT_WAYLAND_SERVER_BUFFER_INTEGRATION");
- targetKey = QString::fromLocal8Bit(serverBufferIntegrationName);
- } else {
+ if (targetKey.isEmpty() && mDisplay->hardwareIntegration())
targetKey = mDisplay->hardwareIntegration()->serverBufferIntegration();
- }
if (targetKey.isEmpty()) {
qWarning("Failed to determine what server buffer integration to use");
@@ -377,13 +385,18 @@ void QWaylandIntegration::initializeServerBufferIntegration()
}
QStringList keys = QWaylandServerBufferIntegrationFactory::keys();
- if (keys.contains(targetKey)) {
+ qCDebug(lcQpaWayland) << "Available server buffer integrations:" << keys;
+
+ if (keys.contains(targetKey))
mServerBufferIntegration.reset(QWaylandServerBufferIntegrationFactory::create(targetKey, QStringList()));
- }
- if (mServerBufferIntegration)
+
+ if (mServerBufferIntegration) {
+ qCDebug(lcQpaWayland) << "Initializing server buffer integration" << targetKey;
mServerBufferIntegration->initialize(mDisplay.data());
- else
- qWarning("Failed to load server buffer integration %s\n", qPrintable(targetKey));
+ } else {
+ qCWarning(lcQpaWayland) << "Failed to load server buffer integration: " << targetKey;
+ qCWarning(lcQpaWayland) << "Available server buffer integrations:" << keys;
+ }
}
void QWaylandIntegration::initializeShellIntegration()
@@ -411,7 +424,7 @@ void QWaylandIntegration::initializeShellIntegration()
Q_FOREACH (QString preferredShell, preferredShells) {
mShellIntegration.reset(createShellIntegration(preferredShell));
if (mShellIntegration) {
- qDebug("Using the '%s' shell integration", qPrintable(preferredShell));
+ qCDebug(lcQpaWayland, "Using the '%s' shell integration", qPrintable(preferredShell));
break;
}
}
diff --git a/src/client/qwaylandintegration_p.h b/src/client/qwaylandintegration_p.h
index a5a3d7b69..944f635bb 100644
--- a/src/client/qwaylandintegration_p.h
+++ b/src/client/qwaylandintegration_p.h
@@ -145,7 +145,7 @@ private:
QScopedPointer<QPlatformNativeInterface> mNativeInterface;
QScopedPointer<QPlatformInputContext> mInputContext;
#if QT_CONFIG(accessibility)
- QScopedPointer<QPlatformAccessibility> mAccessibility;
+ mutable QScopedPointer<QPlatformAccessibility> mAccessibility;
#endif
bool mFailed = false;
bool mClientBufferIntegrationInitialized = false;
diff --git a/src/client/qwaylandshellsurface_p.h b/src/client/qwaylandshellsurface_p.h
index 6bc3258c7..f683d9e01 100644
--- a/src/client/qwaylandshellsurface_p.h
+++ b/src/client/qwaylandshellsurface_p.h
@@ -54,8 +54,6 @@
#include <QtCore/QSize>
#include <QObject>
-#include <wayland-client.h>
-
#include <QtWaylandClient/private/qwayland-wayland.h>
#include <QtWaylandClient/qtwaylandclientglobal.h>
@@ -75,8 +73,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandShellSurface : public QObject
public:
explicit QWaylandShellSurface(QWaylandWindow *window);
~QWaylandShellSurface() override {}
- virtual void resize(QWaylandInputDevice * /*inputDevice*/, enum wl_shell_surface_resize /*edges*/)
- {}
+ virtual void resize(QWaylandInputDevice * /*inputDevice*/, Qt::Edges /*edges*/) {}
virtual bool move(QWaylandInputDevice *) { return false; }
virtual void setTitle(const QString & /*title*/) {}
diff --git a/src/client/qwaylandshmbackingstore.cpp b/src/client/qwaylandshmbackingstore.cpp
index 3fe2ce80c..34044ec9b 100644
--- a/src/client/qwaylandshmbackingstore.cpp
+++ b/src/client/qwaylandshmbackingstore.cpp
@@ -49,8 +49,7 @@
#include <QtGui/QPainter>
#include <QMutexLocker>
-#include <wayland-client.h>
-#include <wayland-client-protocol.h>
+#include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
#include <unistd.h>
#include <sys/mman.h>
diff --git a/src/client/qwaylandsubsurface_p.h b/src/client/qwaylandsubsurface_p.h
index e9a7cb20e..76da10b24 100644
--- a/src/client/qwaylandsubsurface_p.h
+++ b/src/client/qwaylandsubsurface_p.h
@@ -51,8 +51,6 @@
// We mean it.
//
-#include <wayland-client.h>
-
#include <QtCore/qglobal.h>
#include <QtCore/qmutex.h>
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
index 470ae0091..17576ecee 100644
--- a/src/client/qwaylandwindow.cpp
+++ b/src/client/qwaylandwindow.cpp
@@ -67,8 +67,6 @@
#include <QtCore/QDebug>
-#include <wayland-client.h>
-
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
@@ -500,9 +498,11 @@ void QWaylandWindow::surface_enter(wl_output *output)
auto addedScreen = QWaylandScreen::fromWlOutput(output);
if (mScreens.contains(addedScreen)) {
- qWarning() << "Unexpected wl_surface.enter received for output with id:"
- << wl_proxy_get_id(reinterpret_cast<wl_proxy *>(output))
- << "screen name:" << addedScreen->name() << "screen model:" << addedScreen->model();
+ qWarning(lcQpaWayland) << "Ignoring unexpected wl_surface.enter received for output with id:"
+ << wl_proxy_get_id(reinterpret_cast<wl_proxy *>(output))
+ << "screen name:" << addedScreen->name()
+ << "screen model:" << addedScreen->model()
+ << "This is most likely a bug in the compositor.";
return;
}
@@ -519,9 +519,11 @@ void QWaylandWindow::surface_leave(wl_output *output)
auto *removedScreen = QWaylandScreen::fromWlOutput(output);
bool wasRemoved = mScreens.removeOne(removedScreen);
if (!wasRemoved) {
- qWarning() << "Unexpected wl_surface.leave received for output with id:"
- << wl_proxy_get_id(reinterpret_cast<wl_proxy *>(output))
- << "screen name:" << removedScreen->name() << "screen model:" << removedScreen->model();
+ qWarning(lcQpaWayland) << "Ignoring unexpected wl_surface.leave received for output with id:"
+ << wl_proxy_get_id(reinterpret_cast<wl_proxy *>(output))
+ << "screen name:" << removedScreen->name()
+ << "screen model:" << removedScreen->model()
+ << "This is most likely a bug in the compositor.";
return;
}
diff --git a/src/client/qwaylandwindowmanagerintegration_p.h b/src/client/qwaylandwindowmanagerintegration_p.h
index 1319abd91..31de6ddd3 100644
--- a/src/client/qwaylandwindowmanagerintegration_p.h
+++ b/src/client/qwaylandwindowmanagerintegration_p.h
@@ -54,7 +54,6 @@
#include <QtCore/QObject>
#include <QtCore/QScopedPointer>
-#include <wayland-client.h>
#include <QtServiceSupport/private/qgenericunixservices_p.h>
#include <QtWaylandClient/private/qwayland-qt-windowmanager.h>
diff --git a/src/compositor/compositor_api/qwaylandclient.cpp b/src/compositor/compositor_api/qwaylandclient.cpp
index 7f0b225b2..d26dfc6d5 100644
--- a/src/compositor/compositor_api/qwaylandclient.cpp
+++ b/src/compositor/compositor_api/qwaylandclient.cpp
@@ -44,7 +44,7 @@
#include <QtWaylandCompositor/private/qwaylandcompositor_p.h>
-#include <wayland-server.h>
+#include <wayland-server-core.h>
#include <wayland-util.h>
QT_BEGIN_NAMESPACE
diff --git a/src/compositor/compositor_api/qwaylanddestroylistener_p.h b/src/compositor/compositor_api/qwaylanddestroylistener_p.h
index 7c6001c36..0bbeb69c0 100644
--- a/src/compositor/compositor_api/qwaylanddestroylistener_p.h
+++ b/src/compositor/compositor_api/qwaylanddestroylistener_p.h
@@ -55,7 +55,7 @@
#include <QtCore/private/qobject_p.h>
-#include <wayland-server.h>
+#include <wayland-server-core.h>
QT_BEGIN_NAMESPACE
diff --git a/src/compositor/compositor_api/qwaylandoutput.cpp b/src/compositor/compositor_api/qwaylandoutput.cpp
index 1f34f4eac..006edbe6a 100644
--- a/src/compositor/compositor_api/qwaylandoutput.cpp
+++ b/src/compositor/compositor_api/qwaylandoutput.cpp
@@ -47,6 +47,7 @@
#include <QtWaylandCompositor/private/qwaylandsurface_p.h>
#include <QtWaylandCompositor/private/qwaylandcompositor_p.h>
#include <QtWaylandCompositor/private/qwaylandview_p.h>
+#include <QtWaylandCompositor/private/qwaylandutils_p.h>
#include <QtCore/QCoreApplication>
#include <QtCore/QtMath>
@@ -350,8 +351,8 @@ void QWaylandOutput::initialize()
*/
QWaylandOutput *QWaylandOutput::fromResource(wl_resource *resource)
{
- if (auto *r = QWaylandOutputPrivate::Resource::fromResource(resource))
- return static_cast<QWaylandOutputPrivate *>(r->output_object)->q_func();
+ if (auto p = QtWayland::fromResource<QWaylandOutputPrivate *>(resource))
+ return p->q_func();
return nullptr;
}
diff --git a/src/compositor/compositor_api/qwaylandpointer.cpp b/src/compositor/compositor_api/qwaylandpointer.cpp
index 77e736a58..96263e0c2 100644
--- a/src/compositor/compositor_api/qwaylandpointer.cpp
+++ b/src/compositor/compositor_api/qwaylandpointer.cpp
@@ -239,7 +239,7 @@ uint QWaylandPointer::sendMouseReleaseEvent(Qt::MouseButton button)
/*!
* Sets the current mouse focus to \a view and sends a mouse move event to it with the
- * local position \a localPos and output space position \a outputSpacePos.
+ * local position \a localPos in surface coordinates and output space position \a outputSpacePos.
*/
void QWaylandPointer::sendMouseMoveEvent(QWaylandView *view, const QPointF &localPos, const QPointF &outputSpacePos)
{
@@ -253,7 +253,7 @@ void QWaylandPointer::sendMouseMoveEvent(QWaylandView *view, const QPointF &loca
if (view) {
// We adjust if the mouse position is on the edge
// to work around Qt's event propagation
- QSizeF size(view->surface()->size());
+ QSizeF size(view->surface()->destinationSize());
if (d->localPosition.x() == size.width())
d->localPosition.rx() -= 0.01;
if (d->localPosition.y() == size.height())
@@ -294,7 +294,7 @@ QWaylandView *QWaylandPointer::mouseFocus() const
}
/*!
- * Returns the current local position of the QWaylandPointer.
+ * Returns the current local position of the QWaylandPointer in surface coordinates.
*/
QPointF QWaylandPointer::currentLocalPosition() const
{
diff --git a/src/compositor/compositor_api/qwaylandquickcompositor.cpp b/src/compositor/compositor_api/qwaylandquickcompositor.cpp
index 8e8a903e3..426008a60 100644
--- a/src/compositor/compositor_api/qwaylandquickcompositor.cpp
+++ b/src/compositor/compositor_api/qwaylandquickcompositor.cpp
@@ -53,6 +53,7 @@
#include "qwaylandquickitem.h"
#include "qwaylandoutput.h"
#include <QtWaylandCompositor/private/qwaylandcompositor_p.h>
+#include <QtWaylandCompositor/QWaylandViewporter>
#include "qwaylandsurfacegrabber.h"
QT_BEGIN_NAMESPACE
@@ -60,8 +61,9 @@ QT_BEGIN_NAMESPACE
class QWaylandQuickCompositorPrivate : public QWaylandCompositorPrivate
{
public:
- QWaylandQuickCompositorPrivate(QWaylandCompositor *compositor)
+ explicit QWaylandQuickCompositorPrivate(QWaylandCompositor *compositor)
: QWaylandCompositorPrivate(compositor)
+ , m_viewporter(new QWaylandViewporter(compositor))
{
}
protected:
@@ -69,6 +71,8 @@ protected:
{
return new QWaylandQuickSurface();
}
+private:
+ QScopedPointer<QWaylandViewporter> m_viewporter;
};
QWaylandQuickCompositor::QWaylandQuickCompositor(QObject *parent)
diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp
index 77a9247a9..f848a0169 100644
--- a/src/compositor/compositor_api/qwaylandquickitem.cpp
+++ b/src/compositor/compositor_api/qwaylandquickitem.cpp
@@ -64,7 +64,7 @@
#include <QtCore/QMutexLocker>
#include <QtCore/QMutex>
-#include <wayland-server.h>
+#include <wayland-server-core.h>
#include <QThread>
#ifndef GL_TEXTURE_EXTERNAL_OES
@@ -886,7 +886,7 @@ void QWaylandQuickItem::handleSurfaceChanged()
if (d->oldSurface) {
disconnect(d->oldSurface.data(), &QWaylandSurface::hasContentChanged, this, &QWaylandQuickItem::surfaceMappedChanged);
disconnect(d->oldSurface.data(), &QWaylandSurface::parentChanged, this, &QWaylandQuickItem::parentChanged);
- disconnect(d->oldSurface.data(), &QWaylandSurface::sizeChanged, this, &QWaylandQuickItem::updateSize);
+ disconnect(d->oldSurface.data(), &QWaylandSurface::destinationSizeChanged, this, &QWaylandQuickItem::updateSize);
disconnect(d->oldSurface.data(), &QWaylandSurface::bufferScaleChanged, this, &QWaylandQuickItem::updateSize);
disconnect(d->oldSurface.data(), &QWaylandSurface::configure, this, &QWaylandQuickItem::updateBuffer);
disconnect(d->oldSurface.data(), &QWaylandSurface::redraw, this, &QQuickItem::update);
@@ -903,7 +903,7 @@ void QWaylandQuickItem::handleSurfaceChanged()
if (QWaylandSurface *newSurface = d->view->surface()) {
connect(newSurface, &QWaylandSurface::hasContentChanged, this, &QWaylandQuickItem::surfaceMappedChanged);
connect(newSurface, &QWaylandSurface::parentChanged, this, &QWaylandQuickItem::parentChanged);
- connect(newSurface, &QWaylandSurface::sizeChanged, this, &QWaylandQuickItem::updateSize);
+ connect(newSurface, &QWaylandSurface::destinationSizeChanged, this, &QWaylandQuickItem::updateSize);
connect(newSurface, &QWaylandSurface::bufferScaleChanged, this, &QWaylandQuickItem::updateSize);
connect(newSurface, &QWaylandSurface::configure, this, &QWaylandQuickItem::updateBuffer);
connect(newSurface, &QWaylandSurface::redraw, this, &QQuickItem::update);
@@ -992,7 +992,7 @@ void QWaylandQuickItem::updateSize()
QSize size(0, 0);
if (surface())
- size = surface()->size() * (d->scaleFactor() / surface()->bufferScale());
+ size = surface()->destinationSize() * d->scaleFactor();
setImplicitSize(size.width(), size.height());
if (d->sizeFollowsSurface)
@@ -1061,16 +1061,32 @@ bool QWaylandQuickItem::inputRegionContains(const QPointF &localPosition)
QPointF QWaylandQuickItem::mapToSurface(const QPointF &point) const
{
Q_D(const QWaylandQuickItem);
- if (!surface() || surface()->size().isEmpty())
+ if (!surface() || surface()->destinationSize().isEmpty())
return point / d->scaleFactor();
- qreal xScale = width() / surface()->size().width() * surface()->bufferScale();
- qreal yScale = height() / surface()->size().height() * surface()->bufferScale();
+ qreal xScale = width() / surface()->destinationSize().width();
+ qreal yScale = height() / surface()->destinationSize().height();
return QPointF(point.x() / xScale, point.y() / yScale);
}
/*!
+ * Maps the given \a point in the Wayland surfaces's coordinate system to the equivalent
+ * point within this item's coordinate system, and returns the mapped coordinate.
+ */
+QPointF QWaylandQuickItem::mapFromSurface(const QPointF &point) const
+{
+ Q_D(const QWaylandQuickItem);
+ if (!surface() || surface()->destinationSize().isEmpty())
+ return point * d->scaleFactor();
+
+ qreal xScale = width() / surface()->destinationSize().width();
+ qreal yScale = height() / surface()->destinationSize().height();
+
+ return QPointF(point.x() * xScale, point.y() * yScale);
+}
+
+/*!
* \qmlproperty bool QtWaylandCompositor::WaylandQuickItem::sizeFollowsSurface
*
* This property specifies whether the size of the item should always match
@@ -1301,6 +1317,10 @@ QSGNode *QWaylandQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
d->provider->setSmooth(smooth());
node->setRect(rect);
+ qreal scale = surface()->bufferScale();
+ QRectF source = surface()->sourceGeometry();
+ node->setSourceRect(QRectF(source.topLeft() * scale, source.size() * scale));
+
return node;
} else {
Q_ASSERT(!d->provider);
diff --git a/src/compositor/compositor_api/qwaylandquickitem.h b/src/compositor/compositor_api/qwaylandquickitem.h
index 23708353e..6f47c29a4 100644
--- a/src/compositor/compositor_api/qwaylandquickitem.h
+++ b/src/compositor/compositor_api/qwaylandquickitem.h
@@ -102,6 +102,7 @@ public:
bool inputRegionContains(const QPointF &localPosition) const;
bool inputRegionContains(const QPointF &localPosition);
Q_INVOKABLE QPointF mapToSurface(const QPointF &point) const;
+ Q_INVOKABLE QPointF mapFromSurface(const QPointF &point) const;
bool sizeFollowsSurface() const;
void setSizeFollowsSurface(bool sizeFollowsSurface);
diff --git a/src/compositor/compositor_api/qwaylandseat.cpp b/src/compositor/compositor_api/qwaylandseat.cpp
index a7b01ef03..d135ad035 100644
--- a/src/compositor/compositor_api/qwaylandseat.cpp
+++ b/src/compositor/compositor_api/qwaylandseat.cpp
@@ -54,6 +54,7 @@
#if QT_CONFIG(wayland_datadevice)
#include <QtWaylandCompositor/private/qwldatadevice_p.h>
#endif
+#include <QtWaylandCompositor/private/qwaylandutils_p.h>
#include "extensions/qwlqtkey_p.h"
#include "extensions/qwaylandtextinput.h"
@@ -631,8 +632,8 @@ bool QWaylandSeat::isOwner(QInputEvent *inputEvent) const
*/
QWaylandSeat *QWaylandSeat::fromSeatResource(struct ::wl_resource *resource)
{
- if (auto *r = QWaylandSeatPrivate::Resource::fromResource(resource))
- return static_cast<QWaylandSeatPrivate *>(r->seat_object)->q_func();
+ if (auto p = QtWayland::fromResource<QWaylandSeatPrivate *>(resource))
+ return p->q_func();
return nullptr;
}
diff --git a/src/compositor/compositor_api/qwaylandsurface.cpp b/src/compositor/compositor_api/qwaylandsurface.cpp
index 050ab5641..eef51283c 100644
--- a/src/compositor/compositor_api/qwaylandsurface.cpp
+++ b/src/compositor/compositor_api/qwaylandsurface.cpp
@@ -59,6 +59,7 @@
#include <QtWaylandCompositor/private/qwaylandcompositor_p.h>
#include <QtWaylandCompositor/private/qwaylandview_p.h>
#include <QtWaylandCompositor/private/qwaylandseat_p.h>
+#include <QtWaylandCompositor/private/qwaylandutils_p.h>
#include <QtCore/private/qobject_p.h>
@@ -234,21 +235,29 @@ void QWaylandSurfacePrivate::surface_commit(Resource *)
// Needed in order to know whether we want to emit signals later
QSize oldBufferSize = bufferSize;
+ QRectF oldSourceGeometry = sourceGeometry;
+ QSize oldDestinationSize = destinationSize;
bool oldHasContent = hasContent;
int oldBufferScale = bufferScale;
// Update all internal state
if (pending.buffer.hasBuffer() || pending.newlyAttached)
bufferRef = pending.buffer;
+ bufferScale = pending.bufferScale;
bufferSize = bufferRef.size();
- damage = pending.damage.intersected(QRect(QPoint(), bufferSize));
+ QSize surfaceSize = bufferSize / bufferScale;
+ sourceGeometry = !pending.sourceGeometry.isValid() ? QRect(QPoint(), surfaceSize) : pending.sourceGeometry;
+ destinationSize = pending.destinationSize.isEmpty() ? sourceGeometry.size().toSize() : pending.destinationSize;
+ damage = pending.damage.intersected(QRect(QPoint(), destinationSize));
hasContent = bufferRef.hasContent();
- bufferScale = pending.bufferScale;
frameCallbacks << pendingFrameCallbacks;
- inputRegion = pending.inputRegion.intersected(QRect(QPoint(), bufferSize));
- opaqueRegion = pending.opaqueRegion.intersected(QRect(QPoint(), bufferSize));
+ inputRegion = pending.inputRegion.intersected(QRect(QPoint(), destinationSize));
+ opaqueRegion = pending.opaqueRegion.intersected(QRect(QPoint(), destinationSize));
QPoint offsetForNextFrame = pending.offset;
+ if (viewport)
+ viewport->checkCommittedState();
+
// Clear per-commit state
pending.buffer = QWaylandBufferRef();
pending.offset = QPoint();
@@ -268,12 +277,22 @@ void QWaylandSurfacePrivate::surface_commit(Resource *)
emit q->damaged(damage);
- if (oldBufferSize != bufferSize)
+ if (oldBufferSize != bufferSize) {
+ emit q->bufferSizeChanged();
+#if QT_DEPRECATED_SINCE(5, 13)
emit q->sizeChanged();
+#endif
+ }
if (oldBufferScale != bufferScale)
emit q->bufferScaleChanged();
+ if (oldDestinationSize != destinationSize)
+ emit q->destinationSizeChanged();
+
+ if (oldSourceGeometry != sourceGeometry)
+ emit q->sourceGeometryChanged();
+
if (oldHasContent != hasContent)
emit q->hasContentChanged();
@@ -461,21 +480,105 @@ bool QWaylandSurface::hasContent() const
}
/*!
+ * \qmlproperty rect QtWaylandCompositor::WaylandSurface::sourceGeometry
+ *
+ * This property describes the portion of the attached Wayland buffer that should
+ * be drawn on the screen. The coordinates are from the corner of the buffer and are
+ * scaled by \l bufferScale.
+ *
+ * \sa bufferScale
+ * \sa bufferSize
+ * \sa destinationSize
+ */
+
+/*!
+ * \property QWaylandSurface::sourceGeometry
+ *
+ * This property describes the portion of the attached QWaylandBuffer that should
+ * be drawn on the screen. The coordinates are from the corner of the buffer and are
+ * scaled by \l bufferScale.
+ *
+ * \sa bufferScale
+ * \sa bufferSize
+ * \sa destinationSize
+ */
+QRectF QWaylandSurface::sourceGeometry() const
+{
+ Q_D(const QWaylandSurface);
+ return d->sourceGeometry;
+}
+
+/*!
+ * \qmlproperty size QtWaylandCompositor::WaylandSurface::destinationSize
+ *
+ * This property holds the size of this WaylandSurface in surface coordinates.
+ *
+ * \sa bufferScale
+ * \sa bufferSize
+ */
+
+/*!
+ * \property QWaylandSurface::destinationSize
+ *
+ * This property holds the size of this WaylandSurface in surface coordinates.
+ *
+ * \sa bufferScale
+ * \sa bufferSize
+ */
+QSize QWaylandSurface::destinationSize() const
+{
+ Q_D(const QWaylandSurface);
+ return d->destinationSize;
+}
+
+/*!
+ * \qmlproperty size QtWaylandCompositor::WaylandSurface::bufferSize
+ *
+ * This property holds the size of the current buffer of this WaylandSurface in pixels,
+ * not in surface coordinates.
+ *
+ * For the size in surface coordinates, use \l destinationSize instead.
+ *
+ * \sa destinationSize
+ * \sa bufferScale
+ */
+
+/*!
+ * \property QWaylandSurface::bufferSize
+ *
+ * This property holds the size of the current buffer of this QWaylandSurface in pixels,
+ * not in surface coordinates.
+ *
+ * For the size in surface coordinates, use \l destinationSize instead.
+ *
+ * \sa destinationSize
+ * \sa bufferScale
+ */
+QSize QWaylandSurface::bufferSize() const
+{
+ Q_D(const QWaylandSurface);
+ return d->bufferSize;
+}
+
+#if QT_DEPRECATED_SINCE(5, 13)
+/*!
* \qmlproperty size QtWaylandCompositor::WaylandSurface::size
+ * \obsolete use bufferSize or destinationSize instead
*
- * This property holds the WaylandSurface's size in pixels.
+ * This property has been deprecated, use \l bufferSize or \l destinationSize instead.
*/
/*!
* \property QWaylandSurface::size
+ * \obsolete use bufferSize or destinationSize instead
*
- * This property holds the QWaylandSurface's size in pixels.
+ * This property has been deprecated, use \l bufferSize or \l destinationSize instead.
*/
QSize QWaylandSurface::size() const
{
- Q_D(const QWaylandSurface);
- return d->bufferSize;
+ return bufferSize();
}
+#endif
/*!
* \qmlproperty size QtWaylandCompositor::WaylandSurface::bufferScale
@@ -742,10 +845,10 @@ QList<QWaylandView *> QWaylandSurface::views() const
/*!
* Returns the QWaylandSurface corresponding to the Wayland resource \a res.
*/
-QWaylandSurface *QWaylandSurface::fromResource(::wl_resource *res)
+QWaylandSurface *QWaylandSurface::fromResource(::wl_resource *resource)
{
- if (auto *r = QWaylandSurfacePrivate::Resource::fromResource(res))
- return static_cast<QWaylandSurfacePrivate *>(r->surface_object)->q_func();
+ if (auto p = QtWayland::fromResource<QWaylandSurfacePrivate *>(resource))
+ return p->q_func();
return nullptr;
}
diff --git a/src/compositor/compositor_api/qwaylandsurface.h b/src/compositor/compositor_api/qwaylandsurface.h
index a138b2af5..9bf842900 100644
--- a/src/compositor/compositor_api/qwaylandsurface.h
+++ b/src/compositor/compositor_api/qwaylandsurface.h
@@ -81,7 +81,11 @@ class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandSurface : public QWaylandObject
Q_OBJECT
Q_DECLARE_PRIVATE(QWaylandSurface)
Q_PROPERTY(QWaylandClient *client READ client CONSTANT)
- Q_PROPERTY(QSize size READ size NOTIFY sizeChanged)
+ Q_PROPERTY(QRectF sourceGeometry READ sourceGeometry NOTIFY sourceGeometryChanged)
+ Q_PROPERTY(QSize destinationSize READ destinationSize NOTIFY destinationSizeChanged)
+#if QT_DEPRECATED_SINCE(5, 13)
+ Q_PROPERTY(QSize size READ size NOTIFY sizeChanged) // Qt 6: Remove
+#endif
Q_PROPERTY(int bufferScale READ bufferScale NOTIFY bufferScaleChanged)
Q_PROPERTY(Qt::ScreenOrientation contentOrientation READ contentOrientation NOTIFY contentOrientationChanged)
Q_PROPERTY(QWaylandSurface::Origin origin READ origin NOTIFY originChanged)
@@ -110,7 +114,12 @@ public:
bool hasContent() const;
- QSize size() const;
+ QRectF sourceGeometry() const;
+ QSize destinationSize() const;
+#if QT_DEPRECATED_SINCE(5, 13)
+ QT_DEPRECATED QSize size() const;
+#endif
+ QSize bufferSize() const;
int bufferScale() const;
Qt::ScreenOrientation contentOrientation() const;
@@ -155,7 +164,12 @@ Q_SIGNALS:
void damaged(const QRegion &rect);
void parentChanged(QWaylandSurface *newParent, QWaylandSurface *oldParent);
void childAdded(QWaylandSurface *child);
- void sizeChanged();
+ void sourceGeometryChanged();
+ void destinationSizeChanged();
+#if QT_DEPRECATED_SINCE(5, 13)
+ QT_DEPRECATED void sizeChanged();
+#endif
+ void bufferSizeChanged();
void bufferScaleChanged();
void offsetForNextFrame(const QPoint &offset);
void contentOrientationChanged();
diff --git a/src/compositor/compositor_api/qwaylandsurface_p.h b/src/compositor/compositor_api/qwaylandsurface_p.h
index df868de63..85643623d 100644
--- a/src/compositor/compositor_api/qwaylandsurface_p.h
+++ b/src/compositor/compositor_api/qwaylandsurface_p.h
@@ -73,6 +73,7 @@
#include <wayland-util.h>
#include <QtWaylandCompositor/private/qwayland-server-wayland.h>
+#include <QtWaylandCompositor/private/qwaylandviewporter_p.h>
QT_BEGIN_NAMESPACE
@@ -144,6 +145,7 @@ public: //member variables
QRegion damage;
QWaylandBufferRef bufferRef;
QWaylandSurfaceRole *role = nullptr;
+ QWaylandViewporterPrivate::Viewport *viewport = nullptr;
struct {
QWaylandBufferRef buffer;
@@ -152,6 +154,8 @@ public: //member variables
bool newlyAttached;
QRegion inputRegion;
int bufferScale;
+ QRectF sourceGeometry;
+ QSize destinationSize;
QRegion opaqueRegion;
} pending;
@@ -166,6 +170,8 @@ public: //member variables
QRegion inputRegion;
QRegion opaqueRegion;
+ QRectF sourceGeometry;
+ QSize destinationSize;
QSize bufferSize;
int bufferScale = 1;
bool isCursorSurface = false;
diff --git a/src/compositor/configure.json b/src/compositor/configure.json
index 3b3d33200..ec9327adf 100644
--- a/src/compositor/configure.json
+++ b/src/compositor/configure.json
@@ -79,6 +79,12 @@
"type": "compile",
"test": "dmabuf_server_buffer",
"use": "egl"
+ },
+ "dmabuf-client-buffer": {
+ "label": "Linux Client dma-buf Buffer Sharing",
+ "type": "compile",
+ "test": "dmabuf_client_buffer",
+ "use": "egl"
}
},
@@ -127,6 +133,11 @@
"condition": "features.wayland-server && features.opengl && features.egl && tests.dmabuf-server-buffer",
"output": [ "privateFeature" ]
},
+ "wayland-dmabuf-client-buffer": {
+ "label": "Linux dma-buf client buffer integration",
+ "condition": "features.wayland-server && features.opengl && features.egl && tests.dmabuf-client-buffer",
+ "output": [ "privateFeature" ]
+ },
"wayland-shm-emulation-server-buffer": {
"label": "Shm emulation server buffer",
"condition": "features.wayland-server && features.opengl",
diff --git a/src/compositor/extensions/extensions.pri b/src/compositor/extensions/extensions.pri
index 5c708f891..38fe79a2f 100644
--- a/src/compositor/extensions/extensions.pri
+++ b/src/compositor/extensions/extensions.pri
@@ -9,6 +9,7 @@ WAYLANDSERVERSOURCES += \
../extensions/qt-key-unstable-v1.xml \
../extensions/qt-windowmanager.xml \
../3rdparty/protocol/text-input-unstable-v2.xml \
+ ../3rdparty/protocol/viewporter.xml \
../3rdparty/protocol/xdg-shell-unstable-v6.xml \
../3rdparty/protocol/xdg-shell.xml \
../3rdparty/protocol/xdg-decoration-unstable-v1.xml \
@@ -27,6 +28,8 @@ HEADERS += \
extensions/qwaylandtextinputmanager_p.h \
extensions/qwaylandqtwindowmanager.h \
extensions/qwaylandqtwindowmanager_p.h \
+ extensions/qwaylandviewporter.h \
+ extensions/qwaylandviewporter_p.h \
extensions/qwaylandxdgshellv5.h \
extensions/qwaylandxdgshellv5_p.h \
extensions/qwaylandxdgshellv6.h \
@@ -49,6 +52,7 @@ SOURCES += \
extensions/qwaylandtextinput.cpp \
extensions/qwaylandtextinputmanager.cpp \
extensions/qwaylandqtwindowmanager.cpp \
+ extensions/qwaylandviewporter.cpp \
extensions/qwaylandxdgshellv5.cpp \
extensions/qwaylandxdgshellv6.cpp \
extensions/qwaylandxdgshell.cpp \
diff --git a/src/compositor/extensions/pregenerated/3rdparty/qwayland-server-xdg-shell-unstable-v5_p.h b/src/compositor/extensions/pregenerated/3rdparty/qwayland-server-xdg-shell-unstable-v5_p.h
index 63817a5e3..8124860b9 100644
--- a/src/compositor/extensions/pregenerated/3rdparty/qwayland-server-xdg-shell-unstable-v5_p.h
+++ b/src/compositor/extensions/pregenerated/3rdparty/qwayland-server-xdg-shell-unstable-v5_p.h
@@ -71,6 +71,7 @@ namespace QtWaylandServer {
virtual ~Resource() {}
xdg_shell_v5 *xdg_shell_object;
+ xdg_shell_v5 *object() { return xdg_shell_object; }
struct ::wl_resource *handle;
struct ::wl_client *client() const { return wl_resource_get_client(handle); }
@@ -191,6 +192,7 @@ namespace QtWaylandServer {
virtual ~Resource() {}
xdg_surface_v5 *xdg_surface_object;
+ xdg_surface_v5 *object() { return xdg_surface_object; }
struct ::wl_resource *handle;
struct ::wl_client *client() const { return wl_resource_get_client(handle); }
@@ -364,6 +366,7 @@ namespace QtWaylandServer {
virtual ~Resource() {}
xdg_popup_v5 *xdg_popup_object;
+ xdg_popup_v5 *object() { return xdg_popup_object; }
struct ::wl_resource *handle;
struct ::wl_client *client() const { return wl_resource_get_client(handle); }
diff --git a/src/compositor/extensions/pregenerated/3rdparty/wayland-xdg-shell-unstable-v5-server-protocol_p.h b/src/compositor/extensions/pregenerated/3rdparty/wayland-xdg-shell-unstable-v5-server-protocol_p.h
index b979f048c..493fd52d4 100644
--- a/src/compositor/extensions/pregenerated/3rdparty/wayland-xdg-shell-unstable-v5-server-protocol_p.h
+++ b/src/compositor/extensions/pregenerated/3rdparty/wayland-xdg-shell-unstable-v5-server-protocol_p.h
@@ -6,7 +6,7 @@
#include <stdint.h>
#include <stddef.h>
-#include "wayland-server.h"
+#include "wayland-server-core.h"
#ifdef __cplusplus
extern "C" {
diff --git a/src/compositor/extensions/qwaylandivisurface.cpp b/src/compositor/extensions/qwaylandivisurface.cpp
index b6398f060..0ae488def 100644
--- a/src/compositor/extensions/qwaylandivisurface.cpp
+++ b/src/compositor/extensions/qwaylandivisurface.cpp
@@ -47,6 +47,8 @@
#include <QtWaylandCompositor/QWaylandResource>
#include <QDebug>
+#include <QtWaylandCompositor/private/qwaylandutils_p.h>
+
QT_BEGIN_NAMESPACE
QWaylandSurfaceRole QWaylandIviSurfacePrivate::s_role("ivi_surface");
@@ -182,10 +184,9 @@ QWaylandSurfaceRole *QWaylandIviSurface::role()
*/
QWaylandIviSurface *QWaylandIviSurface::fromResource(wl_resource *resource)
{
- auto iviSurfaceResource = QWaylandIviSurfacePrivate::Resource::fromResource(resource);
- if (!iviSurfaceResource)
- return nullptr;
- return static_cast<QWaylandIviSurfacePrivate *>(iviSurfaceResource->ivi_surface_object)->q_func();
+ if (auto p = QtWayland::fromResource<QWaylandIviSurfacePrivate *>(resource))
+ return p->q_func();
+ return nullptr;
}
/*!
diff --git a/src/compositor/extensions/qwaylandviewporter.cpp b/src/compositor/extensions/qwaylandviewporter.cpp
new file mode 100644
index 000000000..3856c135d
--- /dev/null
+++ b/src/compositor/extensions/qwaylandviewporter.cpp
@@ -0,0 +1,243 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** 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 "qwaylandviewporter_p.h"
+
+#include <QtWaylandCompositor/QWaylandSurface>
+#include <QtWaylandCompositor/QWaylandCompositor>
+
+#include <QtWaylandCompositor/private/qwaylandsurface_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QWaylandViewporter
+ \inmodule QtWaylandCompositor
+ \since 5.13
+ \brief Provides an extension for surface resizing and cropping.
+
+ The QWaylandViewporter extension provides a way for clients to resize and crop surface
+ contents.
+
+ QWaylandViewporter corresponds to the Wayland interface, \c wp_viewporter.
+*/
+
+/*!
+ Constructs a QWaylandViewporter object.
+*/
+QWaylandViewporter::QWaylandViewporter()
+ : QWaylandCompositorExtensionTemplate<QWaylandViewporter>(*new QWaylandViewporterPrivate)
+{
+}
+
+/*!
+ * Constructs a QWaylandViewporter object for the provided \a compositor.
+ */
+QWaylandViewporter::QWaylandViewporter(QWaylandCompositor *compositor)
+ : QWaylandCompositorExtensionTemplate<QWaylandViewporter>(compositor, *new QWaylandViewporterPrivate())
+{
+}
+
+/*!
+ Initializes the extension.
+*/
+void QWaylandViewporter::initialize()
+{
+ Q_D(QWaylandViewporter);
+
+ QWaylandCompositorExtensionTemplate::initialize();
+ auto *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
+ if (!compositor) {
+ qWarning() << "Failed to find QWaylandCompositor when initializing QWaylandViewporter";
+ return;
+ }
+ d->init(compositor->display(), 1);
+}
+
+/*!
+ Returns the Wayland interface for the QWaylandViewporter.
+*/
+const wl_interface *QWaylandViewporter::interface()
+{
+ return QWaylandViewporterPrivate::interface();
+}
+
+void QWaylandViewporterPrivate::wp_viewporter_destroy(Resource *resource)
+{
+ // Viewport objects are allowed ot outlive the viewporter
+ wl_resource_destroy(resource->handle);
+}
+
+void QWaylandViewporterPrivate::wp_viewporter_get_viewport(Resource *resource, uint id, wl_resource *surfaceResource)
+{
+ auto *surface = QWaylandSurface::fromResource(surfaceResource);
+ if (!surface) {
+ qWarning() << "Couldn't find surface for viewporter";
+ return;
+ }
+
+ auto *surfacePrivate = QWaylandSurfacePrivate::get(surface);
+ if (surfacePrivate->viewport) {
+ wl_resource_post_error(resource->handle, WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS,
+ "viewport already exists for surface");
+ return;
+ }
+
+ surfacePrivate->viewport = new Viewport(surface, resource->client(), id);
+}
+
+QWaylandViewporterPrivate::Viewport::Viewport(QWaylandSurface *surface, wl_client *client, int id)
+ : QtWaylandServer::wp_viewport(client, id, /*version*/ 1)
+ , m_surface(surface)
+{
+ Q_ASSERT(surface);
+}
+
+QWaylandViewporterPrivate::Viewport::~Viewport()
+{
+ if (m_surface) {
+ auto *surfacePrivate = QWaylandSurfacePrivate::get(m_surface);
+ Q_ASSERT(surfacePrivate->viewport == this);
+ surfacePrivate->viewport = nullptr;
+ }
+}
+
+// This function has to be called immediately after a surface is committed, before no
+// other client events have been dispatched, or we may incorrectly error out on an
+// incomplete pending state. See comment below.
+void QWaylandViewporterPrivate::Viewport::checkCommittedState()
+{
+ auto *surfacePrivate = QWaylandSurfacePrivate::get(m_surface);
+
+ // We can't use the current state for destination/source when checking,
+ // as that has fallbacks to the buffer size so we can't distinguish
+ // between the set/unset case. We use the pending state because no other
+ // requests has modified it yet.
+ QSize destination = surfacePrivate->pending.destinationSize;
+ QRectF source = surfacePrivate->pending.sourceGeometry;
+
+ if (!destination.isValid() && source.size() != source.size().toSize()) {
+ wl_resource_post_error(resource()->handle, error_bad_size,
+ "non-integer size (%fx%f) with unset destination",
+ source.width(), source.height());
+ return;
+ }
+
+ QRectF max = QRectF(QPointF(), m_surface->bufferSize() / m_surface->bufferScale());
+ // We can't use QRectF.contains, because that would return false for values on the border
+ if (max.united(source) != max) {
+ wl_resource_post_error(resource()->handle, error_out_of_buffer,
+ "source %f,%f, %fx%f extends outside attached buffer %fx%f",
+ source.x(), source.y(), source.width(), source.height(),
+ max.width(), max.height());
+ return;
+ }
+}
+
+
+void QWaylandViewporterPrivate::Viewport::wp_viewport_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource);
+ delete this;
+}
+
+void QWaylandViewporterPrivate::Viewport::wp_viewport_destroy(Resource *resource)
+{
+ if (m_surface) {
+ auto *surfacePrivate = QWaylandSurfacePrivate::get(m_surface);
+ surfacePrivate->pending.destinationSize = QSize();
+ surfacePrivate->pending.sourceGeometry = QRectF();
+ }
+ wl_resource_destroy(resource->handle);
+}
+
+void QWaylandViewporterPrivate::Viewport::wp_viewport_set_source(QtWaylandServer::wp_viewport::Resource *resource, wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height)
+{
+ Q_UNUSED(resource);
+
+ if (!m_surface) {
+ wl_resource_post_error(resource->handle, error_no_surface,
+ "set_source requested for destroyed surface");
+ return;
+ }
+
+ QPointF position(wl_fixed_to_double(x), wl_fixed_to_double(y));
+ QSizeF size(wl_fixed_to_double(width), wl_fixed_to_double(height));
+ QRectF sourceGeometry(position, size);
+
+ if (sourceGeometry == QRectF(-1, -1, -1, -1)) {
+ auto *surfacePrivate = QWaylandSurfacePrivate::get(m_surface);
+ surfacePrivate->pending.sourceGeometry = QRectF();
+ return;
+ }
+
+ if (position.x() < 0 || position.y() < 0) {
+ wl_resource_post_error(resource->handle, error_bad_value,
+ "negative position in set_source");
+ return;
+ }
+
+ if (!size.isValid()) {
+ wl_resource_post_error(resource->handle, error_bad_value,
+ "negative size in set_source");
+ return;
+ }
+
+ auto *surfacePrivate = QWaylandSurfacePrivate::get(m_surface);
+ surfacePrivate->pending.sourceGeometry = sourceGeometry;
+}
+
+void QWaylandViewporterPrivate::Viewport::wp_viewport_set_destination(QtWaylandServer::wp_viewport::Resource *resource, int32_t width, int32_t height)
+{
+ Q_UNUSED(resource);
+
+ if (!m_surface) {
+ wl_resource_post_error(resource->handle, error_no_surface,
+ "set_destination requested for destroyed surface");
+ return;
+ }
+
+ QSize destinationSize(width, height);
+ if (!destinationSize.isValid() && destinationSize != QSize(-1, -1)) {
+ wl_resource_post_error(resource->handle, error_bad_value,
+ "negative size in set_destination");
+ return;
+ }
+ auto *surfacePrivate = QWaylandSurfacePrivate::get(m_surface);
+ surfacePrivate->pending.destinationSize = destinationSize;
+}
+
+QT_END_NAMESPACE
diff --git a/src/compositor/extensions/qwaylandviewporter.h b/src/compositor/extensions/qwaylandviewporter.h
new file mode 100644
index 000000000..811c74145
--- /dev/null
+++ b/src/compositor/extensions/qwaylandviewporter.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** 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 QWAYLANDVIEWPORTER_H
+#define QWAYLANDVIEWPORTER_H
+
+#include <QtWaylandCompositor/QWaylandCompositorExtension>
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandViewporterPrivate;
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandViewporter
+ : public QWaylandCompositorExtensionTemplate<QWaylandViewporter>
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QWaylandViewporter)
+
+public:
+ explicit QWaylandViewporter();
+ explicit QWaylandViewporter(QWaylandCompositor *compositor);
+
+ void initialize() override;
+
+ static const struct wl_interface *interface();
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDVIEWPORTER_H
diff --git a/src/compositor/extensions/qwaylandviewporter_p.h b/src/compositor/extensions/qwaylandviewporter_p.h
new file mode 100644
index 000000000..d22da6990
--- /dev/null
+++ b/src/compositor/extensions/qwaylandviewporter_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** 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 QWAYLANDVIEWPORTER_P_H
+#define QWAYLANDVIEWPORTER_P_H
+
+#include "qwaylandviewporter.h"
+
+#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h>
+#include <QtWaylandCompositor/private/qwayland-server-viewporter.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 QWaylandSurface;
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandViewporterPrivate
+ : public QWaylandCompositorExtensionPrivate
+ , public QtWaylandServer::wp_viewporter
+{
+ Q_DECLARE_PUBLIC(QWaylandViewporter)
+public:
+ explicit QWaylandViewporterPrivate() = default;
+
+ class Q_WAYLAND_COMPOSITOR_EXPORT Viewport
+ : public QtWaylandServer::wp_viewport
+ {
+ public:
+ explicit Viewport(QWaylandSurface *surface, wl_client *client, int id);
+ ~Viewport() override;
+ void checkCommittedState();
+
+ protected:
+ void wp_viewport_destroy_resource(Resource *resource) override;
+ void wp_viewport_destroy(Resource *resource) override;
+ void wp_viewport_set_source(Resource *resource, wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height) override;
+ void wp_viewport_set_destination(Resource *resource, int32_t width, int32_t height) override;
+
+ private:
+ QPointer<QWaylandSurface> m_surface = nullptr;
+ };
+
+protected:
+ void wp_viewporter_destroy(Resource *resource) override;
+ void wp_viewporter_get_viewport(Resource *resource, uint32_t id, wl_resource *surface) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDVIEWPORTER_P_H
diff --git a/src/compositor/extensions/qwaylandwlshell.cpp b/src/compositor/extensions/qwaylandwlshell.cpp
index d932a06c9..3f6734632 100644
--- a/src/compositor/extensions/qwaylandwlshell.cpp
+++ b/src/compositor/extensions/qwaylandwlshell.cpp
@@ -44,6 +44,7 @@
#ifdef QT_WAYLAND_COMPOSITOR_QUICK
#include "qwaylandwlshellintegration_p.h"
#endif
+#include <QtWaylandCompositor/private/qwaylandutils_p.h>
#include <QtWaylandCompositor/QWaylandCompositor>
#include <QtWaylandCompositor/QWaylandView>
@@ -699,9 +700,8 @@ void QWaylandWlShellSurface::ping()
*/
QWaylandWlShellSurface *QWaylandWlShellSurface::fromResource(wl_resource *resource)
{
- QWaylandWlShellSurfacePrivate::Resource *res = QWaylandWlShellSurfacePrivate::Resource::fromResource(resource);
- if (res)
- return static_cast<QWaylandWlShellSurfacePrivate *>(res->shell_surface_object)->q_func();
+ if (auto p = QtWayland::fromResource<QWaylandWlShellSurfacePrivate *>(resource))
+ return p->q_func();
return nullptr;
}
diff --git a/src/compositor/extensions/qwaylandwlshell_p.h b/src/compositor/extensions/qwaylandwlshell_p.h
index e8d568fce..f8a29bac8 100644
--- a/src/compositor/extensions/qwaylandwlshell_p.h
+++ b/src/compositor/extensions/qwaylandwlshell_p.h
@@ -46,7 +46,7 @@
#include <QtWaylandCompositor/QWaylandWlShellSurface>
#include <QtWaylandCompositor/QWaylandSeat>
-#include <wayland-server.h>
+#include <wayland-server-core.h>
#include <QHash>
#include <QPoint>
#include <QSet>
diff --git a/src/compositor/extensions/qwaylandwlshellintegration.cpp b/src/compositor/extensions/qwaylandwlshellintegration.cpp
index 896b1587d..99a2e7655 100644
--- a/src/compositor/extensions/qwaylandwlshellintegration.cpp
+++ b/src/compositor/extensions/qwaylandwlshellintegration.cpp
@@ -84,8 +84,7 @@ void WlShellIntegration::handleStartResize(QWaylandSeat *seat, QWaylandWlShellSu
grabberState = GrabberState::Resize;
resizeState.seat = seat;
resizeState.resizeEdges = edges;
- float scaleFactor = m_item->view()->output()->scaleFactor();
- resizeState.initialSize = m_shellSurface->surface()->size() / scaleFactor;
+ resizeState.initialSize = m_shellSurface->surface()->destinationSize();
resizeState.initialized = false;
}
@@ -217,9 +216,7 @@ void WlShellIntegration::handleSetPopup(QWaylandSeat *seat, QWaylandSurface *par
t.clear(&t);
m_item->setRotation(0);
m_item->setScale(1.0);
- auto scaleFactor = m_item->output()->scaleFactor() / devicePixelRatio();
- m_item->setX(relativeToParent.x() * scaleFactor);
- m_item->setY(relativeToParent.y() * scaleFactor);
+ m_item->setPosition(m_item->mapFromSurface(relativeToParent));
m_item->setParentItem(parentItem);
}
@@ -267,7 +264,7 @@ void WlShellIntegration::handleShellSurfaceDestroyed()
void WlShellIntegration::handleSurfaceHasContentChanged()
{
- if (m_shellSurface && m_shellSurface->surface()->size().isEmpty()
+ if (m_shellSurface && m_shellSurface->surface()->destinationSize().isEmpty()
&& m_shellSurface->windowType() == Qt::WindowType::Popup) {
handlePopupClosed();
}
@@ -287,9 +284,8 @@ void WlShellIntegration::adjustOffsetForNextFrame(const QPointF &offset)
if (!m_item->view()->isPrimary())
return;
- float scaleFactor = m_item->view()->output()->scaleFactor();
QQuickItem *moveItem = m_item->moveItem();
- moveItem->setPosition(moveItem->position() + offset * scaleFactor / devicePixelRatio());
+ moveItem->setPosition(moveItem->position() + m_item->mapFromSurface(offset));
}
bool WlShellIntegration::mouseMoveEvent(QMouseEvent *event)
diff --git a/src/compositor/extensions/qwaylandxdgshell.cpp b/src/compositor/extensions/qwaylandxdgshell.cpp
index bd332287e..6f0c83122 100644
--- a/src/compositor/extensions/qwaylandxdgshell.cpp
+++ b/src/compositor/extensions/qwaylandxdgshell.cpp
@@ -40,6 +40,7 @@
#ifdef QT_WAYLAND_COMPOSITOR_QUICK
#include "qwaylandxdgshellintegration_p.h"
#endif
+#include <QtWaylandCompositor/private/qwaylandutils_p.h>
#include <QtWaylandCompositor/QWaylandCompositor>
#include <QtWaylandCompositor/QWaylandSeat>
@@ -311,7 +312,7 @@ QRect QWaylandXdgSurfacePrivate::calculateFallbackWindowGeometry() const
{
// TODO: The unset window geometry should include subsurfaces as well, so this solution
// won't work too well on those kinds of clients.
- return QRect(QPoint(0, 0), m_surface->size() / m_surface->bufferScale());
+ return QRect(QPoint(), m_surface->destinationSize());
}
void QWaylandXdgSurfacePrivate::updateFallbackWindowGeometry()
@@ -510,7 +511,7 @@ void QWaylandXdgSurface::initialize(QWaylandXdgShell *xdgShell, QWaylandSurface
d->init(resource.resource());
setExtensionContainer(surface);
d->m_windowGeometry = d->calculateFallbackWindowGeometry();
- connect(surface, &QWaylandSurface::sizeChanged, this, &QWaylandXdgSurface::handleSurfaceSizeChanged);
+ connect(surface, &QWaylandSurface::destinationSizeChanged, this, &QWaylandXdgSurface::handleSurfaceSizeChanged);
connect(surface, &QWaylandSurface::bufferScaleChanged, this, &QWaylandXdgSurface::handleBufferScaleChanged);
emit shellChanged();
emit surfaceChanged();
@@ -674,10 +675,9 @@ QByteArray QWaylandXdgSurface::interfaceName()
*/
QWaylandXdgSurface *QWaylandXdgSurface::fromResource(wl_resource *resource)
{
- auto xsResource = QWaylandXdgSurfacePrivate::Resource::fromResource(resource);
- if (!xsResource)
- return nullptr;
- return static_cast<QWaylandXdgSurfacePrivate *>(xsResource->xdg_surface_object)->q_func();
+ if (auto p = QtWayland::fromResource<QWaylandXdgSurfacePrivate *>(resource))
+ return p->q_func();
+ return nullptr;
}
#ifdef QT_WAYLAND_COMPOSITOR_QUICK
@@ -1182,8 +1182,8 @@ QWaylandSurfaceRole *QWaylandXdgToplevel::role()
*/
QWaylandXdgToplevel *QWaylandXdgToplevel::fromResource(wl_resource *resource)
{
- if (auto *r = QWaylandXdgToplevelPrivate::Resource::fromResource(resource))
- return static_cast<QWaylandXdgToplevelPrivate *>(r->xdg_toplevel_object)->q_func();
+ if (auto p = QtWayland::fromResource<QWaylandXdgToplevelPrivate *>(resource))
+ return p->q_func();
return nullptr;
}
@@ -2064,9 +2064,7 @@ void QWaylandXdgPositioner::xdg_positioner_set_offset(QtWaylandServer::xdg_posit
QWaylandXdgPositioner *QWaylandXdgPositioner::fromResource(wl_resource *resource)
{
- if (auto *r = Resource::fromResource(resource))
- return static_cast<QWaylandXdgPositioner *>(r->xdg_positioner_object);
- return nullptr;
+ return QtWayland::fromResource<QWaylandXdgPositioner *>(resource);
}
Qt::Edges QWaylandXdgPositioner::convertToEdges(anchor anchor)
diff --git a/src/compositor/extensions/qwaylandxdgshellintegration.cpp b/src/compositor/extensions/qwaylandxdgshellintegration.cpp
index cc8faf6c7..3de52944b 100644
--- a/src/compositor/extensions/qwaylandxdgshellintegration.cpp
+++ b/src/compositor/extensions/qwaylandxdgshellintegration.cpp
@@ -73,7 +73,7 @@ XdgToplevelIntegration::XdgToplevelIntegration(QWaylandQuickShellSurfaceItem *it
connect(m_xdgSurface->shell(), &QWaylandXdgShell::popupCreated, this, [item](QWaylandXdgPopup *popup, QWaylandXdgSurface *){
handlePopupCreated(item, popup);
});
- connect(m_xdgSurface->surface(), &QWaylandSurface::sizeChanged, this, &XdgToplevelIntegration::handleSurfaceSizeChanged);
+ connect(m_xdgSurface->surface(), &QWaylandSurface::destinationSizeChanged, this, &XdgToplevelIntegration::handleSurfaceSizeChanged);
connect(m_toplevel, &QObject::destroyed, this, &XdgToplevelIntegration::handleToplevelDestroyed);
}
@@ -130,7 +130,7 @@ void XdgToplevelIntegration::handleStartResize(QWaylandSeat *seat, Qt::Edges edg
resizeState.resizeEdges = edges;
resizeState.initialWindowSize = m_xdgSurface->windowGeometry().size();
resizeState.initialPosition = m_item->moveItem()->position();
- resizeState.initialSurfaceSize = m_item->surface()->size();
+ resizeState.initialSurfaceSize = m_item->surface()->destinationSize();
resizeState.initialized = false;
}
@@ -247,14 +247,14 @@ void XdgToplevelIntegration::handleActivatedChanged()
void XdgToplevelIntegration::handleSurfaceSizeChanged()
{
if (grabberState == GrabberState::Resize) {
- qreal x = resizeState.initialPosition.x();
- qreal y = resizeState.initialPosition.y();
+ qreal dx = 0;
+ qreal dy = 0;
if (resizeState.resizeEdges & Qt::TopEdge)
- y += resizeState.initialSurfaceSize.height() - m_item->surface()->size().height();
-
+ dy = resizeState.initialSurfaceSize.height() - m_item->surface()->destinationSize().height();
if (resizeState.resizeEdges & Qt::LeftEdge)
- x += resizeState.initialSurfaceSize.width() - m_item->surface()->size().width();
- m_item->moveItem()->setPosition(QPointF(x, y));
+ dx = resizeState.initialSurfaceSize.width() - m_item->surface()->destinationSize().width();
+ QPointF offset = m_item->mapFromSurface({dx, dy});
+ m_item->moveItem()->setPosition(resizeState.initialPosition + offset);
}
}
@@ -285,11 +285,11 @@ void XdgPopupIntegration::handleGeometryChanged()
{
if (m_item->view()->output()) {
const QPoint windowOffset = m_popup->parentXdgSurface()->windowGeometry().topLeft();
- const QPoint position = m_popup->unconstrainedPosition() + windowOffset;
+ const QPoint surfacePosition = m_popup->unconstrainedPosition() + windowOffset;
+ const QPoint itemPosition = m_item->mapFromSurface(surfacePosition).toPoint();
//TODO: positioner size or other size...?
- const float scaleFactor = m_item->view()->output()->scaleFactor();
//TODO check positioner constraints etc... sliding, flipping
- m_item->moveItem()->setPosition(position * scaleFactor);
+ m_item->moveItem()->setPosition(itemPosition);
} else {
qWarning() << "XdgPopupIntegration popup item without output" << m_item;
}
diff --git a/src/compositor/extensions/qwaylandxdgshellv5.cpp b/src/compositor/extensions/qwaylandxdgshellv5.cpp
index a6e88aabb..9e157a8a3 100644
--- a/src/compositor/extensions/qwaylandxdgshellv5.cpp
+++ b/src/compositor/extensions/qwaylandxdgshellv5.cpp
@@ -43,6 +43,7 @@
#ifdef QT_WAYLAND_COMPOSITOR_QUICK
#include "qwaylandxdgshellv5integration_p.h"
#endif
+#include <QtWaylandCompositor/private/qwaylandutils_p.h>
#include <QtWaylandCompositor/QWaylandCompositor>
#include <QtWaylandCompositor/QWaylandSurface>
@@ -249,7 +250,7 @@ QRect QWaylandXdgSurfaceV5Private::calculateFallbackWindowGeometry() const
{
// TODO: The unset window geometry should include subsurfaces as well, so this solution
// won't work too well on those kinds of clients.
- return QRect(QPoint(0, 0), m_surface->size() / m_surface->bufferScale());
+ return QRect(QPoint(), m_surface->destinationSize());
}
void QWaylandXdgSurfaceV5Private::updateFallbackWindowGeometry()
@@ -837,7 +838,7 @@ void QWaylandXdgSurfaceV5::initialize(QWaylandXdgShellV5 *xdgShell, QWaylandSurf
d->init(resource.resource());
setExtensionContainer(surface);
d->m_windowGeometry = d->calculateFallbackWindowGeometry();
- connect(surface, &QWaylandSurface::sizeChanged, this, &QWaylandXdgSurfaceV5::handleSurfaceSizeChanged);
+ connect(surface, &QWaylandSurface::destinationSizeChanged, this, &QWaylandXdgSurfaceV5::handleSurfaceSizeChanged);
connect(surface, &QWaylandSurface::bufferScaleChanged, this, &QWaylandXdgSurfaceV5::handleBufferScaleChanged);
emit shellChanged();
emit surfaceChanged();
@@ -1179,10 +1180,9 @@ QWaylandSurfaceRole *QWaylandXdgSurfaceV5::role()
*/
QWaylandXdgSurfaceV5 *QWaylandXdgSurfaceV5::fromResource(wl_resource *resource)
{
- auto xsResource = QWaylandXdgSurfaceV5Private::Resource::fromResource(resource);
- if (!xsResource)
- return nullptr;
- return static_cast<QWaylandXdgSurfaceV5Private *>(xsResource->xdg_surface_object)->q_func();
+ if (auto p = QtWayland::fromResource<QWaylandXdgSurfaceV5Private *>(resource))
+ return p->q_func();
+ return nullptr;
}
QSize QWaylandXdgSurfaceV5::sizeForResize(const QSizeF &size, const QPointF &delta,
@@ -1497,10 +1497,9 @@ QWaylandSurfaceRole *QWaylandXdgPopupV5::role()
QWaylandXdgPopupV5 *QWaylandXdgPopupV5::fromResource(wl_resource *resource)
{
- auto popupResource = QWaylandXdgPopupV5Private::Resource::fromResource(resource);
- if (!popupResource)
- return nullptr;
- return static_cast<QWaylandXdgPopupV5Private *>(popupResource->xdg_popup_object)->q_func();
+ if (auto p = QtWayland::fromResource<QWaylandXdgPopupV5Private *>(resource))
+ return p->q_func();
+ return nullptr;
}
void QWaylandXdgPopupV5::sendPopupDone()
diff --git a/src/compositor/extensions/qwaylandxdgshellv5integration.cpp b/src/compositor/extensions/qwaylandxdgshellv5integration.cpp
index ea04a33d2..1d63632a3 100644
--- a/src/compositor/extensions/qwaylandxdgshellv5integration.cpp
+++ b/src/compositor/extensions/qwaylandxdgshellv5integration.cpp
@@ -71,7 +71,7 @@ XdgShellV5Integration::XdgShellV5Integration(QWaylandQuickShellSurfaceItem *item
connect(m_xdgSurface, &QWaylandXdgSurfaceV5::unsetMaximized, this, &XdgShellV5Integration::handleUnsetMaximized);
connect(m_xdgSurface, &QWaylandXdgSurfaceV5::maximizedChanged, this, &XdgShellV5Integration::handleMaximizedChanged);
connect(m_xdgSurface, &QWaylandXdgSurfaceV5::activatedChanged, this, &XdgShellV5Integration::handleActivatedChanged);
- connect(m_xdgSurface->surface(), &QWaylandSurface::sizeChanged, this, &XdgShellV5Integration::handleSurfaceSizeChanged);
+ connect(m_xdgSurface->surface(), &QWaylandSurface::destinationSizeChanged, this, &XdgShellV5Integration::handleSurfaceSizeChanged);
connect(m_xdgSurface->shell(), &QWaylandXdgShellV5::xdgPopupCreated, this, [item](QWaylandXdgPopupV5 *popup){
handlePopupCreated(item, popup);
});
@@ -139,7 +139,7 @@ void XdgShellV5Integration::handleStartResize(QWaylandSeat *seat, QWaylandXdgSur
resizeState.resizeEdges = edges;
resizeState.initialWindowSize = m_xdgSurface->windowGeometry().size();
resizeState.initialPosition = m_item->moveItem()->position();
- resizeState.initialSurfaceSize = m_item->surface()->size();
+ resizeState.initialSurfaceSize = m_item->surface()->destinationSize();
resizeState.initialized = false;
}
@@ -194,14 +194,14 @@ void XdgShellV5Integration::handleActivatedChanged()
void XdgShellV5Integration::handleSurfaceSizeChanged()
{
if (grabberState == GrabberState::Resize) {
- qreal x = resizeState.initialPosition.x();
- qreal y = resizeState.initialPosition.y();
+ qreal dx = 0;
+ qreal dy = 0;
if (resizeState.resizeEdges & QWaylandXdgSurfaceV5::ResizeEdge::TopEdge)
- y += resizeState.initialSurfaceSize.height() - m_item->surface()->size().height();
-
+ dy = resizeState.initialSurfaceSize.height() - m_item->surface()->destinationSize().height();
if (resizeState.resizeEdges & QWaylandXdgSurfaceV5::ResizeEdge::LeftEdge)
- x += resizeState.initialSurfaceSize.width() - m_item->surface()->size().width();
- m_item->moveItem()->setPosition(QPointF(x, y));
+ dx = resizeState.initialSurfaceSize.width() - m_item->surface()->destinationSize().width();
+ QPointF offset = m_item->mapFromSurface({dx, dy});
+ m_item->moveItem()->setPosition(resizeState.initialPosition + offset);
}
}
@@ -212,10 +212,12 @@ XdgPopupV5Integration::XdgPopupV5Integration(QWaylandQuickShellSurfaceItem *item
, m_xdgShell(QWaylandXdgPopupV5Private::get(m_xdgPopup)->m_xdgShell)
{
item->setSurface(m_xdgPopup->surface());
- if (item->view()->output())
- item->moveItem()->setPosition(QPointF(m_xdgPopup->position() * item->view()->output()->scaleFactor()));
- else
+ if (item->view()->output()) {
+ QPoint position = item->mapFromSurface(m_xdgPopup->position()).toPoint();
+ item->moveItem()->setPosition(position);
+ } else {
qWarning() << "XdgPopupV5Integration popup item without output" << item;
+ }
QWaylandClient *client = m_xdgPopup->surface()->client();
auto shell = m_xdgShell;
diff --git a/src/compositor/extensions/qwaylandxdgshellv6.cpp b/src/compositor/extensions/qwaylandxdgshellv6.cpp
index 8338fe6e2..9aab9b2b8 100644
--- a/src/compositor/extensions/qwaylandxdgshellv6.cpp
+++ b/src/compositor/extensions/qwaylandxdgshellv6.cpp
@@ -40,6 +40,7 @@
#ifdef QT_WAYLAND_COMPOSITOR_QUICK
#include "qwaylandxdgshellv6integration_p.h"
#endif
+#include <QtWaylandCompositor/private/qwaylandutils_p.h>
#include <QtWaylandCompositor/QWaylandCompositor>
#include <QtWaylandCompositor/QWaylandSeat>
@@ -316,7 +317,7 @@ QRect QWaylandXdgSurfaceV6Private::calculateFallbackWindowGeometry() const
{
// TODO: The unset window geometry should include subsurfaces as well, so this solution
// won't work too well on those kinds of clients.
- return QRect(QPoint(0, 0), m_surface->size() / m_surface->bufferScale());
+ return QRect(QPoint(), m_surface->destinationSize());
}
void QWaylandXdgSurfaceV6Private::updateFallbackWindowGeometry()
@@ -515,7 +516,7 @@ void QWaylandXdgSurfaceV6::initialize(QWaylandXdgShellV6 *xdgShell, QWaylandSurf
d->init(resource.resource());
setExtensionContainer(surface);
d->m_windowGeometry = d->calculateFallbackWindowGeometry();
- connect(surface, &QWaylandSurface::sizeChanged, this, &QWaylandXdgSurfaceV6::handleSurfaceSizeChanged);
+ connect(surface, &QWaylandSurface::destinationSizeChanged, this, &QWaylandXdgSurfaceV6::handleSurfaceSizeChanged);
connect(surface, &QWaylandSurface::bufferScaleChanged, this, &QWaylandXdgSurfaceV6::handleBufferScaleChanged);
emit shellChanged();
emit surfaceChanged();
@@ -679,10 +680,9 @@ QByteArray QWaylandXdgSurfaceV6::interfaceName()
*/
QWaylandXdgSurfaceV6 *QWaylandXdgSurfaceV6::fromResource(wl_resource *resource)
{
- auto xsResource = QWaylandXdgSurfaceV6Private::Resource::fromResource(resource);
- if (!xsResource)
- return nullptr;
- return static_cast<QWaylandXdgSurfaceV6Private *>(xsResource->zxdg_surface_v6_object)->q_func();
+ if (auto p = QtWayland::fromResource<QWaylandXdgSurfaceV6Private *>(resource))
+ return p->q_func();
+ return nullptr;
}
#ifdef QT_WAYLAND_COMPOSITOR_QUICK
@@ -1995,9 +1995,7 @@ void QWaylandXdgPositionerV6::zxdg_positioner_v6_set_offset(QtWaylandServer::zxd
QWaylandXdgPositionerV6 *QWaylandXdgPositionerV6::fromResource(wl_resource *resource)
{
- if (auto *r = Resource::fromResource(resource))
- return static_cast<QWaylandXdgPositionerV6 *>(r->zxdg_positioner_v6_object);
- return nullptr;
+ return QtWayland::fromResource<QWaylandXdgPositionerV6 *>(resource);
}
QT_END_NAMESPACE
diff --git a/src/compositor/extensions/qwaylandxdgshellv6integration.cpp b/src/compositor/extensions/qwaylandxdgshellv6integration.cpp
index 61a9092a3..66dbc6841 100644
--- a/src/compositor/extensions/qwaylandxdgshellv6integration.cpp
+++ b/src/compositor/extensions/qwaylandxdgshellv6integration.cpp
@@ -73,7 +73,7 @@ XdgToplevelV6Integration::XdgToplevelV6Integration(QWaylandQuickShellSurfaceItem
connect(m_xdgSurface->shell(), &QWaylandXdgShellV6::popupCreated, this, [item](QWaylandXdgPopupV6 *popup, QWaylandXdgSurfaceV6 *){
handlePopupCreated(item, popup);
});
- connect(m_xdgSurface->surface(), &QWaylandSurface::sizeChanged, this, &XdgToplevelV6Integration::handleSurfaceSizeChanged);
+ connect(m_xdgSurface->surface(), &QWaylandSurface::destinationSizeChanged, this, &XdgToplevelV6Integration::handleSurfaceSizeChanged);
connect(m_toplevel, &QObject::destroyed, this, &XdgToplevelV6Integration::handleToplevelDestroyed);
}
@@ -130,7 +130,7 @@ void XdgToplevelV6Integration::handleStartResize(QWaylandSeat *seat, Qt::Edges e
resizeState.resizeEdges = edges;
resizeState.initialWindowSize = m_xdgSurface->windowGeometry().size();
resizeState.initialPosition = m_item->moveItem()->position();
- resizeState.initialSurfaceSize = m_item->surface()->size();
+ resizeState.initialSurfaceSize = m_item->surface()->destinationSize();
resizeState.initialized = false;
}
@@ -247,14 +247,14 @@ void XdgToplevelV6Integration::handleActivatedChanged()
void XdgToplevelV6Integration::handleSurfaceSizeChanged()
{
if (grabberState == GrabberState::Resize) {
- qreal x = resizeState.initialPosition.x();
- qreal y = resizeState.initialPosition.y();
+ qreal dx = 0;
+ qreal dy = 0;
if (resizeState.resizeEdges & Qt::TopEdge)
- y += resizeState.initialSurfaceSize.height() - m_item->surface()->size().height();
-
+ dy = resizeState.initialSurfaceSize.height() - m_item->surface()->destinationSize().height();
if (resizeState.resizeEdges & Qt::LeftEdge)
- x += resizeState.initialSurfaceSize.width() - m_item->surface()->size().width();
- m_item->moveItem()->setPosition(QPointF(x, y));
+ dx = resizeState.initialSurfaceSize.width() - m_item->surface()->destinationSize().width();
+ QPointF offset = m_item->mapFromSurface({dx, dy});
+ m_item->moveItem()->setPosition(resizeState.initialPosition + offset);
}
}
@@ -285,11 +285,11 @@ void XdgPopupV6Integration::handleGeometryChanged()
{
if (m_item->view()->output()) {
const QPoint windowOffset = m_popup->parentXdgSurface()->windowGeometry().topLeft();
- const QPoint position = m_popup->unconstrainedPosition() + windowOffset;
+ const QPoint surfacePosition = m_popup->unconstrainedPosition() + windowOffset;
+ const QPoint itemPosition = m_item->mapFromSurface(surfacePosition).toPoint();
//TODO: positioner size or other size...?
- const float scaleFactor = m_item->view()->output()->scaleFactor();
//TODO check positioner constraints etc... sliding, flipping
- m_item->moveItem()->setPosition(position * scaleFactor);
+ m_item->moveItem()->setPosition(itemPosition);
} else {
qWarning() << "XdgPopupV6Integration popup item without output" << m_item;
}
diff --git a/src/compositor/global/global.pri b/src/compositor/global/global.pri
index 29d4f4376..172f916bf 100644
--- a/src/compositor/global/global.pri
+++ b/src/compositor/global/global.pri
@@ -4,6 +4,7 @@ HEADERS += \
global/qtwaylandcompositorglobal.h \
global/qwaylandcompositorextension.h \
global/qwaylandcompositorextension_p.h \
+ global/qwaylandutils_p.h \
global/qwaylandquickextension.h \
SOURCES += \
diff --git a/src/compositor/global/qwaylandcompositorextension.cpp b/src/compositor/global/qwaylandcompositorextension.cpp
index e50df48bd..912985399 100644
--- a/src/compositor/global/qwaylandcompositorextension.cpp
+++ b/src/compositor/global/qwaylandcompositorextension.cpp
@@ -44,7 +44,7 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
-#include <wayland-server.h>
+#include <wayland-server-core.h>
QT_BEGIN_NAMESPACE
diff --git a/src/compositor/global/qwaylandutils_p.h b/src/compositor/global/qwaylandutils_p.h
new file mode 100644
index 000000000..934e27617
--- /dev/null
+++ b/src/compositor/global/qwaylandutils_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDUTILS_P_H
+#define QWAYLANDUTILS_P_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.
+//
+
+#include <QtCore/qglobal.h>
+
+struct wl_resource;
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWayland {
+
+template<typename return_type>
+return_type fromResource(struct ::wl_resource *resource) {
+ if (auto *r = std::remove_pointer<return_type>::type::Resource::fromResource(resource))
+ return static_cast<return_type>(r->object());
+ return nullptr;
+}
+
+} // namespace QtWayland
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDUTILS_P_H
diff --git a/src/compositor/hardware_integration/qwlclientbufferintegration_p.h b/src/compositor/hardware_integration/qwlclientbufferintegration_p.h
index 13a69fce9..7b458fbc2 100644
--- a/src/compositor/hardware_integration/qwlclientbufferintegration_p.h
+++ b/src/compositor/hardware_integration/qwlclientbufferintegration_p.h
@@ -55,7 +55,7 @@
#include <QtWaylandCompositor/qwaylandsurface.h>
#include <QtWaylandCompositor/qwaylandbufferref.h>
#include <QtCore/QSize>
-#include <wayland-server.h>
+#include <wayland-server-core.h>
QT_BEGIN_NAMESPACE
diff --git a/src/compositor/wayland_wrapper/qwlclientbuffer.cpp b/src/compositor/wayland_wrapper/qwlclientbuffer.cpp
index 7df9ead3c..cb1ee3da0 100644
--- a/src/compositor/wayland_wrapper/qwlclientbuffer.cpp
+++ b/src/compositor/wayland_wrapper/qwlclientbuffer.cpp
@@ -47,7 +47,7 @@
#include <QtCore/QDebug>
-#include <wayland-server-protocol.h>
+#include <QtWaylandCompositor/private/wayland-wayland-server-protocol.h>
#include "qwaylandsharedmemoryformathelper_p.h"
#include <QtWaylandCompositor/private/qwaylandcompositor_p.h>
diff --git a/src/compositor/wayland_wrapper/qwlclientbuffer_p.h b/src/compositor/wayland_wrapper/qwlclientbuffer_p.h
index ac8c1ed01..f31ef5d46 100644
--- a/src/compositor/wayland_wrapper/qwlclientbuffer_p.h
+++ b/src/compositor/wayland_wrapper/qwlclientbuffer_p.h
@@ -59,7 +59,7 @@
#include <QtWaylandCompositor/QWaylandSurface>
#include <QtWaylandCompositor/QWaylandBufferRef>
-#include <wayland-server.h>
+#include <wayland-server-core.h>
QT_BEGIN_NAMESPACE
@@ -110,7 +110,7 @@ protected:
void ref();
void deref();
void sendRelease();
- void setDestroyed();
+ virtual void setDestroyed();
struct ::wl_resource *m_buffer = nullptr;
QRegion m_damage;
diff --git a/src/compositor/wayland_wrapper/qwldatasource.cpp b/src/compositor/wayland_wrapper/qwldatasource.cpp
index baa47d6fc..f5f456790 100644
--- a/src/compositor/wayland_wrapper/qwldatasource.cpp
+++ b/src/compositor/wayland_wrapper/qwldatasource.cpp
@@ -41,6 +41,7 @@
#include "qwldataoffer_p.h"
#include "qwldatadevice_p.h"
#include "qwldatadevicemanager_p.h"
+#include <QtWaylandCompositor/private/qwaylandutils_p.h>
#include <unistd.h>
#include <QtWaylandCompositor/private/wayland-wayland-server-protocol.h>
@@ -101,7 +102,7 @@ void DataSource::setDevice(DataDevice *device)
DataSource *DataSource::fromResource(struct ::wl_resource *resource)
{
- return static_cast<DataSource *>(Resource::fromResource(resource)->data_source_object);
+ return QtWayland::fromResource<DataSource *>(resource);
}
void DataSource::data_source_offer(Resource *, const QString &mime_type)
diff --git a/src/compositor/wayland_wrapper/qwlregion.cpp b/src/compositor/wayland_wrapper/qwlregion.cpp
index 52c19e946..4383474cb 100644
--- a/src/compositor/wayland_wrapper/qwlregion.cpp
+++ b/src/compositor/wayland_wrapper/qwlregion.cpp
@@ -39,6 +39,8 @@
#include "qwlregion_p.h"
+#include <QtWaylandCompositor/private/qwaylandutils_p.h>
+
QT_BEGIN_NAMESPACE
namespace QtWayland {
@@ -54,9 +56,7 @@ Region::~Region()
Region *Region::fromResource(struct ::wl_resource *resource)
{
- if (auto *r = Resource::fromResource(resource))
- return static_cast<Region *>(r->region_object);
- return nullptr;
+ return QtWayland::fromResource<Region *>(resource);
}
void Region::region_destroy_resource(Resource *)
diff --git a/src/compositor/wayland_wrapper/wayland_wrapper.pri b/src/compositor/wayland_wrapper/wayland_wrapper.pri
index 3041d7696..b0c8371f4 100644
--- a/src/compositor/wayland_wrapper/wayland_wrapper.pri
+++ b/src/compositor/wayland_wrapper/wayland_wrapper.pri
@@ -1,6 +1,6 @@
CONFIG += wayland-scanner
-WAYLANDSERVERSOURCES_SYSTEM += \
- ../3rdparty/protocol/wayland.xml \
+WAYLANDSERVERSOURCES += \
+ ../3rdparty/protocol/wayland.xml
HEADERS += \
wayland_wrapper/qwlbuffermanager_p.h \
diff --git a/src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglintegration.h b/src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglintegration.h
index 5e8a3bf46..9a614f58e 100644
--- a/src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglintegration.h
+++ b/src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglintegration.h
@@ -41,7 +41,7 @@
#define QWAYLANDBRCMEGLINTEGRATION_H
#include <QtWaylandClient/private/qwaylandclientbufferintegration_p.h>
-#include <wayland-client.h>
+#include <wayland-client-core.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
diff --git a/src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglwindow.cpp b/src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglwindow.cpp
index 5cd52f676..31adf100b 100644
--- a/src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglwindow.cpp
+++ b/src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglwindow.cpp
@@ -50,7 +50,6 @@
#include <EGL/eglext_brcm.h>
-#include <wayland-client.h>
#include "wayland-brcm-client-protocol.h"
QT_BEGIN_NAMESPACE
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandeglclientbufferintegration.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandeglclientbufferintegration.cpp
index 4b3a635c7..3a34d2561 100644
--- a/src/hardwareintegration/client/wayland-egl/qwaylandeglclientbufferintegration.cpp
+++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglclientbufferintegration.cpp
@@ -42,7 +42,7 @@
#include "qwaylandeglwindow.h"
#include "qwaylandglcontext.h"
-#include <wayland-client.h>
+#include <wayland-client-core.h>
#include <QtCore/QDebug>
#include <private/qeglconvenience_p.h>
@@ -65,7 +65,7 @@ static const char *qwaylandegl_threadedgl_blacklist_vendor[] = {
QWaylandEglClientBufferIntegration::QWaylandEglClientBufferIntegration()
{
- qDebug() << "Using Wayland-EGL";
+ qCDebug(lcQpaWayland) << "Using Wayland-EGL";
}
@@ -87,7 +87,7 @@ void QWaylandEglClientBufferIntegration::initialize(QWaylandDisplay *display)
m_eglDisplay = eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_KHR, display->wl_display(), nullptr);
} else {
- qWarning("The EGL implementation does not support the Wayland platform");
+ qCWarning(lcQpaWayland) << "The EGL implementation does not support the Wayland platform";
return;
}
} else {
@@ -102,13 +102,13 @@ void QWaylandEglClientBufferIntegration::initialize(QWaylandDisplay *display)
m_display = display;
if (m_eglDisplay == EGL_NO_DISPLAY) {
- qWarning("EGL not available");
+ qCWarning(lcQpaWayland) << "EGL not available";
return;
}
EGLint major,minor;
if (!eglInitialize(m_eglDisplay, &major, &minor)) {
- qWarning("failed to initialize EGL display");
+ qCWarning(lcQpaWayland) << "Failed to initialize EGL display" << hex << eglGetError();
m_eglDisplay = EGL_NO_DISPLAY;
return;
}
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandeglinclude.h b/src/hardwareintegration/client/wayland-egl/qwaylandeglinclude.h
index 233ce78bd..e9998b832 100644
--- a/src/hardwareintegration/client/wayland-egl/qwaylandeglinclude.h
+++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglinclude.h
@@ -41,7 +41,7 @@
#define QWAYLANDEGLINCLUDE_H
#include <string.h>
-#include <wayland-client.h>
+#include <wayland-client-core.h>
#include <wayland-egl.h>
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h
index 88e893a74..9e6cb876c 100644
--- a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h
+++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h
@@ -62,7 +62,7 @@ public:
void ensureSize() override;
void updateSurface(bool create);
- virtual void setGeometry(const QRect &rect) override;
+ void setGeometry(const QRect &rect) override;
QRect contentsRect() const;
EGLSurface eglSurface() const;
diff --git a/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglclientbufferintegration.cpp b/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglclientbufferintegration.cpp
index aa5367e02..104a4df91 100644
--- a/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglclientbufferintegration.cpp
+++ b/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglclientbufferintegration.cpp
@@ -118,7 +118,7 @@ const struct qt_xcomposite_listener QWaylandXCompositeEGLClientBufferIntegration
QWaylandXCompositeEGLClientBufferIntegration::rootInformation
};
-void QWaylandXCompositeEGLClientBufferIntegration::wlDisplayHandleGlobal(void *data, wl_registry *registry, uint32_t id, const QString &interface, uint32_t version)
+void QWaylandXCompositeEGLClientBufferIntegration::wlDisplayHandleGlobal(void *data, ::wl_registry *registry, uint32_t id, const QString &interface, uint32_t version)
{
Q_UNUSED(version);
if (interface == "qt_xcomposite") {
diff --git a/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglclientbufferintegration.h b/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglclientbufferintegration.h
index ee55d6892..7037ee2d0 100644
--- a/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglclientbufferintegration.h
+++ b/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglclientbufferintegration.h
@@ -41,7 +41,7 @@
#define QWAYLANDXCOMPOSITEEGLCLIENTBUFFERINTEGRATION_H
#include <QtWaylandClient/private/qwaylandclientbufferintegration_p.h>
-#include <wayland-client.h>
+#include <wayland-client-core.h>
#include <QtCore/QTextStream>
#include <QtCore/QDataStream>
@@ -64,6 +64,7 @@
struct qt_xcomposite;
struct qt_xcomposite_listener;
+struct wl_registry;
QT_BEGIN_NAMESPACE
@@ -100,7 +101,7 @@ private:
int mScreen;
Window mRootWindow;
- static void wlDisplayHandleGlobal(void *data, struct wl_registry *registry, uint32_t id,
+ static void wlDisplayHandleGlobal(void *data, struct ::wl_registry *registry, uint32_t id,
const QString &interface, uint32_t version);
static const struct ::qt_xcomposite_listener xcomposite_listener;
diff --git a/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxintegration.cpp b/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxintegration.cpp
index 090cfb8a0..8be47fa2e 100644
--- a/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxintegration.cpp
+++ b/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxintegration.cpp
@@ -109,7 +109,7 @@ const struct qt_xcomposite_listener QWaylandXCompositeGLXIntegration::xcomposite
QWaylandXCompositeGLXIntegration::rootInformation
};
-void QWaylandXCompositeGLXIntegration::wlDisplayHandleGlobal(void *data, wl_registry *registry, uint32_t id, const QString &interface, uint32_t version)
+void QWaylandXCompositeGLXIntegration::wlDisplayHandleGlobal(void *data, ::wl_registry *registry, uint32_t id, const QString &interface, uint32_t version)
{
Q_UNUSED(version);
if (interface == "qt_xcomposite") {
diff --git a/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxintegration.h b/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxintegration.h
index 26f2bad6f..809690816 100644
--- a/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxintegration.h
+++ b/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxintegration.h
@@ -41,7 +41,7 @@
#define QWAYLANDXCOMPOSITEGLXINTEGRATION_H
#include <QtWaylandClient/private/qwaylandclientbufferintegration_p.h>
-#include <wayland-client.h>
+#include <wayland-client-core.h>
#include <QtCore/QTextStream>
#include <QtCore/QDataStream>
@@ -59,6 +59,7 @@
struct qt_xcomposite;
struct qt_xcomposite_listener;
+struct wl_registry;
QT_BEGIN_NAMESPACE
@@ -93,7 +94,7 @@ private:
int mScreen = 0;
Window mRootWindow = 0;
- static void wlDisplayHandleGlobal(void *data, struct wl_registry *registry, uint32_t id,
+ static void wlDisplayHandleGlobal(void *data, struct ::wl_registry *registry, uint32_t id,
const QString &interface, uint32_t version);
static const struct qt_xcomposite_listener xcomposite_listener;
diff --git a/src/hardwareintegration/client/xcomposite_share/qwaylandxcompositebuffer.cpp b/src/hardwareintegration/client/xcomposite_share/qwaylandxcompositebuffer.cpp
index 5f1818cdf..33d9a6038 100644
--- a/src/hardwareintegration/client/xcomposite_share/qwaylandxcompositebuffer.cpp
+++ b/src/hardwareintegration/client/xcomposite_share/qwaylandxcompositebuffer.cpp
@@ -39,7 +39,6 @@
#include "qwaylandxcompositebuffer.h"
-#include <wayland-client.h>
#include "wayland-xcomposite-client-protocol.h"
QT_BEGIN_NAMESPACE
diff --git a/src/hardwareintegration/client/xcomposite_share/xcomposite_share.pri b/src/hardwareintegration/client/xcomposite_share/xcomposite_share.pri
index b18aa2d50..d2b129d03 100644
--- a/src/hardwareintegration/client/xcomposite_share/xcomposite_share.pri
+++ b/src/hardwareintegration/client/xcomposite_share/xcomposite_share.pri
@@ -1,7 +1,7 @@
INCLUDEPATH += $$PWD
QMAKE_USE += xcomposite x11
-CONFIG += wayland-scanner
+CONFIG += wayland-scanner-client-wayland-protocol-include
WAYLANDCLIENTSOURCES += $$PWD/../../../extensions/xcomposite.xml
HEADERS += \
diff --git a/src/hardwareintegration/compositor/brcm-egl/brcmbuffer.h b/src/hardwareintegration/compositor/brcm-egl/brcmbuffer.h
index 3028fbed5..83545de2e 100644
--- a/src/hardwareintegration/compositor/brcm-egl/brcmbuffer.h
+++ b/src/hardwareintegration/compositor/brcm-egl/brcmbuffer.h
@@ -41,6 +41,7 @@
#define BRCMBUFFER_H
#include <QtWaylandCompositor/private/qwayland-server-wayland.h>
+#include <QtWaylandCompositor/private/qwaylandutils_p.h>
#include <QtCore/QSize>
#include <QtCore/QVector>
@@ -62,7 +63,7 @@ public:
QSize size() { return m_size; }
- static BrcmBuffer *fromResource(struct ::wl_resource *resource) { return static_cast<BrcmBuffer*>(Resource::fromResource(resource)->buffer_object); }
+ static BrcmBuffer *fromResource(struct ::wl_resource *resource) { return QtWayland::fromResource<BrcmBuffer *>(resource); }
protected:
void buffer_destroy_resource(Resource *resource) override;
diff --git a/src/hardwareintegration/compositor/libhybris-egl-server/libhybriseglserverbufferintegration.cpp b/src/hardwareintegration/compositor/libhybris-egl-server/libhybriseglserverbufferintegration.cpp
index 5a42c00dc..af9059603 100644
--- a/src/hardwareintegration/compositor/libhybris-egl-server/libhybriseglserverbufferintegration.cpp
+++ b/src/hardwareintegration/compositor/libhybris-egl-server/libhybriseglserverbufferintegration.cpp
@@ -42,7 +42,7 @@
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLTexture>
#include <hybris/eglplatformcommon/hybris_nativebufferext.h>
-#include <wayland-server.h>
+#include <wayland-server-core.h>
QT_BEGIN_NAMESPACE
LibHybrisEglServerBuffer::LibHybrisEglServerBuffer(LibHybrisEglServerBufferIntegration *integration, const QImage &qimage, QtWayland::ServerBuffer::Format format)
diff --git a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pri b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pri
new file mode 100644
index 000000000..77f6d9410
--- /dev/null
+++ b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pri
@@ -0,0 +1,16 @@
+INCLUDEPATH += $$PWD
+
+QMAKE_USE_PRIVATE += egl wayland-server wayland-egl
+
+CONFIG += wayland-scanner
+WAYLANDSERVERSOURCES += $$PWD/../../../3rdparty/protocol/linux-dmabuf-unstable-v1.xml
+
+QT += egl_support-private
+
+SOURCES += \
+ $$PWD/linuxdmabufclientbufferintegration.cpp \
+ $$PWD/linuxdmabuf.cpp
+
+HEADERS += \
+ $$PWD/linuxdmabufclientbufferintegration.h \
+ $$PWD/linuxdmabuf.h
diff --git a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.cpp b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.cpp
new file mode 100644
index 000000000..2ba0462c7
--- /dev/null
+++ b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.cpp
@@ -0,0 +1,332 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "linuxdmabuf.h"
+#include "linuxdmabufclientbufferintegration.h"
+
+#include <QtWaylandCompositor/QWaylandCompositor>
+
+#include <drm_fourcc.h>
+#include <drm_mode.h>
+#include <unistd.h>
+
+QT_BEGIN_NAMESPACE
+
+LinuxDmabuf::LinuxDmabuf(wl_display *display, LinuxDmabufClientBufferIntegration *clientBufferIntegration)
+ : zwp_linux_dmabuf_v1(display, 3 /*version*/)
+ , m_clientBufferIntegration(clientBufferIntegration)
+{
+}
+
+void LinuxDmabuf::setSupportedModifiers(const QHash<uint32_t, QVector<uint64_t>> &modifiers)
+{
+ Q_ASSERT(resourceMap().isEmpty());
+ m_modifiers = modifiers;
+}
+
+void LinuxDmabuf::zwp_linux_dmabuf_v1_bind_resource(Resource *resource)
+{
+ for (auto it = m_modifiers.constBegin(); it != m_modifiers.constEnd(); ++it) {
+ auto format = it.key();
+ auto modifiers = it.value();
+ // send DRM_FORMAT_MOD_INVALID when no modifiers are supported for a format
+ if (modifiers.isEmpty())
+ modifiers << DRM_FORMAT_MOD_INVALID;
+ for (const auto &modifier : qAsConst(modifiers)) {
+ if (resource->version() >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) {
+ const uint32_t modifier_lo = modifier & 0xFFFFFFFF;
+ const uint32_t modifier_hi = modifier >> 32;
+ send_modifier(resource->handle, format, modifier_hi, modifier_lo);
+ } else if (modifier == DRM_FORMAT_MOD_LINEAR || modifier == DRM_FORMAT_MOD_INVALID) {
+ send_format(resource->handle, format);
+ }
+ }
+ }
+}
+
+void LinuxDmabuf::zwp_linux_dmabuf_v1_create_params(Resource *resource, uint32_t params_id)
+{
+ wl_resource *r = wl_resource_create(resource->client(), &zwp_linux_buffer_params_v1_interface,
+ wl_resource_get_version(resource->handle), params_id);
+ new LinuxDmabufParams(m_clientBufferIntegration, r); // deleted by the client, or when it disconnects
+}
+
+LinuxDmabufParams::LinuxDmabufParams(LinuxDmabufClientBufferIntegration *clientBufferIntegration, wl_resource *resource)
+ : zwp_linux_buffer_params_v1(resource)
+ , m_clientBufferIntegration(clientBufferIntegration)
+{
+}
+
+LinuxDmabufParams::~LinuxDmabufParams()
+{
+ for (auto it = m_planes.begin(); it != m_planes.end(); ++it) {
+ if (it.value().fd != -1)
+ close(it.value().fd);
+ it.value().fd = -1;
+ }
+}
+
+bool LinuxDmabufParams::handleCreateParams(Resource *resource, int width, int height, uint format, uint flags)
+{
+ if (m_used) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
+ "Params already used");
+ return false;
+ }
+
+ if (width <= 0 || height <= 0) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
+ "Invalid dimensions in create request");
+ return false;
+ }
+
+ if (m_planes.isEmpty()) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
+ "Cannot create a buffer with no planes");
+ return false;
+ }
+
+ // check for holes in plane sequence
+ auto planeIds = m_planes.keys();
+ std::sort(planeIds.begin(), planeIds.end());
+ for (int i = 0; i < planeIds.count(); ++i) {
+ if (uint(i) != planeIds[i]) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
+ "No dmabuf parameters provided for plane %i", i);
+ return false;
+ }
+ }
+
+ // check for overflows
+ for (auto it = m_planes.constBegin(); it != m_planes.constEnd(); ++it) {
+ const auto planeId = it.key();
+ const auto plane = it.value();
+ if (static_cast<int64_t>(plane.offset) + plane.stride > UINT32_MAX) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+ "Size overflow for plane %i",
+ planeId);
+ return false;
+ }
+ if (planeId == 0 && static_cast<int64_t>(plane.offset) + plane.stride * static_cast<int64_t>(height) > UINT32_MAX) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+ "Size overflow for plane %i",
+ planeId);
+ return false;
+ }
+
+ // do not report an error as it might be caused by the kernel not supporting seeking on dmabuf
+ off_t size = lseek(plane.fd, 0, SEEK_END);
+ if (size == -1) {
+ qCDebug(qLcWaylandCompositorHardwareIntegration) << "Seeking is not supported";
+ continue;
+ }
+
+ if (static_cast<int64_t>(plane.offset) >= size) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+ "Invalid offset %i for plane %i",
+ plane.offset, planeId);
+ return false;
+ }
+
+ if (static_cast<int64_t>(plane.offset) + static_cast<int64_t>(plane.stride) > size) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+ "Invalid stride %i for plane %i",
+ plane.stride, planeId);
+ return false;
+ }
+
+ // only valid for first plane as other planes might be sub-sampled
+ if (planeId == 0 && plane.offset + static_cast<int64_t>(plane.stride) * height > size) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+ "Invalid buffer stride or height for plane %i", planeId);
+ return false;
+ }
+ }
+
+ m_size = QSize(width, height);
+ m_drmFormat = format;
+ m_flags = flags;
+ m_used = true;
+
+ return true;
+}
+
+void LinuxDmabufParams::zwp_linux_buffer_params_v1_destroy(Resource *resource)
+{
+ wl_resource_destroy(resource->handle);
+}
+
+void LinuxDmabufParams::zwp_linux_buffer_params_v1_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource);
+ delete this;
+}
+
+void LinuxDmabufParams::zwp_linux_buffer_params_v1_add(Resource *resource, int32_t fd, uint32_t plane_idx, uint32_t offset, uint32_t stride, uint32_t modifier_hi, uint32_t modifier_lo)
+{
+ const uint64_t modifiers = (static_cast<uint64_t>(modifier_hi) << 32) | modifier_lo;
+ if (plane_idx >= LinuxDmabufWlBuffer::MaxDmabufPlanes) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
+ "Plane index %i is out of bounds", plane_idx);
+ }
+
+ if (m_planes.contains(plane_idx)) {
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
+ "Plane already set");
+ }
+
+ Plane plane;
+ plane.fd = fd;
+ plane.modifiers = modifiers;
+ plane.offset = offset;
+ plane.stride = stride;
+ m_planes.insert(plane_idx, plane);
+}
+
+void LinuxDmabufParams::zwp_linux_buffer_params_v1_create(Resource *resource, int32_t width, int32_t height, uint32_t format, uint32_t flags)
+{
+ if (!handleCreateParams(resource, width, height, format, flags))
+ return;
+
+ auto *buffer = new LinuxDmabufWlBuffer(resource->client(), m_clientBufferIntegration);
+ buffer->m_size = m_size;
+ buffer->m_flags = m_flags;
+ buffer->m_drmFormat = m_drmFormat;
+ buffer->m_planesNumber = m_planes.size(); // it is checked before that planes are in consecutive sequence
+ for (auto it = m_planes.begin(); it != m_planes.end(); ++it) {
+ buffer->m_planes[it.key()] = it.value();
+ it.value().fd = -1; // ownership is moved
+ }
+
+ if (!m_clientBufferIntegration->importBuffer(buffer->resource()->handle, buffer)) {
+ send_failed(resource->handle);
+ } else {
+ send_created(resource->handle, buffer->resource()->handle);
+ }
+}
+
+void LinuxDmabufParams::zwp_linux_buffer_params_v1_create_immed(Resource *resource, uint32_t buffer_id, int32_t width, int32_t height, uint32_t format, uint32_t flags)
+{
+ if (!handleCreateParams(resource, width, height, format, flags))
+ return;
+
+ auto *buffer = new LinuxDmabufWlBuffer(resource->client(), m_clientBufferIntegration, buffer_id);
+ buffer->m_size = m_size;
+ buffer->m_flags = m_flags;
+ buffer->m_drmFormat = m_drmFormat;
+ buffer->m_planesNumber = m_planes.size(); // it is checked before that planes are in consecutive sequence
+ for (auto it = m_planes.begin(); it != m_planes.end(); ++it) {
+ buffer->m_planes[it.key()] = it.value();
+ it.value().fd = -1; // ownership is moved
+ }
+
+ if (!m_clientBufferIntegration->importBuffer(buffer->resource()->handle, buffer)) {
+ // for the 'create_immed' request, the implementation can decide
+ // how to handle the failure by an unknown cause; we decide
+ // to raise a fatal error at the client
+ wl_resource_post_error(resource->handle,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
+ "Import of the provided DMA buffer failed");
+ }
+ // note: create signal shall not be sent for the 'create_immed' request
+}
+
+LinuxDmabufWlBuffer::LinuxDmabufWlBuffer(::wl_client *client, LinuxDmabufClientBufferIntegration *clientBufferIntegration, uint id)
+ : wl_buffer(client, id, 1 /*version*/)
+ , m_clientBufferIntegration(clientBufferIntegration)
+{
+}
+
+LinuxDmabufWlBuffer::~LinuxDmabufWlBuffer()
+{
+ m_clientBufferIntegration->removeBuffer(resource()->handle);
+ buffer_destroy(resource());
+}
+
+void LinuxDmabufWlBuffer::buffer_destroy(Resource *resource)
+{
+ Q_UNUSED(resource);
+ for (uint32_t i = 0; i < m_planesNumber; ++i) {
+ if (m_textures[i] != nullptr) {
+ m_clientBufferIntegration->deleteGLTextureWhenPossible(m_textures[i]);
+ m_textures[i] = nullptr;
+ }
+ if (m_eglImages[i] != EGL_NO_IMAGE_KHR) {
+ m_clientBufferIntegration->deleteImage(m_eglImages[i]);
+ m_eglImages[i] = EGL_NO_IMAGE_KHR;
+ }
+ if (m_planes[i].fd != -1)
+ close(m_planes[i].fd);
+ m_planes[i].fd = -1;
+ }
+ m_planesNumber = 0;
+}
+
+void LinuxDmabufWlBuffer::initImage(uint32_t plane, EGLImageKHR image)
+{
+ Q_ASSERT(plane < m_planesNumber);
+ Q_ASSERT(m_eglImages.at(plane) == EGL_NO_IMAGE_KHR);
+ m_eglImages[plane] = image;
+}
+
+void LinuxDmabufWlBuffer::initTexture(uint32_t plane, QOpenGLTexture *texture)
+{
+ Q_ASSERT(plane < m_planesNumber);
+ Q_ASSERT(m_textures.at(plane) == nullptr);
+ m_textures[plane] = texture;
+}
+
+void LinuxDmabufWlBuffer::buffer_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource);
+ delete this;
+}
+
+QT_END_NAMESPACE
diff --git a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.h b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.h
new file mode 100644
index 000000000..2abc2ce6b
--- /dev/null
+++ b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.h
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef LINUXDMABUF_H
+#define LINUXDMABUF_H
+
+#include "qwayland-server-linux-dmabuf-unstable-v1.h"
+
+#include <QtWaylandCompositor/private/qwayland-server-wayland.h>
+#include <QtWaylandCompositor/private/qwlclientbufferintegration_p.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QHash>
+#include <QtCore/QSize>
+#include <QtCore/QTextStream>
+#include <QtGui/QOpenGLTexture>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+// compatibility with libdrm <= 2.4.74
+#ifndef DRM_FORMAT_RESERVED
+#define DRM_FORMAT_RESERVED ((1ULL << 56) - 1)
+#endif
+#ifndef DRM_FORMAT_MOD_VENDOR_NONE
+#define DRM_FORMAT_MOD_VENDOR_NONE 0
+#endif
+#ifndef DRM_FORMAT_MOD_LINEAR
+#define DRM_FORMAT_MOD_LINEAR fourcc_mod_code(NONE, 0)
+#endif
+#ifndef DRM_FORMAT_MOD_INVALID
+#define DRM_FORMAT_MOD_INVALID fourcc_mod_code(NONE, DRM_FORMAT_RESERVED)
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandCompositor;
+class QWaylandResource;
+class LinuxDmabufParams;
+class LinuxDmabufClientBufferIntegration;
+
+struct Plane {
+ int fd = -1;
+ uint32_t offset = 0;
+ uint32_t stride = 0;
+ uint64_t modifiers = 0;
+};
+
+class LinuxDmabuf : public QtWaylandServer::zwp_linux_dmabuf_v1
+{
+public:
+ explicit LinuxDmabuf(wl_display *display, LinuxDmabufClientBufferIntegration *clientBufferIntegration);
+
+ void setSupportedModifiers(const QHash<uint32_t, QVector<uint64_t>> &modifiers);
+
+protected:
+ void zwp_linux_dmabuf_v1_bind_resource(Resource *resource) override;
+ void zwp_linux_dmabuf_v1_create_params(Resource *resource, uint32_t params_id) override;
+
+private:
+ QHash<uint32_t, QVector<uint64_t>> m_modifiers; // key=DRM format, value=supported DRM modifiers for format
+ LinuxDmabufClientBufferIntegration *m_clientBufferIntegration;
+};
+
+class LinuxDmabufParams : public QtWaylandServer::zwp_linux_buffer_params_v1
+{
+public:
+ explicit LinuxDmabufParams(LinuxDmabufClientBufferIntegration *clientBufferIntegration, wl_resource *resource);
+ ~LinuxDmabufParams() override;
+
+private:
+ bool handleCreateParams(Resource *resource, int width, int height, uint format, uint flags);
+ uint m_drmFormat = 0;
+ uint m_flags = 0;
+ QSize m_size;
+ bool m_used = false;
+ QMap<uint, Plane> m_planes;
+ LinuxDmabufClientBufferIntegration *m_clientBufferIntegration;
+
+protected:
+ void zwp_linux_buffer_params_v1_destroy(Resource *resource) override;
+ void zwp_linux_buffer_params_v1_add(Resource *resource, int32_t fd, uint32_t plane_idx, uint32_t offset, uint32_t stride, uint32_t modifier_hi, uint32_t modifier_lo) override;
+ void zwp_linux_buffer_params_v1_create(Resource *resource, int32_t width, int32_t height, uint32_t format, uint32_t flags) override;
+ void zwp_linux_buffer_params_v1_create_immed(Resource *resource, uint32_t buffer_id, int32_t width, int32_t height, uint32_t format, uint32_t flags) override;
+ void zwp_linux_buffer_params_v1_destroy_resource(Resource *resource) override;
+
+ friend class LinuxDmabufClientBufferIntegrationPrivate;
+};
+
+class LinuxDmabufWlBuffer : public QtWaylandServer::wl_buffer
+{
+public:
+ explicit LinuxDmabufWlBuffer(::wl_client *client, LinuxDmabufClientBufferIntegration *clientBufferIntegration, uint id = 0);
+ ~LinuxDmabufWlBuffer() override;
+
+ void initImage(uint32_t plane, EGLImageKHR image);
+ void initTexture(uint32_t plane, QOpenGLTexture *texture);
+ inline QSize size() const { return m_size; }
+ inline uint32_t flags() const { return m_flags; }
+ inline uint32_t drmFormat() const { return m_drmFormat; }
+ inline Plane& plane(uint index) { return m_planes.at(index); }
+ inline uint32_t planesNumber() const { return m_planesNumber; }
+ inline EGLImageKHR image(uint32_t plane) { return m_eglImages.at(plane); }
+ inline QOpenGLTexture *texture(uint32_t plane) const { return m_textures.at(plane); }
+ void buffer_destroy_resource(Resource *resource) override;
+
+ static const uint32_t MaxDmabufPlanes = 4;
+
+private:
+ QSize m_size;
+ uint32_t m_flags = 0;
+ uint32_t m_drmFormat = EGL_TEXTURE_RGBA;
+ std::array<Plane, MaxDmabufPlanes> m_planes;
+ uint32_t m_planesNumber = 1;
+ LinuxDmabufClientBufferIntegration *m_clientBufferIntegration = nullptr;
+ std::array<EGLImageKHR, MaxDmabufPlanes> m_eglImages = { {EGL_NO_IMAGE_KHR, EGL_NO_IMAGE_KHR, EGL_NO_IMAGE_KHR, EGL_NO_IMAGE_KHR} };
+ std::array<QOpenGLTexture *, MaxDmabufPlanes> m_textures = { {nullptr, nullptr, nullptr, nullptr} };
+ void freeResources();
+ void buffer_destroy(Resource *resource) override;
+
+ friend class LinuxDmabufParams;
+};
+
+QT_END_NAMESPACE
+
+#endif // LINUXDMABUF_H
diff --git a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp
new file mode 100644
index 000000000..a85f24542
--- /dev/null
+++ b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp
@@ -0,0 +1,501 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "linuxdmabufclientbufferintegration.h"
+#include "linuxdmabuf.h"
+
+#include <QtWaylandCompositor/QWaylandCompositor>
+#include <QtWaylandCompositor/private/qwayland-server-wayland.h>
+#include <qpa/qplatformnativeinterface.h>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLTexture>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <unistd.h>
+#include <drm_fourcc.h>
+
+QT_BEGIN_NAMESPACE
+
+static QWaylandBufferRef::BufferFormatEgl formatFromDrmFormat(EGLint format) {
+ switch (format) {
+ case DRM_FORMAT_RGB332:
+ case DRM_FORMAT_BGR233:
+ case DRM_FORMAT_XRGB4444:
+ case DRM_FORMAT_XBGR4444:
+ case DRM_FORMAT_RGBX4444:
+ case DRM_FORMAT_BGRX4444:
+ case DRM_FORMAT_XRGB1555:
+ case DRM_FORMAT_XBGR1555:
+ case DRM_FORMAT_RGBX5551:
+ case DRM_FORMAT_BGRX5551:
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_BGR565:
+ case DRM_FORMAT_RGB888:
+ case DRM_FORMAT_BGR888:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_RGBX8888:
+ case DRM_FORMAT_BGRX8888:
+ case DRM_FORMAT_XRGB2101010:
+ case DRM_FORMAT_XBGR2101010:
+ case DRM_FORMAT_RGBX1010102:
+ case DRM_FORMAT_BGRX1010102:
+ return QWaylandBufferRef::BufferFormatEgl_RGB;
+ case DRM_FORMAT_ARGB4444:
+ case DRM_FORMAT_ABGR4444:
+ case DRM_FORMAT_RGBA4444:
+ case DRM_FORMAT_BGRA4444:
+ case DRM_FORMAT_ARGB1555:
+ case DRM_FORMAT_ABGR1555:
+ case DRM_FORMAT_RGBA5551:
+ case DRM_FORMAT_BGRA5551:
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_RGBA8888:
+ case DRM_FORMAT_BGRA8888:
+ case DRM_FORMAT_ARGB2101010:
+ case DRM_FORMAT_ABGR2101010:
+ case DRM_FORMAT_RGBA1010102:
+ case DRM_FORMAT_BGRA1010102:
+ return QWaylandBufferRef::BufferFormatEgl_RGBA;
+ case DRM_FORMAT_YUYV:
+ return QWaylandBufferRef::BufferFormatEgl_Y_XUXV;
+ default:
+ qCDebug(qLcWaylandCompositorHardwareIntegration) << "Buffer format" << hex << format << "not supported";
+ return QWaylandBufferRef::BufferFormatEgl_Null;
+ }
+}
+
+static QOpenGLTexture::TextureFormat openGLFormatFromBufferFormat(QWaylandBufferRef::BufferFormatEgl format) {
+ switch (format) {
+ case QWaylandBufferRef::BufferFormatEgl_RGB:
+ return QOpenGLTexture::RGBFormat;
+ case QWaylandBufferRef::BufferFormatEgl_RGBA:
+ return QOpenGLTexture::RGBAFormat;
+ default:
+ return QOpenGLTexture::NoFormat;
+ }
+}
+
+bool LinuxDmabufClientBufferIntegration::initSimpleTexture(LinuxDmabufWlBuffer *dmabufBuffer)
+{
+ bool success = true;
+
+ // Resolving GL functions may need a context current, so do it only here.
+ if (!gl_egl_image_target_texture_2d)
+ gl_egl_image_target_texture_2d = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"));
+
+ if (dmabufBuffer->plane(0).modifiers != DRM_FORMAT_MOD_INVALID && !m_supportsDmabufModifiers) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Buffer uses dmabuf modifiers, which are not supported.";
+ success = false;
+ }
+
+ for (uint32_t i = 0; i < dmabufBuffer->planesNumber(); ++i) {
+ QVarLengthArray<EGLint, 17> attribs;
+ switch (i) {
+ case 0:
+ attribs = {
+ EGL_WIDTH, dmabufBuffer->size().width(),
+ EGL_HEIGHT, dmabufBuffer->size().height(),
+ EGL_LINUX_DRM_FOURCC_EXT, EGLint(dmabufBuffer->drmFormat()),
+ EGL_DMA_BUF_PLANE0_FD_EXT, dmabufBuffer->plane(i).fd,
+ EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGLint(dmabufBuffer->plane(i).offset),
+ EGL_DMA_BUF_PLANE0_PITCH_EXT, EGLint(dmabufBuffer->plane(i).stride),
+ EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, EGLint(dmabufBuffer->plane(i).modifiers & 0xffffffff),
+ EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, EGLint(dmabufBuffer->plane(i).modifiers >> 32),
+ EGL_NONE
+ };
+ break;
+ case 1:
+ attribs = {
+ EGL_WIDTH, dmabufBuffer->size().width(),
+ EGL_HEIGHT, dmabufBuffer->size().height(),
+ EGL_LINUX_DRM_FOURCC_EXT, EGLint(dmabufBuffer->drmFormat()),
+ EGL_DMA_BUF_PLANE1_FD_EXT, dmabufBuffer->plane(i).fd,
+ EGL_DMA_BUF_PLANE1_OFFSET_EXT, EGLint(dmabufBuffer->plane(i).offset),
+ EGL_DMA_BUF_PLANE1_PITCH_EXT, EGLint(dmabufBuffer->plane(i).stride),
+ EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, EGLint(dmabufBuffer->plane(i).modifiers & 0xffffffff),
+ EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT, EGLint(dmabufBuffer->plane(i).modifiers >> 32),
+ EGL_NONE
+ };
+ break;
+ case 2:
+ attribs = {
+ EGL_WIDTH, dmabufBuffer->size().width(),
+ EGL_HEIGHT, dmabufBuffer->size().height(),
+ EGL_LINUX_DRM_FOURCC_EXT, EGLint(dmabufBuffer->drmFormat()),
+ EGL_DMA_BUF_PLANE2_FD_EXT, dmabufBuffer->plane(i).fd,
+ EGL_DMA_BUF_PLANE2_OFFSET_EXT, EGLint(dmabufBuffer->plane(i).offset),
+ EGL_DMA_BUF_PLANE2_PITCH_EXT, EGLint(dmabufBuffer->plane(i).stride),
+ EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, EGLint(dmabufBuffer->plane(i).modifiers & 0xffffffff),
+ EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT, EGLint(dmabufBuffer->plane(i).modifiers >> 32),
+ EGL_NONE
+ };
+ break;
+ case 3:
+ attribs = {
+ EGL_WIDTH, dmabufBuffer->size().width(),
+ EGL_HEIGHT, dmabufBuffer->size().height(),
+ EGL_LINUX_DRM_FOURCC_EXT, EGLint(dmabufBuffer->drmFormat()),
+ EGL_DMA_BUF_PLANE3_FD_EXT, dmabufBuffer->plane(i).fd,
+ EGL_DMA_BUF_PLANE3_OFFSET_EXT, EGLint(dmabufBuffer->plane(i).offset),
+ EGL_DMA_BUF_PLANE3_PITCH_EXT, EGLint(dmabufBuffer->plane(i).stride),
+ EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT, EGLint(dmabufBuffer->plane(i).modifiers & 0xffffffff),
+ EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT, EGLint(dmabufBuffer->plane(i).modifiers >> 32),
+ EGL_NONE
+ };
+ break;
+ default:
+ return false;
+ }
+
+ // note: EGLImageKHR does NOT take ownership of the file descriptors
+ EGLImageKHR image = egl_create_image(m_eglDisplay,
+ EGL_NO_CONTEXT,
+ EGL_LINUX_DMA_BUF_EXT,
+ (EGLClientBuffer) nullptr,
+ attribs.constData());
+
+ if (image == EGL_NO_IMAGE_KHR) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "failed to create EGL image for plane" << i;
+ success = false;
+ }
+
+ dmabufBuffer->initImage(i, image);
+ }
+ return success;
+}
+
+bool LinuxDmabufClientBufferIntegration::initYuvTexture(LinuxDmabufWlBuffer *dmabufBuffer)
+{
+ bool success = true;
+
+ const YuvFormatConversion conversion = m_yuvFormats.value(dmabufBuffer->drmFormat());
+ if (conversion.inputPlanes != dmabufBuffer->planesNumber()) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Buffer for this format must provide" << conversion.inputPlanes
+ << "planes but only" << dmabufBuffer->planesNumber() << "received";
+ return false;
+ }
+
+ // Resolving GL functions may need a context current, so do it only here.
+ if (!gl_egl_image_target_texture_2d)
+ gl_egl_image_target_texture_2d = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"));
+
+
+ if (dmabufBuffer->plane(0).modifiers != DRM_FORMAT_MOD_INVALID && !m_supportsDmabufModifiers) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Buffer uses dmabuf modifiers, which are not supported.";
+ success = false;
+ }
+
+ for (uint32_t i = 0; i < conversion.outputPlanes; ++i) {
+ const YuvPlaneConversion plane = conversion.plane[i];
+
+ QVarLengthArray<EGLint, 17> attribs = {
+ EGL_WIDTH, dmabufBuffer->size().width() / plane.widthDivisor,
+ EGL_HEIGHT, dmabufBuffer->size().height() / plane.heightDivisor,
+ EGL_LINUX_DRM_FOURCC_EXT, plane.format,
+ EGL_DMA_BUF_PLANE0_FD_EXT, dmabufBuffer->plane(plane.planeIndex).fd,
+ EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGLint(dmabufBuffer->plane(plane.planeIndex).offset),
+ EGL_DMA_BUF_PLANE0_PITCH_EXT, EGLint(dmabufBuffer->plane(plane.planeIndex).stride),
+ EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, EGLint(dmabufBuffer->plane(plane.planeIndex).modifiers & 0xffffffff),
+ EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, EGLint(dmabufBuffer->plane(plane.planeIndex).modifiers >> 32),
+ EGL_NONE
+ };
+
+ // note: EGLImageKHR does NOT take ownership of the file descriptors
+ EGLImageKHR image = egl_create_image(m_eglDisplay,
+ EGL_NO_CONTEXT,
+ EGL_LINUX_DMA_BUF_EXT,
+ (EGLClientBuffer) nullptr,
+ attribs.constData());
+
+ if (image == EGL_NO_IMAGE_KHR) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "failed to create EGL image for plane" << i;
+ success = false;
+ }
+
+ dmabufBuffer->initImage(i, image);
+ }
+ return success;
+}
+
+LinuxDmabufClientBufferIntegration::LinuxDmabufClientBufferIntegration()
+{
+ m_yuvFormats.insert(DRM_FORMAT_YUYV,
+ YuvFormatConversion {
+ .inputPlanes = 1,
+ .outputPlanes = 2,
+ {{
+ .format = DRM_FORMAT_GR88,
+ .widthDivisor = 1,
+ .heightDivisor = 1,
+ .planeIndex = 0
+ }, {
+ .format = DRM_FORMAT_ARGB8888,
+ .widthDivisor = 2,
+ .heightDivisor = 1,
+ .planeIndex = 0
+ }}
+ });
+}
+
+LinuxDmabufClientBufferIntegration::~LinuxDmabufClientBufferIntegration()
+{
+ m_importedBuffers.clear();
+}
+
+void LinuxDmabufClientBufferIntegration::initializeHardware(struct ::wl_display *display)
+{
+ m_linuxDmabuf.reset(new LinuxDmabuf(display, this));
+
+ const bool ignoreBindDisplay = !qgetenv("QT_WAYLAND_IGNORE_BIND_DISPLAY").isEmpty() && qgetenv("QT_WAYLAND_IGNORE_BIND_DISPLAY").toInt() != 0;
+
+ // initialize hardware extensions
+ egl_query_dmabuf_modifiers_ext = reinterpret_cast<PFNEGLQUERYDMABUFMODIFIERSEXTPROC>(eglGetProcAddress("eglQueryDmaBufModifiersEXT"));
+ egl_query_dmabuf_formats_ext = reinterpret_cast<PFNEGLQUERYDMABUFFORMATSEXTPROC>(eglGetProcAddress("eglQueryDmaBufFormatsEXT"));
+ if (!egl_query_dmabuf_modifiers_ext || !egl_query_dmabuf_formats_ext) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Failed to initialize EGL display. Could not find eglQueryDmaBufModifiersEXT and eglQueryDmaBufFormatsEXT.";
+ return;
+ }
+
+ egl_bind_wayland_display = reinterpret_cast<PFNEGLBINDWAYLANDDISPLAYWL>(eglGetProcAddress("eglBindWaylandDisplayWL"));
+ egl_unbind_wayland_display = reinterpret_cast<PFNEGLUNBINDWAYLANDDISPLAYWL>(eglGetProcAddress("eglUnbindWaylandDisplayWL"));
+ if ((!egl_bind_wayland_display || !egl_unbind_wayland_display) && !ignoreBindDisplay) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Failed to initialize EGL display. Could not find eglBindWaylandDisplayWL and eglUnbindWaylandDisplayWL.";
+ return;
+ }
+
+ egl_create_image = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"));
+ egl_destroy_image = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR"));
+ if (!egl_create_image || !egl_destroy_image) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Failed to initialize EGL display. Could not find eglCreateImageKHR and eglDestroyImageKHR.";
+ return;
+ }
+
+ // initialize EGL display
+ QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
+ if (!nativeInterface) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Failed to initialize EGL display. No native platform interface available.";
+ return;
+ }
+
+ m_eglDisplay = nativeInterface->nativeResourceForIntegration("EglDisplay");
+ if (!m_eglDisplay) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Failed to initialize EGL display. Could not get EglDisplay for window.";
+ return;
+ }
+
+ const char *extensionString = eglQueryString(m_eglDisplay, EGL_EXTENSIONS);
+ if (!extensionString || !strstr(extensionString, "EGL_EXT_image_dma_buf_import")) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Failed to initialize EGL display. There is no EGL_EXT_image_dma_buf_import extension.";
+ return;
+ }
+ if (strstr(extensionString, "EGL_EXT_image_dma_buf_import_modifiers"))
+ m_supportsDmabufModifiers = true;
+
+ if (egl_bind_wayland_display && egl_unbind_wayland_display) {
+ m_displayBound = egl_bind_wayland_display(m_eglDisplay, display);
+ if (!m_displayBound) {
+ if (ignoreBindDisplay) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Could not bind Wayland display. Ignoring.";
+ } else {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "Failed to initialize EGL display. Could not bind Wayland display.";
+ return;
+ }
+ }
+ }
+
+ // request and sent formats/modifiers only after egl_display is bound
+ QHash<uint32_t, QVector<uint64_t>> modifiers;
+ for (const auto &format : supportedDrmFormats()) {
+ modifiers[format] = supportedDrmModifiers(format);
+ }
+ m_linuxDmabuf->setSupportedModifiers(modifiers);
+}
+
+QVector<uint32_t> LinuxDmabufClientBufferIntegration::supportedDrmFormats()
+{
+ if (!egl_query_dmabuf_formats_ext)
+ return QVector<uint32_t>();
+
+ // request total number of formats
+ EGLint count = 0;
+ EGLBoolean success = egl_query_dmabuf_formats_ext(m_eglDisplay, 0, nullptr, &count);
+
+ if (success && count > 0) {
+ QVector<uint32_t> drmFormats(count);
+ if (egl_query_dmabuf_formats_ext(m_eglDisplay, count, (EGLint *) drmFormats.data(), &count))
+ return drmFormats;
+ }
+
+ return QVector<uint32_t>();
+}
+
+QVector<uint64_t> LinuxDmabufClientBufferIntegration::supportedDrmModifiers(uint32_t format)
+{
+ if (!egl_query_dmabuf_modifiers_ext)
+ return QVector<uint64_t>();
+
+ // request total number of formats
+ EGLint count = 0;
+ EGLBoolean success = egl_query_dmabuf_modifiers_ext(m_eglDisplay, format, 0, nullptr, nullptr, &count);
+
+ if (success && count > 0) {
+ QVector<uint64_t> modifiers(count);
+ if (egl_query_dmabuf_modifiers_ext(m_eglDisplay, format, count, modifiers.data(), nullptr, &count)) {
+ return modifiers;
+ }
+ }
+
+ return QVector<uint64_t>();
+}
+
+void LinuxDmabufClientBufferIntegration::deleteOrphanedTextures()
+{
+ Q_ASSERT(QOpenGLContext::currentContext());
+ qDeleteAll(m_orphanedTextures);
+ m_orphanedTextures.clear();
+}
+
+void LinuxDmabufClientBufferIntegration::deleteImage(EGLImageKHR image)
+{
+ egl_destroy_image(m_eglDisplay, image);
+}
+
+QtWayland::ClientBuffer *LinuxDmabufClientBufferIntegration::createBufferFor(wl_resource *resource)
+{
+ // fallback for shared memory buffers
+ if (wl_shm_buffer_get(resource))
+ return nullptr;
+
+ auto it = m_importedBuffers.find(resource);
+ if (it != m_importedBuffers.end()) {
+ m_importedBuffers.value(resource);
+ return new LinuxDmabufClientBuffer(this, it.value()->resource()->handle, m_importedBuffers.value(resource));
+ }
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "could not create client buffer for dmabuf buffer";
+ return nullptr;
+}
+
+bool LinuxDmabufClientBufferIntegration::importBuffer(wl_resource *resource, LinuxDmabufWlBuffer *linuxDmabufBuffer)
+{
+ if (m_importedBuffers.contains(resource)) {
+ qCWarning(qLcWaylandCompositorHardwareIntegration) << "buffer has already been added";
+ return false;
+ }
+ m_importedBuffers[resource] = linuxDmabufBuffer;
+ if (m_yuvFormats.contains(linuxDmabufBuffer->drmFormat()))
+ return initYuvTexture(linuxDmabufBuffer);
+ else
+ return initSimpleTexture(linuxDmabufBuffer);
+}
+
+void LinuxDmabufClientBufferIntegration::removeBuffer(wl_resource *resource)
+{
+ m_importedBuffers.remove(resource);
+}
+
+LinuxDmabufClientBuffer::LinuxDmabufClientBuffer(LinuxDmabufClientBufferIntegration *integration,
+ wl_resource *bufferResource,
+ LinuxDmabufWlBuffer *dmabufBuffer)
+ : ClientBuffer(bufferResource)
+ , m_integration(integration)
+{
+ d = dmabufBuffer;
+}
+
+QOpenGLTexture *LinuxDmabufClientBuffer::toOpenGlTexture(int plane)
+{
+ // At this point we should have a valid OpenGL context, so it's safe to destroy textures
+ m_integration->deleteOrphanedTextures();
+
+ if (!m_buffer)
+ return nullptr;
+
+ QOpenGLTexture *texture = d->texture(plane);
+
+ const auto target = static_cast<QOpenGLTexture::Target>(GL_TEXTURE_2D);
+
+ if (!texture) {
+ texture = new QOpenGLTexture(target);
+ texture->setFormat(openGLFormatFromBufferFormat(formatFromDrmFormat(d->drmFormat())));
+ texture->setSize(d->size().width(), d->size().height());
+ texture->create();
+ d->initTexture(plane, texture);
+ }
+
+ if (m_textureDirty) {
+ texture->bind();
+ glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ m_integration->gl_egl_image_target_texture_2d(target, d->image(plane));
+ }
+ return texture;
+}
+
+void LinuxDmabufClientBuffer::setDestroyed()
+{
+ m_integration->removeBuffer(m_buffer);
+ ClientBuffer::setDestroyed();
+}
+
+LinuxDmabufClientBuffer::~LinuxDmabufClientBuffer()
+{
+ // resources are deleted by buffer_destroy_resource
+ m_buffer = nullptr;
+ d = nullptr;
+}
+
+QWaylandBufferRef::BufferFormatEgl LinuxDmabufClientBuffer::bufferFormatEgl() const
+{
+ return formatFromDrmFormat(d->drmFormat());
+}
+
+QSize LinuxDmabufClientBuffer::size() const
+{
+ return d->size();
+}
+
+QWaylandSurface::Origin LinuxDmabufClientBuffer::origin() const
+{
+ return (d->flags() & QtWaylandServer::zwp_linux_buffer_params_v1::flags_y_invert) ? QWaylandSurface::OriginBottomLeft : QWaylandSurface::OriginTopLeft;
+}
+
+QT_END_NAMESPACE
diff --git a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.h b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.h
new file mode 100644
index 000000000..914c1e7a6
--- /dev/null
+++ b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef LINUXDMABUFCLIENTBUFFERINTEGRATION_H
+#define LINUXDMABUFCLIENTBUFFERINTEGRATION_H
+
+#include "linuxdmabuf.h"
+
+#include <QtWaylandCompositor/private/qwlclientbufferintegration_p.h>
+#include <QtWaylandCompositor/private/qwlclientbuffer_p.h>
+#include <QtWaylandCompositor/private/qwayland-server-wayland.h>
+
+#include <drm_fourcc.h>
+
+QT_BEGIN_NAMESPACE
+
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL_compat) (EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFFORMATSEXTPROC) (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFMODIFIERSEXTPROC) (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers);
+
+class LinuxDmabufClientBufferIntegrationPrivate;
+class LinuxDmabufParams;
+class LinuxDmabufClientBuffer;
+
+// buffer conversion definitions to import YUV buffers
+struct YuvPlaneConversion {
+ EGLint format = DRM_FORMAT_YUYV;
+ EGLint widthDivisor = 1;
+ EGLint heightDivisor = 1;
+ EGLint planeIndex = 0;
+};
+struct YuvFormatConversion {
+ uint32_t inputPlanes = 1;
+ uint32_t outputPlanes = 1;
+ struct YuvPlaneConversion plane[LinuxDmabufWlBuffer::MaxDmabufPlanes];
+};
+
+class LinuxDmabufClientBufferIntegration : public QtWayland::ClientBufferIntegration
+{
+public:
+ LinuxDmabufClientBufferIntegration();
+ ~LinuxDmabufClientBufferIntegration() override;
+
+ void initializeHardware(struct ::wl_display *display) override;
+ QtWayland::ClientBuffer *createBufferFor(wl_resource *resource) override;
+ bool importBuffer(wl_resource *resource, LinuxDmabufWlBuffer *linuxDmabufBuffer);
+ void removeBuffer(wl_resource *resource);
+ void deleteOrphanedTextures();
+ void deleteImage(EGLImageKHR image);
+ void deleteGLTextureWhenPossible(QOpenGLTexture *texture) { m_orphanedTextures << texture; }
+ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC gl_egl_image_target_texture_2d = nullptr;
+
+private:
+ Q_DISABLE_COPY(LinuxDmabufClientBufferIntegration)
+
+ PFNEGLBINDWAYLANDDISPLAYWL egl_bind_wayland_display = nullptr;
+ PFNEGLUNBINDWAYLANDDISPLAYWL egl_unbind_wayland_display = nullptr;
+ PFNEGLCREATEIMAGEKHRPROC egl_create_image = nullptr;
+ PFNEGLDESTROYIMAGEKHRPROC egl_destroy_image = nullptr;
+ PFNEGLQUERYDMABUFMODIFIERSEXTPROC egl_query_dmabuf_modifiers_ext = nullptr;
+ PFNEGLQUERYDMABUFFORMATSEXTPROC egl_query_dmabuf_formats_ext = nullptr;
+
+ bool initSimpleTexture(LinuxDmabufWlBuffer *dmabufBuffer);
+ bool initYuvTexture(LinuxDmabufWlBuffer *dmabufBuffer);
+ QVector<uint32_t> supportedDrmFormats();
+ QVector<uint64_t> supportedDrmModifiers(uint32_t format);
+
+ EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
+ bool m_displayBound = false;
+ QVector<QOpenGLTexture *> m_orphanedTextures;
+ QHash<EGLint, YuvFormatConversion> m_yuvFormats;
+ bool m_supportsDmabufModifiers = false;
+ QHash<struct ::wl_resource *, LinuxDmabufWlBuffer *> m_importedBuffers;
+ QScopedPointer<LinuxDmabuf> m_linuxDmabuf;
+};
+
+class LinuxDmabufClientBuffer : public QtWayland::ClientBuffer
+{
+public:
+ ~LinuxDmabufClientBuffer() override;
+
+ QWaylandBufferRef::BufferFormatEgl bufferFormatEgl() const override;
+ QSize size() const override;
+ QWaylandSurface::Origin origin() const override;
+ QOpenGLTexture *toOpenGlTexture(int plane) override;
+
+protected:
+ void setDestroyed() override;
+
+private:
+ friend class LinuxDmabufClientBufferIntegration;
+ friend class LinuxDmabufClientBufferIntegrationPrivate;
+
+ LinuxDmabufClientBuffer(LinuxDmabufClientBufferIntegration* integration, wl_resource *bufferResource, LinuxDmabufWlBuffer *dmabufBuffer);
+
+ LinuxDmabufWlBuffer *d = nullptr;
+ LinuxDmabufClientBufferIntegration *m_integration = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // LINUXDMABUFCLIENTBUFFERINTEGRATION_H
diff --git a/src/hardwareintegration/compositor/xcomposite_share/xcompositebuffer.h b/src/hardwareintegration/compositor/xcomposite_share/xcompositebuffer.h
index b3f1cf3a9..73a66d3af 100644
--- a/src/hardwareintegration/compositor/xcomposite_share/xcompositebuffer.h
+++ b/src/hardwareintegration/compositor/xcomposite_share/xcompositebuffer.h
@@ -41,6 +41,9 @@
#define XCOMPOSITEBUFFER_H
#include <qwayland-server-wayland.h>
+
+#include <QtWaylandCompositor/private/qwaylandutils_p.h>
+
#include <QtWaylandCompositor/QWaylandSurface>
#include <QtWaylandCompositor/QWaylandCompositor>
@@ -68,7 +71,7 @@ public:
QSize size() const { return mSize; }
- static XCompositeBuffer *fromResource(struct ::wl_resource *resource) { return static_cast<XCompositeBuffer*>(Resource::fromResource(resource)->buffer_object); }
+ static XCompositeBuffer *fromResource(struct ::wl_resource *resource) { return QtWayland::fromResource<XCompositeBuffer *>(resource); }
protected:
void buffer_destroy_resource(Resource *) override;
diff --git a/src/hardwareintegration/compositor/xcomposite_share/xcompositehandler.h b/src/hardwareintegration/compositor/xcomposite_share/xcompositehandler.h
index bb43ed1af..28168994c 100644
--- a/src/hardwareintegration/compositor/xcomposite_share/xcompositehandler.h
+++ b/src/hardwareintegration/compositor/xcomposite_share/xcompositehandler.h
@@ -45,7 +45,7 @@
#include "xlibinclude.h"
#include "qwayland-server-xcomposite.h"
-#include <wayland-server.h>
+#include <wayland-server-core.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/decorations/bradient/main.cpp b/src/plugins/decorations/bradient/main.cpp
index 3fa723446..83dc8604b 100644
--- a/src/plugins/decorations/bradient/main.cpp
+++ b/src/plugins/decorations/bradient/main.cpp
@@ -315,19 +315,19 @@ void QWaylandBradientDecoration::processMouseTop(QWaylandInputDevice *inputDevic
#if QT_CONFIG(cursor)
waylandWindow()->setMouseCursor(inputDevice, Qt::SizeFDiagCursor);
#endif
- startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_TOP_LEFT,b);
+ startResize(inputDevice, Qt::TopEdge | Qt::LeftEdge, b);
} else if (local.x() > window()->width() + margins().left()) {
//top right bit
#if QT_CONFIG(cursor)
waylandWindow()->setMouseCursor(inputDevice, Qt::SizeBDiagCursor);
#endif
- startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_TOP_RIGHT,b);
+ startResize(inputDevice, Qt::TopEdge | Qt::RightEdge, b);
} else {
//top resize bit
#if QT_CONFIG(cursor)
waylandWindow()->setMouseCursor(inputDevice, Qt::SplitVCursor);
#endif
- startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_TOP,b);
+ startResize(inputDevice, Qt::TopEdge, b);
}
} else if (local.x() <= margins().left()) {
processMouseLeft(inputDevice, local, b, mods);
@@ -358,19 +358,19 @@ void QWaylandBradientDecoration::processMouseBottom(QWaylandInputDevice *inputDe
#if QT_CONFIG(cursor)
waylandWindow()->setMouseCursor(inputDevice, Qt::SizeBDiagCursor);
#endif
- startResize(inputDevice, WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT,b);
+ startResize(inputDevice, Qt::BottomEdge | Qt::LeftEdge, b);
} else if (local.x() > window()->width() + margins().left()) {
//bottom right bit
#if QT_CONFIG(cursor)
waylandWindow()->setMouseCursor(inputDevice, Qt::SizeFDiagCursor);
#endif
- startResize(inputDevice, WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT,b);
+ startResize(inputDevice, Qt::BottomEdge | Qt::RightEdge, b);
} else {
//bottom bit
#if QT_CONFIG(cursor)
waylandWindow()->setMouseCursor(inputDevice, Qt::SplitVCursor);
#endif
- startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_BOTTOM,b);
+ startResize(inputDevice, Qt::BottomEdge, b);
}
}
@@ -381,7 +381,7 @@ void QWaylandBradientDecoration::processMouseLeft(QWaylandInputDevice *inputDevi
#if QT_CONFIG(cursor)
waylandWindow()->setMouseCursor(inputDevice, Qt::SplitHCursor);
#endif
- startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_LEFT,b);
+ startResize(inputDevice, Qt::LeftEdge, b);
}
void QWaylandBradientDecoration::processMouseRight(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
@@ -391,7 +391,7 @@ void QWaylandBradientDecoration::processMouseRight(QWaylandInputDevice *inputDev
#if QT_CONFIG(cursor)
waylandWindow()->setMouseCursor(inputDevice, Qt::SplitHCursor);
#endif
- startResize(inputDevice, WL_SHELL_SURFACE_RESIZE_RIGHT,b);
+ startResize(inputDevice, Qt::RightEdge, b);
}
class QWaylandBradientDecorationPlugin : public QWaylandDecorationPlugin
diff --git a/src/plugins/hardwareintegration/compositor/compositor.pro b/src/plugins/hardwareintegration/compositor/compositor.pro
index cd47b2676..94e0f8bf1 100644
--- a/src/plugins/hardwareintegration/compositor/compositor.pro
+++ b/src/plugins/hardwareintegration/compositor/compositor.pro
@@ -1,6 +1,8 @@
TEMPLATE = subdirs
QT_FOR_CONFIG += waylandcompositor-private
+qtConfig(wayland-dmabuf-client-buffer): \
+ SUBDIRS += linux-dmabuf-unstable-v1
qtConfig(wayland-egl): \
SUBDIRS += wayland-egl
qtConfig(wayland-brcm): \
diff --git a/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.json b/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.json
new file mode 100644
index 000000000..1fab86fef
--- /dev/null
+++ b/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "linux-dmabuf-unstable-v1" ]
+}
diff --git a/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pro b/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pro
new file mode 100644
index 000000000..bc4311423
--- /dev/null
+++ b/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pro
@@ -0,0 +1,12 @@
+QT = waylandcompositor waylandcompositor-private core-private gui-private
+
+OTHER_FILES += linux-dmabuf.json
+
+SOURCES += \
+ main.cpp \
+
+include(../../../../hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pri)
+
+PLUGIN_TYPE = wayland-graphics-integration-server
+PLUGIN_CLASS_NAME = QWaylandDmabufClientBufferIntegrationPlugin
+load(qt_plugin)
diff --git a/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/main.cpp b/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/main.cpp
new file mode 100644
index 000000000..d16268a2c
--- /dev/null
+++ b/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/main.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWaylandCompositor/private/qwlclientbufferintegrationfactory_p.h>
+#include <QtWaylandCompositor/private/qwlclientbufferintegrationplugin_p.h>
+#include "linuxdmabufclientbufferintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandDmabufClientBufferIntegrationPlugin : public QtWayland::ClientBufferIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QtWaylandClientBufferIntegrationFactoryInterface_iid FILE "linux-dmabuf-unstable-v1.json")
+public:
+ QtWayland::ClientBufferIntegration *create(const QString& key, const QStringList& paramList) override;
+};
+
+QtWayland::ClientBufferIntegration *QWaylandDmabufClientBufferIntegrationPlugin::create(const QString& key, const QStringList& paramList)
+{
+ Q_UNUSED(paramList);
+ Q_UNUSED(key);
+ return new LinuxDmabufClientBufferIntegration();
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/shellintegration/fullscreen-shell-v1/fullscreen-shell-v1.json b/src/plugins/shellintegration/fullscreen-shell-v1/fullscreen-shell-v1.json
new file mode 100644
index 000000000..f32637bcc
--- /dev/null
+++ b/src/plugins/shellintegration/fullscreen-shell-v1/fullscreen-shell-v1.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "fullscreen-shell-v1" ]
+}
diff --git a/src/plugins/shellintegration/fullscreen-shell-v1/fullscreen-shell-v1.pro b/src/plugins/shellintegration/fullscreen-shell-v1/fullscreen-shell-v1.pro
new file mode 100644
index 000000000..a522f87a8
--- /dev/null
+++ b/src/plugins/shellintegration/fullscreen-shell-v1/fullscreen-shell-v1.pro
@@ -0,0 +1,23 @@
+QT += gui-private waylandclient-private
+CONFIG += wayland-scanner
+
+QMAKE_USE += wayland-client
+
+WAYLANDCLIENTSOURCES += \
+ ../../../3rdparty/protocol/fullscreen-shell-unstable-v1.xml
+
+HEADERS += \
+ qwaylandfullscreenshellv1integration.h \
+ qwaylandfullscreenshellv1surface.h
+
+SOURCES += \
+ main.cpp \
+ qwaylandfullscreenshellv1integration.cpp \
+ qwaylandfullscreenshellv1surface.cpp
+
+OTHER_FILES += \
+ fullscreen-shell-v1.json
+
+PLUGIN_TYPE = wayland-shell-integration
+PLUGIN_CLASS_NAME = QWaylandFullScreenShellV1IntegrationPlugin
+load(qt_plugin)
diff --git a/src/plugins/shellintegration/fullscreen-shell-v1/main.cpp b/src/plugins/shellintegration/fullscreen-shell-v1/main.cpp
new file mode 100644
index 000000000..dfcd997da
--- /dev/null
+++ b/src/plugins/shellintegration/fullscreen-shell-v1/main.cpp
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWaylandClient/private/qwaylandshellintegrationplugin_p.h>
+
+#include "qwaylandfullscreenshellv1integration.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+class QWaylandFullScreenShellV1IntegrationPlugin : public QWaylandShellIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QWaylandShellIntegrationFactoryInterface_iid FILE "fullscreen-shell-v1.json")
+public:
+ QWaylandShellIntegration *create(const QString &key, const QStringList &paramList) override;
+};
+
+QWaylandShellIntegration *QWaylandFullScreenShellV1IntegrationPlugin::create(const QString &key, const QStringList &paramList)
+{
+ Q_UNUSED(paramList);
+
+ if (key == QLatin1String("fullscreen-shell-v1"))
+ return new QWaylandFullScreenShellV1Integration();
+ return nullptr;
+}
+
+} // namespace QtWaylandClient
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.cpp b/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.cpp
new file mode 100644
index 000000000..0cd2cb1e8
--- /dev/null
+++ b/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwaylandfullscreenshellv1integration.h"
+#include "qwaylandfullscreenshellv1surface.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+bool QWaylandFullScreenShellV1Integration::initialize(QWaylandDisplay *display)
+{
+ for (const QWaylandDisplay::RegistryGlobal &global : display->globals()) {
+ if (global.interface == QLatin1String("zwp_fullscreen_shell_v1") && !m_shell) {
+ m_shell.reset(new QtWayland::zwp_fullscreen_shell_v1(display->wl_registry(), global.id, global.version));
+ break;
+ }
+ }
+
+ if (!m_shell) {
+ qCDebug(lcQpaWayland) << "Couldn't find global zwp_fullscreen_shell_v1 for fullscreen-shell";
+ return false;
+ }
+
+ return QWaylandShellIntegration::initialize(display);
+}
+
+QWaylandShellSurface *QWaylandFullScreenShellV1Integration::createShellSurface(QWaylandWindow *window)
+{
+ return new QWaylandFullScreenShellV1Surface(m_shell.data(), window);
+}
+
+} // namespace QtWaylandClient
+
+QT_END_NAMESPACE
diff --git a/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.h b/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.h
new file mode 100644
index 000000000..131f9e720
--- /dev/null
+++ b/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDFULLSCREENSHELLV1INTEGRATION_H
+#define QWAYLANDFULLSCREENSHELLV1INTEGRATION_H
+
+#include <wayland-client.h>
+#include <QtWaylandClient/private/qwayland-wayland.h>
+#include <QtWaylandClient/private/qwaylandshellintegration_p.h>
+
+#include "qwayland-fullscreen-shell-unstable-v1.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+class Q_WAYLAND_CLIENT_EXPORT QWaylandFullScreenShellV1Integration : public QWaylandShellIntegration
+{
+public:
+ bool initialize(QWaylandDisplay *display) override;
+ QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
+
+private:
+ QScopedPointer<QtWayland::zwp_fullscreen_shell_v1> m_shell;
+};
+
+} // namespace QtWaylandClient
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDFULLSCREENSHELLV1INTEGRATION_H
diff --git a/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.cpp b/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.cpp
new file mode 100644
index 000000000..9a829f6e9
--- /dev/null
+++ b/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWaylandClient/private/qwaylandscreen_p.h>
+
+#include "qwaylandfullscreenshellv1surface.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+QWaylandFullScreenShellV1Surface::QWaylandFullScreenShellV1Surface(QtWayland::zwp_fullscreen_shell_v1 *shell, QWaylandWindow *window)
+ : QWaylandShellSurface(window)
+ , m_shell(shell)
+ , m_window(window)
+{
+ auto screen = static_cast<QWaylandScreen *>(m_window->screen());
+ m_shell->present_surface(m_window->object(),
+ QtWayland::zwp_fullscreen_shell_v1::present_method_default,
+ screen->output());
+}
+
+} // namespace QtWaylandClient
+
+QT_END_NAMESPACE
diff --git a/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.h b/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.h
new file mode 100644
index 000000000..718e1e861
--- /dev/null
+++ b/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDFULLSCREENSHELLV1SURFACE_H
+#define QWAYLANDFULLSCREENSHELLV1SURFACE_H
+
+#include <QtWaylandClient/qtwaylandclientglobal.h>
+#include <QtWaylandClient/private/qwaylandshellsurface_p.h>
+#include <QtWaylandClient/private/qwaylandwindow_p.h>
+
+#include "qwayland-fullscreen-shell-unstable-v1.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+class Q_WAYLAND_CLIENT_EXPORT QWaylandFullScreenShellV1Surface : public QWaylandShellSurface
+{
+public:
+ QWaylandFullScreenShellV1Surface(QtWayland::zwp_fullscreen_shell_v1 *shell, QWaylandWindow *window);
+
+private:
+ QtWayland::zwp_fullscreen_shell_v1 *m_shell = nullptr;
+ QWaylandWindow *m_window = nullptr;
+};
+
+} // namespace QtWaylandClient
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDFULLSCREENSHELLV1SURFACE_H
diff --git a/src/plugins/shellintegration/shellintegration.pro b/src/plugins/shellintegration/shellintegration.pro
index 48b6efa36..39c57940a 100644
--- a/src/plugins/shellintegration/shellintegration.pro
+++ b/src/plugins/shellintegration/shellintegration.pro
@@ -1,9 +1,9 @@
TEMPLATE = subdirs
+QT_FOR_CONFIG += waylandclient-private
-SUBDIRS += \
- ivi-shell \
- xdg-shell \
- xdg-shell-v5 \
- xdg-shell-v6 \
- wl-shell \
-
+qtConfig(wayland-client-fullscreen-shell-v1): SUBDIRS += fullscreen-shell-v1
+qtConfig(wayland-client-ivi-shell): SUBDIRS += ivi-shell
+qtConfig(wayland-client-wl-shell): SUBDIRS += wl-shell
+qtConfig(wayland-client-xdg-shell): SUBDIRS += xdg-shell
+qtConfig(wayland-client-xdg-shell-v5): SUBDIRS += xdg-shell-v5
+qtConfig(wayland-client-xdg-shell-v6): SUBDIRS += xdg-shell-v6
diff --git a/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration_p.h b/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration_p.h
index 80a7507d4..3d76cc310 100644
--- a/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration_p.h
+++ b/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration_p.h
@@ -51,7 +51,6 @@
// We mean it.
//
-#include <wayland-client.h>
#include <private/qwayland-wayland.h>
#include <QtWaylandClient/private/qwaylandshellintegration_p.h>
diff --git a/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp b/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp
index 88a63655c..4506c312a 100644
--- a/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp
+++ b/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp
@@ -76,11 +76,10 @@ QWaylandWlShellSurface::~QWaylandWlShellSurface()
delete m_extendedWindow;
}
-void QWaylandWlShellSurface::resize(QWaylandInputDevice *inputDevice, enum wl_shell_surface_resize edges)
+void QWaylandWlShellSurface::resize(QWaylandInputDevice *inputDevice, Qt::Edges edges)
{
- resize(inputDevice->wl_seat(),
- inputDevice->serial(),
- edges);
+ enum resize resizeEdges = convertToResizeEdges(edges);
+ resize(inputDevice->wl_seat(), inputDevice->serial(), resizeEdges);
}
bool QWaylandWlShellSurface::move(QWaylandInputDevice *inputDevice)
@@ -193,6 +192,14 @@ void QWaylandWlShellSurface::requestWindowStates(Qt::WindowStates states)
m_pending.states = states & ~Qt::WindowMinimized;
}
+enum QWaylandWlShellSurface::resize QWaylandWlShellSurface::convertToResizeEdges(Qt::Edges edges)
+{
+ return static_cast<enum resize>(
+ ((edges & Qt::TopEdge) ? resize_top : 0)
+ | ((edges & Qt::BottomEdge) ? resize_bottom : 0)
+ | ((edges & Qt::LeftEdge) ? resize_left : 0)
+ | ((edges & Qt::RightEdge) ? resize_right : 0));
+}
void QWaylandWlShellSurface::setTopLevel()
{
diff --git a/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface_p.h b/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface_p.h
index 57e06525a..324c10aac 100644
--- a/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface_p.h
+++ b/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface_p.h
@@ -53,8 +53,6 @@
#include <QtCore/QSize>
-#include <wayland-client.h>
-
#include <QtWaylandClient/qtwaylandclientglobal.h>
#include <QtWaylandClient/private/qwayland-wayland.h>
#include <QtWaylandClient/private/qwaylandshellsurface_p.h>
@@ -78,7 +76,7 @@ public:
~QWaylandWlShellSurface() override;
using QtWayland::wl_shell_surface::resize;
- void resize(QWaylandInputDevice *inputDevice, enum wl_shell_surface_resize edges) override;
+ void resize(QWaylandInputDevice *inputDevice, Qt::Edges edges) override;
using QtWayland::wl_shell_surface::move;
bool move(QWaylandInputDevice *inputDevice) override;
@@ -99,6 +97,7 @@ protected:
void requestWindowStates(Qt::WindowStates states) override;
private:
+ static enum resize convertToResizeEdges(Qt::Edges edges);
void setTopLevel();
void updateTransientParent(QWindow *parent);
void setPopup(QWaylandWindow *parent, QWaylandInputDevice *device, uint serial);
diff --git a/src/plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/qwayland-xdg-shell-unstable-v5.cpp b/src/plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/qwayland-xdg-shell-unstable-v5.cpp
index 0115eb1da..51979acf7 100644
--- a/src/plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/qwayland-xdg-shell-unstable-v5.cpp
+++ b/src/plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/qwayland-xdg-shell-unstable-v5.cpp
@@ -25,6 +25,7 @@
* DEALINGS IN THE SOFTWARE.
*/
#include "qwayland-xdg-shell-unstable-v5_p.h"
+#include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
QT_BEGIN_NAMESPACE
QT_WARNING_PUSH
diff --git a/src/plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/qwayland-xdg-shell-unstable-v5_p.h b/src/plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/qwayland-xdg-shell-unstable-v5_p.h
index 3d8a6c13d..8fb1ea7b8 100644
--- a/src/plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/qwayland-xdg-shell-unstable-v5_p.h
+++ b/src/plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/qwayland-xdg-shell-unstable-v5_p.h
@@ -31,6 +31,8 @@
#include <QByteArray>
#include <QString>
+struct wl_registry;
+
QT_BEGIN_NAMESPACE
QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Wmissing-field-initializers")
diff --git a/src/plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/wayland-xdg-shell-unstable-v5-client-protocol_p.h b/src/plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/wayland-xdg-shell-unstable-v5-client-protocol_p.h
index 46644610b..8877e8830 100644
--- a/src/plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/wayland-xdg-shell-unstable-v5-client-protocol_p.h
+++ b/src/plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/wayland-xdg-shell-unstable-v5-client-protocol_p.h
@@ -7,7 +7,7 @@
#include <stdint.h>
#include <stddef.h>
-#include "wayland-client.h"
+#include "wayland-client-core.h"
#ifdef __cplusplus
extern "C" {
diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h
index ff8e5639f..7494f6a67 100644
--- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h
@@ -53,8 +53,6 @@
#include "qwayland-xdg-shell-unstable-v5_p.h"
-#include <wayland-client.h>
-
#include <QtWaylandClient/qtwaylandclientglobal.h>
#include <QtWaylandClient/private/qwaylandshellsurface_p.h>
diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5_p.h b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5_p.h
index 67e5d32a7..2b0a59f17 100644
--- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5_p.h
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5_p.h
@@ -56,8 +56,6 @@
#include <QtCore/QSize>
#include <QtCore/QVector>
-#include <wayland-client.h>
-
#include <QtWaylandClient/qtwaylandclientglobal.h>
#include <QtWaylandClient/private/qwaylandshellsurface_p.h>
diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp
index 61a865cb2..b691ee747 100644
--- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp
@@ -73,18 +73,19 @@ QWaylandXdgSurfaceV5::~QWaylandXdgSurfaceV5()
delete m_extendedWindow;
}
-void QWaylandXdgSurfaceV5::resize(QWaylandInputDevice *inputDevice, enum wl_shell_surface_resize edges)
+QtWayland::xdg_surface_v5::resize_edge QWaylandXdgSurfaceV5::convertToResizeEdges(Qt::Edges edges)
{
- // May need some conversion if types get incompatibles, ATM they're identical
- enum resize_edge const * const arg = reinterpret_cast<enum resize_edge const *>(&edges);
- resize(inputDevice, *arg);
+ return static_cast<enum resize_edge>(
+ ((edges & Qt::TopEdge) ? resize_edge_top : 0)
+ | ((edges & Qt::BottomEdge) ? resize_edge_bottom : 0)
+ | ((edges & Qt::LeftEdge) ? resize_edge_left : 0)
+ | ((edges & Qt::RightEdge) ? resize_edge_right : 0));
}
-void QWaylandXdgSurfaceV5::resize(QWaylandInputDevice *inputDevice, enum resize_edge edges)
+void QWaylandXdgSurfaceV5::resize(QWaylandInputDevice *inputDevice, Qt::Edges edges)
{
- resize(inputDevice->wl_seat(),
- inputDevice->serial(),
- edges);
+ resize_edge resizeEdges = convertToResizeEdges(edges);
+ resize(inputDevice->wl_seat(), inputDevice->serial(), resizeEdges);
}
bool QWaylandXdgSurfaceV5::move(QWaylandInputDevice *inputDevice)
diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5_p.h b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5_p.h
index b938047ec..231a56d84 100644
--- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5_p.h
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5_p.h
@@ -59,8 +59,6 @@
#include <QtCore/QSize>
#include <QtCore/QMargins>
-#include <wayland-client.h>
-
QT_BEGIN_NAMESPACE
class QWindow;
@@ -81,9 +79,8 @@ public:
~QWaylandXdgSurfaceV5() override;
using QtWayland::xdg_surface_v5::resize;
- void resize(QWaylandInputDevice *inputDevice, enum resize_edge edges);
-
- void resize(QWaylandInputDevice *inputDevice, enum wl_shell_surface_resize edges) override;
+ static resize_edge convertToResizeEdges(Qt::Edges edges);
+ void resize(QWaylandInputDevice *inputDevice, Qt::Edges edges) override;
using QtWayland::xdg_surface_v5::move;
bool move(QWaylandInputDevice *inputDevice) override;
diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp
index 9e55e3e16..e12573ad0 100644
--- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp
+++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp
@@ -157,6 +157,15 @@ void QWaylandXdgSurfaceV6::Toplevel::requestWindowStates(Qt::WindowStates states
}
}
+QtWayland::zxdg_toplevel_v6::resize_edge QWaylandXdgSurfaceV6::Toplevel::convertToResizeEdges(Qt::Edges edges)
+{
+ return static_cast<enum resize_edge>(
+ ((edges & Qt::TopEdge) ? resize_edge_top : 0)
+ | ((edges & Qt::BottomEdge) ? resize_edge_bottom : 0)
+ | ((edges & Qt::LeftEdge) ? resize_edge_left : 0)
+ | ((edges & Qt::RightEdge) ? resize_edge_right : 0));
+}
+
QWaylandXdgSurfaceV6::Popup::Popup(QWaylandXdgSurfaceV6 *xdgSurface, QWaylandXdgSurfaceV6 *parent,
QtWayland::zxdg_positioner_v6 *positioner)
: zxdg_popup_v6(xdgSurface->get_popup(parent->object(), positioner->object()))
@@ -226,19 +235,13 @@ QWaylandXdgSurfaceV6::~QWaylandXdgSurfaceV6()
destroy();
}
-void QWaylandXdgSurfaceV6::resize(QWaylandInputDevice *inputDevice, zxdg_toplevel_v6_resize_edge edges)
+void QWaylandXdgSurfaceV6::resize(QWaylandInputDevice *inputDevice, Qt::Edges edges)
{
Q_ASSERT(m_toplevel && m_toplevel->isInitialized());
- m_toplevel->resize(inputDevice->wl_seat(), inputDevice->serial(), edges);
+ auto resizeEdges = Toplevel::convertToResizeEdges(edges);
+ m_toplevel->resize(inputDevice->wl_seat(), inputDevice->serial(), resizeEdges);
}
-void QWaylandXdgSurfaceV6::resize(QWaylandInputDevice *inputDevice, enum wl_shell_surface_resize edges)
-{
- auto xdgEdges = reinterpret_cast<enum zxdg_toplevel_v6_resize_edge const *>(&edges);
- resize(inputDevice, *xdgEdges);
-}
-
-
bool QWaylandXdgSurfaceV6::move(QWaylandInputDevice *inputDevice)
{
if (m_toplevel && m_toplevel->isInitialized()) {
diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6_p.h b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6_p.h
index 659aad047..5a2867379 100644
--- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6_p.h
+++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6_p.h
@@ -60,8 +60,6 @@
#include <QtCore/QSize>
#include <QtGui/QRegion>
-#include <wayland-client.h>
-
QT_BEGIN_NAMESPACE
class QWindow;
@@ -79,8 +77,7 @@ public:
QWaylandXdgSurfaceV6(QWaylandXdgShellV6 *shell, ::zxdg_surface_v6 *surface, QWaylandWindow *window);
~QWaylandXdgSurfaceV6() override;
- void resize(QWaylandInputDevice *inputDevice, enum zxdg_toplevel_v6_resize_edge edges);
- void resize(QWaylandInputDevice *inputDevice, enum wl_shell_surface_resize edges) override;
+ void resize(QWaylandInputDevice *inputDevice, Qt::Edges edges) override;
bool move(QWaylandInputDevice *inputDevice) override;
void setTitle(const QString &title) override;
void setAppId(const QString &appId) override;
@@ -108,6 +105,9 @@ private:
void zxdg_toplevel_v6_close() override;
void requestWindowStates(Qt::WindowStates states);
+
+ static resize_edge convertToResizeEdges(Qt::Edges edges);
+
struct {
QSize size = {0, 0};
Qt::WindowStates states = Qt::WindowNoState;
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
index 1310e340d..8759cb8c9 100644
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
@@ -185,6 +185,15 @@ void QWaylandXdgSurface::Toplevel::requestWindowStates(Qt::WindowStates states)
}
}
+QtWayland::xdg_toplevel::resize_edge QWaylandXdgSurface::Toplevel::convertToResizeEdges(Qt::Edges edges)
+{
+ return static_cast<enum resize_edge>(
+ ((edges & Qt::TopEdge) ? resize_edge_top : 0)
+ | ((edges & Qt::BottomEdge) ? resize_edge_bottom : 0)
+ | ((edges & Qt::LeftEdge) ? resize_edge_left : 0)
+ | ((edges & Qt::RightEdge) ? resize_edge_right : 0));
+}
+
QWaylandXdgSurface::Popup::Popup(QWaylandXdgSurface *xdgSurface, QWaylandXdgSurface *parent,
QtWayland::xdg_positioner *positioner)
: xdg_popup(xdgSurface->get_popup(parent->object(), positioner->object()))
@@ -254,19 +263,13 @@ QWaylandXdgSurface::~QWaylandXdgSurface()
destroy();
}
-void QWaylandXdgSurface::resize(QWaylandInputDevice *inputDevice, xdg_toplevel_resize_edge edges)
+void QWaylandXdgSurface::resize(QWaylandInputDevice *inputDevice, Qt::Edges edges)
{
Q_ASSERT(m_toplevel && m_toplevel->isInitialized());
- m_toplevel->resize(inputDevice->wl_seat(), inputDevice->serial(), edges);
+ auto resizeEdges = Toplevel::convertToResizeEdges(edges);
+ m_toplevel->resize(inputDevice->wl_seat(), inputDevice->serial(), resizeEdges);
}
-void QWaylandXdgSurface::resize(QWaylandInputDevice *inputDevice, enum wl_shell_surface_resize edges)
-{
- auto xdgEdges = reinterpret_cast<enum xdg_toplevel_resize_edge const *>(&edges);
- resize(inputDevice, *xdgEdges);
-}
-
-
bool QWaylandXdgSurface::move(QWaylandInputDevice *inputDevice)
{
if (m_toplevel && m_toplevel->isInitialized()) {
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
index 741b83cfd..1dc1def23 100644
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
@@ -62,8 +62,6 @@
#include <QtCore/QSize>
#include <QtGui/QRegion>
-#include <wayland-client.h>
-
QT_BEGIN_NAMESPACE
class QWindow;
@@ -82,8 +80,7 @@ public:
QWaylandXdgSurface(QWaylandXdgShell *shell, ::xdg_surface *surface, QWaylandWindow *window);
~QWaylandXdgSurface() override;
- void resize(QWaylandInputDevice *inputDevice, enum xdg_toplevel_resize_edge edges);
- void resize(QWaylandInputDevice *inputDevice, enum wl_shell_surface_resize edges) override;
+ void resize(QWaylandInputDevice *inputDevice, Qt::Edges edges) override;
bool move(QWaylandInputDevice *inputDevice) override;
void setTitle(const QString &title) override;
void setAppId(const QString &appId) override;
@@ -114,6 +111,9 @@ private:
void requestWindowFlags(Qt::WindowFlags flags);
void requestWindowStates(Qt::WindowStates states);
+
+ static resize_edge convertToResizeEdges(Qt::Edges edges);
+
struct {
QSize size = {0, 0};
Qt::WindowStates states = Qt::WindowNoState;
diff --git a/src/qtwaylandscanner/qtwaylandscanner.cpp b/src/qtwaylandscanner/qtwaylandscanner.cpp
index 6f4a33b5f..56045e880 100644
--- a/src/qtwaylandscanner/qtwaylandscanner.cpp
+++ b/src/qtwaylandscanner/qtwaylandscanner.cpp
@@ -441,7 +441,7 @@ bool Scanner::process()
printf("#ifndef %s\n", inclusionGuard.constData());
printf("#define %s\n", inclusionGuard.constData());
printf("\n");
- printf("#include \"wayland-server.h\"\n");
+ printf("#include \"wayland-server-core.h\"\n");
if (m_headerPath.isEmpty())
printf("#include \"wayland-%s-server-protocol.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData());
else
@@ -505,6 +505,7 @@ bool Scanner::process()
printf(" virtual ~Resource() {}\n");
printf("\n");
printf(" %s *%s_object;\n", interfaceName, interfaceNameStripped);
+ printf(" %s *object() { return %s_object; } \n", interfaceName, interfaceNameStripped);
printf(" struct ::wl_resource *handle;\n");
printf("\n");
printf(" struct ::wl_client *client() const { return wl_resource_get_client(handle); }\n");
@@ -769,6 +770,7 @@ bool Scanner::process()
printf(" void %s::destroy_func(struct ::wl_resource *client_resource)\n", interfaceName);
printf(" {\n");
printf(" Resource *resource = Resource::fromResource(client_resource);\n");
+ printf(" Q_ASSERT(resource);\n");
printf(" %s *that = resource->%s_object;\n", interfaceName, interfaceNameStripped);
printf(" that->m_resource_map.remove(resource->client(), resource);\n");
printf(" that->%s_destroy_resource(resource);\n", interfaceNameStripped);
@@ -939,6 +941,8 @@ bool Scanner::process()
printf("#include <QByteArray>\n");
printf("#include <QString>\n");
printf("\n");
+ printf("struct wl_registry;\n");
+ printf("\n");
printf("QT_BEGIN_NAMESPACE\n");
printf("QT_WARNING_PUSH\n");
printf("QT_WARNING_DISABLE_GCC(\"-Wmissing-field-initializers\")\n");
@@ -1056,6 +1060,22 @@ bool Scanner::process()
printf("QT_WARNING_DISABLE_GCC(\"-Wmissing-field-initializers\")\n");
printf("\n");
printf("namespace QtWayland {\n");
+ printf("\n");
+
+ // wl_registry_bind is part of the protocol, so we can't use that... instead we use core
+ // libwayland API to do the same thing a wayland-scanner generated wl_registry_bind would.
+ printf("static inline void *wlRegistryBind(struct ::wl_registry *registry, uint32_t name, const struct ::wl_interface *interface, uint32_t version)\n");
+ printf("{\n");
+ printf(" const uint32_t bindOpCode = 0;\n");
+ printf("#if (WAYLAND_VERSION_MAJOR == 1 && WAYLAND_VERSION_MINOR > 10) || WAYLAND_VERSION_MAJOR > 1\n");
+ printf(" return (void *) wl_proxy_marshal_constructor_versioned((struct wl_proxy *) registry,\n");
+ printf(" bindOpCode, interface, version, name, interface->name, version, nullptr);\n");
+ printf("#else\n");
+ printf(" return (void *) wl_proxy_marshal_constructor((struct wl_proxy *) registry,\n");
+ printf(" bindOpCode, interface, name, interface->name, version, nullptr);\n");
+ printf("#endif\n");
+ printf("}\n");
+ printf("\n");
for (int j = 0; j < interfaces.size(); ++j) {
const WaylandInterface &interface = interfaces.at(j);
@@ -1096,7 +1116,7 @@ bool Scanner::process()
printf(" void %s::init(struct ::wl_registry *registry, int id, int version)\n", interfaceName);
printf(" {\n");
- printf(" m_%s = static_cast<struct ::%s *>(wl_registry_bind(registry, id, &%s_interface, version));\n", interfaceName, interfaceName, interfaceName);
+ printf(" m_%s = static_cast<struct ::%s *>(wlRegistryBind(registry, id, &%s_interface, version));\n", interfaceName, interfaceName, interfaceName);
if (hasEvents)
printf(" init_listener();\n");
printf(" }\n");
diff --git a/sync.profile b/sync.profile
index 756674cda..147f2782f 100644
--- a/sync.profile
+++ b/sync.profile
@@ -61,6 +61,7 @@
"^qwayland-server-server-buffer-extension.h",
"^qwayland-server-text-input-unstable-v2.h",
"^qwayland-server-touch-extension.h",
+ "^qwayland-server-viewporter.h",
"^qwayland-server-xdg-decoration-unstable-v1.h",
"^qwayland-server-xdg-shell-unstable-v5.h",
"^qwayland-server-xdg-shell-unstable-v6.h",
@@ -71,6 +72,7 @@
"^wayland-qt-key-unstable-v1-server-protocol.h",
"^wayland-server-buffer-extension-server-protocol.h",
"^wayland-text-input-unstable-v2-server-protocol.h",
+ "^wayland-viewporter-server-protocol.h",
"^wayland-touch-extension-server-protocol.h",
"^wayland-wayland-server-protocol.h",
"^wayland-xdg-decoration-unstable-v1-server-protocol.h",
@@ -78,5 +80,9 @@
"^wayland-xdg-shell-unstable-v5-server-protocol.h",
"^wayland-xdg-shell-unstable-v6-server-protocol.h",
],
+ "$basedir/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1" => [
+ "^qwayland-server-linux-dmabuf-unstable-v1.h",
+ "^wayland-linux-dmabuf-unstable-v1-server-protocol.h",
+ ],
);
@private_headers = ( qr/^qwayland-.*\.h/, qr/^wayland-.*-protocol\.h/ );
diff --git a/tests/auto/client/client.pro b/tests/auto/client/client.pro
index 9fd8fc3f9..af7889d5f 100644
--- a/tests/auto/client/client.pro
+++ b/tests/auto/client/client.pro
@@ -2,6 +2,10 @@ TEMPLATE=subdirs
SUBDIRS += \
client \
+ fullscreenshellv1 \
iviapplication \
- xdgshellv6 \
- wl_connect
+ seatv4 \
+ surface \
+ wl_connect \
+ xdgshell \
+ xdgshellv6
diff --git a/tests/auto/client/client/client.pro b/tests/auto/client/client/client.pro
index f4ced252c..7c3a934d0 100644
--- a/tests/auto/client/client/client.pro
+++ b/tests/auto/client/client/client.pro
@@ -1,4 +1,4 @@
-include (../shared/shared.pri)
+include (../shared_old/shared_old.pri)
TARGET = tst_client
SOURCES += tst_client.cpp
diff --git a/tests/auto/client/fullscreenshellv1/fullscreenshellv1.pro b/tests/auto/client/fullscreenshellv1/fullscreenshellv1.pro
new file mode 100644
index 000000000..49d19d5c3
--- /dev/null
+++ b/tests/auto/client/fullscreenshellv1/fullscreenshellv1.pro
@@ -0,0 +1,4 @@
+include (../shared_old/shared_old.pri)
+
+TARGET = tst_client_fullscreenshell1
+SOURCES += tst_fullscreenshellv1.cpp
diff --git a/tests/auto/client/fullscreenshellv1/tst_fullscreenshellv1.cpp b/tests/auto/client/fullscreenshellv1/tst_fullscreenshellv1.cpp
new file mode 100644
index 000000000..f93d9fbc5
--- /dev/null
+++ b/tests/auto/client/fullscreenshellv1/tst_fullscreenshellv1.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+** Copyright (C) 2017 The Qt Company Ltd.
+** 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 "mockcompositor.h"
+
+#include <QWindow>
+
+#include <QtTest/QtTest>
+
+static const QSize screenSize(1600, 1200);
+
+class TestWindow : public QWindow
+{
+public:
+ TestWindow()
+ {
+ setSurfaceType(QSurface::RasterSurface);
+ setGeometry(0, 0, 800, 600);
+ create();
+ }
+};
+
+class tst_WaylandClientFullScreenShellV1 : public QObject
+{
+ Q_OBJECT
+public:
+ tst_WaylandClientFullScreenShellV1(MockCompositor *c)
+ : m_compositor(c)
+ {
+ QSocketNotifier *notifier = new QSocketNotifier(m_compositor->waylandFileDescriptor(), QSocketNotifier::Read, this);
+ connect(notifier, &QSocketNotifier::activated, this, &tst_WaylandClientFullScreenShellV1::processWaylandEvents);
+ // connect to the event dispatcher to make sure to flush out the outgoing message queue
+ connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::awake, this, &tst_WaylandClientFullScreenShellV1::processWaylandEvents);
+ connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, this, &tst_WaylandClientFullScreenShellV1::processWaylandEvents);
+ }
+
+public slots:
+ void processWaylandEvents()
+ {
+ m_compositor->processWaylandEvents();
+ }
+
+ void cleanup()
+ {
+ // make sure the surfaces from the last test are properly cleaned up
+ // and don't show up as false positives in the next test
+ QTRY_VERIFY(!m_compositor->fullScreenShellV1Surface());
+ }
+
+private slots:
+ void createDestroyWindow();
+
+private:
+ MockCompositor *m_compositor = nullptr;
+};
+
+void tst_WaylandClientFullScreenShellV1::createDestroyWindow()
+{
+ TestWindow window;
+ window.show();
+
+ QTRY_VERIFY(m_compositor->fullScreenShellV1Surface());
+
+ window.destroy();
+ QTRY_VERIFY(!m_compositor->fullScreenShellV1Surface());
+}
+
+int main(int argc, char **argv)
+{
+ setenv("XDG_RUNTIME_DIR", ".", 1);
+ setenv("QT_QPA_PLATFORM", "wayland", 1); // force QGuiApplication to use wayland plugin
+ setenv("QT_WAYLAND_SHELL_INTEGRATION", "fullscreen-shell-v1", 1);
+ setenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1", 1); // window decorations don't make much sense here
+
+ MockCompositor compositor;
+ compositor.setOutputMode(screenSize);
+
+ QGuiApplication app(argc, argv);
+ compositor.applicationInitialized();
+
+ tst_WaylandClientFullScreenShellV1 tc(&compositor);
+ return QTest::qExec(&tc, argc, argv);
+}
+
+#include <tst_fullscreenshellv1.moc>
diff --git a/tests/auto/client/iviapplication/iviapplication.pro b/tests/auto/client/iviapplication/iviapplication.pro
index 326921373..f2d596e6c 100644
--- a/tests/auto/client/iviapplication/iviapplication.pro
+++ b/tests/auto/client/iviapplication/iviapplication.pro
@@ -1,4 +1,4 @@
-include (../shared/shared.pri)
+include (../shared_old/shared_old.pri)
TARGET = tst_client_iviapplication
SOURCES += tst_iviapplication.cpp
diff --git a/tests/auto/client/seatv4/seatv4.pro b/tests/auto/client/seatv4/seatv4.pro
new file mode 100644
index 000000000..c02db5855
--- /dev/null
+++ b/tests/auto/client/seatv4/seatv4.pro
@@ -0,0 +1,4 @@
+include (../shared/shared.pri)
+
+TARGET = tst_seatv4
+SOURCES += tst_seatv4.cpp
diff --git a/tests/auto/client/seatv4/tst_seatv4.cpp b/tests/auto/client/seatv4/tst_seatv4.cpp
new file mode 100644
index 000000000..0e0ada5d0
--- /dev/null
+++ b/tests/auto/client/seatv4/tst_seatv4.cpp
@@ -0,0 +1,289 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** 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 "mockcompositor.h"
+
+#include <QtGui/QRasterWindow>
+#include <QtGui/QOpenGLWindow>
+
+using namespace MockCompositor;
+
+// wl_seat version 5 was introduced in wayland 1.10, and although that's pretty old,
+// there are still compositors that have yet to update their implementation to support
+// the new version (most importantly our own QtWaylandCompositor).
+// As long as that's the case, this test makes sure input events still works on version 4.
+class SeatV4Compositor : public DefaultCompositor {
+public:
+ explicit SeatV4Compositor()
+ {
+ exec([this] {
+ m_config.autoConfigure = true;
+
+ removeAll<Seat>();
+
+ uint capabilities = MockCompositor::Seat::capability_pointer;
+ int version = 4;
+ add<Seat>(capabilities, version);
+ });
+ }
+};
+
+class tst_seatv4 : public QObject, private SeatV4Compositor
+{
+ Q_OBJECT
+private slots:
+ void cleanup();
+ void bindsToSeat();
+ void createsPointer();
+ void setsCursorOnEnter();
+ void usesEnterSerial();
+ void mousePress();
+ void simpleAxis_data();
+ void simpleAxis();
+ void invalidPointerEvents();
+ void scaledCursor();
+};
+
+void tst_seatv4::cleanup()
+{
+ QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage()));
+ QCOMPOSITOR_COMPARE(getAll<Output>().size(), 1); // No extra outputs left
+}
+
+void tst_seatv4::bindsToSeat()
+{
+ QCOMPOSITOR_COMPARE(get<Seat>()->resourceMap().size(), 1);
+ QCOMPOSITOR_COMPARE(get<Seat>()->resourceMap().first()->version(), 4);
+}
+
+void tst_seatv4::createsPointer()
+{
+ QCOMPOSITOR_TRY_COMPARE(pointer()->resourceMap().size(), 1);
+ QCOMPOSITOR_TRY_COMPARE(pointer()->resourceMap().first()->version(), 4);
+}
+
+void tst_seatv4::setsCursorOnEnter()
+{
+ QRasterWindow window;
+ window.resize(64, 64);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ exec([=] { pointer()->sendEnter(xdgSurface()->m_surface, {32, 32}); });
+ QCOMPOSITOR_TRY_VERIFY(pointer()->cursorSurface());
+}
+
+void tst_seatv4::usesEnterSerial()
+{
+ QSignalSpy setCursorSpy(exec([=] { return pointer(); }), &Pointer::setCursor);
+ QRasterWindow window;
+ window.resize(64, 64);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ uint enterSerial = exec([=] {
+ return pointer()->sendEnter(xdgSurface()->m_surface, {32, 32});
+ });
+ QCOMPOSITOR_TRY_VERIFY(pointer()->cursorSurface());
+
+ QTRY_COMPARE(setCursorSpy.count(), 1);
+ QCOMPARE(setCursorSpy.takeFirst().at(0).toUInt(), enterSerial);
+}
+
+void tst_seatv4::mousePress()
+{
+ class Window : public QRasterWindow {
+ public:
+ void mousePressEvent(QMouseEvent *) override { m_pressed = true; }
+ bool m_pressed = false;
+ };
+
+ Window window;
+ window.resize(64, 64);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ exec([&] {
+ auto *surface = xdgSurface()->m_surface;
+ pointer()->sendEnter(surface, {32, 32});
+ pointer()->sendButton(client(), BTN_LEFT, 1);
+ pointer()->sendButton(client(), BTN_LEFT, 0);
+ });
+ QTRY_VERIFY(window.m_pressed);
+}
+
+void tst_seatv4::simpleAxis_data()
+{
+ QTest::addColumn<uint>("axis");
+ QTest::addColumn<qreal>("value");
+ QTest::addColumn<Qt::Orientation>("orientation");
+ QTest::addColumn<QPoint>("angleDelta");
+
+ // Directions in regular windows/linux terms (no "natural" scrolling)
+ QTest::newRow("down") << uint(Pointer::axis_vertical_scroll) << 1.0 << Qt::Vertical << QPoint{0, -12};
+ QTest::newRow("up") << uint(Pointer::axis_vertical_scroll) << -1.0 << Qt::Vertical << QPoint{0, 12};
+ QTest::newRow("left") << uint(Pointer::axis_horizontal_scroll) << 1.0 << Qt::Horizontal << QPoint{-12, 0};
+ QTest::newRow("right") << uint(Pointer::axis_horizontal_scroll) << -1.0 << Qt::Horizontal << QPoint{12, 0};
+ QTest::newRow("up big") << uint(Pointer::axis_vertical_scroll) << -10.0 << Qt::Vertical << QPoint{0, 120};
+}
+
+void tst_seatv4::simpleAxis()
+{
+ QFETCH(uint, axis);
+ QFETCH(qreal, value);
+ QFETCH(Qt::Orientation, orientation);
+ QFETCH(QPoint, angleDelta);
+
+ class WheelWindow : QRasterWindow {
+ public:
+ explicit WheelWindow()
+ {
+ resize(64, 64);
+ show();
+ }
+ void wheelEvent(QWheelEvent *event) override
+ {
+ QRasterWindow::wheelEvent(event);
+ // Angle delta should always be provided (says docs)
+ QVERIFY(!event->angleDelta().isNull());
+
+ // There are now scroll phases on Wayland prior to v5
+ QCOMPARE(event->phase(), Qt::NoScrollPhase);
+
+ // Pixel delta should only be set if we know it's a high-res input device (which we don't)
+ QCOMPARE(event->pixelDelta(), QPoint(0, 0));
+
+ // The axis vector of the event is already in surface space, so there is now way to tell
+ // whether it is inverted or not.
+ QCOMPARE(event->inverted(), false);
+
+ // We didn't press any buttons
+ QCOMPARE(event->buttons(), Qt::NoButton);
+
+ if (event->orientation() == Qt::Horizontal)
+ QCOMPARE(event->delta(), event->angleDelta().x());
+ else
+ QCOMPARE(event->delta(), event->angleDelta().y());
+
+ // There has been no information about what created the event.
+ // Documentation says not synthesized is appropriate in such cases
+ QCOMPARE(event->source(), Qt::MouseEventNotSynthesized);
+
+ m_events.append(Event(event->pixelDelta(), event->angleDelta(), event->orientation()));
+ }
+ struct Event // Because I didn't find a convenient way to copy it entirely
+ {
+ // TODO: Constructors can be removed when we start supporting brace-initializers
+ Event() = default;
+ Event(const QPoint &pixelDelta, const QPoint &angleDelta, Qt::Orientation orientation)
+ : pixelDelta(pixelDelta), angleDelta(angleDelta), orientation(orientation)
+ {}
+ const QPoint pixelDelta;
+ const QPoint angleDelta; // eights of a degree, positive is upwards, left
+ const Qt::Orientation orientation{};
+ };
+ QVector<Event> m_events;
+ };
+
+ WheelWindow window;
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ exec([=] {
+ Surface *surface = xdgSurface()->m_surface;
+ pointer()->sendEnter(surface, {32, 32});
+ wl_client *client = surface->resource()->client();
+ // Length of vector in surface-local space. i.e. positive is downwards
+ pointer()->sendAxis(
+ client,
+ Pointer::axis(axis),
+ value // Length of vector in surface-local space. i.e. positive is downwards
+ );
+ });
+
+ QTRY_COMPARE(window.m_events.size(), 1);
+ auto event = window.m_events.takeFirst();
+ QCOMPARE(event.angleDelta, angleDelta);
+ QCOMPARE(event.orientation, orientation);
+}
+
+void tst_seatv4::invalidPointerEvents()
+{
+ QRasterWindow window;
+ window.resize(64, 64);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ exec([=] {
+ auto *p = pointer();
+ auto *c = client();
+ // Purposefully send events without a wl_pointer.enter
+ p->sendMotion(c, {32, 32});
+ p->sendButton(c, BTN_LEFT, Pointer::button_state_pressed);
+ p->sendAxis(c, Pointer::axis_vertical_scroll, 1.0);
+ });
+
+ // Make sure we get here without crashing
+ xdgPingAndWaitForPong();
+}
+
+void tst_seatv4::scaledCursor()
+{
+ QSKIP("Currently broken and should be fixed");
+ // Add a highdpi output
+ exec([&] {
+ int scale = 2;
+ add<Output>(scale);
+ });
+
+ QRasterWindow window;
+ window.resize(64, 64);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ exec([=] { pointer()->sendEnter(xdgSurface()->m_surface, {32, 32}); });
+ QCOMPOSITOR_TRY_VERIFY(pointer()->cursorSurface());
+ QCOMPOSITOR_TRY_VERIFY(pointer()->cursorSurface()->m_committed.buffer);
+ QCOMPOSITOR_TRY_COMPARE(pointer()->cursorSurface()->m_committed.bufferScale, 1);
+ QSize unscaledPixelSize = exec([=] {
+ return pointer()->cursorSurface()->m_committed.buffer->size();
+ });
+
+ exec([=] {
+ auto *surface = pointer()->cursorSurface();
+ surface->sendEnter(getAll<Output>()[1]);
+ surface->sendLeave(getAll<Output>()[0]);
+ });
+
+ QCOMPOSITOR_TRY_COMPARE(pointer()->cursorSurface()->m_committed.buffer->size(), unscaledPixelSize * 2);
+
+ // Remove the extra output to clean up for the next test
+ exec([&] { remove(getAll<Output>()[1]); });
+}
+
+QCOMPOSITOR_TEST_MAIN(tst_seatv4)
+#include "tst_seatv4.moc"
diff --git a/tests/auto/client/shared/corecompositor.cpp b/tests/auto/client/shared/corecompositor.cpp
new file mode 100644
index 000000000..afa25e94c
--- /dev/null
+++ b/tests/auto/client/shared/corecompositor.cpp
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** 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 "corecompositor.h"
+
+namespace MockCompositor {
+
+CoreCompositor::CoreCompositor()
+ : m_display(wl_display_create())
+ , m_socketName(wl_display_add_socket_auto(m_display))
+ , m_eventLoop(wl_display_get_event_loop(m_display))
+
+ // Start dispatching
+ , m_dispatchThread([this](){
+ while (m_running) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ dispatch();
+ }
+ })
+{
+ m_timer.start();
+ Q_ASSERT(isClean());
+}
+
+CoreCompositor::~CoreCompositor()
+{
+ m_running = false;
+ m_dispatchThread.join();
+ wl_display_destroy(m_display);
+}
+
+bool CoreCompositor::isClean()
+{
+ Lock lock(this);
+ for (auto *global : qAsConst(m_globals)) {
+ if (!global->isClean())
+ return false;
+ }
+ return true;
+}
+
+QString CoreCompositor::dirtyMessage()
+{
+ Lock lock(this);
+ QStringList messages;
+ for (auto *global : qAsConst(m_globals)) {
+ if (!global->isClean())
+ messages << (global->metaObject()->className() % QLatin1String(": ") % global->dirtyMessage());
+ }
+ return messages.join(", ");
+}
+
+void CoreCompositor::dispatch()
+{
+ Lock lock(this);
+ wl_display_flush_clients(m_display);
+ constexpr int timeout = 0; // immediate return
+ wl_event_loop_dispatch(m_eventLoop, timeout);
+}
+
+/*!
+ * \brief Adds a new global interface for the compositor
+ *
+ * Takes ownership of \a global
+ */
+void CoreCompositor::add(Global *global)
+{
+ warnIfNotLockedByThread(Q_FUNC_INFO);
+ m_globals.append(global);
+}
+
+void CoreCompositor::remove(Global *global)
+{
+ warnIfNotLockedByThread(Q_FUNC_INFO);
+ //TODO: Need to delete global as well!
+ m_globals.removeAll(global);
+}
+
+uint CoreCompositor::nextSerial()
+{
+ warnIfNotLockedByThread(Q_FUNC_INFO);
+ return wl_display_next_serial(m_display);
+}
+
+uint CoreCompositor::currentTimeMilliseconds()
+{
+ warnIfNotLockedByThread(Q_FUNC_INFO);
+ return uint(m_timer.elapsed());
+}
+
+wl_client *CoreCompositor::client(int index)
+{
+ warnIfNotLockedByThread(Q_FUNC_INFO);
+ wl_list *clients = wl_display_get_client_list(m_display);
+ wl_client *client = nullptr;
+ int i = 0;
+ wl_client_for_each(client, clients) {
+ if (i++ == index)
+ return client;
+ }
+ return nullptr;
+}
+
+void CoreCompositor::warnIfNotLockedByThread(const char *caller)
+{
+ if (!m_lock || !m_lock->isOwnedByCurrentThread()) {
+ qWarning() << caller << "called without locking the compositor to the current thread."
+ << "This means the compositor can start dispatching at any moment,"
+ << "potentially leading to threading issues."
+ << "Unless you know what you are doing you should probably fix the test"
+ << "by locking the compositor before accessing it (see mutex()).";
+ }
+}
+
+} // namespace MockCompositor
diff --git a/tests/auto/client/shared/corecompositor.h b/tests/auto/client/shared/corecompositor.h
new file mode 100644
index 000000000..875b7d050
--- /dev/null
+++ b/tests/auto/client/shared/corecompositor.h
@@ -0,0 +1,209 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** 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 MOCKCOMPOSITOR_CORECOMPOSITOR_H
+#define MOCKCOMPOSITOR_CORECOMPOSITOR_H
+
+#include <QtTest/QtTest>
+
+#include <wayland-server-core.h>
+
+struct wl_resource;
+
+namespace MockCompositor {
+
+class Global : public QObject
+{
+ Q_OBJECT
+public:
+ virtual bool isClean() { return true; }
+ virtual QString dirtyMessage() { return isClean() ? "clean" : "dirty"; }
+};
+
+class CoreCompositor
+{
+public:
+ explicit CoreCompositor();
+ ~CoreCompositor();
+ bool isClean();
+ QString dirtyMessage();
+ void dispatch();
+
+ template<typename function_type, typename... arg_types>
+ auto exec(function_type func, arg_types&&... args) -> decltype(func())
+ {
+ Lock lock(this);
+ return func(std::forward<arg_types>(args)...);
+ }
+
+ template<typename function_type, typename... arg_types>
+ auto call(function_type func, arg_types&&... args) -> decltype(func())
+ {
+ Lock lock(this);
+ auto boundFunc = std::bind(func, this);
+ return boundFunc(this, std::forward<arg_types>(args)...);
+ }
+
+ // Unsafe section below, YOU are responsible that the compositor is locked or
+ // this is run through the mutex() method!
+
+ void add(Global *global);
+ void remove(Global *global);
+
+ /*!
+ * \brief Constructs and adds a new global with the given parameters
+ *
+ * Convenience function. i.e.
+ *
+ * compositor->add(new MyGlobal(compositor, version);
+ *
+ * can be written as:
+ *
+ * compositor->add<MyGlobal>(version);
+ *
+ * Returns the new global
+ */
+ template<typename global_type, typename... arg_types>
+ global_type *add(arg_types&&... args)
+ {
+ warnIfNotLockedByThread(Q_FUNC_INFO);
+ auto *global = new global_type(this, std::forward<arg_types>(args)...);
+ m_globals.append(global);
+ return global;
+ }
+
+ /*!
+ * \brief Removes all globals of the given type
+ *
+ * Convenience function
+ */
+ template<typename global_type, typename... arg_types>
+ void removeAll()
+ {
+ const auto globals = getAll<global_type>();
+ for (auto global : globals)
+ remove(global);
+ }
+
+ /*!
+ * \brief Returns a global with the given type, if any
+ */
+ template<typename global_type>
+ global_type *get()
+ {
+ warnIfNotLockedByThread(Q_FUNC_INFO);
+ for (auto *global : qAsConst(m_globals)) {
+ if (auto *casted = qobject_cast<global_type *>(global))
+ return casted;
+ }
+ return nullptr;
+ }
+
+ /*!
+ * \brief Returns all globals with the given type, if any
+ */
+ template<typename global_type>
+ QVector<global_type *> getAll()
+ {
+ warnIfNotLockedByThread(Q_FUNC_INFO);
+ QVector<global_type *> matching;
+ for (auto *global : qAsConst(m_globals)) {
+ if (auto *casted = qobject_cast<global_type *>(global))
+ matching.append(casted);
+ }
+ return matching;
+ }
+
+ uint nextSerial();
+ uint currentTimeMilliseconds();
+ wl_client *client(int index = 0);
+ void warnIfNotLockedByThread(const char* caller = "warnIfNotLockedbyThread");
+
+public:
+ // Only use this carefully from the test thread (i.e. lock first)
+ wl_display *m_display = nullptr;
+protected:
+ class Lock {
+ public:
+ explicit Lock(CoreCompositor *compositor)
+ : m_compositor(compositor)
+ , m_threadId(std::this_thread::get_id())
+ {
+ // Can't use a QMutexLocker here, as it's not movable
+ compositor->m_mutex.lock();
+ Q_ASSERT(compositor->m_lock == nullptr);
+ compositor->m_lock = this;
+ }
+ ~Lock()
+ {
+ Q_ASSERT(m_compositor->m_lock == this);
+ m_compositor->m_lock = nullptr;
+ m_compositor->m_mutex.unlock();
+ }
+
+ // Move semantics
+ Lock(Lock &&) = default;
+ Lock &operator=(Lock &&) = default;
+
+ // Disable copying
+ Lock(const Lock &) = delete;
+ Lock &operator=(const Lock &) = delete;
+
+ bool isOwnedByCurrentThread() const { return m_threadId == std::this_thread::get_id(); }
+ private:
+ CoreCompositor *m_compositor = nullptr;
+ std::thread::id m_threadId;
+ };
+ QByteArray m_socketName;
+ wl_event_loop *m_eventLoop = nullptr;
+ bool m_running = true;
+ QVector<Global *> m_globals;
+ QElapsedTimer m_timer;
+
+private:
+ Lock *m_lock = nullptr;
+ QMutex m_mutex;
+ std::thread m_dispatchThread;
+};
+
+template<typename container_type>
+QByteArray toByteArray(container_type container)
+{
+ return QByteArray(reinterpret_cast<const char *>(container.data()), sizeof (container[0]) * container.size());
+}
+
+template<typename return_type>
+return_type *fromResource(::wl_resource *resource) {
+ if (auto *r = return_type::Resource::fromResource(resource))
+ return static_cast<return_type *>(r->object());
+ return nullptr;
+}
+
+} // namespace MockCompositor
+
+#endif // MOCKCOMPOSITOR_CORECOMPOSITOR_H
diff --git a/tests/auto/client/shared/coreprotocol.cpp b/tests/auto/client/shared/coreprotocol.cpp
new file mode 100644
index 000000000..46d46d980
--- /dev/null
+++ b/tests/auto/client/shared/coreprotocol.cpp
@@ -0,0 +1,322 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** 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 "coreprotocol.h"
+
+namespace MockCompositor {
+
+void Surface::sendFrameCallbacks()
+{
+ uint time = m_wlCompositor->m_compositor->currentTimeMilliseconds();
+ for (auto *callback : m_waitingFrameCallbacks)
+ callback->sendDone(time);
+ m_waitingFrameCallbacks.clear();
+}
+
+void Surface::sendEnter(Output *output)
+{
+ m_outputs.append(output);
+ const auto outputResources = output->resourceMap().values(resource()->client());
+ for (auto outputResource: outputResources)
+ wl_surface::send_enter(resource()->handle, outputResource->handle);
+}
+
+void Surface::sendLeave(Output *output)
+{
+ m_outputs.removeOne(output);
+ const auto outputResources = output->resourceMap().values(resource()->client());
+ for (auto outputResource: outputResources)
+ wl_surface::send_leave(resource()->handle, outputResource->handle);
+}
+
+void Surface::surface_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource);
+ for (auto *commit : m_commits)
+ delete commit->commitSpecific.frame;
+ bool removed = m_wlCompositor->m_surfaces.removeOne(this);
+ Q_ASSERT(removed);
+ delete this;
+}
+
+void Surface::surface_attach(Resource *resource, wl_resource *buffer, int32_t x, int32_t y)
+{
+ Q_UNUSED(resource);
+ QPoint offset(x, y);
+ m_pending.buffer = fromResource<Buffer>(buffer);
+ m_pending.commitSpecific.attachOffset = offset;
+ m_pending.commitSpecific.attached = true;
+ emit attach(buffer, offset);
+}
+
+void Surface::surface_set_buffer_scale(QtWaylandServer::wl_surface::Resource *resource, int32_t scale)
+{
+ Q_UNUSED(resource);
+ m_pending.bufferScale = scale;
+}
+
+void Surface::surface_commit(Resource *resource)
+{
+ Q_UNUSED(resource);
+ m_committed = m_pending;
+ m_commits.append(new DoubleBufferedState(m_committed));
+
+ if (auto *frame = m_pending.commitSpecific.frame)
+ m_waitingFrameCallbacks.append(frame);
+
+ m_pending.commitSpecific = PerCommitData();
+ emit commit();
+ if (m_committed.commitSpecific.attached)
+ emit bufferCommitted();
+}
+
+void Surface::surface_frame(Resource *resource, uint32_t callback)
+{
+ // Although valid, there is really no point having multiple frame requests in the same commit.
+ // Make sure we don't do it
+ QCOMPARE(m_pending.commitSpecific.frame, nullptr);
+
+ auto *frame = new Callback(resource->client(), callback, 1);
+ m_pending.commitSpecific.frame = frame;
+}
+
+bool WlCompositor::isClean() {
+ for (auto *surface : qAsConst(m_surfaces)) {
+ if (!CursorRole::fromSurface(surface))
+ return false;
+ }
+ return true;
+}
+
+QString WlCompositor::dirtyMessage()
+{
+ if (isClean())
+ return "clean";
+ QStringList messages;
+ for (auto *s : qAsConst(m_surfaces)) {
+ QString role = s->m_role ? s->m_role->staticMetaObject.className(): "none/unknown";
+ messages << "Surface with role: " + role;
+ }
+ return "Dirty, surfaces left:\n\t" + messages.join("\n\t");
+}
+
+void Output::sendScale(int factor)
+{
+ Q_ASSERT(m_version >= WL_OUTPUT_SCALE_SINCE_VERSION);
+ m_scale = factor;
+ const auto resources = resourceMap().values();
+ for (auto r: resources)
+ wl_output::send_scale(r->handle, factor);
+}
+
+void Output::sendDone()
+{
+ Q_ASSERT(m_version >= WL_OUTPUT_DONE_SINCE_VERSION);
+ const auto resources = resourceMap().values();
+ for (auto r: resources)
+ wl_output::send_done(r->handle);
+}
+
+void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource)
+{
+ if (m_version >= WL_OUTPUT_SCALE_SINCE_VERSION)
+ wl_output::send_scale(resource->handle, m_scale);
+ //TODO: send other required stuff as well
+ if (m_version >= WL_OUTPUT_DONE_SINCE_VERSION)
+ wl_output::send_done(resource->handle);
+}
+
+// Seat stuff
+Seat::Seat(CoreCompositor *compositor, uint capabilities, int version) //TODO: check version
+ : QtWaylandServer::wl_seat(compositor->m_display, version)
+ , m_compositor(compositor)
+{
+ setCapabilities(capabilities);
+}
+
+Seat::~Seat()
+{
+ qDeleteAll(m_oldPointers);
+ delete m_pointer;
+}
+
+void Seat::setCapabilities(uint capabilities) {
+ // TODO: Add support for touch and keyboard
+ Q_ASSERT(capabilities == 0 || capabilities == capability_pointer);
+
+ m_capabilities = capabilities;
+
+ if (m_capabilities & capability_pointer) {
+ if (!m_pointer)
+ m_pointer = (new Pointer(this));
+ } else if (m_pointer) {
+ m_oldPointers << m_pointer;
+ m_pointer = nullptr;
+ }
+
+ for (auto *resource : resourceMap())
+ wl_seat::send_capabilities(resource->handle, capabilities);
+}
+
+void Seat::seat_get_pointer(Resource *resource, uint32_t id)
+{
+ if (~m_capabilities & capability_pointer) {
+ qWarning() << "Client requested a wl_pointer without the capability being available."
+ << "This Could be a race condition when hotunplugging,"
+ << "but is most likely a client error";
+ Pointer *pointer = new Pointer(this);
+ pointer->add(resource->client(), id, resource->version());
+ // TODO: mark as destroyed
+ m_oldPointers << pointer;
+ return;
+ }
+ m_pointer->add(resource->client(), id, resource->version());
+}
+
+Surface *Pointer::cursorSurface()
+{
+ return m_cursorRole ? m_cursorRole->m_surface : nullptr;
+}
+
+uint Pointer::sendEnter(Surface *surface, const QPointF &position)
+{
+ wl_fixed_t x = wl_fixed_from_double(position.x());
+ wl_fixed_t y = wl_fixed_from_double(position.y());
+ m_enterSerial = m_seat->m_compositor->nextSerial();
+
+ wl_client *client = surface->resource()->client();
+ const auto pointerResources = resourceMap().values(client);
+ for (auto *r : pointerResources)
+ send_enter(r->handle, m_enterSerial, surface->resource()->handle, x ,y);
+ return m_enterSerial;
+}
+
+// Make sure you call enter, frame etc. first
+void Pointer::sendMotion(wl_client *client, const QPointF &position)
+{
+ wl_fixed_t x = wl_fixed_from_double(position.x());
+ wl_fixed_t y = wl_fixed_from_double(position.y());
+ auto time = m_seat->m_compositor->currentTimeMilliseconds();
+ const auto pointerResources = resourceMap().values(client);
+ for (auto *r : pointerResources)
+ send_motion(r->handle, time, x, y);
+}
+
+// Make sure you call enter, frame etc. first
+uint Pointer::sendButton(wl_client *client, uint button, uint state)
+{
+ Q_ASSERT(state == button_state_pressed || state == button_state_released);
+ auto time = m_seat->m_compositor->currentTimeMilliseconds();
+ uint serial = m_seat->m_compositor->nextSerial();
+ const auto pointerResources = resourceMap().values(client);
+ for (auto *r : pointerResources)
+ send_button(r->handle, serial, time, button, state);
+ return serial;
+}
+
+// Make sure you call enter, frame etc. first
+void Pointer::sendAxis(wl_client *client, axis axis, qreal value)
+{
+ auto time = m_seat->m_compositor->currentTimeMilliseconds();
+ wl_fixed_t val = wl_fixed_from_double(value);
+ const auto pointerResources = resourceMap().values(client);
+ for (auto *r : pointerResources)
+ send_axis(r->handle, time, axis, val);
+}
+
+void Pointer::pointer_set_cursor(Resource *resource, uint32_t serial, wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y)
+{
+ Q_UNUSED(resource);
+ Q_UNUSED(hotspot_x);
+ Q_UNUSED(hotspot_y);
+ auto *s = fromResource<Surface>(surface);
+ QVERIFY(s);
+
+ if (s->m_role) {
+ auto *cursorRole = CursorRole::fromSurface(s);
+ QVERIFY(cursorRole);
+ QVERIFY(cursorRole == m_cursorRole);
+ } else {
+ m_cursorRole = new CursorRole(s); //TODO: make sure we don't leak CursorRole
+ s->m_role = m_cursorRole;
+ }
+// QCOMPARE(serial, m_enterSerial); //TODO: uncomment when this bug is fixed
+ emit setCursor(serial);
+}
+
+// Shm implementation
+Shm::Shm(CoreCompositor *compositor, QVector<format> formats, int version)
+ : QtWaylandServer::wl_shm(compositor->m_display, version)
+ , m_compositor(compositor)
+ , m_formats(formats)
+{
+ // Some formats are specified as mandatory
+ Q_ASSERT(m_formats.contains(format_argb8888));
+ Q_ASSERT(m_formats.contains(format_xrgb8888));
+}
+
+bool Shm::isClean()
+{
+// for (ShmPool *pool : qAsConst(m_pools)) {
+// //TODO: return false if not cursor buffer
+// if (pool->m_buffers.isEmpty()) {
+// return false;
+// }
+// }
+ return true;
+}
+
+void Shm::shm_create_pool(Resource *resource, uint32_t id, int32_t fd, int32_t size)
+{
+ Q_UNUSED(fd);
+ Q_UNUSED(size);
+ auto *pool = new ShmPool(this, resource->client(), id, 1);
+ m_pools.append(pool);
+}
+
+ShmPool::ShmPool(Shm *shm, wl_client *client, int id, int version)
+ : QtWaylandServer::wl_shm_pool(client, id, version)
+ , m_shm(shm)
+{
+}
+
+void ShmPool::shm_pool_create_buffer(Resource *resource, uint32_t id, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format)
+{
+ QSize size(width, height);
+ new ShmBuffer(offset, size, stride, Shm::format(format), resource->client(), id);
+}
+
+void ShmPool::shm_pool_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource);
+ bool removed = m_shm->m_pools.removeOne(this);
+ Q_ASSERT(removed);
+ delete this;
+}
+
+} // namespace MockCompositor
diff --git a/tests/auto/client/shared/coreprotocol.h b/tests/auto/client/shared/coreprotocol.h
new file mode 100644
index 000000000..2fbe9b139
--- /dev/null
+++ b/tests/auto/client/shared/coreprotocol.h
@@ -0,0 +1,313 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** 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 MOCKCOMPOSITOR_COREPROTOCOL_H
+#define MOCKCOMPOSITOR_COREPROTOCOL_H
+
+#include "corecompositor.h"
+
+#include <qwayland-server-wayland.h>
+
+namespace MockCompositor {
+
+class WlCompositor;
+class Output;
+class Pointer;
+class CursorRole;
+class ShmPool;
+class ShmBuffer;
+
+class Buffer : public QObject, public QtWaylandServer::wl_buffer
+{
+ Q_OBJECT
+public:
+ explicit Buffer(wl_client *client, int id, int version)
+ : QtWaylandServer::wl_buffer(client, id, version)
+ {
+ }
+ virtual QSize size() const = 0;
+ bool m_destroyed = false;
+
+protected:
+ void buffer_destroy_resource(Resource *resource) override
+ {
+ Q_UNUSED(resource);
+ m_destroyed = true;
+ // The client side resource has been destroyed, but we keep this object because it may be
+ // be used as a reference by e.g. surface for the currently committed buffer so it's not
+ // yet safe to free it.
+
+ //TODO: The memory should be freed by its factory
+ }
+ void buffer_destroy(Resource *resource) override { wl_resource_destroy(resource->handle); }
+};
+
+class Callback : public QObject, public QtWaylandServer::wl_callback
+{
+ Q_OBJECT
+public:
+ explicit Callback(wl_client *client, int id, int version = 1)
+ : QtWaylandServer::wl_callback(client, id, version)
+ {
+ }
+ ~Callback() override { if (!m_destroyed) wl_resource_destroy(resource()->handle); }
+ void send_done(uint32_t data) = delete; // use state-tracking method below instead
+ void sendDone(uint data) { Q_ASSERT(!m_done); QtWaylandServer::wl_callback::send_done(data); m_done = true; }
+ void sendDoneAndDestroy(uint data) { sendDone(data); wl_resource_destroy(resource()->handle); }
+ bool m_done = false;
+ bool m_destroyed = false;
+protected:
+ void callback_destroy_resource(Resource *resource) override { Q_UNUSED(resource); m_destroyed = true; }
+};
+
+class SurfaceRole : public QObject {
+ Q_OBJECT
+};
+
+class Surface : public QObject, public QtWaylandServer::wl_surface
+{
+ Q_OBJECT
+public:
+ explicit Surface(WlCompositor *wlCompositor, wl_client *client, int id, int version)
+ : QtWaylandServer::wl_surface(client, id, version)
+ , m_wlCompositor(wlCompositor)
+ {
+ }
+ ~Surface() override { qDeleteAll(m_commits); } // TODO: maybe make sure buffers are released?
+ void sendFrameCallbacks();
+ void sendEnter(Output *output);
+ void send_enter(::wl_resource *output) = delete;
+ void sendLeave(Output *output);
+ void send_leave(::wl_resource *output) = delete;
+
+ WlCompositor *m_wlCompositor;
+ struct PerCommitData {
+ Callback *frame = nullptr;
+ QPoint attachOffset;
+ bool attached = false;
+ };
+ struct DoubleBufferedState {
+ PerCommitData commitSpecific;
+ Buffer *buffer = nullptr;
+ uint configureSerial = 0;
+ int bufferScale = 1;
+ } m_pending, m_committed;
+ QVector<DoubleBufferedState *> m_commits;
+ QVector<Callback *> m_waitingFrameCallbacks;
+ QVector<Output *> m_outputs;
+ SurfaceRole *m_role = nullptr;
+
+signals:
+ void attach(void *buffer, QPoint offset);
+ void commit();
+ void bufferCommitted();
+
+protected:
+ void surface_destroy_resource(Resource *resource) override;
+ void surface_destroy(Resource *resource) override { wl_resource_destroy(resource->handle); }
+ void surface_attach(Resource *resource, wl_resource *buffer, int32_t x, int32_t y) override;
+ void surface_set_buffer_scale(Resource *resource, int32_t scale) override;
+ void surface_commit(Resource *resource) override;
+ void surface_frame(Resource *resource, uint32_t callback) override;
+};
+
+class WlCompositor : public Global, public QtWaylandServer::wl_compositor
+{
+ Q_OBJECT
+public:
+ explicit WlCompositor(CoreCompositor *compositor, int version = 3)
+ : QtWaylandServer::wl_compositor(compositor->m_display, version)
+ , m_compositor(compositor)
+ {}
+ bool isClean() override;
+ QString dirtyMessage() override;
+ QVector<Surface *> m_surfaces;
+ CoreCompositor *m_compositor = nullptr;
+
+signals:
+ void surfaceCreated(Surface *surface);
+
+protected:
+ void compositor_create_surface(Resource *resource, uint32_t id) override
+ {
+ auto *surface = new Surface(this, resource->client(), id, resource->version());
+ m_surfaces.append(surface);
+ emit surfaceCreated(surface);
+ }
+};
+
+class SubCompositor : public Global, public QtWaylandServer::wl_subcompositor
+{
+ Q_OBJECT
+public:
+ explicit SubCompositor(CoreCompositor *compositor, int version = 1)
+ : QtWaylandServer::wl_subcompositor(compositor->m_display, version)
+ {}
+ // TODO
+};
+
+class Output : public Global, public QtWaylandServer::wl_output
+{
+ Q_OBJECT
+public:
+ explicit Output(CoreCompositor *compositor, int scale = 1, int version = 2)
+ : QtWaylandServer::wl_output(compositor->m_display, version)
+ , m_scale(scale)
+ , m_version(version)
+ {}
+ void sendScale(int factor);
+ void send_scale(int32_t factor) = delete;
+ void send_scale(struct ::wl_resource *resource, int32_t factor) = delete;
+ void sendDone();
+ int m_scale = 1;
+ int m_version = 1; // TODO: remove on libwayland upgrade
+
+protected:
+ void output_bind_resource(Resource *resource) override;
+};
+
+class Seat : public Global, public QtWaylandServer::wl_seat
+{
+ Q_OBJECT
+public:
+ explicit Seat(CoreCompositor *compositor, uint capabilities, int version = 4);
+ ~Seat() override;
+ void send_capabilities(Resource *resource, uint capabilities) = delete; // Use wrapper instead
+ void send_capabilities(uint capabilities) = delete; // Use wrapper instead
+ void setCapabilities(uint capabilities);
+
+ CoreCompositor *m_compositor = nullptr;
+
+ Pointer* m_pointer = nullptr;
+ QVector<Pointer *> m_oldPointers;
+
+ uint m_capabilities = 0;
+
+protected:
+ void seat_bind_resource(Resource *resource) override
+ {
+ wl_seat::send_capabilities(resource->handle, m_capabilities);
+ }
+
+ void seat_get_pointer(Resource *resource, uint32_t id) override;
+// void seat_get_keyboard(Resource *resource, uint32_t id) override;
+// void seat_get_touch(Resource *resource, uint32_t id) override;
+
+// void seat_release(Resource *resource) override;
+};
+
+class Pointer : public QObject, public QtWaylandServer::wl_pointer
+{
+ Q_OBJECT
+public:
+ explicit Pointer(Seat *seat) : m_seat(seat) {}
+ Surface *cursorSurface();
+ CursorRole* m_cursorRole = nullptr; //TODO: cleanup
+ uint sendEnter(Surface *surface, const QPointF &position);
+ void sendMotion(wl_client *client, const QPointF &position);
+ uint sendButton(wl_client *client, uint button, uint state);
+ void sendAxis(wl_client *client, axis axis, qreal value);
+
+ Seat *m_seat = nullptr;
+ uint m_enterSerial = 0;
+
+signals:
+ void setCursor(uint serial); //TODO: add arguments?
+
+protected:
+ void pointer_set_cursor(Resource *resource, uint32_t serial, ::wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y) override;
+ //TODO
+};
+
+class CursorRole : public SurfaceRole {
+ Q_OBJECT
+public:
+ explicit CursorRole(Surface *surface) // TODO: needs some more args
+ : m_surface(surface)
+ {
+ }
+ static CursorRole *fromSurface(Surface *surface) { return qobject_cast<CursorRole *>(surface->m_role); }
+ Surface *m_surface = nullptr;
+};
+
+class Shm : public Global, public QtWaylandServer::wl_shm
+{
+ Q_OBJECT
+public:
+ explicit Shm(CoreCompositor *compositor, QVector<format> formats = {format_argb8888, format_xrgb8888, format_rgb888}, int version = 1);
+ bool isClean() override;
+ CoreCompositor *m_compositor = nullptr;
+ QVector<ShmPool *> m_pools;
+ const QVector<format> m_formats;
+
+protected:
+ void shm_create_pool(Resource *resource, uint32_t id, int32_t fd, int32_t size) override;
+ void shm_bind_resource(Resource *resource) override
+ {
+ for (auto format : qAsConst(m_formats))
+ send_format(resource->handle, format);
+ }
+};
+
+class ShmPool : QObject, public QtWaylandServer::wl_shm_pool
+{
+ Q_OBJECT
+public:
+ explicit ShmPool(Shm *shm, wl_client *client, int id, int version = 1);
+ Shm *m_shm = nullptr;
+ QVector<ShmBuffer *> m_buffers;
+
+protected:
+ void shm_pool_create_buffer(Resource *resource, uint32_t id, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) override;
+ void shm_pool_destroy_resource(Resource *resource) override;
+ void shm_pool_destroy(Resource *resource) override { wl_resource_destroy(resource->handle); }
+};
+
+class ShmBuffer : public Buffer
+{
+ Q_OBJECT
+public:
+ static ShmBuffer *fromBuffer(Buffer *buffer) { return qobject_cast<ShmBuffer *>(buffer); }
+ explicit ShmBuffer(int offset, const QSize &size, int stride, Shm::format format, wl_client *client, int id, int version = 1)
+ : Buffer(client, id, version)
+ , m_offset(offset)
+ , m_size(size)
+ , m_stride(stride)
+ , m_format(format)
+ {
+ }
+ QSize size() const override { return m_size; }
+ const int m_offset;
+ const QSize m_size;
+ const int m_stride;
+ const Shm::format m_format;
+};
+
+} // namespace MockCompositor
+
+#endif // MOCKCOMPOSITOR_COREPROTOCOL_H
diff --git a/tests/auto/client/shared/mockcompositor.cpp b/tests/auto/client/shared/mockcompositor.cpp
index 797c05c44..45d62a153 100644
--- a/tests/auto/client/shared/mockcompositor.cpp
+++ b/tests/auto/client/shared/mockcompositor.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
@@ -27,477 +27,64 @@
****************************************************************************/
#include "mockcompositor.h"
-#include "mockinput.h"
-#include "mockoutput.h"
-#include "mocksurface.h"
-#include "mockwlshell.h"
-#include "mockxdgshellv6.h"
-#include "mockiviapplication.h"
-#include <wayland-xdg-shell-unstable-v6-server-protocol.h>
-
-#include <stdio.h>
-MockCompositor::MockCompositor()
-{
- pthread_create(&m_thread, 0, run, this);
-
- m_mutex.lock();
- m_waitCondition.wait(&m_mutex);
- m_mutex.unlock();
-}
-
-MockCompositor::~MockCompositor()
-{
- m_alive = false;
- m_waitCondition.wakeOne();
- pthread_join(m_thread, 0);
-}
-
-void MockCompositor::lock()
-{
- m_mutex.lock();
-}
-
-void MockCompositor::unlock()
-{
- m_mutex.unlock();
-}
-
-void MockCompositor::applicationInitialized()
-{
- m_ready = true;
-}
-
-int MockCompositor::waylandFileDescriptor() const
-{
- return m_compositor->fileDescriptor();
-}
-
-void MockCompositor::processWaylandEvents()
-{
- m_waitCondition.wakeOne();
-}
-
-void MockCompositor::setOutputMode(const QSize &size)
-{
- Command command = makeCommand(Impl::Compositor::setOutputMode, m_compositor);
- command.parameters << size;
- processCommand(command);
-}
-
-void MockCompositor::setKeyboardFocus(const QSharedPointer<MockSurface> &surface)
-{
- Command command = makeCommand(Impl::Compositor::setKeyboardFocus, m_compositor);
- command.parameters << QVariant::fromValue(surface);
- processCommand(command);
-}
-
-void MockCompositor::sendMousePress(const QSharedPointer<MockSurface> &surface, const QPoint &pos)
-{
- Command command = makeCommand(Impl::Compositor::sendMousePress, m_compositor);
- command.parameters << QVariant::fromValue(surface) << pos;
- processCommand(command);
-}
-
-void MockCompositor::sendMouseRelease(const QSharedPointer<MockSurface> &surface)
-{
- Command command = makeCommand(Impl::Compositor::sendMouseRelease, m_compositor);
- command.parameters << QVariant::fromValue(surface);
- processCommand(command);
-}
-
-void MockCompositor::sendKeyPress(const QSharedPointer<MockSurface> &surface, uint code)
-{
- Command command = makeCommand(Impl::Compositor::sendKeyPress, m_compositor);
- command.parameters << QVariant::fromValue(surface) << code;
- processCommand(command);
-}
-
-void MockCompositor::sendKeyRelease(const QSharedPointer<MockSurface> &surface, uint code)
-{
- Command command = makeCommand(Impl::Compositor::sendKeyRelease, m_compositor);
- command.parameters << QVariant::fromValue(surface) << code;
- processCommand(command);
-}
-
-void MockCompositor::sendTouchDown(const QSharedPointer<MockSurface> &surface, const QPoint &position, int id)
-{
- Command command = makeCommand(Impl::Compositor::sendTouchDown, m_compositor);
- command.parameters << QVariant::fromValue(surface) << position << id;
- processCommand(command);
-}
-
-void MockCompositor::sendTouchMotion(const QSharedPointer<MockSurface> &surface, const QPoint &position, int id)
-{
- Command command = makeCommand(Impl::Compositor::sendTouchMotion, m_compositor);
- command.parameters << QVariant::fromValue(surface) << position << id;
- processCommand(command);
-}
-
-void MockCompositor::sendTouchUp(const QSharedPointer<MockSurface> &surface, int id)
-{
- Command command = makeCommand(Impl::Compositor::sendTouchUp, m_compositor);
- command.parameters << QVariant::fromValue(surface) << id;
- processCommand(command);
-}
-
-void MockCompositor::sendTouchFrame(const QSharedPointer<MockSurface> &surface)
-{
- Command command = makeCommand(Impl::Compositor::sendTouchFrame, m_compositor);
- command.parameters << QVariant::fromValue(surface);
- processCommand(command);
-}
-
-void MockCompositor::sendDataDeviceDataOffer(const QSharedPointer<MockSurface> &surface)
-{
- Command command = makeCommand(Impl::Compositor::sendDataDeviceDataOffer, m_compositor);
- command.parameters << QVariant::fromValue(surface);
- processCommand(command);
-}
-
-void MockCompositor::sendDataDeviceEnter(const QSharedPointer<MockSurface> &surface, const QPoint& position)
-{
- Command command = makeCommand(Impl::Compositor::sendDataDeviceEnter, m_compositor);
- command.parameters << QVariant::fromValue(surface) << QVariant::fromValue(position);
- processCommand(command);
-}
-
-void MockCompositor::sendDataDeviceMotion(const QPoint &position)
-{
- Command command = makeCommand(Impl::Compositor::sendDataDeviceMotion, m_compositor);
- command.parameters << QVariant::fromValue(position);
- processCommand(command);
-}
-
-void MockCompositor::sendDataDeviceDrop(const QSharedPointer<MockSurface> &surface)
-{
- Command command = makeCommand(Impl::Compositor::sendDataDeviceDrop, m_compositor);
- command.parameters << QVariant::fromValue(surface);
- processCommand(command);
-}
-
-void MockCompositor::sendDataDeviceLeave(const QSharedPointer<MockSurface> &surface)
-{
- Command command = makeCommand(Impl::Compositor::sendDataDeviceLeave, m_compositor);
- command.parameters << QVariant::fromValue(surface);
- processCommand(command);
-}
-
-void MockCompositor::sendAddOutput()
-{
- Command command = makeCommand(Impl::Compositor::sendAddOutput, m_compositor);
- processCommand(command);
-}
-
-void MockCompositor::sendRemoveOutput(const QSharedPointer<MockOutput> &output)
-{
- Command command = makeCommand(Impl::Compositor::sendRemoveOutput, m_compositor);
- command.parameters << QVariant::fromValue(output);
- processCommand(command);
-}
-
-void MockCompositor::sendOutputGeometry(const QSharedPointer<MockOutput> &output, const QRect &geometry)
-{
- Command command = makeCommand(Impl::Compositor::sendOutputGeometry, m_compositor);
- command.parameters << QVariant::fromValue(output);
- command.parameters << QVariant::fromValue(geometry);
- processCommand(command);
-}
-
-void MockCompositor::sendSurfaceEnter(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output)
-{
- Command command = makeCommand(Impl::Compositor::sendSurfaceEnter, m_compositor);
- command.parameters << QVariant::fromValue(surface);
- command.parameters << QVariant::fromValue(output);
- processCommand(command);
-}
-
-void MockCompositor::sendSurfaceLeave(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output)
-{
- Command command = makeCommand(Impl::Compositor::sendSurfaceLeave, m_compositor);
- command.parameters << QVariant::fromValue(surface);
- command.parameters << QVariant::fromValue(output);
- processCommand(command);
-}
-
-void MockCompositor::sendShellSurfaceConfigure(const QSharedPointer<MockSurface> surface, const QSize &size)
-{
- Command command = makeCommand(Impl::Compositor::sendShellSurfaceConfigure, m_compositor);
- command.parameters << QVariant::fromValue(surface);
- command.parameters << QVariant::fromValue(size);
- processCommand(command);
-}
-
-void MockCompositor::sendIviSurfaceConfigure(const QSharedPointer<MockIviSurface> iviSurface, const QSize &size)
-{
- Command command = makeCommand(Impl::Compositor::sendIviSurfaceConfigure, m_compositor);
- command.parameters << QVariant::fromValue(iviSurface);
- command.parameters << QVariant::fromValue(size);
- processCommand(command);
-}
-
-void MockCompositor::sendXdgToplevelV6Configure(const QSharedPointer<MockXdgToplevelV6> toplevel, const QSize &size, const QVector<uint> &states)
-{
- Command command = makeCommand(Impl::Compositor::sendXdgToplevelV6Configure, m_compositor);
- command.parameters << QVariant::fromValue(toplevel);
- command.parameters << QVariant::fromValue(size);
- QByteArray statesBytes(reinterpret_cast<const char *>(states.data()),
- states.size() * static_cast<int>(sizeof(uint)));
- command.parameters << statesBytes;
- processCommand(command);
-}
-
-void MockCompositor::waitForStartDrag()
-{
- Command command = makeCommand(Impl::Compositor::waitForStartDrag, m_compositor);
- processCommand(command);
-}
-
-QSharedPointer<MockSurface> MockCompositor::surface()
-{
- QSharedPointer<MockSurface> result;
- lock();
- QVector<Impl::Surface *> surfaces = m_compositor->surfaces();
- foreach (Impl::Surface *surface, surfaces) {
- // we don't want to mistake the cursor surface for a window surface
- if (surface->isMapped()) {
- result = surface->mockSurface();
- break;
- }
- }
- unlock();
- return result;
-}
-
-QSharedPointer<MockOutput> MockCompositor::output(int index)
-{
- QSharedPointer<MockOutput> result;
- lock();
- if (Impl::Output *output = m_compositor->outputs().value(index, nullptr))
- result = output->mockOutput();
- unlock();
- return result;
-}
-
-QSharedPointer<MockIviSurface> MockCompositor::iviSurface(int index)
-{
- QSharedPointer<MockIviSurface> result;
- lock();
- if (Impl::IviSurface *toplevel = m_compositor->iviApplication()->iviSurfaces().value(index, nullptr))
- result = toplevel->mockIviSurface();
- unlock();
- return result;
-}
-
-QSharedPointer<MockXdgToplevelV6> MockCompositor::xdgToplevelV6(int index)
-{
- QSharedPointer<MockXdgToplevelV6> result;
- lock();
- if (Impl::XdgToplevelV6 *toplevel = m_compositor->xdgShellV6()->toplevels().value(index, nullptr))
- result = toplevel->mockToplevel();
- unlock();
- return result;
-}
-
-MockCompositor::Command MockCompositor::makeCommand(Command::Callback callback, void *target)
-{
- Command command;
- command.callback = callback;
- command.target = target;
- return command;
-}
-
-void MockCompositor::processCommand(const Command &command)
-{
- lock();
- m_commandQueue << command;
- unlock();
-
- m_waitCondition.wakeOne();
-}
-
-void MockCompositor::dispatchCommands()
-{
- lock();
- int count = m_commandQueue.length();
- unlock();
-
- for (int i = 0; i < count; ++i) {
- lock();
- const Command command = m_commandQueue.takeFirst();
- unlock();
- command.callback(command.target, command.parameters);
- }
-}
-
-void *MockCompositor::run(void *data)
-{
- MockCompositor *controller = static_cast<MockCompositor *>(data);
-
- Impl::Compositor compositor;
-
- controller->m_compositor = &compositor;
- controller->m_waitCondition.wakeOne();
-
- while (!controller->m_ready) {
- controller->dispatchCommands();
- compositor.dispatchEvents(20);
- }
-
- while (controller->m_alive) {
- {
- QMutexLocker locker(&controller->m_mutex);
- if (controller->m_commandQueue.isEmpty())
- controller->m_waitCondition.wait(&controller->m_mutex);
- }
- controller->dispatchCommands();
- compositor.dispatchEvents(20);
- }
-
- return 0;
-}
-
-namespace Impl {
-
-Compositor::Compositor()
- : m_display(wl_display_create())
-{
- if (wl_display_add_socket(m_display, 0)) {
- fprintf(stderr, "Fatal: Failed to open server socket\n");
- exit(EXIT_FAILURE);
+namespace MockCompositor {
+
+DefaultCompositor::DefaultCompositor()
+{
+ {
+ Lock l(this);
+
+ // Globals: Should ideally always be at least the latest versions we support.
+ // Legacy versions can override in separate tests by removing and adding.
+ add<WlCompositor>();
+ add<SubCompositor>();
+ add<Output>();
+ add<Seat>(Seat::capability_pointer);
+ add<XdgWmBase>();
+ add<Shm>();
+ // TODO: other shells, viewporter, xdgoutput etc
+
+ QObject::connect(get<WlCompositor>(), &WlCompositor::surfaceCreated, [&] (Surface *surface){
+ QObject::connect(surface, &Surface::bufferCommitted, [=] {
+ if (m_config.autoRelease) {
+ // Pretend we made a copy of the buffer and just release it immediately
+ surface->m_committed.buffer->send_release();
+ }
+ if (m_config.autoEnter && surface->m_outputs.empty())
+ surface->sendEnter(get<Output>());
+ wl_display_flush_clients(m_display);
+ });
+ });
+
+ QObject::connect(get<XdgWmBase>(), &XdgWmBase::toplevelCreated, [&] (XdgToplevel *toplevel) {
+ // Needed because lambdas don't support Qt::DirectConnection
+ exec([&]{
+ if (m_config.autoConfigure)
+ toplevel->sendCompleteConfigure();
+ });
+ });
}
-
- wl_global_create(m_display, &wl_compositor_interface, 1, this, bindCompositor);
-
- m_data_device_manager.reset(new DataDeviceManager(this, m_display));
-
- wl_display_init_shm(m_display);
-
- m_seat.reset(new Seat(this, m_display));
- m_pointer = m_seat->pointer();
- m_keyboard = m_seat->keyboard();
- m_touch = m_seat->touch();
-
- m_outputs.append(new Output(m_display, QSize(1920, 1080), QPoint(0, 0)));
- m_iviApplication.reset(new IviApplication(m_display));
- m_wlShell.reset(new WlShell(m_display));
- m_xdgShellV6.reset(new XdgShellV6(m_display));
-
- m_loop = wl_display_get_event_loop(m_display);
- m_fd = wl_event_loop_get_fd(m_loop);
-}
-
-Compositor::~Compositor()
-{
- wl_display_destroy(m_display);
+ Q_ASSERT(isClean());
}
-void Compositor::dispatchEvents(int timeout)
+uint DefaultCompositor::sendXdgShellPing()
{
- wl_display_flush_clients(m_display);
- wl_event_loop_dispatch(m_loop, timeout);
+ warnIfNotLockedByThread(Q_FUNC_INFO);
+ uint serial = nextSerial();
+ auto *base = get<XdgWmBase>();
+ const auto resourceMap = base->resourceMap();
+ Q_ASSERT(resourceMap.size() == 1); // binding more than once shouldn't be needed
+ base->send_ping(resourceMap.first()->handle, serial);
+ return serial;
}
-static void compositor_create_surface(wl_client *client, wl_resource *compositorResource, uint32_t id)
+void DefaultCompositor::xdgPingAndWaitForPong()
{
- Compositor *compositor = static_cast<Compositor *>(wl_resource_get_user_data(compositorResource));
- compositor->addSurface(new Surface(client, id, wl_resource_get_version(compositorResource), compositor));
+ QSignalSpy pongSpy(exec([=] { return get<XdgWmBase>(); }), &XdgWmBase::pong);
+ uint serial = exec([=] { return sendXdgShellPing(); });
+ QTRY_COMPARE(pongSpy.count(), 1);
+ QTRY_COMPARE(pongSpy.first().at(0).toUInt(), serial);
}
-static void compositor_create_region(wl_client *client, wl_resource *compositorResource, uint32_t id)
-{
- Q_UNUSED(client);
- Q_UNUSED(compositorResource);
- Q_UNUSED(id);
-}
-
-void Compositor::bindCompositor(wl_client *client, void *compositorData, uint32_t version, uint32_t id)
-{
- static const struct wl_compositor_interface compositorInterface = {
- compositor_create_surface,
- compositor_create_region
- };
-
- wl_resource *resource = wl_resource_create(client, &wl_compositor_interface, static_cast<int>(version), id);
- wl_resource_set_implementation(resource, &compositorInterface, compositorData, nullptr);
-}
-
-static void unregisterResourceCallback(wl_listener *listener, void *data)
-{
- struct wl_resource *resource = reinterpret_cast<struct wl_resource *>(data);
- wl_list_remove(wl_resource_get_link(resource));
- delete listener;
-}
-
-void registerResource(wl_list *list, wl_resource *resource)
-{
- wl_list_insert(list, wl_resource_get_link(resource));
-
- wl_listener *listener = new wl_listener;
- listener->notify = unregisterResourceCallback;
-
- wl_resource_add_destroy_listener(resource, listener);
-}
-
-QVector<Surface *> Compositor::surfaces() const
-{
- return m_surfaces;
-}
-
-QVector<Output *> Compositor::outputs() const
-{
- return m_outputs;
-}
-
-IviApplication *Compositor::iviApplication() const
-{
- return m_iviApplication.data();
-}
-
-XdgShellV6 *Compositor::xdgShellV6() const
-{
- return m_xdgShellV6.data();
-}
-
-uint32_t Compositor::nextSerial()
-{
- return wl_display_next_serial(m_display);
-}
-
-void Compositor::addSurface(Surface *surface)
-{
- m_surfaces << surface;
-}
-
-void Compositor::removeSurface(Surface *surface)
-{
- m_surfaces.removeOne(surface);
- m_keyboard->handleSurfaceDestroyed(surface);
- m_pointer->handleSurfaceDestroyed(surface);
-}
-
-Surface *Compositor::resolveSurface(const QVariant &v)
-{
- QSharedPointer<MockSurface> mockSurface = v.value<QSharedPointer<MockSurface> >();
- return mockSurface ? mockSurface->handle() : nullptr;
-}
-
-Output *Compositor::resolveOutput(const QVariant &v)
-{
- QSharedPointer<MockOutput> mockOutput = v.value<QSharedPointer<MockOutput> >();
- return mockOutput ? mockOutput->handle() : nullptr;
-}
-
-IviSurface *Compositor::resolveIviSurface(const QVariant &v)
-{
- QSharedPointer<MockIviSurface> mockIviSurface = v.value<QSharedPointer<MockIviSurface>>();
- return mockIviSurface ? mockIviSurface->handle() : nullptr;
-}
-
-XdgToplevelV6 *Compositor::resolveToplevel(const QVariant &v)
-{
- QSharedPointer<MockXdgToplevelV6> mockToplevel = v.value<QSharedPointer<MockXdgToplevelV6>>();
- return mockToplevel ? mockToplevel->handle() : nullptr;
-}
-
-}
+} // namespace MockCompositor
diff --git a/tests/auto/client/shared/mockcompositor.h b/tests/auto/client/shared/mockcompositor.h
index 51b6f4bfb..07366a493 100644
--- a/tests/auto/client/shared/mockcompositor.h
+++ b/tests/auto/client/shared/mockcompositor.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
@@ -29,259 +29,55 @@
#ifndef MOCKCOMPOSITOR_H
#define MOCKCOMPOSITOR_H
-#include "mockxdgshellv6.h"
-#include "mockiviapplication.h"
+#include "corecompositor.h"
+#include "coreprotocol.h"
+#include "xdgshell.h"
-#include <pthread.h>
-#include <qglobal.h>
-#include <wayland-server.h>
+#include <QtGui/QGuiApplication>
-#include <QImage>
-#include <QMutex>
-#include <QRect>
-#include <QSharedPointer>
-#include <QVariant>
-#include <QVector>
-#include <QWaitCondition>
-
-namespace Impl {
-
-typedef void (**Implementation)(void);
-
-class Keyboard;
-class Pointer;
-class Touch;
-class Seat;
-class DataDeviceManager;
-class Surface;
-class Output;
-class IviApplication;
-class WlShell;
-class XdgShellV6;
-
-class Compositor
-{
-public:
- Compositor();
- ~Compositor();
-
- int fileDescriptor() const { return m_fd; }
- void dispatchEvents(int timeout = 0);
-
- uint32_t nextSerial();
- uint32_t time() { return ++m_time; }
-
- QVector<Surface *> surfaces() const;
- QVector<Output *> outputs() const;
-
- IviApplication *iviApplication() const;
- XdgShellV6 *xdgShellV6() const;
-
- void addSurface(Surface *surface);
- void removeSurface(Surface *surface);
-
- static void setKeyboardFocus(void *data, const QList<QVariant> &parameters);
- static void sendMousePress(void *data, const QList<QVariant> &parameters);
- static void sendMouseRelease(void *data, const QList<QVariant> &parameters);
- static void sendKeyPress(void *data, const QList<QVariant> &parameters);
- static void sendKeyRelease(void *data, const QList<QVariant> &parameters);
- static void sendTouchDown(void *data, const QList<QVariant> &parameters);
- static void sendTouchUp(void *data, const QList<QVariant> &parameters);
- static void sendTouchMotion(void *data, const QList<QVariant> &parameters);
- static void sendTouchFrame(void *data, const QList<QVariant> &parameters);
- static void sendDataDeviceDataOffer(void *data, const QList<QVariant> &parameters);
- static void sendDataDeviceEnter(void *data, const QList<QVariant> &parameters);
- static void sendDataDeviceMotion(void *data, const QList<QVariant> &parameters);
- static void sendDataDeviceDrop(void *data, const QList<QVariant> &parameters);
- static void sendDataDeviceLeave(void *data, const QList<QVariant> &parameters);
- static void waitForStartDrag(void *data, const QList<QVariant> &parameters);
- static void setOutputMode(void *compositor, const QList<QVariant> &parameters);
- static void sendAddOutput(void *data, const QList<QVariant> &parameters);
- static void sendRemoveOutput(void *data, const QList<QVariant> &parameters);
- static void sendOutputGeometry(void *data, const QList<QVariant> &parameters);
- static void sendSurfaceEnter(void *data, const QList<QVariant> &parameters);
- static void sendSurfaceLeave(void *data, const QList<QVariant> &parameters);
- static void sendShellSurfaceConfigure(void *data, const QList<QVariant> &parameters);
- static void sendIviSurfaceConfigure(void *data, const QList<QVariant> &parameters);
- static void sendXdgToplevelV6Configure(void *data, const QList<QVariant> &parameters);
-
-public:
- bool m_startDragSeen = false;
-
-private:
- static void bindCompositor(wl_client *client, void *data, uint32_t version, uint32_t id);
- static Surface *resolveSurface(const QVariant &v);
- static Output *resolveOutput(const QVariant &v);
- static IviSurface *resolveIviSurface(const QVariant &v);
- static XdgToplevelV6 *resolveToplevel(const QVariant &v);
-
- void initShm();
-
- QRect m_outputGeometry;
-
- wl_display *m_display = nullptr;
- wl_event_loop *m_loop = nullptr;
- wl_shm *m_shm = nullptr;
- int m_fd = -1;
-
- uint32_t m_time = 0;
-
- QScopedPointer<Seat> m_seat;
- Pointer *m_pointer = nullptr;
- Keyboard *m_keyboard = nullptr;
- Touch *m_touch = nullptr;
- QScopedPointer<DataDeviceManager> m_data_device_manager;
- QVector<Surface *> m_surfaces;
- QVector<Output *> m_outputs;
- QScopedPointer<IviApplication> m_iviApplication;
- QScopedPointer<WlShell> m_wlShell;
- QScopedPointer<XdgShellV6> m_xdgShellV6;
-};
-
-void registerResource(wl_list *list, wl_resource *resource);
-
-}
-
-class MockSurface
-{
-public:
- Impl::Surface *handle() const { return m_surface; }
-
- QImage image;
-
-private:
- MockSurface(Impl::Surface *surface);
- friend class Impl::Compositor;
- friend class Impl::Surface;
-
- Impl::Surface *m_surface = nullptr;
-};
-
-Q_DECLARE_METATYPE(QSharedPointer<MockSurface>)
-
-class MockIviSurface
-{
-public:
- Impl::IviSurface *handle() const { return m_iviSurface; }
- const uint iviId;
-
-private:
- MockIviSurface(Impl::IviSurface *iviSurface) : iviId(iviSurface->iviId()), m_iviSurface(iviSurface) {}
- friend class Impl::Compositor;
- friend class Impl::IviSurface;
-
- Impl::IviSurface *m_iviSurface;
-};
+#ifndef BTN_LEFT
+// As defined in linux/input-event-codes.h
+#define BTN_LEFT 0x110
+#endif
-Q_DECLARE_METATYPE(QSharedPointer<MockIviSurface>)
+namespace MockCompositor {
-class MockXdgToplevelV6 : public QObject
+class DefaultCompositor : public CoreCompositor
{
- Q_OBJECT
-public:
- Impl::XdgToplevelV6 *handle() const { return m_toplevel; }
-
- void sendConfigure(const QSharedPointer<MockXdgToplevelV6> toplevel);
-
-signals:
- uint setMinimizedRequested();
- uint setMaximizedRequested();
- uint unsetMaximizedRequested();
- uint setFullscreenRequested();
- uint unsetFullscreenRequested();
- void windowGeometryRequested(QRect geometry); // NOTE: This is really an xdg surface event
-
-private:
- MockXdgToplevelV6(Impl::XdgToplevelV6 *toplevel) : m_toplevel(toplevel) {}
- friend class Impl::Compositor;
- friend class Impl::XdgToplevelV6;
-
- Impl::XdgToplevelV6 *m_toplevel;
-};
-
-Q_DECLARE_METATYPE(QSharedPointer<MockXdgToplevelV6>)
-
-class MockOutput {
public:
- Impl::Output *handle() const { return m_output; }
- MockOutput(Impl::Output *output);
-private:
- Impl::Output *m_output = nullptr;
+ explicit DefaultCompositor();
+ // Convenience functions
+ Surface *surface(int i = 0) { return get<WlCompositor>()->m_surfaces.value(i, nullptr); }
+ XdgSurface *xdgSurface(int i = 0) { return get<XdgWmBase>()->m_xdgSurfaces.value(i, nullptr); }
+ XdgToplevel *xdgToplevel(int i = 0) { return get<XdgWmBase>()->toplevel(i); }
+ XdgPopup *xdgPopup(int i = 0) { return get<XdgWmBase>()->popup(i); }
+ Pointer *pointer() { auto *seat = get<Seat>(); Q_ASSERT(seat); return seat->m_pointer; }
+ uint sendXdgShellPing();
+ void xdgPingAndWaitForPong();
+ // Things that can be changed run-time without confusing the client (i.e. don't require separate tests)
+ struct Config {
+ bool autoEnter = true;
+ bool autoRelease = true;
+ bool autoConfigure = false;
+ } m_config;
+ void resetConfig() { exec([&] { m_config = Config{}; }); }
};
-Q_DECLARE_METATYPE(QSharedPointer<MockOutput>)
-
-class MockCompositor
-{
-public:
- MockCompositor();
- ~MockCompositor();
-
- void applicationInitialized();
-
- int waylandFileDescriptor() const;
- void processWaylandEvents();
-
- void setOutputMode(const QSize &size);
- void setKeyboardFocus(const QSharedPointer<MockSurface> &surface);
- void sendMousePress(const QSharedPointer<MockSurface> &surface, const QPoint &pos);
- void sendMouseRelease(const QSharedPointer<MockSurface> &surface);
- void sendKeyPress(const QSharedPointer<MockSurface> &surface, uint code);
- void sendKeyRelease(const QSharedPointer<MockSurface> &surface, uint code);
- void sendTouchDown(const QSharedPointer<MockSurface> &surface, const QPoint &position, int id);
- void sendTouchMotion(const QSharedPointer<MockSurface> &surface, const QPoint &position, int id);
- void sendTouchUp(const QSharedPointer<MockSurface> &surface, int id);
- void sendTouchFrame(const QSharedPointer<MockSurface> &surface);
- void sendDataDeviceDataOffer(const QSharedPointer<MockSurface> &surface);
- void sendDataDeviceEnter(const QSharedPointer<MockSurface> &surface, const QPoint &position);
- void sendDataDeviceMotion(const QPoint &position);
- void sendDataDeviceDrop(const QSharedPointer<MockSurface> &surface);
- void sendDataDeviceLeave(const QSharedPointer<MockSurface> &surface);
- void sendAddOutput();
- void sendRemoveOutput(const QSharedPointer<MockOutput> &output);
- void sendOutputGeometry(const QSharedPointer<MockOutput> &output, const QRect &geometry);
- void sendSurfaceEnter(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output);
- void sendSurfaceLeave(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output);
- void sendShellSurfaceConfigure(const QSharedPointer<MockSurface> surface, const QSize &size = QSize(0, 0));
- void sendIviSurfaceConfigure(const QSharedPointer<MockIviSurface> iviSurface, const QSize &size);
- void sendXdgToplevelV6Configure(const QSharedPointer<MockXdgToplevelV6> toplevel, const QSize &size = QSize(0, 0),
- const QVector<uint> &states = { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED });
- void waitForStartDrag();
-
- QSharedPointer<MockSurface> surface();
- QSharedPointer<MockOutput> output(int index = 0);
- QSharedPointer<MockIviSurface> iviSurface(int index = 0);
- QSharedPointer<MockXdgToplevelV6> xdgToplevelV6(int index = 0);
-
- void lock();
- void unlock();
-
-private:
- struct Command
- {
- typedef void (*Callback)(void *target, const QList<QVariant> &parameters);
-
- Callback callback;
- void *target = nullptr;
- QList<QVariant> parameters;
- };
-
- static Command makeCommand(Command::Callback callback, void *target);
-
- void processCommand(const Command &command);
- void dispatchCommands();
-
- static void *run(void *data);
-
- bool m_alive = true;
- bool m_ready = false;
- pthread_t m_thread;
- QMutex m_mutex;
- QWaitCondition m_waitCondition;
-
- Impl::Compositor *m_compositor = nullptr;
-
- QList<Command> m_commandQueue;
-};
+} // namespace MockCompositor
+
+#define QCOMPOSITOR_VERIFY(expr) QVERIFY(exec([&]{ return expr; }))
+#define QCOMPOSITOR_TRY_VERIFY(expr) QTRY_VERIFY(exec([&]{ return expr; }))
+#define QCOMPOSITOR_COMPARE(expr, expr2) QCOMPARE(exec([&]{ return expr; }), expr2)
+#define QCOMPOSITOR_TRY_COMPARE(expr, expr2) QTRY_COMPARE(exec([&]{ return expr; }), expr2)
+
+#define QCOMPOSITOR_TEST_MAIN(test) \
+int main(int argc, char **argv) \
+{ \
+ setenv("XDG_RUNTIME_DIR", ".", 1); \
+ setenv("QT_QPA_PLATFORM", "wayland", 1); \
+ test tc; \
+ QGuiApplication app(argc, argv); \
+ return QTest::qExec(&tc, argc, argv); \
+} \
#endif
diff --git a/tests/auto/client/shared/shared.pri b/tests/auto/client/shared/shared.pri
index f3cb4d5a2..3376c73bc 100644
--- a/tests/auto/client/shared/shared.pri
+++ b/tests/auto/client/shared/shared.pri
@@ -1,31 +1,21 @@
-CONFIG += testcase link_pkgconfig
-QT += testlib
-QT += core-private gui-private waylandclient-private
+QT += testlib waylandclient-private
+CONFIG += testcase wayland-scanner
+QMAKE_USE += wayland-server
-QMAKE_USE += wayland-client wayland-server
-
-CONFIG += wayland-scanner
WAYLANDSERVERSOURCES += \
- ../../../../src/3rdparty/protocol/ivi-application.xml \
- ../../../../src/3rdparty/protocol/wayland.xml \
- ../../../../src/3rdparty/protocol/xdg-shell-unstable-v6.xml
+ $$PWD/../../../../src/3rdparty/protocol/wayland.xml \
+ $$PWD/../../../../src/3rdparty/protocol/xdg-shell.xml
INCLUDEPATH += ../shared
-SOURCES += \
- ../shared/mockcompositor.cpp \
- ../shared/mockinput.cpp \
- ../shared/mockiviapplication.cpp \
- ../shared/mockwlshell.cpp \
- ../shared/mockxdgshellv6.cpp \
- ../shared/mocksurface.cpp \
- ../shared/mockoutput.cpp
-
HEADERS += \
- ../shared/mockcompositor.h \
- ../shared/mockinput.h \
- ../shared/mockiviapplication.h \
- ../shared/mockwlshell.h \
- ../shared/mockxdgshellv6.h \
- ../shared/mocksurface.h \
- ../shared/mockoutput.h
+ $$PWD/corecompositor.h \
+ $$PWD/coreprotocol.h \
+ $$PWD/mockcompositor.h \
+ $$PWD/xdgshell.h
+
+SOURCES += \
+ $$PWD/corecompositor.cpp \
+ $$PWD/coreprotocol.cpp \
+ $$PWD/mockcompositor.cpp \
+ $$PWD/xdgshell.cpp
diff --git a/tests/auto/client/shared/xdgshell.cpp b/tests/auto/client/shared/xdgshell.cpp
new file mode 100644
index 000000000..ebbcc2942
--- /dev/null
+++ b/tests/auto/client/shared/xdgshell.cpp
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** 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 "xdgshell.h"
+
+namespace MockCompositor {
+
+XdgWmBase::XdgWmBase(CoreCompositor *compositor, int version)
+ : QtWaylandServer::xdg_wm_base(compositor->m_display, version)
+ , m_compositor(compositor)
+{
+}
+
+XdgToplevel *XdgWmBase::toplevel(int i)
+{
+ int j = 0;
+ for (auto *xdgSurface : qAsConst(m_xdgSurfaces)) {
+ if (auto *toplevel = xdgSurface->m_toplevel) {
+ if (j == i)
+ return toplevel;
+ ++j;
+ }
+ }
+ return nullptr;
+}
+
+XdgPopup *XdgWmBase::popup(int i)
+{
+ int j = 0;
+ for (auto *xdgSurface : qAsConst(m_xdgSurfaces)) {
+ if (auto *popup = xdgSurface->m_popup) {
+ if (j == i)
+ return popup;
+ ++j;
+ }
+ }
+ return nullptr;
+}
+
+void XdgWmBase::xdg_wm_base_get_xdg_surface(Resource *resource, uint32_t id, wl_resource *surface)
+{
+ auto *s = fromResource<Surface>(surface);
+ auto *xdgSurface = new XdgSurface(this, s, resource->client(), id, resource->version());
+ m_xdgSurfaces << xdgSurface;
+ emit xdgSurfaceCreated(xdgSurface);
+}
+
+void XdgWmBase::xdg_wm_base_pong(Resource *resource, uint32_t serial)
+{
+ Q_UNUSED(resource);
+ emit pong(serial);
+}
+
+XdgSurface::XdgSurface(XdgWmBase *xdgWmBase, Surface *surface, wl_client *client, int id, int version)
+ : QtWaylandServer::xdg_surface(client, id, version)
+ , m_xdgWmBase(xdgWmBase)
+ , m_surface(surface)
+{
+ QVERIFY(!surface->m_pending.buffer);
+ QVERIFY(!surface->m_committed.buffer);
+ connect(this, &XdgSurface::toplevelCreated, xdgWmBase, &XdgWmBase::toplevelCreated);
+ connect(surface, &Surface::attach, this, &XdgSurface::verifyConfigured);
+ connect(surface, &Surface::commit, this, [this] {
+ if (m_ackedConfigureSerial != m_committedConfigureSerial) {
+ m_committedConfigureSerial = m_ackedConfigureSerial;
+ emit configureCommitted(m_committedConfigureSerial);
+ }
+ });
+}
+
+void XdgSurface::sendConfigure(uint serial)
+{
+ Q_ASSERT(serial);
+ m_pendingConfigureSerials.append(serial);
+ m_configureSent = true;
+ xdg_surface::send_configure(serial);
+}
+
+uint XdgSurface::sendConfigure()
+{
+ const uint serial = m_xdgWmBase->m_compositor->nextSerial();
+ sendConfigure(serial);
+ return serial;
+}
+
+void XdgSurface::xdg_surface_get_toplevel(Resource *resource, uint32_t id)
+{
+ QVERIFY(!m_toplevel);
+ QVERIFY(!m_popup);
+ m_toplevel = new XdgToplevel(this, id, resource->version());
+ emit toplevelCreated(m_toplevel);
+}
+
+void XdgSurface::xdg_surface_get_popup(Resource *resource, uint32_t id, wl_resource *parent, wl_resource *positioner)
+{
+ Q_UNUSED(parent);
+ Q_UNUSED(positioner);
+ QVERIFY(!m_toplevel);
+ QVERIFY(!m_popup);
+ m_popup = new XdgPopup(this, id, resource->version());
+}
+
+void XdgSurface::xdg_surface_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource);
+ bool removed = m_xdgWmBase->m_xdgSurfaces.removeOne(this);
+ Q_ASSERT(removed);
+ delete this;
+}
+
+void XdgSurface::xdg_surface_ack_configure(Resource *resource, uint32_t serial)
+{
+ Q_UNUSED(resource);
+ QVERIFY2(m_pendingConfigureSerials.contains(serial), qPrintable(QString::number(serial)));
+ m_ackedConfigureSerial = serial;
+ while (!m_pendingConfigureSerials.empty()) {
+ uint s = m_pendingConfigureSerials.takeFirst();
+ if (s == serial)
+ return;
+ }
+}
+
+XdgToplevel::XdgToplevel(XdgSurface *xdgSurface, int id, int version)
+ : QtWaylandServer::xdg_toplevel(xdgSurface->resource()->client(), id, version)
+ , m_xdgSurface(xdgSurface)
+{
+}
+
+void XdgToplevel::sendConfigure(const QSize &size, const QVector<uint> &states)
+{
+ send_configure(size.width(), size.height(), toByteArray(states));
+}
+
+uint XdgToplevel::sendCompleteConfigure(const QSize &size, const QVector<uint> &states)
+{
+ sendConfigure(size, states);
+ return m_xdgSurface->sendConfigure();
+}
+
+XdgPopup::XdgPopup(XdgSurface *xdgSurface, int id, int version)
+ : QtWaylandServer::xdg_popup(xdgSurface->resource()->client(), id, version)
+ , m_xdgSurface(xdgSurface)
+{
+}
+
+void XdgPopup::sendConfigure(const QRect &geometry)
+{
+ send_configure(geometry.x(), geometry.y(), geometry.width(), geometry.height());
+}
+
+void XdgPopup::xdg_popup_grab(QtWaylandServer::xdg_popup::Resource *resource, wl_resource *seat, uint32_t serial)
+{
+ Q_UNUSED(resource);
+ Q_UNUSED(seat); // TODO: verify correct seat as well
+ //TODO: verify no other popup has grabbed
+ QVERIFY(!m_grabbed);
+ m_grabbed = true;
+ m_grabSerial = serial;
+}
+
+} // namespace MockCompositor
diff --git a/tests/auto/client/shared/xdgshell.h b/tests/auto/client/shared/xdgshell.h
new file mode 100644
index 000000000..3fcec7983
--- /dev/null
+++ b/tests/auto/client/shared/xdgshell.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** 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 MOCKCOMPOSITOR_XDGSHELL_H
+#define MOCKCOMPOSITOR_XDGSHELL_H
+
+#include "coreprotocol.h"
+#include <qwayland-server-xdg-shell.h>
+
+namespace MockCompositor {
+
+class XdgSurface;
+class XdgToplevel;
+class XdgPopup;
+using XdgPositioner = QtWaylandServer::xdg_positioner;
+
+class XdgWmBase : public Global, public QtWaylandServer::xdg_wm_base
+{
+ Q_OBJECT
+public:
+ explicit XdgWmBase(CoreCompositor *compositor, int version = 1);
+ using QtWaylandServer::xdg_wm_base::send_ping;
+ void send_ping(uint32_t) = delete; // It's a global, use resource specific instead
+ bool isClean() override { return m_xdgSurfaces.empty(); }
+ QString dirtyMessage() override { return m_xdgSurfaces.empty() ? "clean" : "remaining xdg surfaces"; }
+ QVector<XdgSurface *> m_xdgSurfaces;
+ XdgToplevel *toplevel(int i = 0);
+ XdgPopup *popup(int i = 0);
+ CoreCompositor *m_compositor = nullptr;
+
+signals:
+ void pong(uint serial);
+ void xdgSurfaceCreated(XdgSurface *xdgSurface);
+ void toplevelCreated(XdgToplevel *toplevel);
+
+protected:
+ void xdg_wm_base_get_xdg_surface(Resource *resource, uint32_t id, ::wl_resource *surface) override;
+ void xdg_wm_base_pong(Resource *resource, uint32_t serial) override;
+ void xdg_wm_base_create_positioner(Resource *resource, uint32_t id) override
+ {
+ new XdgPositioner(resource->client(), id, resource->version());
+ }
+};
+
+class XdgSurface : public QObject, public QtWaylandServer::xdg_surface
+{
+ Q_OBJECT
+public:
+ explicit XdgSurface(XdgWmBase *xdgWmBase, Surface *surface, wl_client *client, int id, int version);
+ void send_configure(uint serial) = delete; // Use the one below instead, as it tracks state
+ void sendConfigure(uint serial);
+ uint sendConfigure();
+ XdgToplevel *m_toplevel = nullptr;
+ XdgPopup *m_popup = nullptr;
+ XdgWmBase *m_xdgWmBase = nullptr;
+ Surface *m_surface = nullptr;
+ bool m_configureSent = false;
+ QVector<uint> m_pendingConfigureSerials;
+ uint m_ackedConfigureSerial = 0;
+ uint m_committedConfigureSerial = 0;
+
+public slots:
+ void verifyConfigured() { QVERIFY(m_configureSent); }
+
+signals:
+ void configureCommitted(uint);
+ void toplevelCreated(XdgToplevel *toplevel);
+
+protected:
+ void xdg_surface_get_toplevel(Resource *resource, uint32_t id) override;
+ void xdg_surface_get_popup(Resource *resource, uint32_t id, ::wl_resource *parent, ::wl_resource *positioner) override;
+ void xdg_surface_destroy_resource(Resource *resource) override;
+ void xdg_surface_destroy(Resource *resource) override { wl_resource_destroy(resource->handle); }
+ void xdg_surface_ack_configure(Resource *resource, uint32_t serial) override;
+};
+
+class XdgToplevel : public QtWaylandServer::xdg_toplevel
+{
+public:
+ explicit XdgToplevel(XdgSurface *xdgSurface, int id, int version = 1);
+ void sendConfigure(const QSize &size = {0, 0}, const QVector<uint> &states = {});
+ uint sendCompleteConfigure(const QSize &size = {0, 0}, const QVector<uint> &states = {});
+ Surface *surface() { return m_xdgSurface->m_surface; }
+ XdgSurface *m_xdgSurface = nullptr;
+};
+
+class XdgPopup : public QtWaylandServer::xdg_popup
+{
+public:
+ explicit XdgPopup(XdgSurface *xdgSurface, int id, int version = 1);
+ void sendConfigure(const QRect &geometry);
+ Surface *surface() { return m_xdgSurface->m_surface; }
+ XdgSurface *m_xdgSurface = nullptr;
+ bool m_grabbed = false;
+ uint m_grabSerial = 0;
+protected:
+ void xdg_popup_grab(Resource *resource, ::wl_resource *seat, uint32_t serial) override;
+};
+
+} // namespace MockCompositor
+
+#endif // MOCKCOMPOSITOR_XDGSHELL_H
diff --git a/tests/auto/client/shared_old/mockcompositor.cpp b/tests/auto/client/shared_old/mockcompositor.cpp
new file mode 100644
index 000000000..df24b4091
--- /dev/null
+++ b/tests/auto/client/shared_old/mockcompositor.cpp
@@ -0,0 +1,520 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** 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 "mockcompositor.h"
+#include "mockinput.h"
+#include "mockoutput.h"
+#include "mocksurface.h"
+#include "mockwlshell.h"
+#include "mockxdgshellv6.h"
+#include "mockiviapplication.h"
+
+#include <wayland-xdg-shell-unstable-v6-server-protocol.h>
+
+#include <stdio.h>
+MockCompositor::MockCompositor()
+{
+ pthread_create(&m_thread, 0, run, this);
+
+ m_mutex.lock();
+ m_waitCondition.wait(&m_mutex);
+ m_mutex.unlock();
+}
+
+MockCompositor::~MockCompositor()
+{
+ m_alive = false;
+ m_waitCondition.wakeOne();
+ pthread_join(m_thread, 0);
+}
+
+void MockCompositor::lock()
+{
+ m_mutex.lock();
+}
+
+void MockCompositor::unlock()
+{
+ m_mutex.unlock();
+}
+
+void MockCompositor::applicationInitialized()
+{
+ m_ready = true;
+}
+
+int MockCompositor::waylandFileDescriptor() const
+{
+ return m_compositor->fileDescriptor();
+}
+
+void MockCompositor::processWaylandEvents()
+{
+ m_waitCondition.wakeOne();
+}
+
+void MockCompositor::setOutputMode(const QSize &size)
+{
+ Command command = makeCommand(Impl::Compositor::setOutputMode, m_compositor);
+ command.parameters << size;
+ processCommand(command);
+}
+
+void MockCompositor::setKeyboardFocus(const QSharedPointer<MockSurface> &surface)
+{
+ Command command = makeCommand(Impl::Compositor::setKeyboardFocus, m_compositor);
+ command.parameters << QVariant::fromValue(surface);
+ processCommand(command);
+}
+
+void MockCompositor::sendMousePress(const QSharedPointer<MockSurface> &surface, const QPoint &pos)
+{
+ Command command = makeCommand(Impl::Compositor::sendMousePress, m_compositor);
+ command.parameters << QVariant::fromValue(surface) << pos;
+ processCommand(command);
+}
+
+void MockCompositor::sendMouseRelease(const QSharedPointer<MockSurface> &surface)
+{
+ Command command = makeCommand(Impl::Compositor::sendMouseRelease, m_compositor);
+ command.parameters << QVariant::fromValue(surface);
+ processCommand(command);
+}
+
+void MockCompositor::sendKeyPress(const QSharedPointer<MockSurface> &surface, uint code)
+{
+ Command command = makeCommand(Impl::Compositor::sendKeyPress, m_compositor);
+ command.parameters << QVariant::fromValue(surface) << code;
+ processCommand(command);
+}
+
+void MockCompositor::sendKeyRelease(const QSharedPointer<MockSurface> &surface, uint code)
+{
+ Command command = makeCommand(Impl::Compositor::sendKeyRelease, m_compositor);
+ command.parameters << QVariant::fromValue(surface) << code;
+ processCommand(command);
+}
+
+void MockCompositor::sendTouchDown(const QSharedPointer<MockSurface> &surface, const QPoint &position, int id)
+{
+ Command command = makeCommand(Impl::Compositor::sendTouchDown, m_compositor);
+ command.parameters << QVariant::fromValue(surface) << position << id;
+ processCommand(command);
+}
+
+void MockCompositor::sendTouchMotion(const QSharedPointer<MockSurface> &surface, const QPoint &position, int id)
+{
+ Command command = makeCommand(Impl::Compositor::sendTouchMotion, m_compositor);
+ command.parameters << QVariant::fromValue(surface) << position << id;
+ processCommand(command);
+}
+
+void MockCompositor::sendTouchUp(const QSharedPointer<MockSurface> &surface, int id)
+{
+ Command command = makeCommand(Impl::Compositor::sendTouchUp, m_compositor);
+ command.parameters << QVariant::fromValue(surface) << id;
+ processCommand(command);
+}
+
+void MockCompositor::sendTouchFrame(const QSharedPointer<MockSurface> &surface)
+{
+ Command command = makeCommand(Impl::Compositor::sendTouchFrame, m_compositor);
+ command.parameters << QVariant::fromValue(surface);
+ processCommand(command);
+}
+
+void MockCompositor::sendDataDeviceDataOffer(const QSharedPointer<MockSurface> &surface)
+{
+ Command command = makeCommand(Impl::Compositor::sendDataDeviceDataOffer, m_compositor);
+ command.parameters << QVariant::fromValue(surface);
+ processCommand(command);
+}
+
+void MockCompositor::sendDataDeviceEnter(const QSharedPointer<MockSurface> &surface, const QPoint& position)
+{
+ Command command = makeCommand(Impl::Compositor::sendDataDeviceEnter, m_compositor);
+ command.parameters << QVariant::fromValue(surface) << QVariant::fromValue(position);
+ processCommand(command);
+}
+
+void MockCompositor::sendDataDeviceMotion(const QPoint &position)
+{
+ Command command = makeCommand(Impl::Compositor::sendDataDeviceMotion, m_compositor);
+ command.parameters << QVariant::fromValue(position);
+ processCommand(command);
+}
+
+void MockCompositor::sendDataDeviceDrop(const QSharedPointer<MockSurface> &surface)
+{
+ Command command = makeCommand(Impl::Compositor::sendDataDeviceDrop, m_compositor);
+ command.parameters << QVariant::fromValue(surface);
+ processCommand(command);
+}
+
+void MockCompositor::sendDataDeviceLeave(const QSharedPointer<MockSurface> &surface)
+{
+ Command command = makeCommand(Impl::Compositor::sendDataDeviceLeave, m_compositor);
+ command.parameters << QVariant::fromValue(surface);
+ processCommand(command);
+}
+
+void MockCompositor::sendAddOutput()
+{
+ Command command = makeCommand(Impl::Compositor::sendAddOutput, m_compositor);
+ processCommand(command);
+}
+
+void MockCompositor::sendRemoveOutput(const QSharedPointer<MockOutput> &output)
+{
+ Command command = makeCommand(Impl::Compositor::sendRemoveOutput, m_compositor);
+ command.parameters << QVariant::fromValue(output);
+ processCommand(command);
+}
+
+void MockCompositor::sendOutputGeometry(const QSharedPointer<MockOutput> &output, const QRect &geometry)
+{
+ Command command = makeCommand(Impl::Compositor::sendOutputGeometry, m_compositor);
+ command.parameters << QVariant::fromValue(output);
+ command.parameters << QVariant::fromValue(geometry);
+ processCommand(command);
+}
+
+void MockCompositor::sendSurfaceEnter(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output)
+{
+ Command command = makeCommand(Impl::Compositor::sendSurfaceEnter, m_compositor);
+ command.parameters << QVariant::fromValue(surface);
+ command.parameters << QVariant::fromValue(output);
+ processCommand(command);
+}
+
+void MockCompositor::sendSurfaceLeave(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output)
+{
+ Command command = makeCommand(Impl::Compositor::sendSurfaceLeave, m_compositor);
+ command.parameters << QVariant::fromValue(surface);
+ command.parameters << QVariant::fromValue(output);
+ processCommand(command);
+}
+
+void MockCompositor::sendShellSurfaceConfigure(const QSharedPointer<MockSurface> surface, const QSize &size)
+{
+ Command command = makeCommand(Impl::Compositor::sendShellSurfaceConfigure, m_compositor);
+ command.parameters << QVariant::fromValue(surface);
+ command.parameters << QVariant::fromValue(size);
+ processCommand(command);
+}
+
+void MockCompositor::sendIviSurfaceConfigure(const QSharedPointer<MockIviSurface> iviSurface, const QSize &size)
+{
+ Command command = makeCommand(Impl::Compositor::sendIviSurfaceConfigure, m_compositor);
+ command.parameters << QVariant::fromValue(iviSurface);
+ command.parameters << QVariant::fromValue(size);
+ processCommand(command);
+}
+
+void MockCompositor::sendXdgToplevelV6Configure(const QSharedPointer<MockXdgToplevelV6> toplevel, const QSize &size, const QVector<uint> &states)
+{
+ Command command = makeCommand(Impl::Compositor::sendXdgToplevelV6Configure, m_compositor);
+ command.parameters << QVariant::fromValue(toplevel);
+ command.parameters << QVariant::fromValue(size);
+ QByteArray statesBytes(reinterpret_cast<const char *>(states.data()),
+ states.size() * static_cast<int>(sizeof(uint)));
+ command.parameters << statesBytes;
+ processCommand(command);
+}
+
+void MockCompositor::waitForStartDrag()
+{
+ Command command = makeCommand(Impl::Compositor::waitForStartDrag, m_compositor);
+ processCommand(command);
+}
+
+QSharedPointer<MockSurface> MockCompositor::surface()
+{
+ QSharedPointer<MockSurface> result;
+ lock();
+ QVector<Impl::Surface *> surfaces = m_compositor->surfaces();
+ foreach (Impl::Surface *surface, surfaces) {
+ // we don't want to mistake the cursor surface for a window surface
+ if (surface->isMapped()) {
+ result = surface->mockSurface();
+ break;
+ }
+ }
+ unlock();
+ return result;
+}
+
+QSharedPointer<MockOutput> MockCompositor::output(int index)
+{
+ QSharedPointer<MockOutput> result;
+ lock();
+ if (Impl::Output *output = m_compositor->outputs().value(index, nullptr))
+ result = output->mockOutput();
+ unlock();
+ return result;
+}
+
+QSharedPointer<MockIviSurface> MockCompositor::iviSurface(int index)
+{
+ QSharedPointer<MockIviSurface> result;
+ lock();
+ if (Impl::IviSurface *toplevel = m_compositor->iviApplication()->iviSurfaces().value(index, nullptr))
+ result = toplevel->mockIviSurface();
+ unlock();
+ return result;
+}
+
+QSharedPointer<MockXdgToplevelV6> MockCompositor::xdgToplevelV6(int index)
+{
+ QSharedPointer<MockXdgToplevelV6> result;
+ lock();
+ if (Impl::XdgToplevelV6 *toplevel = m_compositor->xdgShellV6()->toplevels().value(index, nullptr))
+ result = toplevel->mockToplevel();
+ unlock();
+ return result;
+}
+
+QSharedPointer<MockSurface> MockCompositor::fullScreenShellV1Surface(int index)
+{
+ QSharedPointer<MockSurface> result;
+ lock();
+ if (Impl::Surface *surface = m_compositor->fullScreenShellV1()->surfaces().value(index, nullptr))
+ result = surface->mockSurface();
+ unlock();
+ return result;
+}
+
+MockCompositor::Command MockCompositor::makeCommand(Command::Callback callback, void *target)
+{
+ Command command;
+ command.callback = callback;
+ command.target = target;
+ return command;
+}
+
+void MockCompositor::processCommand(const Command &command)
+{
+ lock();
+ m_commandQueue << command;
+ unlock();
+
+ m_waitCondition.wakeOne();
+}
+
+void MockCompositor::dispatchCommands()
+{
+ lock();
+ int count = m_commandQueue.length();
+ unlock();
+
+ for (int i = 0; i < count; ++i) {
+ lock();
+ const Command command = m_commandQueue.takeFirst();
+ unlock();
+ command.callback(command.target, command.parameters);
+ }
+}
+
+void *MockCompositor::run(void *data)
+{
+ MockCompositor *controller = static_cast<MockCompositor *>(data);
+
+ Impl::Compositor compositor;
+
+ controller->m_compositor = &compositor;
+ controller->m_waitCondition.wakeOne();
+
+ while (!controller->m_ready) {
+ controller->dispatchCommands();
+ compositor.dispatchEvents(20);
+ }
+
+ while (controller->m_alive) {
+ {
+ QMutexLocker locker(&controller->m_mutex);
+ if (controller->m_commandQueue.isEmpty())
+ controller->m_waitCondition.wait(&controller->m_mutex);
+ }
+ controller->dispatchCommands();
+ compositor.dispatchEvents(20);
+ }
+
+ return 0;
+}
+
+namespace Impl {
+
+Compositor::Compositor()
+ : m_display(wl_display_create())
+{
+ if (wl_display_add_socket(m_display, 0)) {
+ fprintf(stderr, "Fatal: Failed to open server socket\n");
+ exit(EXIT_FAILURE);
+ }
+
+ wl_global_create(m_display, &wl_compositor_interface, 1, this, bindCompositor);
+
+ m_data_device_manager.reset(new DataDeviceManager(this, m_display));
+
+ wl_display_init_shm(m_display);
+
+ m_seat.reset(new Seat(this, m_display));
+ m_pointer = m_seat->pointer();
+ m_keyboard = m_seat->keyboard();
+ m_touch = m_seat->touch();
+
+ m_outputs.append(new Output(m_display, QSize(1920, 1080), QPoint(0, 0)));
+ m_iviApplication.reset(new IviApplication(m_display));
+ m_wlShell.reset(new WlShell(m_display));
+ m_xdgShellV6.reset(new XdgShellV6(m_display));
+ m_fullScreenShellV1.reset(new FullScreenShellV1(m_display));
+
+ m_loop = wl_display_get_event_loop(m_display);
+ m_fd = wl_event_loop_get_fd(m_loop);
+}
+
+Compositor::~Compositor()
+{
+ wl_display_destroy(m_display);
+}
+
+void Compositor::dispatchEvents(int timeout)
+{
+ wl_display_flush_clients(m_display);
+ wl_event_loop_dispatch(m_loop, timeout);
+}
+
+static void compositor_create_surface(wl_client *client, wl_resource *compositorResource, uint32_t id)
+{
+ Compositor *compositor = static_cast<Compositor *>(wl_resource_get_user_data(compositorResource));
+ compositor->addSurface(new Surface(client, id, wl_resource_get_version(compositorResource), compositor));
+}
+
+static void compositor_create_region(wl_client *client, wl_resource *compositorResource, uint32_t id)
+{
+ Q_UNUSED(client);
+ Q_UNUSED(compositorResource);
+ Q_UNUSED(id);
+}
+
+void Compositor::bindCompositor(wl_client *client, void *compositorData, uint32_t version, uint32_t id)
+{
+ static const struct wl_compositor_interface compositorInterface = {
+ compositor_create_surface,
+ compositor_create_region
+ };
+
+ wl_resource *resource = wl_resource_create(client, &wl_compositor_interface, static_cast<int>(version), id);
+ wl_resource_set_implementation(resource, &compositorInterface, compositorData, nullptr);
+}
+
+static void unregisterResourceCallback(wl_listener *listener, void *data)
+{
+ struct wl_resource *resource = reinterpret_cast<struct wl_resource *>(data);
+ wl_list_remove(wl_resource_get_link(resource));
+ delete listener;
+}
+
+void registerResource(wl_list *list, wl_resource *resource)
+{
+ wl_list_insert(list, wl_resource_get_link(resource));
+
+ wl_listener *listener = new wl_listener;
+ listener->notify = unregisterResourceCallback;
+
+ wl_resource_add_destroy_listener(resource, listener);
+}
+
+QVector<Surface *> Compositor::surfaces() const
+{
+ return m_surfaces;
+}
+
+QVector<Output *> Compositor::outputs() const
+{
+ return m_outputs;
+}
+
+IviApplication *Compositor::iviApplication() const
+{
+ return m_iviApplication.data();
+}
+
+XdgShellV6 *Compositor::xdgShellV6() const
+{
+ return m_xdgShellV6.data();
+}
+
+FullScreenShellV1 *Compositor::fullScreenShellV1() const
+{
+ return m_fullScreenShellV1.data();
+}
+
+uint32_t Compositor::nextSerial()
+{
+ return wl_display_next_serial(m_display);
+}
+
+void Compositor::addSurface(Surface *surface)
+{
+ m_surfaces << surface;
+}
+
+void Compositor::removeSurface(Surface *surface)
+{
+ m_surfaces.removeOne(surface);
+ m_keyboard->handleSurfaceDestroyed(surface);
+ m_pointer->handleSurfaceDestroyed(surface);
+ m_fullScreenShellV1->removeSurface(surface);
+}
+
+Surface *Compositor::resolveSurface(const QVariant &v)
+{
+ QSharedPointer<MockSurface> mockSurface = v.value<QSharedPointer<MockSurface> >();
+ return mockSurface ? mockSurface->handle() : nullptr;
+}
+
+Output *Compositor::resolveOutput(const QVariant &v)
+{
+ QSharedPointer<MockOutput> mockOutput = v.value<QSharedPointer<MockOutput> >();
+ return mockOutput ? mockOutput->handle() : nullptr;
+}
+
+IviSurface *Compositor::resolveIviSurface(const QVariant &v)
+{
+ QSharedPointer<MockIviSurface> mockIviSurface = v.value<QSharedPointer<MockIviSurface>>();
+ return mockIviSurface ? mockIviSurface->handle() : nullptr;
+}
+
+XdgToplevelV6 *Compositor::resolveToplevel(const QVariant &v)
+{
+ QSharedPointer<MockXdgToplevelV6> mockToplevel = v.value<QSharedPointer<MockXdgToplevelV6>>();
+ return mockToplevel ? mockToplevel->handle() : nullptr;
+}
+
+}
diff --git a/tests/auto/client/shared_old/mockcompositor.h b/tests/auto/client/shared_old/mockcompositor.h
new file mode 100644
index 000000000..4bab1ed67
--- /dev/null
+++ b/tests/auto/client/shared_old/mockcompositor.h
@@ -0,0 +1,290 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** 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 MOCKCOMPOSITOR_H
+#define MOCKCOMPOSITOR_H
+
+#include "mockxdgshellv6.h"
+#include "mockiviapplication.h"
+#include "mockfullscreenshellv1.h"
+
+#include <pthread.h>
+#include <qglobal.h>
+#include <wayland-server-core.h>
+
+#include <QImage>
+#include <QMutex>
+#include <QRect>
+#include <QSharedPointer>
+#include <QVariant>
+#include <QVector>
+#include <QWaitCondition>
+
+namespace Impl {
+
+typedef void (**Implementation)(void);
+
+class Keyboard;
+class Pointer;
+class Touch;
+class Seat;
+class DataDeviceManager;
+class Surface;
+class Output;
+class IviApplication;
+class WlShell;
+class XdgShellV6;
+
+class Compositor
+{
+public:
+ Compositor();
+ ~Compositor();
+
+ int fileDescriptor() const { return m_fd; }
+ void dispatchEvents(int timeout = 0);
+
+ uint32_t nextSerial();
+ uint32_t time() { return ++m_time; }
+
+ QVector<Surface *> surfaces() const;
+ QVector<Output *> outputs() const;
+
+ IviApplication *iviApplication() const;
+ XdgShellV6 *xdgShellV6() const;
+ FullScreenShellV1 *fullScreenShellV1() const;
+
+ void addSurface(Surface *surface);
+ void removeSurface(Surface *surface);
+
+ static void setKeyboardFocus(void *data, const QList<QVariant> &parameters);
+ static void sendMousePress(void *data, const QList<QVariant> &parameters);
+ static void sendMouseRelease(void *data, const QList<QVariant> &parameters);
+ static void sendKeyPress(void *data, const QList<QVariant> &parameters);
+ static void sendKeyRelease(void *data, const QList<QVariant> &parameters);
+ static void sendTouchDown(void *data, const QList<QVariant> &parameters);
+ static void sendTouchUp(void *data, const QList<QVariant> &parameters);
+ static void sendTouchMotion(void *data, const QList<QVariant> &parameters);
+ static void sendTouchFrame(void *data, const QList<QVariant> &parameters);
+ static void sendDataDeviceDataOffer(void *data, const QList<QVariant> &parameters);
+ static void sendDataDeviceEnter(void *data, const QList<QVariant> &parameters);
+ static void sendDataDeviceMotion(void *data, const QList<QVariant> &parameters);
+ static void sendDataDeviceDrop(void *data, const QList<QVariant> &parameters);
+ static void sendDataDeviceLeave(void *data, const QList<QVariant> &parameters);
+ static void waitForStartDrag(void *data, const QList<QVariant> &parameters);
+ static void setOutputMode(void *compositor, const QList<QVariant> &parameters);
+ static void sendAddOutput(void *data, const QList<QVariant> &parameters);
+ static void sendRemoveOutput(void *data, const QList<QVariant> &parameters);
+ static void sendOutputGeometry(void *data, const QList<QVariant> &parameters);
+ static void sendSurfaceEnter(void *data, const QList<QVariant> &parameters);
+ static void sendSurfaceLeave(void *data, const QList<QVariant> &parameters);
+ static void sendShellSurfaceConfigure(void *data, const QList<QVariant> &parameters);
+ static void sendIviSurfaceConfigure(void *data, const QList<QVariant> &parameters);
+ static void sendXdgToplevelV6Configure(void *data, const QList<QVariant> &parameters);
+
+public:
+ bool m_startDragSeen = false;
+
+private:
+ static void bindCompositor(wl_client *client, void *data, uint32_t version, uint32_t id);
+ static Surface *resolveSurface(const QVariant &v);
+ static Output *resolveOutput(const QVariant &v);
+ static IviSurface *resolveIviSurface(const QVariant &v);
+ static XdgToplevelV6 *resolveToplevel(const QVariant &v);
+
+ void initShm();
+
+ QRect m_outputGeometry;
+
+ wl_display *m_display = nullptr;
+ wl_event_loop *m_loop = nullptr;
+ int m_fd = -1;
+
+ uint32_t m_time = 0;
+
+ QScopedPointer<Seat> m_seat;
+ Pointer *m_pointer = nullptr;
+ Keyboard *m_keyboard = nullptr;
+ Touch *m_touch = nullptr;
+ QScopedPointer<DataDeviceManager> m_data_device_manager;
+ QVector<Surface *> m_surfaces;
+ QVector<Output *> m_outputs;
+ QScopedPointer<IviApplication> m_iviApplication;
+ QScopedPointer<WlShell> m_wlShell;
+ QScopedPointer<XdgShellV6> m_xdgShellV6;
+ QScopedPointer<FullScreenShellV1> m_fullScreenShellV1;
+};
+
+void registerResource(wl_list *list, wl_resource *resource);
+
+}
+
+class MockSurface
+{
+public:
+ Impl::Surface *handle() const { return m_surface; }
+
+ QImage image;
+
+private:
+ MockSurface(Impl::Surface *surface);
+ friend class Impl::Compositor;
+ friend class Impl::Surface;
+
+ Impl::Surface *m_surface = nullptr;
+};
+
+Q_DECLARE_METATYPE(QSharedPointer<MockSurface>)
+
+class MockIviSurface
+{
+public:
+ Impl::IviSurface *handle() const { return m_iviSurface; }
+ const uint iviId;
+
+private:
+ MockIviSurface(Impl::IviSurface *iviSurface) : iviId(iviSurface->iviId()), m_iviSurface(iviSurface) {}
+ friend class Impl::Compositor;
+ friend class Impl::IviSurface;
+
+ Impl::IviSurface *m_iviSurface;
+};
+
+Q_DECLARE_METATYPE(QSharedPointer<MockIviSurface>)
+
+class MockXdgToplevelV6 : public QObject
+{
+ Q_OBJECT
+public:
+ Impl::XdgToplevelV6 *handle() const { return m_toplevel; }
+
+ void sendConfigure(const QSharedPointer<MockXdgToplevelV6> toplevel);
+
+signals:
+ uint setMinimizedRequested();
+ uint setMaximizedRequested();
+ uint unsetMaximizedRequested();
+ uint setFullscreenRequested();
+ uint unsetFullscreenRequested();
+ void windowGeometryRequested(QRect geometry); // NOTE: This is really an xdg surface event
+
+private:
+ MockXdgToplevelV6(Impl::XdgToplevelV6 *toplevel) : m_toplevel(toplevel) {}
+ friend class Impl::Compositor;
+ friend class Impl::XdgToplevelV6;
+
+ Impl::XdgToplevelV6 *m_toplevel;
+};
+
+Q_DECLARE_METATYPE(QSharedPointer<MockXdgToplevelV6>)
+
+class MockOutput {
+public:
+ Impl::Output *handle() const { return m_output; }
+ MockOutput(Impl::Output *output);
+private:
+ Impl::Output *m_output = nullptr;
+};
+
+Q_DECLARE_METATYPE(QSharedPointer<MockOutput>)
+
+class MockCompositor
+{
+public:
+ MockCompositor();
+ ~MockCompositor();
+
+ void applicationInitialized();
+
+ int waylandFileDescriptor() const;
+ void processWaylandEvents();
+
+ void setOutputMode(const QSize &size);
+ void setKeyboardFocus(const QSharedPointer<MockSurface> &surface);
+ void sendMousePress(const QSharedPointer<MockSurface> &surface, const QPoint &pos);
+ void sendMouseRelease(const QSharedPointer<MockSurface> &surface);
+ void sendKeyPress(const QSharedPointer<MockSurface> &surface, uint code);
+ void sendKeyRelease(const QSharedPointer<MockSurface> &surface, uint code);
+ void sendTouchDown(const QSharedPointer<MockSurface> &surface, const QPoint &position, int id);
+ void sendTouchMotion(const QSharedPointer<MockSurface> &surface, const QPoint &position, int id);
+ void sendTouchUp(const QSharedPointer<MockSurface> &surface, int id);
+ void sendTouchFrame(const QSharedPointer<MockSurface> &surface);
+ void sendDataDeviceDataOffer(const QSharedPointer<MockSurface> &surface);
+ void sendDataDeviceEnter(const QSharedPointer<MockSurface> &surface, const QPoint &position);
+ void sendDataDeviceMotion(const QPoint &position);
+ void sendDataDeviceDrop(const QSharedPointer<MockSurface> &surface);
+ void sendDataDeviceLeave(const QSharedPointer<MockSurface> &surface);
+ void sendAddOutput();
+ void sendRemoveOutput(const QSharedPointer<MockOutput> &output);
+ void sendOutputGeometry(const QSharedPointer<MockOutput> &output, const QRect &geometry);
+ void sendSurfaceEnter(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output);
+ void sendSurfaceLeave(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output);
+ void sendShellSurfaceConfigure(const QSharedPointer<MockSurface> surface, const QSize &size = QSize(0, 0));
+ void sendIviSurfaceConfigure(const QSharedPointer<MockIviSurface> iviSurface, const QSize &size);
+ void sendXdgToplevelV6Configure(const QSharedPointer<MockXdgToplevelV6> toplevel, const QSize &size = QSize(0, 0),
+ const QVector<uint> &states = { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED });
+ void waitForStartDrag();
+
+ QSharedPointer<MockSurface> surface();
+ QSharedPointer<MockOutput> output(int index = 0);
+ QSharedPointer<MockIviSurface> iviSurface(int index = 0);
+ QSharedPointer<MockXdgToplevelV6> xdgToplevelV6(int index = 0);
+ QSharedPointer<MockSurface> fullScreenShellV1Surface(int index = 0);
+
+ void lock();
+ void unlock();
+
+private:
+ struct Command
+ {
+ typedef void (*Callback)(void *target, const QList<QVariant> &parameters);
+
+ Callback callback;
+ void *target = nullptr;
+ QList<QVariant> parameters;
+ };
+
+ static Command makeCommand(Command::Callback callback, void *target);
+
+ void processCommand(const Command &command);
+ void dispatchCommands();
+
+ static void *run(void *data);
+
+ bool m_alive = true;
+ bool m_ready = false;
+ pthread_t m_thread;
+ QMutex m_mutex;
+ QWaitCondition m_waitCondition;
+
+ Impl::Compositor *m_compositor = nullptr;
+
+ QList<Command> m_commandQueue;
+};
+
+#endif
diff --git a/tests/auto/client/shared_old/mockfullscreenshellv1.cpp b/tests/auto/client/shared_old/mockfullscreenshellv1.cpp
new file mode 100644
index 000000000..22c49cde6
--- /dev/null
+++ b/tests/auto/client/shared_old/mockfullscreenshellv1.cpp
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 "mockfullscreenshellv1.h"
+#include "mocksurface.h"
+
+namespace Impl {
+
+void FullScreenShellV1::zwp_fullscreen_shell_v1_present_surface(Resource *resource, struct ::wl_resource *surface, uint32_t method, struct ::wl_resource *output)
+{
+ Q_UNUSED(resource)
+ Q_UNUSED(method)
+ Q_UNUSED(output)
+
+ m_surfaces.append(Surface::fromResource(surface));
+}
+
+} // namespace Impl
diff --git a/tests/auto/client/shared_old/mockfullscreenshellv1.h b/tests/auto/client/shared_old/mockfullscreenshellv1.h
new file mode 100644
index 000000000..819bbc186
--- /dev/null
+++ b/tests/auto/client/shared_old/mockfullscreenshellv1.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 MOCKFULLSCREENSHELLV1_H
+#define MOCKFULLSCREENSHELLV1_H
+
+#include <qwayland-server-fullscreen-shell-unstable-v1.h>
+
+#include <QVector>
+
+namespace Impl {
+
+class Surface;
+class FullScreenShellV1;
+
+class FullScreenShellV1 : public QtWaylandServer::zwp_fullscreen_shell_v1
+{
+public:
+ explicit FullScreenShellV1(::wl_display *display) : zwp_fullscreen_shell_v1(display, 1) {}
+
+ QVector<Surface *> surfaces() const { return m_surfaces; }
+ void removeSurface(Surface *surface) { m_surfaces.removeOne(surface); }
+
+protected:
+ void zwp_fullscreen_shell_v1_present_surface(Resource *resource, struct ::wl_resource *surface, uint32_t method, struct ::wl_resource *output) override;
+
+private:
+ QVector<Surface *> m_surfaces;
+};
+
+} // namespace Impl
+
+#endif // MOCKFULLSCREENSHELLV1_H
diff --git a/tests/auto/client/shared/mockinput.cpp b/tests/auto/client/shared_old/mockinput.cpp
index 8b7592824..8b7592824 100644
--- a/tests/auto/client/shared/mockinput.cpp
+++ b/tests/auto/client/shared_old/mockinput.cpp
diff --git a/tests/auto/client/shared/mockinput.h b/tests/auto/client/shared_old/mockinput.h
index d9adb3621..d9adb3621 100644
--- a/tests/auto/client/shared/mockinput.h
+++ b/tests/auto/client/shared_old/mockinput.h
diff --git a/tests/auto/client/shared/mockiviapplication.cpp b/tests/auto/client/shared_old/mockiviapplication.cpp
index 29a308993..29a308993 100644
--- a/tests/auto/client/shared/mockiviapplication.cpp
+++ b/tests/auto/client/shared_old/mockiviapplication.cpp
diff --git a/tests/auto/client/shared/mockiviapplication.h b/tests/auto/client/shared_old/mockiviapplication.h
index 4d65eeaba..4d65eeaba 100644
--- a/tests/auto/client/shared/mockiviapplication.h
+++ b/tests/auto/client/shared_old/mockiviapplication.h
diff --git a/tests/auto/client/shared/mockoutput.cpp b/tests/auto/client/shared_old/mockoutput.cpp
index 13e0524ad..13e0524ad 100644
--- a/tests/auto/client/shared/mockoutput.cpp
+++ b/tests/auto/client/shared_old/mockoutput.cpp
diff --git a/tests/auto/client/shared/mockoutput.h b/tests/auto/client/shared_old/mockoutput.h
index 9f261d5d7..9f261d5d7 100644
--- a/tests/auto/client/shared/mockoutput.h
+++ b/tests/auto/client/shared_old/mockoutput.h
diff --git a/tests/auto/client/shared/mocksurface.cpp b/tests/auto/client/shared_old/mocksurface.cpp
index 84dcda6b0..84dcda6b0 100644
--- a/tests/auto/client/shared/mocksurface.cpp
+++ b/tests/auto/client/shared_old/mocksurface.cpp
diff --git a/tests/auto/client/shared/mocksurface.h b/tests/auto/client/shared_old/mocksurface.h
index 949dc23dd..949dc23dd 100644
--- a/tests/auto/client/shared/mocksurface.h
+++ b/tests/auto/client/shared_old/mocksurface.h
diff --git a/tests/auto/client/shared/mockwlshell.cpp b/tests/auto/client/shared_old/mockwlshell.cpp
index 50e539932..50e539932 100644
--- a/tests/auto/client/shared/mockwlshell.cpp
+++ b/tests/auto/client/shared_old/mockwlshell.cpp
diff --git a/tests/auto/client/shared/mockwlshell.h b/tests/auto/client/shared_old/mockwlshell.h
index 3da586ca8..3da586ca8 100644
--- a/tests/auto/client/shared/mockwlshell.h
+++ b/tests/auto/client/shared_old/mockwlshell.h
diff --git a/tests/auto/client/shared/mockxdgshellv6.cpp b/tests/auto/client/shared_old/mockxdgshellv6.cpp
index 05eff74ad..05eff74ad 100644
--- a/tests/auto/client/shared/mockxdgshellv6.cpp
+++ b/tests/auto/client/shared_old/mockxdgshellv6.cpp
diff --git a/tests/auto/client/shared/mockxdgshellv6.h b/tests/auto/client/shared_old/mockxdgshellv6.h
index a238fa562..a238fa562 100644
--- a/tests/auto/client/shared/mockxdgshellv6.h
+++ b/tests/auto/client/shared_old/mockxdgshellv6.h
diff --git a/tests/auto/client/shared_old/shared_old.pri b/tests/auto/client/shared_old/shared_old.pri
new file mode 100644
index 000000000..467e98115
--- /dev/null
+++ b/tests/auto/client/shared_old/shared_old.pri
@@ -0,0 +1,34 @@
+CONFIG += testcase link_pkgconfig
+QT += testlib
+QT += core-private gui-private waylandclient-private
+
+QMAKE_USE += wayland-client wayland-server
+
+CONFIG += wayland-scanner
+WAYLANDSERVERSOURCES += \
+ ../../../../src/3rdparty/protocol/ivi-application.xml \
+ ../../../../src/3rdparty/protocol/wayland.xml \
+ ../../../../src/3rdparty/protocol/xdg-shell-unstable-v6.xml \
+ ../../../../src/3rdparty/protocol/fullscreen-shell-unstable-v1.xml
+
+INCLUDEPATH += ../shared_old
+
+SOURCES += \
+ ../shared_old/mockcompositor.cpp \
+ ../shared_old/mockfullscreenshellv1.cpp \
+ ../shared_old/mockinput.cpp \
+ ../shared_old/mockiviapplication.cpp \
+ ../shared_old/mockwlshell.cpp \
+ ../shared_old/mockxdgshellv6.cpp \
+ ../shared_old/mocksurface.cpp \
+ ../shared_old/mockoutput.cpp
+
+HEADERS += \
+ ../shared_old/mockcompositor.h \
+ ../shared_old/mockfullscreenshellv1.h \
+ ../shared_old/mockinput.h \
+ ../shared_old/mockiviapplication.h \
+ ../shared_old/mockwlshell.h \
+ ../shared_old/mockxdgshellv6.h \
+ ../shared_old/mocksurface.h \
+ ../shared_old/mockoutput.h
diff --git a/tests/auto/client/surface/surface.pro b/tests/auto/client/surface/surface.pro
new file mode 100644
index 000000000..36882aa2d
--- /dev/null
+++ b/tests/auto/client/surface/surface.pro
@@ -0,0 +1,5 @@
+include (../shared/shared.pri)
+
+TARGET = tst_surface
+SOURCES += tst_surface.cpp
+
diff --git a/tests/auto/client/surface/tst_surface.cpp b/tests/auto/client/surface/tst_surface.cpp
new file mode 100644
index 000000000..dddff0866
--- /dev/null
+++ b/tests/auto/client/surface/tst_surface.cpp
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** 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 "mockcompositor.h"
+#include <QtGui/QRasterWindow>
+#include <QtGui/QOpenGLWindow>
+
+using namespace MockCompositor;
+
+class tst_surface : public QObject, private DefaultCompositor
+{
+ Q_OBJECT
+private slots:
+ void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); }
+ void createDestroySurface();
+ void waitForFrameCallbackRaster();
+ void waitForFrameCallbackGl();
+ void negotiateShmFormat();
+};
+
+void tst_surface::createDestroySurface()
+{
+ QWindow window;
+ window.show();
+
+ QCOMPOSITOR_TRY_VERIFY(surface());
+
+ window.destroy();
+ QCOMPOSITOR_TRY_VERIFY(!surface());
+}
+
+void tst_surface::waitForFrameCallbackRaster()
+{
+ QSKIP("TODO: This currently fails, needs a fix");
+ class TestWindow : public QRasterWindow {
+ public:
+ explicit TestWindow() { resize(40, 40); }
+ void paintEvent(QPaintEvent *event) override
+ {
+ Q_UNUSED(event);
+ update();
+ }
+ };
+ TestWindow window;
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+ QSignalSpy bufferSpy(exec([=] { return xdgSurface()->m_surface; }), &Surface::bufferCommitted);
+ exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+
+ // We should get the first buffer without waiting for a frame callback
+ QTRY_COMPARE(bufferSpy.count(), 1);
+ bufferSpy.removeFirst();
+
+ // Make sure we follow frame callbacks for some frames
+ for (int i = 0; i < 5; ++i) {
+ xdgPingAndWaitForPong(); // Make sure things have happened on the client
+ exec([&] {
+ QVERIFY(bufferSpy.empty()); // Make sure no extra buffers have arrived
+ QVERIFY(!xdgToplevel()->surface()->m_waitingFrameCallbacks.empty());
+ xdgToplevel()->surface()->sendFrameCallbacks();
+ });
+ QTRY_COMPARE(bufferSpy.count(), 1);
+ bufferSpy.removeFirst();
+ }
+}
+
+void tst_surface::waitForFrameCallbackGl()
+{
+ QSKIP("TODO: This currently fails, needs a fix");
+ class TestWindow : public QOpenGLWindow {
+ public:
+ explicit TestWindow()
+ {
+ resize(40, 40);
+ connect(this, &QOpenGLWindow::frameSwapped,
+ this, QOverload<>::of(&QPaintDeviceWindow::update));
+ update();
+ }
+ void paintGL() override
+ {
+ glClearColor(1, 0, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+ };
+ TestWindow window;
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+ QSignalSpy bufferSpy(exec([=] { return xdgSurface()->m_surface; }), &Surface::bufferCommitted);
+ exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+
+ // We should get the first buffer without waiting for a frame callback
+ QTRY_COMPARE(bufferSpy.count(), 1);
+ bufferSpy.removeFirst();
+
+ // Make sure we follow frame callbacks for some frames
+ for (int i = 0; i < 5; ++i) {
+ xdgPingAndWaitForPong(); // Make sure things have happened on the client
+ exec([&] {
+ QVERIFY(bufferSpy.empty()); // Make sure no extra buffers have arrived
+ QVERIFY(!xdgToplevel()->surface()->m_waitingFrameCallbacks.empty());
+ xdgToplevel()->surface()->sendFrameCallbacks();
+ });
+ QTRY_COMPARE(bufferSpy.count(), 1);
+ bufferSpy.removeFirst();
+ }
+}
+
+void tst_surface::negotiateShmFormat()
+{
+ QSKIP("TODO: I'm not sure why we're choosing xrgb over argb in this case...");
+ QRasterWindow window;
+ window.setFlag(Qt::FramelessWindowHint); // decorations force alpha
+ QSurfaceFormat format;
+ format.setAlphaBufferSize(0);
+ window.setFormat(format);
+ window.resize(64, 48);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+ QSignalSpy bufferSpy(exec([=] { return xdgSurface()->m_surface; }), &Surface::bufferCommitted);
+ const uint serial = exec([=] { return xdgToplevel()->sendCompleteConfigure(); });
+ QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, serial);
+ exec([&] {
+ Buffer *buffer = xdgToplevel()->surface()->m_committed.buffer;
+ QVERIFY(buffer);
+ auto *shmBuffer = ShmBuffer::fromBuffer(buffer);
+ QVERIFY(shmBuffer);
+ qDebug() << "shmBuffer->m_format" << shmBuffer->m_format;
+ QCOMPARE(shmBuffer->m_format, Shm::format_xrgb8888);
+ });
+}
+
+QCOMPOSITOR_TEST_MAIN(tst_surface)
+#include "tst_surface.moc"
diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp
new file mode 100644
index 000000000..55e994b06
--- /dev/null
+++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp
@@ -0,0 +1,269 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** 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 "mockcompositor.h"
+#include <QtGui/QRasterWindow>
+#include <QtGui/QOpenGLWindow>
+
+using namespace MockCompositor;
+
+class tst_xdgshell : public QObject, private DefaultCompositor
+{
+ Q_OBJECT
+private slots:
+ void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); }
+ void showMinimized();
+ void basicConfigure();
+ void configureSize();
+ void configureStates();
+ void popup();
+ void pongs();
+};
+
+void tst_xdgshell::showMinimized()
+{
+ QSKIP("TODO: This currently fails, needs a fix");
+ // On xdg-shell there's really no way for the compositor to tell the window if it's minimized
+ // There are wl_surface.enter events and so on, but there's really no way to differentiate
+ // between a window preview and an unminimized window.
+ QWindow window;
+ window.showMinimized();
+ QCOMPARE(window.windowStates(), Qt::WindowMinimized); // should return minimized until
+ QTRY_COMPARE(window.windowStates(), Qt::WindowNoState); // rejected by handleWindowStateChanged
+
+ // Make sure the window on the compositor side is/was created here, and not after the test
+ // finishes, as that may mess up for later tests.
+ QCOMPOSITOR_TRY_VERIFY(surface());
+ QVERIFY(!window.isExposed());
+}
+
+void tst_xdgshell::basicConfigure()
+{
+ QRasterWindow window;
+ window.resize(64, 48);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+
+ QSignalSpy configureSpy(exec([=] { return xdgSurface(); }), &XdgSurface::configureCommitted);
+
+ QTRY_VERIFY(window.isVisible());
+ // The window should not be exposed before the first xdg_surface configure event
+ QTRY_VERIFY(!window.isExposed());
+
+ exec([=] {
+ xdgToplevel()->sendConfigure({0, 0}, {}); // Let the window decide the size
+ });
+
+ // Nothing should happen before the *xdg_surface* configure
+ QTRY_VERIFY(!window.isExposed()); //Window should not be exposed before the first configure event
+ QVERIFY(configureSpy.isEmpty());
+
+ const uint serial = exec([=] { return nextSerial(); });
+
+ exec([=] {
+ xdgSurface()->sendConfigure(serial);
+ });
+
+ // Finally, we're exposed
+ QTRY_VERIFY(window.isExposed());
+
+ // The client is now going to ack the configure
+ QTRY_COMPARE(configureSpy.count(), 1);
+ QCOMPARE(configureSpy.takeFirst().at(0).toUInt(), serial);
+
+ // And attach a buffer
+ exec([&] {
+ Buffer *buffer = xdgToplevel()->surface()->m_committed.buffer;
+ QVERIFY(buffer);
+ QCOMPARE(buffer->size(), window.frameGeometry().size());
+ });
+}
+
+void tst_xdgshell::configureSize()
+{
+ QRasterWindow window;
+ window.resize(64, 48);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+
+ QSignalSpy configureSpy(exec([=] { return xdgSurface(); }), &XdgSurface::configureCommitted);
+
+ const QSize configureSize(60, 40);
+
+ exec([=] {
+ xdgToplevel()->sendCompleteConfigure(configureSize);
+ });
+
+ QTRY_COMPARE(configureSpy.count(), 1);
+
+ exec([=] {
+ Buffer *buffer = xdgToplevel()->surface()->m_committed.buffer;
+ QVERIFY(buffer);
+ QCOMPARE(buffer->size(), configureSize);
+ });
+}
+
+void tst_xdgshell::configureStates()
+{
+ QRasterWindow window;
+ window.resize(64, 48);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+
+ const QSize windowedSize(320, 240);
+ const uint windowedSerial = exec([=] {
+ return xdgToplevel()->sendCompleteConfigure(windowedSize, { XdgToplevel::state_activated });
+ });
+ QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, windowedSerial);
+ QCOMPARE(window.visibility(), QWindow::Windowed);
+ QCOMPARE(window.windowStates(), Qt::WindowNoState);
+ QCOMPARE(window.frameGeometry().size(), windowedSize);
+ // Toplevel windows don't know their position on xdg-shell
+// QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
+
+// QEXPECT_FAIL("", "configure has already been acked, we shouldn't have to wait for isActive", Continue);
+// QVERIFY(window.isActive());
+ QTRY_VERIFY(window.isActive()); // Just make sure it eventually get's set correctly
+
+ const QSize screenSize(640, 480);
+ const uint maximizedSerial = exec([=] {
+ return xdgToplevel()->sendCompleteConfigure(screenSize, { XdgToplevel::state_activated, XdgToplevel::state_maximized });
+ });
+ QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, maximizedSerial);
+ QCOMPARE(window.visibility(), QWindow::Maximized);
+ QCOMPARE(window.windowStates(), Qt::WindowMaximized);
+ QCOMPARE(window.frameGeometry().size(), screenSize);
+// QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
+
+ const uint fullscreenSerial = exec([=] {
+ return xdgToplevel()->sendCompleteConfigure(screenSize, { XdgToplevel::state_activated, XdgToplevel::state_fullscreen });
+ });
+ QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, fullscreenSerial);
+ QCOMPARE(window.visibility(), QWindow::FullScreen);
+ QCOMPARE(window.windowStates(), Qt::WindowFullScreen);
+ QCOMPARE(window.frameGeometry().size(), screenSize);
+// QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
+
+ // The window should remember its original size
+ const uint restoreSerial = exec([=] {
+ return xdgToplevel()->sendCompleteConfigure({0, 0}, { XdgToplevel::state_activated });
+ });
+ QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, restoreSerial);
+ QCOMPARE(window.visibility(), QWindow::Windowed);
+ QCOMPARE(window.windowStates(), Qt::WindowNoState);
+ QCOMPARE(window.frameGeometry().size(), windowedSize);
+// QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
+}
+
+void tst_xdgshell::popup()
+{
+ class Window : public QRasterWindow {
+ public:
+ void mousePressEvent(QMouseEvent *event) override
+ {
+ QRasterWindow::mousePressEvent(event);
+ m_popup.reset(new QRasterWindow);
+ m_popup->setTransientParent(this);
+ m_popup->setFlags(Qt::Popup);
+ m_popup->resize(100, 100);
+ m_popup->show();
+ }
+ QScopedPointer<QRasterWindow> m_popup;
+ };
+ Window window;
+ window.resize(200, 200);
+ window.show();
+
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+ QSignalSpy toplevelConfigureSpy(exec([=] { return xdgSurface(); }), &XdgSurface::configureCommitted);
+ exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+ QTRY_COMPARE(toplevelConfigureSpy.count(), 1);
+
+ uint clickSerial = exec([=] {
+ auto *surface = xdgToplevel()->surface();
+ auto *p = pointer();
+ p->sendEnter(surface, {100, 100});
+// p->sendFrame(); //TODO: uncomment when we support seat v5
+ uint serial = p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
+ p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
+ return serial;
+// p->sendFrame(); //TODO: uncomment when we support seat v5
+ });
+
+ QTRY_VERIFY(window.m_popup);
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup());
+ QSignalSpy popupConfigureSpy(exec([=] { return xdgPopup()->m_xdgSurface; }), &XdgSurface::configureCommitted);
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_grabbed);
+ QCOMPOSITOR_TRY_COMPARE(xdgPopup()->m_grabSerial, clickSerial);
+
+ QRasterWindow *popup = window.m_popup.get();
+ QVERIFY(!popup->isExposed()); // wait for configure
+
+ //TODO: Verify it works with a different configure window geometry
+ exec([=] { xdgPopup()->sendConfigure(QRect(100, 100, 100, 100)); });
+
+ // Nothing should happen before the *xdg_surface* configure
+ QTRY_VERIFY(!popup->isExposed()); // Popup shouldn't be exposed before the first configure event
+ QVERIFY(popupConfigureSpy.isEmpty());
+
+ const uint configureSerial = exec([=] {
+ return xdgPopup()->m_xdgSurface->sendConfigure();
+ });
+
+ // Finally, we're exposed
+ QTRY_VERIFY(popup->isExposed());
+
+ // The client is now going to ack the configure
+ QTRY_COMPARE(popupConfigureSpy.count(), 1);
+ QCOMPARE(popupConfigureSpy.takeFirst().at(0).toUInt(), configureSerial);
+
+ // And attach a buffer
+ exec([&] {
+ Buffer *buffer = xdgPopup()->surface()->m_committed.buffer;
+ QVERIFY(buffer);
+ QCOMPARE(buffer->size(), popup->frameGeometry().size());
+ });
+}
+
+void tst_xdgshell::pongs()
+{
+ QSignalSpy pongSpy(exec([=] { return get<XdgWmBase>(); }), &XdgWmBase::pong);
+ // Verify that the client has bound to the global
+ QCOMPOSITOR_TRY_COMPARE(get<XdgWmBase>()->resourceMap().size(), 1);
+ const uint serial = exec([=] { return nextSerial(); });
+ exec([=] {
+ auto *base = get<XdgWmBase>();
+ wl_resource *resource = base->resourceMap().first()->handle;
+ base->send_ping(resource, serial);
+ });
+ QTRY_COMPARE(pongSpy.count(), 1);
+ QCOMPARE(pongSpy.first().at(0).toUInt(), serial);
+}
+
+QCOMPOSITOR_TEST_MAIN(tst_xdgshell)
+#include "tst_xdgshell.moc"
diff --git a/tests/auto/client/xdgshell/xdgshell.pro b/tests/auto/client/xdgshell/xdgshell.pro
new file mode 100644
index 000000000..d7c3f9df6
--- /dev/null
+++ b/tests/auto/client/xdgshell/xdgshell.pro
@@ -0,0 +1,5 @@
+include (../shared/shared.pri)
+
+TARGET = tst_xdgshell
+SOURCES += tst_xdgshell.cpp
+
diff --git a/tests/auto/client/xdgshellv6/xdgshellv6.pro b/tests/auto/client/xdgshellv6/xdgshellv6.pro
index 4fec593df..cc8a22d83 100644
--- a/tests/auto/client/xdgshellv6/xdgshellv6.pro
+++ b/tests/auto/client/xdgshellv6/xdgshellv6.pro
@@ -1,4 +1,4 @@
-include (../shared/shared.pri)
+include (../shared_old/shared_old.pri)
TARGET = tst_client_xdgshellv6
SOURCES += tst_xdgshellv6.cpp
diff --git a/tests/auto/compositor/compositor/compositor.pro b/tests/auto/compositor/compositor/compositor.pro
index 0ce2c6be0..4e5cf50b8 100644
--- a/tests/auto/compositor/compositor/compositor.pro
+++ b/tests/auto/compositor/compositor/compositor.pro
@@ -13,6 +13,8 @@ qtConfig(xkbcommon): \
WAYLANDCLIENTSOURCES += \
../../../../src/3rdparty/protocol/xdg-shell-unstable-v5.xml \
../../../../src/3rdparty/protocol/ivi-application.xml \
+ ../../../../src/3rdparty/protocol/wayland.xml \
+ ../../../../src/3rdparty/protocol/viewporter.xml
SOURCES += \
tst_compositor.cpp \
diff --git a/tests/auto/compositor/compositor/mockclient.cpp b/tests/auto/compositor/compositor/mockclient.cpp
index f74314407..b6cb4ab46 100644
--- a/tests/auto/compositor/compositor/mockclient.cpp
+++ b/tests/auto/compositor/compositor/mockclient.cpp
@@ -173,6 +173,8 @@ void MockClient::handleGlobal(uint32_t id, const QByteArray &interface)
wl_output_add_listener(output, &outputListener, this);
} else if (interface == "wl_shm") {
shm = static_cast<wl_shm *>(wl_registry_bind(registry, id, &wl_shm_interface, 1));
+ } else if (interface == "wp_viewporter") {
+ viewporter = static_cast<wp_viewporter *>(wl_registry_bind(registry, id, &wp_viewporter_interface, 1));
} else if (interface == "wl_shell") {
wlshell = static_cast<wl_shell *>(wl_registry_bind(registry, id, &wl_shell_interface, 1));
} else if (interface == "xdg_shell") {
diff --git a/tests/auto/compositor/compositor/mockclient.h b/tests/auto/compositor/compositor/mockclient.h
index 6bfb652ed..bf5d8fc88 100644
--- a/tests/auto/compositor/compositor/mockclient.h
+++ b/tests/auto/compositor/compositor/mockclient.h
@@ -26,9 +26,10 @@
**
****************************************************************************/
-#include <wayland-client.h>
+#include "wayland-wayland-client-protocol.h"
#include <qwayland-xdg-shell-unstable-v5.h>
#include <wayland-ivi-application-client-protocol.h>
+#include "wayland-viewporter-client-protocol.h"
#include <QObject>
#include <QImage>
@@ -69,6 +70,7 @@ public:
wl_registry *registry = nullptr;
wl_shell *wlshell = nullptr;
xdg_shell *xdgShell = nullptr;
+ wp_viewporter *viewporter = nullptr;
ivi_application *iviApplication = nullptr;
QList<MockSeat *> m_seats;
diff --git a/tests/auto/compositor/compositor/mockkeyboard.h b/tests/auto/compositor/compositor/mockkeyboard.h
index 1090db597..fd7f06aee 100644
--- a/tests/auto/compositor/compositor/mockkeyboard.h
+++ b/tests/auto/compositor/compositor/mockkeyboard.h
@@ -30,7 +30,7 @@
#define MOCKKEYBOARD_H
#include <QObject>
-#include <wayland-client.h>
+#include "wayland-wayland-client-protocol.h"
class MockKeyboard : public QObject
{
diff --git a/tests/auto/compositor/compositor/mockpointer.h b/tests/auto/compositor/compositor/mockpointer.h
index 2054040fd..db6b2b69c 100644
--- a/tests/auto/compositor/compositor/mockpointer.h
+++ b/tests/auto/compositor/compositor/mockpointer.h
@@ -30,7 +30,7 @@
#define MOCKPOINTER_H
#include <QObject>
-#include <wayland-client.h>
+#include "wayland-wayland-client-protocol.h"
class MockPointer : public QObject
{
diff --git a/tests/auto/compositor/compositor/mockseat.h b/tests/auto/compositor/compositor/mockseat.h
index f8c103ed4..0d0f4074c 100644
--- a/tests/auto/compositor/compositor/mockseat.h
+++ b/tests/auto/compositor/compositor/mockseat.h
@@ -32,7 +32,7 @@
#include "mockkeyboard.h"
#include <QObject>
-#include <wayland-client.h>
+#include "wayland-wayland-client-protocol.h"
class MockSeat : public QObject
{
diff --git a/tests/auto/compositor/compositor/testcompositor.cpp b/tests/auto/compositor/compositor/testcompositor.cpp
index 710bb7b3a..22ecf28cb 100644
--- a/tests/auto/compositor/compositor/testcompositor.cpp
+++ b/tests/auto/compositor/compositor/testcompositor.cpp
@@ -30,7 +30,7 @@
#include "testseat.h"
#include "testkeyboardgrabber.h"
-#include <wayland-server.h>
+#include <wayland-server-core.h>
TestCompositor::TestCompositor(bool createInputDev)
: shell(new QWaylandWlShell(this))
diff --git a/tests/auto/compositor/compositor/tst_compositor.cpp b/tests/auto/compositor/compositor/tst_compositor.cpp
index e12aa564e..0e11618aa 100644
--- a/tests/auto/compositor/compositor/tst_compositor.cpp
+++ b/tests/auto/compositor/compositor/tst_compositor.cpp
@@ -46,6 +46,7 @@
#include <QtWaylandCompositor/QWaylandSurface>
#include <QtWaylandCompositor/QWaylandResource>
#include <QtWaylandCompositor/QWaylandKeymap>
+#include <QtWaylandCompositor/QWaylandViewporter>
#include <qwayland-xdg-shell-unstable-v5.h>
#include <qwayland-ivi-application.h>
@@ -68,6 +69,7 @@ private slots:
void seatKeyboardFocus();
void seatMouseFocus();
void inputRegion();
+ void defaultInputRegionHiDpi();
void singleClient();
void multipleClients();
void geometry();
@@ -94,6 +96,20 @@ private slots:
void convertsXdgEdgesToQtEdges();
void xdgShellV6Positioner();
+
+ void viewporterGlobal();
+ void viewportDestination();
+ void viewportSource();
+ void viewportSourceAndDestination();
+ void viewportDestruction();
+ void viewportProtocolErrors_data();
+ void viewportProtocolErrors();
+ void viewportClearDestination();
+ void viewportClearSource();
+ void viewportExistsError();
+ void viewportDestinationNoSurfaceError();
+ void viewportSourceNoSurfaceError();
+ void viewportHiDpi();
};
void tst_WaylandCompositor::init() {
@@ -434,7 +450,8 @@ void tst_WaylandCompositor::mapSurface()
QSignalSpy hasContentSpy(waylandSurface, SIGNAL(hasContentChanged()));
- QCOMPARE(waylandSurface->size(), QSize());
+ QCOMPARE(waylandSurface->bufferSize(), QSize());
+ QCOMPARE(waylandSurface->destinationSize(), QSize());
QCOMPARE(waylandSurface->hasContent(), false);
QSize size(256, 256);
@@ -448,7 +465,8 @@ void tst_WaylandCompositor::mapSurface()
QTRY_COMPARE(hasContentSpy.count(), 1);
QCOMPARE(waylandSurface->hasContent(), true);
- QCOMPARE(waylandSurface->size(), size);
+ QCOMPARE(waylandSurface->bufferSize(), size);
+ QCOMPARE(waylandSurface->destinationSize(), size);
wl_surface_destroy(surface);
}
@@ -478,7 +496,8 @@ void tst_WaylandCompositor::mapSurfaceHiDpi()
wl_surface_damage(surface, 0, 0, surfaceSize.width(), surfaceSize.height());
auto verifyComittedState = [=]() {
- QCOMPARE(waylandSurface->size(), bufferSize);
+ QCOMPARE(waylandSurface->bufferSize(), bufferSize);
+ QCOMPARE(waylandSurface->destinationSize(), surfaceSize);
QCOMPARE(waylandSurface->bufferScale(), bufferScale);
QCOMPARE(waylandSurface->hasContent(), true);
};
@@ -497,6 +516,9 @@ void tst_WaylandCompositor::mapSurfaceHiDpi()
QObject::connect(waylandSurface, &QWaylandSurface::sizeChanged, verifyComittedState);
QSignalSpy sizeSpy(waylandSurface, SIGNAL(sizeChanged()));
+ QObject::connect(waylandSurface, &QWaylandSurface::destinationSizeChanged, verifyComittedState);
+ QSignalSpy destinationSizeSpy(waylandSurface, SIGNAL(destinationSizeChanged()));
+
QObject::connect(waylandSurface, &QWaylandSurface::bufferScaleChanged, verifyComittedState);
QSignalSpy bufferScaleSpy(waylandSurface, SIGNAL(bufferScaleChanged()));
@@ -507,7 +529,8 @@ void tst_WaylandCompositor::mapSurfaceHiDpi()
QSignalSpy offsetSpy(waylandSurface, SIGNAL(offsetForNextFrame(const QPoint &)));
// No state should be applied before the commit
- QCOMPARE(waylandSurface->size(), QSize());
+ QCOMPARE(waylandSurface->bufferSize(), QSize());
+ QCOMPARE(waylandSurface->destinationSize(), QSize());
QCOMPARE(waylandSurface->hasContent(), false);
QCOMPARE(waylandSurface->bufferScale(), 1);
QCOMPARE(offsetSpy.count(), 0);
@@ -516,6 +539,7 @@ void tst_WaylandCompositor::mapSurfaceHiDpi()
QTRY_COMPARE(hasContentSpy.count(), 1);
QTRY_COMPARE(sizeSpy.count(), 1);
+ QTRY_COMPARE(destinationSizeSpy.count(), 1);
QTRY_COMPARE(bufferScaleSpy.count(), 1);
QTRY_COMPARE(offsetSpy.count(), 1);
@@ -826,6 +850,33 @@ void tst_WaylandCompositor::inputRegion()
QVERIFY(!waylandSurface->inputRegionContains(QPoint(1, 2)));
}
+void tst_WaylandCompositor::defaultInputRegionHiDpi()
+{
+ TestCompositor compositor(true);
+ compositor.create();
+
+ MockClient client;
+ wl_surface *surface = client.createSurface();
+
+ int bufferScale = 2;
+ QSize surfaceSize(16, 16);
+ QSize bufferSize = surfaceSize * bufferScale;
+ ShmBuffer buffer(bufferSize, client.shm);
+ wl_surface_attach(surface, buffer.handle, 0, 0);
+ wl_surface_damage(surface, 0, 0, surfaceSize.width(), surfaceSize.height());
+ wl_surface_set_buffer_scale(surface, bufferScale);
+ wl_surface_commit(surface);
+
+ QTRY_COMPARE(compositor.surfaces.size(), 1);
+ QWaylandSurface *waylandSurface = compositor.surfaces.at(0);
+
+ QCOMPARE(waylandSurface->bufferScale(), bufferScale);
+ QVERIFY(waylandSurface->inputRegionContains(QPoint(0, 0)));
+ QVERIFY(waylandSurface->inputRegionContains(QPoint(15, 15)));
+ QVERIFY(!waylandSurface->inputRegionContains(QPoint(-1, -1)));
+ QVERIFY(!waylandSurface->inputRegionContains(QPoint(16, 16)));
+}
+
class XdgTestCompositor: public TestCompositor {
Q_OBJECT
public:
@@ -1211,5 +1262,406 @@ void tst_WaylandCompositor::xdgShellV6Positioner()
QCOMPARE(p.unconstrainedPosition(), QPoint(1 + 800 - 100 / 2 + 4, 2 + 600 / 2 - 50 + 8));
}
+class ViewporterTestCompositor: public TestCompositor {
+ Q_OBJECT
+public:
+ ViewporterTestCompositor() : viewporter(this) {}
+ QWaylandViewporter viewporter;
+};
+
+void tst_WaylandCompositor::viewporterGlobal()
+{
+ ViewporterTestCompositor compositor;
+ compositor.create();
+ MockClient client;
+ QTRY_VERIFY(client.viewporter);
+}
+
+void tst_WaylandCompositor::viewportDestination()
+{
+ ViewporterTestCompositor compositor;
+ compositor.create();
+ MockClient client;
+ QTRY_VERIFY(client.viewporter);
+
+ wl_surface *surface = client.createSurface();
+ QTRY_COMPARE(compositor.surfaces.size(), 1);
+ QWaylandSurface *waylandSurface = compositor.surfaces.at(0);
+
+ QCOMPARE(waylandSurface->destinationSize(), QSize());
+ QCOMPARE(waylandSurface->sourceGeometry(), QRect());
+
+ const QSize bufferSize(64, 64);
+ ShmBuffer buffer(bufferSize, client.shm);
+ wl_surface_attach(surface, buffer.handle, 0, 0);
+ wl_surface_damage(surface, 0, 0, bufferSize.width(), bufferSize.height());
+ wp_viewport *viewport = wp_viewporter_get_viewport(client.viewporter, surface);
+ const QSize destinationSize(128, 123);
+ wp_viewport_set_destination(viewport, destinationSize.width(), destinationSize.height());
+ wl_surface_commit(surface);
+
+ QTRY_COMPARE(waylandSurface->bufferSize(), bufferSize);
+ QCOMPARE(waylandSurface->destinationSize(), QSize(128, 123));
+ QCOMPARE(waylandSurface->sourceGeometry(), QRect(QPoint(), bufferSize));
+
+ wp_viewport_destroy(viewport);
+ wl_surface_destroy(surface);
+ QCOMPARE(client.error, 0);
+}
+
+void tst_WaylandCompositor::viewportSource()
+{
+ ViewporterTestCompositor compositor;
+ compositor.create();
+ MockClient client;
+ QTRY_VERIFY(client.viewporter);
+
+ wl_surface *surface = client.createSurface();
+ QTRY_COMPARE(compositor.surfaces.size(), 1);
+ QWaylandSurface *waylandSurface = compositor.surfaces.at(0);
+
+ QCOMPARE(waylandSurface->destinationSize(), QSize());
+ QCOMPARE(waylandSurface->sourceGeometry(), QRect());
+
+ const QSize bufferSize(64, 64);
+ ShmBuffer buffer(bufferSize, client.shm);
+ wl_surface_attach(surface, buffer.handle, 0, 0);
+ wl_surface_damage(surface, 0, 0, bufferSize.width(), bufferSize.height());
+ wp_viewport *viewport = wp_viewporter_get_viewport(client.viewporter, surface);
+ const QRectF sourceGeometry(QPointF(10.5, 20.5), QSizeF(30, 40));
+ wp_viewport_set_source(viewport,
+ wl_fixed_from_double(sourceGeometry.x()),
+ wl_fixed_from_double(sourceGeometry.y()),
+ wl_fixed_from_double(sourceGeometry.width()),
+ wl_fixed_from_double(sourceGeometry.height()));
+ wl_surface_commit(surface);
+
+ QTRY_COMPARE(waylandSurface->bufferSize(), bufferSize);
+ QCOMPARE(waylandSurface->destinationSize(), sourceGeometry.size().toSize());
+ QCOMPARE(waylandSurface->sourceGeometry(), sourceGeometry);
+
+ wp_viewport_destroy(viewport);
+ wl_surface_destroy(surface);
+ QCOMPARE(client.error, 0);
+}
+
+void tst_WaylandCompositor::viewportSourceAndDestination()
+{
+ ViewporterTestCompositor compositor;
+ compositor.create();
+ MockClient client;
+ QTRY_VERIFY(client.viewporter);
+
+ wl_surface *surface = client.createSurface();
+ QTRY_COMPARE(compositor.surfaces.size(), 1);
+ QWaylandSurface *waylandSurface = compositor.surfaces.at(0);
+
+ QCOMPARE(waylandSurface->destinationSize(), QSize());
+ QCOMPARE(waylandSurface->sourceGeometry(), QRect());
+
+ const QSize bufferSize(64, 64);
+ ShmBuffer buffer(bufferSize, client.shm);
+ wl_surface_attach(surface, buffer.handle, 0, 0);
+ wl_surface_damage(surface, 0, 0, bufferSize.width(), bufferSize.height());
+
+ wp_viewport *viewport = wp_viewporter_get_viewport(client.viewporter, surface);
+
+ const QSize destinationSize(128, 123);
+ wp_viewport_set_destination(viewport, destinationSize.width(), destinationSize.height());
+
+ const QRectF sourceGeometry(QPointF(10, 20), QSizeF(30, 40));
+ wp_viewport_set_source(viewport,
+ wl_fixed_from_double(sourceGeometry.x()),
+ wl_fixed_from_double(sourceGeometry.y()),
+ wl_fixed_from_double(sourceGeometry.width()),
+ wl_fixed_from_double(sourceGeometry.height()));
+
+ wl_surface_commit(surface);
+
+ QTRY_COMPARE(waylandSurface->bufferSize(), bufferSize);
+ QCOMPARE(waylandSurface->destinationSize(), destinationSize);
+ QCOMPARE(waylandSurface->sourceGeometry(), sourceGeometry);
+
+ wp_viewport_destroy(viewport);
+ wl_surface_destroy(surface);
+ QCOMPARE(client.error, 0);
+}
+
+void tst_WaylandCompositor::viewportDestruction()
+{
+ ViewporterTestCompositor compositor;
+ compositor.create();
+ MockClient client;
+ QTRY_VERIFY(client.viewporter);
+
+ wl_surface *surface = client.createSurface();
+ QTRY_COMPARE(compositor.surfaces.size(), 1);
+ QWaylandSurface *waylandSurface = compositor.surfaces.at(0);
+
+ QCOMPARE(waylandSurface->destinationSize(), QSize());
+ QCOMPARE(waylandSurface->sourceGeometry(), QRect());
+
+ const QSize bufferSize(64, 64);
+ ShmBuffer buffer(bufferSize, client.shm);
+ wl_surface_attach(surface, buffer.handle, 0, 0);
+ wl_surface_damage(surface, 0, 0, bufferSize.width(), bufferSize.height());
+
+ wp_viewport *viewport = wp_viewporter_get_viewport(client.viewporter, surface);
+
+ const QSize destinationSize(128, 123);
+ wp_viewport_set_destination(viewport, destinationSize.width(), destinationSize.height());
+
+ const QRectF sourceGeometry(QPointF(10, 20), QSizeF(30, 40));
+ wp_viewport_set_source(viewport,
+ wl_fixed_from_double(sourceGeometry.x()),
+ wl_fixed_from_double(sourceGeometry.y()),
+ wl_fixed_from_double(sourceGeometry.width()),
+ wl_fixed_from_double(sourceGeometry.height()));
+
+ wl_surface_commit(surface);
+
+ QTRY_COMPARE(waylandSurface->bufferSize(), bufferSize);
+ QCOMPARE(waylandSurface->destinationSize(), destinationSize);
+ QCOMPARE(waylandSurface->sourceGeometry(), sourceGeometry);
+
+ wp_viewport_destroy(viewport);
+ wl_surface_commit(surface);
+
+ QTRY_COMPARE(waylandSurface->destinationSize(), bufferSize);
+ QCOMPARE(waylandSurface->sourceGeometry(), QRectF(QPoint(), bufferSize));
+
+ wl_surface_destroy(surface);
+ QCOMPARE(client.error, 0);
+}
+
+void tst_WaylandCompositor::viewportProtocolErrors_data()
+{
+ QTest::addColumn<QRectF>("source");
+ QTest::addColumn<QSize>("destination");
+ QTest::addColumn<uint>("error");
+
+ QTest::newRow("invalid source position") << QRectF(-1, 0, 16, 16) << QSize(64, 64) << uint(WP_VIEWPORT_ERROR_BAD_VALUE);
+ QTest::newRow("invalid source size") << QRectF(0, 0, -1, 16) << QSize(64, 64) << uint(WP_VIEWPORT_ERROR_BAD_VALUE);
+ QTest::newRow("invalid destination size") << QRectF(0, 0, 16, 16) << QSize(-16, 64) << uint(WP_VIEWPORT_ERROR_BAD_VALUE);
+ QTest::newRow("invalid non-integer source with unset size") << QRectF(0, 0, 15.5, 15.5) << QSize(-1, -1) << uint(WP_VIEWPORT_ERROR_BAD_SIZE);
+ QTest::newRow("bigger source than buffer") << QRectF(0, 0, 13337, 13337) << QSize(-1, -1) << uint(WP_VIEWPORT_ERROR_OUT_OF_BUFFER);
+}
+
+void tst_WaylandCompositor::viewportProtocolErrors()
+{
+ QFETCH(QRectF, source);
+ QFETCH(QSize, destination);
+ QFETCH(uint, error);
+
+ ViewporterTestCompositor compositor;
+ compositor.create();
+ MockClient client;
+ QTRY_VERIFY(client.viewporter);
+
+ wl_surface *surface = client.createSurface();
+
+ const QSize bufferSize(64, 64);
+ ShmBuffer buffer(bufferSize, client.shm);
+ wl_surface_attach(surface, buffer.handle, 0, 0);
+ wl_surface_damage(surface, 0, 0, bufferSize.width(), bufferSize.height());
+ wp_viewport *viewport = wp_viewporter_get_viewport(client.viewporter, surface);
+ wp_viewport_set_source(viewport,
+ wl_fixed_from_double(source.x()),
+ wl_fixed_from_double(source.y()),
+ wl_fixed_from_double(source.width()),
+ wl_fixed_from_double(source.height()));
+ wp_viewport_set_destination(viewport, destination.width(), destination.height());
+ wl_surface_commit(surface);
+
+ QTRY_COMPARE(client.error, EPROTO);
+ QCOMPARE(client.protocolError.interface, &wp_viewport_interface);
+ QCOMPARE(static_cast<wp_viewport_error>(client.protocolError.code), error);
+}
+
+void tst_WaylandCompositor::viewportClearDestination()
+{
+ ViewporterTestCompositor compositor;
+ compositor.create();
+ MockClient client;
+ QTRY_VERIFY(client.viewporter);
+
+ wl_surface *surface = client.createSurface();
+ QTRY_COMPARE(compositor.surfaces.size(), 1);
+ QWaylandSurface *waylandSurface = compositor.surfaces.at(0);
+
+ QCOMPARE(waylandSurface->destinationSize(), QSize());
+ QCOMPARE(waylandSurface->sourceGeometry(), QRect());
+
+ const QSize bufferSize(64, 64);
+ ShmBuffer buffer(bufferSize, client.shm);
+ wl_surface_attach(surface, buffer.handle, 0, 0);
+ wl_surface_damage(surface, 0, 0, bufferSize.width(), bufferSize.height());
+
+ wp_viewport *viewport = wp_viewporter_get_viewport(client.viewporter, surface);
+
+ const QSize destinationSize(128, 123);
+ wp_viewport_set_destination(viewport, destinationSize.width(), destinationSize.height());
+ wl_surface_commit(surface);
+
+ QTRY_COMPARE(waylandSurface->bufferSize(), bufferSize);
+ QCOMPARE(waylandSurface->destinationSize(), destinationSize);
+
+ wp_viewport_set_destination(viewport, -1, -1);
+ wl_surface_commit(surface);
+
+ QTRY_COMPARE(waylandSurface->destinationSize(), bufferSize);
+ QCOMPARE(waylandSurface->sourceGeometry(), QRectF(QPoint(), bufferSize));
+
+ wp_viewport_destroy(viewport);
+ wl_surface_destroy(surface);
+ QCOMPARE(client.error, 0);
+}
+
+void tst_WaylandCompositor::viewportClearSource()
+{
+ ViewporterTestCompositor compositor;
+ compositor.create();
+ MockClient client;
+ QTRY_VERIFY(client.viewporter);
+
+ wl_surface *surface = client.createSurface();
+ QTRY_COMPARE(compositor.surfaces.size(), 1);
+ QWaylandSurface *waylandSurface = compositor.surfaces.at(0);
+
+ QCOMPARE(waylandSurface->destinationSize(), QSize());
+ QCOMPARE(waylandSurface->sourceGeometry(), QRect());
+
+ const QSize bufferSize(64, 64);
+ ShmBuffer buffer(bufferSize, client.shm);
+ wl_surface_attach(surface, buffer.handle, 0, 0);
+ wl_surface_damage(surface, 0, 0, bufferSize.width(), bufferSize.height());
+
+ wp_viewport *viewport = wp_viewporter_get_viewport(client.viewporter, surface);
+ QRectF source(10, 20, 30, 40);
+ wp_viewport_set_source(viewport,
+ wl_fixed_from_double(source.x()),
+ wl_fixed_from_double(source.y()),
+ wl_fixed_from_double(source.width()),
+ wl_fixed_from_double(source.height()));
+ wl_surface_commit(surface);
+
+ QTRY_COMPARE(waylandSurface->sourceGeometry(), source);
+
+ wp_viewport_set_source(viewport,
+ wl_fixed_from_double(-1),
+ wl_fixed_from_double(-1),
+ wl_fixed_from_double(-1),
+ wl_fixed_from_double(-1));
+ wl_surface_commit(surface);
+
+ QTRY_COMPARE(waylandSurface->sourceGeometry(), QRectF(QPoint(), bufferSize));
+
+ wp_viewport_destroy(viewport);
+ wl_surface_destroy(surface);
+ QCOMPARE(client.error, 0);
+}
+
+void tst_WaylandCompositor::viewportExistsError()
+{
+ ViewporterTestCompositor compositor;
+ compositor.create();
+ MockClient client;
+ QTRY_VERIFY(client.viewporter);
+
+ wl_surface *surface = client.createSurface();
+ wp_viewporter_get_viewport(client.viewporter, surface);
+ wp_viewporter_get_viewport(client.viewporter, surface);
+
+ QTRY_COMPARE(client.error, EPROTO);
+ QCOMPARE(client.protocolError.interface, &wp_viewporter_interface);
+ QCOMPARE(static_cast<wp_viewporter_error>(client.protocolError.code), WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS);
+}
+
+void tst_WaylandCompositor::viewportDestinationNoSurfaceError()
+{
+ ViewporterTestCompositor compositor;
+ compositor.create();
+ MockClient client;
+ QTRY_VERIFY(client.viewporter);
+
+ wl_surface *surface = client.createSurface();
+ wp_viewport *viewport = wp_viewporter_get_viewport(client.viewporter, surface);
+ wl_surface_destroy(surface);
+ wp_viewport_set_destination(viewport, 32, 32);
+
+ QTRY_COMPARE(client.error, EPROTO);
+ QCOMPARE(client.protocolError.interface, &wp_viewport_interface);
+ QCOMPARE(static_cast<wp_viewport_error>(client.protocolError.code), WP_VIEWPORT_ERROR_NO_SURFACE);
+}
+
+void tst_WaylandCompositor::viewportSourceNoSurfaceError()
+{
+ ViewporterTestCompositor compositor;
+ compositor.create();
+ MockClient client;
+ QTRY_VERIFY(client.viewporter);
+
+ wl_surface *surface = client.createSurface();
+ wp_viewport *viewport = wp_viewporter_get_viewport(client.viewporter, surface);
+ wl_surface_destroy(surface);
+ wp_viewport_set_source(viewport,
+ wl_fixed_from_double(0),
+ wl_fixed_from_double(0),
+ wl_fixed_from_double(1),
+ wl_fixed_from_double(1));
+
+ QTRY_COMPARE(client.error, EPROTO);
+ QCOMPARE(client.protocolError.interface, &wp_viewport_interface);
+ QCOMPARE(static_cast<wp_viewport_error>(client.protocolError.code), WP_VIEWPORT_ERROR_NO_SURFACE);
+}
+
+void tst_WaylandCompositor::viewportHiDpi()
+{
+ ViewporterTestCompositor compositor;
+ compositor.create();
+ MockClient client;
+ QTRY_VERIFY(client.viewporter);
+
+ wl_surface *surface = client.createSurface();
+ QTRY_COMPARE(compositor.surfaces.size(), 1);
+ QWaylandSurface *waylandSurface = compositor.surfaces.at(0);
+
+ const QSize bufferSize(128, 128);
+ ShmBuffer buffer(bufferSize, client.shm);
+ wl_surface_attach(surface, buffer.handle, 0, 0);
+ wl_surface_damage(surface, 0, 0, bufferSize.width(), bufferSize.height());
+ constexpr int bufferScale = 2;
+ wl_surface_set_buffer_scale(surface, bufferScale);
+
+ wl_surface_commit(surface);
+ QTRY_COMPARE(waylandSurface->destinationSize(), bufferSize / bufferScale);
+
+ wp_viewport *viewport = wp_viewporter_get_viewport(client.viewporter, surface);
+ const QRectF sourceGeometry(QPointF(10, 20), QSizeF(30, 40));
+ wp_viewport_set_source(viewport,
+ wl_fixed_from_double(sourceGeometry.x()),
+ wl_fixed_from_double(sourceGeometry.y()),
+ wl_fixed_from_double(sourceGeometry.width()),
+ wl_fixed_from_double(sourceGeometry.height()));
+ wl_surface_commit(surface);
+
+ QTRY_COMPARE(waylandSurface->destinationSize(), sourceGeometry.size());
+ QCOMPARE(waylandSurface->sourceGeometry(), sourceGeometry);
+ QCOMPARE(waylandSurface->bufferSize(), bufferSize);
+
+ const QSize destinationSize(128, 123);
+ wp_viewport_set_destination(viewport, destinationSize.width(), destinationSize.height());
+ wl_surface_commit(surface);
+
+ QTRY_COMPARE(waylandSurface->destinationSize(), destinationSize);
+ QCOMPARE(waylandSurface->sourceGeometry(), sourceGeometry);
+ QCOMPARE(waylandSurface->bufferSize(), bufferSize);
+
+ QCOMPARE(client.error, 0);
+
+ wp_viewport_destroy(viewport);
+ wl_surface_destroy(surface);
+}
+
#include <tst_compositor.moc>
QTEST_MAIN(tst_WaylandCompositor);