summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf6
-rw-r--r--examples/wayland/minimal-cpp/compositor.cpp8
-rw-r--r--examples/wayland/minimal-cpp/compositor.h2
-rw-r--r--examples/wayland/minimal-cpp/window.cpp2
-rw-r--r--examples/wayland/multi-output/qml/GridScreen.qml10
-rw-r--r--examples/wayland/multi-output/qml/ShellScreen.qml10
-rw-r--r--examples/wayland/multi-output/qml/main.qml4
-rw-r--r--examples/wayland/qwindow-compositor/compositor.cpp4
-rw-r--r--examples/wayland/qwindow-compositor/window.cpp6
-rw-r--r--examples/wayland/server-buffer/README5
-rw-r--r--examples/wayland/texture-sharing/.gitignore2
-rw-r--r--examples/wayland/texture-sharing/README27
-rw-r--r--examples/wayland/texture-sharing/custom-compositor/compositor.qrc9
-rw-r--r--examples/wayland/texture-sharing/custom-compositor/custom-compositor.pro18
-rw-r--r--examples/wayland/texture-sharing/custom-compositor/images/background.pngbin0 -> 9287 bytes
-rw-r--r--examples/wayland/texture-sharing/custom-compositor/images/car.ktxbin0 -> 11908 bytes
-rw-r--r--examples/wayland/texture-sharing/custom-compositor/images/qt4.astcbin0 -> 12816 bytes
-rw-r--r--examples/wayland/texture-sharing/custom-compositor/images/qt_logo.pngbin0 -> 1528 bytes
-rw-r--r--examples/wayland/texture-sharing/custom-compositor/main.cpp143
-rw-r--r--examples/wayland/texture-sharing/custom-compositor/qml/main.qml122
-rw-r--r--examples/wayland/texture-sharing/minimal-compositor.qml93
-rw-r--r--examples/wayland/texture-sharing/qml-client/main.cpp68
-rw-r--r--examples/wayland/texture-sharing/qml-client/main.qml248
-rw-r--r--examples/wayland/texture-sharing/qml-client/qml-client.pro13
-rw-r--r--examples/wayland/texture-sharing/qml-client/qml-client.qrc5
-rw-r--r--examples/wayland/texture-sharing/texture-sharing.pro5
-rw-r--r--examples/wayland/wayland.pro20
-rw-r--r--src/3rdparty/protocol/idle-inhibit-unstable-v1.xml83
-rw-r--r--src/3rdparty/protocol/qt_attribution.json20
-rw-r--r--src/3rdparty/protocol/wp-primary-selection-unstable-v1.xml225
-rw-r--r--src/client/client.pro8
-rw-r--r--src/client/configure.json12
-rw-r--r--src/client/qwaylandclipboard.cpp71
-rw-r--r--src/client/qwaylandcursor.cpp25
-rw-r--r--src/client/qwaylandcursor_p.h2
-rw-r--r--src/client/qwaylanddatadevice.cpp8
-rw-r--r--src/client/qwaylanddataoffer.cpp15
-rw-r--r--src/client/qwaylanddataoffer_p.h24
-rw-r--r--src/client/qwaylanddatasource.cpp3
-rw-r--r--src/client/qwaylanddisplay.cpp28
-rw-r--r--src/client/qwaylanddisplay_p.h12
-rw-r--r--src/client/qwaylandextendedsurface.cpp2
-rw-r--r--src/client/qwaylandinputcontext.cpp12
-rw-r--r--src/client/qwaylandinputdevice.cpp515
-rw-r--r--src/client/qwaylandinputdevice_p.h116
-rw-r--r--src/client/qwaylandintegration.cpp6
-rw-r--r--src/client/qwaylandnativeinterface.cpp24
-rw-r--r--src/client/qwaylandprimaryselectionv1.cpp162
-rw-r--r--src/client/qwaylandprimaryselectionv1_p.h148
-rw-r--r--src/client/qwaylandscreen.cpp3
-rw-r--r--src/client/qwaylandshmbackingstore.cpp30
-rw-r--r--src/client/qwaylandshmbackingstore_p.h5
-rw-r--r--src/client/qwaylandsurface.cpp122
-rw-r--r--src/client/qwaylandsurface_p.h97
-rw-r--r--src/client/qwaylandtouch.cpp1
-rw-r--r--src/client/qwaylandwindow.cpp178
-rw-r--r--src/client/qwaylandwindow_p.h19
-rw-r--r--src/compositor/compositor_api/compositor_api.pri13
-rw-r--r--src/compositor/compositor_api/qwaylandcompositor.cpp12
-rw-r--r--src/compositor/compositor_api/qwaylandcompositor_p.h4
-rw-r--r--src/compositor/compositor_api/qwaylandkeyboard.cpp13
-rw-r--r--src/compositor/compositor_api/qwaylandoutput.cpp13
-rw-r--r--src/compositor/compositor_api/qwaylandoutput_p.h5
-rw-r--r--src/compositor/compositor_api/qwaylandquickcompositor.cpp4
-rw-r--r--src/compositor/compositor_api/qwaylandquickitem.cpp84
-rw-r--r--src/compositor/compositor_api/qwaylandquickitem_p.h2
-rw-r--r--src/compositor/compositor_api/qwaylandseat.cpp33
-rw-r--r--src/compositor/compositor_api/qwaylandsurface.cpp37
-rw-r--r--src/compositor/compositor_api/qwaylandsurface.h10
-rw-r--r--src/compositor/compositor_api/qwaylandsurface_p.h3
-rw-r--r--src/compositor/compositor_api/qwaylandview.cpp3
-rw-r--r--src/compositor/configure.json7
-rw-r--r--src/compositor/extensions/extensions.pri31
-rw-r--r--src/compositor/extensions/qwaylandidleinhibitv1.cpp190
-rw-r--r--src/compositor/extensions/qwaylandidleinhibitv1.h62
-rw-r--r--src/compositor/extensions/qwaylandidleinhibitv1_p.h88
-rw-r--r--src/compositor/extensions/qwaylandqtwindowmanager.cpp3
-rw-r--r--src/compositor/extensions/qwaylandquickshellintegration.cpp100
-rw-r--r--src/compositor/extensions/qwaylandquickshellintegration.h58
-rw-r--r--src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp25
-rw-r--r--src/compositor/extensions/qwaylandquickshellsurfaceitem.h3
-rw-r--r--src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h17
-rw-r--r--src/compositor/extensions/qwaylandquickxdgoutputv1.cpp73
-rw-r--r--src/compositor/extensions/qwaylandquickxdgoutputv1.h62
-rw-r--r--src/compositor/extensions/qwaylandtextinput.cpp4
-rw-r--r--src/compositor/extensions/qwaylandwlscaler_p.h2
-rw-r--r--src/compositor/extensions/qwaylandwlshell.cpp9
-rw-r--r--src/compositor/extensions/qwaylandwlshellintegration.cpp19
-rw-r--r--src/compositor/extensions/qwaylandwlshellintegration_p.h8
-rw-r--r--src/compositor/extensions/qwaylandxdgoutputv1.cpp595
-rw-r--r--src/compositor/extensions/qwaylandxdgoutputv1.h111
-rw-r--r--src/compositor/extensions/qwaylandxdgoutputv1_p.h112
-rw-r--r--src/compositor/extensions/qwaylandxdgshell.cpp24
-rw-r--r--src/compositor/extensions/qwaylandxdgshell.h1
-rw-r--r--src/compositor/extensions/qwaylandxdgshellintegration.cpp16
-rw-r--r--src/compositor/extensions/qwaylandxdgshellintegration_p.h8
-rw-r--r--src/compositor/extensions/qwaylandxdgshellv5.cpp33
-rw-r--r--src/compositor/extensions/qwaylandxdgshellv5_p.h2
-rw-r--r--src/compositor/extensions/qwaylandxdgshellv5integration.cpp16
-rw-r--r--src/compositor/extensions/qwaylandxdgshellv5integration_p.h8
-rw-r--r--src/compositor/extensions/qwaylandxdgshellv6.cpp24
-rw-r--r--src/compositor/extensions/qwaylandxdgshellv6.h1
-rw-r--r--src/compositor/extensions/qwaylandxdgshellv6integration.cpp16
-rw-r--r--src/compositor/extensions/qwaylandxdgshellv6integration_p.h8
-rw-r--r--src/compositor/extensions/qwltexturesharingextension.cpp8
-rw-r--r--src/compositor/global/qwaylandcompositorextension.cpp2
-rw-r--r--src/compositor/hardware_integration/qwlserverbufferintegration_p.h8
-rw-r--r--src/compositor/wayland_wrapper/qwlclientbuffer.cpp12
-rw-r--r--src/compositor/wayland_wrapper/qwldatadevicemanager.cpp7
-rw-r--r--src/compositor/wayland_wrapper/qwldataoffer.cpp3
-rw-r--r--src/extensions/README.md18
-rw-r--r--src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.cpp5
-rw-r--r--src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp5
-rw-r--r--src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp2
-rw-r--r--src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.cpp5
-rw-r--r--src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp6
-rw-r--r--src/imports/compositor/qwaylandquickcompositorplugin.cpp15
-rw-r--r--src/imports/imports.pro12
-rw-r--r--src/imports/texture-sharing-extension/texture-sharing-extension.pro2
-rw-r--r--src/imports/texture-sharing/texture-sharing.pro2
-rw-r--r--src/plugins/hardwareintegration/hardwareintegration.pro2
-rw-r--r--src/plugins/plugins.pro13
-rw-r--r--src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.cpp2
-rw-r--r--src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.cpp6
-rw-r--r--src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.h2
-rw-r--r--src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration.cpp5
-rw-r--r--src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp19
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp4
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp3
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp2
-rw-r--r--src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp2
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp2
-rw-r--r--src/qtwaylandscanner/qtwaylandscanner.cpp225
-rw-r--r--src/shared/qwaylandinputmethodeventbuilder.cpp2
-rw-r--r--src/src.pro30
-rw-r--r--sync.profile10
-rw-r--r--tests/auto/auto.pro11
-rw-r--r--tests/auto/client/client.pro2
-rw-r--r--tests/auto/client/client/tst_client.cpp8
-rw-r--r--tests/auto/client/datadevicev1/tst_datadevicev1.cpp8
-rw-r--r--tests/auto/client/inputcontext/inputcontext.pro2
-rw-r--r--tests/auto/client/output/tst_output.cpp3
-rw-r--r--tests/auto/client/primaryselectionv1/primaryselectionv1.pro7
-rw-r--r--tests/auto/client/primaryselectionv1/tst_primaryselectionv1.cpp475
-rw-r--r--tests/auto/client/seatv4/BLACKLIST2
-rw-r--r--tests/auto/client/seatv4/tst_seatv4.cpp57
-rw-r--r--tests/auto/client/seatv5/seatv5.pro4
-rw-r--r--tests/auto/client/seatv5/tst_seatv5.cpp590
-rw-r--r--tests/auto/client/shared/corecompositor.h17
-rw-r--r--tests/auto/client/shared/coreprotocol.cpp115
-rw-r--r--tests/auto/client/shared/coreprotocol.h26
-rw-r--r--tests/auto/client/shared/mockcompositor.cpp2
-rw-r--r--tests/auto/client/shared/mockcompositor.h9
-rw-r--r--tests/auto/client/shared_old/mockcompositor.cpp4
-rw-r--r--tests/auto/client/shared_old/mocksurface.cpp3
-rw-r--r--tests/auto/client/surface/tst_surface.cpp6
-rw-r--r--tests/auto/client/xdgshell/tst_xdgshell.cpp77
-rw-r--r--tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp4
-rw-r--r--tests/auto/compositor/compositor/compositor.pro10
-rw-r--r--tests/auto/compositor/compositor/mockclient.cpp25
-rw-r--r--tests/auto/compositor/compositor/mockclient.h8
-rw-r--r--tests/auto/compositor/compositor/mockxdgoutputv1.cpp68
-rw-r--r--tests/auto/compositor/compositor/mockxdgoutputv1.h64
-rw-r--r--tests/auto/compositor/compositor/tst_compositor.cpp204
-rw-r--r--tests/manual/texture-sharing/cpp-client/cpp-client.pro15
-rw-r--r--tests/manual/texture-sharing/cpp-client/main.cpp229
166 files changed, 6505 insertions, 769 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 1ed62c5ac..2c01c5d2a 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,3 +1,7 @@
load(qt_build_config)
-MODULE_VERSION = 5.13.1
+DEFINES += QT_NO_FOREACH
+DEFINES += QT_NO_JAVA_STYLE_ITERATORS
+DEFINES += QT_NO_LINKED_LIST
+
+MODULE_VERSION = 5.14.0
diff --git a/examples/wayland/minimal-cpp/compositor.cpp b/examples/wayland/minimal-cpp/compositor.cpp
index fa9ae2da9..a4b989975 100644
--- a/examples/wayland/minimal-cpp/compositor.cpp
+++ b/examples/wayland/minimal-cpp/compositor.cpp
@@ -163,9 +163,13 @@ void Compositor::handleMouseMove(const QPoint &position)
defaultSeat()->sendMouseMoveEvent(view, mapToView(view, position));
}
-void Compositor::handleMouseWheel(Qt::Orientation orientation, int delta)
+void Compositor::handleMouseWheel(const QPoint &angleDelta)
{
- defaultSeat()->sendMouseWheelEvent(orientation, delta);
+ // TODO: fix this to send a single event, when diagonal scrolling is supported
+ if (angleDelta.x() != 0)
+ defaultSeat()->sendMouseWheelEvent(Qt::Horizontal, angleDelta.x());
+ if (angleDelta.y() != 0)
+ defaultSeat()->sendMouseWheelEvent(Qt::Vertical, angleDelta.y());
}
void Compositor::handleKeyPress(quint32 nativeScanCode)
diff --git a/examples/wayland/minimal-cpp/compositor.h b/examples/wayland/minimal-cpp/compositor.h
index 3c0c80e0e..e32442dd4 100644
--- a/examples/wayland/minimal-cpp/compositor.h
+++ b/examples/wayland/minimal-cpp/compositor.h
@@ -102,7 +102,7 @@ public:
void handleMousePress(const QPoint &position, Qt::MouseButton button);
void handleMouseRelease(const QPoint &position, Qt::MouseButton button, Qt::MouseButtons buttons);
void handleMouseMove(const QPoint &position);
- void handleMouseWheel(Qt::Orientation orientation, int delta);
+ void handleMouseWheel(const QPoint &angleDelta);
void handleKeyPress(quint32 nativeScanCode);
void handleKeyRelease(quint32 nativeScanCode);
diff --git a/examples/wayland/minimal-cpp/window.cpp b/examples/wayland/minimal-cpp/window.cpp
index f32fb515c..9f22cc68a 100644
--- a/examples/wayland/minimal-cpp/window.cpp
+++ b/examples/wayland/minimal-cpp/window.cpp
@@ -129,7 +129,7 @@ void Window::mouseMoveEvent(QMouseEvent *event)
void Window::wheelEvent(QWheelEvent *event)
{
- m_compositor->handleMouseWheel(event->orientation(), event->delta());
+ m_compositor->handleMouseWheel(event->angleDelta());
}
void Window::keyPressEvent(QKeyEvent *e)
diff --git a/examples/wayland/multi-output/qml/GridScreen.qml b/examples/wayland/multi-output/qml/GridScreen.qml
index 340291afd..a59cb8fb4 100644
--- a/examples/wayland/multi-output/qml/GridScreen.qml
+++ b/examples/wayland/multi-output/qml/GridScreen.qml
@@ -50,7 +50,7 @@
import QtQuick 2.0
import QtQuick.Window 2.2
-import QtWayland.Compositor 1.0
+import QtWayland.Compositor 1.14
WaylandOutput {
id: output
@@ -93,4 +93,12 @@ WaylandOutput {
}
}
}
+
+ XdgOutputV1 {
+ name: "WL-2"
+ description: "Overview screen"
+ logicalPosition: output.position
+ logicalSize: Qt.size(output.geometry.width / output.scaleFactor,
+ output.geometry.height / output.scaleFactor)
+ }
}
diff --git a/examples/wayland/multi-output/qml/ShellScreen.qml b/examples/wayland/multi-output/qml/ShellScreen.qml
index 4482e6e85..aa9b4b29b 100644
--- a/examples/wayland/multi-output/qml/ShellScreen.qml
+++ b/examples/wayland/multi-output/qml/ShellScreen.qml
@@ -50,7 +50,7 @@
import QtQuick 2.0
import QtQuick.Window 2.2
-import QtWayland.Compositor 1.0
+import QtWayland.Compositor 1.14
WaylandOutput {
id: output
@@ -84,4 +84,12 @@ WaylandOutput {
}
}
}
+
+ XdgOutputV1 {
+ name: "WL-1"
+ description: "Screen with window management"
+ logicalPosition: output.position
+ logicalSize: Qt.size(output.geometry.width / output.scaleFactor,
+ output.geometry.height / output.scaleFactor)
+ }
}
diff --git a/examples/wayland/multi-output/qml/main.qml b/examples/wayland/multi-output/qml/main.qml
index d01def55e..45f91fd66 100644
--- a/examples/wayland/multi-output/qml/main.qml
+++ b/examples/wayland/multi-output/qml/main.qml
@@ -49,7 +49,7 @@
****************************************************************************/
import QtQuick 2.0
-import QtWayland.Compositor 1.0
+import QtWayland.Compositor 1.14
WaylandCompositor {
id: comp
@@ -91,6 +91,8 @@ WaylandCompositor {
}
}
+ XdgOutputManagerV1 {}
+
WlShell {
id: defaultShell
diff --git a/examples/wayland/qwindow-compositor/compositor.cpp b/examples/wayland/qwindow-compositor/compositor.cpp
index 199de22e2..220ea3d74 100644
--- a/examples/wayland/qwindow-compositor/compositor.cpp
+++ b/examples/wayland/qwindow-compositor/compositor.cpp
@@ -266,7 +266,7 @@ void Compositor::viewAnimationDone()
View * Compositor::findView(const QWaylandSurface *s) const
{
- Q_FOREACH (View* view, m_views) {
+ for (View* view : m_views) {
if (view->surface() == s)
return view;
}
@@ -545,6 +545,6 @@ void Compositor::raise(View *view)
int source = endPos + 1 + i;
int dest = startPos + i;
for (int j = source; j > dest; j--)
- m_views.swap(j, j-1);
+ m_views.swapItemsAt(j, j-1);
}
}
diff --git a/examples/wayland/qwindow-compositor/window.cpp b/examples/wayland/qwindow-compositor/window.cpp
index 9a8ffc2de..c439d20a8 100644
--- a/examples/wayland/qwindow-compositor/window.cpp
+++ b/examples/wayland/qwindow-compositor/window.cpp
@@ -125,7 +125,8 @@ void Window::paintGL()
functions->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GLenum currentTarget = GL_TEXTURE_2D;
- Q_FOREACH (View *view, m_compositor->views()) {
+ const auto views = m_compositor->views();
+ for (View *view : views) {
if (view->isCursor())
continue;
auto texture = view->getTexture();
@@ -160,7 +161,8 @@ void Window::paintGL()
View *Window::viewAt(const QPointF &point)
{
View *ret = nullptr;
- Q_FOREACH (View *view, m_compositor->views()) {
+ const auto views = m_compositor->views();
+ for (View *view : views) {
if (view == m_dragIconView)
continue;
QRectF geom(view->position(), view->size());
diff --git a/examples/wayland/server-buffer/README b/examples/wayland/server-buffer/README
index 5744a6baf..da20b0f50 100644
--- a/examples/wayland/server-buffer/README
+++ b/examples/wayland/server-buffer/README
@@ -1,4 +1,7 @@
-This is the example to demonstrate the server buffer interfaces
+This example shows how to use the low-level server buffer extension. This
+version of Qt also provides a texture sharing extension that provides more
+functionality and convenience for sharing graphical assets with Qt Quick
+clients: see the texture-sharing example.
Compile up both compositor and client.
diff --git a/examples/wayland/texture-sharing/.gitignore b/examples/wayland/texture-sharing/.gitignore
new file mode 100644
index 000000000..c684448d3
--- /dev/null
+++ b/examples/wayland/texture-sharing/.gitignore
@@ -0,0 +1,2 @@
+custom-compositor/custom-compositor
+qml-client/qml-client
diff --git a/examples/wayland/texture-sharing/README b/examples/wayland/texture-sharing/README
new file mode 100644
index 000000000..27ea76745
--- /dev/null
+++ b/examples/wayland/texture-sharing/README
@@ -0,0 +1,27 @@
+This example shows how to use the texture sharing extension, allowing
+multiple clients to share the same copy of an image in graphics memory.
+
+The texture sharing extension uses the server buffer extension to transport
+graphics buffers. There are different server buffer plugins for different
+graphics hardware. This is specified by setting an environment variable for
+the compositor process.
+
+-On a device with Mesa and Intel integrated graphics, set:
+
+ QT_WAYLAND_SERVER_BUFFER_INTEGRATION=dmabuf-server
+
+-On a device with NVIDIA graphics, set:
+
+ QT_WAYLAND_SERVER_BUFFER_INTEGRATION=vulkan-server
+
+'custom-compositor' shows how to write a server that creates shared textures
+programmatically.
+
+The file 'minimal-compositor.qml' shows how to add texture sharing to an
+existing compositor, using only QML. It is based on the minimal-qml example,
+and can be executed with qmlscene.
+
+'qml-client' shows how to use shared textures in a Qt Quick client.
+The compositor uses the hardware integration extension to broadcast
+the name of the server buffer integration to all clients, so qml-client
+can be started like any normal wayland client.
diff --git a/examples/wayland/texture-sharing/custom-compositor/compositor.qrc b/examples/wayland/texture-sharing/custom-compositor/compositor.qrc
new file mode 100644
index 000000000..86a8567f7
--- /dev/null
+++ b/examples/wayland/texture-sharing/custom-compositor/compositor.qrc
@@ -0,0 +1,9 @@
+<RCC>
+ <qresource prefix="/">
+ <file>images/background.png</file>
+ <file>images/qt_logo.png</file>
+ <file>images/qt4.astc</file>
+ <file>images/car.ktx</file>
+ <file>qml/main.qml</file>
+ </qresource>
+</RCC>
diff --git a/examples/wayland/texture-sharing/custom-compositor/custom-compositor.pro b/examples/wayland/texture-sharing/custom-compositor/custom-compositor.pro
new file mode 100644
index 000000000..e80e9e153
--- /dev/null
+++ b/examples/wayland/texture-sharing/custom-compositor/custom-compositor.pro
@@ -0,0 +1,18 @@
+QT += core gui qml
+
+QT += waylandcompositor-private
+
+SOURCES += \
+ main.cpp
+
+OTHER_FILES = \
+ qml/main.qml \
+ qml/Screen.qml \
+ images/background.jpg
+
+RESOURCES += compositor.qrc
+
+TARGET = custom-compositor
+
+target.path = $$[QT_INSTALL_EXAMPLES]/wayland/texture-sharing/custom-compositor
+INSTALLS += target
diff --git a/examples/wayland/texture-sharing/custom-compositor/images/background.png b/examples/wayland/texture-sharing/custom-compositor/images/background.png
new file mode 100644
index 000000000..845830c59
--- /dev/null
+++ b/examples/wayland/texture-sharing/custom-compositor/images/background.png
Binary files differ
diff --git a/examples/wayland/texture-sharing/custom-compositor/images/car.ktx b/examples/wayland/texture-sharing/custom-compositor/images/car.ktx
new file mode 100644
index 000000000..2aefdd306
--- /dev/null
+++ b/examples/wayland/texture-sharing/custom-compositor/images/car.ktx
Binary files differ
diff --git a/examples/wayland/texture-sharing/custom-compositor/images/qt4.astc b/examples/wayland/texture-sharing/custom-compositor/images/qt4.astc
new file mode 100644
index 000000000..7f7a3f473
--- /dev/null
+++ b/examples/wayland/texture-sharing/custom-compositor/images/qt4.astc
Binary files differ
diff --git a/examples/wayland/texture-sharing/custom-compositor/images/qt_logo.png b/examples/wayland/texture-sharing/custom-compositor/images/qt_logo.png
new file mode 100644
index 000000000..5e2b355ea
--- /dev/null
+++ b/examples/wayland/texture-sharing/custom-compositor/images/qt_logo.png
Binary files differ
diff --git a/examples/wayland/texture-sharing/custom-compositor/main.cpp b/examples/wayland/texture-sharing/custom-compositor/main.cpp
new file mode 100644
index 000000000..a39c8c381
--- /dev/null
+++ b/examples/wayland/texture-sharing/custom-compositor/main.cpp
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Wayland module
+**
+** $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 <QtCore/QUrl>
+#include <QtCore/QDebug>
+#include <QtGui/QGuiApplication>
+#include <QtQml/QQmlApplicationEngine>
+
+#include <QtQml/qqml.h>
+#include <QtQml/QQmlEngine>
+
+#include <QtGui/QPainter>
+#include <QtGui/QImage>
+
+#include <QtCore/QDateTime>
+
+#include "QtWaylandCompositor/private/qwltexturesharingextension_p.h"
+
+class CustomSharingExtension : public QWaylandTextureSharingExtension
+{
+ Q_OBJECT
+public:
+ CustomSharingExtension() {qDebug("Instantiating custom texture sharing extension.");}
+protected:
+ bool customPixelData(const QString &key, QByteArray *data, QSize *size, uint *glInternalFormat) override
+ {
+ qDebug() << "CustomSharingExtension looking for local texture data for" << key;
+ if (key.startsWith("unreasonably large ")) {
+ int w = 10000;
+ int h = 10000;
+ int numBytes = w * h * 4;
+ *data = QByteArray(numBytes, 0);
+ quint32 *pixels = reinterpret_cast<quint32*>(data->data());
+ for (int i = 0; i < w*h; ++i)
+ pixels[i] = 0xff7f1fff;
+ *glInternalFormat = GL_RGBA8;
+ *size = QSize(w,h);
+ return true;
+ }
+
+ QImage img;
+
+ if (key == QLatin1String("test pattern 1")) {
+ img = QImage(128,128,QImage::Format_ARGB32_Premultiplied);
+ img.fill(QColor(0x55,0x0,0x55,0x01));
+ {
+ QPainter p(&img);
+ QPen pen = p.pen();
+ pen.setWidthF(3);
+ pen.setColor(Qt::red);
+ p.setPen(pen);
+ p.drawLine(0,0,128,128);
+ pen.setColor(Qt::green);
+ p.setPen(pen);
+ p.drawLine(128,0,0,128);
+ pen.setColor(Qt::blue);
+ p.setPen(pen);
+ p.drawLine(32,16,96,16);
+ pen.setColor(Qt::black);
+ p.setPen(pen);
+ p.translate(64, 64);
+ p.rotate(45);
+ p.drawText(QRect(-48, -32, 96, 64),
+ QDateTime::currentDateTime().toString(),
+ QTextOption(Qt::AlignHCenter));
+ }
+ }
+
+ if (!img.isNull()) {
+ img = img.convertToFormat(QImage::Format_RGBA8888);
+ *data = QByteArray(reinterpret_cast<const char*>(img.constBits()), img.sizeInBytes());
+ *size = img.size();
+ *glInternalFormat = GL_RGBA8;
+ return true;
+ }
+ return false;
+ }
+};
+
+Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(CustomSharingExtension);
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
+ QGuiApplication app(argc, argv);
+ QQmlApplicationEngine appEngine;
+
+ qmlRegisterType<CustomSharingExtensionQuickExtension>("com.theqtcompany.customsharingextension", 1, 0, "CustomSharingExtension");
+ appEngine.addImageProvider("wlshared", new QWaylandSharedTextureProvider);
+
+ appEngine.load(QUrl("qrc:///qml/main.qml"));
+
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/examples/wayland/texture-sharing/custom-compositor/qml/main.qml b/examples/wayland/texture-sharing/custom-compositor/qml/main.qml
new file mode 100644
index 000000000..16a412fcd
--- /dev/null
+++ b/examples/wayland/texture-sharing/custom-compositor/qml/main.qml
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Wayland module
+**
+** $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$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Window 2.2
+import QtWayland.Compositor 1.3
+
+import com.theqtcompany.customsharingextension 1.0
+
+WaylandCompositor {
+ WaylandOutput {
+ sizeFollowsWindow: true
+ window: Window {
+ width: 1024
+ height: 768
+ visible: true
+ Image {
+ id: background
+ anchors.fill: parent
+ fillMode: Image.Tile
+ source: "qrc:/images/background.png"
+ smooth: true
+
+ Rectangle {
+ width: 100
+ height: 100
+ color: "red"
+ anchors.bottom: parent.bottom;
+ anchors.right: parent.right;
+ MouseArea {
+ anchors.fill: parent
+ onClicked: sharedTextureImage.source = "image://wlshared/car.ktx"
+ }
+ }
+ Image {
+ id: sharedTextureImage
+ anchors.bottom: parent.bottom;
+ anchors.right: parent.right;
+ source: ""
+ }
+ Image {
+ id: topRightImage
+ anchors.top: parent.top;
+ anchors.right: parent.right;
+ source: "image://wlshared/qt_logo.png"
+ }
+ }
+ Repeater {
+ model: shellSurfaces
+ ShellSurfaceItem {
+ autoCreatePopupItems: true
+ shellSurface: modelData
+ onSurfaceDestroyed: shellSurfaces.remove(index)
+ }
+ }
+ }
+ }
+ WlShell {
+ onWlShellSurfaceCreated:
+ shellSurfaces.append({shellSurface: shellSurface});
+ }
+ XdgShellV6 {
+ onToplevelCreated:
+ shellSurfaces.append({shellSurface: xdgSurface});
+ }
+ XdgShell {
+ onToplevelCreated:
+ shellSurfaces.append({shellSurface: xdgSurface});
+ }
+ ListModel { id: shellSurfaces }
+
+ CustomSharingExtension {
+ imageSearchPath: ":/images;."
+ }
+}
diff --git a/examples/wayland/texture-sharing/minimal-compositor.qml b/examples/wayland/texture-sharing/minimal-compositor.qml
new file mode 100644
index 000000000..3f714dc58
--- /dev/null
+++ b/examples/wayland/texture-sharing/minimal-compositor.qml
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $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$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Window 2.2
+import QtWayland.Compositor 1.3
+
+// importing the texture sharing extension:
+import QtWayland.Compositor.TextureSharingExtension 1.0
+
+WaylandCompositor {
+ WaylandOutput {
+ sizeFollowsWindow: true
+ window: Window {
+ width: 1024
+ height: 768
+ visible: true
+ Repeater {
+ model: shellSurfaces
+ ShellSurfaceItem {
+ autoCreatePopupItems: true
+ shellSurface: modelData
+ onSurfaceDestroyed: shellSurfaces.remove(index)
+ }
+ }
+ }
+ }
+ WlShell {
+ onWlShellSurfaceCreated:
+ shellSurfaces.append({shellSurface: shellSurface});
+ }
+ XdgShellV6 {
+ onToplevelCreated:
+ shellSurfaces.append({shellSurface: xdgSurface});
+ }
+ XdgShell {
+ onToplevelCreated:
+ shellSurfaces.append({shellSurface: xdgSurface});
+ }
+ ListModel { id: shellSurfaces }
+
+ // instantiating the texture sharing extension:
+ TextureSharingExtension {
+ imageSearchPath: ".;/tmp;/usr/share/pixmaps"
+ }
+}
diff --git a/examples/wayland/texture-sharing/qml-client/main.cpp b/examples/wayland/texture-sharing/qml-client/main.cpp
new file mode 100644
index 000000000..618d6701d
--- /dev/null
+++ b/examples/wayland/texture-sharing/qml-client/main.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2019 The Qt Company Ltd.
+ ** Contact: https://www.qt.io/licensing/
+ **
+ ** This file is part of the examples of the Qt Wayland module
+ **
+ ** $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 <QGuiApplication>
+#include <QtQuick/QQuickView>
+#include <QStandardPaths>
+#include <QFileInfo>
+#include <QQmlApplicationEngine>
+#include <QDebug>
+#include <QDir>
+#include <QTimer>
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+ QQmlApplicationEngine appEngine;
+
+ appEngine.load(QUrl("qrc:///main.qml"));
+
+ return app.exec();
+}
diff --git a/examples/wayland/texture-sharing/qml-client/main.qml b/examples/wayland/texture-sharing/qml-client/main.qml
new file mode 100644
index 000000000..371a97594
--- /dev/null
+++ b/examples/wayland/texture-sharing/qml-client/main.qml
@@ -0,0 +1,248 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Wayland module
+**
+** $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$
+**
+****************************************************************************/
+
+import QtQuick 2.9
+import QtQuick.Window 2.2
+
+import QtWayland.Client.TextureSharing 1.0
+
+Window {
+ width: 800
+ height: 500
+ visible: true
+
+ Rectangle {
+ anchors.fill: parent
+ color: "#C0FEFE"
+
+ Flickable {
+ anchors.fill: parent
+ contentHeight: imageGrid.height
+
+ Grid {
+ id: imageGrid
+ columns: 2
+ width: parent.width
+ spacing: 25
+ padding: 25
+
+
+ // loadedImage
+ Text {
+ width: 400
+ wrapMode: Text.Wrap
+ text: "An Image element using the shared buffer provider to load from a PNG image.<br>" +
+ "Source: '" + loadedImage.source + "'" +
+ (loadedImage.sourceSize.height <= 0 ? "<font color=\"#FF0000\"><br>[Image not loaded]</font>" : "")
+ }
+ Image {
+ id: loadedImage
+ fillMode: Image.PreserveAspectFit
+ source: "image://wlshared/qt_logo.png"
+ }
+ Rectangle {
+ visible: loadedImage.height <= 0
+ width:100; height: 100
+ color: "green"
+ }
+
+ // paintedImage
+ Text {
+ width: 400
+ wrapMode: Text.Wrap
+ text: "An Image element using the shared buffer provider.<br>" +
+ "This texture is created by the compositor using QPainter. <br>" +
+ "Source: '" + paintedImage.source + "'" +
+ (paintedImage.sourceSize.height <= 0 ? "<font color=\"#FF0000\"><br>[Image not loaded]</font>" : "")
+ }
+ Image {
+ id: paintedImage
+ fillMode: Image.PreserveAspectFit
+ source: "image://wlshared/test pattern 1"
+ }
+ Rectangle {
+ visible: paintedImage.height <= 0
+ width:100; height: 100
+ color: "green"
+ }
+
+ // ktxImage
+ Text {
+ width: 400
+ wrapMode: Text.Wrap
+ text: "An Image element using the shared buffer provider to load an ETC2 compressed texture." +
+ "<br>Source: '" + ktxImage.source + "'" +
+ (ktxImage.sourceSize.height <= 0 ? "<font color=\"#FF0000\"><br>[Image not loaded]</font>" : "")
+ }
+ Image {
+ id: ktxImage
+ source: "image://wlshared/car.ktx"
+ fillMode: Image.PreserveAspectFit
+ }
+ Rectangle {
+ visible: ktxImage.height <= 0
+ width:100; height: 100
+ color: "green"
+ }
+
+ //astcImage
+ Text {
+ width: 400
+ wrapMode: Text.Wrap
+ text: "An Image element using the shared buffer provider to load an ASTC compressed texture." +
+ "<br>Source: '" + astcImage.source + "'" +
+ (astcImage.sourceSize.height <= 0 ? "<font color=\"#FF0000\"><br>[Image not loaded]</font>" : "")
+ }
+
+ Image {
+ id: astcImage
+ source: "image://wlshared/qt4.astc"
+ fillMode: Image.PreserveAspectFit
+ }
+ Rectangle {
+ visible: astcImage.height <= 0
+ width:100; height: 100
+ color: "green"
+ }
+
+ // dynamicImage
+ Column {
+ Text {
+ width: 400
+ wrapMode: Text.Wrap
+ text: "An Image element using the shared buffer provider." +
+ "<br>Source: '" + dynamicImage.source + "'" +
+ (dynamicImage.sourceSize.height <= 0 ? "<font color=\"#FF0000\"><br>[Image not loaded]</font>" : "")
+ }
+ Row {
+ spacing: 10
+ Text {
+ text: "Enter filename:"
+ }
+ Rectangle {
+ color: "white"
+ width: sourceEdit.contentWidth + 30
+ height: sourceEdit.contentHeight
+ TextInput {
+ id: sourceEdit
+ anchors.fill: parent
+ horizontalAlignment: TextInput.AlignHCenter
+ onEditingFinished: dynamicImage.source = text ? "image://wlshared/" + text : ""
+ }
+ }
+ }
+ }
+ Image {
+ id: dynamicImage
+ fillMode: Image.PreserveAspectFit
+ }
+ Rectangle {
+ visible: dynamicImage.height <= 0
+ width:100; height: 100
+ color: "green"
+ }
+
+ // largeImage
+ Text {
+ width: 400
+ wrapMode: Text.Wrap
+ text: "An Image element using the shared buffer provider.<br>" +
+ "Left click to load a very large image. " +
+ "Right click to unload the image, potentially freeing graphics memory on the server-side " +
+ "if no other client is using the image." +
+ "<br>Source: '" + largeImage.source + "'" +
+ "<br>Size: " + largeImage.sourceSize +
+ (largeImage.sourceSize.height <= 0 ? "<font color=\"#FF0000\"><br>[Image not loaded]</font>" : "")
+ }
+
+ Rectangle {
+ width: 200
+ height: 200
+ border.color: "black"
+ border.width: 2
+ color: "transparent"
+ Image {
+ id: largeImage
+ anchors.fill: parent
+ fillMode: Image.PreserveAspectFit
+ }
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+ onClicked: {
+ if (mouse.button == Qt.LeftButton)
+ largeImage.source = "image://wlshared/unreasonably large image"
+ else
+ largeImage.source = ""
+
+ }
+ }
+ }
+
+ } // Grid
+ }
+
+ Rectangle {
+ color: "gray"
+ width: parent.width
+ height: 20
+ anchors.bottom: parent.bottom
+
+ Text {
+ color: "white"
+ anchors.fill: parent
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ text: "Scroll or drag for more"
+ }
+ }
+
+ }
+}
diff --git a/examples/wayland/texture-sharing/qml-client/qml-client.pro b/examples/wayland/texture-sharing/qml-client/qml-client.pro
new file mode 100644
index 000000000..67d5c7071
--- /dev/null
+++ b/examples/wayland/texture-sharing/qml-client/qml-client.pro
@@ -0,0 +1,13 @@
+QT += quick
+
+SOURCES += \
+ main.cpp
+
+RESOURCES += \
+ qml-client.qrc
+
+DISTFILES += \
+ main.qml
+
+target.path = $$[QT_INSTALL_EXAMPLES]/wayland/texture-sharing/qml-client
+INSTALLS += target
diff --git a/examples/wayland/texture-sharing/qml-client/qml-client.qrc b/examples/wayland/texture-sharing/qml-client/qml-client.qrc
new file mode 100644
index 000000000..5f6483ac3
--- /dev/null
+++ b/examples/wayland/texture-sharing/qml-client/qml-client.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ </qresource>
+</RCC>
diff --git a/examples/wayland/texture-sharing/texture-sharing.pro b/examples/wayland/texture-sharing/texture-sharing.pro
new file mode 100644
index 000000000..3f7792828
--- /dev/null
+++ b/examples/wayland/texture-sharing/texture-sharing.pro
@@ -0,0 +1,5 @@
+TEMPLATE=subdirs
+
+SUBDIRS += \
+ qml-client \
+ custom-compositor
diff --git a/examples/wayland/wayland.pro b/examples/wayland/wayland.pro
index 5551b5703..f9287481b 100644
--- a/examples/wayland/wayland.pro
+++ b/examples/wayland/wayland.pro
@@ -3,12 +3,11 @@ TEMPLATE=subdirs
!qtHaveModule(waylandcompositor): \
return()
-!qtConfig(opengl): \
- return()
-
-SUBDIRS += \
- qwindow-compositor \
- minimal-cpp
+qtConfig(opengl) {
+ SUBDIRS += \
+ qwindow-compositor \
+ minimal-cpp
+}
qtHaveModule(quick) {
SUBDIRS += minimal-qml
@@ -21,8 +20,13 @@ qtHaveModule(quick) {
SUBDIRS += server-side-decoration
qtHaveModule(waylandclient) {
SUBDIRS += \
- custom-extension \
- server-buffer
+ custom-extension
+
+ qtConfig(opengl) {
+ SUBDIRS += \
+ server-buffer \
+ texture-sharing
+ }
}
SUBDIRS += hwlayer-compositor
}
diff --git a/src/3rdparty/protocol/idle-inhibit-unstable-v1.xml b/src/3rdparty/protocol/idle-inhibit-unstable-v1.xml
new file mode 100644
index 000000000..9c06cdcba
--- /dev/null
+++ b/src/3rdparty/protocol/idle-inhibit-unstable-v1.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="idle_inhibit_unstable_v1">
+
+ <copyright>
+ Copyright © 2015 Samsung Electronics Co., 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_idle_inhibit_manager_v1" version="1">
+ <description summary="control behavior when display idles">
+ This interface permits inhibiting the idle behavior such as screen
+ blanking, locking, and screensaving. The client binds the idle manager
+ globally, then creates idle-inhibitor objects for each surface.
+
+ 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="destroy the idle inhibitor object">
+ Destroy the inhibit manager.
+ </description>
+ </request>
+
+ <request name="create_inhibitor">
+ <description summary="create a new inhibitor object">
+ Create a new inhibitor object associated with the given surface.
+ </description>
+ <arg name="id" type="new_id" interface="zwp_idle_inhibitor_v1"/>
+ <arg name="surface" type="object" interface="wl_surface"
+ summary="the surface that inhibits the idle behavior"/>
+ </request>
+
+ </interface>
+
+ <interface name="zwp_idle_inhibitor_v1" version="1">
+ <description summary="context object for inhibiting idle behavior">
+ An idle inhibitor prevents the output that the associated surface is
+ visible on from being set to a state where it is not visually usable due
+ to lack of user interaction (e.g. blanked, dimmed, locked, set to power
+ save, etc.) Any screensaver processes are also blocked from displaying.
+
+ If the surface is destroyed, unmapped, becomes occluded, loses
+ visibility, or otherwise becomes not visually relevant for the user, the
+ idle inhibitor will not be honored by the compositor; if the surface
+ subsequently regains visibility the inhibitor takes effect once again.
+ Likewise, the inhibitor isn't honored if the system was already idled at
+ the time the inhibitor was established, although if the system later
+ de-idles and re-idles the inhibitor will take effect.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the idle inhibitor object">
+ Remove the inhibitor effect from the associated wl_surface.
+ </description>
+ </request>
+
+ </interface>
+</protocol>
diff --git a/src/3rdparty/protocol/qt_attribution.json b/src/3rdparty/protocol/qt_attribution.json
index 7e068f755..c49ead4f3 100644
--- a/src/3rdparty/protocol/qt_attribution.json
+++ b/src/3rdparty/protocol/qt_attribution.json
@@ -56,6 +56,23 @@ Copyright (c) 2013 BMW Car IT GmbH"
},
{
+ "Id": "wayland-primary-selection-protocol",
+ "Name": "Wayland Primary Selection Protocol",
+ "QDocModule": "qtwaylandcompositor",
+ "QtUsage": "Used in the Qt Wayland platform plugin",
+ "Files": "wp-primary-selection-unstable-v1.xml",
+
+ "Description": "The primary selection extension allows copying text by selecting it and pasting it with the middle mouse button.",
+ "Homepage": "https://wayland.freedesktop.org",
+ "Version": "1",
+ "DownloadLocation": "https://cgit.freedesktop.org/wayland/wayland-protocols/plain/unstable/primary-selection/primary-selection-unstable-v1.xml",
+ "LicenseId": "MIT",
+ "License": "MIT License",
+ "LicenseFile": "MIT_LICENSE.txt",
+ "Copyright": "Copyright © 2015 2016 Red Hat"
+ },
+
+ {
"Id": "wayland-scaler-protocol",
"Name": "Wayland Scaler Protocol",
"QDocModule": "qtwaylandcompositor",
@@ -110,8 +127,9 @@ Copyright (c) 2013 BMW Car IT GmbH"
"Id": "wayland-xdg-output-protocol",
"Name": "Wayland XDG Output Protocol",
"QDocModule": "qtwaylandcompositor",
- "QtUsage": "Used in the Qt Wayland platform plugin.",
+ "QtUsage": "Used in the Qt Wayland Compositor API, and the Qt Wayland platform plugin.",
"Files": "xdg-output-unstable-v1.xml",
+
"Description": "The XDG Output protocol is an extended way to describe output regions under Wayland",
"Homepage": "https://wayland.freedesktop.org",
"Version": "unstable v1, version 2",
diff --git a/src/3rdparty/protocol/wp-primary-selection-unstable-v1.xml b/src/3rdparty/protocol/wp-primary-selection-unstable-v1.xml
new file mode 100644
index 000000000..e5a39e34c
--- /dev/null
+++ b/src/3rdparty/protocol/wp-primary-selection-unstable-v1.xml
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wp_primary_selection_unstable_v1">
+ <copyright>
+ Copyright © 2015, 2016 Red Hat
+
+ 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>
+
+ <description summary="Primary selection protocol">
+ This protocol provides the ability to have a primary selection device to
+ match that of the X server. This primary selection is a shortcut to the
+ common clipboard selection, where text just needs to be selected in order
+ to allow copying it elsewhere. The de facto way to perform this action
+ is the middle mouse button, although it is not limited to this one.
+
+ Clients wishing to honor primary selection should create a primary
+ selection source and set it as the selection through
+ wp_primary_selection_device.set_selection whenever the text selection
+ changes. In order to minimize calls in pointer-driven text selection,
+ it should happen only once after the operation finished. Similarly,
+ a NULL source should be set when text is unselected.
+
+ wp_primary_selection_offer objects are first announced through the
+ wp_primary_selection_device.data_offer event. Immediately after this event,
+ the primary data offer will emit wp_primary_selection_offer.offer events
+ to let know of the mime types being offered.
+
+ When the primary selection changes, the client with the keyboard focus
+ will receive wp_primary_selection_device.selection events. Only the client
+ with the keyboard focus will receive such events with a non-NULL
+ wp_primary_selection_offer. Across keyboard focus changes, previously
+ focused clients will receive wp_primary_selection_device.events with a
+ NULL wp_primary_selection_offer.
+
+ In order to request the primary selection data, the client must pass
+ a recent serial pertaining to the press event that is triggering the
+ operation, if the compositor deems the serial valid and recent, the
+ wp_primary_selection_source.send event will happen in the other end
+ to let the transfer begin. The client owning the primary selection
+ should write the requested data, and close the file descriptor
+ immediately.
+
+ If the primary selection owner client disappeared during the transfer,
+ the client reading the data will receive a
+ wp_primary_selection_device.selection event with a NULL
+ wp_primary_selection_offer, the client should take this as a hint
+ to finish the reads related to the no longer existing offer.
+
+ The primary selection owner should be checking for errors during
+ writes, merely cancelling the ongoing transfer if any happened.
+ </description>
+
+ <interface name="zwp_primary_selection_device_manager_v1" version="1">
+ <description summary="X primary selection emulation">
+ The primary selection device manager is a singleton global object that
+ provides access to the primary selection. It allows to create
+ wp_primary_selection_source objects, as well as retrieving the per-seat
+ wp_primary_selection_device objects.
+ </description>
+
+ <request name="create_source">
+ <description summary="create a new primary selection source">
+ Create a new primary selection source.
+ </description>
+ <arg name="id" type="new_id" interface="zwp_primary_selection_source_v1"/>
+ </request>
+
+ <request name="get_device">
+ <description summary="create a new primary selection device">
+ Create a new data device for a given seat.
+ </description>
+ <arg name="id" type="new_id" interface="zwp_primary_selection_device_v1"/>
+ <arg name="seat" type="object" interface="wl_seat"/>
+ </request>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the primary selection device manager">
+ Destroy the primary selection device manager.
+ </description>
+ </request>
+ </interface>
+
+ <interface name="zwp_primary_selection_device_v1" version="1">
+ <request name="set_selection">
+ <description summary="set the primary selection">
+ Replaces the current selection. The previous owner of the primary
+ selection will receive a wp_primary_selection_source.cancelled event.
+
+ To unset the selection, set the source to NULL.
+ </description>
+ <arg name="source" type="object" interface="zwp_primary_selection_source_v1" allow-null="true"/>
+ <arg name="serial" type="uint" summary="serial of the event that triggered this request"/>
+ </request>
+
+ <event name="data_offer">
+ <description summary="introduce a new wp_primary_selection_offer">
+ Introduces a new wp_primary_selection_offer object that may be used
+ to receive the current primary selection. Immediately following this
+ event, the new wp_primary_selection_offer object will send
+ wp_primary_selection_offer.offer events to describe the offered mime
+ types.
+ </description>
+ <arg name="offer" type="new_id" interface="zwp_primary_selection_offer_v1"/>
+ </event>
+
+ <event name="selection">
+ <description summary="advertise a new primary selection">
+ The wp_primary_selection_device.selection event is sent to notify the
+ client of a new primary selection. This event is sent after the
+ wp_primary_selection.data_offer event introducing this object, and after
+ the offer has announced its mimetypes through
+ wp_primary_selection_offer.offer.
+
+ The data_offer is valid until a new offer or NULL is received
+ or until the client loses keyboard focus. The client must destroy the
+ previous selection data_offer, if any, upon receiving this event.
+ </description>
+ <arg name="id" type="object" interface="zwp_primary_selection_offer_v1" allow-null="true"/>
+ </event>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the primary selection device">
+ Destroy the primary selection device.
+ </description>
+ </request>
+ </interface>
+
+ <interface name="zwp_primary_selection_offer_v1" version="1">
+ <description summary="offer to transfer primary selection contents">
+ A wp_primary_selection_offer represents an offer to transfer the contents
+ of the primary selection clipboard to the client. Similar to
+ wl_data_offer, the offer also describes the mime types that the data can
+ be converted to and provides the mechanisms for transferring the data
+ directly to the client.
+ </description>
+
+ <request name="receive">
+ <description summary="request that the data is transferred">
+ To transfer the contents of the primary selection clipboard, the client
+ issues this request and indicates the mime type that it wants to
+ receive. The transfer happens through the passed file descriptor
+ (typically created with the pipe system call). The source client writes
+ the data in the mime type representation requested and then closes the
+ file descriptor.
+
+ The receiving client reads from the read end of the pipe until EOF and
+ closes its end, at which point the transfer is complete.
+ </description>
+ <arg name="mime_type" type="string"/>
+ <arg name="fd" type="fd"/>
+ </request>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the primary selection offer">
+ Destroy the primary selection offer.
+ </description>
+ </request>
+
+ <event name="offer">
+ <description summary="advertise offered mime type">
+ Sent immediately after creating announcing the
+ wp_primary_selection_offer through
+ wp_primary_selection_device.data_offer. One event is sent per offered
+ mime type.
+ </description>
+ <arg name="mime_type" type="string"/>
+ </event>
+ </interface>
+
+ <interface name="zwp_primary_selection_source_v1" version="1">
+ <description summary="offer to replace the contents of the primary selection">
+ The source side of a wp_primary_selection_offer, it provides a way to
+ describe the offered data and respond to requests to transfer the
+ requested contents of the primary selection clipboard.
+ </description>
+
+ <request name="offer">
+ <description summary="add an offered mime type">
+ This request adds a mime type to the set of mime types advertised to
+ targets. Can be called several times to offer multiple types.
+ </description>
+ <arg name="mime_type" type="string"/>
+ </request>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the primary selection source">
+ Destroy the primary selection source.
+ </description>
+ </request>
+
+ <event name="send">
+ <description summary="send the primary selection contents">
+ Request for the current primary selection contents from the client.
+ Send the specified mime type over the passed file descriptor, then
+ close it.
+ </description>
+ <arg name="mime_type" type="string"/>
+ <arg name="fd" type="fd"/>
+ </event>
+
+ <event name="cancelled">
+ <description summary="request for primary selection contents was canceled">
+ This primary selection source is no longer valid. The client should
+ clean up and destroy this primary selection source.
+ </description>
+ </event>
+ </interface>
+</protocol>
diff --git a/src/client/client.pro b/src/client/client.pro
index 4233ac950..d0ae9009e 100644
--- a/src/client/client.pro
+++ b/src/client/client.pro
@@ -31,6 +31,7 @@ WAYLANDCLIENTSOURCES += \
../extensions/touch-extension.xml \
../extensions/qt-key-unstable-v1.xml \
../extensions/qt-windowmanager.xml \
+ ../3rdparty/protocol/wp-primary-selection-unstable-v1.xml \
../3rdparty/protocol/text-input-unstable-v2.xml \
../3rdparty/protocol/xdg-output-unstable-v1.xml \
../3rdparty/protocol/wayland.xml
@@ -46,6 +47,7 @@ SOURCES += qwaylandintegration.cpp \
qwaylandshellsurface.cpp \
qwaylandextendedsurface.cpp \
qwaylandsubsurface.cpp \
+ qwaylandsurface.cpp \
qwaylandtouch.cpp \
qwaylandqtkey.cpp \
../shared/qwaylandmimehelper.cpp \
@@ -70,6 +72,7 @@ HEADERS += qwaylandintegration_p.h \
qwaylandshellsurface_p.h \
qwaylandextendedsurface_p.h \
qwaylandsubsurface_p.h \
+ qwaylandsurface_p.h \
qwaylandtouch_p.h \
qwaylandqtkey_p.h \
qwaylandabstractdecoration_p.h \
@@ -116,6 +119,11 @@ qtConfig(wayland-datadevice) {
qwaylanddatasource.cpp
}
+qtConfig(wayland-client-primary-selection) {
+ HEADERS += qwaylandprimaryselectionv1_p.h
+ SOURCES += qwaylandprimaryselectionv1.cpp
+}
+
qtConfig(draganddrop) {
HEADERS += \
qwaylanddnd_p.h
diff --git a/src/client/configure.json b/src/client/configure.json
index 91024c9d3..e9e16324b 100644
--- a/src/client/configure.json
+++ b/src/client/configure.json
@@ -93,6 +93,11 @@
"condition": "features.draganddrop || features.clipboard",
"output": [ "privateFeature" ]
},
+ "wayland-client-primary-selection": {
+ "label": "primary-selection clipboard",
+ "condition": "features.clipboard",
+ "output": [ "privateFeature" ]
+ },
"wayland-client-fullscreen-shell-v1": {
"label": "fullscreen-shell-v1",
"condition": "features.wayland-client",
@@ -158,14 +163,9 @@
"condition": "features.wayland-client && features.opengl && features.egl && tests.dmabuf-server-buffer",
"output": [ "privateFeature" ]
},
- "wayland-client-texture-sharing-experimental" : {
- "label": "Texture sharing (experimental)",
- "autoDetect": "false",
- "output": [ "privateFeature" ]
- },
"wayland-vulkan-server-buffer": {
"label": "Vulkan-based server buffer integration",
- "condition": "features.wayland-client && features.opengl && features.egl && tests.vulkan-server-buffer && features.wayland-client-texture-sharing-experimental",
+ "condition": "features.wayland-client && features.opengl && features.egl && tests.vulkan-server-buffer",
"output": [ "privateFeature" ]
},
"wayland-shm-emulation-server-buffer": {
diff --git a/src/client/qwaylandclipboard.cpp b/src/client/qwaylandclipboard.cpp
index 60820da92..369c6ec07 100644
--- a/src/client/qwaylandclipboard.cpp
+++ b/src/client/qwaylandclipboard.cpp
@@ -43,6 +43,9 @@
#include "qwaylanddataoffer_p.h"
#include "qwaylanddatasource_p.h"
#include "qwaylanddatadevice_p.h"
+#if QT_CONFIG(wayland_client_primary_selection)
+#include "qwaylandprimaryselectionv1_p.h"
+#endif
QT_BEGIN_NAMESPACE
@@ -59,44 +62,74 @@ QWaylandClipboard::~QWaylandClipboard()
QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
{
- if (mode != QClipboard::Clipboard)
+ auto *seat = mDisplay->currentInputDevice();
+ if (!seat)
return &m_emptyData;
- QWaylandInputDevice *inputDevice = mDisplay->currentInputDevice();
- if (!inputDevice || !inputDevice->dataDevice())
+ switch (mode) {
+ case QClipboard::Clipboard:
+ if (auto *dataDevice = seat->dataDevice()) {
+ if (auto *source = dataDevice->selectionSource())
+ return source->mimeData();
+ if (auto *offer = dataDevice->selectionOffer())
+ return offer->mimeData();
+ }
+ return &m_emptyData;
+ case QClipboard::Selection:
+#if QT_CONFIG(wayland_client_primary_selection)
+ if (auto *selectionDevice = seat->primarySelectionDevice()) {
+ if (auto *source = selectionDevice->selectionSource())
+ return source->mimeData();
+ if (auto *offer = selectionDevice->selectionOffer())
+ return offer->mimeData();
+ }
+#endif
+ return &m_emptyData;
+ default:
return &m_emptyData;
-
- QWaylandDataSource *source = inputDevice->dataDevice()->selectionSource();
- if (source) {
- return source->mimeData();
}
-
- if (inputDevice->dataDevice()->selectionOffer())
- return inputDevice->dataDevice()->selectionOffer()->mimeData();
-
- return &m_emptyData;
}
void QWaylandClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
{
- if (mode != QClipboard::Clipboard)
- return;
-
- QWaylandInputDevice *inputDevice = mDisplay->currentInputDevice();
- if (!inputDevice || !inputDevice->dataDevice())
+ auto *seat = mDisplay->currentInputDevice();
+ if (!seat)
return;
static const QString plain = QStringLiteral("text/plain");
static const QString utf8 = QStringLiteral("text/plain;charset=utf-8");
+
if (data && data->hasFormat(plain) && !data->hasFormat(utf8))
data->setData(utf8, data->data(plain));
- inputDevice->dataDevice()->setSelectionSource(data ? new QWaylandDataSource(mDisplay->dndSelectionHandler(), data) : nullptr);
- emitChanged(mode);
+ switch (mode) {
+ case QClipboard::Clipboard:
+ if (auto *dataDevice = seat->dataDevice()) {
+ dataDevice->setSelectionSource(data ? new QWaylandDataSource(mDisplay->dndSelectionHandler(), data) : nullptr);
+ emitChanged(mode);
+ }
+ break;
+ case QClipboard::Selection:
+#if QT_CONFIG(wayland_client_primary_selection)
+ if (auto *selectionDevice = seat->primarySelectionDevice()) {
+ selectionDevice->setSelectionSource(data ? new QWaylandPrimarySelectionSourceV1(mDisplay->primarySelectionManager(), data) : nullptr);
+ emitChanged(mode);
+ }
+#endif
+ break;
+ default:
+ break;
+ }
}
bool QWaylandClipboard::supportsMode(QClipboard::Mode mode) const
{
+#if QT_CONFIG(wayland_client_primary_selection)
+ if (mode == QClipboard::Selection) {
+ auto *seat = mDisplay->currentInputDevice();
+ return seat && seat->primarySelectionDevice();
+ }
+#endif
return mode == QClipboard::Clipboard;
}
diff --git a/src/client/qwaylandcursor.cpp b/src/client/qwaylandcursor.cpp
index 8b2ed036d..4356b23a0 100644
--- a/src/client/qwaylandcursor.cpp
+++ b/src/client/qwaylandcursor.cpp
@@ -48,6 +48,8 @@
#include <wayland-cursor.h>
+#include <algorithm>
+
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
@@ -75,7 +77,10 @@ wl_cursor *QWaylandCursorTheme::requestCursor(WaylandCursor shape)
if (struct wl_cursor *cursor = m_cursors.value(shape, nullptr))
return cursor;
- static const QMultiMap<WaylandCursor, QByteArray>cursorNamesMap {
+ static Q_CONSTEXPR struct ShapeAndName {
+ WaylandCursor shape;
+ const char name[33];
+ } cursorNamesMap[] = {
{ArrowCursor, "left_ptr"},
{ArrowCursor, "default"},
{ArrowCursor, "top_left_arrow"},
@@ -193,9 +198,14 @@ wl_cursor *QWaylandCursorTheme::requestCursor(WaylandCursor shape)
{ResizeSouthWestCursor, "bottom_left_corner"},
};
- QList<QByteArray> cursorNames = cursorNamesMap.values(shape);
- for (auto &name : qAsConst(cursorNames)) {
- if (wl_cursor *cursor = wl_cursor_theme_get_cursor(m_theme, name.constData())) {
+ const auto byShape = [](ShapeAndName lhs, ShapeAndName rhs) {
+ return lhs.shape < rhs.shape;
+ };
+ Q_ASSERT(std::is_sorted(std::begin(cursorNamesMap), std::end(cursorNamesMap), byShape));
+ const auto p = std::equal_range(std::begin(cursorNamesMap), std::end(cursorNamesMap),
+ ShapeAndName{shape, ""}, byShape);
+ for (auto it = p.first; it != p.second; ++it) {
+ if (wl_cursor *cursor = wl_cursor_theme_get_cursor(m_theme, it->name)) {
m_cursors.insert(shape, cursor);
return cursor;
}
@@ -209,7 +219,7 @@ wl_cursor *QWaylandCursorTheme::requestCursor(WaylandCursor shape)
return nullptr;
}
-struct wl_cursor_image *QWaylandCursorTheme::cursorImage(Qt::CursorShape shape)
+::wl_cursor_image *QWaylandCursorTheme::cursorImage(Qt::CursorShape shape, uint millisecondsIntoAnimation)
{
struct wl_cursor *waylandCursor = nullptr;
@@ -227,8 +237,9 @@ struct wl_cursor_image *QWaylandCursorTheme::cursorImage(Qt::CursorShape shape)
return nullptr;
}
- struct wl_cursor_image *image = waylandCursor->images[0];
- struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
+ int frame = wl_cursor_frame(waylandCursor, millisecondsIntoAnimation);
+ ::wl_cursor_image *image = waylandCursor->images[frame];
+ ::wl_buffer *buffer = wl_cursor_image_get_buffer(image);
if (!buffer) {
qCWarning(lcQpaWayland) << "Could not find buffer for cursor";
return nullptr;
diff --git a/src/client/qwaylandcursor_p.h b/src/client/qwaylandcursor_p.h
index 6c48fb628..a4605f3d2 100644
--- a/src/client/qwaylandcursor_p.h
+++ b/src/client/qwaylandcursor_p.h
@@ -75,7 +75,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandCursorTheme
public:
static QWaylandCursorTheme *create(QWaylandShm *shm, int size, const QString &themeName);
~QWaylandCursorTheme();
- struct wl_cursor_image *cursorImage(Qt::CursorShape shape);
+ ::wl_cursor_image *cursorImage(Qt::CursorShape shape, uint millisecondsIntoAnimation = 0);
private:
enum WaylandCursor {
diff --git a/src/client/qwaylanddatadevice.cpp b/src/client/qwaylanddatadevice.cpp
index 990f92ba9..fc3c7077a 100644
--- a/src/client/qwaylanddatadevice.cpp
+++ b/src/client/qwaylanddatadevice.cpp
@@ -47,6 +47,7 @@
#include "qwaylandinputdevice_p.h"
#include "qwaylanddisplay_p.h"
#include "qwaylandabstractdecoration_p.h"
+#include "qwaylandsurface_p.h"
#include <QtCore/QMimeData>
#include <QtGui/QGuiApplication>
@@ -104,9 +105,10 @@ QWaylandDataOffer *QWaylandDataDevice::dragOffer() const
bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
{
- QWaylandWindow *origin = m_display->currentInputDevice()->pointerFocus();
+ auto *seat = m_display->currentInputDevice();
+ auto *origin = seat->pointerFocus();
if (!origin)
- origin = m_display->currentInputDevice()->touchFocus();
+ origin = seat->touchFocus();
if (!origin) {
qCDebug(lcQpaWayland) << "Couldn't start a drag because the origin window could not be found.";
@@ -116,7 +118,7 @@ bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData));
connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled);
- start_drag(m_dragSource->object(), origin->object(), icon->object(), m_display->currentInputDevice()->serial());
+ start_drag(m_dragSource->object(), origin->wlSurface(), icon->wlSurface(), m_display->currentInputDevice()->serial());
return true;
}
diff --git a/src/client/qwaylanddataoffer.cpp b/src/client/qwaylanddataoffer.cpp
index 3da16ed00..4c06277fe 100644
--- a/src/client/qwaylanddataoffer.cpp
+++ b/src/client/qwaylanddataoffer.cpp
@@ -58,7 +58,8 @@ static QString utf8Text()
QWaylandDataOffer::QWaylandDataOffer(QWaylandDisplay *display, struct ::wl_data_offer *offer)
: QtWayland::wl_data_offer(offer)
- , m_mimeData(new QWaylandMimeData(this, display))
+ , m_display(display)
+ , m_mimeData(new QWaylandMimeData(this))
{
}
@@ -81,14 +82,19 @@ QMimeData *QWaylandDataOffer::mimeData()
return m_mimeData.data();
}
+void QWaylandDataOffer::startReceiving(const QString &mimeType, int fd)
+{
+ receive(mimeType, fd);
+ wl_display_flush(m_display->wl_display());
+}
+
void QWaylandDataOffer::data_offer_offer(const QString &mime_type)
{
m_mimeData->appendFormat(mime_type);
}
-QWaylandMimeData::QWaylandMimeData(QWaylandDataOffer *dataOffer, QWaylandDisplay *display)
+QWaylandMimeData::QWaylandMimeData(QWaylandAbstractDataOffer *dataOffer)
: m_dataOffer(dataOffer)
- , m_display(display)
{
}
@@ -140,8 +146,7 @@ QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QVariant::T
return QVariant();
}
- m_dataOffer->receive(mime, pipefd[1]);
- wl_display_flush(m_display->wl_display());
+ m_dataOffer->startReceiving(mime, pipefd[1]);
close(pipefd[1]);
diff --git a/src/client/qwaylanddataoffer_p.h b/src/client/qwaylanddataoffer_p.h
index 5412400a5..9cf1483ca 100644
--- a/src/client/qwaylanddataoffer_p.h
+++ b/src/client/qwaylanddataoffer_p.h
@@ -65,27 +65,40 @@ namespace QtWaylandClient {
class QWaylandDisplay;
class QWaylandMimeData;
-class Q_WAYLAND_CLIENT_EXPORT QWaylandDataOffer : public QtWayland::wl_data_offer
+class QWaylandAbstractDataOffer
+{
+public:
+ virtual void startReceiving(const QString &mimeType, int fd) = 0;
+ virtual QMimeData *mimeData() = 0;
+
+ virtual ~QWaylandAbstractDataOffer() = default;
+};
+
+class Q_WAYLAND_CLIENT_EXPORT QWaylandDataOffer
+ : public QtWayland::wl_data_offer // needs to be the first because we do static casts from the user pointer to the wrapper
+ , public QWaylandAbstractDataOffer
{
public:
explicit QWaylandDataOffer(QWaylandDisplay *display, struct ::wl_data_offer *offer);
~QWaylandDataOffer() override;
+ QMimeData *mimeData() override;
QString firstFormat() const;
- QMimeData *mimeData();
+ void startReceiving(const QString &mimeType, int fd) override;
protected:
void data_offer_offer(const QString &mime_type) override;
private:
+ QWaylandDisplay *m_display = nullptr;
QScopedPointer<QWaylandMimeData> m_mimeData;
};
class QWaylandMimeData : public QInternalMimeData {
public:
- explicit QWaylandMimeData(QWaylandDataOffer *dataOffer, QWaylandDisplay *display);
+ explicit QWaylandMimeData(QWaylandAbstractDataOffer *dataOffer);
~QWaylandMimeData() override;
void appendFormat(const QString &mimeType);
@@ -98,13 +111,12 @@ protected:
private:
int readData(int fd, QByteArray &data) const;
- mutable QWaylandDataOffer *m_dataOffer = nullptr;
- QWaylandDisplay *m_display = nullptr;
+ QWaylandAbstractDataOffer *m_dataOffer = nullptr;
mutable QStringList m_types;
mutable QHash<QString, QByteArray> m_data;
};
-}
+} // namespace QtWaylandClient
QT_END_NAMESPACE
#endif
diff --git a/src/client/qwaylanddatasource.cpp b/src/client/qwaylanddatasource.cpp
index 0c6ad50e4..ea76943a7 100644
--- a/src/client/qwaylanddatasource.cpp
+++ b/src/client/qwaylanddatasource.cpp
@@ -60,7 +60,8 @@ QWaylandDataSource::QWaylandDataSource(QWaylandDataDeviceManager *dataDeviceMana
{
if (!mimeData)
return;
- Q_FOREACH (const QString &format, mimeData->formats()) {
+ const auto formats = mimeData->formats();
+ for (const QString &format : formats) {
offer(format);
}
}
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
index 78524f6fc..a17e8917a 100644
--- a/src/client/qwaylanddisplay.cpp
+++ b/src/client/qwaylanddisplay.cpp
@@ -41,6 +41,7 @@
#include "qwaylandintegration_p.h"
#include "qwaylandwindow_p.h"
+#include "qwaylandsurface_p.h"
#include "qwaylandabstractdecoration_p.h"
#include "qwaylandscreen_p.h"
#include "qwaylandcursor_p.h"
@@ -51,7 +52,10 @@
#if QT_CONFIG(wayland_datadevice)
#include "qwaylanddatadevicemanager_p.h"
#include "qwaylanddatadevice_p.h"
-#endif
+#endif // QT_CONFIG(wayland_datadevice)
+#if QT_CONFIG(wayland_client_primary_selection)
+#include "qwaylandprimaryselectionv1_p.h"
+#endif // QT_CONFIG(wayland_client_primary_selection)
#if QT_CONFIG(cursor)
#include <wayland-cursor.h>
#endif
@@ -68,6 +72,7 @@
#include "qwaylandqtkey_p.h"
#include <QtWaylandClient/private/qwayland-text-input-unstable-v2.h>
+#include <QtWaylandClient/private/qwayland-wp-primary-selection-unstable-v1.h>
#include <QtCore/private/qcore_unix_p.h>
@@ -109,7 +114,7 @@ struct ::wl_region *QWaylandDisplay::createRegion(const QRegion &qregion)
return nullptr;
}
- return mSubCompositor->get_subsurface(window->object(), parent->object());
+ return mSubCompositor->get_subsurface(window->wlSurface(), parent->wlSurface());
}
QWaylandShellIntegration *QWaylandDisplay::shellIntegration() const
@@ -162,13 +167,11 @@ QWaylandDisplay::~QWaylandDisplay(void)
if (mSyncCallback)
wl_callback_destroy(mSyncCallback);
- qDeleteAll(mInputDevices);
- mInputDevices.clear();
+ qDeleteAll(qExchange(mInputDevices, {}));
- foreach (QWaylandScreen *screen, mScreens) {
+ for (QWaylandScreen *screen : qExchange(mScreens, {})) {
QWindowSystemInterface::handleScreenRemoved(screen);
}
- mScreens.clear();
qDeleteAll(mWaitingScreens);
#if QT_CONFIG(wayland_datadevice)
@@ -307,6 +310,10 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
mTouchExtension.reset(new QWaylandTouchExtension(this, id));
} else if (interface == QStringLiteral("zqt_key_v1")) {
mQtKeyExtension.reset(new QWaylandQtKeyExtension(this, id));
+#if QT_CONFIG(wayland_client_primary_selection)
+ } else if (interface == QStringLiteral("zwp_primary_selection_device_manager_v1")) {
+ mPrimarySelectionManager.reset(new QWaylandPrimarySelectionDeviceManagerV1(this, id, 1));
+#endif
} else if (interface == QStringLiteral("zwp_text_input_manager_v2") && !mClientSideInputContextRequested) {
mTextInputManager.reset(new QtWayland::zwp_text_input_manager_v2(registry, id, 1));
for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
@@ -329,7 +336,8 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
mGlobals.append(RegistryGlobal(id, interface, version, registry));
- foreach (Listener l, mRegistryListeners)
+ const auto copy = mRegistryListeners; // be prepared for listeners unregistering on notification
+ for (Listener l : copy)
(*l.listener)(l.data, registry, id, interface, version);
}
@@ -347,7 +355,7 @@ void QWaylandDisplay::registry_global_remove(uint32_t id)
}
}
- foreach (QWaylandScreen *screen, mScreens) {
+ for (QWaylandScreen *screen : qAsConst(mScreens)) {
if (screen->outputId() == id) {
mScreens.removeOne(screen);
QWindowSystemInterface::handleScreenRemoved(screen);
@@ -367,9 +375,9 @@ void QWaylandDisplay::registry_global_remove(uint32_t id)
}
}
-bool QWaylandDisplay::hasRegistryGlobal(const QString &interfaceName)
+bool QWaylandDisplay::hasRegistryGlobal(QStringView interfaceName) const
{
- Q_FOREACH (const RegistryGlobal &global, mGlobals)
+ for (const RegistryGlobal &global : mGlobals)
if (global.interface == interfaceName)
return true;
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
index 7cfbc19b8..14bb77198 100644
--- a/src/client/qwaylanddisplay_p.h
+++ b/src/client/qwaylanddisplay_p.h
@@ -93,11 +93,15 @@ class QWaylandScreen;
class QWaylandClientBufferIntegration;
class QWaylandWindowManagerIntegration;
class QWaylandDataDeviceManager;
+#if QT_CONFIG(wayland_client_primary_selection)
+class QWaylandPrimarySelectionDeviceManagerV1;
+#endif
class QWaylandTouchExtension;
class QWaylandQtKeyExtension;
class QWaylandWindow;
class QWaylandIntegration;
class QWaylandHardwareIntegration;
+class QWaylandSurface;
class QWaylandShellIntegration;
class QWaylandCursor;
class QWaylandCursorTheme;
@@ -149,6 +153,9 @@ public:
#if QT_CONFIG(wayland_datadevice)
QWaylandDataDeviceManager *dndSelectionHandler() const { return mDndSelectionHandler.data(); }
#endif
+#if QT_CONFIG(wayland_client_primary_selection)
+ QWaylandPrimarySelectionDeviceManagerV1 *primarySelectionManager() const { return mPrimarySelectionManager.data(); }
+#endif
QtWayland::qt_surface_extension *windowExtension() const { return mWindowExtension.data(); }
QWaylandTouchExtension *touchExtension() const { return mTouchExtension.data(); }
QtWayland::zwp_text_input_manager_v2 *textInputManager() const { return mTextInputManager.data(); }
@@ -166,7 +173,7 @@ public:
: id(id_), interface(interface_), version(version_), registry(registry_) { }
};
QList<RegistryGlobal> globals() const { return mGlobals; }
- bool hasRegistryGlobal(const QString &interfaceName);
+ bool hasRegistryGlobal(QStringView interfaceName) const;
/* wl_registry_add_listener does not add but rather sets a listener, so this function is used
* to enable many listeners at once. */
@@ -236,6 +243,9 @@ private:
QScopedPointer<QWaylandTouchExtension> mTouchExtension;
QScopedPointer<QWaylandQtKeyExtension> mQtKeyExtension;
QScopedPointer<QWaylandWindowManagerIntegration> mWindowManagerIntegration;
+#if QT_CONFIG(wayland_client_primary_selection)
+ QScopedPointer<QWaylandPrimarySelectionDeviceManagerV1> mPrimarySelectionManager;
+#endif
QScopedPointer<QtWayland::zwp_text_input_manager_v2> mTextInputManager;
QScopedPointer<QWaylandHardwareIntegration> mHardwareIntegration;
QScopedPointer<QtWayland::zxdg_output_manager_v1> mXdgOutputManager;
diff --git a/src/client/qwaylandextendedsurface.cpp b/src/client/qwaylandextendedsurface.cpp
index c5db6d7ba..a7836e292 100644
--- a/src/client/qwaylandextendedsurface.cpp
+++ b/src/client/qwaylandextendedsurface.cpp
@@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
QWaylandExtendedSurface::QWaylandExtendedSurface(QWaylandWindow *window)
- : QtWayland::qt_extended_surface(window->display()->windowExtension()->get_extended_surface(window->object()))
+ : QtWayland::qt_extended_surface(window->display()->windowExtension()->get_extended_surface(window->wlSurface()))
, m_window(window)
{
}
diff --git a/src/client/qwaylandinputcontext.cpp b/src/client/qwaylandinputcontext.cpp
index 0f27f551d..e9afe05ed 100644
--- a/src/client/qwaylandinputcontext.cpp
+++ b/src/client/qwaylandinputcontext.cpp
@@ -120,7 +120,7 @@ void QWaylandTextInput::updateState(Qt::InputMethodQueries queries, uint32_t fla
return;
auto *window = static_cast<QWaylandWindow *>(QGuiApplication::focusWindow()->handle());
- auto *surface = window->object();
+ auto *surface = window->wlSurface();
if (!surface || (surface != m_surface))
return;
@@ -224,11 +224,11 @@ void QWaylandTextInput::zwp_text_input_v2_leave(uint32_t serial, ::wl_surface *s
void QWaylandTextInput::zwp_text_input_v2_modifiers_map(wl_array *map)
{
- QList<QByteArray> modifiersMap = QByteArray::fromRawData(static_cast<const char*>(map->data), map->size).split('\0');
+ const QList<QByteArray> modifiersMap = QByteArray::fromRawData(static_cast<const char*>(map->data), map->size).split('\0');
m_modifiersMap.clear();
- Q_FOREACH (const QByteArray &modifier, modifiersMap) {
+ for (const QByteArray &modifier : modifiersMap) {
if (modifier == "Shift")
m_modifiersMap.append(Qt::ShiftModifier);
else if (modifier == "Control")
@@ -431,7 +431,7 @@ static ::wl_surface *surfaceForWindow(QWindow *window)
return nullptr;
auto *waylandWindow = static_cast<QWaylandWindow *>(window->handle());
- return waylandWindow->wl_surface::object();
+ return waylandWindow->wlSurface();
}
void QWaylandInputContext::update(Qt::InputMethodQueries queries)
@@ -537,7 +537,7 @@ void QWaylandInputContext::setFocusObject(QObject *)
if (mCurrentWindow && mCurrentWindow->handle()) {
if (mCurrentWindow.data() != window || !inputMethodAccepted()) {
- struct ::wl_surface *surface = static_cast<QWaylandWindow *>(mCurrentWindow->handle())->object();
+ auto *surface = static_cast<QWaylandWindow *>(mCurrentWindow->handle())->wlSurface();
if (surface)
textInput()->disable(surface);
mCurrentWindow.clear();
@@ -546,7 +546,7 @@ void QWaylandInputContext::setFocusObject(QObject *)
if (window && window->handle() && inputMethodAccepted()) {
if (mCurrentWindow.data() != window) {
- struct ::wl_surface *surface = static_cast<QWaylandWindow *>(window->handle())->object();
+ auto *surface = static_cast<QWaylandWindow *>(window->handle())->wlSurface();
if (surface) {
textInput()->enable(surface);
mCurrentWindow = window;
diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp
index 8f3df8e4d..a9da452dc 100644
--- a/src/client/qwaylandinputdevice.cpp
+++ b/src/client/qwaylandinputdevice.cpp
@@ -41,11 +41,15 @@
#include "qwaylandintegration_p.h"
#include "qwaylandwindow_p.h"
+#include "qwaylandsurface_p.h"
#include "qwaylandbuffer_p.h"
#if QT_CONFIG(wayland_datadevice)
#include "qwaylanddatadevice_p.h"
#include "qwaylanddatadevicemanager_p.h"
#endif
+#if QT_CONFIG(wayland_client_primary_selection)
+#include "qwaylandprimaryselectionv1_p.h"
+#endif
#include "qwaylandtouch_p.h"
#include "qwaylandscreen_p.h"
#include "qwaylandcursor_p.h"
@@ -73,6 +77,8 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
+Q_LOGGING_CATEGORY(lcQpaWaylandInput, "qt.qpa.wayland.input");
+
QWaylandInputDevice::Keyboard::Keyboard(QWaylandInputDevice *p)
: mParent(p)
{
@@ -147,25 +153,45 @@ QWaylandInputDevice::Pointer::~Pointer()
wl_pointer_destroy(object());
}
+QWaylandWindow *QWaylandInputDevice::Pointer::focusWindow() const
+{
+ return mFocus ? mFocus->waylandWindow() : nullptr;
+}
+
#if QT_CONFIG(cursor)
-class CursorSurface : public QObject, public QtWayland::wl_surface
+class WlCallback : public QtWayland::wl_callback {
+public:
+ explicit WlCallback(::wl_callback *callback, std::function<void(uint32_t)> fn, bool autoDelete = false)
+ : QtWayland::wl_callback(callback)
+ , m_fn(fn)
+ , m_autoDelete(autoDelete)
+ {}
+ ~WlCallback() override { wl_callback_destroy(object()); }
+ bool done() const { return m_done; }
+ void callback_done(uint32_t callback_data) override {
+ m_done = true;
+ m_fn(callback_data);
+ if (m_autoDelete)
+ delete this;
+ }
+private:
+ bool m_done = false;
+ std::function<void(uint32_t)> m_fn;
+ bool m_autoDelete = false;
+};
+
+class CursorSurface : public QWaylandSurface
{
public:
explicit CursorSurface(QWaylandInputDevice::Pointer *pointer, QWaylandDisplay *display)
- : m_pointer(pointer)
+ : QWaylandSurface(display)
+ , m_pointer(pointer)
{
- init(display->createSurface(this));
//TODO: When we upgrade to libwayland 1.10, use wl_surface_get_version instead.
m_version = display->compositorVersion();
- connect(qApp, &QGuiApplication::screenRemoved, this, [this](QScreen *screen) {
- int oldScale = outputScale();
- if (!m_screens.removeOne(static_cast<QWaylandScreen *>(screen->handle())))
- return;
-
- if (outputScale() != oldScale)
- m_pointer->updateCursor();
- });
+ connect(this, &QWaylandSurface::screensChanged,
+ m_pointer, &QWaylandInputDevice::Pointer::updateCursor);
}
void hide()
@@ -177,7 +203,7 @@ public:
}
// Size and hotspot are in surface coordinates
- void update(wl_buffer *buffer, const QPoint &hotspot, const QSize &size, int bufferScale)
+ void update(wl_buffer *buffer, const QPoint &hotspot, const QSize &size, int bufferScale, bool animated = false)
{
// Calling code needs to ensure buffer scale is supported if != 1
Q_ASSERT(bufferScale == 1 || m_version >= 3);
@@ -194,6 +220,13 @@ public:
attach(buffer, 0, 0);
damage(0, 0, size.width(), size.height());
+ m_frameCallback.reset();
+ if (animated) {
+ m_frameCallback.reset(new WlCallback(frame(), [this](uint32_t time){
+ Q_UNUSED(time);
+ m_pointer->updateCursor();
+ }));
+ }
commit();
}
@@ -205,38 +238,12 @@ public:
return scale;
}
-protected:
- void surface_enter(struct ::wl_output *output) override
- {
- int oldScale = outputScale();
- auto *screen = QWaylandScreen::fromWlOutput(output);
- if (m_screens.contains(screen))
- return;
-
- m_screens.append(screen);
-
- if (outputScale() != oldScale)
- m_pointer->updateCursor();
- }
-
- void surface_leave(struct ::wl_output *output) override
- {
- int oldScale = outputScale();
- auto *screen = QWaylandScreen::fromWlOutput(output);
-
- if (!m_screens.removeOne(screen))
- return;
-
- if (outputScale() != oldScale)
- m_pointer->updateCursor();
- }
-
private:
+ QScopedPointer<WlCallback> m_frameCallback;
QWaylandInputDevice::Pointer *m_pointer = nullptr;
uint m_version = 0;
uint m_setSerial = 0;
QPoint m_hotspot;
- QVector<QWaylandScreen *> m_screens;
};
QString QWaylandInputDevice::Pointer::cursorThemeName() const
@@ -318,12 +325,14 @@ void QWaylandInputDevice::Pointer::updateCursor()
return;
// Set from shape using theme
- if (struct ::wl_cursor_image *image = mCursor.theme->cursorImage(shape)) {
+ uint time = seat()->mCursor.animationTimer.elapsed();
+ if (struct ::wl_cursor_image *image = mCursor.theme->cursorImage(shape, time)) {
struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
int bufferScale = mCursor.themeBufferScale;
QPoint hotspot = QPoint(image->hotspot_x, image->hotspot_y) / bufferScale;
QSize size = QSize(image->width, image->height) / bufferScale;
- getOrCreateCursorSurface()->update(buffer, hotspot, size, bufferScale);
+ bool animated = image->delay > 0;
+ getOrCreateCursorSurface()->update(buffer, hotspot, size, bufferScale, animated);
return;
}
@@ -353,10 +362,10 @@ QWaylandInputDevice::Touch::~Touch()
}
QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version, uint32_t id)
- : QtWayland::wl_seat(display->wl_registry(), id, qMin(version, 4))
+ : QtWayland::wl_seat(display->wl_registry(), id, qMin(version, 5))
, mQDisplay(display)
, mDisplay(display->wl_display())
- , mVersion(qMin(version, 4))
+ , mVersion(qMin(version, 5))
{
#if QT_CONFIG(wayland_datadevice)
if (mQDisplay->dndSelectionHandler()) {
@@ -364,6 +373,12 @@ QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version,
}
#endif
+#if QT_CONFIG(wayland_client_primary_selection)
+ // TODO: Could probably decouple this more if there was a signal for new seat added
+ if (auto *psm = mQDisplay->primarySelectionManager())
+ setPrimarySelectionDevice(psm->createDevice(this));
+#endif
+
if (mQDisplay->textInputManager())
mTextInput.reset(new QWaylandTextInput(mQDisplay, mQDisplay->textInputManager()->get_text_input(wl_seat())));
@@ -427,6 +442,21 @@ QWaylandInputDevice::Touch *QWaylandInputDevice::createTouch(QWaylandInputDevice
return new Touch(device);
}
+QWaylandInputDevice::Keyboard *QWaylandInputDevice::keyboard() const
+{
+ return mKeyboard;
+}
+
+QWaylandInputDevice::Pointer *QWaylandInputDevice::pointer() const
+{
+ return mPointer;
+}
+
+QWaylandInputDevice::Touch *QWaylandInputDevice::touch() const
+{
+ return mTouch;
+}
+
void QWaylandInputDevice::handleEndDrag()
{
if (mTouch)
@@ -447,6 +477,18 @@ QWaylandDataDevice *QWaylandInputDevice::dataDevice() const
}
#endif
+#if QT_CONFIG(wayland_client_primary_selection)
+void QWaylandInputDevice::setPrimarySelectionDevice(QWaylandPrimarySelectionDeviceV1 *primarySelectionDevice)
+{
+ mPrimarySelectionDevice.reset(primarySelectionDevice);
+}
+
+QWaylandPrimarySelectionDeviceV1 *QWaylandInputDevice::primarySelectionDevice() const
+{
+ return mPrimarySelectionDevice.data();
+}
+#endif
+
void QWaylandInputDevice::setTextInput(QWaylandTextInput *textInput)
{
mTextInput.reset(textInput);
@@ -465,7 +507,7 @@ void QWaylandInputDevice::removeMouseButtonFromState(Qt::MouseButton button)
QWaylandWindow *QWaylandInputDevice::pointerFocus() const
{
- return mPointer ? mPointer->mFocus : nullptr;
+ return mPointer ? mPointer->focusWindow() : nullptr;
}
QWaylandWindow *QWaylandInputDevice::keyboardFocus() const
@@ -524,6 +566,7 @@ void QWaylandInputDevice::setCursor(const QCursor *cursor, const QSharedPointer<
mCursor.shape = cursor ? cursor->shape() : Qt::ArrowCursor;
mCursor.hotspot = cursor ? cursor->hotSpot() : QPoint();
mCursor.fallbackOutputScale = fallbackOutputScale;
+ mCursor.animationTimer.start();
if (mCursor.shape == Qt::BitmapCursor) {
mCursor.bitmapBuffer = cachedBuffer ? cachedBuffer : QWaylandCursor::cursorBitmapBuffer(mQDisplay, cursor);
@@ -550,8 +593,9 @@ void QWaylandInputDevice::setCursor(const QCursor *cursor, const QSharedPointer<
class EnterEvent : public QWaylandPointerEvent
{
public:
- EnterEvent(const QPointF &l, const QPointF &g)
- : QWaylandPointerEvent(QWaylandPointerEvent::Enter, 0, l, g, nullptr, Qt::NoModifier)
+ EnterEvent(QWaylandWindow *surface, const QPointF &local, const QPointF &global)
+ : QWaylandPointerEvent(QWaylandPointerEvent::Enter, Qt::NoScrollPhase, surface, 0,
+ local, global, nullptr, Qt::NoModifier)
{}
};
@@ -562,6 +606,7 @@ void QWaylandInputDevice::Pointer::pointer_enter(uint32_t serial, struct wl_surf
return;
QWaylandWindow *window = QWaylandWindow::fromWlSurface(surface);
+
if (!window)
return; // Ignore foreign surfaces
@@ -571,9 +616,8 @@ void QWaylandInputDevice::Pointer::pointer_enter(uint32_t serial, struct wl_surf
<< "attempting to work around it by invalidating the current focus";
invalidateFocus();
}
-
- mFocus = window;
- connect(mFocus.data(), &QWaylandWindow::wlSurfaceDestroyed, this, &Pointer::handleFocusDestroyed);
+ mFocus = window->waylandSurface();
+ connect(mFocus.data(), &QObject::destroyed, this, &Pointer::handleFocusDestroyed);
mSurfacePos = QPointF(wl_fixed_to_double(sx), wl_fixed_to_double(sy));
mGlobalPos = window->window()->mapToGlobal(mSurfacePos.toPoint());
@@ -587,12 +631,19 @@ void QWaylandInputDevice::Pointer::pointer_enter(uint32_t serial, struct wl_surf
#endif
QWaylandWindow *grab = QWaylandWindow::mouseGrab();
- if (!grab) {
- EnterEvent evt(mSurfacePos, mGlobalPos);
- window->handleMouse(mParent, evt);
- }
+ if (!grab)
+ setFrameEvent(new EnterEvent(window, mSurfacePos, mGlobalPos));
}
+class LeaveEvent : public QWaylandPointerEvent
+{
+public:
+ LeaveEvent(QWaylandWindow *surface, const QPointF &localPos, const QPointF &globalPos)
+ : QWaylandPointerEvent(QWaylandPointerEvent::Leave, Qt::NoScrollPhase, surface, 0,
+ localPos, globalPos, nullptr, Qt::NoModifier)
+ {}
+};
+
void QWaylandInputDevice::Pointer::pointer_leave(uint32_t time, struct wl_surface *surface)
{
// The event may arrive after destroying the window, indicated by
@@ -604,10 +655,8 @@ void QWaylandInputDevice::Pointer::pointer_leave(uint32_t time, struct wl_surfac
if (!window)
return; // Ignore foreign surfaces
- if (!QWaylandWindow::mouseGrab()) {
- QWaylandWindow *window = QWaylandWindow::fromWlSurface(surface);
- window->handleMouseLeave(mParent);
- }
+ if (!QWaylandWindow::mouseGrab())
+ setFrameEvent(new LeaveEvent(window, mSurfacePos, mGlobalPos));
invalidateFocus();
mButtons = Qt::NoButton;
@@ -618,15 +667,17 @@ void QWaylandInputDevice::Pointer::pointer_leave(uint32_t time, struct wl_surfac
class MotionEvent : public QWaylandPointerEvent
{
public:
- MotionEvent(ulong t, const QPointF &l, const QPointF &g, Qt::MouseButtons b, Qt::KeyboardModifiers m)
- : QWaylandPointerEvent(QWaylandPointerEvent::Motion, t, l, g, b, m)
+ MotionEvent(QWaylandWindow *surface, ulong timestamp, const QPointF &localPos,
+ const QPointF &globalPos, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
+ : QWaylandPointerEvent(QWaylandPointerEvent::Motion, Qt::NoScrollPhase, surface,
+ timestamp, localPos, globalPos, buttons, modifiers)
{
}
};
void QWaylandInputDevice::Pointer::pointer_motion(uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
{
- QWaylandWindow *window = mFocus;
+ QWaylandWindow *window = focusWindow();
if (!window) {
// We destroyed the pointer focus surface, but the server didn't get the message yet...
// or the server didn't send an enter event first. In either case, ignore the event.
@@ -648,18 +699,37 @@ void QWaylandInputDevice::Pointer::pointer_motion(uint32_t time, wl_fixed_t surf
// so we just set it outside of the window boundaries.
pos = QPointF(-1, -1);
global = grab->window()->mapToGlobal(pos.toPoint());
- MotionEvent e(time, pos, global, mButtons, mParent->modifiers());
- grab->handleMouse(mParent, e);
- } else {
- MotionEvent e(time, mSurfacePos, mGlobalPos, mButtons, mParent->modifiers());
- window->handleMouse(mParent, e);
+ window = grab;
}
+ setFrameEvent(new MotionEvent(window, time, pos, global, mButtons, mParent->modifiers()));
}
+class PressEvent : public QWaylandPointerEvent
+{
+public:
+ PressEvent(QWaylandWindow *surface, ulong timestamp, const QPointF &localPos,
+ const QPointF &globalPos, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
+ : QWaylandPointerEvent(QWaylandPointerEvent::Press, Qt::NoScrollPhase, surface,
+ timestamp, localPos, globalPos, buttons, modifiers)
+ {
+ }
+};
+
+class ReleaseEvent : public QWaylandPointerEvent
+{
+public:
+ ReleaseEvent(QWaylandWindow *surface, ulong timestamp, const QPointF &localPos,
+ const QPointF &globalPos, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
+ : QWaylandPointerEvent(QWaylandPointerEvent::Release, Qt::NoScrollPhase, surface,
+ timestamp, localPos, globalPos, buttons, modifiers)
+ {
+ }
+};
+
void QWaylandInputDevice::Pointer::pointer_button(uint32_t serial, uint32_t time,
uint32_t button, uint32_t state)
{
- QWaylandWindow *window = mFocus;
+ QWaylandWindow *window = focusWindow();
if (!window) {
// We destroyed the pointer focus surface, but the server didn't get the message yet...
// or the server didn't send an enter event first. In either case, ignore the event.
@@ -701,66 +771,300 @@ void QWaylandInputDevice::Pointer::pointer_button(uint32_t serial, uint32_t time
mParent->mQDisplay->setLastInputDevice(mParent, serial, window);
QWaylandWindow *grab = QWaylandWindow::mouseGrab();
- if (grab && grab != mFocus) {
- QPointF pos = QPointF(-1, -1);
- QPointF global = grab->window()->mapToGlobal(pos.toPoint());
- MotionEvent e(time, pos, global, mButtons, mParent->modifiers());
- grab->handleMouse(mParent, e);
- } else if (window) {
- MotionEvent e(time, mSurfacePos, mGlobalPos, mButtons, mParent->modifiers());
- window->handleMouse(mParent, e);
+
+ QPointF pos = mSurfacePos;
+ QPointF global = mGlobalPos;
+ if (grab && grab != focusWindow()) {
+ pos = QPointF(-1, -1);
+ global = grab->window()->mapToGlobal(pos.toPoint());
+
+ window = grab;
}
+
+ if (state)
+ setFrameEvent(new PressEvent(window, time, pos, global, mButtons, mParent->modifiers()));
+ else
+ setFrameEvent(new ReleaseEvent(window, time, pos, global, mButtons, mParent->modifiers()));
}
void QWaylandInputDevice::Pointer::invalidateFocus()
{
- disconnect(mFocus.data(), &QWaylandWindow::wlSurfaceDestroyed, this, &Pointer::handleFocusDestroyed);
- mFocus = nullptr;
+ if (mFocus) {
+ disconnect(mFocus.data(), &QObject::destroyed, this, &Pointer::handleFocusDestroyed);
+ mFocus = nullptr;
+ }
mEnterSerial = 0;
}
void QWaylandInputDevice::Pointer::releaseButtons()
{
mButtons = Qt::NoButton;
- MotionEvent e(mParent->mTime, mSurfacePos, mGlobalPos, mButtons, mParent->modifiers());
- if (mFocus)
- mFocus->handleMouse(mParent, e);
+
+ if (auto *window = focusWindow()) {
+ MotionEvent e(focusWindow(), mParent->mTime, mSurfacePos, mGlobalPos, mButtons, mParent->modifiers());
+ window->handleMouse(mParent, e);
+ }
}
class WheelEvent : public QWaylandPointerEvent
{
public:
- WheelEvent(ulong t, const QPointF &l, const QPointF &g, const QPoint &pd, const QPoint &ad, Qt::KeyboardModifiers m)
- : QWaylandPointerEvent(QWaylandPointerEvent::Wheel, t, l, g, pd, ad, m)
+ WheelEvent(QWaylandWindow *surface, Qt::ScrollPhase phase, ulong timestamp, const QPointF &local,
+ const QPointF &global, const QPoint &pixelDelta, const QPoint &angleDelta,
+ Qt::MouseEventSource source, Qt::KeyboardModifiers modifiers)
+ : QWaylandPointerEvent(QWaylandPointerEvent::Wheel, phase, surface, timestamp,
+ local, global, pixelDelta, angleDelta, source, modifiers)
{
}
};
void QWaylandInputDevice::Pointer::pointer_axis(uint32_t time, uint32_t axis, int32_t value)
{
- QWaylandWindow *window = mFocus;
- if (!window) {
+ if (!focusWindow()) {
// We destroyed the pointer focus surface, but the server didn't get the message yet...
// or the server didn't send an enter event first. In either case, ignore the event.
return;
}
- QPoint pixelDelta;
- QPoint angleDelta;
+ // Get the delta and convert it into the expected range
+ switch (axis) {
+ case WL_POINTER_AXIS_VERTICAL_SCROLL:
+ mFrameData.delta.ry() += wl_fixed_to_double(value);
+ qCDebug(lcQpaWaylandInput) << "wl_pointer.axis vertical:" << mFrameData.delta.y();
+ break;
+ case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
+ mFrameData.delta.rx() += wl_fixed_to_double(value);
+ qCDebug(lcQpaWaylandInput) << "wl_pointer.axis horizontal:" << mFrameData.delta.x();
+ break;
+ default:
+ //TODO: is this really needed?
+ qCWarning(lcQpaWaylandInput) << "wl_pointer.axis: Unknown axis:" << axis;
+ return;
+ }
+
+ mParent->mTime = time;
- //normalize value and inverse axis
- int valueDelta = wl_fixed_to_int(value) * -12;
+ if (mParent->mVersion < WL_POINTER_FRAME_SINCE_VERSION) {
+ qCDebug(lcQpaWaylandInput) << "Flushing new event; no frame event in this version";
+ flushFrameEvent();
+ }
+}
- if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
- pixelDelta = QPoint();
- angleDelta.setX(valueDelta);
- } else {
- pixelDelta = QPoint();
- angleDelta.setY(valueDelta);
+void QWaylandInputDevice::Pointer::pointer_frame()
+{
+ flushFrameEvent();
+}
+
+void QWaylandInputDevice::Pointer::pointer_axis_source(uint32_t source)
+{
+ switch (source) {
+ case axis_source_wheel:
+ qCDebug(lcQpaWaylandInput) << "Axis source wheel";
+ break;
+ case axis_source_finger:
+ qCDebug(lcQpaWaylandInput) << "Axis source finger";
+ break;
+ case axis_source_continuous:
+ qCDebug(lcQpaWaylandInput) << "Axis source continuous";
+ break;
+ }
+ mFrameData.axisSource = axis_source(source);
+}
+
+void QWaylandInputDevice::Pointer::pointer_axis_stop(uint32_t time, uint32_t axis)
+{
+ if (!focusWindow())
+ return;
+
+ mParent->mTime = time;
+ switch (axis) {
+ case axis_vertical_scroll:
+ qCDebug(lcQpaWaylandInput) << "Received vertical wl_pointer.axis_stop";
+ mFrameData.delta.setY(0); //TODO: what's the point of doing this?
+ break;
+ case axis_horizontal_scroll:
+ qCDebug(lcQpaWaylandInput) << "Received horizontal wl_pointer.axis_stop";
+ mFrameData.delta.setX(0);
+ break;
+ default:
+ qCWarning(lcQpaWaylandInput) << "wl_pointer.axis_stop: Unknown axis: " << axis
+ << "This is most likely a compositor bug";
+ return;
+ }
+
+ // May receive axis_stop for events we haven't sent a ScrollBegin for because
+ // most axis_sources do not mandate an axis_stop event to be sent.
+ if (!mScrollBeginSent) {
+ // TODO: For now, we just ignore these events, but we could perhaps take this as an
+ // indication that this compositor will in fact send axis_stop events for these sources
+ // and send a ScrollBegin the next time an axis_source event with this type is encountered.
+ return;
+ }
+
+ QWaylandWindow *target = QWaylandWindow::mouseGrab();
+ if (!target)
+ target = focusWindow();
+ Qt::KeyboardModifiers mods = mParent->modifiers();
+ WheelEvent wheelEvent(focusWindow(), Qt::ScrollEnd, mParent->mTime, mSurfacePos, mGlobalPos,
+ QPoint(), QPoint(), Qt::MouseEventNotSynthesized, mods);
+ target->handleMouse(mParent, wheelEvent);
+ mScrollBeginSent = false;
+ mScrollDeltaRemainder = QPointF();
+}
+
+void QWaylandInputDevice::Pointer::pointer_axis_discrete(uint32_t axis, int32_t value)
+{
+ if (!focusWindow())
+ return;
+
+ switch (axis) {
+ case axis_vertical_scroll:
+ qCDebug(lcQpaWaylandInput) << "wl_pointer.axis_discrete vertical:" << value;
+ mFrameData.discreteDelta.ry() += value;
+ break;
+ case axis_horizontal_scroll:
+ qCDebug(lcQpaWaylandInput) << "wl_pointer.axis_discrete horizontal:" << value;
+ mFrameData.discreteDelta.rx() += value;
+ break;
+ default:
+ //TODO: is this really needed?
+ qCWarning(lcQpaWaylandInput) << "wl_pointer.axis_discrete: Unknown axis:" << axis;
+ return;
+ }
+}
+
+void QWaylandInputDevice::Pointer::setFrameEvent(QWaylandPointerEvent *event)
+{
+ qCDebug(lcQpaWaylandInput) << "Setting frame event " << event->type;
+ if (mFrameData.event && mFrameData.event->type != event->type) {
+ qCDebug(lcQpaWaylandInput) << "Flushing; previous was " << mFrameData.event->type;
+ flushFrameEvent();
}
- WheelEvent e(time, mSurfacePos, mGlobalPos, pixelDelta, angleDelta, mParent->modifiers());
- window->handleMouse(mParent, e);
+ mFrameData.event = event;
+
+ if (mParent->mVersion < WL_POINTER_FRAME_SINCE_VERSION) {
+ qCDebug(lcQpaWaylandInput) << "Flushing new event; no frame event in this version";
+ flushFrameEvent();
+ }
+}
+
+void QWaylandInputDevice::Pointer::FrameData::resetScrollData()
+{
+ discreteDelta = QPoint();
+ delta = QPointF();
+ axisSource = axis_source_wheel;
+}
+
+bool QWaylandInputDevice::Pointer::FrameData::hasPixelDelta() const
+{
+ switch (axisSource) {
+ case axis_source_wheel_tilt: // sideways tilt of the wheel
+ case axis_source_wheel:
+ // In the case of wheel events, a pixel delta doesn't really make sense,
+ // and will make Qt think this is a continuous scroll event when it isn't,
+ // so just ignore it.
+ return false;
+ case axis_source_finger:
+ case axis_source_continuous:
+ return !delta.isNull();
+ }
+}
+
+QPoint QWaylandInputDevice::Pointer::FrameData::pixelDeltaAndError(QPointF *accumulatedError) const
+{
+ if (!hasPixelDelta())
+ return QPoint();
+
+ Q_ASSERT(accumulatedError);
+ // Add accumulated rounding error before rounding again
+ QPoint pixelDelta = (delta + *accumulatedError).toPoint();
+ *accumulatedError += delta - pixelDelta;
+ Q_ASSERT(qAbs(accumulatedError->x()) < 1.0);
+ Q_ASSERT(qAbs(accumulatedError->y()) < 1.0);
+ return pixelDelta;
+}
+
+QPoint QWaylandInputDevice::Pointer::FrameData::angleDelta() const
+{
+ if (discreteDelta.isNull()) {
+ // If we didn't get any discrete events, then we need to fall back to
+ // the continuous information.
+ return (delta * -12).toPoint(); //TODO: why multiply by 12?
+ }
+
+ // The angle delta is in eights of degrees, and our docs says most mice have
+ // 1 click = 15 degrees. It's also in the opposite direction of surface space.
+ return -discreteDelta * 15 * 8;
+}
+
+Qt::MouseEventSource QWaylandInputDevice::Pointer::FrameData::wheelEventSource() const
+{
+ switch (axisSource) {
+ case axis_source_wheel_tilt: // sideways tilt of the wheel
+ case axis_source_wheel:
+ return Qt::MouseEventNotSynthesized;
+ case axis_source_finger:
+ case axis_source_continuous:
+ default: // Whatever other sources might be added are probably not mouse wheels
+ return Qt::MouseEventSynthesizedBySystem;
+ }
+}
+
+void QWaylandInputDevice::Pointer::flushScrollEvent()
+{
+ QPoint angleDelta = mFrameData.angleDelta();
+
+ // Angle delta is required for Qt wheel events, so don't try to send events if it's zero
+ if (!angleDelta.isNull()) {
+ QWaylandWindow *target = QWaylandWindow::mouseGrab();
+ if (!target)
+ target = focusWindow();
+
+ if (isDefinitelyTerminated(mFrameData.axisSource) && !mScrollBeginSent) {
+ qCDebug(lcQpaWaylandInput) << "Flushing scroll event sending ScrollBegin";
+ target->handleMouse(mParent, WheelEvent(focusWindow(), Qt::ScrollBegin, mParent->mTime,
+ mSurfacePos, mGlobalPos, QPoint(), QPoint(),
+ Qt::MouseEventNotSynthesized,
+ mParent->modifiers()));
+ mScrollBeginSent = true;
+ mScrollDeltaRemainder = QPointF();
+ }
+
+ Qt::ScrollPhase phase = mScrollBeginSent ? Qt::ScrollUpdate : Qt::NoScrollPhase;
+ QPoint pixelDelta = mFrameData.pixelDeltaAndError(&mScrollDeltaRemainder);
+ Qt::MouseEventSource source = mFrameData.wheelEventSource();
+
+ qCDebug(lcQpaWaylandInput) << "Flushing scroll event" << phase << pixelDelta << angleDelta;
+ target->handleMouse(mParent, WheelEvent(focusWindow(), phase, mParent->mTime, mSurfacePos, mGlobalPos,
+ pixelDelta, angleDelta, source, mParent->modifiers()));
+ }
+
+ mFrameData.resetScrollData();
+}
+
+void QWaylandInputDevice::Pointer::flushFrameEvent()
+{
+ if (auto *event = mFrameData.event) {
+ if (auto window = event->surface) {
+ window->handleMouse(mParent, *event);
+ } else if (mFrameData.event->type == QWaylandPointerEvent::Type::Release) {
+ // If the window has been destroyed, we still need to report an up event, but it can't
+ // be handled by the destroyed window (obviously), so send the event here instead.
+ QWindowSystemInterface::handleMouseEvent(nullptr, event->timestamp, event->local,
+ event->global, event->buttons, event->modifiers);
+ }
+ delete mFrameData.event;
+ mFrameData.event = nullptr;
+ }
+
+ //TODO: do modifiers get passed correctly here?
+ flushScrollEvent();
+}
+
+bool QWaylandInputDevice::Pointer::isDefinitelyTerminated(QtWayland::wl_pointer::axis_source source) const
+{
+ return source == axis_source_finger;
}
void QWaylandInputDevice::Keyboard::keyboard_keymap(uint32_t format, int32_t fd, uint32_t size)
@@ -854,7 +1158,18 @@ void QWaylandInputDevice::Keyboard::handleKey(ulong timestamp, QEvent::Type type
}
if (!filtered) {
- QWindowSystemInterface::handleExtendedKeyEvent(focusWindow()->window(), timestamp, type, key, modifiers,
+ auto window = focusWindow()->window();
+
+ if (type == QEvent::KeyPress && key == Qt::Key_Menu) {
+ auto cursor = window->screen()->handle()->cursor();
+ if (cursor) {
+ const QPoint globalPos = cursor->pos();
+ const QPoint pos = window->mapFromGlobal(globalPos);
+ QWindowSystemInterface::handleContextMenuEvent(window, false, pos, globalPos, modifiers);
+ }
+ }
+
+ QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp, type, key, modifiers,
nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorepeat, count);
}
}
@@ -927,7 +1242,7 @@ void QWaylandInputDevice::Keyboard::handleFocusDestroyed()
// surface, so we still need to disconnect the signal
auto *window = qobject_cast<QWaylandWindow *>(sender());
disconnect(window, &QWaylandWindow::wlSurfaceDestroyed, this, &Keyboard::handleFocusDestroyed);
- Q_ASSERT(window->object() == mFocus);
+ Q_ASSERT(window->wlSurface() == mFocus);
handleFocusLost();
}
@@ -938,6 +1253,10 @@ void QWaylandInputDevice::Keyboard::handleFocusLost()
if (auto *dataDevice = mParent->dataDevice())
dataDevice->invalidateSelectionOffer();
#endif
+#if QT_CONFIG(wayland_client_primary_selection)
+ if (auto *device = mParent->primarySelectionDevice())
+ device->invalidateSelectionOffer();
+#endif
mParent->mQDisplay->handleKeyboardFocusChanged(mParent);
mRepeatTimer.stop();
}
@@ -1046,7 +1365,7 @@ void QWaylandInputDevice::handleTouchPoint(int id, Qt::TouchPointState state, co
//is it possible that mTouchFocus is null;
if (!win && mPointer)
- win = mPointer->mFocus;
+ win = mPointer->focusWindow();
if (!win && mKeyboard)
win = mKeyboard->focusWindow();
if (!win || !win->window())
diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h
index 143e11220..60d6f2c17 100644
--- a/src/client/qwaylandinputdevice_p.h
+++ b/src/client/qwaylandinputdevice_p.h
@@ -69,7 +69,8 @@
#endif
#include <QtCore/QDebug>
-#include <QPointer>
+#include <QtCore/QElapsedTimer>
+#include <QtCore/QPointer>
#if QT_CONFIG(cursor)
struct wl_cursor_image;
@@ -77,11 +78,17 @@ struct wl_cursor_image;
QT_BEGIN_NAMESPACE
+namespace QtWayland {
+class zwp_primary_selection_device_v1;
+} //namespace QtWayland
+
namespace QtWaylandClient {
-class QWaylandWindow;
-class QWaylandDisplay;
class QWaylandDataDevice;
+class QWaylandDisplay;
+#if QT_CONFIG(wayland_client_primary_selection)
+class QWaylandPrimarySelectionDeviceV1;
+#endif
class QWaylandTextInput;
#if QT_CONFIG(cursor)
class QWaylandCursorTheme;
@@ -115,6 +122,11 @@ public:
QWaylandDataDevice *dataDevice() const;
#endif
+#if QT_CONFIG(wayland_client_primary_selection)
+ void setPrimarySelectionDevice(QWaylandPrimarySelectionDeviceV1 *primarySelectionDevice);
+ QWaylandPrimarySelectionDeviceV1 *primarySelectionDevice() const;
+#endif
+
void setTextInput(QWaylandTextInput *textInput);
QWaylandTextInput *textInput() const;
@@ -136,6 +148,10 @@ public:
virtual Pointer *createPointer(QWaylandInputDevice *device);
virtual Touch *createTouch(QWaylandInputDevice *device);
+ Keyboard *keyboard() const;
+ Pointer *pointer() const;
+ Touch *touch() const;
+
private:
QWaylandDisplay *mQDisplay = nullptr;
struct wl_display *mDisplay = nullptr;
@@ -150,6 +166,7 @@ private:
Qt::CursorShape shape = Qt::ArrowCursor;
int fallbackOutputScale = 1;
QPoint hotspot;
+ QElapsedTimer animationTimer;
} mCursor;
#endif
@@ -157,6 +174,10 @@ private:
QWaylandDataDevice *mDataDevice = nullptr;
#endif
+#if QT_CONFIG(wayland_client_primary_selection)
+ QScopedPointer<QWaylandPrimarySelectionDeviceV1> mPrimarySelectionDevice;
+#endif
+
Keyboard *mKeyboard = nullptr;
Pointer *mPointer = nullptr;
Touch *mTouch = nullptr;
@@ -231,6 +252,8 @@ public:
Qt::KeyboardModifiers modifiers() const;
+ struct ::wl_keyboard *wl_keyboard() { return QtWayland::wl_keyboard::object(); }
+
private slots:
void handleFocusDestroyed();
void handleFocusLost();
@@ -256,6 +279,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice::Pointer : public QObject, pub
public:
explicit Pointer(QWaylandInputDevice *seat);
~Pointer() override;
+ QWaylandWindow *focusWindow() const;
#if QT_CONFIG(cursor)
QString cursorThemeName() const;
int cursorSize() const; // in surface coordinates
@@ -266,6 +290,8 @@ public:
#endif
QWaylandInputDevice *seat() const { return mParent; }
+ struct ::wl_pointer *wl_pointer() { return QtWayland::wl_pointer::object(); }
+
protected:
void pointer_enter(uint32_t serial, struct wl_surface *surface,
wl_fixed_t sx, wl_fixed_t sy) override;
@@ -277,6 +303,10 @@ protected:
void pointer_axis(uint32_t time,
uint32_t axis,
wl_fixed_t value) override;
+ void pointer_axis_source(uint32_t source) override;
+ void pointer_axis_stop(uint32_t time, uint32_t axis) override;
+ void pointer_axis_discrete(uint32_t axis, int32_t value) override;
+ void pointer_frame() override;
private slots:
void handleFocusDestroyed() { invalidateFocus(); }
@@ -288,7 +318,7 @@ public:
void releaseButtons();
QWaylandInputDevice *mParent = nullptr;
- QPointer<QWaylandWindow> mFocus;
+ QPointer<QWaylandSurface> mFocus;
uint32_t mEnterSerial = 0;
#if QT_CONFIG(cursor)
struct {
@@ -304,6 +334,30 @@ public:
wl_buffer *mCursorBuffer = nullptr;
Qt::CursorShape mCursorShape = Qt::BitmapCursor;
#endif
+
+ struct FrameData {
+ QWaylandPointerEvent *event = nullptr;
+
+ QPointF delta;
+ QPoint discreteDelta;
+ axis_source axisSource = axis_source_wheel;
+
+ void resetScrollData();
+ bool hasPixelDelta() const;
+ QPoint pixelDeltaAndError(QPointF *accumulatedError) const;
+ QPoint pixelDelta() const { return hasPixelDelta() ? delta.toPoint() : QPoint(); }
+ QPoint angleDelta() const;
+ Qt::MouseEventSource wheelEventSource() const;
+ } mFrameData;
+
+ bool mScrollBeginSent = false;
+ QPointF mScrollDeltaRemainder;
+
+ void setFrameEvent(QWaylandPointerEvent *event);
+ void flushScrollEvent();
+ void flushFrameEvent();
+private: //TODO: should other methods be private as well?
+ bool isDefinitelyTerminated(axis_source source) const;
};
class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice::Touch : public QtWayland::wl_touch
@@ -331,6 +385,8 @@ public:
bool allTouchPointsReleased();
void releasePoints();
+ struct ::wl_touch *wl_touch() { return QtWayland::wl_touch::object(); }
+
QWaylandInputDevice *mParent = nullptr;
QPointer<QWaylandWindow> mFocus;
QList<QWindowSystemInterface::TouchPoint> mPendingTouchPoints;
@@ -338,38 +394,58 @@ public:
class QWaylandPointerEvent
{
+ Q_GADGET
public:
enum Type {
Enter,
+ Leave,
Motion,
+ Press,
+ Release,
Wheel
};
- inline QWaylandPointerEvent(Type t, ulong ts, const QPointF &l, const QPointF &g, Qt::MouseButtons b, Qt::KeyboardModifiers m)
- : type(t)
- , timestamp(ts)
- , local(l)
- , global(g)
- , buttons(b)
- , modifiers(m)
+ Q_ENUM(Type)
+
+ inline QWaylandPointerEvent(Type type, Qt::ScrollPhase phase, QWaylandWindow *surface,
+ ulong timestamp, const QPointF &localPos, const QPointF &globalPos,
+ Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
+ : type(type)
+ , phase(phase)
+ , timestamp(timestamp)
+ , local(localPos)
+ , global(globalPos)
+ , buttons(buttons)
+ , modifiers(modifiers)
+ , surface(surface)
{}
- inline QWaylandPointerEvent(Type t, ulong ts, const QPointF &l, const QPointF &g, const QPoint &pd, const QPoint &ad, Qt::KeyboardModifiers m)
- : type(t)
- , timestamp(ts)
- , local(l)
- , global(g)
- , modifiers(m)
- , pixelDelta(pd)
- , angleDelta(ad)
+ inline QWaylandPointerEvent(Type type, Qt::ScrollPhase phase, QWaylandWindow *surface,
+ ulong timestamp, const QPointF &local, const QPointF &global,
+ const QPoint &pixelDelta, const QPoint &angleDelta,
+ Qt::MouseEventSource source,
+ Qt::KeyboardModifiers modifiers)
+ : type(type)
+ , phase(phase)
+ , timestamp(timestamp)
+ , local(local)
+ , global(global)
+ , modifiers(modifiers)
+ , pixelDelta(pixelDelta)
+ , angleDelta(angleDelta)
+ , source(source)
+ , surface(surface)
{}
Type type;
- ulong timestamp;
+ Qt::ScrollPhase phase = Qt::NoScrollPhase;
+ ulong timestamp = 0;
QPointF local;
QPointF global;
Qt::MouseButtons buttons;
Qt::KeyboardModifiers modifiers;
QPoint pixelDelta;
QPoint angleDelta;
+ Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
+ QPointer<QWaylandWindow> surface;
};
}
diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp
index 85fcef43f..f6a80e18f 100644
--- a/src/client/qwaylandintegration.cpp
+++ b/src/client/qwaylandintegration.cpp
@@ -272,7 +272,7 @@ QPlatformAccessibility *QWaylandIntegration::accessibility() const
{
if (!mAccessibility) {
#ifndef QT_NO_ACCESSIBILITY_ATSPI_BRIDGE
- Q_ASSERT_X(QCoreApplication::eventDispatcher(), "QXcbIntegration",
+ Q_ASSERT_X(QCoreApplication::eventDispatcher(), "QWaylandIntegration",
"Initializing accessibility without event-dispatcher!");
mAccessibility.reset(new QSpiAccessibleBridge());
#else
@@ -352,7 +352,7 @@ void QWaylandIntegration::initializeClientBufferIntegration()
&& mDisplay->hardwareIntegration()->clientBufferIntegration() != QLatin1String("linux-dmabuf-unstable-v1")) {
targetKey = mDisplay->hardwareIntegration()->clientBufferIntegration();
} else {
- targetKey = QLatin1Literal("wayland-egl");
+ targetKey = QLatin1String("wayland-egl");
}
}
@@ -430,7 +430,7 @@ void QWaylandIntegration::initializeShellIntegration()
preferredShells << QLatin1String("wl-shell") << QLatin1String("ivi-shell");
}
- Q_FOREACH (QString preferredShell, preferredShells) {
+ for (const QString &preferredShell : qAsConst(preferredShells)) {
mShellIntegration.reset(createShellIntegration(preferredShell));
if (mShellIntegration) {
qCDebug(lcQpaWayland, "Using the '%s' shell integration", qPrintable(preferredShell));
diff --git a/src/client/qwaylandnativeinterface.cpp b/src/client/qwaylandnativeinterface.cpp
index 76acb526b..b4ecc0090 100644
--- a/src/client/qwaylandnativeinterface.cpp
+++ b/src/client/qwaylandnativeinterface.cpp
@@ -47,6 +47,7 @@
#include "qwaylanddisplay_p.h"
#include "qwaylandwindowmanagerintegration_p.h"
#include "qwaylandscreen_p.h"
+#include "qwaylandinputdevice_p.h"
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/QScreen>
#include <QtWaylandClient/private/qwaylandclientbufferintegration_p.h>
@@ -76,6 +77,27 @@ void *QWaylandNativeInterface::nativeResourceForIntegration(const QByteArray &re
if (lowerCaseResource == "egldisplay" && m_integration->clientBufferIntegration())
return m_integration->clientBufferIntegration()->nativeResource(QWaylandClientBufferIntegration::EglDisplay);
+ if (lowerCaseResource == "wl_seat")
+ return m_integration->display()->defaultInputDevice()->wl_seat();
+ if (lowerCaseResource == "wl_keyboard") {
+ auto *keyboard = m_integration->display()->defaultInputDevice()->keyboard();
+ if (keyboard)
+ return keyboard->wl_keyboard();
+ return nullptr;
+ }
+ if (lowerCaseResource == "wl_pointer") {
+ auto *pointer = m_integration->display()->defaultInputDevice()->pointer();
+ if (pointer)
+ return pointer->wl_pointer();
+ return nullptr;
+ }
+ if (lowerCaseResource == "wl_touch") {
+ auto *touch = m_integration->display()->defaultInputDevice()->touch();
+ if (touch)
+ return touch->wl_touch();
+ return nullptr;
+ }
+
return nullptr;
}
@@ -89,7 +111,7 @@ void *QWaylandNativeInterface::nativeResourceForWindow(const QByteArray &resourc
return const_cast<wl_compositor *>(m_integration->display()->wl_compositor());
if (lowerCaseResource == "surface") {
QWaylandWindow *w = static_cast<QWaylandWindow*>(window->handle());
- return w ? w->object() : nullptr;
+ return w ? w->wlSurface() : nullptr;
}
if (lowerCaseResource == "egldisplay" && m_integration->clientBufferIntegration())
diff --git a/src/client/qwaylandprimaryselectionv1.cpp b/src/client/qwaylandprimaryselectionv1.cpp
new file mode 100644
index 000000000..3ddf6dac3
--- /dev/null
+++ b/src/client/qwaylandprimaryselectionv1.cpp
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "qwaylandprimaryselectionv1_p.h"
+#include "qwaylandinputdevice_p.h"
+#include "qwaylanddisplay_p.h"
+#include "qwaylandmimehelper_p.h"
+
+#include <QtGui/private/qguiapplication_p.h>
+
+#include <qpa/qplatformclipboard.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+QWaylandPrimarySelectionDeviceManagerV1::QWaylandPrimarySelectionDeviceManagerV1(QWaylandDisplay *display, uint id, uint version)
+ : zwp_primary_selection_device_manager_v1(display->wl_registry(), id, qMin(version, uint(1)))
+ , m_display(display)
+{
+ // Create devices for all seats.
+ // This only works if we get the global before all devices
+ const auto seats = m_display->inputDevices();
+ for (auto *seat : seats)
+ seat->setPrimarySelectionDevice(createDevice(seat));
+}
+
+QWaylandPrimarySelectionDeviceV1 *QWaylandPrimarySelectionDeviceManagerV1::createDevice(QWaylandInputDevice *seat)
+{
+ return new QWaylandPrimarySelectionDeviceV1(this, seat);
+}
+
+QWaylandPrimarySelectionOfferV1::QWaylandPrimarySelectionOfferV1(QWaylandDisplay *display, ::zwp_primary_selection_offer_v1 *offer)
+ : zwp_primary_selection_offer_v1(offer)
+ , m_display(display)
+ , m_mimeData(new QWaylandMimeData(this))
+{}
+
+void QWaylandPrimarySelectionOfferV1::startReceiving(const QString &mimeType, int fd)
+{
+ receive(mimeType, fd);
+ wl_display_flush(m_display->wl_display());
+}
+
+void QWaylandPrimarySelectionOfferV1::zwp_primary_selection_offer_v1_offer(const QString &mime_type)
+{
+ m_mimeData->appendFormat(mime_type);
+}
+
+QWaylandPrimarySelectionDeviceV1::QWaylandPrimarySelectionDeviceV1(
+ QWaylandPrimarySelectionDeviceManagerV1 *manager, QWaylandInputDevice *seat)
+ : QtWayland::zwp_primary_selection_device_v1(manager->get_device(seat->wl_seat()))
+ , m_display(manager->display())
+ , m_seat(seat)
+{
+}
+
+QWaylandPrimarySelectionDeviceV1::~QWaylandPrimarySelectionDeviceV1()
+{
+ destroy();
+}
+
+void QWaylandPrimarySelectionDeviceV1::setSelectionSource(QWaylandPrimarySelectionSourceV1 *source)
+{
+ if (source) {
+ connect(source, &QWaylandPrimarySelectionSourceV1::cancelled, this, [this]() {
+ m_selectionSource.reset();
+ QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Selection);
+ });
+ }
+ set_selection(source ? source->object() : nullptr, m_seat->serial());
+ m_selectionSource.reset(source);
+}
+
+void QWaylandPrimarySelectionDeviceV1::zwp_primary_selection_device_v1_data_offer(zwp_primary_selection_offer_v1 *offer)
+{
+ new QWaylandPrimarySelectionOfferV1(m_display, offer);
+}
+
+void QWaylandPrimarySelectionDeviceV1::zwp_primary_selection_device_v1_selection(zwp_primary_selection_offer_v1 *id)
+{
+
+ if (id)
+ m_selectionOffer.reset(static_cast<QWaylandPrimarySelectionOfferV1 *>(zwp_primary_selection_offer_v1_get_user_data(id)));
+ else
+ m_selectionOffer.reset();
+
+ QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Selection);
+}
+
+QWaylandPrimarySelectionSourceV1::QWaylandPrimarySelectionSourceV1(QWaylandPrimarySelectionDeviceManagerV1 *manager, QMimeData *mimeData)
+ : QtWayland::zwp_primary_selection_source_v1(manager->create_source())
+ , m_mimeData(mimeData)
+{
+ if (!mimeData)
+ return;
+ for (auto &format : mimeData->formats())
+ offer(format);
+}
+
+QWaylandPrimarySelectionSourceV1::~QWaylandPrimarySelectionSourceV1()
+{
+ destroy();
+}
+
+void QWaylandPrimarySelectionSourceV1::zwp_primary_selection_source_v1_send(const QString &mime_type, int32_t fd)
+{
+ QByteArray content = QWaylandMimeHelper::getByteArray(m_mimeData, mime_type);
+ if (!content.isEmpty()) {
+ // Create a sigpipe handler that does nothing, or clients may be forced to terminate
+ // if the pipe is closed in the other end.
+ struct sigaction action, oldAction;
+ action.sa_handler = SIG_IGN;
+ sigemptyset (&action.sa_mask);
+ action.sa_flags = 0;
+
+ sigaction(SIGPIPE, &action, &oldAction);
+ write(fd, content.constData(), size_t(content.size()));
+ sigaction(SIGPIPE, &oldAction, nullptr);
+ }
+ close(fd);
+}
+
+} // namespace QtWaylandClient
+
+QT_END_NAMESPACE
diff --git a/src/client/qwaylandprimaryselectionv1_p.h b/src/client/qwaylandprimaryselectionv1_p.h
new file mode 100644
index 000000000..b165c51b8
--- /dev/null
+++ b/src/client/qwaylandprimaryselectionv1_p.h
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 QWAYLANDPRIMARYSELECTIONV1_P_H
+#define QWAYLANDPRIMARYSELECTIONV1_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 <QtWaylandClient/private/qwayland-wp-primary-selection-unstable-v1.h>
+
+#include <QtWaylandClient/private/qtwaylandclientglobal_p.h>
+#include <QtWaylandClient/private/qwaylanddataoffer_p.h>
+
+#include <QtCore/QObject>
+
+QT_REQUIRE_CONFIG(wayland_client_primary_selection);
+
+QT_BEGIN_NAMESPACE
+
+class QMimeData;
+
+namespace QtWaylandClient {
+
+class QWaylandInputDevice;
+class QWaylandPrimarySelectionDeviceV1;
+
+class QWaylandPrimarySelectionDeviceManagerV1 : public QtWayland::zwp_primary_selection_device_manager_v1
+{
+public:
+ explicit QWaylandPrimarySelectionDeviceManagerV1(QWaylandDisplay *display, uint id, uint version);
+ QWaylandPrimarySelectionDeviceV1 *createDevice(QWaylandInputDevice *seat);
+ QWaylandDisplay *display() const { return m_display; }
+
+private:
+ QWaylandDisplay *m_display = nullptr;
+};
+
+class QWaylandPrimarySelectionOfferV1 : public QtWayland::zwp_primary_selection_offer_v1, public QWaylandAbstractDataOffer
+{
+public:
+ explicit QWaylandPrimarySelectionOfferV1(QWaylandDisplay *display, ::zwp_primary_selection_offer_v1 *offer);
+ ~QWaylandPrimarySelectionOfferV1() override { destroy(); }
+ void startReceiving(const QString &mimeType, int fd) override;
+ QMimeData *mimeData() override { return m_mimeData.data(); }
+
+protected:
+ void zwp_primary_selection_offer_v1_offer(const QString &mime_type) override;
+
+private:
+ QWaylandDisplay *m_display = nullptr;
+ QScopedPointer<QWaylandMimeData> m_mimeData;
+};
+
+class Q_WAYLAND_CLIENT_EXPORT QWaylandPrimarySelectionSourceV1 : public QObject, public QtWayland::zwp_primary_selection_source_v1
+{
+ Q_OBJECT
+public:
+ explicit QWaylandPrimarySelectionSourceV1(QWaylandPrimarySelectionDeviceManagerV1 *manager, QMimeData *mimeData);
+ ~QWaylandPrimarySelectionSourceV1() override;
+
+ QMimeData *mimeData() const { return m_mimeData; }
+
+signals:
+ void cancelled();
+
+protected:
+ void zwp_primary_selection_source_v1_send(const QString &mime_type, int32_t fd) override;
+ void zwp_primary_selection_source_v1_cancelled() override { emit cancelled(); }
+
+private:
+ QWaylandDisplay *m_display = nullptr;
+ QMimeData *m_mimeData = nullptr;
+};
+
+class QWaylandPrimarySelectionDeviceV1 : public QObject, public QtWayland::zwp_primary_selection_device_v1
+{
+ Q_OBJECT
+ QWaylandPrimarySelectionDeviceV1(QWaylandPrimarySelectionDeviceManagerV1 *manager, QWaylandInputDevice *seat);
+
+public:
+ ~QWaylandPrimarySelectionDeviceV1() override;
+ QWaylandPrimarySelectionOfferV1 *selectionOffer() const { return m_selectionOffer.data(); }
+ void invalidateSelectionOffer() { m_selectionOffer.reset(); }
+ QWaylandPrimarySelectionSourceV1 *selectionSource() const { return m_selectionSource.data(); }
+ void setSelectionSource(QWaylandPrimarySelectionSourceV1 *source);
+
+protected:
+ void zwp_primary_selection_device_v1_data_offer(struct ::zwp_primary_selection_offer_v1 *offer) override;
+ void zwp_primary_selection_device_v1_selection(struct ::zwp_primary_selection_offer_v1 *id) override;
+
+private:
+ QWaylandDisplay *m_display = nullptr;
+ QWaylandInputDevice *m_seat = nullptr;
+ QScopedPointer<QWaylandPrimarySelectionOfferV1> m_selectionOffer;
+ QScopedPointer<QWaylandPrimarySelectionSourceV1> m_selectionSource;
+ friend class QWaylandPrimarySelectionDeviceManagerV1;
+};
+
+} // namespace QtWaylandClient
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDPRIMARYSELECTIONV1_P_H
diff --git a/src/client/qwaylandscreen.cpp b/src/client/qwaylandscreen.cpp
index d116a807b..e70796832 100644
--- a/src/client/qwaylandscreen.cpp
+++ b/src/client/qwaylandscreen.cpp
@@ -175,7 +175,8 @@ QList<QPlatformScreen *> QWaylandScreen::virtualSiblings() const
void QWaylandScreen::setOrientationUpdateMask(Qt::ScreenOrientations mask)
{
- foreach (QWindow *window, QGuiApplication::allWindows()) {
+ const auto allWindows = QGuiApplication::allWindows();
+ for (QWindow *window : allWindows) {
QWaylandWindow *w = static_cast<QWaylandWindow *>(window->handle());
if (w && w->waylandScreen() == this)
w->setOrientationMask(mask);
diff --git a/src/client/qwaylandshmbackingstore.cpp b/src/client/qwaylandshmbackingstore.cpp
index 34044ec9b..9b5971a21 100644
--- a/src/client/qwaylandshmbackingstore.cpp
+++ b/src/client/qwaylandshmbackingstore.cpp
@@ -243,12 +243,13 @@ void QWaylandShmBackingStore::resize(const QSize &size, const QRegion &)
QWaylandShmBuffer *QWaylandShmBackingStore::getBuffer(const QSize &size)
{
- foreach (QWaylandShmBuffer *b, mBuffers) {
+ const auto copy = mBuffers; // remove when ported to vector<unique_ptr> + remove_if
+ for (QWaylandShmBuffer *b : copy) {
if (!b->busy()) {
if (b->size() == size) {
return b;
} else {
- mBuffers.removeOne(b);
+ mBuffers.remove(b);
if (mBackBuffer == b)
mBackBuffer = nullptr;
delete b;
@@ -256,11 +257,11 @@ QWaylandShmBuffer *QWaylandShmBackingStore::getBuffer(const QSize &size)
}
}
- static const int MAX_BUFFERS = 5;
- if (mBuffers.count() < MAX_BUFFERS) {
+ static const size_t MAX_BUFFERS = 5;
+ if (mBuffers.size() < MAX_BUFFERS) {
QImage::Format format = QPlatformScreen::platformScreenForWindow(window())->format();
QWaylandShmBuffer *b = new QWaylandShmBuffer(mDisplay, size, format, waylandWindow()->scale());
- mBuffers.prepend(b);
+ mBuffers.push_front(b);
return b;
}
return nullptr;
@@ -288,20 +289,23 @@ void QWaylandShmBackingStore::resize(const QSize &size)
buffer = getBuffer(sizeWithMargins);
}
- qsizetype oldSize = mBackBuffer ? mBackBuffer->image()->sizeInBytes() : 0;
+ qsizetype oldSizeInBytes = mBackBuffer ? mBackBuffer->image()->sizeInBytes() : 0;
+ qsizetype newSizeInBytes = buffer->image()->sizeInBytes();
+
// mBackBuffer may have been deleted here but if so it means its size was different so we wouldn't copy it anyway
- if (mBackBuffer != buffer && oldSize == buffer->image()->sizeInBytes()) {
- memcpy(buffer->image()->bits(), mBackBuffer->image()->constBits(), buffer->image()->sizeInBytes());
- }
+ if (mBackBuffer != buffer && oldSizeInBytes == newSizeInBytes)
+ memcpy(buffer->image()->bits(), mBackBuffer->image()->constBits(), newSizeInBytes);
+
mBackBuffer = buffer;
+
// ensure the new buffer is at the beginning of the list so next time getBuffer() will pick
// it if possible
- if (mBuffers.first() != buffer) {
- mBuffers.removeOne(buffer);
- mBuffers.prepend(buffer);
+ if (mBuffers.front() != buffer) {
+ mBuffers.remove(buffer);
+ mBuffers.push_front(buffer);
}
- if (windowDecoration() && window()->isVisible())
+ if (windowDecoration() && window()->isVisible() && oldSizeInBytes != newSizeInBytes)
windowDecoration()->update();
}
diff --git a/src/client/qwaylandshmbackingstore_p.h b/src/client/qwaylandshmbackingstore_p.h
index 88ecfc5ec..8a85cd7f3 100644
--- a/src/client/qwaylandshmbackingstore_p.h
+++ b/src/client/qwaylandshmbackingstore_p.h
@@ -57,7 +57,8 @@
#include <QtGui/QImage>
#include <qpa/qplatformwindow.h>
#include <QMutex>
-#include <QLinkedList>
+
+#include <list>
QT_BEGIN_NAMESPACE
@@ -116,7 +117,7 @@ private:
QWaylandShmBuffer *getBuffer(const QSize &size);
QWaylandDisplay *mDisplay = nullptr;
- QLinkedList<QWaylandShmBuffer *> mBuffers;
+ std::list<QWaylandShmBuffer *> mBuffers;
QWaylandShmBuffer *mFrontBuffer = nullptr;
QWaylandShmBuffer *mBackBuffer = nullptr;
bool mPainting = false;
diff --git a/src/client/qwaylandsurface.cpp b/src/client/qwaylandsurface.cpp
new file mode 100644
index 000000000..c35f01b56
--- /dev/null
+++ b/src/client/qwaylandsurface.cpp
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the config.tests 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 "qwaylandsurface_p.h"
+#include "qwaylanddisplay_p.h"
+#include "qwaylandscreen_p.h"
+
+#include <QtGui/QGuiApplication>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+QWaylandSurface::QWaylandSurface(QWaylandDisplay *display)
+ : wl_surface(display->createSurface(this))
+{
+ connect(qApp, &QGuiApplication::screenRemoved, this, &QWaylandSurface::handleScreenRemoved);
+}
+
+QWaylandSurface::~QWaylandSurface()
+{
+ destroy();
+}
+
+QWaylandScreen *QWaylandSurface::oldestEnteredScreen()
+{
+ return m_screens.value(0, nullptr);
+}
+
+QWaylandSurface *QWaylandSurface::fromWlSurface(::wl_surface *surface)
+{
+ if (auto *s = QtWayland::wl_surface::fromObject(surface))
+ return static_cast<QWaylandSurface *>(s);
+ return nullptr;
+}
+
+void QWaylandSurface::handleScreenRemoved(QScreen *qScreen)
+{
+ auto *screen = static_cast<QWaylandScreen *>(qScreen->handle());
+ if (m_screens.removeOne(screen))
+ emit screensChanged();
+}
+
+void QWaylandSurface::surface_enter(wl_output *output)
+{
+ auto addedScreen = QWaylandScreen::fromWlOutput(output);
+
+ if (!addedScreen)
+ return;
+
+ if (m_screens.contains(addedScreen)) {
+ qCWarning(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;
+ }
+
+ m_screens.append(addedScreen);
+ emit screensChanged();
+}
+
+void QWaylandSurface::surface_leave(wl_output *output)
+{
+ auto *removedScreen = QWaylandScreen::fromWlOutput(output);
+
+ if (!removedScreen)
+ return;
+
+ bool wasRemoved = m_screens.removeOne(removedScreen);
+ if (!wasRemoved) {
+ qCWarning(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;
+ }
+ emit screensChanged();
+}
+
+} // namespace QtWaylandClient
+
+QT_END_NAMESPACE
diff --git a/src/client/qwaylandsurface_p.h b/src/client/qwaylandsurface_p.h
new file mode 100644
index 000000000..541010934
--- /dev/null
+++ b/src/client/qwaylandsurface_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the config.tests 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 QWAYLANDSURFACE_P_H
+#define QWAYLANDSURFACE_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 <QtGui/QScreen>
+
+#include <QtWaylandClient/private/qwayland-wayland.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+class QWaylandScreen;
+class QWaylandWindow;
+class QWaylandDisplay;
+
+class QWaylandSurface : public QObject, public QtWayland::wl_surface
+{
+ Q_OBJECT
+public:
+ explicit QWaylandSurface(QWaylandDisplay *display);
+ ~QWaylandSurface() override;
+ QWaylandScreen *oldestEnteredScreen();
+ QWaylandWindow *waylandWindow() const { return m_window; }
+
+ static QWaylandSurface *fromWlSurface(::wl_surface *surface);
+
+signals:
+ void screensChanged();
+
+private slots:
+ void handleScreenRemoved(QScreen *qScreen);
+
+protected:
+ void surface_enter(struct ::wl_output *output) override;
+ void surface_leave(struct ::wl_output *output) override;
+
+ QVector<QWaylandScreen *> m_screens; //As seen by wl_surface.enter/leave events. Chronological order.
+ QWaylandWindow *m_window = nullptr;
+
+ friend class QWaylandWindow; // TODO: shouldn't need to be friends
+};
+
+} // namespace QtWaylandClient
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDSURFACE_P_H
diff --git a/src/client/qwaylandtouch.cpp b/src/client/qwaylandtouch.cpp
index 48c869a60..0394aef31 100644
--- a/src/client/qwaylandtouch.cpp
+++ b/src/client/qwaylandtouch.cpp
@@ -40,6 +40,7 @@
#include "qwaylandtouch_p.h"
#include "qwaylandinputdevice_p.h"
#include "qwaylanddisplay_p.h"
+#include "qwaylandsurface_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
index ae26ba049..2704705e7 100644
--- a/src/client/qwaylandwindow.cpp
+++ b/src/client/qwaylandwindow.cpp
@@ -41,6 +41,7 @@
#include "qwaylandbuffer_p.h"
#include "qwaylanddisplay_p.h"
+#include "qwaylandsurface_p.h"
#include "qwaylandinputdevice_p.h"
#include "qwaylandscreen_p.h"
#include "qwaylandshellsurface_p.h"
@@ -80,7 +81,6 @@ QWaylandWindow::QWaylandWindow(QWindow *window)
{
static WId id = 1;
mWindowId = id++;
- connect(qApp, &QGuiApplication::screenRemoved, this, &QWaylandWindow::handleScreenRemoved);
initializeWlSurface();
}
@@ -90,11 +90,12 @@ QWaylandWindow::~QWaylandWindow()
delete mWindowDecoration;
- if (isInitialized())
+ if (mSurface)
reset(false);
const QWindow *parent = window();
- foreach (QWindow *w, QGuiApplication::topLevelWindows()) {
+ const auto tlw = QGuiApplication::topLevelWindows();
+ for (QWindow *w : tlw) {
if (w->transientParent() == parent)
QWindowSystemInterface::handleCloseEvent(w);
}
@@ -115,7 +116,7 @@ void QWaylandWindow::initWindow()
if (window()->type() == Qt::Desktop)
return;
- if (!isInitialized()) {
+ if (!mSurface) {
initializeWlSurface();
QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceCreated);
QGuiApplication::sendEvent(window(), &e);
@@ -181,7 +182,7 @@ void QWaylandWindow::initWindow()
// typically be integer 1 (normal-dpi) or 2 (high-dpi). Call set_buffer_scale()
// to inform the compositor that high-resolution buffers will be provided.
if (mDisplay->compositorVersion() >= 3)
- set_buffer_scale(scale());
+ mSurface->set_buffer_scale(scale());
if (QScreen *s = window()->screen())
setOrientationMask(s->orientationUpdateMask());
@@ -199,10 +200,13 @@ void QWaylandWindow::initWindow()
void QWaylandWindow::initializeWlSurface()
{
- Q_ASSERT(!isInitialized());
+ Q_ASSERT(!mSurface);
{
QWriteLocker lock(&mSurfaceLock);
- init(mDisplay->createSurface(static_cast<QtWayland::wl_surface *>(this)));
+ mSurface.reset(new QWaylandSurface(mDisplay));
+ connect(mSurface.data(), &QWaylandSurface::screensChanged,
+ this, &QWaylandWindow::handleScreensChanged);
+ mSurface->m_window = this;
}
emit wlSurfaceCreated();
}
@@ -231,7 +235,7 @@ bool QWaylandWindow::shouldCreateSubSurface() const
void QWaylandWindow::reset(bool sendDestroyEvent)
{
- if (isInitialized() && sendDestroyEvent) {
+ if (mSurface && sendDestroyEvent) {
QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed);
QGuiApplication::sendEvent(window(), &e);
}
@@ -239,12 +243,11 @@ void QWaylandWindow::reset(bool sendDestroyEvent)
mShellSurface = nullptr;
delete mSubSurfaceWindow;
mSubSurfaceWindow = nullptr;
- if (isInitialized()) {
+ if (mSurface) {
emit wlSurfaceDestroyed();
QWriteLocker lock(&mSurfaceLock);
- destroy();
+ mSurface.reset();
}
- mScreens.clear();
if (mFrameCallback) {
wl_callback_destroy(mFrameCallback);
@@ -264,7 +267,9 @@ void QWaylandWindow::reset(bool sendDestroyEvent)
QWaylandWindow *QWaylandWindow::fromWlSurface(::wl_surface *surface)
{
- return static_cast<QWaylandWindow *>(static_cast<QtWayland::wl_surface *>(wl_surface_get_user_data(surface)));
+ if (auto *s = QWaylandSurface::fromWlSurface(surface))
+ return s->m_window;
+ return nullptr;
}
WId QWaylandWindow::winId() const
@@ -398,7 +403,12 @@ void QWaylandWindow::closePopups(QWaylandWindow *parent)
QWaylandScreen *QWaylandWindow::calculateScreenFromSurfaceEvents() const
{
- return mScreens.isEmpty() ? waylandScreen() : mScreens.first();
+ if (mSurface) {
+ if (auto *screen = mSurface->oldestEnteredScreen())
+ return screen;
+ }
+
+ return waylandScreen();
}
void QWaylandWindow::setVisible(bool visible)
@@ -442,18 +452,18 @@ void QWaylandWindow::setMask(const QRegion &mask)
mMask = mask;
- if (!isInitialized())
+ if (!mSurface)
return;
if (mMask.isEmpty()) {
- set_input_region(nullptr);
+ mSurface->set_input_region(nullptr);
} else {
struct ::wl_region *region = mDisplay->createRegion(mMask);
- set_input_region(region);
+ mSurface->set_input_region(region);
wl_region_destroy(region);
}
- wl_surface::commit();
+ mSurface->commit();
}
void QWaylandWindow::applyConfigureWhenPossible()
@@ -507,58 +517,6 @@ void QWaylandWindow::applyConfigure()
QWindowSystemInterface::flushWindowSystemEvents();
}
-void QWaylandWindow::surface_enter(wl_output *output)
-{
- QWaylandScreen *oldScreen = calculateScreenFromSurfaceEvents();
- auto addedScreen = QWaylandScreen::fromWlOutput(output);
-
- if (mScreens.contains(addedScreen)) {
- qCWarning(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;
- }
-
- mScreens.append(addedScreen);
-
- QWaylandScreen *newScreen = calculateScreenFromSurfaceEvents();
- if (oldScreen != newScreen) //currently this will only happen if the first wl_surface.enter is for a non-primary screen
- handleScreenChanged();
-}
-
-void QWaylandWindow::surface_leave(wl_output *output)
-{
- QWaylandScreen *oldScreen = calculateScreenFromSurfaceEvents();
- auto *removedScreen = QWaylandScreen::fromWlOutput(output);
- bool wasRemoved = mScreens.removeOne(removedScreen);
- if (!wasRemoved) {
- qCWarning(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;
- }
-
- QWaylandScreen *newScreen = calculateScreenFromSurfaceEvents();
- if (oldScreen != newScreen)
- handleScreenChanged();
-}
-
-void QWaylandWindow::handleScreenRemoved(QScreen *qScreen)
-{
- QWaylandScreen *oldScreen = calculateScreenFromSurfaceEvents();
- bool wasRemoved = mScreens.removeOne(static_cast<QWaylandScreen *>(qScreen->handle()));
- if (wasRemoved) {
- QWaylandScreen *newScreen = calculateScreenFromSurfaceEvents();
- if (oldScreen != newScreen)
- handleScreenChanged();
- }
-}
-
void QWaylandWindow::attach(QWaylandBuffer *buffer, int x, int y)
{
Q_ASSERT(!buffer->committed());
@@ -566,9 +524,9 @@ void QWaylandWindow::attach(QWaylandBuffer *buffer, int x, int y)
handleUpdate();
buffer->setBusy();
- QtWayland::wl_surface::attach(buffer->buffer(), x, y);
+ mSurface->attach(buffer->buffer(), x, y);
} else {
- QtWayland::wl_surface::attach(nullptr, 0, 0);
+ mSurface->attach(nullptr, 0, 0);
}
}
@@ -580,7 +538,7 @@ void QWaylandWindow::attachOffset(QWaylandBuffer *buffer)
void QWaylandWindow::damage(const QRect &rect)
{
- damage(rect.x(), rect.y(), rect.width(), rect.height());
+ mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
}
void QWaylandWindow::safeCommit(QWaylandBuffer *buffer, const QRegion &damage)
@@ -610,20 +568,20 @@ void QWaylandWindow::commit(QWaylandBuffer *buffer, const QRegion &damage)
qCDebug(lcWaylandBackingstore) << "Buffer already committed, ignoring.";
return;
}
- if (!isInitialized())
+ if (!mSurface)
return;
attachOffset(buffer);
for (const QRect &rect: damage)
- wl_surface::damage(rect.x(), rect.y(), rect.width(), rect.height());
+ mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
Q_ASSERT(!buffer->committed());
buffer->setCommitted();
- wl_surface::commit();
+ mSurface->commit();
}
void QWaylandWindow::commit()
{
- wl_surface::commit();
+ mSurface->commit();
}
const wl_callback_listener QWaylandWindow::callbackListener = {
@@ -714,6 +672,11 @@ QRect QWaylandWindow::windowContentGeometry() const
return QRect(QPoint(), surfaceSize());
}
+wl_surface *QWaylandWindow::wlSurface()
+{
+ return mSurface ? mSurface->object() : nullptr;
+}
+
QWaylandShellSurface *QWaylandWindow::shellSurface() const
{
return mShellSurface;
@@ -755,9 +718,9 @@ void QWaylandWindow::handleContentOrientationChange(Qt::ScreenOrientation orient
default:
Q_UNREACHABLE();
}
- set_buffer_transform(transform);
+ mSurface->set_buffer_transform(transform);
// set_buffer_transform is double buffered, we need to commit.
- wl_surface::commit();
+ mSurface->commit();
}
void QWaylandWindow::setOrientationMask(Qt::ScreenOrientations mask)
@@ -846,7 +809,7 @@ bool QWaylandWindow::createDecoration()
}
if (hadDecoration != (bool)mWindowDecoration) {
- foreach (QWaylandSubSurface *subsurf, mChildren) {
+ for (QWaylandSubSurface *subsurf : qAsConst(mChildren)) {
QPoint pos = subsurf->window()->geometry().topLeft();
QMargins m = frameMargins();
subsurf->set_position(pos.x() + m.left(), pos.y() + m.top());
@@ -889,6 +852,18 @@ QWaylandWindow *QWaylandWindow::transientParent() const
void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e)
{
+ if (e.type == QWaylandPointerEvent::Leave) {
+ if (mWindowDecoration) {
+ if (mMouseEventsInContentArea)
+ QWindowSystemInterface::handleLeaveEvent(window());
+ } else {
+ QWindowSystemInterface::handleLeaveEvent(window());
+ }
+#if QT_CONFIG(cursor)
+ restoreMouseCursor(inputDevice);
+#endif
+ return;
+ }
if (mWindowDecoration) {
handleMouseEventWithDecoration(inputDevice, e);
@@ -897,11 +872,15 @@ void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, const QWaylan
case QWaylandPointerEvent::Enter:
QWindowSystemInterface::handleEnterEvent(window(), e.local, e.global);
break;
+ case QWaylandPointerEvent::Press:
+ case QWaylandPointerEvent::Release:
case QWaylandPointerEvent::Motion:
QWindowSystemInterface::handleMouseEvent(window(), e.timestamp, e.local, e.global, e.buttons, e.modifiers);
break;
case QWaylandPointerEvent::Wheel:
- QWindowSystemInterface::handleWheelEvent(window(), e.timestamp, e.local, e.global, e.pixelDelta, e.angleDelta, e.modifiers);
+ QWindowSystemInterface::handleWheelEvent(window(), e.timestamp, e.local, e.global,
+ e.pixelDelta, e.angleDelta, e.modifiers,
+ e.phase, e.source, false);
break;
}
}
@@ -915,20 +894,6 @@ void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, const QWaylan
#endif
}
-void QWaylandWindow::handleMouseLeave(QWaylandInputDevice *inputDevice)
-{
- if (mWindowDecoration) {
- if (mMouseEventsInContentArea) {
- QWindowSystemInterface::handleLeaveEvent(window());
- }
- } else {
- QWindowSystemInterface::handleLeaveEvent(window());
- }
-#if QT_CONFIG(cursor)
- restoreMouseCursor(inputDevice);
-#endif
-}
-
bool QWaylandWindow::touchDragDecoration(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, Qt::TouchPointState state, Qt::KeyboardModifiers mods)
{
if (!mWindowDecoration)
@@ -970,12 +935,18 @@ void QWaylandWindow::handleMouseEventWithDecoration(QWaylandInputDevice *inputDe
case QWaylandPointerEvent::Enter:
QWindowSystemInterface::handleEnterEvent(window(), localTranslated, globalTranslated);
break;
+ case QWaylandPointerEvent::Press:
+ case QWaylandPointerEvent::Release:
case QWaylandPointerEvent::Motion:
QWindowSystemInterface::handleMouseEvent(window(), e.timestamp, localTranslated, globalTranslated, e.buttons, e.modifiers);
break;
- case QWaylandPointerEvent::Wheel:
- QWindowSystemInterface::handleWheelEvent(window(), e.timestamp, localTranslated, globalTranslated, e.pixelDelta, e.angleDelta, e.modifiers);
+ case QWaylandPointerEvent::Wheel: {
+ QWindowSystemInterface::handleWheelEvent(window(), e.timestamp,
+ localTranslated, globalTranslated,
+ e.pixelDelta, e.angleDelta, e.modifiers,
+ e.phase, e.source, false);
break;
+ }
}
mMouseEventsInContentArea = true;
@@ -988,16 +959,21 @@ void QWaylandWindow::handleMouseEventWithDecoration(QWaylandInputDevice *inputDe
}
}
-void QWaylandWindow::handleScreenChanged()
+void QWaylandWindow::handleScreensChanged()
{
QWaylandScreen *newScreen = calculateScreenFromSurfaceEvents();
+
+ if (newScreen == mLastReportedScreen)
+ return;
+
QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen());
+ mLastReportedScreen = newScreen;
int scale = newScreen->scale();
if (scale != mScale) {
mScale = scale;
- if (isInitialized() && mDisplay->compositorVersion() >= 3)
- set_buffer_scale(mScale);
+ if (mSurface && mDisplay->compositorVersion() >= 3)
+ mSurface->set_buffer_scale(mScale);
ensureSize();
}
}
@@ -1167,7 +1143,7 @@ void QWaylandWindow::handleUpdate()
{
// TODO: Should sync subsurfaces avoid requesting frame callbacks?
QReadLocker lock(&mSurfaceLock);
- if (!isInitialized())
+ if (!mSurface)
return;
if (mFrameCallback) {
@@ -1184,7 +1160,7 @@ void QWaylandWindow::handleUpdate()
QMetaObject::invokeMethod(this, [this, id] { killTimer(id); }, Qt::QueuedConnection);
}
- mFrameCallback = frame();
+ mFrameCallback = mSurface->frame();
wl_callback_add_listener(mFrameCallback, &QWaylandWindow::callbackListener, this);
mWaitingForFrameCallback = true;
mWaitingForUpdate = false;
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
index b03d92e56..52e57c72a 100644
--- a/src/client/qwaylandwindow_p.h
+++ b/src/client/qwaylandwindow_p.h
@@ -81,8 +81,9 @@ class QWaylandInputDevice;
class QWaylandScreen;
class QWaylandShmBackingStore;
class QWaylandPointerEvent;
+class QWaylandSurface;
-class Q_WAYLAND_CLIENT_EXPORT QWaylandWindow : public QObject, public QPlatformWindow, public QtWayland::wl_surface
+class Q_WAYLAND_CLIENT_EXPORT QWaylandWindow : public QObject, public QPlatformWindow
{
Q_OBJECT
public:
@@ -110,12 +111,10 @@ public:
void applyConfigureWhenPossible(); //rename to possible?
- using QtWayland::wl_surface::attach;
void attach(QWaylandBuffer *buffer, int x, int y);
void attachOffset(QWaylandBuffer *buffer);
QPoint attachOffset() const;
- using QtWayland::wl_surface::damage;
void damage(const QRect &rect);
void safeCommit(QWaylandBuffer *buffer, const QRegion &damage);
@@ -130,6 +129,8 @@ public:
QSize surfaceSize() const;
QRect windowContentGeometry() const;
+ QWaylandSurface *waylandSurface() const { return mSurface.data(); }
+ ::wl_surface *wlSurface();
static QWaylandWindow *fromWlSurface(::wl_surface *surface);
QWaylandDisplay *display() const { return mDisplay; }
@@ -159,7 +160,6 @@ public:
QWaylandAbstractDecoration *decoration() const;
void handleMouse(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e);
- void handleMouseLeave(QWaylandInputDevice *inputDevice);
bool touchDragDecoration(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global,
Qt::TouchPointState state, Qt::KeyboardModifiers mods);
@@ -209,11 +209,8 @@ signals:
void wlSurfaceDestroyed();
protected:
- void surface_enter(struct ::wl_output *output) override;
- void surface_leave(struct ::wl_output *output) override;
-
- QVector<QWaylandScreen *> mScreens; //As seen by wl_surface.enter/leave events. Chronological order.
QWaylandDisplay *mDisplay = nullptr;
+ QScopedPointer<QWaylandSurface> mSurface;
QWaylandShellSurface *mShellSurface = nullptr;
QWaylandSubSurface *mSubSurfaceWindow = nullptr;
QVector<QWaylandSubSurface *> mChildren;
@@ -244,6 +241,7 @@ protected:
bool mSentInitialResize = false;
QPoint mOffset;
int mScale = 1;
+ QWaylandScreen *mLastReportedScreen = nullptr;
QIcon mWindowIcon;
@@ -255,9 +253,6 @@ protected:
QWaylandBuffer *mQueuedBuffer = nullptr;
QRegion mQueuedBufferDamage;
-private slots:
- void handleScreenRemoved(QScreen *qScreen);
-
private:
void setGeometry_helper(const QRect &rect);
void initWindow();
@@ -270,7 +265,7 @@ private:
QWaylandScreen *calculateScreenFromSurfaceEvents() const;
void handleMouseEventWithDecoration(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e);
- void handleScreenChanged();
+ void handleScreensChanged();
bool mInResizeFromApplyConfigure = false;
QRect mLastExposeGeometry;
diff --git a/src/compositor/compositor_api/compositor_api.pri b/src/compositor/compositor_api/compositor_api.pri
index c8f1c98b7..bbc3a03e7 100644
--- a/src/compositor/compositor_api/compositor_api.pri
+++ b/src/compositor/compositor_api/compositor_api.pri
@@ -69,16 +69,21 @@ qtConfig(wayland-compositor-quick) {
compositor_api/qwaylandquickcompositor.cpp \
compositor_api/qwaylandquicksurface.cpp \
compositor_api/qwaylandquickoutput.cpp \
- compositor_api/qwaylandquickitem.cpp \
- compositor_api/qwaylandquickhardwarelayer.cpp
+ compositor_api/qwaylandquickitem.cpp
HEADERS += \
compositor_api/qwaylandquickcompositor.h \
compositor_api/qwaylandquicksurface.h \
compositor_api/qwaylandquickoutput.h \
compositor_api/qwaylandquickitem.h \
- compositor_api/qwaylandquickitem_p.h \
- compositor_api/qwaylandquickhardwarelayer_p.h
+ compositor_api/qwaylandquickitem_p.h
+
+ qtConfig(opengl) {
+ SOURCES += \
+ compositor_api/qwaylandquickhardwarelayer.cpp
+ HEADERS += \
+ compositor_api/qwaylandquickhardwarelayer_p.h
+ }
QT += qml qml-private quick quick-private
}
diff --git a/src/compositor/compositor_api/qwaylandcompositor.cpp b/src/compositor/compositor_api/qwaylandcompositor.cpp
index 530cf8ed6..e2d617c37 100644
--- a/src/compositor/compositor_api/qwaylandcompositor.cpp
+++ b/src/compositor/compositor_api/qwaylandcompositor.cpp
@@ -200,8 +200,8 @@ void QWaylandCompositorPrivate::init()
buffer_manager = new QtWayland::BufferManager(q);
wl_display_init_shm(display);
- QVector<wl_shm_format> formats = QWaylandSharedMemoryFormatHelper::supportedWaylandFormats();
- foreach (wl_shm_format format, formats)
+ const QVector<wl_shm_format> formats = QWaylandSharedMemoryFormatHelper::supportedWaylandFormats();
+ for (wl_shm_format format : formats)
wl_display_add_shm_format(display, format);
if (!socket_name.isEmpty()) {
@@ -234,7 +234,7 @@ void QWaylandCompositorPrivate::init()
initialized = true;
- Q_FOREACH (QPointer<QObject> object, polish_objects) {
+ for (const QPointer<QObject> &object : qExchange(polish_objects, {})) {
if (object) {
QEvent polishEvent(QEvent::Polish);
QCoreApplication::sendEvent(object.data(), &polishEvent);
@@ -302,7 +302,7 @@ void QWaylandCompositorPrivate::addPolishObject(QObject *object)
if (initialized) {
QCoreApplication::postEvent(object, new QEvent(QEvent::Polish));
} else {
- polish_objects.append(object);
+ polish_objects.push_back(object);
}
}
@@ -706,7 +706,7 @@ QList<QWaylandSurface *> QWaylandCompositor::surfacesForClient(QWaylandClient* c
{
Q_D(const QWaylandCompositor);
QList<QWaylandSurface *> surfs;
- foreach (QWaylandSurface *surface, d->all_surfaces) {
+ for (QWaylandSurface *surface : d->all_surfaces) {
if (surface->client() == client)
surfs.append(surface);
}
@@ -728,7 +728,7 @@ QList<QWaylandSurface *> QWaylandCompositor::surfaces() const
QWaylandOutput *QWaylandCompositor::outputFor(QWindow *window) const
{
Q_D(const QWaylandCompositor);
- foreach (QWaylandOutput *output, d->outputs) {
+ for (QWaylandOutput *output : d->outputs) {
if (output->window() == window)
return output;
}
diff --git a/src/compositor/compositor_api/qwaylandcompositor_p.h b/src/compositor/compositor_api/qwaylandcompositor_p.h
index 2c9624216..2437533dd 100644
--- a/src/compositor/compositor_api/qwaylandcompositor_p.h
+++ b/src/compositor/compositor_api/qwaylandcompositor_p.h
@@ -60,6 +60,8 @@
#include <QtWaylandCompositor/private/qwayland-server-wayland.h>
+#include <vector>
+
#if QT_CONFIG(xkbcommon)
#include <QtXkbCommonSupport/private/qxkbcommon_p.h>
#endif
@@ -175,7 +177,7 @@ protected:
bool retainSelection = false;
bool preInitialized = false;
bool initialized = false;
- QList<QPointer<QObject> > polish_objects;
+ std::vector<QPointer<QObject> > polish_objects;
#if QT_CONFIG(xkbcommon)
QXkbCommon::ScopedXKBContext mXkbContext;
diff --git a/src/compositor/compositor_api/qwaylandkeyboard.cpp b/src/compositor/compositor_api/qwaylandkeyboard.cpp
index 2302c0b6a..c5ec008d7 100644
--- a/src/compositor/compositor_api/qwaylandkeyboard.cpp
+++ b/src/compositor/compositor_api/qwaylandkeyboard.cpp
@@ -256,7 +256,8 @@ void QWaylandKeyboardPrivate::maybeUpdateKeymap()
return;
createXKBKeymap();
- foreach (Resource *res, resourceMap()) {
+ const auto resMap = resourceMap();
+ for (Resource *res : resMap) {
send_keymap(res->handle, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymap_fd, keymap_size);
}
@@ -365,6 +366,13 @@ void QWaylandKeyboardPrivate::createXKBKeymap()
QByteArray variant = keymap->variant().toLocal8Bit();
QByteArray options = keymap->options().toLocal8Bit();
+ if (!layout.isEmpty() && !layout.contains("us")) {
+ // This is needed for shortucts like "ctrl+c" to function even when
+ // user has selected only non-latin keyboard layouts, e.g. 'ru'.
+ layout.append(",us");
+ variant.append(",");
+ }
+
struct xkb_rule_names rule_names = {
rules.constData(),
model.constData(),
@@ -386,7 +394,8 @@ void QWaylandKeyboardPrivate::createXKBKeymap()
void QWaylandKeyboardPrivate::sendRepeatInfo()
{
- Q_FOREACH (Resource *resource, resourceMap()) {
+ const auto resMap = resourceMap();
+ for (Resource *resource : resMap) {
if (resource->version() >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)
send_repeat_info(resource->handle, repeatRate, repeatDelay);
}
diff --git a/src/compositor/compositor_api/qwaylandoutput.cpp b/src/compositor/compositor_api/qwaylandoutput.cpp
index 006edbe6a..601f692af 100644
--- a/src/compositor/compositor_api/qwaylandoutput.cpp
+++ b/src/compositor/compositor_api/qwaylandoutput.cpp
@@ -48,6 +48,7 @@
#include <QtWaylandCompositor/private/qwaylandcompositor_p.h>
#include <QtWaylandCompositor/private/qwaylandview_p.h>
#include <QtWaylandCompositor/private/qwaylandutils_p.h>
+#include <QtWaylandCompositor/private/qwaylandxdgoutputv1_p.h>
#include <QtCore/QCoreApplication>
#include <QtCore/QtMath>
@@ -162,6 +163,9 @@ void QWaylandOutputPrivate::sendGeometryInfo()
if (resource->version() >= 2)
send_done(resource->handle);
}
+
+ if (xdgOutput)
+ QWaylandXdgOutputV1Private::get(xdgOutput)->sendDone();
}
void QWaylandOutputPrivate::sendMode(const Resource *resource, const QWaylandOutputMode &mode)
@@ -185,6 +189,9 @@ void QWaylandOutputPrivate::sendModesInfo()
if (resource->version() >= 2)
send_done(resource->handle);
}
+
+ if (xdgOutput)
+ QWaylandXdgOutputV1Private::get(xdgOutput)->sendDone();
}
void QWaylandOutputPrivate::handleWindowPixelSizeChanged()
@@ -831,7 +838,8 @@ void QWaylandOutput::setScaleFactor(int scale)
d->scaleFactor = scale;
- Q_FOREACH (QWaylandOutputPrivate::Resource *resource, d->resourceMap().values()) {
+ const auto resMap = d->resourceMap();
+ for (QWaylandOutputPrivate::Resource *resource : resMap) {
if (resource->version() >= 2) {
d->send_scale(resource->handle, scale);
d->send_done(resource->handle);
@@ -839,6 +847,9 @@ void QWaylandOutput::setScaleFactor(int scale)
}
Q_EMIT scaleFactorChanged();
+
+ if (d->xdgOutput)
+ QWaylandXdgOutputV1Private::get(d->xdgOutput)->sendDone();
}
/*!
diff --git a/src/compositor/compositor_api/qwaylandoutput_p.h b/src/compositor/compositor_api/qwaylandoutput_p.h
index 4badd3797..58188ac38 100644
--- a/src/compositor/compositor_api/qwaylandoutput_p.h
+++ b/src/compositor/compositor_api/qwaylandoutput_p.h
@@ -57,6 +57,7 @@
#include <QtWaylandCompositor/QWaylandOutput>
#include <QtWaylandCompositor/QWaylandClient>
#include <QtWaylandCompositor/QWaylandSurface>
+#include <QtWaylandCompositor/QWaylandXdgOutputV1>
#include <QtWaylandCompositor/private/qwayland-server-wayland.h>
@@ -110,6 +111,8 @@ public:
void handleWindowPixelSizeChanged();
+ QPointer<QWaylandXdgOutputV1> xdgOutput;
+
protected:
void output_bind_resource(Resource *resource) override;
@@ -137,6 +140,8 @@ private:
Q_DECLARE_PUBLIC(QWaylandOutput)
Q_DISABLE_COPY(QWaylandOutputPrivate)
+
+ friend class QWaylandXdgOutputManagerV1Private;
};
diff --git a/src/compositor/compositor_api/qwaylandquickcompositor.cpp b/src/compositor/compositor_api/qwaylandquickcompositor.cpp
index 14b592efb..1b3f93e5c 100644
--- a/src/compositor/compositor_api/qwaylandquickcompositor.cpp
+++ b/src/compositor/compositor_api/qwaylandquickcompositor.cpp
@@ -128,6 +128,7 @@ void QWaylandQuickCompositor::grabSurface(QWaylandSurfaceGrabber *grabber, const
return;
}
+#if QT_CONFIG(opengl)
QWaylandQuickOutput *output = static_cast<QWaylandQuickOutput *>(defaultOutput());
if (!output) {
emit grabber->failed(QWaylandSurfaceGrabber::RendererNotReady);
@@ -169,6 +170,9 @@ void QWaylandQuickCompositor::grabSurface(QWaylandSurfaceGrabber *grabber, const
state->grabber = grabber;
state->buffer = buffer;
static_cast<QQuickWindow *>(output->window())->scheduleRenderJob(state, QQuickWindow::NoStage);
+#else
+ emit grabber->failed(QWaylandSurfaceGrabber::UnknownBufferType);
+#endif
}
QT_END_NAMESPACE
diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp
index 648993fc4..ecea8125e 100644
--- a/src/compositor/compositor_api/qwaylandquickitem.cpp
+++ b/src/compositor/compositor_api/qwaylandquickitem.cpp
@@ -73,6 +73,7 @@
QT_BEGIN_NAMESPACE
+#if QT_CONFIG(opengl)
static const struct {
const char * const vertexShaderSourceFile;
const char * const fragmentShaderSourceFile;
@@ -259,6 +260,7 @@ void QWaylandBufferMaterial::ensureTextures(int count)
m_textures << nullptr;
}
}
+#endif // QT_CONFIG(opengl)
QMutex *QWaylandQuickItemPrivate::mutex = nullptr;
@@ -284,10 +286,12 @@ public:
if (m_ref.hasBuffer()) {
if (buffer.isSharedMemory()) {
m_sgTex = surfaceItem->window()->createTextureFromImage(buffer.image());
- if (m_sgTex) {
+#if QT_CONFIG(opengl)
+ if (m_sgTex)
m_sgTex->bind();
- }
+#endif
} else {
+#if QT_CONFIG(opengl)
QQuickWindow::CreateTextureOptions opt;
QWaylandQuickSurface *surface = qobject_cast<QWaylandQuickSurface *>(surfaceItem->surface());
if (surface && surface->useTextureAlpha()) {
@@ -297,6 +301,9 @@ public:
auto texture = buffer.toOpenGLTexture();
auto size = surface->bufferSize();
m_sgTex = surfaceItem->window()->createTextureFromId(texture->textureId(), size, opt);
+#else
+ qCWarning(qLcWaylandCompositor) << "Without OpenGL support only shared memory textures are supported";
+#endif
}
}
emit textureChanged();
@@ -603,13 +610,17 @@ void QWaylandQuickItem::wheelEvent(QWheelEvent *event)
{
Q_D(QWaylandQuickItem);
if (d->shouldSendInputEvents()) {
- if (!inputRegionContains(event->posF())) {
+ if (!inputRegionContains(event->position())) {
event->ignore();
return;
}
QWaylandSeat *seat = compositor()->seatFor(event);
- seat->sendMouseWheelEvent(event->orientation(), event->delta());
+ // TODO: fix this to send a single event, when diagonal scrolling is supported
+ if (event->angleDelta().x() != 0)
+ seat->sendMouseWheelEvent(Qt::Horizontal, event->angleDelta().x());
+ if (event->angleDelta().y() != 0)
+ seat->sendMouseWheelEvent(Qt::Vertical, event->angleDelta().y());
} else {
event->ignore();
}
@@ -1327,7 +1338,11 @@ QSGNode *QWaylandQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
const QRectF rect = invertY ? QRectF(0, height(), width(), -height())
: QRectF(0, 0, width(), height());
- if (ref.isSharedMemory() || bufferTypes[ref.bufferFormatEgl()].canProvideTexture) {
+ if (ref.isSharedMemory()
+#if QT_CONFIG(opengl)
+ || bufferTypes[ref.bufferFormatEgl()].canProvideTexture
+#endif
+ ) {
// This case could covered by the more general path below, but this is more efficient (especially when using ShaderEffect items).
QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode *>(oldNode);
@@ -1353,45 +1368,48 @@ QSGNode *QWaylandQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
node->setSourceRect(QRectF(source.topLeft() * scale, source.size() * scale));
return node;
- } else {
- Q_ASSERT(!d->provider);
+ }
- QSGGeometryNode *node = static_cast<QSGGeometryNode *>(oldNode);
+#if QT_CONFIG(opengl)
+ Q_ASSERT(!d->provider);
- if (!node) {
- node = new QSGGeometryNode;
- d->newTexture = true;
- }
+ QSGGeometryNode *node = static_cast<QSGGeometryNode *>(oldNode);
- QSGGeometry *geometry = node->geometry();
- QWaylandBufferMaterial *material = static_cast<QWaylandBufferMaterial *>(node->material());
+ if (!node) {
+ node = new QSGGeometryNode;
+ d->newTexture = true;
+ }
- if (!geometry)
- geometry = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4);
+ QSGGeometry *geometry = node->geometry();
+ QWaylandBufferMaterial *material = static_cast<QWaylandBufferMaterial *>(node->material());
- if (!material)
- material = new QWaylandBufferMaterial(ref.bufferFormatEgl());
+ if (!geometry)
+ geometry = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4);
- if (d->newTexture) {
- d->newTexture = false;
- for (int plane = 0; plane < bufferTypes[ref.bufferFormatEgl()].planeCount; plane++)
- if (auto texture = ref.toOpenGLTexture(plane))
- material->setTextureForPlane(plane, texture);
- material->bind();
- }
+ if (!material)
+ material = new QWaylandBufferMaterial(ref.bufferFormatEgl());
- QSGGeometry::updateTexturedRectGeometry(geometry, rect, QRectF(0, 0, 1, 1));
+ if (d->newTexture) {
+ d->newTexture = false;
+ for (int plane = 0; plane < bufferTypes[ref.bufferFormatEgl()].planeCount; plane++)
+ if (auto texture = ref.toOpenGLTexture(plane))
+ material->setTextureForPlane(plane, texture);
+ material->bind();
+ }
- node->setGeometry(geometry);
- node->setFlag(QSGNode::OwnsGeometry, true);
+ QSGGeometry::updateTexturedRectGeometry(geometry, rect, QRectF(0, 0, 1, 1));
- node->setMaterial(material);
- node->setFlag(QSGNode::OwnsMaterial, true);
+ node->setGeometry(geometry);
+ node->setFlag(QSGNode::OwnsGeometry, true);
- return node;
- }
+ node->setMaterial(material);
+ node->setFlag(QSGNode::OwnsMaterial, true);
- Q_UNREACHABLE();
+ return node;
+#else
+ qCWarning(qLcWaylandCompositor) << "Without OpenGL support only shared memory textures are supported";
+ return nullptr;
+#endif // QT_CONFIG(opengl)
}
void QWaylandQuickItem::setTouchEventsEnabled(bool enabled)
diff --git a/src/compositor/compositor_api/qwaylandquickitem_p.h b/src/compositor/compositor_api/qwaylandquickitem_p.h
index 352a130dc..832272a37 100644
--- a/src/compositor/compositor_api/qwaylandquickitem_p.h
+++ b/src/compositor/compositor_api/qwaylandquickitem_p.h
@@ -64,6 +64,7 @@ class QWaylandSurfaceTextureProvider;
class QMutex;
class QOpenGLTexture;
+#if QT_CONFIG(opengl)
class QWaylandBufferMaterialShader : public QSGMaterialShader
{
public:
@@ -102,6 +103,7 @@ private:
const QWaylandBufferRef::BufferFormatEgl m_format;
QVarLengthArray<QOpenGLTexture*, 3> m_textures;
};
+#endif // QT_CONFIG(opengl)
class QWaylandQuickItemPrivate : public QQuickItemPrivate
{
diff --git a/src/compositor/compositor_api/qwaylandseat.cpp b/src/compositor/compositor_api/qwaylandseat.cpp
index bc5e1d8b2..0a6248d11 100644
--- a/src/compositor/compositor_api/qwaylandseat.cpp
+++ b/src/compositor/compositor_api/qwaylandseat.cpp
@@ -289,6 +289,10 @@ void QWaylandSeat::sendKeyReleaseEvent(uint code)
* Sends a touch point event to the \a surface on a touch device with the given
* \a id, \a point and \a state.
*
+ * \warning This API should not be used in combination with forwarding of touch
+ * events using \l QWaylandQuickItem::touchEventsEnabled or \l sendFullTouchEvent,
+ * as it might lead to conflicting touch ids.
+ *
* Returns the serial for the touch up or touch down event.
*/
uint QWaylandSeat::sendTouchPointEvent(QWaylandSurface *surface, int id, const QPointF &point, Qt::TouchPointState state)
@@ -310,6 +314,10 @@ uint QWaylandSeat::sendTouchPointEvent(QWaylandSurface *surface, int id, const Q
* \note You need to send a touch frame event when you are done sending touch
* events.
*
+ * \warning This API should not be used in combination with forwarding of touch
+ * events using \l WaylandQuickItem::touchEventsEnabled, as it might lead to
+ * conflicting touch ids.
+ *
* Returns the serial for the touch down event.
*/
@@ -320,6 +328,10 @@ uint QWaylandSeat::sendTouchPointEvent(QWaylandSurface *surface, int id, const Q
* \note You need to send a touch frame event when you are done sending touch
* events.
*
+ * \warning This API should not be used in combination with forwarding of touch
+ * events using \l QWaylandQuickItem::touchEventsEnabled or \l sendFullTouchEvent,
+ * as it might lead to conflicting touch ids.
+ *
* Returns the serial for the touch down event.
*/
uint QWaylandSeat::sendTouchPointPressed(QWaylandSurface *surface, int id, const QPointF &position)
@@ -336,6 +348,10 @@ uint QWaylandSeat::sendTouchPointPressed(QWaylandSurface *surface, int id, const
* \note You need to send a touch frame event when you are done sending touch
* events.
*
+ * \warning This API should not be used in combination with forwarding of touch
+ * events using \l WaylandQuickItem::touchEventsEnabled, as it might lead to
+ * conflicting touch ids.
+ *
* Returns the serial for the touch up event.
*/
@@ -346,6 +362,10 @@ uint QWaylandSeat::sendTouchPointPressed(QWaylandSurface *surface, int id, const
* \note You need to send a touch frame event when you are done sending touch
* events.
*
+ * \warning This API should not be used in combination with forwarding of touch
+ * events using \l QWaylandQuickItem::touchEventsEnabled or \l sendFullTouchEvent,
+ * as it might lead to conflicting touch ids.
+ *
* Returns the serial for the touch up event.
*/
uint QWaylandSeat::sendTouchPointReleased(QWaylandSurface *surface, int id, const QPointF &position)
@@ -362,6 +382,10 @@ uint QWaylandSeat::sendTouchPointReleased(QWaylandSurface *surface, int id, cons
* \note You need to send a touch frame event when you are done sending touch
* events.
*
+ * \warning This API should not be used in combination with forwarding of touch
+ * events using \l WaylandQuickItem::touchEventsEnabled, as it might lead to
+ * conflicting touch ids.
+ *
* Returns the serial for the touch motion event.
*/
@@ -372,6 +396,10 @@ uint QWaylandSeat::sendTouchPointReleased(QWaylandSurface *surface, int id, cons
* \note You need to send a touch frame event when you are done sending touch
* events.
*
+ * \warning This API should not be used in combination with forwarding of touch
+ * events using \l QWaylandQuickItem::touchEventsEnabled or \l sendFullTouchEvent,
+ * as it might lead to conflicting touch ids.
+ *
* Returns the serial for the touch motion event.
*/
uint QWaylandSeat::sendTouchPointMoved(QWaylandSurface *surface, int id, const QPointF &position)
@@ -415,6 +443,11 @@ void QWaylandSeat::sendTouchCancelEvent(QWaylandClient *client)
/*!
* Sends the \a event to the specified \a surface on the touch device.
+ *
+ * \warning This API will automatically map \l QTouchEvent::TouchPoint::id to a
+ * sequential id before sending it to the client. It should therefore not be
+ * used in combination with the other API using explicit ids, as collisions
+ * might occur.
*/
void QWaylandSeat::sendFullTouchEvent(QWaylandSurface *surface, QTouchEvent *event)
{
diff --git a/src/compositor/compositor_api/qwaylandsurface.cpp b/src/compositor/compositor_api/qwaylandsurface.cpp
index a82c93f7b..0d4cae642 100644
--- a/src/compositor/compositor_api/qwaylandsurface.cpp
+++ b/src/compositor/compositor_api/qwaylandsurface.cpp
@@ -137,9 +137,9 @@ QWaylandSurfacePrivate::~QWaylandSurfacePrivate()
bufferRef = QWaylandBufferRef();
- foreach (QtWayland::FrameCallback *c, pendingFrameCallbacks)
+ for (QtWayland::FrameCallback *c : qAsConst(pendingFrameCallbacks))
c->destroy();
- foreach (QtWayland::FrameCallback *c, frameCallbacks)
+ for (QtWayland::FrameCallback *c : qAsConst(frameCallbacks))
c->destroy();
}
@@ -152,7 +152,8 @@ void QWaylandSurfacePrivate::removeFrameCallback(QtWayland::FrameCallback *callb
void QWaylandSurfacePrivate::notifyViewsAboutDestruction()
{
Q_Q(QWaylandSurface);
- foreach (QWaylandView *view, views) {
+ const auto viewsCopy = views; // Views will be removed from the list when marked as destroyed
+ for (QWaylandView *view : viewsCopy) {
QWaylandViewPrivate::get(view)->markSurfaceAsDestroyed(q);
}
if (hasContent) {
@@ -674,7 +675,7 @@ QWaylandCompositor *QWaylandSurface::compositor() const
void QWaylandSurface::frameStarted()
{
Q_D(QWaylandSurface);
- foreach (QtWayland::FrameCallback *c, d->frameCallbacks)
+ for (QtWayland::FrameCallback *c : qAsConst(d->frameCallbacks))
c->canSend = true;
}
@@ -707,10 +708,11 @@ bool QWaylandSurface::inputRegionContains(const QPoint &p) const
return d->inputRegion.contains(p);
}
-//TODO: Add appropriate \since version when this is made public.
/*!
* Returns \c true if the QWaylandSurface's input region contains the point \a position.
* Otherwise returns \c false.
+ *
+ * \since 5.14
*/
bool QWaylandSurface::inputRegionContains(const QPointF &position) const
{
@@ -781,6 +783,31 @@ bool QWaylandSurface::isCursorSurface() const
return d->isCursorSurface;
}
+/*!
+ * \qmlproperty bool QtWaylandCompositor::WaylandSurface::inhibitsIdle
+ * \since 5.14
+ *
+ * This property holds whether this surface is intended to inhibit the idle
+ * behavior of the compositor such as screen blanking, locking and screen saving.
+ *
+ * \sa IdleInhibitManagerV1
+ */
+
+/*!
+ * \property QWaylandSurface::inhibitsIdle
+ * \since 5.14
+ *
+ * This property holds whether this surface is intended to inhibit the idle
+ * behavior of the compositor such as screen blanking, locking and screen saving.
+ *
+ * \sa QWaylandIdleInhibitManagerV1
+ */
+bool QWaylandSurface::inhibitsIdle() const
+{
+ Q_D(const QWaylandSurface);
+ return !d->idleInhibitors.isEmpty();
+}
+
#if QT_CONFIG(im)
QWaylandInputMethodControl *QWaylandSurface::inputMethodControl() const
{
diff --git a/src/compositor/compositor_api/qwaylandsurface.h b/src/compositor/compositor_api/qwaylandsurface.h
index 48b69fe21..64265617f 100644
--- a/src/compositor/compositor_api/qwaylandsurface.h
+++ b/src/compositor/compositor_api/qwaylandsurface.h
@@ -92,6 +92,7 @@ class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandSurface : public QWaylandObject
Q_PROPERTY(QWaylandSurface::Origin origin READ origin NOTIFY originChanged)
Q_PROPERTY(bool hasContent READ hasContent NOTIFY hasContentChanged)
Q_PROPERTY(bool cursorSurface READ isCursorSurface WRITE markAsCursorSurface NOTIFY cursorSurfaceChanged)
+ Q_PROPERTY(bool inhibitsIdle READ inhibitsIdle NOTIFY inhibitsIdleChanged REVISION 14)
public:
enum Origin {
@@ -130,13 +131,7 @@ public:
QWaylandCompositor *compositor() const;
bool inputRegionContains(const QPoint &p) const;
-private:
- // TODO: Making this private now since it's added in a patch release, and we want to ensure
- // compatibility with older patch releases.
- // This should simply be made public (and the friend removed) in the next minor release.
- friend class QWaylandQuickItem;
bool inputRegionContains(const QPointF &position) const;
-public:
Q_INVOKABLE void destroy();
Q_INVOKABLE bool isDestroyed() const;
@@ -155,6 +150,8 @@ public:
void markAsCursorSurface(bool cursorSurface);
bool isCursorSurface() const;
+ bool inhibitsIdle() const;
+
#if QT_CONFIG(im)
QWaylandInputMethodControl *inputMethodControl() const;
#endif
@@ -188,6 +185,7 @@ Q_SIGNALS:
void subsurfacePlaceBelow(QWaylandSurface *sibling);
void dragStarted(QWaylandDrag *drag);
void cursorSurfaceChanged();
+ Q_REVISION(14) void inhibitsIdleChanged();
void configure(bool hasBuffer);
void redraw();
diff --git a/src/compositor/compositor_api/qwaylandsurface_p.h b/src/compositor/compositor_api/qwaylandsurface_p.h
index 1637d8704..97cb19d9b 100644
--- a/src/compositor/compositor_api/qwaylandsurface_p.h
+++ b/src/compositor/compositor_api/qwaylandsurface_p.h
@@ -74,6 +74,7 @@
#include <QtWaylandCompositor/private/qwayland-server-wayland.h>
#include <QtWaylandCompositor/private/qwaylandviewporter_p.h>
+#include <QtWaylandCompositor/private/qwaylandidleinhibitv1_p.h>
QT_BEGIN_NAMESPACE
@@ -167,6 +168,8 @@ public: //member variables
QList<QPointer<QWaylandSurface>> subsurfaceChildren;
+ QVector<QWaylandIdleInhibitManagerV1Private::Inhibitor *> idleInhibitors;
+
QRegion inputRegion;
QRegion opaqueRegion;
diff --git a/src/compositor/compositor_api/qwaylandview.cpp b/src/compositor/compositor_api/qwaylandview.cpp
index 1a6bf1a64..12889bdfa 100644
--- a/src/compositor/compositor_api/qwaylandview.cpp
+++ b/src/compositor/compositor_api/qwaylandview.cpp
@@ -246,7 +246,8 @@ bool QWaylandView::advance()
return false;
if (d->surface && d->surface->primaryView() == this) {
- Q_FOREACH (QWaylandView *view, d->surface->views()) {
+ const auto views = d->surface->views();
+ for (QWaylandView *view : views) {
if (view != this && view->allowDiscardFrontBuffer() && view->d_func()->currentBuffer == d->currentBuffer)
view->discardCurrentBuffer();
}
diff --git a/src/compositor/configure.json b/src/compositor/configure.json
index 5d8fe8dda..46caceff5 100644
--- a/src/compositor/configure.json
+++ b/src/compositor/configure.json
@@ -145,14 +145,9 @@
"condition": "features.wayland-server && features.opengl && features.egl && tests.dmabuf-client-buffer",
"output": [ "privateFeature" ]
},
- "wayland-compositor-texture-sharing-experimental" : {
- "label": "Texture sharing (experimental)",
- "autoDetect": "false",
- "output": [ "privateFeature" ]
- },
"wayland-vulkan-server-buffer": {
"label": "Vulkan-based server buffer integration",
- "condition": "features.wayland-server && features.opengl && features.egl && tests.vulkan-server-buffer && features.wayland-compositor-texture-sharing-experimental",
+ "condition": "features.wayland-server && features.opengl && features.egl && tests.vulkan-server-buffer",
"output": [ "privateFeature" ]
},
"wayland-shm-emulation-server-buffer": {
diff --git a/src/compositor/extensions/extensions.pri b/src/compositor/extensions/extensions.pri
index d8f0069de..61ab043ea 100644
--- a/src/compositor/extensions/extensions.pri
+++ b/src/compositor/extensions/extensions.pri
@@ -14,7 +14,9 @@ WAYLANDSERVERSOURCES += \
../3rdparty/protocol/xdg-shell-unstable-v6.xml \
../3rdparty/protocol/xdg-shell.xml \
../3rdparty/protocol/xdg-decoration-unstable-v1.xml \
+ ../3rdparty/protocol/xdg-output-unstable-v1.xml \
../3rdparty/protocol/ivi-application.xml \
+ ../3rdparty/protocol/idle-inhibit-unstable-v1.xml \
HEADERS += \
extensions/qwlqttouch_p.h \
@@ -41,7 +43,11 @@ HEADERS += \
extensions/qwaylandxdgshell_p.h \
extensions/qwaylandxdgdecorationv1.h \
extensions/qwaylandxdgdecorationv1_p.h \
+ extensions/qwaylandxdgoutputv1.h \
+ extensions/qwaylandxdgoutputv1_p.h \
extensions/qwaylandshellsurface.h \
+ extensions/qwaylandidleinhibitv1.h \
+ extensions/qwaylandidleinhibitv1_p.h \
extensions/qwaylandiviapplication.h \
extensions/qwaylandiviapplication_p.h \
extensions/qwaylandivisurface.h \
@@ -61,32 +67,43 @@ SOURCES += \
extensions/qwaylandxdgshellv6.cpp \
extensions/qwaylandxdgshell.cpp \
extensions/qwaylandxdgdecorationv1.cpp \
+ extensions/qwaylandxdgoutputv1.cpp \
extensions/qwaylandshellsurface.cpp \
+ extensions/qwaylandidleinhibitv1.cpp \
extensions/qwaylandiviapplication.cpp \
extensions/qwaylandivisurface.cpp \
-qtHaveModule(quick):contains(QT_CONFIG, opengl) {
+qtHaveModule(quick) {
HEADERS += \
+ extensions/qwaylandquickshellintegration.h \
extensions/qwaylandquickshellsurfaceitem.h \
extensions/qwaylandquickshellsurfaceitem_p.h \
extensions/qwaylandivisurfaceintegration_p.h \
extensions/qwaylandwlshellintegration_p.h \
+ extensions/qwaylandquickxdgoutputv1.h \
extensions/qwaylandxdgshellv5integration_p.h \
extensions/qwaylandxdgshellv6integration_p.h \
- extensions/qwaylandxdgshellintegration_p.h
+ extensions/qwaylandxdgshellintegration_p.h \
SOURCES += \
+ extensions/qwaylandquickshellintegration.cpp \
extensions/qwaylandquickshellsurfaceitem.cpp \
extensions/qwaylandivisurfaceintegration.cpp \
extensions/qwaylandwlshellintegration.cpp \
+ extensions/qwaylandquickxdgoutputv1.cpp \
extensions/qwaylandxdgshellv5integration.cpp \
extensions/qwaylandxdgshellv6integration.cpp \
- extensions/qwaylandxdgshellintegration.cpp
+ extensions/qwaylandxdgshellintegration.cpp \
- qtConfig(wayland-compositor-texture-sharing-experimental) {
- HEADERS += extensions/qwltexturesharingextension_p.h
- SOURCES += extensions/qwltexturesharingextension.cpp
- WAYLANDSERVERSOURCES += ../extensions/qt-texture-sharing-unstable-v1.xml
+ qtConfig(opengl) {
+ WAYLANDSERVERSOURCES += \
+ ../extensions/qt-texture-sharing-unstable-v1.xml
+
+ HEADERS += \
+ extensions/qwltexturesharingextension_p.h
+
+ SOURCES += \
+ extensions/qwltexturesharingextension.cpp
}
}
diff --git a/src/compositor/extensions/qwaylandidleinhibitv1.cpp b/src/compositor/extensions/qwaylandidleinhibitv1.cpp
new file mode 100644
index 000000000..b97f58130
--- /dev/null
+++ b/src/compositor/extensions/qwaylandidleinhibitv1.cpp
@@ -0,0 +1,190 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWaylandCompositor/QWaylandCompositor>
+#include <QtWaylandCompositor/private/qwaylandsurface_p.h>
+
+#include "qwaylandidleinhibitv1_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QWaylandIdleInhibitManagerV1
+ \inmodule QtWaylandCompositor
+ \since 5.14
+ \brief Provides an extension that allows to inhibit the idle behavior of the compositor
+ \sa QWaylandSurface::inhibitsIdle
+
+ The QWaylandIdleInhibitV1 extension provides a way for a client to inhibit the idle behavior of
+ the compositor when a specific surface is visually relevant to the user.
+
+ QWaylandIdleInhibitManagerV1 corresponds to the Wayland interface, \c zwp_idle_inhibit_manager_v1.
+
+ Inhibited surfaces have the QWaylandSurface::inhibitsIdle property set to \c true.
+*/
+
+/*!
+ \qmltype IdleInhibitManagerV1
+ \inqmlmodule QtWayland.Compositor
+ \since 5.14
+ \brief Provides an extension that allows to inhibit the idle behavior of the compositor
+ \sa WaylandSurface::inhibitsIdle
+
+ The IdleInhibitManagerV1 extension provides a way for a client to inhibit the idle behavior of
+ the compositor when a specific surface is visually relevant to the user.
+
+ IdleInhibitManagerV1 corresponds to the Wayland interface, \c zwp_idle_inhibit_manager_v1.
+
+ To provide the functionality of the extension in a compositor, create an instance of the
+ IdleInhibitManagerV1 component and add it to the list of extensions supported by the compositor:
+
+ \qml \QtMinorVersion
+ import QtWayland.Compositor 1.\1
+
+ WaylandCompositor {
+ IdleInhibitManagerV1 {
+ // ...
+ }
+ }
+ \endqml
+
+ Inhibited surfaces have the WaylandSurface::inhibitsIdle property set to \c true.
+*/
+
+/*!
+ Constructs a QWaylandIdleInhibitManagerV1 object.
+*/
+QWaylandIdleInhibitManagerV1::QWaylandIdleInhibitManagerV1()
+ : QWaylandCompositorExtensionTemplate<QWaylandIdleInhibitManagerV1>(*new QWaylandIdleInhibitManagerV1Private())
+{
+}
+
+/*!
+ Constructs a QWaylandIdleInhibitManagerV1 object for the provided \a compositor.
+*/
+QWaylandIdleInhibitManagerV1::QWaylandIdleInhibitManagerV1(QWaylandCompositor *compositor)
+ : QWaylandCompositorExtensionTemplate<QWaylandIdleInhibitManagerV1>(compositor, *new QWaylandIdleInhibitManagerV1Private())
+{
+}
+
+/*!
+ Destructs a QWaylandIdleInhibitManagerV1 object.
+*/
+QWaylandIdleInhibitManagerV1::~QWaylandIdleInhibitManagerV1() = default;
+
+/*!
+ Initializes the extension.
+*/
+void QWaylandIdleInhibitManagerV1::initialize()
+{
+ Q_D(QWaylandIdleInhibitManagerV1);
+
+ QWaylandCompositorExtensionTemplate::initialize();
+ QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
+ if (!compositor) {
+ qCWarning(qLcWaylandCompositor) << "Failed to find QWaylandCompositor when initializing QWaylandIdleInhibitManagerV1";
+ return;
+ }
+ d->init(compositor->display(), d->interfaceVersion());
+}
+
+/*!
+ Returns the Wayland interface for the QWaylandIdleInhibitManagerV1.
+*/
+const wl_interface *QWaylandIdleInhibitManagerV1::interface()
+{
+ return QWaylandIdleInhibitManagerV1Private::interface();
+}
+
+
+void QWaylandIdleInhibitManagerV1Private::zwp_idle_inhibit_manager_v1_create_inhibitor(Resource *resource, uint id, wl_resource *surfaceResource)
+{
+ auto *surface = QWaylandSurface::fromResource(surfaceResource);
+ if (!surface) {
+ qCWarning(qLcWaylandCompositor) << "Couldn't find surface requested for creating an inhibitor";
+ wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "invalid wl_surface@%d", wl_resource_get_id(surfaceResource));
+ return;
+ }
+
+ auto *surfacePrivate = QWaylandSurfacePrivate::get(surface);
+ if (!surfacePrivate) {
+ wl_resource_post_no_memory(resource->handle);
+ return;
+ }
+
+ auto *inhibitor = new Inhibitor(surface, resource->client(), id, resource->version());
+ if (!inhibitor) {
+ wl_resource_post_no_memory(resource->handle);
+ return;
+ }
+ surfacePrivate->idleInhibitors.append(inhibitor);
+
+ if (surfacePrivate->idleInhibitors.size() == 1)
+ Q_EMIT surface->inhibitsIdleChanged();
+}
+
+
+QWaylandIdleInhibitManagerV1Private::Inhibitor::Inhibitor(QWaylandSurface *surface,
+ wl_client *client,
+ quint32 id, quint32 version)
+ : QtWaylandServer::zwp_idle_inhibitor_v1(client, id, qMin<quint32>(version, interfaceVersion()))
+ , m_surface(surface)
+{
+ Q_ASSERT(surface);
+}
+
+void QWaylandIdleInhibitManagerV1Private::Inhibitor::zwp_idle_inhibitor_v1_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource);
+ delete this;
+}
+
+void QWaylandIdleInhibitManagerV1Private::Inhibitor::zwp_idle_inhibitor_v1_destroy(Resource *resource)
+{
+ if (m_surface) {
+ auto *surfacePrivate = QWaylandSurfacePrivate::get(m_surface.data());
+ Q_ASSERT(surfacePrivate->idleInhibitors.contains(this));
+ surfacePrivate->idleInhibitors.removeOne(this);
+
+ if (surfacePrivate->idleInhibitors.isEmpty())
+ Q_EMIT m_surface.data()->inhibitsIdleChanged();
+ }
+
+ wl_resource_destroy(resource->handle);
+}
+
+QT_END_NAMESPACE
diff --git a/src/compositor/extensions/qwaylandidleinhibitv1.h b/src/compositor/extensions/qwaylandidleinhibitv1.h
new file mode 100644
index 000000000..53c09d084
--- /dev/null
+++ b/src/compositor/extensions/qwaylandidleinhibitv1.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDIDLEINHIBITV1_H
+#define QWAYLANDIDLEINHIBITV1_H
+
+#include <QtWaylandCompositor/QWaylandCompositorExtension>
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandIdleInhibitManagerV1Private;
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandIdleInhibitManagerV1 : public QWaylandCompositorExtensionTemplate<QWaylandIdleInhibitManagerV1>
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QWaylandIdleInhibitManagerV1)
+public:
+ QWaylandIdleInhibitManagerV1();
+ explicit QWaylandIdleInhibitManagerV1(QWaylandCompositor *compositor);
+ ~QWaylandIdleInhibitManagerV1();
+
+ void initialize() override;
+
+ static const struct wl_interface *interface();
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDIDLEINHIBITV1_H
diff --git a/src/compositor/extensions/qwaylandidleinhibitv1_p.h b/src/compositor/extensions/qwaylandidleinhibitv1_p.h
new file mode 100644
index 000000000..380551804
--- /dev/null
+++ b/src/compositor/extensions/qwaylandidleinhibitv1_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDIDLEINHIBITV1_P_H
+#define QWAYLANDIDLEINHIBITV1_P_H
+
+#include <QtWaylandCompositor/QWaylandSurface>
+#include <QtWaylandCompositor/QWaylandIdleInhibitManagerV1>
+#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h>
+#include <QtWaylandCompositor/private/qwayland-server-idle-inhibit-unstable-v1.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandIdleInhibitManagerV1Private
+ : public QWaylandCompositorExtensionPrivate
+ , public QtWaylandServer::zwp_idle_inhibit_manager_v1
+{
+ Q_DECLARE_PUBLIC(QWaylandIdleInhibitManagerV1)
+public:
+ explicit QWaylandIdleInhibitManagerV1Private() = default;
+
+ class Q_WAYLAND_COMPOSITOR_EXPORT Inhibitor
+ : public QtWaylandServer::zwp_idle_inhibitor_v1
+ {
+ public:
+ explicit Inhibitor(QWaylandSurface *surface, wl_client *client, quint32 id, quint32 version);
+
+ protected:
+ void zwp_idle_inhibitor_v1_destroy_resource(Resource *resource) override;
+ void zwp_idle_inhibitor_v1_destroy(Resource *resource) override;
+
+ private:
+ QPointer<QWaylandSurface> m_surface;
+ };
+
+ static QWaylandIdleInhibitManagerV1Private *get(QWaylandIdleInhibitManagerV1 *manager) { return manager ? manager->d_func() : nullptr; }
+
+protected:
+ void zwp_idle_inhibit_manager_v1_create_inhibitor(Resource *resource, uint32_t id, wl_resource *surfaceResource) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDIDLEINHIBITV1_P_H
diff --git a/src/compositor/extensions/qwaylandqtwindowmanager.cpp b/src/compositor/extensions/qwaylandqtwindowmanager.cpp
index 86678b2e6..c3cf3488b 100644
--- a/src/compositor/extensions/qwaylandqtwindowmanager.cpp
+++ b/src/compositor/extensions/qwaylandqtwindowmanager.cpp
@@ -109,7 +109,8 @@ void QWaylandQtWindowManager::setShowIsFullScreen(bool value)
return;
d->showIsFullScreen = value;
- Q_FOREACH (QWaylandQtWindowManagerPrivate::Resource *resource, d->resourceMap().values()) {
+ const auto resMap = d->resourceMap();
+ for (QWaylandQtWindowManagerPrivate::Resource *resource : resMap) {
d->send_hints(resource->handle, static_cast<int32_t>(d->showIsFullScreen));
}
Q_EMIT showIsFullScreenChanged();
diff --git a/src/compositor/extensions/qwaylandquickshellintegration.cpp b/src/compositor/extensions/qwaylandquickshellintegration.cpp
new file mode 100644
index 000000000..d56d6c22a
--- /dev/null
+++ b/src/compositor/extensions/qwaylandquickshellintegration.cpp
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 "qwaylandquickshellintegration.h"
+
+/*!
+ * \class QWaylandQuickShellIntegration
+ * \inmodule QtWaylandCompositor
+ * \since 5.14
+ * \brief Provides support for shell surface integration with QtQuick
+ *
+ * Shell surface implementations should inherit from this class in order to provide
+ * an integration between the shell surface and QtQuick.
+ *
+ * Shell integration is installed as an event filter for a QWaylandQuickShellSurfaceItem.
+ * Reimplement the event filter method and return \c true when you want to filter the
+ * event out, otherwise return \c false.
+ *
+ * Example:
+ *
+ * \code
+ * class MyShellIntegration : public QWaylandQuickShellIntegration
+ * {
+ * Q_OBJECT
+ * public:
+ * MyShellIntegration(QObject *parent = nullptr);
+ *
+ * protected:
+ * bool eventFilter(QObject *object, QEvent *event) override;
+ * };
+ *
+ * MyShellIntegration::MyShellIntegration(QObject *parent)
+ * : QWaylandQuickShellIntegration(parent)
+ * {
+ * }
+ *
+ * bool MyShellIntegration::eventFilter(QObject *object, QEvent *event)
+ * {
+ * QWaylandQuickShellSurfaceItem *shellSurfaceItem = qobject_cast<QWaylandQuickShellSurfaceItem *>(object);
+ * if (!shellSurfaceItem)
+ * return QWaylandQuickShellIntegration::eventFilter(object, event);
+ *
+ * if (event->type() == QEvent::MouseMove) {
+ * QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
+ * qDebug() << "Mouse moved on" << shellSurfaceItem << "pos:" << mouseEvent->pos();
+ * return true;
+ * }
+ *
+ * return QWaylandQuickShellIntegration::eventFilter(object, event);
+ * }
+ * \endcode
+ *
+ * \sa QWaylandQuickShellSurfaceItem
+ * \sa QObject::eventFilter()
+ */
+
+QWaylandQuickShellIntegration::QWaylandQuickShellIntegration(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QWaylandQuickShellIntegration::~QWaylandQuickShellIntegration()
+{
+}
diff --git a/src/compositor/extensions/qwaylandquickshellintegration.h b/src/compositor/extensions/qwaylandquickshellintegration.h
new file mode 100644
index 000000000..00696681b
--- /dev/null
+++ b/src/compositor/extensions/qwaylandquickshellintegration.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 QWAYLANDQUICKSHELLINTEGRATION_H
+#define QWAYLANDQUICKSHELLINTEGRATION_H
+
+#include <QtCore/QObject>
+#include <QtWaylandCompositor/qtwaylandcompositorglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandQuickShellIntegration : public QObject
+{
+ Q_OBJECT
+public:
+ QWaylandQuickShellIntegration(QObject *parent = nullptr);
+ ~QWaylandQuickShellIntegration() override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDQUICKSHELLINTEGRATION_H
diff --git a/src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp b/src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp
index 84e9c356d..bda536017 100644
--- a/src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp
+++ b/src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp
@@ -96,7 +96,11 @@ QWaylandQuickShellSurfaceItem::QWaylandQuickShellSurfaceItem(QQuickItem *parent)
QWaylandQuickShellSurfaceItem::~QWaylandQuickShellSurfaceItem()
{
Q_D(QWaylandQuickShellSurfaceItem);
- delete d->m_shellIntegration;
+
+ if (d->m_shellIntegration) {
+ removeEventFilter(d->m_shellIntegration);
+ delete d->m_shellIntegration;
+ }
}
/*!
@@ -137,12 +141,15 @@ void QWaylandQuickShellSurfaceItem::setShellSurface(QWaylandShellSurface *shellS
d->m_shellSurface = shellSurface;
if (d->m_shellIntegration) {
+ removeEventFilter(d->m_shellIntegration);
delete d->m_shellIntegration;
d->m_shellIntegration = nullptr;
}
- if (shellSurface)
+ if (shellSurface) {
d->m_shellIntegration = shellSurface->createIntegration(this);
+ installEventFilter(d->m_shellIntegration);
+ }
emit shellSurfaceChanged();
}
@@ -208,20 +215,6 @@ void QWaylandQuickShellSurfaceItem::setAutoCreatePopupItems(bool enabled)
emit autoCreatePopupItemsChanged();
}
-void QWaylandQuickShellSurfaceItem::mouseMoveEvent(QMouseEvent *event)
-{
- Q_D(QWaylandQuickShellSurfaceItem);
- if (!d->m_shellIntegration->mouseMoveEvent(event))
- QWaylandQuickItem::mouseMoveEvent(event);
-}
-
-void QWaylandQuickShellSurfaceItem::mouseReleaseEvent(QMouseEvent *event)
-{
- Q_D(QWaylandQuickShellSurfaceItem);
- if (!d->m_shellIntegration->mouseReleaseEvent(event))
- QWaylandQuickItem::mouseReleaseEvent(event);
-}
-
/*!
\class QWaylandQuickShellEventFilter
\brief QWaylandQuickShellEventFilter implements a Wayland popup grab
diff --git a/src/compositor/extensions/qwaylandquickshellsurfaceitem.h b/src/compositor/extensions/qwaylandquickshellsurfaceitem.h
index d14fa3fce..51c0425e6 100644
--- a/src/compositor/extensions/qwaylandquickshellsurfaceitem.h
+++ b/src/compositor/extensions/qwaylandquickshellsurfaceitem.h
@@ -75,9 +75,6 @@ Q_SIGNALS:
protected:
QWaylandQuickShellSurfaceItem(QWaylandQuickShellSurfaceItemPrivate &dd, QQuickItem *parent);
-
- void mouseMoveEvent(QMouseEvent *event) override;
- void mouseReleaseEvent(QMouseEvent *event) override;
};
QT_END_NAMESPACE
diff --git a/src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h b/src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h
index 7a458381e..f622368ab 100644
--- a/src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h
+++ b/src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h
@@ -41,6 +41,7 @@
#define QWAYLANDQUICKSHELLSURFACEITEM_P_H
#include <QtWaylandCompositor/QWaylandQuickShellSurfaceItem>
+#include <QtWaylandCompositor/QWaylandQuickShellIntegration>
#include <QtWaylandCompositor/private/qwaylandquickitem_p.h>
#include <QtCore/QBasicTimer>
@@ -59,7 +60,6 @@ QT_BEGIN_NAMESPACE
// We mean it.
//
-class QWaylandQuickShellIntegration;
class QWaylandShellSurface;
class QWaylandQuickShellSurfaceItem;
@@ -74,16 +74,13 @@ public:
QWaylandQuickShellIntegration *m_shellIntegration = nullptr;
QWaylandShellSurface *m_shellSurface = nullptr;
QQuickItem *m_moveItem = nullptr;
- bool m_autoCreatePopupItems = false;
-};
+ bool m_autoCreatePopupItems =
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ true;
+#else
+ false;
+#endif
-class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandQuickShellIntegration : public QObject
-{
- Q_OBJECT
-public:
- QWaylandQuickShellIntegration(QObject *parent = nullptr) : QObject(parent) {}
- virtual bool mouseMoveEvent(QMouseEvent *) { return false; }
- virtual bool mouseReleaseEvent(QMouseEvent *) { return false; }
};
class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandQuickShellEventFilter : public QObject
diff --git a/src/compositor/extensions/qwaylandquickxdgoutputv1.cpp b/src/compositor/extensions/qwaylandquickxdgoutputv1.cpp
new file mode 100644
index 000000000..eb6717a78
--- /dev/null
+++ b/src/compositor/extensions/qwaylandquickxdgoutputv1.cpp
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QWaylandCompositor>
+#include <QWaylandOutput>
+
+#include "qwaylandquickxdgoutputv1.h"
+#include "qwaylandxdgoutputv1_p.h"
+
+QWaylandQuickXdgOutputV1::QWaylandQuickXdgOutputV1()
+ : QWaylandXdgOutputV1()
+{
+}
+
+void QWaylandQuickXdgOutputV1::componentComplete()
+{
+ // Try to find the manager from the compositor extensions
+ if (!manager()) {
+ for (auto *p = parent(); p != nullptr; p = p->parent()) {
+ if (auto *c = qobject_cast<QWaylandCompositor *>(p)) {
+ for (auto *extension : c->extensions()) {
+ if (auto *m = qobject_cast<QWaylandXdgOutputManagerV1 *>(extension)) {
+ QWaylandXdgOutputV1Private::get(this)->setManager(m);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Try to find the output from the parents
+ if (!output()) {
+ for (auto *p = parent(); p != nullptr; p = p->parent()) {
+ if (auto *o = qobject_cast<QWaylandOutput *>(p)) {
+ QWaylandXdgOutputV1Private::get(this)->setOutput(o);
+ break;
+ }
+ }
+ }
+}
diff --git a/src/compositor/extensions/qwaylandquickxdgoutputv1.h b/src/compositor/extensions/qwaylandquickxdgoutputv1.h
new file mode 100644
index 000000000..c8b16ab8e
--- /dev/null
+++ b/src/compositor/extensions/qwaylandquickxdgoutputv1.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDQUICKXDGOUTPUT_V1
+#define QWAYLANDQUICKXDGOUTPUT_V1
+
+#include <QtQml/QQmlListProperty>
+#include <QtQml/QQmlParserStatus>
+#include <QtWaylandCompositor/QWaylandXdgOutputV1>
+
+QT_BEGIN_NAMESPACE
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandQuickXdgOutputV1
+ : public QWaylandXdgOutputV1
+ , public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+public:
+ explicit QWaylandQuickXdgOutputV1();
+
+protected:
+ void classBegin() override {}
+ void componentComplete() override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDQUICKXDGOUTPUT_V1
diff --git a/src/compositor/extensions/qwaylandtextinput.cpp b/src/compositor/extensions/qwaylandtextinput.cpp
index f60a32a14..b46caa641 100644
--- a/src/compositor/extensions/qwaylandtextinput.cpp
+++ b/src/compositor/extensions/qwaylandtextinput.cpp
@@ -162,7 +162,7 @@ void QWaylandTextInputPrivate::sendInputMethodEvent(QInputMethodEvent *event)
afterCommit.cursorPosition += event->commitString().length();
afterCommit.anchorPosition = afterCommit.cursorPosition;
- foreach (const QInputMethodEvent::Attribute &attribute, event->attributes()) {
+ for (const QInputMethodEvent::Attribute &attribute : event->attributes()) {
if (attribute.type == QInputMethodEvent::Selection) {
afterCommit.cursorPosition = attribute.start;
afterCommit.anchorPosition = attribute.length;
@@ -174,7 +174,7 @@ void QWaylandTextInputPrivate::sendInputMethodEvent(QInputMethodEvent *event)
}
}
send_commit_string(focusResource->handle, event->commitString());
- foreach (const QInputMethodEvent::Attribute &attribute, event->attributes()) {
+ for (const QInputMethodEvent::Attribute &attribute : event->attributes()) {
if (attribute.type == QInputMethodEvent::Cursor) {
int index = QWaylandInputMethodEventBuilder::indexToWayland(event->preeditString(), attribute.start);
send_preedit_cursor(focusResource->handle, index);
diff --git a/src/compositor/extensions/qwaylandwlscaler_p.h b/src/compositor/extensions/qwaylandwlscaler_p.h
index d3c2edd76..10a66f884 100644
--- a/src/compositor/extensions/qwaylandwlscaler_p.h
+++ b/src/compositor/extensions/qwaylandwlscaler_p.h
@@ -55,6 +55,7 @@
QT_BEGIN_NAMESPACE
+#if QT_DEPRECATED_SINCE(5, 13)
class QWaylandSurface;
class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandWlScalerPrivate
@@ -87,6 +88,7 @@ private:
QPointer<QWaylandSurface> m_surface = nullptr;
};
};
+#endif
QT_END_NAMESPACE
diff --git a/src/compositor/extensions/qwaylandwlshell.cpp b/src/compositor/extensions/qwaylandwlshell.cpp
index 66aeb64ba..ea228cab2 100644
--- a/src/compositor/extensions/qwaylandwlshell.cpp
+++ b/src/compositor/extensions/qwaylandwlshell.cpp
@@ -332,7 +332,7 @@ QList<QWaylandWlShellSurface *> QWaylandWlShell::shellSurfacesForClient(QWayland
{
Q_D(const QWaylandWlShell);
QList<QWaylandWlShellSurface *> surfsForClient;
- Q_FOREACH (QWaylandWlShellSurface *shellSurface, d->m_shellSurfaces) {
+ for (QWaylandWlShellSurface *shellSurface : d->m_shellSurfaces) {
if (shellSurface->surface() && shellSurface->surface()->client() == client)
surfsForClient.append(shellSurface);
}
@@ -343,7 +343,7 @@ QList<QWaylandWlShellSurface *> QWaylandWlShell::mappedPopups() const
{
Q_D(const QWaylandWlShell);
QList<QWaylandWlShellSurface *> popupSurfaces;
- Q_FOREACH (QWaylandWlShellSurface *shellSurface, d->m_shellSurfaces) {
+ for (QWaylandWlShellSurface *shellSurface : d->m_shellSurfaces) {
if (shellSurface->windowType() == Qt::WindowType::Popup
&& shellSurface->surface() && shellSurface->surface()->hasContent()) {
popupSurfaces.append(shellSurface);
@@ -355,7 +355,7 @@ QList<QWaylandWlShellSurface *> QWaylandWlShell::mappedPopups() const
QWaylandClient *QWaylandWlShell::popupClient() const
{
Q_D(const QWaylandWlShell);
- Q_FOREACH (QWaylandWlShellSurface *shellSurface, d->m_shellSurfaces) {
+ for (QWaylandWlShellSurface *shellSurface : d->m_shellSurfaces) {
if (shellSurface->windowType() == Qt::WindowType::Popup
&& shellSurface->surface() && shellSurface->surface()->hasContent()) {
return shellSurface->surface()->client();
@@ -366,7 +366,8 @@ QWaylandClient *QWaylandWlShell::popupClient() const
void QWaylandWlShell::closeAllPopups()
{
- Q_FOREACH (QWaylandWlShellSurface* shellSurface, mappedPopups())
+ const auto mapped = mappedPopups();
+ for (QWaylandWlShellSurface *shellSurface : mapped)
shellSurface->sendPopupDone();
}
diff --git a/src/compositor/extensions/qwaylandwlshellintegration.cpp b/src/compositor/extensions/qwaylandwlshellintegration.cpp
index 99a2e7655..724580e24 100644
--- a/src/compositor/extensions/qwaylandwlshellintegration.cpp
+++ b/src/compositor/extensions/qwaylandwlshellintegration.cpp
@@ -198,7 +198,8 @@ void WlShellIntegration::handleSetPopup(QWaylandSeat *seat, QWaylandSurface *par
// Find the parent item on the same output
QWaylandQuickShellSurfaceItem *parentItem = nullptr;
- Q_FOREACH (QWaylandView *view, parent->views()) {
+ const auto views = parent->views();
+ for (QWaylandView *view : views) {
if (view->output() == m_item->view()->output()) {
QWaylandQuickShellSurfaceItem *item = qobject_cast<QWaylandQuickShellSurfaceItem*>(view->renderObject());
if (item) {
@@ -288,7 +289,19 @@ void WlShellIntegration::adjustOffsetForNextFrame(const QPointF &offset)
moveItem->setPosition(moveItem->position() + m_item->mapFromSurface(offset));
}
-bool WlShellIntegration::mouseMoveEvent(QMouseEvent *event)
+bool WlShellIntegration::eventFilter(QObject *object, QEvent *event)
+{
+ if (event->type() == QEvent::MouseMove) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
+ return filterMouseMoveEvent(mouseEvent);
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
+ return filterMouseReleaseEvent(mouseEvent);
+ }
+ return QWaylandQuickShellIntegration::eventFilter(object, event);
+}
+
+bool WlShellIntegration::filterMouseMoveEvent(QMouseEvent *event)
{
if (grabberState == GrabberState::Resize) {
Q_ASSERT(resizeState.seat == m_item->compositor()->seatFor(event));
@@ -317,7 +330,7 @@ bool WlShellIntegration::mouseMoveEvent(QMouseEvent *event)
return false;
}
-bool WlShellIntegration::mouseReleaseEvent(QMouseEvent *event)
+bool WlShellIntegration::filterMouseReleaseEvent(QMouseEvent *event)
{
Q_UNUSED(event);
if (grabberState != GrabberState::Default) {
diff --git a/src/compositor/extensions/qwaylandwlshellintegration_p.h b/src/compositor/extensions/qwaylandwlshellintegration_p.h
index 8af54dfc4..eb23a62fc 100644
--- a/src/compositor/extensions/qwaylandwlshellintegration_p.h
+++ b/src/compositor/extensions/qwaylandwlshellintegration_p.h
@@ -65,8 +65,9 @@ class WlShellIntegration : public QWaylandQuickShellIntegration
public:
WlShellIntegration(QWaylandQuickShellSurfaceItem *item);
~WlShellIntegration() override;
- bool mouseMoveEvent(QMouseEvent *event) override;
- bool mouseReleaseEvent(QMouseEvent *event) override;
+
+protected:
+ bool eventFilter(QObject *object, QEvent *event) override;
private Q_SLOTS:
void handleStartMove(QWaylandSeat *seat);
@@ -130,6 +131,9 @@ private:
QPointF normalPosition;
QPointF finalPosition;
+
+ bool filterMouseMoveEvent(QMouseEvent *event);
+ bool filterMouseReleaseEvent(QMouseEvent *event);
};
}
diff --git a/src/compositor/extensions/qwaylandxdgoutputv1.cpp b/src/compositor/extensions/qwaylandxdgoutputv1.cpp
new file mode 100644
index 000000000..2ab26c162
--- /dev/null
+++ b/src/compositor/extensions/qwaylandxdgoutputv1.cpp
@@ -0,0 +1,595 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QWaylandCompositor>
+
+#include "qwaylandxdgoutputv1_p.h"
+#include "qwaylandoutput_p.h"
+
+#include <wayland-server.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ * \qmltype XdgOutputManagerV1
+ * \inqmlmodule QtWayland.Compositor
+ * \since 5.14
+ * \brief Provides an extension for describing outputs in a desktop oriented fashion
+ *
+ * The XdgOutputManagerV1 extension provides a way for a compositor to describe outputs in a way
+ * that is more in line with the concept of an output on desktop oriented systems.
+ *
+ * Some information may not make sense in other applications such as IVI systems.
+ *
+ * Typically the global compositor space on a desktop system is made of a
+ * contiguous or overlapping set of rectangular regions.
+ *
+ * XdgOutputManagerV1 corresponds to the Wayland interface, \c zxdg_output_manager_v1.
+ *
+ * To provide the functionality of the extension in a compositor, create an instance of the
+ * XdgOutputManagerV1 component and add it to the list of extensions supported by the compositor,
+ * and associated each XdgOutputV1 with its WaylandOutput:
+ *
+ * \qml \QtMinorVersion
+ * import QtWayland.Compositor 1.\1
+ *
+ * WaylandCompositor {
+ * XdgOutputManagerV1 {
+ * WaylandOutput {
+ * id: output1
+ *
+ * position: Qt.point(0, 0)
+ * window: Window {}
+ *
+ * XdgOutputV1 {
+ * name: "WL-1"
+ * logicalPosition: output1.position
+ * logicalSize: Qt.size(output1.geometry.width / output1.scaleFactor,
+ * output1.geometry.height / output1.scaleFactor)
+ * }
+ * }
+ *
+ * WaylandOutput {
+ * id: output2
+ *
+ * position: Qt.point(800, 0)
+ * window: Window {}
+ *
+ * XdgOutputV1 {
+ * name: "WL-2"
+ * logicalPosition: output2.position
+ * logicalSize: Qt.size(output2.geometry.width / output2.scaleFactor,
+ * output2.geometry.height / output2.scaleFactor)
+ * }
+ * }
+ * }
+ * }
+ * \endqml
+ */
+
+/*!
+ * \class QWaylandXdgOutputManagerV1
+ * \inmodule QtWaylandCompositor
+ * \since 5.14
+ * \brief Provides an extension for describing outputs in a desktop oriented fashion
+ *
+ * The QWaylandXdgOutputManagerV1 extension provides a way for a compositor to describe outputs in a way
+ * that is more in line with the concept of an output on desktop oriented systems.
+ *
+ * Some information may not make sense in other applications such as IVI systems.
+ *
+ * QWaylandXdgOutputManagerV1 corresponds to the Wayland interface, \c zxdg_output_manager_v1.
+ */
+
+/*!
+ * Constructs a QWaylandXdgOutputManagerV1 object.
+ */
+QWaylandXdgOutputManagerV1::QWaylandXdgOutputManagerV1()
+ : QWaylandCompositorExtensionTemplate<QWaylandXdgOutputManagerV1>(*new QWaylandXdgOutputManagerV1Private())
+{
+}
+
+/*!
+ * Constructs a QWaylandXdgOutputManagerV1 object for the provided \a compositor.
+ */
+QWaylandXdgOutputManagerV1::QWaylandXdgOutputManagerV1(QWaylandCompositor *compositor)
+ : QWaylandCompositorExtensionTemplate<QWaylandXdgOutputManagerV1>(compositor, *new QWaylandXdgOutputManagerV1Private())
+{
+}
+
+// QWaylandXdgOutputManagerV1Private
+
+/*!
+ * Initializes the extension.
+ */
+void QWaylandXdgOutputManagerV1::initialize()
+{
+ Q_D(QWaylandXdgOutputManagerV1);
+
+ QWaylandCompositorExtensionTemplate::initialize();
+ QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
+ if (!compositor) {
+ qCWarning(qLcWaylandCompositor) << "Failed to find QWaylandCompositor when initializing QWaylandXdgOutputManagerV1";
+ return;
+ }
+ d->init(compositor->display(), d->interfaceVersion());
+}
+
+/*!
+ * Returns the Wayland interface for QWaylandXdgOutputManagerV1.
+ */
+const wl_interface *QWaylandXdgOutputManagerV1::interface()
+{
+ return QWaylandXdgOutputManagerV1Private::interface();
+}
+
+// QWaylandXdgOutputManagerV1Private
+
+void QWaylandXdgOutputManagerV1Private::registerXdgOutput(QWaylandOutput *output, QWaylandXdgOutputV1 *xdgOutput)
+{
+ if (!xdgOutputs.contains(output)) {
+ xdgOutputs[output] = xdgOutput;
+ QWaylandOutputPrivate::get(output)->xdgOutput = xdgOutput;
+ }
+}
+
+void QWaylandXdgOutputManagerV1Private::unregisterXdgOutput(QWaylandOutput *output)
+{
+ xdgOutputs.remove(output);
+}
+
+void QWaylandXdgOutputManagerV1Private::zxdg_output_manager_v1_get_xdg_output(Resource *resource,
+ uint32_t id,
+ wl_resource *outputResource)
+{
+ Q_Q(QWaylandXdgOutputManagerV1);
+
+ // Verify if the associated output exist
+ auto *output = QWaylandOutput::fromResource(outputResource);
+ if (!output) {
+ qCWarning(qLcWaylandCompositor,
+ "The client is requesting a QWaylandXdgOutputV1 for a "
+ "QWaylandOutput that doesn't exist");
+ wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "output not found");
+ return;
+ }
+
+ // Do we have a QWaylandXdgOutputV1 for this output?
+ if (!xdgOutputs.contains(output)) {
+ qCWarning(qLcWaylandCompositor,
+ "The client is requesting a QWaylandXdgOutputV1 that the compositor "
+ "didn't create before");
+ wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "compositor didn't create a QWaylandXdgOutputV1 for this zxdg_output_v1 object");
+ return;
+ }
+
+ // Bind QWaylandXdgOutputV1 and initialize
+ auto *xdgOutput = xdgOutputs[output];
+ auto *xdgOutputPrivate = QWaylandXdgOutputV1Private::get(xdgOutput);
+ Q_ASSERT(xdgOutputPrivate);
+ xdgOutputPrivate->setManager(q);
+ xdgOutputPrivate->setOutput(output);
+ xdgOutputPrivate->add(resource->client(), id, qMin(resource->version(), QWaylandXdgOutputV1Private::interfaceVersion()));
+}
+
+// QWaylandXdgOutputV1
+
+QWaylandXdgOutputV1::QWaylandXdgOutputV1()
+ : QObject(*new QWaylandXdgOutputV1Private)
+{
+}
+
+QWaylandXdgOutputV1::QWaylandXdgOutputV1(QWaylandOutput *output, QWaylandXdgOutputManagerV1 *manager)
+ : QObject(*new QWaylandXdgOutputV1Private)
+{
+ Q_D(QWaylandXdgOutputV1);
+
+ // Set members before emitting changed signals so that handlers will
+ // see both already set and not nullptr, avoiding potential crashes
+ d->manager = manager;
+ d->output = output;
+
+ QWaylandXdgOutputManagerV1Private::get(d->manager)->registerXdgOutput(output, this);
+
+ emit managerChanged();
+ emit outputChanged();
+}
+
+QWaylandXdgOutputV1::~QWaylandXdgOutputV1()
+{
+ Q_D(QWaylandXdgOutputV1);
+
+ if (d->manager)
+ QWaylandXdgOutputManagerV1Private::get(d->manager)->unregisterXdgOutput(d->output);
+}
+
+/*!
+ * \qmlproperty XdgOutputManagerV1 QtWaylandCompositor::XdgOutputV1::manager
+ * \readonly
+ *
+ * This property holds the object that manages this XdgOutputV1.
+ */
+/*!
+ * \property QWaylandXdgOutputV1::manager
+ * \readonly
+ *
+ * This property holds the object that manages this QWaylandXdgOutputV1.
+ */
+QWaylandXdgOutputManagerV1 *QWaylandXdgOutputV1::manager() const
+{
+ Q_D(const QWaylandXdgOutputV1);
+ return d->manager;
+}
+
+/*!
+ * \qmlproperty WaylandOutput QtWaylandCompositor::XdgOutputV1::output
+ * \readonly
+ *
+ * This property holds the WaylandOutput associated with this XdgOutputV1.
+ */
+/*!
+ * \property QWaylandXdgOutputV1::output
+ * \readonly
+ *
+ * This property holds the QWaylandOutput associated with this QWaylandXdgOutputV1.
+ */
+QWaylandOutput *QWaylandXdgOutputV1::output() const
+{
+ Q_D(const QWaylandXdgOutputV1);
+ return d->output;
+}
+
+/*!
+ * \qmlproperty string QtWaylandCompositor::XdgOutputV1::name
+ *
+ * This property holds the name of this output.
+ *
+ * The naming convention is compositor defined, but limited to alphanumeric
+ * characters and dashes ("-"). Each name is unique and will also remain
+ * consistent across sessions with the same hardware and software configuration.
+ *
+ * Examples of names include "HDMI-A-1", "WL-1", "X11-1" etc...
+ * However don't assume the name reflects the underlying technology.
+ *
+ * Changing this property after initialization doesn't take effect.
+ */
+/*!
+ * \property QWaylandXdgOutputV1::name
+ *
+ * This property holds the name of this output.
+ *
+ * The naming convention is compositor defined, but limited to alphanumeric
+ * characters and dashes ("-"). Each name is unique and will also remain
+ * consistent across sessions with the same hardware and software configuration.
+ *
+ * Examples of names include "HDMI-A-1", "WL-1", "X11-1" etc...
+ * However don't assume the name reflects the underlying technology.
+ *
+ * Changing this property after initialization doesn't take effect.
+ */
+QString QWaylandXdgOutputV1::name() const
+{
+ Q_D(const QWaylandXdgOutputV1);
+ return d->name;
+}
+
+void QWaylandXdgOutputV1::setName(const QString &name)
+{
+ Q_D(QWaylandXdgOutputV1);
+
+ if (d->name == name)
+ return;
+
+ // Can't change after clients bound to xdg-output
+ if (d->initialized) {
+ qCWarning(qLcWaylandCompositor, "QWaylandXdgOutputV1::name cannot be changed after initialization");
+ return;
+ }
+
+ d->name = name;
+ emit nameChanged();
+}
+
+/*!
+ * \qmlproperty string QtWaylandCompositor::XdgOutputV1::description
+ *
+ * This property holds the description of this output.
+ *
+ * No convention is defined for the description.
+ *
+ * Changing this property after initialization doesn't take effect.
+ */
+/*!
+ * \property QWaylandXdgOutputV1::description
+ *
+ * This property holds the description of this output.
+ *
+ * No convention is defined for the description.
+ *
+ * Changing this property after initialization doesn't take effect.
+ */
+QString QWaylandXdgOutputV1::description() const
+{
+ Q_D(const QWaylandXdgOutputV1);
+ return d->description;
+}
+
+void QWaylandXdgOutputV1::setDescription(const QString &description)
+{
+ Q_D(QWaylandXdgOutputV1);
+
+ if (d->description == description)
+ return;
+
+ // Can't change after clients bound to xdg-output
+ if (d->initialized) {
+ qCWarning(qLcWaylandCompositor, "QWaylandXdgOutputV1::description cannot be changed after initialization");
+ return;
+ }
+
+ d->description = description;
+ emit descriptionChanged();
+}
+
+/*!
+ * \qmlproperty point QtWaylandCompositor::XdgOutputV1::logicalPosition
+ *
+ * This property holds the coordinates of the output within the global compositor space.
+ *
+ * The default value is 0,0.
+ */
+/*!
+ * \property QWaylandXdgOutputV1::logicalPosition
+ *
+ * This property holds the coordinates of the output within the global compositor space.
+ *
+ * The default value is 0,0.
+ */
+QPoint QWaylandXdgOutputV1::logicalPosition() const
+{
+ Q_D(const QWaylandXdgOutputV1);
+ return d->logicalPos;
+}
+
+void QWaylandXdgOutputV1::setLogicalPosition(const QPoint &position)
+{
+ Q_D(QWaylandXdgOutputV1);
+
+ if (d->logicalPos == position)
+ return;
+
+ d->logicalPos = position;
+ if (d->initialized) {
+ d->sendLogicalPosition(position);
+ d->sendDone();
+ }
+ emit logicalPositionChanged();
+ emit logicalGeometryChanged();
+}
+
+/*!
+ * \qmlproperty size QtWaylandCompositor::XdgOutputV1::logicalSize
+ *
+ * This property holds the size of the output in the global compositor space.
+ *
+ * The default value is -1,-1 which is invalid.
+ *
+ * Please remember that this is the logical size, not the physical size.
+ * For example, for a WaylandOutput mode 3840x2160 and a scale factor 2:
+ * \list
+ * \li A compositor not scaling the surface buffers, will report a logical size of 3840x2160.
+ * \li A compositor automatically scaling the surface buffers, will report a logical size of 1920x1080.
+ * \li A compositor using a fractional scale of 1.5, will report a logical size of 2560x1620.
+ * \endlist
+ */
+/*!
+ * \property QWaylandXdgOutputV1::logicalSize
+ *
+ * This property holds the size of the output in the global compositor space.
+ *
+ * The default value is -1,-1 which is invalid.
+ *
+ * Please remember that this is the logical size, not the physical size.
+ * For example, for a WaylandOutput mode 3840x2160 and a scale factor 2:
+ * \list
+ * \li A compositor not scaling the surface buffers, will report a logical size of 3840x2160.
+ * \li A compositor automatically scaling the surface buffers, will report a logical size of 1920x1080.
+ * \li A compositor using a fractional scale of 1.5, will report a logical size of 2560x1620.
+ * \endlist
+ */
+QSize QWaylandXdgOutputV1::logicalSize() const
+{
+ Q_D(const QWaylandXdgOutputV1);
+ return d->logicalSize;
+}
+
+void QWaylandXdgOutputV1::setLogicalSize(const QSize &size)
+{
+ Q_D(QWaylandXdgOutputV1);
+
+ if (d->logicalSize == size)
+ return;
+
+ d->logicalSize = size;
+ if (d->initialized) {
+ d->sendLogicalSize(size);
+ d->sendDone();
+ }
+ emit logicalSizeChanged();
+ emit logicalGeometryChanged();
+}
+
+/*!
+ * \qmlproperty rect QtWaylandCompositor::XdgOutputV1::logicalGeometry
+ * \readonly
+ *
+ * This property holds the position and size of the output in the global compositor space.
+ * It's the combination of the logical position and logical size.
+ *
+ * \sa XdgOutputV1::logicalPosition
+ * \sa XdgOutputV1::logicalSize
+ */
+/*!
+ * \property QWaylandXdgOutputV1::logicalGeometry
+ * \readonly
+ *
+ * This property holds the position and size of the output in the global compositor space.
+ * It's the combination of the logical position and logical size.
+ *
+ * \sa QWaylandXdgOutputV1::logicalPosition
+ * \sa QWaylandXdgOutputV1::logicalSize
+ */
+QRect QWaylandXdgOutputV1::logicalGeometry() const
+{
+ Q_D(const QWaylandXdgOutputV1);
+ return QRect(d->logicalPos, d->logicalSize);
+}
+
+// QWaylandXdgOutputV1Private
+
+void QWaylandXdgOutputV1Private::sendLogicalPosition(const QPoint &position)
+{
+ const auto values = resourceMap().values();
+ for (auto *resource : values)
+ send_logical_position(resource->handle, position.x(), position.y());
+ needToSendDone = true;
+}
+
+void QWaylandXdgOutputV1Private::sendLogicalSize(const QSize &size)
+{
+ const auto values = resourceMap().values();
+ for (auto *resource : values)
+ send_logical_size(resource->handle, size.width(), size.height());
+ needToSendDone = true;
+}
+
+void QWaylandXdgOutputV1Private::sendDone()
+{
+ if (needToSendDone) {
+ const auto values = resourceMap().values();
+ for (auto *resource : values) {
+ if (resource->version() < 3)
+ send_done(resource->handle);
+ }
+ needToSendDone = false;
+ }
+}
+
+void QWaylandXdgOutputV1Private::setManager(QWaylandXdgOutputManagerV1 *_manager)
+{
+ Q_Q(QWaylandXdgOutputV1);
+
+ if (!_manager) {
+ qCWarning(qLcWaylandCompositor,
+ "Cannot associate a null QWaylandXdgOutputManagerV1 to QWaylandXdgOutputV1 %p", this);
+ return;
+ }
+
+ if (manager == _manager)
+ return;
+
+ if (manager) {
+ qCWarning(qLcWaylandCompositor,
+ "Cannot associate a different QWaylandXdgOutputManagerV1 to QWaylandXdgOutputV1 %p "
+ "after initialization", this);
+ return;
+ }
+
+ manager = _manager;
+ emit q->managerChanged();
+}
+
+void QWaylandXdgOutputV1Private::setOutput(QWaylandOutput *_output)
+{
+ Q_Q(QWaylandXdgOutputV1);
+
+ if (!_output) {
+ qCWarning(qLcWaylandCompositor,
+ "Cannot associate a null QWaylandOutput to QWaylandXdgOutputV1 %p", this);
+ return;
+ }
+
+ if (output == _output)
+ return;
+
+ if (output) {
+ qCWarning(qLcWaylandCompositor,
+ "Cannot associate a different QWaylandOutput to QWaylandXdgOutputV1 %p "
+ "after initialization", this);
+ return;
+ }
+
+ // Assign output above manager, to make both values valid in handlers
+ output = _output;
+
+ if (!manager) {
+ // Try to find the manager from the output parents
+ for (auto *p = output->parent(); p != nullptr; p = p->parent()) {
+ if (auto *m = qobject_cast<QWaylandXdgOutputManagerV1 *>(p)) {
+ manager = m;
+ emit q->managerChanged();
+ break;
+ }
+ }
+ }
+
+ emit q->outputChanged();
+
+ // Register the output
+ if (manager)
+ QWaylandXdgOutputManagerV1Private::get(manager)->registerXdgOutput(output, q);
+}
+
+void QWaylandXdgOutputV1Private::zxdg_output_v1_bind_resource(Resource *resource)
+{
+ send_logical_position(resource->handle, logicalPos.x(), logicalPos.y());
+ send_logical_size(resource->handle, logicalSize.width(), logicalSize.height());
+ if (resource->version() >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION)
+ send_name(resource->handle, name);
+ if (resource->version() >= ZXDG_OUTPUT_V1_DESCRIPTION_SINCE_VERSION)
+ send_description(resource->handle, description);
+ send_done(resource->handle);
+
+ initialized = true;
+}
+
+void QWaylandXdgOutputV1Private::zxdg_output_v1_destroy(Resource *resource)
+{
+ wl_resource_destroy(resource->handle);
+}
+
+QT_END_NAMESPACE
diff --git a/src/compositor/extensions/qwaylandxdgoutputv1.h b/src/compositor/extensions/qwaylandxdgoutputv1.h
new file mode 100644
index 000000000..957ac3bed
--- /dev/null
+++ b/src/compositor/extensions/qwaylandxdgoutputv1.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDXDGOUTPUTV1_H
+#define QWAYLANDXDGOUTPUTV1_H
+
+#include <QRect>
+#include <QtWaylandCompositor/QWaylandCompositorExtension>
+#include <QtWaylandCompositor/qwaylandquickchildren.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandOutput;
+
+class QWaylandXdgOutputManagerV1Private;
+class QWaylandXdgOutputV1Private;
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgOutputManagerV1
+ : public QWaylandCompositorExtensionTemplate<QWaylandXdgOutputManagerV1>
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QWaylandXdgOutputManagerV1)
+public:
+ explicit QWaylandXdgOutputManagerV1();
+ QWaylandXdgOutputManagerV1(QWaylandCompositor *compositor);
+
+ void initialize() override;
+
+ static const wl_interface *interface();
+};
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgOutputV1 : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QWaylandXdgOutputV1)
+ Q_WAYLAND_COMPOSITOR_DECLARE_QUICK_CHILDREN(QWaylandXdgOutputV1)
+ Q_PROPERTY(QWaylandXdgOutputManagerV1 *manager READ manager NOTIFY managerChanged)
+ Q_PROPERTY(QWaylandOutput *output READ output NOTIFY outputChanged)
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged)
+ Q_PROPERTY(QPoint logicalPosition READ logicalPosition WRITE setLogicalPosition NOTIFY logicalPositionChanged)
+ Q_PROPERTY(QSize logicalSize READ logicalSize WRITE setLogicalSize NOTIFY logicalSizeChanged)
+ Q_PROPERTY(QRect logicalGeometry READ logicalGeometry NOTIFY logicalGeometryChanged)
+public:
+ QWaylandXdgOutputV1();
+ QWaylandXdgOutputV1(QWaylandOutput *output, QWaylandXdgOutputManagerV1 *manager);
+ ~QWaylandXdgOutputV1() override;
+
+ QWaylandXdgOutputManagerV1 *manager() const;
+ QWaylandOutput *output() const;
+
+ QString name() const;
+ void setName(const QString &name);
+
+ QString description() const;
+ void setDescription(const QString &name);
+
+ QPoint logicalPosition() const;
+ void setLogicalPosition(const QPoint &position);
+
+ QSize logicalSize() const;
+ void setLogicalSize(const QSize &size);
+
+ QRect logicalGeometry() const;
+
+Q_SIGNALS:
+ void managerChanged();
+ void outputChanged();
+ void logicalPositionChanged();
+ void logicalSizeChanged();
+ void logicalGeometryChanged();
+ void nameChanged();
+ void descriptionChanged();
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDXDGOUTPUTV1_H
diff --git a/src/compositor/extensions/qwaylandxdgoutputv1_p.h b/src/compositor/extensions/qwaylandxdgoutputv1_p.h
new file mode 100644
index 000000000..2e8a6fff9
--- /dev/null
+++ b/src/compositor/extensions/qwaylandxdgoutputv1_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDXDGOUTPUTV1_P_H
+#define QWAYLANDXDGOUTPUTV1_P_H
+
+#include <QWaylandOutput>
+#include <QWaylandXdgOutputV1>
+#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h>
+#include <QtWaylandCompositor/private/qwayland-server-xdg-output-unstable-v1.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgOutputManagerV1Private
+ : public QWaylandCompositorExtensionPrivate
+ , public QtWaylandServer::zxdg_output_manager_v1
+{
+ Q_DECLARE_PUBLIC(QWaylandXdgOutputManagerV1)
+public:
+ explicit QWaylandXdgOutputManagerV1Private() = default;
+
+ void registerXdgOutput(QWaylandOutput *output, QWaylandXdgOutputV1 *xdgOutput);
+ void unregisterXdgOutput(QWaylandOutput *output);
+
+ static QWaylandXdgOutputManagerV1Private *get(QWaylandXdgOutputManagerV1 *manager) { return manager ? manager->d_func() : nullptr; }
+
+protected:
+ void zxdg_output_manager_v1_get_xdg_output(Resource *resource, uint32_t id,
+ wl_resource *outputResource) override;
+
+private:
+ QHash<QWaylandOutput *, QWaylandXdgOutputV1 *> xdgOutputs;
+};
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgOutputV1Private
+ : public QObjectPrivate
+ , public QtWaylandServer::zxdg_output_v1
+{
+ Q_DECLARE_PUBLIC(QWaylandXdgOutputV1)
+public:
+ explicit QWaylandXdgOutputV1Private() = default;
+
+ void sendLogicalPosition(const QPoint &position);
+ void sendLogicalSize(const QSize &size);
+ void sendDone();
+
+ void setManager(QWaylandXdgOutputManagerV1 *manager);
+ void setOutput(QWaylandOutput *output);
+
+ static QWaylandXdgOutputV1Private *get(QWaylandXdgOutputV1 *xdgOutput) { return xdgOutput ? xdgOutput->d_func() : nullptr; }
+
+ bool initialized = false;
+ QWaylandOutput *output = nullptr;
+ QWaylandXdgOutputManagerV1 *manager = nullptr;
+ QPoint logicalPos;
+ QSize logicalSize;
+ QString name;
+ QString description;
+ bool needToSendDone = false;
+
+protected:
+ void zxdg_output_v1_bind_resource(Resource *resource) override;
+ void zxdg_output_v1_destroy(Resource *resource) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDXDGOUTPUTV1_P_H
diff --git a/src/compositor/extensions/qwaylandxdgshell.cpp b/src/compositor/extensions/qwaylandxdgshell.cpp
index 710385c0c..1b8a3c2e2 100644
--- a/src/compositor/extensions/qwaylandxdgshell.cpp
+++ b/src/compositor/extensions/qwaylandxdgshell.cpp
@@ -1279,7 +1279,9 @@ QWaylandXdgToplevel *QWaylandXdgToplevel::fromResource(wl_resource *resource)
QList<int> QWaylandXdgToplevel::statesAsInts() const
{
QList<int> list;
- Q_FOREACH (uint state, states()) {
+ const auto s = states();
+ list.reserve(s.size());
+ for (auto state : s) {
list << static_cast<int>(state);
}
return list;
@@ -1871,6 +1873,26 @@ uint QWaylandXdgPopup::sendConfigure(const QRect &geometry)
}
/*!
+ * \qmlmethod void QtWaylandCompositor::XdgPopup::sendPopupDone()
+ * \since 5.14
+ *
+ * Dismiss the popup. According to the \c xdg-shell protocol this should make the
+ * client destroy the popup.
+ */
+
+/*!
+ * \since 5.14
+ *
+ * Dismiss the popup. According to the \c xdg-shell protocol this should make the
+ * client destroy the popup.
+ */
+void QWaylandXdgPopup::sendPopupDone()
+{
+ Q_D(QWaylandXdgPopup);
+ d->send_popup_done();
+}
+
+/*!
* Returns the surface role for the QWaylandPopup.
*/
QWaylandSurfaceRole *QWaylandXdgPopup::role()
diff --git a/src/compositor/extensions/qwaylandxdgshell.h b/src/compositor/extensions/qwaylandxdgshell.h
index c7834ab91..2e3e28180 100644
--- a/src/compositor/extensions/qwaylandxdgshell.h
+++ b/src/compositor/extensions/qwaylandxdgshell.h
@@ -260,6 +260,7 @@ public:
QPoint unconstrainedPosition() const;
Q_INVOKABLE uint sendConfigure(const QRect &geometry);
+ Q_REVISION(14) Q_INVOKABLE void sendPopupDone();
static QWaylandSurfaceRole *role();
diff --git a/src/compositor/extensions/qwaylandxdgshellintegration.cpp b/src/compositor/extensions/qwaylandxdgshellintegration.cpp
index f415a5a24..0aa160544 100644
--- a/src/compositor/extensions/qwaylandxdgshellintegration.cpp
+++ b/src/compositor/extensions/qwaylandxdgshellintegration.cpp
@@ -77,7 +77,19 @@ XdgToplevelIntegration::XdgToplevelIntegration(QWaylandQuickShellSurfaceItem *it
connect(m_toplevel, &QObject::destroyed, this, &XdgToplevelIntegration::handleToplevelDestroyed);
}
-bool XdgToplevelIntegration::mouseMoveEvent(QMouseEvent *event)
+bool XdgToplevelIntegration::eventFilter(QObject *object, QEvent *event)
+{
+ if (event->type() == QEvent::MouseMove) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
+ return filterMouseMoveEvent(mouseEvent);
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
+ return filterMouseReleaseEvent(mouseEvent);
+ }
+ return QWaylandQuickShellIntegration::eventFilter(object, event);
+}
+
+bool XdgToplevelIntegration::filterMouseMoveEvent(QMouseEvent *event)
{
if (grabberState == GrabberState::Resize) {
Q_ASSERT(resizeState.seat == m_item->compositor()->seatFor(event));
@@ -105,7 +117,7 @@ bool XdgToplevelIntegration::mouseMoveEvent(QMouseEvent *event)
return false;
}
-bool XdgToplevelIntegration::mouseReleaseEvent(QMouseEvent *event)
+bool XdgToplevelIntegration::filterMouseReleaseEvent(QMouseEvent *event)
{
Q_UNUSED(event);
diff --git a/src/compositor/extensions/qwaylandxdgshellintegration_p.h b/src/compositor/extensions/qwaylandxdgshellintegration_p.h
index 34e3873d5..cd6bad572 100644
--- a/src/compositor/extensions/qwaylandxdgshellintegration_p.h
+++ b/src/compositor/extensions/qwaylandxdgshellintegration_p.h
@@ -63,8 +63,9 @@ class XdgToplevelIntegration : public QWaylandQuickShellIntegration
Q_OBJECT
public:
XdgToplevelIntegration(QWaylandQuickShellSurfaceItem *item);
- bool mouseMoveEvent(QMouseEvent *event) override;
- bool mouseReleaseEvent(QMouseEvent *event) override;
+
+protected:
+ bool eventFilter(QObject *object, QEvent *event) override;
private Q_SLOTS:
void handleStartMove(QWaylandSeat *seat);
@@ -120,6 +121,9 @@ private:
// will be hooked to geometry-changed or available-
// geometry-changed.
} nonwindowedState;
+
+ bool filterMouseMoveEvent(QMouseEvent *event);
+ bool filterMouseReleaseEvent(QMouseEvent *event);
};
class XdgPopupIntegration : public QWaylandQuickShellIntegration
diff --git a/src/compositor/extensions/qwaylandxdgshellv5.cpp b/src/compositor/extensions/qwaylandxdgshellv5.cpp
index ffd1ef90d..e38e68eb0 100644
--- a/src/compositor/extensions/qwaylandxdgshellv5.cpp
+++ b/src/compositor/extensions/qwaylandxdgshellv5.cpp
@@ -115,9 +115,9 @@ QWaylandXdgPopupV5 *QWaylandXdgShellV5Private::topmostPopupForClient(wl_client *
return clientPopups.empty() ? nullptr : clientPopups.last();
}
-QWaylandXdgSurfaceV5 *QWaylandXdgShellV5Private::xdgSurfaceFromSurface(QWaylandSurface *surface)
+QWaylandXdgSurfaceV5 *QWaylandXdgShellV5Private::xdgSurfaceFromSurface(QWaylandSurface *surface) const
{
- Q_FOREACH (QWaylandXdgSurfaceV5 *xdgSurface, m_xdgSurfaces) {
+ for (QWaylandXdgSurfaceV5 *xdgSurface : m_xdgSurfaces) {
if (surface == xdgSurface->surface())
return xdgSurface;
}
@@ -414,7 +414,7 @@ void QWaylandXdgSurfaceV5Private::xdg_surface_ack_configure(Resource *resource,
break;
}
- QVector<uint> changedStates;
+ std::vector<uint> changedStates;
std::set_symmetric_difference(
m_lastAckedConfigure.states.begin(), m_lastAckedConfigure.states.end(),
config.states.begin(), config.states.end(),
@@ -423,7 +423,7 @@ void QWaylandXdgSurfaceV5Private::xdg_surface_ack_configure(Resource *resource,
m_lastAckedConfigure = config;
if (!changedStates.empty()) {
- Q_FOREACH (uint state, changedStates) {
+ for (uint state : changedStates) {
switch (state) {
case QWaylandXdgSurfaceV5::State::MaximizedState:
emit q->maximizedChanged();
@@ -580,7 +580,7 @@ void QWaylandXdgShellV5::initialize()
QWaylandClient *QWaylandXdgShellV5::popupClient() const
{
Q_D(const QWaylandXdgShellV5);
- Q_FOREACH (QWaylandXdgPopupV5 *popup, d->m_xdgPopups) {
+ for (QWaylandXdgPopupV5 *popup : d->m_xdgPopups) {
if (popup->surface()->hasContent())
return popup->surface()->client();
}
@@ -627,15 +627,19 @@ uint QWaylandXdgShellV5::ping(QWaylandClient *client)
return serial;
}
+// ### remove once QMap has rbegin()/rend()
+template <typename Iterator>
+std::reverse_iterator<Iterator> make_reverse(Iterator it)
+{
+ return std::reverse_iterator<Iterator>(std::move(it));
+}
+
void QWaylandXdgShellV5::closeAllPopups()
{
Q_D(QWaylandXdgShellV5);
- Q_FOREACH (struct wl_client *client, d->m_xdgPopups.keys()) {
- QList<QWaylandXdgPopupV5 *> popups = d->m_xdgPopups.values(client);
- std::reverse(popups.begin(), popups.end());
- Q_FOREACH (QWaylandXdgPopupV5 *currentTopmostPopup, popups) {
- currentTopmostPopup->sendPopupDone();
- }
+ // Close pop-ups from top-most to bottom-most, lest we get protocol errors:
+ for (auto rit = make_reverse(d->m_xdgPopups.end()), rend = make_reverse(d->m_xdgPopups.begin()); rit != rend; ++rit) {
+ (*rit)->sendPopupDone();
}
}
@@ -987,7 +991,9 @@ void QWaylandXdgSurfaceV5::initialize()
QList<int> QWaylandXdgSurfaceV5::statesAsInts() const
{
QList<int> list;
- Q_FOREACH (uint state, states()) {
+ const auto s = states();
+ list.reserve(s.size());
+ for (auto state : s) {
list << static_cast<int>(state);
}
return list;
@@ -1238,7 +1244,8 @@ uint QWaylandXdgSurfaceV5::sendConfigure(const QSize &size, const QVector<uint>
uint QWaylandXdgSurfaceV5::sendConfigure(const QSize &size, const QVector<QWaylandXdgSurfaceV5::State> &states)
{
QVector<uint> asUints;
- Q_FOREACH (QWaylandXdgSurfaceV5::State state, states) {
+ asUints.reserve(states.size());
+ for (QWaylandXdgSurfaceV5::State state : states) {
asUints << state;
}
return sendConfigure(size, asUints);
diff --git a/src/compositor/extensions/qwaylandxdgshellv5_p.h b/src/compositor/extensions/qwaylandxdgshellv5_p.h
index 8f5af746b..d10359e68 100644
--- a/src/compositor/extensions/qwaylandxdgshellv5_p.h
+++ b/src/compositor/extensions/qwaylandxdgshellv5_p.h
@@ -81,7 +81,7 @@ public:
QMultiMap<struct wl_client *, QWaylandXdgSurfaceV5 *> m_xdgSurfaces;
QMultiMap<struct wl_client *, QWaylandXdgPopupV5 *> m_xdgPopups;
- QWaylandXdgSurfaceV5 *xdgSurfaceFromSurface(QWaylandSurface *surface);
+ QWaylandXdgSurfaceV5 *xdgSurfaceFromSurface(QWaylandSurface *surface) const;
protected:
void xdg_shell_destroy(Resource *resource) override;
diff --git a/src/compositor/extensions/qwaylandxdgshellv5integration.cpp b/src/compositor/extensions/qwaylandxdgshellv5integration.cpp
index 1d63632a3..4907a0611 100644
--- a/src/compositor/extensions/qwaylandxdgshellv5integration.cpp
+++ b/src/compositor/extensions/qwaylandxdgshellv5integration.cpp
@@ -82,7 +82,19 @@ XdgShellV5Integration::~XdgShellV5Integration()
m_item->setSurface(nullptr);
}
-bool XdgShellV5Integration::mouseMoveEvent(QMouseEvent *event)
+bool XdgShellV5Integration::eventFilter(QObject *object, QEvent *event)
+{
+ if (event->type() == QEvent::MouseMove) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
+ return filterMouseMoveEvent(mouseEvent);
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
+ return filterMouseReleaseEvent(mouseEvent);
+ }
+ return QWaylandQuickShellIntegration::eventFilter(object, event);
+}
+
+bool XdgShellV5Integration::filterMouseMoveEvent(QMouseEvent *event)
{
if (grabberState == GrabberState::Resize) {
Q_ASSERT(resizeState.seat == m_item->compositor()->seatFor(event));
@@ -110,7 +122,7 @@ bool XdgShellV5Integration::mouseMoveEvent(QMouseEvent *event)
return false;
}
-bool XdgShellV5Integration::mouseReleaseEvent(QMouseEvent *event)
+bool XdgShellV5Integration::filterMouseReleaseEvent(QMouseEvent *event)
{
Q_UNUSED(event);
diff --git a/src/compositor/extensions/qwaylandxdgshellv5integration_p.h b/src/compositor/extensions/qwaylandxdgshellv5integration_p.h
index 5d0e1e142..99983c866 100644
--- a/src/compositor/extensions/qwaylandxdgshellv5integration_p.h
+++ b/src/compositor/extensions/qwaylandxdgshellv5integration_p.h
@@ -64,8 +64,9 @@ class XdgShellV5Integration : public QWaylandQuickShellIntegration
public:
XdgShellV5Integration(QWaylandQuickShellSurfaceItem *item);
~XdgShellV5Integration() override;
- bool mouseMoveEvent(QMouseEvent *event) override;
- bool mouseReleaseEvent(QMouseEvent *event) override;
+
+protected:
+ bool eventFilter(QObject *object, QEvent *event) override;
private Q_SLOTS:
void handleStartMove(QWaylandSeat *seat);
@@ -108,6 +109,9 @@ private:
QSize initialWindowSize;
QPointF initialPosition;
} maximizeState;
+
+ bool filterMouseMoveEvent(QMouseEvent *event);
+ bool filterMouseReleaseEvent(QMouseEvent *event);
};
class XdgPopupV5Integration : public QWaylandQuickShellIntegration
diff --git a/src/compositor/extensions/qwaylandxdgshellv6.cpp b/src/compositor/extensions/qwaylandxdgshellv6.cpp
index 396506cf0..934dccb06 100644
--- a/src/compositor/extensions/qwaylandxdgshellv6.cpp
+++ b/src/compositor/extensions/qwaylandxdgshellv6.cpp
@@ -1214,7 +1214,9 @@ QWaylandSurfaceRole *QWaylandXdgToplevelV6::role()
QList<int> QWaylandXdgToplevelV6::statesAsInts() const
{
QList<int> list;
- Q_FOREACH (uint state, states()) {
+ const auto s = states();
+ list.reserve(s.size());
+ for (auto state : s) {
list << static_cast<int>(state);
}
return list;
@@ -1802,6 +1804,26 @@ uint QWaylandXdgPopupV6::sendConfigure(const QRect &geometry)
}
/*!
+ * \qmlmethod void QtWaylandCompositor::XdgPopupV6::sendPopupDone()
+ * \since 5.14
+ *
+ * Dismiss the popup. According to the \c xdg-shell-unstable-v6 protocol this should make the
+ * client destroy the popup.
+ */
+
+/*!
+ * \since 5.14
+ *
+ * Dismiss the popup. According to the \c xdg-shell-unstable-v6 protocol this should make the
+ * client destroy the popup.
+ */
+void QWaylandXdgPopupV6::sendPopupDone()
+{
+ Q_D(QWaylandXdgPopupV6);
+ d->send_popup_done();
+}
+
+/*!
* Returns the surface role for the QWaylandPopupV6.
*/
QWaylandSurfaceRole *QWaylandXdgPopupV6::role()
diff --git a/src/compositor/extensions/qwaylandxdgshellv6.h b/src/compositor/extensions/qwaylandxdgshellv6.h
index 710482ac3..71f82521a 100644
--- a/src/compositor/extensions/qwaylandxdgshellv6.h
+++ b/src/compositor/extensions/qwaylandxdgshellv6.h
@@ -246,6 +246,7 @@ public:
QPoint unconstrainedPosition() const;
Q_INVOKABLE uint sendConfigure(const QRect &geometry);
+ Q_REVISION(14) Q_INVOKABLE void sendPopupDone();
static QWaylandSurfaceRole *role();
diff --git a/src/compositor/extensions/qwaylandxdgshellv6integration.cpp b/src/compositor/extensions/qwaylandxdgshellv6integration.cpp
index 66dbc6841..e424af193 100644
--- a/src/compositor/extensions/qwaylandxdgshellv6integration.cpp
+++ b/src/compositor/extensions/qwaylandxdgshellv6integration.cpp
@@ -77,7 +77,19 @@ XdgToplevelV6Integration::XdgToplevelV6Integration(QWaylandQuickShellSurfaceItem
connect(m_toplevel, &QObject::destroyed, this, &XdgToplevelV6Integration::handleToplevelDestroyed);
}
-bool XdgToplevelV6Integration::mouseMoveEvent(QMouseEvent *event)
+bool XdgToplevelV6Integration::eventFilter(QObject *object, QEvent *event)
+{
+ if (event->type() == QEvent::MouseMove) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
+ return filterMouseMoveEvent(mouseEvent);
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
+ return filterMouseReleaseEvent(mouseEvent);
+ }
+ return QWaylandQuickShellIntegration::eventFilter(object, event);
+}
+
+bool XdgToplevelV6Integration::filterMouseMoveEvent(QMouseEvent *event)
{
if (grabberState == GrabberState::Resize) {
Q_ASSERT(resizeState.seat == m_item->compositor()->seatFor(event));
@@ -105,7 +117,7 @@ bool XdgToplevelV6Integration::mouseMoveEvent(QMouseEvent *event)
return false;
}
-bool XdgToplevelV6Integration::mouseReleaseEvent(QMouseEvent *event)
+bool XdgToplevelV6Integration::filterMouseReleaseEvent(QMouseEvent *event)
{
Q_UNUSED(event);
diff --git a/src/compositor/extensions/qwaylandxdgshellv6integration_p.h b/src/compositor/extensions/qwaylandxdgshellv6integration_p.h
index 049b901c9..9df2885f1 100644
--- a/src/compositor/extensions/qwaylandxdgshellv6integration_p.h
+++ b/src/compositor/extensions/qwaylandxdgshellv6integration_p.h
@@ -63,8 +63,9 @@ class XdgToplevelV6Integration : public QWaylandQuickShellIntegration
Q_OBJECT
public:
XdgToplevelV6Integration(QWaylandQuickShellSurfaceItem *item);
- bool mouseMoveEvent(QMouseEvent *event) override;
- bool mouseReleaseEvent(QMouseEvent *event) override;
+
+protected:
+ bool eventFilter(QObject *object, QEvent *event) override;
private Q_SLOTS:
void handleStartMove(QWaylandSeat *seat);
@@ -120,6 +121,9 @@ private:
// will be hooked to geometry-changed or available-
// geometry-changed.
} nonwindowedState;
+
+ bool filterMouseMoveEvent(QMouseEvent *event);
+ bool filterMouseReleaseEvent(QMouseEvent *event);
};
class XdgPopupV6Integration : public QWaylandQuickShellIntegration
diff --git a/src/compositor/extensions/qwltexturesharingextension.cpp b/src/compositor/extensions/qwltexturesharingextension.cpp
index 251c5fec0..cf9fd0116 100644
--- a/src/compositor/extensions/qwltexturesharingextension.cpp
+++ b/src/compositor/extensions/qwltexturesharingextension.cpp
@@ -177,7 +177,7 @@ public:
return new SharedTextureFactory(m_buffer);
}
// qDebug() << "Shared buffer NOT found for" << m_id;
- m_errorString = QLatin1Literal("Shared buffer not found");
+ m_errorString = QLatin1String("Shared buffer not found");
return nullptr;
}
@@ -282,7 +282,7 @@ void QWaylandTextureSharingExtension::initialize()
setImageSearchPath(image_search_path);
if (m_image_dirs.isEmpty())
- m_image_dirs << QLatin1Literal(":/") << QLatin1Literal("./");
+ m_image_dirs << QLatin1String(":/") << QLatin1String("./");
auto suffixes = QTextureFileReader::supportedFileFormats();
suffixes.append(QImageReader::supportedImageFormats());
@@ -295,7 +295,7 @@ void QWaylandTextureSharingExtension::initialize()
if (ctx) {
QQmlEngine *engine = ctx->engine();
if (engine) {
- auto *provider = static_cast<QWaylandSharedTextureProvider*>(engine->imageProvider(QLatin1Literal("wlshared")));
+ auto *provider = static_cast<QWaylandSharedTextureProvider*>(engine->imageProvider(QLatin1String("wlshared")));
if (provider)
provider->setExtensionReady(this);
}
@@ -308,7 +308,7 @@ QString QWaylandTextureSharingExtension::getExistingFilePath(const QString &key)
// paths containing '../'. We handle that here, at the price of also blocking directory
// names ending with two or more dots.
- if (key.contains(QLatin1Literal("../")))
+ if (key.contains(QLatin1String("../")))
return QString();
for (auto dir : m_image_dirs) {
diff --git a/src/compositor/global/qwaylandcompositorextension.cpp b/src/compositor/global/qwaylandcompositorextension.cpp
index 912985399..36daebce7 100644
--- a/src/compositor/global/qwaylandcompositorextension.cpp
+++ b/src/compositor/global/qwaylandcompositorextension.cpp
@@ -146,7 +146,7 @@ QWaylandObject::QWaylandObject(QObjectPrivate &d, QObject *parent)
QWaylandObject::~QWaylandObject()
{
- foreach (QWaylandCompositorExtension *extension, extension_vector)
+ for (QWaylandCompositorExtension *extension : qAsConst(extension_vector))
QWaylandCompositorExtensionPrivate::get(extension)->extension_container = nullptr;
}
diff --git a/src/compositor/hardware_integration/qwlserverbufferintegration_p.h b/src/compositor/hardware_integration/qwlserverbufferintegration_p.h
index b8d9fa99d..e8f774e60 100644
--- a/src/compositor/hardware_integration/qwlserverbufferintegration_p.h
+++ b/src/compositor/hardware_integration/qwlserverbufferintegration_p.h
@@ -55,7 +55,8 @@
#include <QtCore/QSize>
#include <QtGui/qopengl.h>
-#include <QtWaylandCompositor/private/qtwaylandcompositorglobal_p.h>
+#include <QtWaylandCompositor/qtwaylandcompositorglobal.h>
+
struct wl_client;
struct wl_resource;
@@ -85,9 +86,8 @@ public:
virtual bool bufferInUse() { return true; }
virtual QOpenGLTexture *toOpenGlTexture() = 0;
-#if QT_CONFIG(wayland_compositor_texture_sharing_experimental)
virtual void releaseOpenGlTexture() {}
-#endif
+
virtual bool isYInverted() const;
QSize size() const;
@@ -107,7 +107,6 @@ public:
virtual bool supportsFormat(ServerBuffer::Format format) const = 0;
virtual ServerBuffer *createServerBufferFromImage(const QImage &qimage, ServerBuffer::Format format) = 0;
-#if QT_CONFIG(wayland_compositor_texture_sharing_experimental)
virtual ServerBuffer *createServerBufferFromData(const QByteArray &data, const QSize &size, uint glInternalFormat)
{
Q_UNUSED(data);
@@ -115,7 +114,6 @@ public:
Q_UNUSED(glInternalFormat);
return nullptr;
}
-#endif
};
}
diff --git a/src/compositor/wayland_wrapper/qwlclientbuffer.cpp b/src/compositor/wayland_wrapper/qwlclientbuffer.cpp
index cb1ee3da0..d3f8df9f3 100644
--- a/src/compositor/wayland_wrapper/qwlclientbuffer.cpp
+++ b/src/compositor/wayland_wrapper/qwlclientbuffer.cpp
@@ -81,7 +81,7 @@ void ClientBuffer::setDestroyed()
m_committed = false;
m_buffer = nullptr;
- if (!m_refCount)
+ if (!m_refCount.loadAcquire())
delete this;
}
@@ -133,17 +133,19 @@ QWaylandSurface::Origin SharedMemoryBuffer::origin() const
return QWaylandSurface::OriginTopLeft;
}
-
-// TODO: support different color formats, and try to avoid QImage::convertToFormat()
-
QImage SharedMemoryBuffer::image() const
{
if (wl_shm_buffer *shmBuffer = wl_shm_buffer_get(m_buffer)) {
int width = wl_shm_buffer_get_width(shmBuffer);
int height = wl_shm_buffer_get_height(shmBuffer);
int bytesPerLine = wl_shm_buffer_get_stride(shmBuffer);
+
+ // TODO: try to avoid QImage::convertToFormat()
+ wl_shm_format shmFormat = wl_shm_format(wl_shm_buffer_get_format(shmBuffer));
+ QImage::Format format = QWaylandSharedMemoryFormatHelper::fromWaylandShmFormat(shmFormat);
+
uchar *data = static_cast<uchar *>(wl_shm_buffer_get_data(shmBuffer));
- return QImage(data, width, height, bytesPerLine, QImage::Format_ARGB32_Premultiplied);
+ return QImage(data, width, height, bytesPerLine, format);
}
return QImage();
diff --git a/src/compositor/wayland_wrapper/qwldatadevicemanager.cpp b/src/compositor/wayland_wrapper/qwldatadevicemanager.cpp
index e30bc84f8..624a24b06 100644
--- a/src/compositor/wayland_wrapper/qwldatadevicemanager.cpp
+++ b/src/compositor/wayland_wrapper/qwldatadevicemanager.cpp
@@ -186,12 +186,12 @@ struct wl_display *DataDeviceManager::display() const
void DataDeviceManager::overrideSelection(const QMimeData &mimeData)
{
- QStringList formats = mimeData.formats();
+ const QStringList formats = mimeData.formats();
if (formats.isEmpty())
return;
m_retainedData.clear();
- foreach (const QString &format, formats)
+ for (const QString &format : formats)
m_retainedData.setData(format, mimeData.data(format));
QWaylandCompositorPrivate::get(m_compositor)->feedRetainedSelectionData(&m_retainedData);
@@ -217,7 +217,8 @@ bool DataDeviceManager::offerFromCompositorToClient(wl_resource *clientDataDevic
wl_resource_create(client, &wl_data_offer_interface, -1, 0);
wl_resource_set_implementation(selectionOffer, &compositor_offer_interface, this, nullptr);
wl_data_device_send_data_offer(clientDataDeviceResource, selectionOffer);
- foreach (const QString &format, m_retainedData.formats()) {
+ const auto formats = m_retainedData.formats();
+ for (const QString &format : formats) {
QByteArray ba = format.toLatin1();
wl_data_offer_send_offer(selectionOffer, ba.constData());
}
diff --git a/src/compositor/wayland_wrapper/qwldataoffer.cpp b/src/compositor/wayland_wrapper/qwldataoffer.cpp
index 9fea664ac..ddc5545e3 100644
--- a/src/compositor/wayland_wrapper/qwldataoffer.cpp
+++ b/src/compositor/wayland_wrapper/qwldataoffer.cpp
@@ -55,7 +55,8 @@ DataOffer::DataOffer(DataSource *dataSource, QtWaylandServer::wl_data_device::Re
{
// FIXME: connect to dataSource and reset m_dataSource on destroy
target->data_device_object->send_data_offer(target->handle, resource()->handle);
- Q_FOREACH (const QString &mimeType, dataSource->mimeTypes()) {
+ const auto mimeTypes = dataSource->mimeTypes();
+ for (const QString &mimeType : mimeTypes) {
send_offer(mimeType);
}
}
diff --git a/src/extensions/README.md b/src/extensions/README.md
index f75e0f236..8024ffa80 100644
--- a/src/extensions/README.md
+++ b/src/extensions/README.md
@@ -3,12 +3,10 @@
The protocol extensions in this folder are considered implementation details of
Qt. I.e. they may removed, renamed or changed without warning.
-## Suffixed protocols
-
-For protocols that have a version suffix, however, we will strive to not break
-backwards compatibility without bumping the suffix (renaming the protocol).
-E.g.: If your client sees a `zqt_key_v1` global, it can safely bind to it:
-the key event will always take the same number of arguments, regardless of
+However, starting with Qt 5.4, we promise not to break backwards compatibility
+without renaming (or removing) the protocol. I.e., if your client sees a global
+from one of these extensions, it can safely bind to it: the existing events
+and requests will always take the same number of arguments, regardless of
compositor version.
This is important also within a Qt-only scope if there are multiple versions of
@@ -16,3 +14,11 @@ Qt on the system. Consider for instance an application statically linked to Qt
(such as Qt Creator) running against a Qt compositor installed by the distro).
In such cases we don't want the compositor and client to disagree on the
protocol definition.
+
+## Protocol versioning.
+
+Protocol extensions in this folder should be versioned (e.g. `zqt_key_v1`).
+If it is necessary to break protocol compatibility, they will be renamed by
+incrementing the version number. For legacy reasons, there are also unversioned
+protocols in this folder. Those protocols should be renamed to be versioned
+if compatibility is broken.
diff --git a/src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.cpp b/src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.cpp
index 7e1d5966f..4b2be50e6 100644
--- a/src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.cpp
+++ b/src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.cpp
@@ -37,15 +37,12 @@
**
****************************************************************************/
-#define GL_GLEXT_PROTOTYPES
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
#include "vulkanserverbufferintegration.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QDebug>
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLTexture>
+#include <QtGui/qopengl.h>
#include <QtGui/QImage>
#include <QtCore/QCoreApplication>
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
index 24dadff4d..030422c56 100644
--- a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
+++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
@@ -137,9 +137,8 @@ void QWaylandEglWindow::updateSurface(bool create)
m_resize = true;
}
- } else if (create && wl_surface::isInitialized()) {
- ::wl_surface *wlSurface = wl_surface::object();
- m_waylandEglWindow = wl_egl_window_create(wlSurface, sizeWithMargins.width(), sizeWithMargins.height());
+ } else if (create && wlSurface()) {
+ m_waylandEglWindow = wl_egl_window_create(wlSurface(), sizeWithMargins.width(), sizeWithMargins.height());
}
if (!m_eglSurface && m_waylandEglWindow && create) {
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
index bc1f74af9..5bd2760d0 100644
--- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
+++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
@@ -192,7 +192,7 @@ public:
}
void blit(QWaylandEglWindow *window)
{
- Q_ASSERT(window->wl_surface::isInitialized());
+ Q_ASSERT(window->wlSurface());
QOpenGLTextureCache *cache = QOpenGLTextureCache::cacheForContext(m_context->context());
QSize surfaceSize = window->surfaceSize();
diff --git a/src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.cpp b/src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.cpp
index 7f9f8a151..df197ca23 100644
--- a/src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.cpp
+++ b/src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.cpp
@@ -37,10 +37,6 @@
**
****************************************************************************/
-#define GL_GLEXT_PROTOTYPES
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
#include "vulkanserverbufferintegration.h"
#include "vulkanwrapper.h"
@@ -48,6 +44,7 @@
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLTexture>
#include <QtGui/QOffscreenSurface>
+#include <QtGui/qopengl.h>
#include <unistd.h>
#include <fcntl.h>
diff --git a/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp b/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp
index fe66adf55..771e1015c 100644
--- a/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp
+++ b/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp
@@ -40,14 +40,13 @@
// NOTE: Some of the code below is adapted from the public domain code at https://vulkan-tutorial.com/
#define GL_GLEXT_PROTOTYPES
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include <QtVulkanSupport/private/qvkconvenience_p.h>
#include "vulkanwrapper.h"
#include <QImage>
#include <QOpenGLContext>
+#include <QtGui/qopengl.h>
+#include <QtVulkanSupport/private/qvkconvenience_p.h>
#include <set>
@@ -707,7 +706,6 @@ VulkanImageWrapper *VulkanWrapper::createTextureImage(const QImage &img)
VulkanImageWrapper *VulkanWrapper::createTextureImageFromData(const uchar *pixels, uint bufferSize, const QSize &size, uint glInternalFormat)
{
VkFormat vkFormat = VkFormat(QVkConvenience::vkFormatFromGlFormat(glInternalFormat));
-
if (vkFormat == VK_FORMAT_UNDEFINED)
return nullptr;
diff --git a/src/imports/compositor/qwaylandquickcompositorplugin.cpp b/src/imports/compositor/qwaylandquickcompositorplugin.cpp
index c7553d932..223ca0bc5 100644
--- a/src/imports/compositor/qwaylandquickcompositorplugin.cpp
+++ b/src/imports/compositor/qwaylandquickcompositorplugin.cpp
@@ -66,6 +66,8 @@
#include <QtWaylandCompositor/QWaylandXdgShellV6>
#include <QtWaylandCompositor/QWaylandXdgShell>
#include <QtWaylandCompositor/QWaylandXdgDecorationManagerV1>
+#include <QtWaylandCompositor/QWaylandIdleInhibitManagerV1>
+#include <QtWaylandCompositor/QWaylandQuickXdgOutputV1>
#include <QtWaylandCompositor/QWaylandIviApplication>
#include <QtWaylandCompositor/QWaylandIviSurface>
@@ -76,13 +78,17 @@ QT_BEGIN_NAMESPACE
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CONTAINER_CLASS(QWaylandQuickCompositor)
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandQtWindowManager)
+Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandIdleInhibitManagerV1)
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandIviApplication)
+#if QT_DEPRECATED_SINCE(5, 13)
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandWlScaler)
+#endif
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandWlShell)
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandXdgShellV5)
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandXdgShellV6)
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandXdgShell)
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandXdgDecorationManagerV1)
+Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandXdgOutputManagerV1)
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandTextInputManager)
class QmlUrlResolver
@@ -137,7 +143,9 @@ public:
qmlRegisterType<QWaylandQuickCompositorQuickExtensionContainer>(uri, 1, 0, "WaylandCompositor");
qmlRegisterType<QWaylandQuickItem>(uri, 1, 0, "WaylandQuickItem");
qmlRegisterType<QWaylandQuickItem, 13>(uri, 1, 13, "WaylandQuickItem");
+#if QT_CONFIG(opengl)
qmlRegisterType<QWaylandQuickHardwareLayer>(uri, 1, 2, "WaylandHardwareLayer");
+#endif
qmlRegisterType<QWaylandMouseTracker>(uri, 1, 0, "WaylandMouseTracker");
qmlRegisterType<QWaylandQuickOutput>(uri, 1, 0, "WaylandOutput");
qmlRegisterType<QWaylandQuickSurface>(uri, 1, 0, "WaylandSurface");
@@ -182,7 +190,14 @@ public:
qmlRegisterType<QWaylandXdgDecorationManagerV1QuickExtension>(uri, 1, 3, "XdgDecorationManagerV1");
+#if QT_DEPRECATED_SINCE(5, 13)
qmlRegisterType<QWaylandWlScalerQuickExtension>(uri, 1, 13, "WlScaler");
+#endif
+
+ qmlRegisterType<QWaylandIdleInhibitManagerV1QuickExtension>(uri, 1, 14, "IdleInhibitManagerV1");
+
+ qmlRegisterType<QWaylandXdgOutputManagerV1QuickExtension>(uri, 1, 14, "XdgOutputManagerV1");
+ qmlRegisterType<QWaylandQuickXdgOutputV1>(uri, 1, 14, "XdgOutputV1");
}
};
//![class decl]
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index c8394f0c1..7452a9283 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -1,8 +1,12 @@
TEMPLATE = subdirs
-qtHaveModule(quick): {
+qtHaveModule(quick):qtHaveModule(waylandcompositor) {
SUBDIRS += \
- compositor \
- texture-sharing \
- texture-sharing-extension
+ compositor
+
+ qtConfig(opengl):qtHaveModule(waylandclient) {
+ SUBDIRS += \
+ texture-sharing \
+ texture-sharing-extension
+ }
}
diff --git a/src/imports/texture-sharing-extension/texture-sharing-extension.pro b/src/imports/texture-sharing-extension/texture-sharing-extension.pro
index 577ab58e7..68a8cf757 100644
--- a/src/imports/texture-sharing-extension/texture-sharing-extension.pro
+++ b/src/imports/texture-sharing-extension/texture-sharing-extension.pro
@@ -8,6 +8,4 @@ SOURCES += \
QT += quick-private qml gui-private core-private waylandcompositor waylandcompositor-private
-requires(qtConfig(wayland-compositor-texture-sharing-experimental))
-
load(qml_plugin)
diff --git a/src/imports/texture-sharing/texture-sharing.pro b/src/imports/texture-sharing/texture-sharing.pro
index eb5c0a9af..bec769ecb 100644
--- a/src/imports/texture-sharing/texture-sharing.pro
+++ b/src/imports/texture-sharing/texture-sharing.pro
@@ -15,8 +15,6 @@ SOURCES += \
QT += quick-private qml gui-private core-private waylandclient waylandclient-private
CONFIG += wayland-scanner
-requires(qtConfig(wayland-client-texture-sharing-experimental))
-
WAYLANDCLIENTSOURCES += ../../extensions/qt-texture-sharing-unstable-v1.xml
diff --git a/src/plugins/hardwareintegration/hardwareintegration.pro b/src/plugins/hardwareintegration/hardwareintegration.pro
index cb7a4b263..12658adff 100644
--- a/src/plugins/hardwareintegration/hardwareintegration.pro
+++ b/src/plugins/hardwareintegration/hardwareintegration.pro
@@ -1,4 +1,4 @@
TEMPLATE=subdirs
-SUBDIRS += client
+qtHaveModule(waylandclient): SUBDIRS += client
qtHaveModule(waylandcompositor): SUBDIRS += compositor
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index 9b66b851e..e121d92d3 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -1,6 +1,11 @@
TEMPLATE=subdirs
+
+qtHaveModule(waylandclient) {
+ SUBDIRS += \
+ platforms \
+ decorations \
+ shellintegration
+}
+
SUBDIRS += \
- platforms \
- hardwareintegration \
- decorations \
- shellintegration
+ hardwareintegration
diff --git a/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.cpp b/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.cpp
index 9a829f6e9..26f598895 100644
--- a/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.cpp
+++ b/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.cpp
@@ -51,7 +51,7 @@ QWaylandFullScreenShellV1Surface::QWaylandFullScreenShellV1Surface(QtWayland::zw
, m_window(window)
{
auto screen = static_cast<QWaylandScreen *>(m_window->screen());
- m_shell->present_surface(m_window->object(),
+ m_shell->present_surface(m_window->wlSurface(),
QtWayland::zwp_fullscreen_shell_v1::present_method_default,
screen->output());
}
diff --git a/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.cpp b/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.cpp
index efb61dc9f..ea725ac31 100644
--- a/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.cpp
+++ b/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.cpp
@@ -48,6 +48,8 @@
#include "qwaylandivisurface_p.h"
+#include <mutex>
+
#include <unistd.h>
QT_BEGIN_NAMESPACE
@@ -95,7 +97,7 @@ uint32_t QWaylandIviShellIntegration::getNextUniqueSurfaceId()
{
const uint32_t PID_MAX_EXPONENTIATION = 22; // 22 bit shift operation
const uint32_t ID_LIMIT = 1 << (32 - PID_MAX_EXPONENTIATION); // 10 bit is unique id
- QMutexLocker locker(&m_mutex);
+ const std::lock_guard<QRecursiveMutex> locker(m_mutex);
if (m_lastSurfaceId == 0) {
QByteArray env = qgetenv("QT_IVI_SURFACE_ID");
@@ -132,7 +134,7 @@ QWaylandShellSurface *QWaylandIviShellIntegration::createShellSurface(QWaylandWi
if (surfaceId == 0)
return nullptr;
- struct ivi_surface *surface = m_iviApplication->surface_create(surfaceId, window->object());
+ struct ivi_surface *surface = m_iviApplication->surface_create(surfaceId, window->wlSurface());
if (!m_iviController)
return new QWaylandIviSurface(surface, window);
diff --git a/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.h b/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.h
index fc16d2f64..13282e438 100644
--- a/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.h
+++ b/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.h
@@ -71,7 +71,7 @@ private:
uint32_t m_lastSurfaceId = 0;
uint32_t m_surfaceNumber = 0;
bool m_useEnvSurfaceId = false;
- QMutex m_mutex{QMutex::Recursive};
+ QRecursiveMutex m_mutex;
};
}
diff --git a/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration.cpp b/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration.cpp
index 1edb24b3c..ab8098062 100644
--- a/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration.cpp
+++ b/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration.cpp
@@ -49,7 +49,8 @@ namespace QtWaylandClient {
bool QWaylandWlShellIntegration::initialize(QWaylandDisplay *display)
{
- Q_FOREACH (QWaylandDisplay::RegistryGlobal global, display->globals()) {
+ const auto globals = display->globals();
+ for (QWaylandDisplay::RegistryGlobal global : globals) {
if (global.interface == QLatin1String("wl_shell")) {
m_wlShell = new QtWayland::wl_shell(display->wl_registry(), global.id, 1);
break;
@@ -70,7 +71,7 @@ bool QWaylandWlShellIntegration::initialize(QWaylandDisplay *display)
QWaylandShellSurface *QWaylandWlShellIntegration::createShellSurface(QWaylandWindow *window)
{
- return new QWaylandWlShellSurface(m_wlShell->get_shell_surface(window->object()), window);
+ return new QWaylandWlShellSurface(m_wlShell->get_shell_surface(window->wlSurface()), window);
}
void *QWaylandWlShellIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
diff --git a/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp b/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp
index 4506c312a..48e14c753 100644
--- a/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp
+++ b/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp
@@ -62,9 +62,9 @@ QWaylandWlShellSurface::QWaylandWlShellSurface(struct ::wl_shell_surface *shell_
Qt::WindowType type = window->window()->type();
auto *transientParent = window->transientParent();
- if (type == Qt::Popup && transientParent && transientParent->object())
+ if (type == Qt::Popup && transientParent && transientParent->wlSurface())
setPopup(transientParent, m_window->display()->lastInputDevice(), m_window->display()->lastInputSerial());
- else if (transientParent && transientParent->object())
+ else if (transientParent && transientParent->wlSurface())
updateTransientParent(transientParent->window());
else
setTopLevel();
@@ -234,11 +234,9 @@ void QWaylandWlShellSurface::updateTransientParent(QWindow *parent)
|| testShowWithoutActivating(m_window->window()))
flags |= WL_SHELL_SURFACE_TRANSIENT_INACTIVE;
- Q_ASSERT(parent_wayland_window->object());
- set_transient(parent_wayland_window->object(),
- transientPos.x(),
- transientPos.y(),
- flags);
+ auto *parentSurface = parent_wayland_window->wlSurface();
+ Q_ASSERT(parentSurface);
+ set_transient(parentSurface, transientPos.x(), transientPos.y(), flags);
}
void QWaylandWlShellSurface::setPopup(QWaylandWindow *parent, QWaylandInputDevice *device, uint serial)
@@ -261,9 +259,10 @@ void QWaylandWlShellSurface::setPopup(QWaylandWindow *parent, QWaylandInputDevic
transientPos.setY(transientPos.y() + parent_wayland_window->decoration()->margins().top());
}
- Q_ASSERT(parent_wayland_window->object());
- set_popup(device->wl_seat(), serial, parent_wayland_window->object(),
- transientPos.x(), transientPos.y(), 0);
+ auto *parentSurface = parent_wayland_window->wlSurface();
+ Q_ASSERT(parentSurface);
+ uint flags = 0;
+ set_popup(device->wl_seat(), serial, parentSurface, transientPos.x(), transientPos.y(), flags);
}
void QWaylandWlShellSurface::shell_surface_ping(uint32_t serial)
diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp
index 3eda43d7c..7e242c4a5 100644
--- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp
@@ -74,7 +74,7 @@ QWaylandXdgPopupV5 *QWaylandXdgShellV5::createXdgPopup(QWaylandWindow *window, Q
if (!parentWindow)
return nullptr;
- ::wl_surface *parentSurface = parentWindow->object();
+ ::wl_surface *parentSurface = parentWindow->wlSurface();
if (m_popupSerial == 0)
m_popupSerial = inputDevice->serial();
@@ -84,7 +84,7 @@ QWaylandXdgPopupV5 *QWaylandXdgShellV5::createXdgPopup(QWaylandWindow *window, Q
int x = position.x() + parentWindow->frameMargins().left();
int y = position.y() + parentWindow->frameMargins().top();
- auto popup = new QWaylandXdgPopupV5(get_xdg_popup(window->object(), parentSurface, seat, m_popupSerial, x, y), window);
+ auto popup = new QWaylandXdgPopupV5(get_xdg_popup(window->wlSurface(), parentSurface, seat, m_popupSerial, x, y), window);
m_popups.append(window);
QObject::connect(popup, &QWaylandXdgPopupV5::destroyed, [this, window](){
m_popups.removeOne(window);
diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
index 410f27001..4e25949fa 100644
--- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
@@ -51,7 +51,8 @@ namespace QtWaylandClient {
bool QWaylandXdgShellV5Integration::initialize(QWaylandDisplay *display)
{
- Q_FOREACH (QWaylandDisplay::RegistryGlobal global, display->globals()) {
+ const auto globals = display->globals();
+ for (QWaylandDisplay::RegistryGlobal global : globals) {
if (global.interface == QLatin1String("xdg_shell")) {
m_xdgShell.reset(new QWaylandXdgShellV5(display->wl_registry(), global.id));
break;
diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp
index e9f64e2e6..e8bff9193 100644
--- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp
@@ -54,7 +54,7 @@ namespace QtWaylandClient {
QWaylandXdgSurfaceV5::QWaylandXdgSurfaceV5(QWaylandXdgShellV5 *shell, QWaylandWindow *window)
: QWaylandShellSurface(window)
- , QtWayland::xdg_surface_v5(shell->get_xdg_surface(window->object()))
+ , QtWayland::xdg_surface_v5(shell->get_xdg_surface(window->wlSurface()))
, m_window(window)
, m_shell(shell)
{
diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp
index 99b478d98..dc3cfdbfa 100644
--- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp
+++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6.cpp
@@ -425,7 +425,7 @@ QWaylandXdgShellV6::~QWaylandXdgShellV6()
QWaylandXdgSurfaceV6 *QWaylandXdgShellV6::getXdgSurface(QWaylandWindow *window)
{
- return new QWaylandXdgSurfaceV6(this, get_xdg_surface(window->object()), window);
+ return new QWaylandXdgSurfaceV6(this, get_xdg_surface(window->wlSurface()), window);
}
void QWaylandXdgShellV6::zxdg_shell_v6_ping(uint32_t serial)
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
index 026bb56a0..bd1f5a210 100644
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
@@ -463,7 +463,7 @@ QWaylandXdgShell::~QWaylandXdgShell()
QWaylandXdgSurface *QWaylandXdgShell::getXdgSurface(QWaylandWindow *window)
{
- return new QWaylandXdgSurface(this, get_xdg_surface(window->object()), window);
+ return new QWaylandXdgSurface(this, get_xdg_surface(window->wlSurface()), window);
}
void QWaylandXdgShell::xdg_wm_base_ping(uint32_t serial)
diff --git a/src/qtwaylandscanner/qtwaylandscanner.cpp b/src/qtwaylandscanner/qtwaylandscanner.cpp
index 7f3dc5ad6..9691b857f 100644
--- a/src/qtwaylandscanner/qtwaylandscanner.cpp
+++ b/src/qtwaylandscanner/qtwaylandscanner.cpp
@@ -40,7 +40,8 @@
#include <QCoreApplication>
#include <QFile>
#include <QXmlStreamReader>
-#include <QtCore/QList>
+
+#include <vector>
class Scanner
{
@@ -63,7 +64,7 @@ private:
struct WaylandEnum {
QByteArray name;
- QList<WaylandEnumEntry> entries;
+ std::vector<WaylandEnumEntry> entries;
};
struct WaylandArgument {
@@ -78,16 +79,16 @@ private:
bool request;
QByteArray name;
QByteArray type;
- QList<WaylandArgument> arguments;
+ std::vector<WaylandArgument> arguments;
};
struct WaylandInterface {
QByteArray name;
int version;
- QList<WaylandEnum> enums;
- QList<WaylandEvent> events;
- QList<WaylandEvent> requests;
+ std::vector<WaylandEnum> enums;
+ std::vector<WaylandEvent> events;
+ std::vector<WaylandEvent> requests;
};
bool isServerSide();
@@ -101,11 +102,11 @@ private:
Scanner::WaylandInterface readInterface(QXmlStreamReader &xml);
QByteArray waylandToCType(const QByteArray &waylandType, const QByteArray &interface);
QByteArray waylandToQtType(const QByteArray &waylandType, const QByteArray &interface, bool cStyleArray);
- const Scanner::WaylandArgument *newIdArgument(const QList<WaylandArgument> &arguments);
+ const Scanner::WaylandArgument *newIdArgument(const std::vector<WaylandArgument> &arguments);
void printEvent(const WaylandEvent &e, bool omitNames = false, bool withResource = false);
void printEventHandlerSignature(const WaylandEvent &e, const char *interfaceName, bool deepIndent = true);
- void printEnums(const QList<WaylandEnum> &enums);
+ void printEnums(const std::vector<WaylandEnum> &enums);
QByteArray stripInterfaceName(const QByteArray &name);
bool ignoreInterface(const QByteArray &name);
@@ -189,19 +190,22 @@ bool Scanner::boolValue(const QXmlStreamReader &xml, const char *name)
Scanner::WaylandEvent Scanner::readEvent(QXmlStreamReader &xml, bool request)
{
- WaylandEvent event;
- event.request = request;
- event.name = byteArrayValue(xml, "name");
- event.type = byteArrayValue(xml, "type");
+ WaylandEvent event = {
+ .request = request,
+ .name = byteArrayValue(xml, "name"),
+ .type = byteArrayValue(xml, "type"),
+ .arguments = {},
+ };
while (xml.readNextStartElement()) {
if (xml.name() == "arg") {
- WaylandArgument argument;
- argument.name = byteArrayValue(xml, "name");
- argument.type = byteArrayValue(xml, "type");
- argument.interface = byteArrayValue(xml, "interface");
- argument.summary = byteArrayValue(xml, "summary");
- argument.allowNull = boolValue(xml, "allowNull");
- event.arguments << argument;
+ WaylandArgument argument = {
+ .name = byteArrayValue(xml, "name"),
+ .type = byteArrayValue(xml, "type"),
+ .interface = byteArrayValue(xml, "interface"),
+ .summary = byteArrayValue(xml, "summary"),
+ .allowNull = boolValue(xml, "allowNull"),
+ };
+ event.arguments.push_back(std::move(argument));
}
xml.skipCurrentElement();
@@ -211,16 +215,19 @@ Scanner::WaylandEvent Scanner::readEvent(QXmlStreamReader &xml, bool request)
Scanner::WaylandEnum Scanner::readEnum(QXmlStreamReader &xml)
{
- WaylandEnum result;
- result.name = byteArrayValue(xml, "name");
+ WaylandEnum result = {
+ .name = byteArrayValue(xml, "name"),
+ .entries = {},
+ };
while (xml.readNextStartElement()) {
if (xml.name() == "entry") {
- WaylandEnumEntry entry;
- entry.name = byteArrayValue(xml, "name");
- entry.value = byteArrayValue(xml, "value");
- entry.summary = byteArrayValue(xml, "summary");
- result.entries << entry;
+ WaylandEnumEntry entry = {
+ .name = byteArrayValue(xml, "name"),
+ .value = byteArrayValue(xml, "value"),
+ .summary = byteArrayValue(xml, "summary"),
+ };
+ result.entries.push_back(std::move(entry));
}
xml.skipCurrentElement();
@@ -231,17 +238,21 @@ Scanner::WaylandEnum Scanner::readEnum(QXmlStreamReader &xml)
Scanner::WaylandInterface Scanner::readInterface(QXmlStreamReader &xml)
{
- WaylandInterface interface;
- interface.name = byteArrayValue(xml, "name");
- interface.version = intValue(xml, "version", 1);
+ WaylandInterface interface = {
+ .name = byteArrayValue(xml, "name"),
+ .version = intValue(xml, "version", 1),
+ .enums = {},
+ .events = {},
+ .requests = {},
+ };
while (xml.readNextStartElement()) {
if (xml.name() == "event")
- interface.events << readEvent(xml, false);
+ interface.events.push_back(readEvent(xml, false));
else if (xml.name() == "request")
- interface.requests << readEvent(xml, true);
+ interface.requests.push_back(readEvent(xml, true));
else if (xml.name() == "enum")
- interface.enums << readEnum(xml);
+ interface.enums.push_back(readEnum(xml));
else
xml.skipCurrentElement();
}
@@ -283,11 +294,11 @@ QByteArray Scanner::waylandToQtType(const QByteArray &waylandType, const QByteAr
return waylandToCType(waylandType, interface);
}
-const Scanner::WaylandArgument *Scanner::newIdArgument(const QList<WaylandArgument> &arguments)
+const Scanner::WaylandArgument *Scanner::newIdArgument(const std::vector<WaylandArgument> &arguments)
{
- for (int i = 0; i < arguments.size(); ++i) {
- if (arguments.at(i).type == "new_id")
- return &arguments.at(i);
+ for (const WaylandArgument &a : arguments) {
+ if (a.type == "new_id")
+ return &a;
}
return nullptr;
}
@@ -305,8 +316,7 @@ void Scanner::printEvent(const WaylandEvent &e, bool omitNames, bool withResourc
needsComma = true;
}
}
- for (int i = 0; i < e.arguments.size(); ++i) {
- const WaylandArgument &a = e.arguments.at(i);
+ for (const WaylandArgument &a : e.arguments) {
bool isNewId = a.type == "new_id";
if (isNewId && !isServerSide() && (a.interface.isEmpty() != e.request))
continue;
@@ -346,9 +356,8 @@ void Scanner::printEventHandlerSignature(const WaylandEvent &e, const char *inte
printf(" %svoid *data,\n", indent);
printf(" %sstruct ::%s *object", indent, interfaceName);
}
- for (int i = 0; i < e.arguments.size(); ++i) {
+ for (const WaylandArgument &a : e.arguments) {
printf(",\n");
- const WaylandArgument &a = e.arguments.at(i);
bool isNewId = a.type == "new_id";
if (isServerSide() && isNewId) {
printf(" %suint32_t %s", indent, a.name.constData());
@@ -360,17 +369,13 @@ void Scanner::printEventHandlerSignature(const WaylandEvent &e, const char *inte
printf(")");
}
-void Scanner::printEnums(const QList<WaylandEnum> &enums)
+void Scanner::printEnums(const std::vector<WaylandEnum> &enums)
{
- for (int i = 0; i < enums.size(); ++i) {
+ for (const WaylandEnum &e : enums) {
printf("\n");
- const WaylandEnum &e = enums.at(i);
printf(" enum %s {\n", e.name.constData());
- for (int i = 0; i < e.entries.size(); ++i) {
- const WaylandEnumEntry &entry = e.entries.at(i);
- printf(" %s_%s = %s", e.name.constData(), entry.name.constData(), entry.value.constData());
- if (i < e.entries.size() - 1)
- printf(",");
+ for (const WaylandEnumEntry &entry : e.entries) {
+ printf(" %s_%s = %s,", e.name.constData(), entry.name.constData(), entry.value.constData());
if (!entry.summary.isNull())
printf(" // %s", entry.summary.constData());
printf("\n");
@@ -424,11 +429,11 @@ bool Scanner::process()
//QByteArray preProcessorProtocolName = QByteArray(m_protocolName).replace('-', '_').toUpper();
QByteArray preProcessorProtocolName = QByteArray(m_protocolName).toUpper();
- QList<WaylandInterface> interfaces;
+ std::vector<WaylandInterface> interfaces;
while (m_xml->readNextStartElement()) {
if (m_xml->name() == "interface")
- interfaces << readInterface(*m_xml);
+ interfaces.push_back(readInterface(*m_xml));
else
m_xml->skipCurrentElement();
}
@@ -478,12 +483,16 @@ bool Scanner::process()
printf("\n");
printf("namespace QtWaylandServer {\n");
- for (int j = 0; j < interfaces.size(); ++j) {
- const WaylandInterface &interface = interfaces.at(j);
+ bool needsNewLine = false;
+ for (const WaylandInterface &interface : interfaces) {
if (ignoreInterface(interface.name))
continue;
+ if (needsNewLine)
+ printf("\n");
+ needsNewLine = true;
+
const char *interfaceName = interface.name.constData();
QByteArray stripped = stripInterfaceName(interface.name);
@@ -538,11 +547,11 @@ bool Scanner::process()
printEnums(interface.enums);
- bool hasEvents = !interface.events.isEmpty();
+ bool hasEvents = !interface.events.empty();
if (hasEvents) {
printf("\n");
- foreach (const WaylandEvent &e, interface.events) {
+ for (const WaylandEvent &e : interface.events) {
printf(" void send_");
printEvent(e);
printf(";\n");
@@ -559,11 +568,11 @@ bool Scanner::process()
printf(" virtual void %s_bind_resource(Resource *resource);\n", interfaceNameStripped);
printf(" virtual void %s_destroy_resource(Resource *resource);\n", interfaceNameStripped);
- bool hasRequests = !interface.requests.isEmpty();
+ bool hasRequests = !interface.requests.empty();
if (hasRequests) {
printf("\n");
- foreach (const WaylandEvent &e, interface.requests) {
+ for (const WaylandEvent &e : interface.requests) {
printf(" virtual void %s_", interfaceNameStripped);
printEvent(e);
printf(";\n");
@@ -584,8 +593,7 @@ bool Scanner::process()
printf(" static const struct ::%s_interface m_%s_interface;\n", interfaceName, interfaceName);
printf("\n");
- for (int i = 0; i < interface.requests.size(); ++i) {
- const WaylandEvent &e = interface.requests.at(i);
+ for (const WaylandEvent &e : interface.requests) {
printf(" static void ");
printEventHandlerSignature(e, interfaceName);
@@ -603,9 +611,6 @@ bool Scanner::process()
printf(" };\n");
printf(" DisplayDestroyedListener m_displayDestroyedListener;\n");
printf(" };\n");
-
- if (j < interfaces.size() - 1)
- printf("\n");
}
printf("}\n");
@@ -629,8 +634,7 @@ bool Scanner::process()
printf("namespace QtWaylandServer {\n");
bool needsNewLine = false;
- for (int j = 0; j < interfaces.size(); ++j) {
- const WaylandInterface &interface = interfaces.at(j);
+ for (const WaylandInterface &interface : interfaces) {
if (ignoreInterface(interface.name))
continue;
@@ -778,7 +782,7 @@ bool Scanner::process()
printf(" }\n");
printf("\n");
- bool hasRequests = !interface.requests.isEmpty();
+ bool hasRequests = !interface.requests.empty();
QByteArray interfaceMember = hasRequests ? "&m_" + interface.name + "_interface" : QByteArray("nullptr");
@@ -816,17 +820,18 @@ bool Scanner::process()
if (hasRequests) {
printf("\n");
printf(" const struct ::%s_interface %s::m_%s_interface = {", interfaceName, interfaceName, interfaceName);
- for (int i = 0; i < interface.requests.size(); ++i) {
- if (i > 0)
+ bool needsComma = false;
+ for (const WaylandEvent &e : interface.requests) {
+ if (needsComma)
printf(",");
+ needsComma = true;
printf("\n");
- const WaylandEvent &e = interface.requests.at(i);
printf(" %s::handle_%s", interfaceName, e.name.constData());
}
printf("\n");
printf(" };\n");
- foreach (const WaylandEvent &e, interface.requests) {
+ for (const WaylandEvent &e : interface.requests) {
printf("\n");
printf(" void %s::%s_", interfaceName, interfaceNameStripped);
printEvent(e, true);
@@ -836,11 +841,10 @@ bool Scanner::process()
}
printf("\n");
- for (int i = 0; i < interface.requests.size(); ++i) {
+ for (const WaylandEvent &e : interface.requests) {
printf("\n");
printf(" void %s::", interfaceName);
- const WaylandEvent &e = interface.requests.at(i);
printEventHandlerSignature(e, interfaceName, false);
printf("\n");
@@ -849,9 +853,8 @@ bool Scanner::process()
printf(" Resource *r = Resource::fromResource(resource);\n");
printf(" static_cast<%s *>(r->%s_object)->%s_%s(\n", interfaceName, interfaceNameStripped, interfaceNameStripped, e.name.constData());
printf(" r");
- for (int i = 0; i < e.arguments.size(); ++i) {
+ for (const WaylandArgument &a : e.arguments) {
printf(",\n");
- const WaylandArgument &a = e.arguments.at(i);
QByteArray cType = waylandToCType(a.type, a.interface);
QByteArray qtType = waylandToQtType(a.type, a.interface, e.request);
const char *argumentName = a.name.constData();
@@ -865,17 +868,15 @@ bool Scanner::process()
}
}
- for (int i = 0; i < interface.events.size(); ++i) {
+ for (const WaylandEvent &e : interface.events) {
printf("\n");
- const WaylandEvent &e = interface.events.at(i);
printf(" void %s::send_", interfaceName);
printEvent(e);
printf("\n");
printf(" {\n");
printf(" send_%s(\n", e.name.constData());
printf(" m_resource->handle");
- for (int i = 0; i < e.arguments.size(); ++i) {
- const WaylandArgument &a = e.arguments.at(i);
+ for (const WaylandArgument &a : e.arguments) {
printf(",\n");
printf(" %s", a.name.constData());
}
@@ -888,8 +889,7 @@ bool Scanner::process()
printf("\n");
printf(" {\n");
- for (int i = 0; i < e.arguments.size(); ++i) {
- const WaylandArgument &a = e.arguments.at(i);
+ for (const WaylandArgument &a : e.arguments) {
if (a.type != "array")
continue;
QByteArray array = a.name + "_data";
@@ -905,8 +905,7 @@ bool Scanner::process()
printf(" %s_send_%s(\n", interfaceName, e.name.constData());
printf(" resource");
- for (int i = 0; i < e.arguments.size(); ++i) {
- const WaylandArgument &a = e.arguments.at(i);
+ for (const WaylandArgument &a : e.arguments) {
printf(",\n");
QByteArray cType = waylandToCType(a.type, a.interface);
QByteArray qtType = waylandToQtType(a.type, a.interface, e.request);
@@ -962,12 +961,17 @@ bool Scanner::process()
}
printf("\n");
printf("namespace QtWayland {\n");
- for (int j = 0; j < interfaces.size(); ++j) {
- const WaylandInterface &interface = interfaces.at(j);
+
+ bool needsNewLine = false;
+ for (const WaylandInterface &interface : interfaces) {
if (ignoreInterface(interface.name))
continue;
+ if (needsNewLine)
+ printf("\n");
+ needsNewLine = true;
+
const char *interfaceName = interface.name.constData();
QByteArray stripped = stripInterfaceName(interface.name);
@@ -994,9 +998,9 @@ bool Scanner::process()
printEnums(interface.enums);
- if (!interface.requests.isEmpty()) {
+ if (!interface.requests.empty()) {
printf("\n");
- foreach (const WaylandEvent &e, interface.requests) {
+ for (const WaylandEvent &e : interface.requests) {
const WaylandArgument *new_id = newIdArgument(e.arguments);
QByteArray new_id_str = "void ";
if (new_id) {
@@ -1011,12 +1015,12 @@ bool Scanner::process()
}
}
- bool hasEvents = !interface.events.isEmpty();
+ bool hasEvents = !interface.events.empty();
if (hasEvents) {
printf("\n");
printf(" protected:\n");
- foreach (const WaylandEvent &e, interface.events) {
+ for (const WaylandEvent &e : interface.events) {
printf(" virtual void %s_", interfaceNameStripped);
printEvent(e);
printf(";\n");
@@ -1028,8 +1032,7 @@ bool Scanner::process()
if (hasEvents) {
printf(" void init_listener();\n");
printf(" static const struct %s_listener m_%s_listener;\n", interfaceName, interfaceName);
- for (int i = 0; i < interface.events.size(); ++i) {
- const WaylandEvent &e = interface.events.at(i);
+ for (const WaylandEvent &e : interface.events) {
printf(" static void ");
printEventHandlerSignature(e, interfaceName);
@@ -1038,9 +1041,6 @@ bool Scanner::process()
}
printf(" struct ::%s *m_%s;\n", interfaceName, interfaceName);
printf(" };\n");
-
- if (j < interfaces.size() - 1)
- printf("\n");
}
printf("}\n");
printf("\n");
@@ -1077,18 +1077,23 @@ bool Scanner::process()
printf("#endif\n");
printf("}\n");
printf("\n");
- for (int j = 0; j < interfaces.size(); ++j) {
- const WaylandInterface &interface = interfaces.at(j);
+
+ bool needsNewLine = false;
+ for (const WaylandInterface &interface : interfaces) {
if (ignoreInterface(interface.name))
continue;
+ if (needsNewLine)
+ printf("\n");
+ needsNewLine = true;
+
const char *interfaceName = interface.name.constData();
QByteArray stripped = stripInterfaceName(interface.name);
const char *interfaceNameStripped = stripped.constData();
- bool hasEvents = !interface.events.isEmpty();
+ bool hasEvents = !interface.events.empty();
printf(" %s::%s(struct ::wl_registry *registry, int id, int version)\n", interfaceName, interfaceName);
printf(" {\n");
@@ -1152,9 +1157,8 @@ bool Scanner::process()
printf(" return &::%s_interface;\n", interfaceName);
printf(" }\n");
- for (int i = 0; i < interface.requests.size(); ++i) {
+ for (const WaylandEvent &e : interface.requests) {
printf("\n");
- const WaylandEvent &e = interface.requests.at(i);
const WaylandArgument *new_id = newIdArgument(e.arguments);
QByteArray new_id_str = "void ";
if (new_id) {
@@ -1167,8 +1171,7 @@ bool Scanner::process()
printEvent(e);
printf("\n");
printf(" {\n");
- for (int i = 0; i < e.arguments.size(); ++i) {
- const WaylandArgument &a = e.arguments.at(i);
+ for (const WaylandArgument &a : e.arguments) {
if (a.type != "array")
continue;
QByteArray array = a.name + "_data";
@@ -1180,12 +1183,11 @@ bool Scanner::process()
printf(" %s.alloc = 0;\n", arrayName);
printf("\n");
}
- int actualArgumentCount = new_id ? e.arguments.size() - 1 : e.arguments.size();
+ int actualArgumentCount = new_id ? int(e.arguments.size()) - 1 : int(e.arguments.size());
printf(" %s%s_%s(\n", new_id ? "return " : "", interfaceName, e.name.constData());
printf(" m_%s%s", interfaceName, actualArgumentCount > 0 ? "," : "");
bool needsComma = false;
- for (int i = 0; i < e.arguments.size(); ++i) {
- const WaylandArgument &a = e.arguments.at(i);
+ for (const WaylandArgument &a : e.arguments) {
bool isNewId = a.type == "new_id";
if (isNewId && !a.interface.isEmpty())
continue;
@@ -1215,8 +1217,7 @@ bool Scanner::process()
if (hasEvents) {
printf("\n");
- for (int i = 0; i < interface.events.size(); ++i) {
- const WaylandEvent &e = interface.events.at(i);
+ for (const WaylandEvent &e : interface.events) {
printf(" void %s::%s_", interfaceName, interfaceNameStripped);
printEvent(e, true);
printf("\n");
@@ -1229,17 +1230,17 @@ bool Scanner::process()
printf(" {\n");
printf(" Q_UNUSED(object);\n");
printf(" static_cast<%s *>(data)->%s_%s(", interfaceName, interfaceNameStripped, e.name.constData());
- for (int i = 0; i < e.arguments.size(); ++i) {
+ bool needsComma = false;
+ for (const WaylandArgument &a : e.arguments) {
+ if (needsComma)
+ printf(",");
+ needsComma = true;
printf("\n");
- const WaylandArgument &a = e.arguments.at(i);
const char *argumentName = a.name.constData();
if (a.type == "string")
printf(" QString::fromUtf8(%s)", argumentName);
else
printf(" %s", argumentName);
-
- if (i < e.arguments.size() - 1)
- printf(",");
}
printf(");\n");
@@ -1247,9 +1248,8 @@ bool Scanner::process()
printf("\n");
}
printf(" const struct %s_listener %s::m_%s_listener = {\n", interfaceName, interfaceName, interfaceName);
- for (int i = 0; i < interface.events.size(); ++i) {
- const WaylandEvent &e = interface.events.at(i);
- printf(" %s::handle_%s%s\n", interfaceName, e.name.constData(), i < interface.events.size() - 1 ? "," : "");
+ for (const WaylandEvent &e : interface.events) {
+ printf(" %s::handle_%s,\n", interfaceName, e.name.constData());
}
printf(" };\n");
printf("\n");
@@ -1259,9 +1259,6 @@ bool Scanner::process()
printf(" %s_add_listener(m_%s, &m_%s_listener, this);\n", interfaceName, interfaceName, interfaceName);
printf(" }\n");
}
-
- if (j < interfaces.size() - 1)
- printf("\n");
}
printf("}\n");
printf("\n");
diff --git a/src/shared/qwaylandinputmethodeventbuilder.cpp b/src/shared/qwaylandinputmethodeventbuilder.cpp
index 88056637d..526d0ef46 100644
--- a/src/shared/qwaylandinputmethodeventbuilder.cpp
+++ b/src/shared/qwaylandinputmethodeventbuilder.cpp
@@ -157,7 +157,7 @@ QInputMethodEvent QWaylandInputMethodEventBuilder::buildPreedit(const QString &t
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, indexFromWayland(text, m_preeditCursor), 1, QVariant()));
}
- Q_FOREACH (const QInputMethodEvent::Attribute &attr, m_preeditStyles) {
+ for (const QInputMethodEvent::Attribute &attr : qAsConst(m_preeditStyles)) {
int start = indexFromWayland(text, attr.start);
int length = indexFromWayland(text, attr.start + attr.length) - start;
attributes.append(QInputMethodEvent::Attribute(attr.type, start, length, attr.value));
diff --git a/src/src.pro b/src/src.pro
index d4244de33..3d68c69fb 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -3,21 +3,22 @@ include($$OUT_PWD/client/qtwaylandclient-config.pri)
include($$OUT_PWD/compositor/qtwaylandcompositor-config.pri)
QT_FOR_CONFIG += waylandclient-private waylandcompositor-private
-qtConfig(wayland-client) {
+qtConfig(wayland-client)|qtConfig(wayland-server) {
sub_qtwaylandscanner.subdir = qtwaylandscanner
sub_qtwaylandscanner.target = sub-qtwaylandscanner
SUBDIRS += sub_qtwaylandscanner
- sub_client.subdir = client
- sub_client.depends = sub-qtwaylandscanner
- sub_client.target = sub-client
- SUBDIRS += sub_client
+ qtConfig(wayland-client) {
+ sub_client.subdir = client
+ sub_client.depends = sub-qtwaylandscanner
+ sub_client.target = sub-client
+ SUBDIRS += sub_client
+ }
sub_plugins.subdir = plugins
- sub_plugins.depends += sub-qtwaylandscanner sub-client
- qtConfig(wayland-server) {
- sub_plugins.depends += sub-compositor
- }
+ sub_plugins.depends += sub-qtwaylandscanner
+ qtConfig(wayland-client):sub_plugins.depends += sub-client
+ qtConfig(wayland-server):sub_plugins.depends += sub-compositor
sub_plugins.target = sub-plugins
SUBDIRS += sub_plugins
@@ -26,10 +27,11 @@ qtConfig(wayland-client) {
sub_compositor.depends = sub-qtwaylandscanner
sub_compositor.target = sub-compositor
SUBDIRS += sub_compositor
-
- sub_imports.subdir = imports
- sub_imports.depends += sub-compositor sub-client
- sub_imports.target = sub-imports
- SUBDIRS += sub_imports
}
+
+ sub_imports.subdir = imports
+ qtConfig(wayland-client):sub_imports.depends += sub-client
+ qtConfig(wayland-server):sub_imports.depends += sub-compositor
+ sub_imports.target = sub-imports
+ SUBDIRS += sub_imports
}
diff --git a/sync.profile b/sync.profile
index 087bfcf55..572213457 100644
--- a/sync.profile
+++ b/sync.profile
@@ -27,6 +27,7 @@
"^qwayland-text-input-unstable-v2.h",
"^qwayland-touch-extension.h",
"^qwayland-wayland.h",
+ "^qwayland-wp-primary-selection-unstable-v1.h",
"^qwayland-xdg-output-unstable-v1.h",
"^wayland-hardware-integration-client-protocol.h",
"^wayland-qt-windowmanager-client-protocol.h",
@@ -36,6 +37,7 @@
"^wayland-text-input-unstable-v2-client-protocol.h",
"^wayland-touch-extension-client-protocol.h",
"^wayland-wayland-client-protocol.h",
+ "^wayland-wp-primary-selection-unstable-v1-client-protocol.h",
"^wayland-xdg-output-unstable-v1-client-protocol.h",
],
"$basedir/src/plugins/shellintegration/xdg-shell" => [
@@ -51,30 +53,34 @@
"$basedir/src/compositor" => [
"^qwayland-server-wayland.h",
"^qwayland-server-hardware-integration.h",
+ "^qwayland-server-idle-inhibit-unstable-v1.h",
"^qwayland-server-ivi-application.h",
"^qwayland-server-qt-windowmanager.h",
"^qwayland-server-qt-key-unstable-v1.h",
- "^qwayland-server-scaler.h",
"^qwayland-server-qt-texture-sharing-unstable-v1.h",
+ "^qwayland-server-scaler.h",
"^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-output-unstable-v1.h",
"^qwayland-server-xdg-shell-unstable-v6.h",
"^qwayland-server-xdg-shell.h",
"^wayland-hardware-integration-server-protocol.h",
+ "^wayland-idle-inhibit-unstable-v1-server-protocol.h",
"^wayland-ivi-application-server-protocol.h",
"^wayland-qt-windowmanager-server-protocol.h",
"^wayland-qt-key-unstable-v1-server-protocol.h",
- "^wayland-scaler-server-protocol.h",
"^wayland-qt-texture-sharing-unstable-v1-server-protocol.h",
+ "^wayland-scaler-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",
+ "^wayland-xdg-output-unstable-v1-server-protocol.h",
"^wayland-xdg-shell-server-protocol.h",
"^wayland-xdg-shell-unstable-v6-server-protocol.h",
],
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index d81339e86..032ae47a4 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -1,10 +1,11 @@
TEMPLATE=subdirs
QT_FOR_CONFIG += waylandclient-private
-!qtHaveModule(waylandcompositor): \
- return()
+qtHaveModule(waylandclient): \
+ SUBDIRS += client
-SUBDIRS += compositor
+qtHaveModule(waylandclient):qtHaveModule(waylandcompositor): \
+ SUBDIRS += cmake
-qtConfig(wayland-client): \
- SUBDIRS += client cmake
+qtHaveModule(waylandcompositor): \
+ SUBDIRS += compositor
diff --git a/tests/auto/client/client.pro b/tests/auto/client/client.pro
index 06c1cb877..4b1eb2458 100644
--- a/tests/auto/client/client.pro
+++ b/tests/auto/client/client.pro
@@ -6,7 +6,9 @@ SUBDIRS += \
fullscreenshellv1 \
iviapplication \
output \
+ primaryselectionv1 \
seatv4 \
+ seatv5 \
surface \
wl_connect \
xdgdecorationv1 \
diff --git a/tests/auto/client/client/tst_client.cpp b/tests/auto/client/client/tst_client.cpp
index 83b9e6ce0..e19acff7c 100644
--- a/tests/auto/client/client/tst_client.cpp
+++ b/tests/auto/client/client/tst_client.cpp
@@ -36,7 +36,9 @@
#include <QPixmap>
#include <QDrag>
#include <QWindow>
+#if QT_CONFIG(opengl)
#include <QOpenGLWindow>
+#endif
#include <QtTest/QtTest>
#include <QtWaylandClient/private/qwaylandintegration_p.h>
@@ -107,6 +109,7 @@ public:
QPoint mousePressPos;
};
+#if QT_CONFIG(opengl)
class TestGlWindow : public QOpenGLWindow
{
Q_OBJECT
@@ -136,6 +139,7 @@ void TestGlWindow::paintGL()
glClear(GL_COLOR_BUFFER_BIT);
++paintGLCalled;
}
+#endif // QT_CONFIG(opengl)
class tst_WaylandClient : public QObject
{
@@ -176,7 +180,9 @@ private slots:
void dontCrashOnMultipleCommits();
void hiddenTransientParent();
void hiddenPopupParent();
+#if QT_CONFIG(opengl)
void glWindow();
+#endif // QT_CONFIG(opengl)
void longWindowTitle();
void longWindowTitleWithUtf16Characters();
@@ -459,6 +465,7 @@ void tst_WaylandClient::hiddenPopupParent()
QTRY_VERIFY(compositor->surface());
}
+#if QT_CONFIG(opengl)
void tst_WaylandClient::glWindow()
{
QSKIP("Skipping GL tests, as not supported by all CI systems: See https://bugreports.qt.io/browse/QTBUG-65802");
@@ -484,6 +491,7 @@ void tst_WaylandClient::glWindow()
testWindow->setVisible(false);
QTRY_VERIFY(!compositor->surface());
}
+#endif // QT_CONFIG(opengl)
void tst_WaylandClient::longWindowTitle()
{
diff --git a/tests/auto/client/datadevicev1/tst_datadevicev1.cpp b/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
index 7368829d1..e3babceb5 100644
--- a/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
+++ b/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
@@ -66,7 +66,7 @@ void tst_datadevicev1::initTestCase()
{
QCOMPOSITOR_TRY_VERIFY(pointer());
QCOMPOSITOR_TRY_VERIFY(!pointer()->resourceMap().empty());
- QCOMPOSITOR_TRY_COMPARE(pointer()->resourceMap().first()->version(), 4);
+ QCOMPOSITOR_TRY_COMPARE(pointer()->resourceMap().first()->version(), 5);
QCOMPOSITOR_TRY_VERIFY(keyboard());
@@ -104,8 +104,11 @@ void tst_datadevicev1::pasteAscii()
keyboard()->sendEnter(surface); // Need to set keyboard focus according to protocol
pointer()->sendEnter(surface, {32, 32});
+ pointer()->sendFrame(client);
pointer()->sendButton(client, BTN_LEFT, 1);
+ pointer()->sendFrame(client);
pointer()->sendButton(client, BTN_LEFT, 0);
+ pointer()->sendFrame(client);
});
QTRY_COMPARE(window.m_text, "normal ascii");
}
@@ -139,8 +142,11 @@ void tst_datadevicev1::pasteUtf8()
keyboard()->sendEnter(surface); // Need to set keyboard focus according to protocol
pointer()->sendEnter(surface, {32, 32});
+ pointer()->sendFrame(client);
pointer()->sendButton(client, BTN_LEFT, 1);
+ pointer()->sendFrame(client);
pointer()->sendButton(client, BTN_LEFT, 0);
+ pointer()->sendFrame(client);
});
QTRY_COMPARE(window.m_text, "face with tears of joy: 😂");
}
diff --git a/tests/auto/client/inputcontext/inputcontext.pro b/tests/auto/client/inputcontext/inputcontext.pro
index 4419b3e77..1971d455e 100644
--- a/tests/auto/client/inputcontext/inputcontext.pro
+++ b/tests/auto/client/inputcontext/inputcontext.pro
@@ -1,6 +1,4 @@
include (../shared/shared.pri)
-QT += waylandcompositor
-
TARGET = tst_inputcontext
SOURCES += tst_inputcontext.cpp
diff --git a/tests/auto/client/output/tst_output.cpp b/tests/auto/client/output/tst_output.cpp
index 2d2c8efd6..29c773cf6 100644
--- a/tests/auto/client/output/tst_output.cpp
+++ b/tests/auto/client/output/tst_output.cpp
@@ -196,8 +196,11 @@ void tst_output::removePrimaryScreen()
exec([&] {
auto *surface = xdgToplevel()->surface();
pointer()->sendEnter(surface, {32, 32});
+ pointer()->sendFrame(client());
pointer()->sendButton(client(), BTN_LEFT, 1);
+ pointer()->sendFrame(client());
pointer()->sendButton(client(), BTN_LEFT, 0);
+ pointer()->sendFrame(client());
});
// Wait to make sure mouse events dont't cause a crash now that the screen has changed
diff --git a/tests/auto/client/primaryselectionv1/primaryselectionv1.pro b/tests/auto/client/primaryselectionv1/primaryselectionv1.pro
new file mode 100644
index 000000000..9d00562df
--- /dev/null
+++ b/tests/auto/client/primaryselectionv1/primaryselectionv1.pro
@@ -0,0 +1,7 @@
+include (../shared/shared.pri)
+
+WAYLANDSERVERSOURCES += \
+ $$PWD/../../../../src/3rdparty/protocol/wp-primary-selection-unstable-v1.xml
+
+TARGET = tst_primaryselectionv1
+SOURCES += tst_primaryselectionv1.cpp
diff --git a/tests/auto/client/primaryselectionv1/tst_primaryselectionv1.cpp b/tests/auto/client/primaryselectionv1/tst_primaryselectionv1.cpp
new file mode 100644
index 000000000..216db85cd
--- /dev/null
+++ b/tests/auto/client/primaryselectionv1/tst_primaryselectionv1.cpp
@@ -0,0 +1,475 @@
+/****************************************************************************
+**
+** 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 <qwayland-server-wp-primary-selection-unstable-v1.h>
+
+#include <QtGui/QRasterWindow>
+#include <QtGui/QOpenGLWindow>
+#include <QtGui/QClipboard>
+#include <QtCore/private/qcore_unix_p.h>
+
+#include <fcntl.h>
+
+using namespace MockCompositor;
+
+constexpr int primarySelectionVersion = 1; // protocol VERSION, not the name suffix (_v1)
+
+class PrimarySelectionDeviceV1;
+class PrimarySelectionDeviceManagerV1;
+
+class PrimarySelectionOfferV1 : public QObject, public QtWaylandServer::zwp_primary_selection_offer_v1
+{
+ Q_OBJECT
+public:
+ explicit PrimarySelectionOfferV1(PrimarySelectionDeviceV1 *device, wl_client *client, int version)
+ : zwp_primary_selection_offer_v1(client, 0, version)
+ , m_device(device)
+ {}
+ void send_offer() = delete;
+ void sendOffer(const QString &offer)
+ {
+ zwp_primary_selection_offer_v1::send_offer(offer);
+ m_mimeTypes << offer;
+ }
+
+ PrimarySelectionDeviceV1 *m_device = nullptr;
+ QStringList m_mimeTypes;
+
+signals:
+ void receive(QString mimeType, int fd);
+
+protected:
+ void zwp_primary_selection_offer_v1_destroy_resource(Resource *resource) override
+ {
+ Q_UNUSED(resource);
+ delete this;
+ }
+
+ void zwp_primary_selection_offer_v1_receive(Resource *resource, const QString &mime_type, int32_t fd) override
+ {
+ Q_UNUSED(resource);
+ QTRY_VERIFY(m_mimeTypes.contains(mime_type));
+ emit receive(mime_type, fd);
+ }
+
+ void zwp_primary_selection_offer_v1_destroy(Resource *resource) override;
+};
+
+class PrimarySelectionSourceV1 : public QObject, public QtWaylandServer::zwp_primary_selection_source_v1
+{
+ Q_OBJECT
+public:
+ explicit PrimarySelectionSourceV1(wl_client *client, int id, int version)
+ : zwp_primary_selection_source_v1(client, id, version)
+ {
+ }
+ QStringList m_offers;
+protected:
+ void zwp_primary_selection_source_v1_destroy_resource(Resource *resource) override
+ {
+ Q_UNUSED(resource);
+ delete this;
+ }
+ void zwp_primary_selection_source_v1_offer(Resource *resource, const QString &mime_type) override
+ {
+ Q_UNUSED(resource);
+ m_offers << mime_type;
+ }
+ void zwp_primary_selection_source_v1_destroy(Resource *resource) override
+ {
+ wl_resource_destroy(resource->handle);
+ }
+};
+
+class PrimarySelectionDeviceV1 : public QObject, public QtWaylandServer::zwp_primary_selection_device_v1
+{
+ Q_OBJECT
+public:
+ explicit PrimarySelectionDeviceV1(PrimarySelectionDeviceManagerV1 *manager, Seat *seat)
+ : m_manager(manager)
+ , m_seat(seat)
+ {}
+
+ void send_data_offer(::wl_resource *resource) = delete;
+
+ PrimarySelectionOfferV1 *sendDataOffer(::wl_client *client, const QStringList &mimeTypes = {});
+
+ PrimarySelectionOfferV1 *sendDataOffer(const QStringList &mimeTypes = {}) // creates a new offer for the focused surface and sends it
+ {
+ Q_ASSERT(m_seat->m_capabilities & Seat::capability_keyboard);
+ Q_ASSERT(m_seat->m_keyboard->m_enteredSurface);
+ auto *client = m_seat->m_keyboard->m_enteredSurface->resource()->client();
+ return sendDataOffer(client, mimeTypes);
+ }
+
+ void send_selection(::wl_resource *resource) = delete;
+ void sendSelection(PrimarySelectionOfferV1 *offer)
+ {
+ auto *client = offer->resource()->client();
+ for (auto *resource : resourceMap().values(client))
+ zwp_primary_selection_device_v1::send_selection(resource->handle, offer->resource()->handle);
+ m_sentSelectionOffers << offer;
+ }
+
+ PrimarySelectionDeviceManagerV1 *m_manager = nullptr;
+ Seat *m_seat = nullptr;
+ QVector<PrimarySelectionOfferV1 *> m_sentSelectionOffers;
+ PrimarySelectionSourceV1 *m_selectionSource = nullptr;
+ uint m_serial = 0;
+
+protected:
+ void zwp_primary_selection_device_v1_set_selection(Resource *resource, ::wl_resource *source, uint32_t serial) override
+ {
+ Q_UNUSED(resource);
+ m_selectionSource = fromResource<PrimarySelectionSourceV1>(source);
+ m_serial = serial;
+ }
+ void zwp_primary_selection_device_v1_destroy(Resource *resource) override
+ {
+ wl_resource_destroy(resource->handle);
+ }
+ void zwp_primary_selection_device_v1_destroy_resource(Resource *resource) override
+ {
+ Q_UNUSED(resource);
+ delete this;
+ }
+};
+
+class PrimarySelectionDeviceManagerV1 : public Global, public QtWaylandServer::zwp_primary_selection_device_manager_v1
+{
+ Q_OBJECT
+public:
+ explicit PrimarySelectionDeviceManagerV1(CoreCompositor *compositor, int version = 1)
+ : QtWaylandServer::zwp_primary_selection_device_manager_v1(compositor->m_display, version)
+ , m_version(version)
+ {}
+ bool isClean() override
+ {
+ for (auto *device : qAsConst(m_devices)) {
+ // The client should not leak selection offers, i.e. if this fails, there is a missing
+ // zwp_primary_selection_offer_v1.destroy request
+ if (!device->m_sentSelectionOffers.empty())
+ return false;
+ }
+ return true;
+ }
+
+ PrimarySelectionDeviceV1 *deviceFor(Seat *seat)
+ {
+ Q_ASSERT(seat);
+ if (auto *device = m_devices.value(seat, nullptr))
+ return device;
+
+ auto *device = new PrimarySelectionDeviceV1(this, seat);
+ m_devices[seat] = device;
+ return device;
+ }
+
+ int m_version = 1; // TODO: Remove on libwayland upgrade
+ QMap<Seat *, PrimarySelectionDeviceV1 *> m_devices;
+ QVector<PrimarySelectionSourceV1 *> m_sources;
+protected:
+ void zwp_primary_selection_device_manager_v1_destroy(Resource *resource) override
+ {
+ // The protocol doesn't say whether managed objects should be destroyed as well,
+ // so leave them alone, they'll be cleaned up in the destructor anyway
+ wl_resource_destroy(resource->handle);
+ }
+
+ void zwp_primary_selection_device_manager_v1_create_source(Resource *resource, uint32_t id) override
+ {
+ int version = m_version;
+ m_sources << new PrimarySelectionSourceV1(resource->client(), id, version);
+ }
+ void zwp_primary_selection_device_manager_v1_get_device(Resource *resource, uint32_t id, ::wl_resource *seatResource) override
+ {
+ auto *seat = fromResource<Seat>(seatResource);
+ QVERIFY(seat);
+ auto *device = deviceFor(seat);
+ device->add(resource->client(), id, resource->version());
+ }
+};
+
+PrimarySelectionOfferV1 *PrimarySelectionDeviceV1::sendDataOffer(wl_client *client, const QStringList &mimeTypes)
+{
+ Q_ASSERT(client);
+ auto *offer = new PrimarySelectionOfferV1(this, client, m_manager->m_version);
+ for (auto *resource : resourceMap().values(client))
+ zwp_primary_selection_device_v1::send_data_offer(resource->handle, offer->resource()->handle);
+ for (const auto &mimeType : mimeTypes)
+ offer->sendOffer(mimeType);
+ return offer;
+}
+
+void PrimarySelectionOfferV1::zwp_primary_selection_offer_v1_destroy(QtWaylandServer::zwp_primary_selection_offer_v1::Resource *resource)
+{
+ bool removed = m_device->m_sentSelectionOffers.removeOne(this);
+ QVERIFY(removed);
+ wl_resource_destroy(resource->handle);
+}
+
+class PrimarySelectionCompositor : public DefaultCompositor {
+public:
+ explicit PrimarySelectionCompositor()
+ {
+ exec([this] {
+ m_config.autoConfigure = true;
+ add<PrimarySelectionDeviceManagerV1>(primarySelectionVersion);
+ });
+ }
+ PrimarySelectionDeviceV1 *primarySelectionDevice(int i = 0) {
+ return get<PrimarySelectionDeviceManagerV1>()->deviceFor(get<Seat>(i));
+ }
+};
+
+class tst_primaryselectionv1 : public QObject, private PrimarySelectionCompositor
+{
+ Q_OBJECT
+private slots:
+ void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); }
+ void initTestCase();
+ void bindsToManager();
+ void createsPrimaryDevice();
+ void createsPrimaryDeviceForNewSeats();
+ void pasteAscii();
+ void pasteUtf8();
+ void destroysPreviousSelection();
+ void copy();
+};
+
+void tst_primaryselectionv1::initTestCase()
+{
+ QCOMPOSITOR_TRY_VERIFY(pointer());
+ QCOMPOSITOR_TRY_VERIFY(!pointer()->resourceMap().empty());
+ QCOMPOSITOR_TRY_COMPARE(pointer()->resourceMap().first()->version(), 5);
+
+ QCOMPOSITOR_TRY_VERIFY(keyboard());
+}
+
+void tst_primaryselectionv1::bindsToManager()
+{
+ QCOMPOSITOR_TRY_COMPARE(get<PrimarySelectionDeviceManagerV1>()->resourceMap().size(), 1);
+ QCOMPOSITOR_TRY_COMPARE(get<PrimarySelectionDeviceManagerV1>()->resourceMap().first()->version(), primarySelectionVersion);
+}
+
+void tst_primaryselectionv1::createsPrimaryDevice()
+{
+ QCOMPOSITOR_TRY_VERIFY(primarySelectionDevice());
+ QCOMPOSITOR_TRY_VERIFY(primarySelectionDevice()->resourceMap().contains(client()));
+ QCOMPOSITOR_TRY_COMPARE(primarySelectionDevice()->resourceMap().value(client())->version(), primarySelectionVersion);
+ QTRY_VERIFY(QGuiApplication::clipboard()->supportsSelection());
+}
+
+void tst_primaryselectionv1::createsPrimaryDeviceForNewSeats()
+{
+ exec([=] { add<Seat>(); });
+ QCOMPOSITOR_TRY_VERIFY(primarySelectionDevice(1));
+}
+
+void tst_primaryselectionv1::pasteAscii()
+{
+ class Window : public QRasterWindow {
+ public:
+ void mousePressEvent(QMouseEvent *event) override
+ {
+ Q_UNUSED(event);
+ auto *mimeData = QGuiApplication::clipboard()->mimeData(QClipboard::Selection);
+ m_formats = mimeData->formats();
+ m_text = QGuiApplication::clipboard()->text(QClipboard::Selection);
+ }
+ QStringList m_formats;
+ QString m_text;
+ };
+
+ Window window;
+ window.resize(64, 64);
+ window.show();
+
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+ exec([&] {
+ auto *surface = xdgSurface()->m_surface;
+ keyboard()->sendEnter(surface); // Need to set keyboard focus according to protocol
+
+ auto *device = primarySelectionDevice();
+ auto *offer = device->sendDataOffer({"text/plain"});
+ connect(offer, &PrimarySelectionOfferV1::receive, [](QString mimeType, int fd) {
+ QFile file;
+ file.open(fd, QIODevice::WriteOnly, QFile::FileHandleFlag::AutoCloseHandle);
+ QCOMPARE(mimeType, "text/plain");
+ file.write(QByteArray("normal ascii"));
+ file.close();
+ });
+ device->sendSelection(offer);
+
+ pointer()->sendEnter(surface, {32, 32});
+ pointer()->sendFrame(client());
+ pointer()->sendButton(client(), BTN_MIDDLE, 1);
+ pointer()->sendFrame(client());
+ pointer()->sendButton(client(), BTN_MIDDLE, 0);
+ pointer()->sendFrame(client());
+ });
+ QTRY_COMPARE(window.m_formats, QStringList{"text/plain"});
+ QTRY_COMPARE(window.m_text, "normal ascii");
+}
+
+void tst_primaryselectionv1::pasteUtf8()
+{
+ class Window : public QRasterWindow {
+ public:
+ void mousePressEvent(QMouseEvent *event) override
+ {
+ Q_UNUSED(event);
+ auto *mimeData = QGuiApplication::clipboard()->mimeData(QClipboard::Selection);
+ m_formats = mimeData->formats();
+ m_text = QGuiApplication::clipboard()->text(QClipboard::Selection);
+ }
+ QStringList m_formats;
+ QString m_text;
+ };
+
+ Window window;
+ window.resize(64, 64);
+ window.show();
+
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+ exec([&] {
+ auto *surface = xdgSurface()->m_surface;
+ keyboard()->sendEnter(surface); // Need to set keyboard focus according to protocol
+
+ auto *device = primarySelectionDevice();
+ auto *offer = device->sendDataOffer({"text/plain", "text/plain;charset=utf-8"});
+ connect(offer, &PrimarySelectionOfferV1::receive, [](QString mimeType, int fd) {
+ QFile file;
+ file.open(fd, QIODevice::WriteOnly, QFile::FileHandleFlag::AutoCloseHandle);
+ QCOMPARE(mimeType, "text/plain;charset=utf-8");
+ file.write(QByteArray("face with tears of joy: 😂"));
+ file.close();
+ });
+ device->sendSelection(offer);
+
+ pointer()->sendEnter(surface, {32, 32});
+ pointer()->sendFrame(client());
+ pointer()->sendButton(client(), BTN_MIDDLE, 1);
+ pointer()->sendFrame(client());
+ pointer()->sendButton(client(), BTN_MIDDLE, 0);
+ pointer()->sendFrame(client());
+ });
+ QTRY_COMPARE(window.m_formats, QStringList({"text/plain", "text/plain;charset=utf-8"}));
+ QTRY_COMPARE(window.m_text, "face with tears of joy: 😂");
+}
+
+void tst_primaryselectionv1::destroysPreviousSelection()
+{
+ QRasterWindow window;
+ window.resize(64, 64);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ // When the client receives a selection event, it is required to destroy the previous offer
+ exec([&] {
+ auto *surface = xdgSurface()->m_surface;
+ keyboard()->sendEnter(surface); // Need to set keyboard focus according to protocol
+
+ auto *offer = primarySelectionDevice()->sendDataOffer({"text/plain"});
+ primarySelectionDevice()->sendSelection(offer);
+ });
+
+ exec([&] {
+ auto *offer = primarySelectionDevice()->sendDataOffer({"text/plain"});
+ primarySelectionDevice()->sendSelection(offer);
+ QCOMPARE(primarySelectionDevice()->m_sentSelectionOffers.size(), 2);
+ });
+
+ // Verify the first offer gets destroyed
+ QCOMPOSITOR_TRY_COMPARE(primarySelectionDevice()->m_sentSelectionOffers.size(), 1);
+}
+
+void tst_primaryselectionv1::copy()
+{
+ class Window : public QRasterWindow {
+ public:
+ void mousePressEvent(QMouseEvent *event) override
+ {
+ Q_UNUSED(event);
+ QGuiApplication::clipboard()->setText("face with tears of joy: 😂", QClipboard::Selection);
+ }
+ QStringList m_formats;
+ QString m_text;
+ };
+
+ Window window;
+ window.resize(64, 64);
+ window.show();
+
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+ QVector<uint> mouseSerials;
+ exec([&] {
+ auto *surface = xdgSurface()->m_surface;
+ keyboard()->sendEnter(surface); // Need to set keyboard focus according to protocol
+ pointer()->sendEnter(surface, {32, 32});
+ pointer()->sendFrame(client());
+ mouseSerials << pointer()->sendButton(client(), BTN_MIDDLE, 1);
+ pointer()->sendFrame(client());
+ mouseSerials << pointer()->sendButton(client(), BTN_MIDDLE, 0);
+ pointer()->sendFrame(client());
+ });
+ QCOMPOSITOR_TRY_VERIFY(primarySelectionDevice()->m_selectionSource);
+ QCOMPOSITOR_TRY_VERIFY(mouseSerials.contains(primarySelectionDevice()->m_serial));
+ QByteArray pastedBuf;
+ exec([&](){
+ auto *source = primarySelectionDevice()->m_selectionSource;
+ QCOMPARE(source->m_offers, QStringList({"text/plain", "text/plain;charset=utf-8"}));
+ int fd[2];
+ if (pipe(fd) == -1)
+ QSKIP("Failed to create pipe");
+ fcntl(fd[0], F_SETFL, fcntl(fd[0], F_GETFL, 0) | O_NONBLOCK);
+ source->send_send("text/plain;charset=utf-8", fd[1]);
+ auto *notifier = new QSocketNotifier(fd[0], QSocketNotifier::Read, this);
+ connect(notifier, &QSocketNotifier::activated, this, [&](int fd) {
+ exec([&]{
+ static char buf[1024];
+ int n = QT_READ(fd, buf, sizeof buf);
+ if (n <= 0) {
+ delete notifier;
+ close(fd);
+ } else {
+ pastedBuf.append(buf, n);
+ }
+ });
+ });
+ });
+
+ QCOMPOSITOR_TRY_VERIFY(pastedBuf.size()); // this assumes we got everything in one read
+ auto pasted = QString::fromUtf8(pastedBuf);
+ QCOMPARE(pasted, "face with tears of joy: 😂");
+}
+
+QCOMPOSITOR_TEST_MAIN(tst_primaryselectionv1)
+#include "tst_primaryselectionv1.moc"
diff --git a/tests/auto/client/seatv4/BLACKLIST b/tests/auto/client/seatv4/BLACKLIST
new file mode 100644
index 000000000..1c761a74e
--- /dev/null
+++ b/tests/auto/client/seatv4/BLACKLIST
@@ -0,0 +1,2 @@
+[animatedCursor]
+b2qt
diff --git a/tests/auto/client/seatv4/tst_seatv4.cpp b/tests/auto/client/seatv4/tst_seatv4.cpp
index 1d6fb6b9c..2e17bef87 100644
--- a/tests/auto/client/seatv4/tst_seatv4.cpp
+++ b/tests/auto/client/seatv4/tst_seatv4.cpp
@@ -81,6 +81,7 @@ private slots:
void bitmapCursor();
void hidpiBitmapCursor();
void hidpiBitmapCursorNonInt();
+ void animatedCursor();
#endif
};
@@ -236,22 +237,20 @@ 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};
+ QTest::newRow("down") << uint(Pointer::axis_vertical_scroll) << 1.0 << QPoint{0, -12};
+ QTest::newRow("up") << uint(Pointer::axis_vertical_scroll) << -1.0 << QPoint{0, 12};
+ QTest::newRow("left") << uint(Pointer::axis_horizontal_scroll) << 1.0 << QPoint{-12, 0};
+ QTest::newRow("right") << uint(Pointer::axis_horizontal_scroll) << -1.0 << QPoint{12, 0};
+ QTest::newRow("up big") << uint(Pointer::axis_vertical_scroll) << -10.0 << QPoint{0, 120};
}
void tst_seatv4::simpleAxis()
{
QFETCH(uint, axis);
QFETCH(qreal, value);
- QFETCH(Qt::Orientation, orientation);
QFETCH(QPoint, angleDelta);
class WheelWindow : QRasterWindow {
@@ -280,27 +279,18 @@ void tst_seatv4::simpleAxis()
// 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()));
+ m_events.append(Event{event->pixelDelta(), event->angleDelta()});
}
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;
};
@@ -323,7 +313,6 @@ void tst_seatv4::simpleAxis()
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()
@@ -579,6 +568,36 @@ void tst_seatv4::hidpiBitmapCursorNonInt()
QCOMPOSITOR_COMPARE(pointer()->m_hotspot, QPoint(25, 25));
}
+void tst_seatv4::animatedCursor()
+{
+ QRasterWindow window;
+ window.resize(64, 64);
+ window.setCursor(Qt::WaitCursor); // TODO: verify that the theme has an animated wait cursor or skip test
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ exec([=] { pointer()->sendEnter(xdgSurface()->m_surface, {32, 32}); });
+ QCOMPOSITOR_TRY_VERIFY(cursorSurface());
+
+ // We should get the first buffer without waiting for a frame callback
+ QCOMPOSITOR_TRY_VERIFY(cursorSurface()->m_committed.buffer);
+ QSignalSpy bufferSpy(exec([=] { return cursorSurface(); }), &Surface::bufferCommitted);
+
+ exec([&] {
+ // Make sure no extra buffers have arrived
+ QVERIFY(bufferSpy.empty());
+
+ // The client should send a frame request in order to time animations correctly
+ QVERIFY(!cursorSurface()->m_waitingFrameCallbacks.empty());
+
+ // Tell the client it's time to animate
+ cursorSurface()->sendFrameCallbacks();
+ });
+
+ // Verify that we get a new cursor buffer
+ QTRY_COMPARE(bufferSpy.count(), 1);
+}
+
#endif // QT_CONFIG(cursor)
QCOMPOSITOR_TEST_MAIN(tst_seatv4)
diff --git a/tests/auto/client/seatv5/seatv5.pro b/tests/auto/client/seatv5/seatv5.pro
new file mode 100644
index 000000000..2081845ef
--- /dev/null
+++ b/tests/auto/client/seatv5/seatv5.pro
@@ -0,0 +1,4 @@
+include (../shared/shared.pri)
+
+TARGET = tst_seatv5
+SOURCES += tst_seatv5.cpp
diff --git a/tests/auto/client/seatv5/tst_seatv5.cpp b/tests/auto/client/seatv5/tst_seatv5.cpp
new file mode 100644
index 000000000..636f26081
--- /dev/null
+++ b/tests/auto/client/seatv5/tst_seatv5.cpp
@@ -0,0 +1,590 @@
+/****************************************************************************
+**
+** 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 SeatV5Compositor : public DefaultCompositor {
+public:
+ explicit SeatV5Compositor()
+ {
+ exec([this] {
+ m_config.autoConfigure = true;
+
+ removeAll<Seat>();
+
+ uint capabilities = MockCompositor::Seat::capability_pointer | MockCompositor::Seat::capability_touch;
+ int version = 5;
+ add<Seat>(capabilities, version);
+ });
+ }
+};
+
+class tst_seatv5 : public QObject, private SeatV5Compositor
+{
+ Q_OBJECT
+private slots:
+ void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); }
+ void bindsToSeat();
+
+ // Pointer tests
+ void createsPointer();
+ void setsCursorOnEnter();
+ void usesEnterSerial();
+ void simpleAxis_data();
+ void simpleAxis();
+ void fingerScroll();
+ void fingerScrollSlow();
+ void wheelDiscreteScroll();
+
+ // Touch tests
+ void createsTouch();
+ void singleTap();
+ void singleTapFloat();
+ void multiTouch();
+ void multiTouchUpAndMotionFrame();
+};
+
+void tst_seatv5::bindsToSeat()
+{
+ QCOMPOSITOR_COMPARE(get<Seat>()->resourceMap().size(), 1);
+ QCOMPOSITOR_COMPARE(get<Seat>()->resourceMap().first()->version(), 5);
+}
+
+void tst_seatv5::createsPointer()
+{
+ QCOMPOSITOR_TRY_COMPARE(pointer()->resourceMap().size(), 1);
+ QCOMPOSITOR_TRY_COMPARE(pointer()->resourceMap().first()->version(), 5);
+}
+
+void tst_seatv5::setsCursorOnEnter()
+{
+ QRasterWindow window;
+ window.resize(64, 64);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ exec([=] {
+ auto *surface = xdgSurface()->m_surface;
+ pointer()->sendEnter(surface, {0, 0});
+ pointer()->sendFrame(surface->resource()->client());
+ });
+
+ QCOMPOSITOR_TRY_VERIFY(pointer()->cursorSurface());
+}
+
+void tst_seatv5::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, {0, 0});
+ });
+ QCOMPOSITOR_TRY_VERIFY(pointer()->cursorSurface());
+
+ QTRY_COMPARE(setCursorSpy.count(), 1);
+ QCOMPARE(setCursorSpy.takeFirst().at(0).toUInt(), enterSerial);
+}
+
+class WheelWindow : QRasterWindow {
+public:
+ WheelWindow()
+ {
+ resize(64, 64);
+ show();
+ }
+ void wheelEvent(QWheelEvent *event) override
+ {
+ QRasterWindow::wheelEvent(event);
+// qDebug() << event << "angleDelta" << event->angleDelta() << "pixelDelta" << event->pixelDelta();
+
+ if (event->phase() != Qt::ScrollUpdate && event->phase() != Qt::NoScrollPhase) {
+ // Shouldn't have deltas in the these phases
+ QCOMPARE(event->angleDelta(), QPoint(0, 0));
+ 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);
+
+ m_events.append(Event{event});
+ }
+ struct Event // Because I didn't find a convenient way to copy it entirely
+ {
+ explicit Event() = default;
+ explicit Event(const QWheelEvent *event)
+ : phase(event->phase())
+ , pixelDelta(event->pixelDelta())
+ , angleDelta(event->angleDelta())
+ , source(event->source())
+ {
+ }
+ const Qt::ScrollPhase phase{};
+ const QPoint pixelDelta;
+ const QPoint angleDelta; // eights of a degree, positive is upwards, left
+ const Qt::MouseEventSource source{};
+ };
+ QVector<Event> m_events;
+};
+
+void tst_seatv5::simpleAxis_data()
+{
+ QTest::addColumn<uint>("axis");
+ QTest::addColumn<qreal>("value");
+ QTest::addColumn<QPoint>("angleDelta");
+
+ // Directions in regular windows/linux terms (no "natural" scrolling)
+ QTest::newRow("down") << uint(Pointer::axis_vertical_scroll) << 1.0 << QPoint{0, -12};
+ QTest::newRow("up") << uint(Pointer::axis_vertical_scroll) << -1.0 << QPoint{0, 12};
+ QTest::newRow("left") << uint(Pointer::axis_horizontal_scroll) << 1.0 << QPoint{-12, 0};
+ QTest::newRow("right") << uint(Pointer::axis_horizontal_scroll) << -1.0 << QPoint{12, 0};
+ QTest::newRow("up big") << uint(Pointer::axis_vertical_scroll) << -10.0 << QPoint{0, 120};
+}
+
+void tst_seatv5::simpleAxis()
+{
+ QFETCH(uint, axis);
+ QFETCH(qreal, value);
+ QFETCH(QPoint, angleDelta);
+
+ WheelWindow window;
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ exec([=] {
+ auto *p = pointer();
+ p->sendEnter(xdgToplevel()->surface(), {32, 32});
+ p->sendFrame(client());
+ p->sendAxis(
+ client(),
+ Pointer::axis(axis),
+ value // Length of vector in surface-local space. i.e. positive is downwards
+ );
+ p->sendFrame(client());
+ });
+
+ QTRY_VERIFY(!window.m_events.empty());
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.phase, Qt::NoScrollPhase);
+ // Pixel delta should only be set if we know it's a high-res input device (which we don't)
+ QCOMPARE(e.pixelDelta, QPoint(0, 0));
+ // There has been no information about what created the event.
+ // Documentation says not synthesized is appropriate in such cases
+ QCOMPARE(e.source, Qt::MouseEventNotSynthesized);
+ QCOMPARE(e.angleDelta, angleDelta);
+ }
+
+ // Sending axis_stop is not mandatory when axis source != finger
+}
+
+void tst_seatv5::fingerScroll()
+{
+ WheelWindow window;
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ exec([=] {
+ auto *p = pointer();
+ auto *c = client();
+ p->sendEnter(xdgToplevel()->surface(), {32, 32});
+ p->sendFrame(c);
+ p->sendAxisSource(c, Pointer::axis_source_finger);
+ p->sendAxis(c, Pointer::axis_vertical_scroll, 10);
+ p->sendFrame(c);
+ });
+
+ QTRY_VERIFY(!window.m_events.empty());
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.phase, Qt::ScrollBegin);
+ QCOMPARE(e.angleDelta, QPoint());
+ QCOMPARE(e.pixelDelta, QPoint());
+ }
+
+ QTRY_VERIFY(!window.m_events.empty());
+ // For some reason we send two ScrollBegins, one for each direction, not sure if this is really
+ // necessary, (could be removed from QtBase, hence the conditional below.
+ if (window.m_events.first().phase == Qt::ScrollBegin) {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.angleDelta, QPoint());
+ QCOMPARE(e.pixelDelta, QPoint());
+ }
+
+ QTRY_VERIFY(!window.m_events.empty());
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.phase, Qt::ScrollUpdate);
+ QVERIFY(qAbs(e.angleDelta.x()) <= qAbs(e.angleDelta.y())); // Vertical scroll
+// QCOMPARE(e.angleDelta, angleDelta); // TODO: what should this be?
+ QCOMPARE(e.pixelDelta, QPoint(0, 10));
+ QCOMPARE(e.source, Qt::MouseEventSynthesizedBySystem); // A finger is not a wheel
+ }
+
+ QTRY_VERIFY(window.m_events.empty());
+
+ // Scroll horizontally as well
+ exec([=] {
+ pointer()->sendAxisSource(client(), Pointer::axis_source_finger);
+ pointer()->sendAxis(client(), Pointer::axis_horizontal_scroll, 10);
+ pointer()->sendFrame(client());
+ });
+ QTRY_VERIFY(!window.m_events.empty());
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.phase, Qt::ScrollUpdate);
+ QVERIFY(qAbs(e.angleDelta.x()) > qAbs(e.angleDelta.y())); // Horizontal scroll
+ QCOMPARE(e.pixelDelta, QPoint(10, 0));
+ QCOMPARE(e.source, Qt::MouseEventSynthesizedBySystem); // A finger is not a wheel
+ }
+
+ // Scroll diagonally
+ exec([=] {
+ pointer()->sendAxisSource(client(), Pointer::axis_source_finger);
+ pointer()->sendAxis(client(), Pointer::axis_horizontal_scroll, 10);
+ pointer()->sendAxis(client(), Pointer::axis_vertical_scroll, 10);
+ pointer()->sendFrame(client());
+ });
+ QTRY_VERIFY(!window.m_events.empty());
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.phase, Qt::ScrollUpdate);
+ QCOMPARE(e.pixelDelta, QPoint(10, 10));
+ QCOMPARE(e.source, Qt::MouseEventSynthesizedBySystem); // A finger is not a wheel
+ }
+
+ // For diagonal events, Qt sends an additional compatibility ScrollUpdate event
+ if (window.m_events.first().phase == Qt::ScrollUpdate) {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.angleDelta, QPoint());
+ QCOMPARE(e.pixelDelta, QPoint());
+ }
+
+ QVERIFY(window.m_events.empty());
+
+ // Sending axis_stop is mandatory when axis source == finger
+ exec([=] {
+ pointer()->sendAxisStop(client(), Pointer::axis_vertical_scroll);
+ pointer()->sendFrame(client());
+ });
+
+ QTRY_VERIFY(!window.m_events.empty());
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.phase, Qt::ScrollEnd);
+ }
+}
+
+
+void tst_seatv5::fingerScrollSlow()
+{
+ WheelWindow window;
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ exec([=] {
+ auto *p = pointer();
+ auto *c = client();
+ p->sendEnter(xdgToplevel()->surface(), {32, 32});
+ p->sendFrame(c);
+ // Send 10 really small updates
+ for (int i = 0; i < 10; ++i) {
+ p->sendAxisSource(c, Pointer::axis_source_finger);
+ p->sendAxis(c, Pointer::axis_vertical_scroll, 0.1);
+ p->sendFrame(c);
+ }
+ p->sendAxisStop(c, Pointer::axis_vertical_scroll);
+ p->sendFrame(c);
+ });
+
+ QTRY_VERIFY(!window.m_events.empty());
+ QPoint accumulated;
+ while (window.m_events.first().phase != Qt::ScrollEnd) {
+ auto e = window.m_events.takeFirst();
+ accumulated += e.pixelDelta;
+ QTRY_VERIFY(!window.m_events.empty());
+ }
+ QCOMPARE(accumulated.y(), 1);
+}
+void tst_seatv5::wheelDiscreteScroll()
+{
+ WheelWindow window;
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ exec([=] {
+ auto *p = pointer();
+ auto *c = client();
+ p->sendEnter(xdgToplevel()->surface(), {32, 32});
+ p->sendFrame(c);
+ p->sendAxisSource(c, Pointer::axis_source_wheel);
+ p->sendAxisDiscrete(c, Pointer::axis_vertical_scroll, 1); // 1 click downwards
+ p->sendAxis(c, Pointer::axis_vertical_scroll, 1.0);
+ p->sendFrame(c);
+ });
+
+ QTRY_VERIFY(!window.m_events.empty());
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.phase, Qt::NoScrollPhase);
+ QVERIFY(qAbs(e.angleDelta.x()) <= qAbs(e.angleDelta.y())); // Vertical scroll
+ // According to the docs the angle delta is in eights of a degree and most mice have
+ // 1 click = 15 degrees. The angle delta should therefore be:
+ // 15 degrees / (1/8 eights per degrees) = 120 eights of degrees.
+ QCOMPARE(e.angleDelta, QPoint(0, -120));
+ // Click scrolls are not continuous and should not have a pixel delta
+ QCOMPARE(e.pixelDelta, QPoint(0, 0));
+ }
+}
+
+void tst_seatv5::createsTouch()
+{
+ QCOMPOSITOR_TRY_COMPARE(touch()->resourceMap().size(), 1);
+ QCOMPOSITOR_TRY_COMPARE(touch()->resourceMap().first()->version(), 5);
+}
+
+class TouchWindow : public QRasterWindow {
+public:
+ TouchWindow()
+ {
+ resize(64, 64);
+ show();
+ }
+ void touchEvent(QTouchEvent *event) override
+ {
+ QRasterWindow::touchEvent(event);
+ m_events.append(Event{event});
+ }
+ struct Event // Because I didn't find a convenient way to copy it entirely
+ {
+ explicit Event() = default;
+ explicit Event(const QTouchEvent *event)
+ : type(event->type())
+ , touchPointStates(event->touchPointStates())
+ , touchPoints(event->touchPoints())
+ {
+ }
+ const QEvent::Type type{};
+ const Qt::TouchPointStates touchPointStates{};
+ const QList<QTouchEvent::TouchPoint> touchPoints;
+ };
+ QVector<Event> m_events;
+};
+
+void tst_seatv5::singleTap()
+{
+ TouchWindow window;
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ exec([=] {
+ auto *t = touch();
+ auto *c = client();
+ t->sendDown(xdgToplevel()->surface(), {32, 32}, 1);
+ t->sendFrame(c);
+ t->sendUp(c, 1);
+ t->sendFrame(c);
+ });
+
+ QTRY_VERIFY(!window.m_events.empty());
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.type, QEvent::TouchBegin);
+ QCOMPARE(e.touchPointStates, Qt::TouchPointState::TouchPointPressed);
+ QCOMPARE(e.touchPoints.length(), 1);
+ QCOMPARE(e.touchPoints.first().pos(), QPointF(32-window.frameMargins().left(), 32-window.frameMargins().top()));
+ }
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.type, QEvent::TouchEnd);
+ QCOMPARE(e.touchPointStates, Qt::TouchPointState::TouchPointReleased);
+ QCOMPARE(e.touchPoints.length(), 1);
+ QCOMPARE(e.touchPoints.first().pos(), QPointF(32-window.frameMargins().left(), 32-window.frameMargins().top()));
+ }
+}
+
+void tst_seatv5::singleTapFloat()
+{
+ TouchWindow window;
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ exec([=] {
+ auto *t = touch();
+ auto *c = client();
+ t->sendDown(xdgToplevel()->surface(), {32.75, 32.25}, 1);
+ t->sendFrame(c);
+ t->sendUp(c, 1);
+ t->sendFrame(c);
+ });
+
+ QTRY_VERIFY(!window.m_events.empty());
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.type, QEvent::TouchBegin);
+ QCOMPARE(e.touchPointStates, Qt::TouchPointState::TouchPointPressed);
+ QCOMPARE(e.touchPoints.length(), 1);
+ QCOMPARE(e.touchPoints.first().pos(), QPointF(32.75-window.frameMargins().left(), 32.25-window.frameMargins().top()));
+ }
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.type, QEvent::TouchEnd);
+ QCOMPARE(e.touchPointStates, Qt::TouchPointState::TouchPointReleased);
+ QCOMPARE(e.touchPoints.length(), 1);
+ QCOMPARE(e.touchPoints.first().pos(), QPointF(32.75-window.frameMargins().left(), 32.25-window.frameMargins().top()));
+ }
+}
+
+void tst_seatv5::multiTouch()
+{
+ TouchWindow window;
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ exec([=] {
+ auto *t = touch();
+ auto *c = client();
+
+ t->sendDown(xdgToplevel()->surface(), {32, 32}, 0);
+ t->sendDown(xdgToplevel()->surface(), {48, 48}, 1);
+ t->sendFrame(c);
+
+ // Compositor event order should not change the order of the QTouchEvent::touchPoints()
+ // See QTBUG-77014
+ t->sendMotion(c, {49, 48}, 1);
+ t->sendMotion(c, {33, 32}, 0);
+ t->sendFrame(c);
+
+ t->sendUp(c, 0);
+ t->sendFrame(c);
+
+ t->sendUp(c, 1);
+ t->sendFrame(c);
+ });
+
+ QTRY_VERIFY(!window.m_events.empty());
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.type, QEvent::TouchBegin);
+ QCOMPARE(e.touchPointStates, Qt::TouchPointState::TouchPointPressed);
+ QCOMPARE(e.touchPoints.length(), 2);
+
+ QCOMPARE(e.touchPoints[0].state(), Qt::TouchPointState::TouchPointPressed);
+ QCOMPARE(e.touchPoints[0].pos(), QPointF(32-window.frameMargins().left(), 32-window.frameMargins().top()));
+
+ QCOMPARE(e.touchPoints[1].state(), Qt::TouchPointState::TouchPointPressed);
+ QCOMPARE(e.touchPoints[1].pos(), QPointF(48-window.frameMargins().left(), 48-window.frameMargins().top()));
+ }
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.type, QEvent::TouchUpdate);
+ QCOMPARE(e.touchPoints.length(), 2);
+
+ QCOMPARE(e.touchPoints[0].state(), Qt::TouchPointState::TouchPointMoved);
+ QCOMPARE(e.touchPoints[0].pos(), QPointF(33-window.frameMargins().left(), 32-window.frameMargins().top()));
+
+ QCOMPARE(e.touchPoints[1].state(), Qt::TouchPointState::TouchPointMoved);
+ QCOMPARE(e.touchPoints[1].pos(), QPointF(49-window.frameMargins().left(), 48-window.frameMargins().top()));
+ }
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.type, QEvent::TouchUpdate);
+ QCOMPARE(e.touchPointStates, Qt::TouchPointState::TouchPointReleased | Qt::TouchPointState::TouchPointStationary);
+ QCOMPARE(e.touchPoints.length(), 2);
+
+ QCOMPARE(e.touchPoints[0].state(), Qt::TouchPointState::TouchPointReleased);
+ QCOMPARE(e.touchPoints[0].pos(), QPointF(33-window.frameMargins().left(), 32-window.frameMargins().top()));
+
+ QCOMPARE(e.touchPoints[1].state(), Qt::TouchPointState::TouchPointStationary);
+ QCOMPARE(e.touchPoints[1].pos(), QPointF(49-window.frameMargins().left(), 48-window.frameMargins().top()));
+ }
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.type, QEvent::TouchEnd);
+ QCOMPARE(e.touchPointStates, Qt::TouchPointState::TouchPointReleased);
+ QCOMPARE(e.touchPoints.length(), 1);
+ QCOMPARE(e.touchPoints[0].state(), Qt::TouchPointState::TouchPointReleased);
+ QCOMPARE(e.touchPoints[0].pos(), QPointF(49-window.frameMargins().left(), 48-window.frameMargins().top()));
+ }
+}
+
+void tst_seatv5::multiTouchUpAndMotionFrame()
+{
+ TouchWindow window;
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ exec([=] {
+ auto *t = touch();
+ auto *c = client();
+
+ t->sendDown(xdgToplevel()->surface(), {32, 32}, 0);
+ t->sendDown(xdgToplevel()->surface(), {48, 48}, 1);
+ t->sendFrame(c);
+
+ // Sending an up event after a frame event, before any motion or down events used to
+ // unnecessarily trigger a workaround for a bug in an old version of Weston. The workaround
+ // would prematurely insert a fake frame event splitting the touch event up into two events.
+ // However, this should only be needed on the up event for the very last touch point. So in
+ // this test we verify that it doesn't unncecessarily break up the events.
+ t->sendUp(c, 0);
+ t->sendMotion(c, {49, 48}, 1);
+ t->sendFrame(c);
+
+ t->sendUp(c, 1);
+ t->sendFrame(c);
+ });
+
+ QTRY_VERIFY(!window.m_events.empty());
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.type, QEvent::TouchBegin);
+ QCOMPARE(e.touchPoints[0].state(), Qt::TouchPointState::TouchPointPressed);
+ QCOMPARE(e.touchPoints[1].state(), Qt::TouchPointState::TouchPointPressed);
+ }
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.type, QEvent::TouchUpdate);
+ QCOMPARE(e.touchPoints.length(), 2);
+ QCOMPARE(e.touchPoints[0].state(), Qt::TouchPointState::TouchPointReleased);
+ QCOMPARE(e.touchPoints[1].state(), Qt::TouchPointState::TouchPointMoved);
+ }
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.type, QEvent::TouchEnd);
+ QCOMPARE(e.touchPoints.length(), 1);
+ QCOMPARE(e.touchPoints[0].state(), Qt::TouchPointState::TouchPointReleased);
+ }
+ QVERIFY(window.m_events.empty());
+}
+
+QCOMPOSITOR_TEST_MAIN(tst_seatv5)
+#include "tst_seatv5.moc"
diff --git a/tests/auto/client/shared/corecompositor.h b/tests/auto/client/shared/corecompositor.h
index 875b7d050..254465ee6 100644
--- a/tests/auto/client/shared/corecompositor.h
+++ b/tests/auto/client/shared/corecompositor.h
@@ -125,6 +125,23 @@ public:
}
/*!
+ * \brief Returns the nth global with the given type, if any
+ */
+ template<typename global_type>
+ global_type *get(int index)
+ {
+ warnIfNotLockedByThread(Q_FUNC_INFO);
+ for (auto *global : qAsConst(m_globals)) {
+ if (auto *casted = qobject_cast<global_type *>(global)) {
+ if (index--)
+ continue;
+ return casted;
+ }
+ }
+ return nullptr;
+ }
+
+ /*!
* \brief Returns all globals with the given type, if any
*/
template<typename global_type>
diff --git a/tests/auto/client/shared/coreprotocol.cpp b/tests/auto/client/shared/coreprotocol.cpp
index 729d481f8..b0be2cb4e 100644
--- a/tests/auto/client/shared/coreprotocol.cpp
+++ b/tests/auto/client/shared/coreprotocol.cpp
@@ -191,12 +191,15 @@ Seat::~Seat()
{
qDeleteAll(m_oldPointers);
delete m_pointer;
+
+ qDeleteAll(m_oldTouchs);
+ delete m_touch;
+
+ qDeleteAll(m_oldKeyboards);
+ delete m_keyboard;
}
void Seat::setCapabilities(uint capabilities) {
- // TODO: Add support for touch
- Q_ASSERT(~capabilities & capability_touch);
-
m_capabilities = capabilities;
if (m_capabilities & capability_pointer) {
@@ -207,6 +210,14 @@ void Seat::setCapabilities(uint capabilities) {
m_pointer = nullptr;
}
+ if (m_capabilities & capability_touch) {
+ if (!m_touch)
+ m_touch = (new Touch(this));
+ } else if (m_touch) {
+ m_oldTouchs << m_touch;
+ m_touch = nullptr;
+ }
+
if (m_capabilities & capability_keyboard) {
if (!m_keyboard)
m_keyboard = (new Keyboard(this));
@@ -234,9 +245,24 @@ void Seat::seat_get_pointer(Resource *resource, uint32_t id)
m_pointer->add(resource->client(), id, resource->version());
}
+void Seat::seat_get_touch(QtWaylandServer::wl_seat::Resource *resource, uint32_t id)
+{
+ if (~m_capabilities & capability_touch) {
+ qWarning() << "Client requested a wl_touch without the capability being available."
+ << "This Could be a race condition when hotunplugging,"
+ << "but is most likely a client error";
+ Touch *touch = new Touch(this);
+ touch->add(resource->client(), id, resource->version());
+ // TODO: mark as destroyed
+ m_oldTouchs << touch;
+ return;
+ }
+ m_touch->add(resource->client(), id, resource->version());
+}
+
void Seat::seat_get_keyboard(QtWaylandServer::wl_seat::Resource *resource, uint32_t id)
{
- if (~m_capabilities & capability_pointer) {
+ if (~m_capabilities & capability_keyboard) {
qWarning() << "Client requested a wl_keyboard without the capability being available."
<< "This Could be a race condition when hotunplugging,"
<< "but is most likely a client error";
@@ -314,6 +340,39 @@ void Pointer::sendAxis(wl_client *client, axis axis, qreal value)
send_axis(r->handle, time, axis, val);
}
+void Pointer::sendAxisDiscrete(wl_client *client, QtWaylandServer::wl_pointer::axis axis, int discrete)
+{
+ // TODO: assert v5 or newer
+ const auto pointerResources = resourceMap().values(client);
+ for (auto *r : pointerResources)
+ send_axis_discrete(r->handle, axis, discrete);
+}
+
+void Pointer::sendAxisSource(wl_client *client, QtWaylandServer::wl_pointer::axis_source source)
+{
+ // TODO: assert v5 or newer
+ const auto pointerResources = resourceMap().values(client);
+ for (auto *r : pointerResources)
+ send_axis_source(r->handle, source);
+}
+
+void Pointer::sendAxisStop(wl_client *client, QtWaylandServer::wl_pointer::axis axis)
+{
+ // TODO: assert v5 or newer
+ auto time = m_seat->m_compositor->currentTimeMilliseconds();
+ const auto pointerResources = resourceMap().values(client);
+ for (auto *r : pointerResources)
+ send_axis_stop(r->handle, time, axis);
+}
+
+void Pointer::sendFrame(wl_client *client)
+{
+ //TODO: assert version 5 or newer?
+ const auto pointerResources = resourceMap().values(client);
+ for (auto *r : pointerResources)
+ send_frame(r->handle);
+}
+
void Pointer::pointer_set_cursor(Resource *resource, uint32_t serial, wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y)
{
Q_UNUSED(resource);
@@ -338,6 +397,52 @@ void Pointer::pointer_set_cursor(Resource *resource, uint32_t serial, wl_resourc
emit setCursor(serial);
}
+uint Touch::sendDown(Surface *surface, const QPointF &position, int id)
+{
+ wl_fixed_t x = wl_fixed_from_double(position.x());
+ wl_fixed_t y = wl_fixed_from_double(position.y());
+ uint serial = m_seat->m_compositor->nextSerial();
+ auto time = m_seat->m_compositor->currentTimeMilliseconds();
+ wl_client *client = surface->resource()->client();
+
+ const auto touchResources = resourceMap().values(client);
+ for (auto *r : touchResources)
+ wl_touch::send_down(r->handle, serial, time, surface->resource()->handle, id, x, y);
+
+ return serial;
+}
+
+uint Touch::sendUp(wl_client *client, int id)
+{
+ uint serial = m_seat->m_compositor->nextSerial();
+ auto time = m_seat->m_compositor->currentTimeMilliseconds();
+
+ const auto touchResources = resourceMap().values(client);
+ for (auto *r : touchResources)
+ wl_touch::send_up(r->handle, serial, time, id);
+
+ return serial;
+}
+
+void Touch::sendMotion(wl_client *client, const QPointF &position, int id)
+{
+ 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 touchResources = resourceMap().values(client);
+ for (auto *r : touchResources)
+ wl_touch::send_motion(r->handle, time, id, x, y);
+}
+
+void Touch::sendFrame(wl_client *client)
+{
+ const auto touchResources = resourceMap().values(client);
+ for (auto *r : touchResources)
+ send_frame(r->handle);
+}
+
uint Keyboard::sendEnter(Surface *surface)
{
auto serial = m_seat->m_compositor->nextSerial();
@@ -345,6 +450,7 @@ uint Keyboard::sendEnter(Surface *surface)
const auto pointerResources = resourceMap().values(client);
for (auto *r : pointerResources)
send_enter(r->handle, serial, surface->resource()->handle, QByteArray());
+ m_enteredSurface = surface;
return serial;
}
@@ -355,6 +461,7 @@ uint Keyboard::sendLeave(Surface *surface)
const auto pointerResources = resourceMap().values(client);
for (auto *r : pointerResources)
send_leave(r->handle, serial, surface->resource()->handle);
+ m_enteredSurface = nullptr;
return serial;
}
diff --git a/tests/auto/client/shared/coreprotocol.h b/tests/auto/client/shared/coreprotocol.h
index 5cef476c8..fe8202ad1 100644
--- a/tests/auto/client/shared/coreprotocol.h
+++ b/tests/auto/client/shared/coreprotocol.h
@@ -38,6 +38,7 @@ namespace MockCompositor {
class WlCompositor;
class Output;
class Pointer;
+class Touch;
class Keyboard;
class CursorRole;
class ShmPool;
@@ -236,7 +237,7 @@ class Seat : public Global, public QtWaylandServer::wl_seat
{
Q_OBJECT
public:
- explicit Seat(CoreCompositor *compositor, uint capabilities, int version = 4);
+ explicit Seat(CoreCompositor *compositor, uint capabilities = Seat::capability_pointer | Seat::capability_keyboard | Seat::capability_touch, int version = 5);
~Seat() override;
void send_capabilities(Resource *resource, uint capabilities) = delete; // Use wrapper instead
void send_capabilities(uint capabilities) = delete; // Use wrapper instead
@@ -247,6 +248,9 @@ public:
Pointer* m_pointer = nullptr;
QVector<Pointer *> m_oldPointers;
+ Touch* m_touch = nullptr;
+ QVector<Touch *> m_oldTouchs;
+
Keyboard* m_keyboard = nullptr;
QVector<Keyboard *> m_oldKeyboards;
@@ -259,8 +263,8 @@ protected:
}
void seat_get_pointer(Resource *resource, uint32_t id) override;
+ void seat_get_touch(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;
};
@@ -279,6 +283,10 @@ public:
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);
+ void sendAxisDiscrete(wl_client *client, axis axis, int discrete);
+ void sendAxisSource(wl_client *client, axis_source source);
+ void sendAxisStop(wl_client *client, axis axis);
+ void sendFrame(wl_client *client);
Seat *m_seat = nullptr;
QVector<uint> m_enterSerials;
@@ -303,6 +311,19 @@ public:
Surface *m_surface = nullptr;
};
+class Touch : public QObject, public QtWaylandServer::wl_touch
+{
+ Q_OBJECT
+public:
+ explicit Touch(Seat *seat) : m_seat(seat) {}
+ uint sendDown(Surface *surface, const QPointF &position, int id);
+ uint sendUp(wl_client *client, int id);
+ void sendMotion(wl_client *client, const QPointF &position, int id);
+ void sendFrame(wl_client *client);
+
+ Seat *m_seat = nullptr;
+};
+
class Keyboard : public QObject, public QtWaylandServer::wl_keyboard
{
Q_OBJECT
@@ -313,6 +334,7 @@ public:
uint sendLeave(Surface *surface);
uint sendKey(wl_client *client, uint key, uint state);
Seat *m_seat = nullptr;
+ Surface *m_enteredSurface = nullptr;
};
class Shm : public Global, public QtWaylandServer::wl_shm
diff --git a/tests/auto/client/shared/mockcompositor.cpp b/tests/auto/client/shared/mockcompositor.cpp
index 6b9af4295..5f2d89078 100644
--- a/tests/auto/client/shared/mockcompositor.cpp
+++ b/tests/auto/client/shared/mockcompositor.cpp
@@ -41,7 +41,7 @@ DefaultCompositor::DefaultCompositor()
add<SubCompositor>();
auto *output = add<Output>();
output->m_data.physicalSize = output->m_data.mode.physicalSizeForDpi(96);
- add<Seat>(Seat::capability_pointer | Seat::capability_keyboard);
+ add<Seat>(Seat::capability_pointer | Seat::capability_keyboard | Seat::capability_touch);
add<XdgWmBase>();
add<Shm>();
// TODO: other shells, viewporter, xdgoutput etc
diff --git a/tests/auto/client/shared/mockcompositor.h b/tests/auto/client/shared/mockcompositor.h
index 05bf32c8d..fc4d7cc46 100644
--- a/tests/auto/client/shared/mockcompositor.h
+++ b/tests/auto/client/shared/mockcompositor.h
@@ -36,10 +36,16 @@
#include <QtGui/QGuiApplication>
-#ifndef BTN_LEFT
// As defined in linux/input-event-codes.h
+#ifndef BTN_LEFT
#define BTN_LEFT 0x110
#endif
+#ifndef BTN_RIGHT
+#define BTN_RIGHT 0x111
+#endif
+#ifndef BTN_MIDDLE
+#define BTN_MIDDLE 0x112
+#endif
namespace MockCompositor {
@@ -54,6 +60,7 @@ public:
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; }
+ Touch *touch() { auto *seat = get<Seat>(); Q_ASSERT(seat); return seat->m_touch; }
Surface *cursorSurface() { auto *p = pointer(); return p ? p->cursorSurface() : nullptr; }
Keyboard *keyboard() { auto *seat = get<Seat>(); Q_ASSERT(seat); return seat->m_keyboard; }
uint sendXdgShellPing();
diff --git a/tests/auto/client/shared_old/mockcompositor.cpp b/tests/auto/client/shared_old/mockcompositor.cpp
index 0dfaef5ea..f71a78102 100644
--- a/tests/auto/client/shared_old/mockcompositor.cpp
+++ b/tests/auto/client/shared_old/mockcompositor.cpp
@@ -221,8 +221,8 @@ QSharedPointer<MockSurface> MockCompositor::surface()
QSharedPointer<MockSurface> result;
lock();
{
- QVector<Impl::Surface *> surfaces = m_compositor->surfaces();
- foreach (Impl::Surface *surface, surfaces) {
+ const QVector<Impl::Surface *> surfaces = m_compositor->surfaces();
+ for (Impl::Surface *surface : surfaces) {
// we don't want to mistake the cursor surface for a window surface
if (surface->isMapped()) {
result = surface->mockSurface();
diff --git a/tests/auto/client/shared_old/mocksurface.cpp b/tests/auto/client/shared_old/mocksurface.cpp
index 81a5edbd0..e9df5f907 100644
--- a/tests/auto/client/shared_old/mocksurface.cpp
+++ b/tests/auto/client/shared_old/mocksurface.cpp
@@ -149,11 +149,10 @@ void Surface::surface_commit(Resource *resource)
}
}
- foreach (wl_resource *frameCallback, m_frameCallbackList) {
+ for (wl_resource *frameCallback : qExchange(m_frameCallbackList, {})) {
wl_callback_send_done(frameCallback, m_compositor->time());
wl_resource_destroy(frameCallback);
}
- m_frameCallbackList.clear();
}
}
diff --git a/tests/auto/client/surface/tst_surface.cpp b/tests/auto/client/surface/tst_surface.cpp
index dddff0866..9659235a0 100644
--- a/tests/auto/client/surface/tst_surface.cpp
+++ b/tests/auto/client/surface/tst_surface.cpp
@@ -28,7 +28,9 @@
#include "mockcompositor.h"
#include <QtGui/QRasterWindow>
+#if QT_CONFIG(opengl)
#include <QtGui/QOpenGLWindow>
+#endif
using namespace MockCompositor;
@@ -39,7 +41,9 @@ private slots:
void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); }
void createDestroySurface();
void waitForFrameCallbackRaster();
+#if QT_CONFIG(opengl)
void waitForFrameCallbackGl();
+#endif
void negotiateShmFormat();
};
@@ -89,6 +93,7 @@ void tst_surface::waitForFrameCallbackRaster()
}
}
+#if QT_CONFIG(opengl)
void tst_surface::waitForFrameCallbackGl()
{
QSKIP("TODO: This currently fails, needs a fix");
@@ -129,6 +134,7 @@ void tst_surface::waitForFrameCallbackGl()
bufferSpy.removeFirst();
}
}
+#endif // QT_CONFIG(opengl)
void tst_surface::negotiateShmFormat()
{
diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp
index 9b18abdc3..ac5c24988 100644
--- a/tests/auto/client/xdgshell/tst_xdgshell.cpp
+++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp
@@ -29,6 +29,8 @@
#include "mockcompositor.h"
#include <QtGui/QRasterWindow>
#include <QtGui/QOpenGLWindow>
+#include <QtGui/qpa/qplatformnativeinterface.h>
+#include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
using namespace MockCompositor;
@@ -47,6 +49,7 @@ private slots:
void pongs();
void minMaxSize();
void windowGeometry();
+ void foreignSurface();
};
void tst_xdgshell::showMinimized()
@@ -211,12 +214,13 @@ void tst_xdgshell::popup()
uint clickSerial = exec([=] {
auto *surface = xdgToplevel()->surface();
auto *p = pointer();
+ auto *c = client();
p->sendEnter(surface, {100, 100});
-// p->sendFrame(); //TODO: uncomment when we support seat v5
+ p->sendFrame(c);
uint serial = p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
- p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
+ p->sendButton(c, BTN_LEFT, Pointer::button_state_released);
return serial;
-// p->sendFrame(); //TODO: uncomment when we support seat v5
+ p->sendFrame(c);
});
QTRY_VERIFY(window.m_popup);
@@ -295,13 +299,14 @@ void tst_xdgshell::tooltipOnPopup()
exec([=] {
auto *surface = xdgToplevel()->surface();
auto *p = pointer();
+ auto *c = client();
p->sendEnter(surface, {100, 100});
-// p->sendFrame(); //TODO: uncomment when we support seat v5
+ p->sendFrame(c);
p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
-// p->sendFrame();
+ p->sendFrame(c);
p->sendLeave(surface);
-// p->sendFrame();
+ p->sendFrame(c);
});
QCOMPOSITOR_TRY_VERIFY(xdgPopup());
@@ -312,11 +317,12 @@ void tst_xdgshell::tooltipOnPopup()
exec([=] {
auto *surface = xdgPopup()->surface();
auto *p = pointer();
+ auto *c = client();
p->sendEnter(surface, {100, 100});
-// p->sendFrame();
+ p->sendFrame(c);
p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
-// p->sendFrame();
+ p->sendFrame(c);
});
QCOMPOSITOR_TRY_VERIFY(xdgPopup(1));
@@ -377,13 +383,14 @@ void tst_xdgshell::switchPopups()
exec([=] {
auto *surface = xdgToplevel()->surface();
auto *p = pointer();
+ auto *c = client();
p->sendEnter(surface, {100, 100});
-// p->sendFrame(); //TODO: uncomment when we support seat v5
- p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
- p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
-// p->sendFrame();
+ p->sendFrame(c);
+ p->sendButton(c, BTN_LEFT, Pointer::button_state_pressed);
+ p->sendButton(c, BTN_LEFT, Pointer::button_state_released);
+ p->sendFrame(c);
p->sendLeave(surface);
-// p->sendFrame();
+ p->sendFrame(c);
});
QCOMPOSITOR_TRY_VERIFY(xdgPopup());
@@ -396,11 +403,12 @@ void tst_xdgshell::switchPopups()
exec([=] {
auto *surface = xdgToplevel()->surface();
auto *p = pointer();
+ auto *c = client();
p->sendEnter(surface, {100, 100});
-// p->sendFrame();
- p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
- p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
-// p->sendFrame();
+ p->sendFrame(c);
+ p->sendButton(c, BTN_LEFT, Pointer::button_state_pressed);
+ p->sendButton(c, BTN_LEFT, Pointer::button_state_released);
+ p->sendFrame(c);
});
// The client will now hide one popup and then show another
@@ -473,10 +481,41 @@ void tst_xdgshell::windowGeometry()
exec([=] { xdgToplevel()->sendCompleteConfigure(); });
- QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committed.windowGeometry, QRect(QPoint(0, 0), window.frameGeometry().size()));
+ QSize marginsSize;
+ marginsSize.setWidth(window.frameMargins().left() + window.frameMargins().right());
+ marginsSize.setHeight(window.frameMargins().top() + window.frameMargins().bottom());
+
+ QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committed.windowGeometry, QRect(QPoint(0, 0), QSize(400, 320) + marginsSize));
window.resize(800, 600);
- QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committed.windowGeometry, QRect(QPoint(0, 0), window.frameGeometry().size()));
+ QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committed.windowGeometry, QRect(QPoint(0, 0), QSize(800, 600) + marginsSize));
+}
+
+void tst_xdgshell::foreignSurface()
+{
+ auto *ni = QGuiApplication::platformNativeInterface();
+ auto *compositor = static_cast<::wl_compositor *>(ni->nativeResourceForIntegration("compositor"));
+ ::wl_surface *foreignSurface = wl_compositor_create_surface(compositor);
+
+ // There *could* be cursor surfaces lying around, we don't want to confuse those with
+ // the foreign surface we will be creating.
+ const int newSurfaceIndex = exec([&]{
+ return get<WlCompositor>()->m_surfaces.size();
+ });
+
+ QCOMPOSITOR_TRY_VERIFY(surface(newSurfaceIndex));
+ exec([&] {
+ pointer()->sendEnter(surface(newSurfaceIndex), {32, 32});
+ pointer()->sendLeave(surface(newSurfaceIndex));
+ });
+
+ // Just do something to make sure we don't destroy the surface before
+ // the pointer events above are handled.
+ QSignalSpy spy(exec([=] { return surface(newSurfaceIndex); }), &Surface::commit);
+ wl_surface_commit(foreignSurface);
+ QTRY_COMPARE(spy.count(), 1);
+
+ wl_surface_destroy(foreignSurface);
}
QCOMPOSITOR_TEST_MAIN(tst_xdgshell)
diff --git a/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp b/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp
index a397f60eb..027e1dfa8 100644
--- a/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp
+++ b/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp
@@ -413,11 +413,11 @@ void tst_WaylandClientXdgShellV6::dontSpamExposeEvents()
QSharedPointer<MockSurface> surface;
QTRY_VERIFY(surface = m_compositor->surface());
- QTRY_VERIFY(window.exposeEventCount == 0);
+ QTRY_COMPARE(window.exposeEventCount, 0);
m_compositor->sendShellSurfaceConfigure(surface);
QTRY_VERIFY(window.isExposed());
- QTRY_VERIFY(window.exposeEventCount == 1);
+ QTRY_COMPARE(window.exposeEventCount, 1);
}
int main(int argc, char **argv)
diff --git a/tests/auto/compositor/compositor/compositor.pro b/tests/auto/compositor/compositor/compositor.pro
index 500a92c61..270016597 100644
--- a/tests/auto/compositor/compositor/compositor.pro
+++ b/tests/auto/compositor/compositor/compositor.pro
@@ -14,7 +14,9 @@ WAYLANDCLIENTSOURCES += \
../../../../src/3rdparty/protocol/ivi-application.xml \
../../../../src/3rdparty/protocol/wayland.xml \
../../../../src/3rdparty/protocol/xdg-shell.xml \
- ../../../../src/3rdparty/protocol/viewporter.xml
+ ../../../../src/3rdparty/protocol/viewporter.xml \
+ ../../../../src/3rdparty/protocol/idle-inhibit-unstable-v1.xml \
+ ../../../../src/3rdparty/protocol/xdg-output-unstable-v1.xml
SOURCES += \
tst_compositor.cpp \
@@ -24,7 +26,8 @@ SOURCES += \
mockseat.cpp \
testseat.cpp \
mockkeyboard.cpp \
- mockpointer.cpp
+ mockpointer.cpp \
+ mockxdgoutputv1.cpp
HEADERS += \
testcompositor.h \
@@ -33,4 +36,5 @@ HEADERS += \
mockseat.h \
testseat.h \
mockkeyboard.h \
- mockpointer.h
+ mockpointer.h \
+ mockxdgoutputv1.h
diff --git a/tests/auto/compositor/compositor/mockclient.cpp b/tests/auto/compositor/compositor/mockclient.cpp
index fa4d4c6b3..27d1eed89 100644
--- a/tests/auto/compositor/compositor/mockclient.cpp
+++ b/tests/auto/compositor/compositor/mockclient.cpp
@@ -184,11 +184,19 @@ void MockClient::handleGlobal(uint32_t id, const QByteArray &interface)
} else if (interface == "wl_seat") {
wl_seat *s = static_cast<wl_seat *>(wl_registry_bind(registry, id, &wl_seat_interface, 1));
m_seats << new MockSeat(s);
+ } else if (interface == "zwp_idle_inhibit_manager_v1") {
+ idleInhibitManager = static_cast<zwp_idle_inhibit_manager_v1 *>(wl_registry_bind(registry, id, &zwp_idle_inhibit_manager_v1_interface, 1));
+ } else if (interface == "zxdg_output_manager_v1") {
+ xdgOutputManager = new QtWayland::zxdg_output_manager_v1(registry, id, 2);
}
}
void MockClient::handleGlobalRemove(uint32_t id)
{
+ auto *output = m_outputs[id];
+ if (m_xdgOutputs.contains(output))
+ delete m_xdgOutputs.take(output);
+
m_outputs.remove(id);
}
@@ -222,6 +230,23 @@ ivi_surface *MockClient::createIviSurface(wl_surface *surface, uint iviId)
return ivi_application_surface_create(iviApplication, iviId, surface);
}
+zwp_idle_inhibitor_v1 *MockClient::createIdleInhibitor(wl_surface *surface)
+{
+ flushDisplay();
+
+ auto *idleInhibitor = zwp_idle_inhibit_manager_v1_create_inhibitor(
+ idleInhibitManager, surface);
+ zwp_idle_inhibitor_v1_set_user_data(idleInhibitor, this);
+ return idleInhibitor;
+}
+
+MockXdgOutputV1 *MockClient::createXdgOutput(wl_output *output)
+{
+ auto *xdgOutput = new MockXdgOutputV1(xdgOutputManager->get_xdg_output(output));
+ m_xdgOutputs[output] = xdgOutput;
+ return xdgOutput;
+}
+
ShmBuffer::ShmBuffer(const QSize &size, wl_shm *shm)
{
int stride = size.width() * 4;
diff --git a/tests/auto/compositor/compositor/mockclient.h b/tests/auto/compositor/compositor/mockclient.h
index 31424cf79..89d0a0b3f 100644
--- a/tests/auto/compositor/compositor/mockclient.h
+++ b/tests/auto/compositor/compositor/mockclient.h
@@ -30,6 +30,7 @@
#include <qwayland-xdg-shell.h>
#include <wayland-ivi-application-client-protocol.h>
#include "wayland-viewporter-client-protocol.h"
+#include "wayland-idle-inhibit-unstable-v1-client-protocol.h"
#include <QObject>
#include <QImage>
@@ -38,6 +39,8 @@
#include <QtCore/QMap>
#include <QWaylandOutputMode>
+#include "mockxdgoutputv1.h"
+
class MockSeat;
class ShmBuffer
@@ -64,16 +67,21 @@ public:
xdg_surface *createXdgSurface(wl_surface *surface);
xdg_toplevel *createXdgToplevel(xdg_surface *xdgSurface);
ivi_surface *createIviSurface(wl_surface *surface, uint iviId);
+ zwp_idle_inhibitor_v1 *createIdleInhibitor(wl_surface *surface);
+ MockXdgOutputV1 *createXdgOutput(wl_output *output);
wl_display *display = nullptr;
wl_compositor *compositor = nullptr;
QMap<uint, wl_output *> m_outputs;
+ QMap<wl_output *, MockXdgOutputV1 *> m_xdgOutputs;
wl_shm *shm = nullptr;
wl_registry *registry = nullptr;
wl_shell *wlshell = nullptr;
xdg_wm_base *xdgWmBase = nullptr;
wp_viewporter *viewporter = nullptr;
ivi_application *iviApplication = nullptr;
+ zwp_idle_inhibit_manager_v1 *idleInhibitManager = nullptr;
+ QtWayland::zxdg_output_manager_v1 *xdgOutputManager = nullptr;
QList<MockSeat *> m_seats;
diff --git a/tests/auto/compositor/compositor/mockxdgoutputv1.cpp b/tests/auto/compositor/compositor/mockxdgoutputv1.cpp
new file mode 100644
index 000000000..eebc55bbb
--- /dev/null
+++ b/tests/auto/compositor/compositor/mockxdgoutputv1.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mockxdgoutputv1.h"
+
+MockXdgOutputV1::MockXdgOutputV1(struct ::zxdg_output_v1 *object)
+ : QtWayland::zxdg_output_v1(object)
+{
+}
+
+MockXdgOutputV1::~MockXdgOutputV1()
+{
+ destroy();
+}
+
+void MockXdgOutputV1::zxdg_output_v1_logical_position(int32_t x, int32_t y)
+{
+ pending.logicalPosition = QPoint(x, y);
+}
+
+void MockXdgOutputV1::zxdg_output_v1_logical_size(int32_t width, int32_t height)
+{
+ pending.logicalSize = QSize(width, height);
+}
+
+void MockXdgOutputV1::zxdg_output_v1_done()
+{
+ // In version 3 we'll have to do this for wl_output.done as well
+ name = pending.name;
+ description = pending.description;
+ logicalPosition = pending.logicalPosition;
+ logicalSize = pending.logicalSize;
+}
+
+void MockXdgOutputV1::zxdg_output_v1_name(const QString &name)
+{
+ pending.name = name;
+}
+
+void MockXdgOutputV1::zxdg_output_v1_description(const QString &description)
+{
+ pending.description = description;
+}
diff --git a/tests/auto/compositor/compositor/mockxdgoutputv1.h b/tests/auto/compositor/compositor/mockxdgoutputv1.h
new file mode 100644
index 000000000..db5820698
--- /dev/null
+++ b/tests/auto/compositor/compositor/mockxdgoutputv1.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MOCKXDGOUTPUTV1_H
+#define MOCKXDGOUTPUTV1_H
+
+#include <QPoint>
+#include <QSize>
+#include <QString>
+
+#include "qwayland-xdg-output-unstable-v1.h"
+
+class MockXdgOutputV1 : public QtWayland::zxdg_output_v1
+{
+public:
+ explicit MockXdgOutputV1(struct ::zxdg_output_v1 *object);
+ ~MockXdgOutputV1();
+
+ QString name;
+ QString description;
+ QPoint logicalPosition;
+ QSize logicalSize;
+
+ struct {
+ QString name;
+ QString description;
+ QPoint logicalPosition;
+ QSize logicalSize;
+ } pending;
+
+protected:
+ void zxdg_output_v1_logical_position(int32_t x, int32_t y) override;
+ void zxdg_output_v1_logical_size(int32_t width, int32_t height) override;
+ void zxdg_output_v1_done() override;
+ void zxdg_output_v1_name(const QString &name) override;
+ void zxdg_output_v1_description(const QString &description) override;
+};
+
+#endif // MOCKXDGOUTPUTV1_H
diff --git a/tests/auto/compositor/compositor/tst_compositor.cpp b/tests/auto/compositor/compositor/tst_compositor.cpp
index c425f2ba1..7fbe8979b 100644
--- a/tests/auto/compositor/compositor/tst_compositor.cpp
+++ b/tests/auto/compositor/compositor/tst_compositor.cpp
@@ -29,6 +29,7 @@
#include "mockclient.h"
#include "mockseat.h"
#include "mockpointer.h"
+#include "mockxdgoutputv1.h"
#include "testcompositor.h"
#include "testkeyboardgrabber.h"
#include "testseat.h"
@@ -47,8 +48,12 @@
#include <QtWaylandCompositor/QWaylandResource>
#include <QtWaylandCompositor/QWaylandKeymap>
#include <QtWaylandCompositor/QWaylandViewporter>
+#include <QtWaylandCompositor/QWaylandIdleInhibitManagerV1>
+#include <QtWaylandCompositor/QWaylandXdgOutputManagerV1>
#include <qwayland-xdg-shell.h>
#include <qwayland-ivi-application.h>
+#include <QtWaylandCompositor/private/qwaylandoutput_p.h>
+#include <QtWaylandCompositor/private/qwaylandsurface_p.h>
#include <QtTest/QtTest>
@@ -73,12 +78,14 @@ private slots:
void singleClient();
void multipleClients();
void geometry();
+ void availableGeometry();
void modes();
void comparingModes();
void sizeFollowsWindow();
void mapSurface();
void mapSurfaceHiDpi();
void frameCallback();
+ void pixelFormats();
void outputs();
void customSurface();
@@ -110,6 +117,10 @@ private slots:
void viewportDestinationNoSurfaceError();
void viewportSourceNoSurfaceError();
void viewportHiDpi();
+
+ void idleInhibit();
+
+ void xdgOutput();
};
void tst_WaylandCompositor::init() {
@@ -367,6 +378,22 @@ void tst_WaylandCompositor::geometry()
QTRY_COMPARE(client.refreshRate, 60000);
}
+void tst_WaylandCompositor::availableGeometry()
+{
+ TestCompositor compositor;
+ compositor.create();
+
+ QWaylandOutputMode mode(QSize(1024, 768), 60000);
+ compositor.defaultOutput()->addMode(mode, true);
+ compositor.defaultOutput()->setCurrentMode(mode);
+
+ MockClient client;
+
+ QRect availableGeometry(50, 100, 850, 600);
+ compositor.defaultOutput()->setAvailableGeometry(availableGeometry);
+ QCOMPARE(compositor.defaultOutput()->availableGeometry(), availableGeometry);
+}
+
void tst_WaylandCompositor::modes()
{
TestCompositor compositor;
@@ -513,8 +540,13 @@ void tst_WaylandCompositor::mapSurfaceHiDpi()
QObject::connect(waylandSurface, &QWaylandSurface::hasContentChanged, verifyComittedState);
QSignalSpy hasContentSpy(waylandSurface, SIGNAL(hasContentChanged()));
+#if QT_DEPRECATED_SINCE(5, 13)
QObject::connect(waylandSurface, &QWaylandSurface::sizeChanged, verifyComittedState);
QSignalSpy sizeSpy(waylandSurface, SIGNAL(sizeChanged()));
+#endif
+
+ QObject::connect(waylandSurface, &QWaylandSurface::bufferSizeChanged, verifyComittedState);
+ QSignalSpy bufferSizeSpy(waylandSurface, SIGNAL(bufferSizeChanged()));
QObject::connect(waylandSurface, &QWaylandSurface::destinationSizeChanged, verifyComittedState);
QSignalSpy destinationSizeSpy(waylandSurface, SIGNAL(destinationSizeChanged()));
@@ -538,7 +570,10 @@ void tst_WaylandCompositor::mapSurfaceHiDpi()
wl_surface_commit(surface);
QTRY_COMPARE(hasContentSpy.count(), 1);
+#if QT_DEPRECATED_SINCE(5, 13)
QTRY_COMPARE(sizeSpy.count(), 1);
+#endif
+ QTRY_COMPARE(bufferSizeSpy.count(), 1);
QTRY_COMPARE(destinationSizeSpy.count(), 1);
QTRY_COMPARE(bufferScaleSpy.count(), 1);
QTRY_COMPARE(offsetSpy.count(), 1);
@@ -561,27 +596,27 @@ static void registerFrameCallback(wl_surface *surface, int *counter)
wl_callback_add_listener(wl_surface_frame(surface), &frameCallbackListener, counter);
}
-void tst_WaylandCompositor::frameCallback()
+class BufferView : public QWaylandView
{
- class BufferView : public QWaylandView
+public:
+ void bufferCommitted(const QWaylandBufferRef &ref, const QRegion &damage) override
{
- public:
- void bufferCommitted(const QWaylandBufferRef &ref, const QRegion &damage) override
- {
- Q_UNUSED(damage);
- bufferRef = ref;
- }
+ Q_UNUSED(damage);
+ bufferRef = ref;
+ }
- QImage image() const
- {
- if (bufferRef.isNull() || !bufferRef.isSharedMemory())
- return QImage();
- return bufferRef.image();
- }
+ QImage image() const
+ {
+ if (bufferRef.isNull() || !bufferRef.isSharedMemory())
+ return QImage();
+ return bufferRef.image();
+ }
- QWaylandBufferRef bufferRef;
- };
+ QWaylandBufferRef bufferRef;
+};
+void tst_WaylandCompositor::frameCallback()
+{
TestCompositor compositor;
compositor.create();
@@ -622,6 +657,35 @@ void tst_WaylandCompositor::frameCallback()
wl_surface_destroy(surface);
}
+void tst_WaylandCompositor::pixelFormats()
+{
+ TestCompositor compositor;
+ compositor.create();
+
+ MockClient client;
+
+ wl_surface *surface = client.createSurface();
+ QTRY_COMPARE(compositor.surfaces.size(), 1);
+ QWaylandSurface *waylandSurface = compositor.surfaces.at(0);
+ BufferView* view = new BufferView;
+ view->setSurface(waylandSurface);
+ view->setOutput(compositor.defaultOutput());
+
+ QSize size(32, 32);
+ ShmBuffer buffer(size, client.shm); // Will be WL_SHM_FORMAT_ARGB8888;
+ wl_surface_attach(surface, buffer.handle, 0, 0);
+ wl_surface_damage(surface, 0, 0, size.width(), size.height());
+ wl_surface_commit(surface);
+
+ QTRY_COMPARE(waylandSurface->hasContent(), true);
+
+ // According to https://lists.freedesktop.org/archives/wayland-devel/2017-August/034791.html
+ // all RGB formats with alpha are premultiplied. Verify it here:
+ QCOMPARE(view->image().format(), QImage::Format_ARGB32_Premultiplied);
+
+ wl_surface_destroy(surface);
+}
+
void tst_WaylandCompositor::outputs()
{
TestCompositor compositor;
@@ -715,9 +779,8 @@ void tst_WaylandCompositor::seatCreation()
// The compositor will create the default input device
QTRY_VERIFY(seat->isInitialized());
- QList<QMouseEvent *> allEvents;
- allEvents += seat->createMouseEvents(5);
- foreach (QMouseEvent *me, allEvents) {
+ const QList<QMouseEvent *> allEvents = seat->createMouseEvents(5);
+ for (QMouseEvent *me : allEvents) {
compositor.seatFor(me);
}
@@ -846,6 +909,11 @@ void tst_WaylandCompositor::inputRegion()
QVERIFY(!waylandSurface->inputRegionContains(QPoint(1, 6)));
QVERIFY(!waylandSurface->inputRegionContains(QPoint(4, 2)));
+ QVERIFY(!waylandSurface->inputRegionContains(QPointF(0.99, 1.99)));
+ QVERIFY(waylandSurface->inputRegionContains(QPointF(1, 2)));
+ QVERIFY(waylandSurface->inputRegionContains(QPointF(3.99, 4.99)));
+ QVERIFY(!waylandSurface->inputRegionContains(QPointF(4, 5)));
+
// Setting a nullptr input region means we want all events
wl_surface_set_input_region(surface, nullptr);
wl_surface_commit(surface);
@@ -1700,5 +1768,103 @@ void tst_WaylandCompositor::viewportHiDpi()
wl_surface_destroy(surface);
}
+class IdleInhibitCompositor : public TestCompositor
+{
+ Q_OBJECT
+public:
+ IdleInhibitCompositor() : idleInhibitManager(this) {}
+ QWaylandIdleInhibitManagerV1 idleInhibitManager;
+};
+
+void tst_WaylandCompositor::idleInhibit()
+{
+ IdleInhibitCompositor compositor;
+ compositor.create();
+ MockClient client;
+ QTRY_VERIFY(client.idleInhibitManager);
+
+ auto *surface = client.createSurface();
+ QVERIFY(surface);
+ QTRY_COMPARE(compositor.surfaces.size(), 1);
+
+ QWaylandSurface *waylandSurface = compositor.surfaces.at(0);
+ auto *waylandSurfacePrivate =
+ QWaylandSurfacePrivate::get(waylandSurface);
+ QVERIFY(waylandSurfacePrivate);
+
+ QSignalSpy changedSpy(waylandSurface, SIGNAL(inhibitsIdleChanged()));
+
+ QCOMPARE(waylandSurface->inhibitsIdle(), false);
+
+ auto *idleInhibitor = client.createIdleInhibitor(surface);
+ QVERIFY(idleInhibitor);
+ QTRY_COMPARE(waylandSurfacePrivate->idleInhibitors.size(), 1);
+ QCOMPARE(waylandSurface->inhibitsIdle(), true);
+ QTRY_COMPARE(changedSpy.count(), 1);
+}
+
+class XdgOutputCompositor : public TestCompositor
+{
+ Q_OBJECT
+public:
+ XdgOutputCompositor() : xdgOutputManager(this) {}
+ QWaylandXdgOutputManagerV1 xdgOutputManager;
+};
+
+void tst_WaylandCompositor::xdgOutput()
+{
+ XdgOutputCompositor compositor;
+ compositor.create();
+
+ QWaylandOutputMode mode(QSize(1024, 768), 60000);
+ compositor.defaultOutput()->addMode(mode, true);
+ compositor.defaultOutput()->setCurrentMode(mode);
+
+ MockClient client;
+ QTRY_VERIFY(client.xdgOutputManager);
+ QTRY_COMPARE(client.m_outputs.size(), 1);
+
+ auto *wlOutput = client.m_outputs.first();
+ QVERIFY(wlOutput);
+
+ // Output is not associated yet
+ QCOMPARE(QWaylandOutputPrivate::get(compositor.defaultOutput())->xdgOutput.isNull(), true);
+
+ // Create xdg-output on the server
+ auto *xdgOutputServer = new QWaylandXdgOutputV1(compositor.defaultOutput(), &compositor.xdgOutputManager);
+ QVERIFY(xdgOutputServer);
+ xdgOutputServer->setName(QStringLiteral("OUTPUT1"));
+ xdgOutputServer->setDescription(QStringLiteral("This is a test output"));
+
+ // Create it on the client
+ auto *xdgOutput = client.createXdgOutput(wlOutput);
+ QVERIFY(xdgOutput);
+ QVERIFY(client.m_xdgOutputs.contains(wlOutput));
+
+ // Now it should be associated
+ QCOMPARE(QWaylandOutputPrivate::get(compositor.defaultOutput())->xdgOutput.isNull(), false);
+
+ // Verify initial values
+ QTRY_COMPARE(xdgOutput->name, "OUTPUT1");
+ QTRY_COMPARE(xdgOutput->logicalPosition, QPoint());
+ QTRY_COMPARE(xdgOutput->logicalSize, QSize());
+
+ // Change properties
+ xdgOutputServer->setName(QStringLiteral("OUTPUT2"));
+ xdgOutputServer->setDescription(QStringLiteral("New description"));
+ xdgOutputServer->setLogicalPosition(QPoint(100, 100));
+ xdgOutputServer->setLogicalSize(QSize(1000, 1000));
+ compositor.flushClients();
+
+ // Name and description can't be changed after initialization,
+ // so we expect them to be the same
+ // TODO: With protocol version 3 the description will be allowed to change,
+ // but we implement version 2 now
+ QTRY_COMPARE(xdgOutput->name, "OUTPUT1");
+ QTRY_COMPARE(xdgOutput->description, "This is a test output");
+ QTRY_COMPARE(xdgOutput->logicalPosition, QPoint(100, 100));
+ QTRY_COMPARE(xdgOutput->logicalSize, QSize(1000, 1000));
+}
+
#include <tst_compositor.moc>
QTEST_MAIN(tst_WaylandCompositor);
diff --git a/tests/manual/texture-sharing/cpp-client/cpp-client.pro b/tests/manual/texture-sharing/cpp-client/cpp-client.pro
new file mode 100644
index 000000000..d251791db
--- /dev/null
+++ b/tests/manual/texture-sharing/cpp-client/cpp-client.pro
@@ -0,0 +1,15 @@
+QT += waylandclient-private gui-private
+CONFIG += wayland-scanner
+
+WAYLANDCLIENTSOURCES += $$PWD/../../../../src/extensions/qt-texture-sharing-unstable-v1.xml
+
+SOURCES += main.cpp \
+ $$PWD/../../../../src/imports/texture-sharing/texturesharingextension.cpp
+
+HEADERS += \
+ $$PWD/../../../../src/imports/texture-sharing/texturesharingextension.h
+
+INCLUDEPATH += $$PWD/../../../../src/imports/texture-sharing/
+
+target.path = $$[QT_INSTALL_EXAMPLES]/wayland/texture-sharing/cpp-client
+INSTALLS += target
diff --git a/tests/manual/texture-sharing/cpp-client/main.cpp b/tests/manual/texture-sharing/cpp-client/main.cpp
new file mode 100644
index 000000000..e3f6d7025
--- /dev/null
+++ b/tests/manual/texture-sharing/cpp-client/main.cpp
@@ -0,0 +1,229 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2019 The Qt Company Ltd.
+ ** Contact: https://www.qt.io/licensing/
+ **
+ ** This file is part of the examples of the Qt Wayland module
+ **
+ ** $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 <QGuiApplication>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QOpenGLWindow>
+#include <QOpenGLTexture>
+#include <QOpenGLTextureBlitter>
+#include <QPainter>
+#include <QMouseEvent>
+#include <QPlatformSurfaceEvent>
+
+#include <QtWaylandClient/private/qwaylanddisplay_p.h>
+#include <QtWaylandClient/private/qwaylandintegration_p.h>
+#include <QtWaylandClient/private/qwaylandserverbufferintegration_p.h>
+#include "texturesharingextension.h"
+
+#include <QDebug>
+#include <QtGui/qpa/qplatformnativeinterface.h>
+#include <QTimer>
+#include <QMap>
+
+class TestWindow : public QOpenGLWindow
+{
+ Q_OBJECT
+
+public:
+ TestWindow()
+ : m_extension(nullptr)
+ {
+ m_extension = new TextureSharingExtension;
+ connect(m_extension, SIGNAL(bufferReceived(QtWaylandClient::QWaylandServerBuffer*, const QString&)), this, SLOT(receiveBuffer(QtWaylandClient::QWaylandServerBuffer*, const QString&)));
+ connect(m_extension, &TextureSharingExtension::activeChanged, this, &TestWindow::handleExtensionActive);
+ }
+
+public slots:
+ void receiveBuffer(QtWaylandClient::QWaylandServerBuffer *buffer, const QString &key)
+ {
+ if (!buffer) {
+ qWarning() << "Could not find image with key" << key;
+ return;
+ }
+ m_buffers.insert(key, buffer);
+ update();
+ }
+
+
+ void handleExtensionActive()
+ {
+ if (m_extension->isActive())
+ getImage("qt_logo");
+ }
+
+protected:
+
+ void mousePressEvent(QMouseEvent *ev) override {
+ QRect rect(10, height() - 10 - 50, 50, 50);
+ bool rectPressed = rect.contains(ev->pos());
+
+ static int c;
+
+ if (rectPressed && ev->button() == Qt::LeftButton)
+ getImage(QString("unreasonably large image %1").arg(c++));
+ else if (ev->button() == Qt::RightButton)
+ getImage("guitar.jpg");
+ else if (ev->button() == Qt::MiddleButton)
+ unloadImageAt(ev->pos());
+ }
+
+ void initializeGL() override
+ {
+ m_blitter = new QOpenGLTextureBlitter;
+ m_blitter->create();
+ }
+
+ void paintGL() override {
+ glClearColor(.5, .45, .42, 1.);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // draw a "button" to click in
+ glScissor(10,10,50,50);
+ glEnable(GL_SCISSOR_TEST);
+ glClearColor(0.4, 0.7, 0.9, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glDisable(GL_SCISSOR_TEST);
+
+ int x = 0;
+ qDebug() << "*** paintGL ***";
+ showBuffers();
+ for (auto buffer: qAsConst(m_buffers)) {
+ m_blitter->bind();
+ QSize s(buffer->size());
+ qDebug() << "painting" << buffer << s;
+ if (s.width() > 1024) {
+ qDebug() << "showing large buffer at reduced size";
+ s = QSize(128,128);
+ }
+ QRectF targetRect(QPointF(x,0), s);
+ QOpenGLTexture *texture = buffer->toOpenGlTexture();
+ if (!texture) {
+ qWarning("Null texture");
+ continue;
+ }
+ auto surfaceOrigin = QOpenGLTextureBlitter::OriginTopLeft;
+ QMatrix4x4 targetTransform = QOpenGLTextureBlitter::targetTransform(targetRect, QRect(QPoint(), size()));
+ m_blitter->blit(texture->textureId(), targetTransform, surfaceOrigin);
+ m_blitter->release();
+ x += s.width() + 10;
+ }
+ }
+
+private:
+ void getImage(const QString &key) {
+ if (!m_buffers.contains(key))
+ m_extension->requestImage(key);
+ }
+
+ void showBuffers() const
+ {
+ auto end = m_buffers.cend();
+ for (auto it = m_buffers.cbegin(); it != end; ++it) {
+ qDebug() << " " << it.key() << it.value();
+ }
+ }
+
+ void unloadImageAt(const QPoint &pos) {
+ int x = 0;
+ QtWaylandClient::QWaylandServerBuffer *foundBuffer = nullptr;
+ QString name;
+ auto end = m_buffers.cend();
+ for (auto it = m_buffers.cbegin(); it != end; ++it) {
+ auto *buffer = it.value();
+ QSize s(buffer->size());
+ if (s.width() > 1024)
+ s = QSize(128,128);
+ QRectF targetRect(QPointF(x,0), s);
+ //qDebug() << " " << it.key() << it.value() << targetRect << pos;
+
+ if (targetRect.contains(pos)) {
+ foundBuffer = buffer;
+ name = it.key();
+ //qDebug() << "FOUND!!";
+ break;
+ }
+
+ x += s.width() + 10;
+ }
+ if (foundBuffer) {
+ qDebug() << "unloading image" << name << "found at" << pos;
+ unloadImage(name);
+ } else {
+ qDebug() << "no image at" << pos;
+ }
+ }
+
+ void unloadImage(const QString &key) {
+ auto *buf = m_buffers.take(key);
+ if (buf) {
+ qDebug() << "unloadImage deleting" << buf;
+ delete buf;
+ m_extension->abandonImage(key);
+ }
+ update();
+ }
+
+ QOpenGLTextureBlitter *m_blitter = nullptr;
+ TextureSharingExtension *m_extension = nullptr;
+ QMap<QString, QtWaylandClient::QWaylandServerBuffer*> m_buffers;
+
+};
+
+int main (int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+
+ TestWindow window;
+ window.show();
+
+ return app.exec();
+}
+
+#include "main.moc"