Advance Wayland and KDE package bring-up
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#include "kwin_wayland_test.h"
|
||||
|
||||
#include "core/output.h"
|
||||
#include "decorations/decorationbridge.h"
|
||||
#include "decorations/settings.h"
|
||||
#include "pointer_input.h"
|
||||
#include "wayland_server.h"
|
||||
#include "window.h"
|
||||
#include "workspace.h"
|
||||
|
||||
#include <KWayland/Client/compositor.h>
|
||||
#include <KWayland/Client/shm_pool.h>
|
||||
#include <KWayland/Client/surface.h>
|
||||
|
||||
#include <KDecoration3/DecoratedWindow>
|
||||
#include <KDecoration3/Decoration>
|
||||
#include <KDecoration3/DecorationSettings>
|
||||
|
||||
#include <QSignalSpy>
|
||||
|
||||
using namespace KWin;
|
||||
|
||||
static const QString s_socketName = QStringLiteral("wayland_test_kwin_maximized-0");
|
||||
|
||||
class TestMaximized : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
void testMaximizedPassedToDeco();
|
||||
void testInitiallyMaximizedBorderless();
|
||||
void testBorderlessMaximizedWindow();
|
||||
void testMaximizedGainFocusAndBeActivated();
|
||||
};
|
||||
|
||||
void TestMaximized::initTestCase()
|
||||
{
|
||||
qRegisterMetaType<KWin::Window *>();
|
||||
QVERIFY(waylandServer()->init(s_socketName));
|
||||
Test::setOutputConfig({
|
||||
QRect(0, 0, 1280, 1024),
|
||||
QRect(1280, 0, 1280, 1024),
|
||||
});
|
||||
|
||||
kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
|
||||
|
||||
kwinApp()->start();
|
||||
const auto outputs = workspace()->outputs();
|
||||
QCOMPARE(outputs.count(), 2);
|
||||
QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
|
||||
QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
|
||||
}
|
||||
|
||||
void TestMaximized::init()
|
||||
{
|
||||
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::XdgDecorationV1));
|
||||
|
||||
workspace()->setActiveOutput(QPoint(640, 512));
|
||||
KWin::input()->pointer()->warp(QPoint(640, 512));
|
||||
}
|
||||
|
||||
void TestMaximized::cleanup()
|
||||
{
|
||||
Test::destroyWaylandConnection();
|
||||
|
||||
// adjust config
|
||||
auto group = kwinApp()->config()->group(QStringLiteral("Windows"));
|
||||
group.writeEntry("BorderlessMaximizedWindows", false);
|
||||
group.sync();
|
||||
Workspace::self()->slotReconfigure();
|
||||
QCOMPARE(options->borderlessMaximizedWindows(), false);
|
||||
}
|
||||
|
||||
void TestMaximized::testMaximizedPassedToDeco()
|
||||
{
|
||||
// this test verifies that when a XdgShellClient gets maximized the Decoration receives the signal
|
||||
|
||||
// Create the test window.
|
||||
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
|
||||
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly));
|
||||
std::unique_ptr<Test::XdgToplevelDecorationV1> xdgDecoration(Test::createXdgToplevelDecorationV1(shellSurface.get()));
|
||||
|
||||
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
|
||||
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
|
||||
surface->commit(KWayland::Client::Surface::CommitFlag::None);
|
||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||
|
||||
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
|
||||
QVERIFY(window);
|
||||
QVERIFY(window->isDecorated());
|
||||
|
||||
auto decoration = window->decoration();
|
||||
QVERIFY(decoration);
|
||||
QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeRestore);
|
||||
|
||||
// Wait for configure event that signals the window is active now.
|
||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
|
||||
|
||||
// now maximize
|
||||
QSignalSpy bordersChangedSpy(decoration, &KDecoration3::Decoration::bordersChanged);
|
||||
QSignalSpy maximizedChangedSpy(decoration->window(), &KDecoration3::DecoratedWindow::maximizedChanged);
|
||||
QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
|
||||
|
||||
workspace()->slotWindowMaximize();
|
||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
|
||||
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(1280, 1024 - decoration->borderTop()));
|
||||
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).toSize(), Qt::red);
|
||||
QVERIFY(frameGeometryChangedSpy.wait());
|
||||
|
||||
// If no borders, there is only the initial geometry shape change, but none through border resizing.
|
||||
QCOMPARE(frameGeometryChangedSpy.count(), 1);
|
||||
QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeFull);
|
||||
QCOMPARE(maximizedChangedSpy.count(), 1);
|
||||
QCOMPARE(maximizedChangedSpy.last().first().toBool(), true);
|
||||
|
||||
// now unmaximize again
|
||||
workspace()->slotWindowMaximize();
|
||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 4);
|
||||
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(100, 50));
|
||||
|
||||
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||
Test::render(surface.get(), QSize(100, 50), Qt::red);
|
||||
QVERIFY(frameGeometryChangedSpy.wait());
|
||||
QCOMPARE(frameGeometryChangedSpy.count(), 2);
|
||||
QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeRestore);
|
||||
QCOMPARE(maximizedChangedSpy.count(), 2);
|
||||
QCOMPARE(maximizedChangedSpy.last().first().toBool(), false);
|
||||
|
||||
// Destroy the test window.
|
||||
shellSurface.reset();
|
||||
QVERIFY(Test::waitForWindowClosed(window));
|
||||
}
|
||||
|
||||
void TestMaximized::testInitiallyMaximizedBorderless()
|
||||
{
|
||||
// This test verifies that a window created as maximized, will be maximized and without Border with BorderlessMaximizedWindows
|
||||
|
||||
// adjust config
|
||||
auto group = kwinApp()->config()->group(QStringLiteral("Windows"));
|
||||
group.writeEntry("BorderlessMaximizedWindows", true);
|
||||
group.sync();
|
||||
Workspace::self()->slotReconfigure();
|
||||
QCOMPARE(options->borderlessMaximizedWindows(), true);
|
||||
|
||||
// Create the test window.
|
||||
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
|
||||
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly));
|
||||
std::unique_ptr<Test::XdgToplevelDecorationV1> decoration(Test::createXdgToplevelDecorationV1(shellSurface.get()));
|
||||
|
||||
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
|
||||
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
|
||||
shellSurface->set_maximized();
|
||||
QSignalSpy decorationConfigureRequestedSpy(decoration.get(), &Test::XdgToplevelDecorationV1::configureRequested);
|
||||
decoration->set_mode(Test::XdgToplevelDecorationV1::mode_server_side);
|
||||
surface->commit(KWayland::Client::Surface::CommitFlag::None);
|
||||
|
||||
// Wait for the initial configure event.
|
||||
Test::XdgToplevel::States states;
|
||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
|
||||
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(1280, 1024));
|
||||
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
||||
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
|
||||
QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
|
||||
|
||||
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||
Window *window = Test::renderAndWaitForShown(surface.get(), QSize(1280, 1024), Qt::blue);
|
||||
QVERIFY(window);
|
||||
QVERIFY(!window->isDecorated());
|
||||
QVERIFY(window->isActive());
|
||||
QVERIFY(window->isMaximizable());
|
||||
QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeFull);
|
||||
QCOMPARE(window->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
||||
QCOMPARE(window->frameGeometry(), QRect(0, 0, 1280, 1024));
|
||||
QCOMPARE(decorationConfigureRequestedSpy.last().at(0).value<Test::XdgToplevelDecorationV1::mode>(),
|
||||
Test::XdgToplevelDecorationV1::mode_server_side);
|
||||
|
||||
// Destroy the window.
|
||||
shellSurface.reset();
|
||||
surface.reset();
|
||||
QVERIFY(Test::waitForWindowClosed(window));
|
||||
}
|
||||
void TestMaximized::testBorderlessMaximizedWindow()
|
||||
{
|
||||
// This test verifies that a maximized window looses it's server-side
|
||||
// decoration when the borderless maximized option is on.
|
||||
|
||||
// Enable the borderless maximized windows option.
|
||||
auto group = kwinApp()->config()->group(QStringLiteral("Windows"));
|
||||
group.writeEntry("BorderlessMaximizedWindows", true);
|
||||
group.sync();
|
||||
Workspace::self()->slotReconfigure();
|
||||
QCOMPARE(options->borderlessMaximizedWindows(), true);
|
||||
|
||||
// Create the test window.
|
||||
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
|
||||
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly));
|
||||
std::unique_ptr<Test::XdgToplevelDecorationV1> decoration(Test::createXdgToplevelDecorationV1(shellSurface.get()));
|
||||
|
||||
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
|
||||
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
|
||||
QSignalSpy decorationConfigureRequestedSpy(decoration.get(), &Test::XdgToplevelDecorationV1::configureRequested);
|
||||
decoration->set_mode(Test::XdgToplevelDecorationV1::mode_server_side);
|
||||
surface->commit(KWayland::Client::Surface::CommitFlag::None);
|
||||
|
||||
// Wait for the initial configure event.
|
||||
Test::XdgToplevel::States states;
|
||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
|
||||
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(0, 0));
|
||||
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
||||
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
|
||||
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
|
||||
|
||||
// Map the window.
|
||||
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||
Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
|
||||
QVERIFY(window);
|
||||
QVERIFY(window->isActive());
|
||||
QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeRestore);
|
||||
QCOMPARE(window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
|
||||
QCOMPARE(window->isDecorated(), true);
|
||||
|
||||
// We should receive a configure event when the window becomes active.
|
||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
|
||||
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
||||
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
||||
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
|
||||
|
||||
// Maximize the window.
|
||||
const QRectF maximizeRestoreGeometry = window->frameGeometry();
|
||||
workspace()->slotWindowMaximize();
|
||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
|
||||
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(1280, 1024));
|
||||
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
||||
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
||||
QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
|
||||
|
||||
QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
|
||||
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||
Test::render(surface.get(), QSize(1280, 1024), Qt::blue);
|
||||
QVERIFY(frameGeometryChangedSpy.wait());
|
||||
QCOMPARE(window->frameGeometry(), QRect(0, 0, 1280, 1024));
|
||||
QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeFull);
|
||||
QCOMPARE(window->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
|
||||
QCOMPARE(window->isDecorated(), false);
|
||||
|
||||
// Restore the window.
|
||||
workspace()->slotWindowMaximize();
|
||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 4);
|
||||
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(100, 50));
|
||||
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
||||
QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
|
||||
QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
|
||||
|
||||
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||
Test::render(surface.get(), QSize(100, 50), Qt::red);
|
||||
QVERIFY(frameGeometryChangedSpy.wait());
|
||||
QCOMPARE(window->frameGeometry(), maximizeRestoreGeometry);
|
||||
QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeRestore);
|
||||
QCOMPARE(window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
|
||||
QCOMPARE(window->isDecorated(), true);
|
||||
|
||||
// Destroy the window.
|
||||
shellSurface.reset();
|
||||
QVERIFY(Test::waitForWindowClosed(window));
|
||||
}
|
||||
|
||||
void TestMaximized::testMaximizedGainFocusAndBeActivated()
|
||||
{
|
||||
// This test verifies that a window will be raised and gain focus when it's maximized
|
||||
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
|
||||
std::unique_ptr<Test::XdgToplevel> xdgShellSurface(Test::createXdgToplevelSurface(surface.get()));
|
||||
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
|
||||
std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
|
||||
std::unique_ptr<Test::XdgToplevel> xdgShellSurface2(Test::createXdgToplevelSurface(surface2.get()));
|
||||
auto window2 = Test::renderAndWaitForShown(surface2.get(), QSize(100, 50), Qt::blue);
|
||||
|
||||
QVERIFY(!window->isActive());
|
||||
QVERIFY(window2->isActive());
|
||||
QCOMPARE(workspace()->stackingOrder(), (QList<Window *>{window, window2}));
|
||||
|
||||
workspace()->performWindowOperation(window, Options::MaximizeOp);
|
||||
|
||||
QVERIFY(window->isActive());
|
||||
QVERIFY(!window2->isActive());
|
||||
QCOMPARE(workspace()->stackingOrder(), (QList<Window *>{window2, window}));
|
||||
|
||||
xdgShellSurface.reset();
|
||||
QVERIFY(Test::waitForWindowClosed(window));
|
||||
xdgShellSurface2.reset();
|
||||
QVERIFY(Test::waitForWindowClosed(window2));
|
||||
}
|
||||
|
||||
WAYLANDTEST_MAIN(TestMaximized)
|
||||
#include "maximize_test.moc"
|
||||
Reference in New Issue
Block a user