summaryrefslogtreecommitdiffstats
path: root/tests/auto/client/xdgshell/tst_xdgshell.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/client/xdgshell/tst_xdgshell.cpp')
-rw-r--r--tests/auto/client/xdgshell/tst_xdgshell.cpp455
1 files changed, 371 insertions, 84 deletions
diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp
index ac5c24988..1dc57e280 100644
--- a/tests/auto/client/xdgshell/tst_xdgshell.cpp
+++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp
@@ -1,36 +1,12 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// Copyright (C) 2023 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockcompositor.h"
#include <QtGui/QRasterWindow>
-#include <QtGui/QOpenGLWindow>
#include <QtGui/qpa/qplatformnativeinterface.h>
#include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
+#include <QtWaylandClient/private/qwaylandwindow_p.h>
using namespace MockCompositor;
@@ -38,23 +14,36 @@ class tst_xdgshell : public QObject, private DefaultCompositor
{
Q_OBJECT
private slots:
+ void init();
void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); }
void showMinimized();
void basicConfigure();
void configureSize();
void configureStates();
+ void configureBounds();
void popup();
void tooltipOnPopup();
+ void tooltipAndSiblingPopup();
void switchPopups();
+ void hidePopupParent();
void pongs();
+ void minMaxSize_data();
void minMaxSize();
void windowGeometry();
void foreignSurface();
+ void nativeResources();
+ void suspended();
+ void initiallySuspended();
+ void modality();
};
+void tst_xdgshell::init()
+{
+ setenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1", 1);
+}
+
void tst_xdgshell::showMinimized()
{
- QSKIP("TODO: This currently fails, needs a fix");
// On xdg-shell there's really no way for the compositor to tell the window if it's minimized
// There are wl_surface.enter events and so on, but there's really no way to differentiate
// between a window preview and an unminimized window.
@@ -76,13 +65,13 @@ void tst_xdgshell::basicConfigure()
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- QSignalSpy configureSpy(exec([=] { return xdgSurface(); }), &XdgSurface::configureCommitted);
+ QSignalSpy configureSpy(exec([&] { return xdgSurface(); }), &XdgSurface::configureCommitted);
QTRY_VERIFY(window.isVisible());
// The window should not be exposed before the first xdg_surface configure event
QTRY_VERIFY(!window.isExposed());
- exec([=] {
+ exec([&] {
xdgToplevel()->sendConfigure({0, 0}, {}); // Let the window decide the size
});
@@ -90,9 +79,9 @@ void tst_xdgshell::basicConfigure()
QTRY_VERIFY(!window.isExposed()); //Window should not be exposed before the first configure event
QVERIFY(configureSpy.isEmpty());
- const uint serial = exec([=] { return nextSerial(); });
+ const uint serial = exec([&] { return nextSerial(); });
- exec([=] {
+ exec([&] {
xdgSurface()->sendConfigure(serial);
});
@@ -100,7 +89,7 @@ void tst_xdgshell::basicConfigure()
QTRY_VERIFY(window.isExposed());
// The client is now going to ack the configure
- QTRY_COMPARE(configureSpy.count(), 1);
+ QTRY_COMPARE(configureSpy.size(), 1);
QCOMPARE(configureSpy.takeFirst().at(0).toUInt(), serial);
// And attach a buffer
@@ -118,17 +107,17 @@ void tst_xdgshell::configureSize()
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- QSignalSpy configureSpy(exec([=] { return xdgSurface(); }), &XdgSurface::configureCommitted);
+ QSignalSpy configureSpy(exec([&] { return xdgSurface(); }), &XdgSurface::configureCommitted);
const QSize configureSize(60, 40);
- exec([=] {
+ exec([&] {
xdgToplevel()->sendCompleteConfigure(configureSize);
});
- QTRY_COMPARE(configureSpy.count(), 1);
+ QTRY_COMPARE(configureSpy.size(), 1);
- exec([=] {
+ exec([&] {
Buffer *buffer = xdgToplevel()->surface()->m_committed.buffer;
QVERIFY(buffer);
QCOMPARE(buffer->size(), configureSize);
@@ -137,13 +126,14 @@ void tst_xdgshell::configureSize()
void tst_xdgshell::configureStates()
{
+ QVERIFY(qputenv("QT_WAYLAND_FRAME_CALLBACK_TIMEOUT", "0"));
QRasterWindow window;
window.resize(64, 48);
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
const QSize windowedSize(320, 240);
- const uint windowedSerial = exec([=] {
+ const uint windowedSerial = exec([&] {
return xdgToplevel()->sendCompleteConfigure(windowedSize, { XdgToplevel::state_activated });
});
QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, windowedSerial);
@@ -153,12 +143,15 @@ void tst_xdgshell::configureStates()
// Toplevel windows don't know their position on xdg-shell
// QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
-// QEXPECT_FAIL("", "configure has already been acked, we shouldn't have to wait for isActive", Continue);
-// QVERIFY(window.isActive());
- QTRY_VERIFY(window.isActive()); // Just make sure it eventually get's set correctly
+ // window.windowstate() is driven by keyboard focus, however for decorations we want to follow
+ // XDGShell this is internal to QtWayland so it is queried directly
+ auto waylandWindow = static_cast<QtWaylandClient::QWaylandWindow *>(window.handle());
+ Q_ASSERT(waylandWindow);
+ QTRY_VERIFY(waylandWindow->windowStates().testFlag(
+ Qt::WindowActive)); // Just make sure it eventually get's set correctly
const QSize screenSize(640, 480);
- const uint maximizedSerial = exec([=] {
+ const uint maximizedSerial = exec([&] {
return xdgToplevel()->sendCompleteConfigure(screenSize, { XdgToplevel::state_activated, XdgToplevel::state_maximized });
});
QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, maximizedSerial);
@@ -167,7 +160,7 @@ void tst_xdgshell::configureStates()
QCOMPARE(window.frameGeometry().size(), screenSize);
// QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
- const uint fullscreenSerial = exec([=] {
+ const uint fullscreenSerial = exec([&] {
return xdgToplevel()->sendCompleteConfigure(screenSize, { XdgToplevel::state_activated, XdgToplevel::state_fullscreen });
});
QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, fullscreenSerial);
@@ -177,7 +170,7 @@ void tst_xdgshell::configureStates()
// QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
// The window should remember its original size
- const uint restoreSerial = exec([=] {
+ const uint restoreSerial = exec([&] {
return xdgToplevel()->sendCompleteConfigure({0, 0}, { XdgToplevel::state_activated });
});
QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, restoreSerial);
@@ -185,6 +178,31 @@ void tst_xdgshell::configureStates()
QCOMPARE(window.windowStates(), Qt::WindowNoState);
QCOMPARE(window.frameGeometry().size(), windowedSize);
// QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
+ QVERIFY(qunsetenv("QT_WAYLAND_FRAME_CALLBACK_TIMEOUT"));
+}
+
+void tst_xdgshell::configureBounds()
+{
+ QRasterWindow window;
+ window.resize(1280, 1024);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+
+ // Take xdg_toplevel.configure_bounds into account only if the configure event has 0x0 size.
+ const uint serial1 = exec([&] {
+ xdgToplevel()->sendConfigureBounds(QSize(800, 600));
+ return xdgToplevel()->sendCompleteConfigure(QSize(0, 0), { XdgToplevel::state_activated });
+ });
+ QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, serial1);
+ QCOMPARE(window.frameGeometry().size(), QSize(800, 600));
+
+ // Window size in xdg_toplevel configure events takes precedence over the configure bounds.
+ const uint serial2 = exec([&] {
+ xdgToplevel()->sendConfigureBounds(QSize(800, 600));
+ return xdgToplevel()->sendCompleteConfigure(QSize(1600, 900), { XdgToplevel::state_activated });
+ });
+ QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, serial2);
+ QCOMPARE(window.frameGeometry().size(), QSize(1600, 900));
}
void tst_xdgshell::popup()
@@ -207,11 +225,11 @@ void tst_xdgshell::popup()
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- QSignalSpy toplevelConfigureSpy(exec([=] { return xdgSurface(); }), &XdgSurface::configureCommitted);
- exec([=] { xdgToplevel()->sendCompleteConfigure(); });
- QTRY_COMPARE(toplevelConfigureSpy.count(), 1);
+ QSignalSpy toplevelConfigureSpy(exec([&] { return xdgSurface(); }), &XdgSurface::configureCommitted);
+ exec([&] { xdgToplevel()->sendCompleteConfigure(); });
+ QTRY_COMPARE(toplevelConfigureSpy.size(), 1);
- uint clickSerial = exec([=] {
+ uint clickSerial = exec([&] {
auto *surface = xdgToplevel()->surface();
auto *p = pointer();
auto *c = client();
@@ -219,27 +237,27 @@ void tst_xdgshell::popup()
p->sendFrame(c);
uint serial = p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
p->sendButton(c, BTN_LEFT, Pointer::button_state_released);
- return serial;
p->sendFrame(c);
+ return serial;
});
QTRY_VERIFY(window.m_popup);
QCOMPOSITOR_TRY_VERIFY(xdgPopup());
- QSignalSpy popupConfigureSpy(exec([=] { return xdgPopup()->m_xdgSurface; }), &XdgSurface::configureCommitted);
+ QSignalSpy popupConfigureSpy(exec([&] { return xdgPopup()->m_xdgSurface; }), &XdgSurface::configureCommitted);
QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_grabbed);
QCOMPOSITOR_TRY_COMPARE(xdgPopup()->m_grabSerial, clickSerial);
QRasterWindow *popup = window.m_popup.get();
QVERIFY(!popup->isExposed()); // wait for configure
- //TODO: Verify it works with a different configure window geometry
- exec([=] { xdgPopup()->sendConfigure(QRect(100, 100, 100, 100)); });
+ QRect rect1 = QRect(100, 100, 100, 100);
+ exec([&] { xdgPopup()->sendConfigure(rect1); });
// Nothing should happen before the *xdg_surface* configure
QTRY_VERIFY(!popup->isExposed()); // Popup shouldn't be exposed before the first configure event
QVERIFY(popupConfigureSpy.isEmpty());
- const uint configureSerial = exec([=] {
+ const uint configureSerial = exec([&] {
return xdgPopup()->m_xdgSurface->sendConfigure();
});
@@ -247,8 +265,20 @@ void tst_xdgshell::popup()
QTRY_VERIFY(popup->isExposed());
// The client is now going to ack the configure
- QTRY_COMPARE(popupConfigureSpy.count(), 1);
+ QTRY_COMPARE(popupConfigureSpy.size(), 1);
QCOMPARE(popupConfigureSpy.takeFirst().at(0).toUInt(), configureSerial);
+ QCOMPARE(popup->geometry(), rect1);
+
+ QRect rect2 = QRect(50, 50, 150, 150);
+ exec([&] { xdgPopup()->sendConfigure(rect2); });
+
+ const uint configureSerial2 = exec([&] {
+ return xdgPopup()->m_xdgSurface->sendConfigure();
+ });
+
+ QTRY_COMPARE(popupConfigureSpy.size(), 1);
+ QCOMPARE(popupConfigureSpy.takeFirst().at(0).toUInt(), configureSerial2);
+ QCOMPARE(popup->geometry(), rect2);
// And attach a buffer
exec([&] {
@@ -293,10 +323,10 @@ void tst_xdgshell::tooltipOnPopup()
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+ exec([&] { xdgToplevel()->sendCompleteConfigure(); });
QCOMPOSITOR_TRY_VERIFY(xdgToplevel()->m_xdgSurface->m_committedConfigureSerial);
- exec([=] {
+ exec([&] {
auto *surface = xdgToplevel()->surface();
auto *p = pointer();
auto *c = client();
@@ -310,11 +340,11 @@ void tst_xdgshell::tooltipOnPopup()
});
QCOMPOSITOR_TRY_VERIFY(xdgPopup());
- exec([=] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
+ exec([&] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_xdgSurface->m_committedConfigureSerial);
QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_grabbed);
- exec([=] {
+ exec([&] {
auto *surface = xdgPopup()->surface();
auto *p = pointer();
auto *c = client();
@@ -326,7 +356,7 @@ void tst_xdgshell::tooltipOnPopup()
});
QCOMPOSITOR_TRY_VERIFY(xdgPopup(1));
- exec([=] { xdgPopup(1)->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
+ exec([&] { xdgPopup(1)->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
QCOMPOSITOR_TRY_VERIFY(xdgPopup(1)->m_xdgSurface->m_committedConfigureSerial);
QCOMPOSITOR_TRY_VERIFY(!xdgPopup(1)->m_grabbed);
@@ -339,6 +369,92 @@ void tst_xdgshell::tooltipOnPopup()
QCOMPOSITOR_TRY_COMPARE(xdgPopup(0), nullptr);
}
+void tst_xdgshell::tooltipAndSiblingPopup()
+{
+ class ToolTip : public QRasterWindow {
+ public:
+ explicit ToolTip(QWindow *parent) {
+ setTransientParent(parent);
+ setFlags(Qt::ToolTip);
+ resize(100, 100);
+ show();
+ }
+ void mousePressEvent(QMouseEvent *event) override {
+ QRasterWindow::mousePressEvent(event);
+ m_popup = new QRasterWindow;
+ m_popup->setTransientParent(transientParent());
+ m_popup->setFlags(Qt::Popup);
+ m_popup->resize(100, 100);
+ m_popup->show();
+ }
+
+ QRasterWindow *m_popup = nullptr;
+ };
+
+ class Window : public QRasterWindow {
+ public:
+ void mousePressEvent(QMouseEvent *event) override {
+ QRasterWindow::mousePressEvent(event);
+ m_tooltip = new ToolTip(this);
+ }
+ ToolTip *m_tooltip = nullptr;
+ };
+
+ Window window;
+ window.resize(200, 200);
+ window.show();
+
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+ exec([&] { xdgToplevel()->sendCompleteConfigure(); });
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel()->m_xdgSurface->m_committedConfigureSerial);
+
+ exec([&] {
+ auto *surface = xdgToplevel()->surface();
+ auto *p = pointer();
+ auto *c = client();
+ p->sendEnter(surface, {100, 100});
+ p->sendFrame(c);
+ p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
+ p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
+ p->sendFrame(c);
+ p->sendLeave(surface);
+ p->sendFrame(c);
+ });
+
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup());
+ exec([&] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_xdgSurface->m_committedConfigureSerial);
+ QCOMPOSITOR_TRY_VERIFY(!xdgPopup()->m_grabbed);
+
+ exec([&] {
+ auto *surface = xdgPopup()->surface();
+ auto *p = pointer();
+ auto *c = client();
+ p->sendEnter(surface, {100, 100});
+ p->sendFrame(c);
+ p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
+ p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
+ p->sendFrame(c);
+ });
+
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup(1));
+ exec([&] { xdgPopup(1)->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup(1)->m_xdgSurface->m_committedConfigureSerial);
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup(1)->m_grabbed);
+
+ // Close the middle tooltip (it should not close the sibling popup)
+ window.m_tooltip->close();
+
+ QCOMPOSITOR_TRY_COMPARE(xdgPopup(1), nullptr);
+ // Verify the remaining xdg surface is a grab popup..
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup(0));
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup(0)->m_grabbed);
+
+ window.m_tooltip->m_popup->close();
+ QCOMPOSITOR_TRY_COMPARE(xdgPopup(1), nullptr);
+ QCOMPOSITOR_TRY_COMPARE(xdgPopup(0), nullptr);
+}
+
// QTBUG-65680
void tst_xdgshell::switchPopups()
{
@@ -369,7 +485,7 @@ void tst_xdgshell::switchPopups()
m_popups << new Popup(this);
}
~Window() override { qDeleteAll(m_popups); }
- QVector<Popup *> m_popups;
+ QList<Popup *> m_popups;
};
Window window;
@@ -377,10 +493,10 @@ void tst_xdgshell::switchPopups()
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+ exec([&] { xdgToplevel()->sendCompleteConfigure(); });
QCOMPOSITOR_TRY_VERIFY(xdgToplevel()->m_xdgSurface->m_committedConfigureSerial);
- exec([=] {
+ exec([&] {
auto *surface = xdgToplevel()->surface();
auto *p = pointer();
auto *c = client();
@@ -394,13 +510,13 @@ void tst_xdgshell::switchPopups()
});
QCOMPOSITOR_TRY_VERIFY(xdgPopup());
- exec([=] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
+ exec([&] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_xdgSurface->m_committedConfigureSerial);
QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_grabbed);
- QSignalSpy firstDestroyed(exec([=] { return xdgPopup(); }), &XdgPopup::destroyRequested);
+ QSignalSpy firstDestroyed(exec([&] { return xdgPopup(); }), &XdgPopup::destroyRequested);
- exec([=] {
+ exec([&] {
auto *surface = xdgToplevel()->surface();
auto *p = pointer();
auto *c = client();
@@ -425,10 +541,54 @@ void tst_xdgshell::switchPopups()
QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_parentXdgSurface == xdgToplevel()->m_xdgSurface);
// For good measure just check that configuring works as usual
- exec([=] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
+ exec([&] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_xdgSurface->m_committedConfigureSerial);
}
+void tst_xdgshell::hidePopupParent()
+{
+ class Window : public QRasterWindow {
+ public:
+ void mousePressEvent(QMouseEvent *event) override
+ {
+ QRasterWindow::mousePressEvent(event);
+ m_popup.reset(new QRasterWindow);
+ m_popup->setTransientParent(this);
+ m_popup->setFlags(Qt::Popup);
+ m_popup->resize(100, 100);
+ m_popup->show();
+ }
+ QScopedPointer<QRasterWindow> m_popup;
+ };
+ Window window;
+ window.resize(200, 200);
+ window.show();
+
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+ exec([&] { xdgToplevel()->sendCompleteConfigure(); });
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel()->m_xdgSurface->m_committedConfigureSerial);
+
+ exec([&] {
+ auto *surface = xdgToplevel()->surface();
+ auto *p = pointer();
+ auto *c = client();
+ p->sendEnter(surface, {100, 100});
+ p->sendFrame(c);
+ p->sendButton(c, BTN_LEFT, Pointer::button_state_pressed);
+ p->sendButton(c, BTN_LEFT, Pointer::button_state_released);
+ p->sendFrame(c);
+ });
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup());
+ exec([&] {
+ xdgPopup()->sendConfigure(QRect(100, 100, 100, 100));
+ xdgPopup()->m_xdgSurface->sendConfigure();
+ });
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_xdgSurface->m_committedConfigureSerial);
+
+ window.hide();
+ QCOMPOSITOR_TRY_VERIFY(!xdgToplevel());
+}
+
void tst_xdgshell::pongs()
{
// Create and show a window to trigger shell integration initialzation,
@@ -440,36 +600,80 @@ void tst_xdgshell::pongs()
// Verify that the client has bound to the global
QCOMPOSITOR_TRY_COMPARE(get<XdgWmBase>()->resourceMap().size(), 1);
- QSignalSpy pongSpy(exec([=] { return get<XdgWmBase>(); }), &XdgWmBase::pong);
- const uint serial = exec([=] { return nextSerial(); });
- exec([=] {
+ QSignalSpy pongSpy(exec([&] { return get<XdgWmBase>(); }), &XdgWmBase::pong);
+ const uint serial = exec([&] { return nextSerial(); });
+ exec([&] {
auto *base = get<XdgWmBase>();
wl_resource *resource = base->resourceMap().first()->handle;
base->send_ping(resource, serial);
});
- QTRY_COMPARE(pongSpy.count(), 1);
+ QTRY_COMPARE(pongSpy.size(), 1);
QCOMPARE(pongSpy.first().at(0).toUInt(), serial);
}
+void tst_xdgshell::minMaxSize_data()
+{
+ QTest::addColumn<QSize>("initialMinSize");
+ QTest::addColumn<QSize>("initialMaxSize");
+ QTest::addColumn<QSize>("nextMinSize");
+ QTest::addColumn<QSize>("nextMaxSize");
+ QTest::addColumn<QSize>("expectedInitialMinSize");
+ QTest::addColumn<QSize>("expectedInitialMaxSize");
+ QTest::addColumn<QSize>("expectedNextMinSize");
+ QTest::addColumn<QSize>("expectedNextMaxSize");
+
+ QTest::newRow("onlyMinSize") << QSize(50, 60) << QSize() << QSize(500, 600) << QSize()
+ << QSize(50, 60) << QSize(0, 0) << QSize(500, 600) << QSize(0, 0);
+
+ QTest::newRow("onlyMaxSize") << QSize() << QSize(70, 80) << QSize() << QSize(700, 800)
+ << QSize(0,0 ) << QSize(70, 80) << QSize(0, 0) << QSize(700, 800);
+
+ QTest::newRow("maxIsSentAsZero") << QSize() << QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX) << QSize() << QSize()
+ << QSize(0,0 ) << QSize(0, 0) << QSize(0, 0) << QSize(0, 0);
+
+
+ QTest::newRow("fullHints") << QSize(50, 60) << QSize(700, 800) << QSize(500, 600) << QSize(710, 810)
+ << QSize(50, 60) << QSize(700, 800) << QSize(500, 600) << QSize(710, 810);
+
+ // setting a minimum above the maximum is not allowed, we should no-op
+ QTest::newRow("invalidResize") << QSize(50, 60) << QSize(100, 100) << QSize(500, 600) << QSize(100, 100)
+ << QSize(50, 60) << QSize(100, 100) << QSize(50, 60) << QSize(100, 100);}
+
void tst_xdgshell::minMaxSize()
{
+ QFETCH(QSize, initialMinSize);
+ QFETCH(QSize, initialMaxSize);
+
+ QFETCH(QSize, expectedInitialMinSize);
+ QFETCH(QSize, expectedInitialMaxSize);
+
QRasterWindow window;
- window.setMinimumSize(QSize(100, 100));
- window.setMaximumSize(QSize(1000, 1000));
- window.resize(400, 320);
+ if (initialMinSize.isValid())
+ window.setMinimumSize(initialMinSize);
+ if (initialMaxSize.isValid())
+ window.setMaximumSize(initialMaxSize);
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+ exec([&] { xdgToplevel()->sendCompleteConfigure(); });
- QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.minSize, QSize(100, 100));
- QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.maxSize, QSize(1000, 1000));
+ // we don't roundtrip with our configuration the initial commit should be correct
- window.setMaximumSize(QSize(500, 400));
- QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.maxSize, QSize(500, 400));
+ QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.minSize, expectedInitialMinSize);
+ QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.maxSize, expectedInitialMaxSize);
- window.setMinimumSize(QSize(50, 40));
- QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.minSize, QSize(50, 40));
+ QFETCH(QSize, nextMinSize);
+ QFETCH(QSize, expectedNextMinSize);
+ window.setMinimumSize(nextMinSize);
+ window.update();
+ QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.minSize, expectedNextMinSize);
+
+ QFETCH(QSize, nextMaxSize);
+ QFETCH(QSize, expectedNextMaxSize);
+
+ window.setMaximumSize(nextMaxSize);
+ window.update();
+ QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.maxSize, expectedNextMaxSize);
}
void tst_xdgshell::windowGeometry()
@@ -479,7 +683,7 @@ void tst_xdgshell::windowGeometry()
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+ exec([&] { xdgToplevel()->sendCompleteConfigure(); });
QSize marginsSize;
marginsSize.setWidth(window.frameMargins().left() + window.frameMargins().right());
@@ -511,12 +715,95 @@ void tst_xdgshell::foreignSurface()
// 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);
+ QSignalSpy spy(exec([&] { return surface(newSurfaceIndex); }), &Surface::commit);
wl_surface_commit(foreignSurface);
- QTRY_COMPARE(spy.count(), 1);
+ QTRY_COMPARE(spy.size(), 1);
wl_surface_destroy(foreignSurface);
}
+void tst_xdgshell::nativeResources()
+{
+ QRasterWindow window;
+ window.resize(400, 320);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+
+ auto *ni = QGuiApplication::platformNativeInterface();
+ auto *xdg_surface_proxy = static_cast<::wl_proxy *>(ni->nativeResourceForWindow("xdg_surface", &window));
+ QCOMPARE(wl_proxy_get_class(xdg_surface_proxy), "xdg_surface");
+
+ auto *xdg_toplevel_proxy = static_cast<::wl_proxy *>(ni->nativeResourceForWindow("xdg_toplevel", &window));
+ QCOMPARE(wl_proxy_get_class(xdg_toplevel_proxy), "xdg_toplevel");
+
+ auto *xdg_popup_proxy = static_cast<::wl_proxy *>(ni->nativeResourceForWindow("xdg_popup", &window));
+ QCOMPARE(xdg_popup_proxy, nullptr);
+}
+
+void tst_xdgshell::suspended()
+{
+ QRasterWindow window;
+ window.resize(400, 320);
+ window.show();
+ QVERIFY(!window.isExposed()); // not exposed until we're configured
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+
+ exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel()->m_xdgSurface->m_committedConfigureSerial);
+ QTRY_VERIFY(window.isExposed());
+
+ exec([=] { xdgToplevel()->sendCompleteConfigure(QSize(), {XdgToplevel::state_suspended}); });
+ QTRY_VERIFY(!window.isExposed());
+
+ exec([=] { xdgToplevel()->sendCompleteConfigure(QSize(), {}); });
+ QTRY_VERIFY(window.isExposed());
+}
+
+void tst_xdgshell::initiallySuspended()
+{
+ QRasterWindow window;
+ window.resize(400, 320);
+ window.show();
+ QVERIFY(!window.isExposed());
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+ exec([=] { xdgToplevel()->sendCompleteConfigure(QSize(), {XdgToplevel::state_suspended}); });
+ QVERIFY(!window.isExposed());
+}
+
+void tst_xdgshell::modality()
+{
+ QRasterWindow parent;
+ parent.resize(400, 320);
+ parent.show();
+
+ QRasterWindow child;
+ child.resize(400, 320);
+ child.setTransientParent(&parent);
+ child.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel(1));
+ QCOMPOSITOR_VERIFY(!xdgDialog());
+
+ child.hide();
+ child.setModality(Qt::WindowModal);
+ child.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgDialog());
+ QCOMPOSITOR_VERIFY(xdgDialog()->modal);
+
+ child.hide();
+ QCOMPOSITOR_TRY_VERIFY(!xdgDialog());
+
+ child.setModality(Qt::ApplicationModal);
+ child.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgDialog());
+ QCOMPOSITOR_VERIFY(xdgDialog()->modal);
+
+ child.hide();
+ QCOMPOSITOR_TRY_VERIFY(!xdgDialog());
+
+ child.show();
+ child.setModality(Qt::NonModal);
+ QCOMPOSITOR_TRY_VERIFY(!xdgDialog());
+}
+
QCOMPOSITOR_TEST_MAIN(tst_xdgshell)
#include "tst_xdgshell.moc"