wayland: Properly handle async xdg-decoration updates
Currently, if a window switches between SSD and CSD, it is possible to encounter a "corrupted" state where the server-side decoration is wrapped around the window while it still has the client-side decoration. The xdg-decoration protocol fixes this problem by saying that decoration updates are bound to xdg_surface configure events. At the moment, kwin sort of applies decoration updates immediately. With this change, decoration updates will be done according to the spec. If the compositor wants to create a decoration, it will send a configure event and apply the decoration when the configure event is acked by the client. In order to send the configure event with a good window geometry size, kwin will create the decoration to query the border size but not assign it to the client yet. As is, KDecoration api doesn't make querying the border size ahead of time easy. The decoration plugin can assign arbitrary border sizes to windows as it pleases it. We could change that, but it effectively means starting KDecoration3 and setting existing window deco ecosystem around kwin on fire the second time, that's off the table. If the compositor wants to remove the decoration, it will send a configure event. When the configure event is acked and the surface is committed, the window decoration will be destroyed. Sync'ing decoration updates to configure events ensures that we cannot end up with having both client-side and server-side decoration. It also helps us to fix a bunch of geometry related issues caused by creating and destroying the decoration without any surface buffer attached yet. BUG: 445259
This commit is contained in:
parent
db996e0824
commit
acb0683e0d
11 changed files with 275 additions and 222 deletions
|
@ -28,7 +28,6 @@
|
||||||
#include <KWayland/Client/compositor.h>
|
#include <KWayland/Client/compositor.h>
|
||||||
#include <KWayland/Client/keyboard.h>
|
#include <KWayland/Client/keyboard.h>
|
||||||
#include <KWayland/Client/pointer.h>
|
#include <KWayland/Client/pointer.h>
|
||||||
#include <KWayland/Client/server_decoration.h>
|
|
||||||
#include <KWayland/Client/seat.h>
|
#include <KWayland/Client/seat.h>
|
||||||
#include <KWayland/Client/shm_pool.h>
|
#include <KWayland/Client/shm_pool.h>
|
||||||
#include <KWayland/Client/surface.h>
|
#include <KWayland/Client/surface.h>
|
||||||
|
@ -97,16 +96,21 @@ AbstractClient *DecorationInputTest::showWindow()
|
||||||
|
|
||||||
KWayland::Client::Surface *surface = Test::createSurface(Test::waylandCompositor());
|
KWayland::Client::Surface *surface = Test::createSurface(Test::waylandCompositor());
|
||||||
VERIFY(surface);
|
VERIFY(surface);
|
||||||
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface, surface);
|
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface, Test::CreationSetup::CreateOnly, surface);
|
||||||
VERIFY(shellSurface);
|
VERIFY(shellSurface);
|
||||||
auto deco = Test::waylandServerSideDecoration()->create(surface, surface);
|
Test::XdgToplevelDecorationV1 *decoration = Test::createXdgToplevelDecorationV1(shellSurface, shellSurface);
|
||||||
QSignalSpy decoSpy(deco, &ServerSideDecoration::modeChanged);
|
VERIFY(decoration);
|
||||||
VERIFY(decoSpy.isValid());
|
|
||||||
VERIFY(decoSpy.wait());
|
QSignalSpy decorationConfigureRequestedSpy(decoration, &Test::XdgToplevelDecorationV1::configureRequested);
|
||||||
deco->requestMode(ServerSideDecoration::Mode::Server);
|
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
|
||||||
VERIFY(decoSpy.wait());
|
|
||||||
COMPARE(deco->mode(), ServerSideDecoration::Mode::Server);
|
decoration->set_mode(Test::XdgToplevelDecorationV1::mode_server_side);
|
||||||
|
surface->commit(KWayland::Client::Surface::CommitFlag::None);
|
||||||
|
VERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
|
COMPARE(decorationConfigureRequestedSpy.last().at(0).value<Test::XdgToplevelDecorationV1::mode>(), Test::XdgToplevelDecorationV1::mode_server_side);
|
||||||
|
|
||||||
// let's render
|
// let's render
|
||||||
|
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||||
auto c = Test::renderAndWaitForShown(surface, QSize(500, 50), Qt::blue);
|
auto c = Test::renderAndWaitForShown(surface, QSize(500, 50), Qt::blue);
|
||||||
VERIFY(c);
|
VERIFY(c);
|
||||||
COMPARE(workspace()->activeClient(), c);
|
COMPARE(workspace()->activeClient(), c);
|
||||||
|
@ -149,7 +153,7 @@ void DecorationInputTest::initTestCase()
|
||||||
void DecorationInputTest::init()
|
void DecorationInputTest::init()
|
||||||
{
|
{
|
||||||
using namespace KWayland::Client;
|
using namespace KWayland::Client;
|
||||||
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat | Test::AdditionalWaylandInterface::Decoration));
|
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat | Test::AdditionalWaylandInterface::XdgDecorationV1));
|
||||||
QVERIFY(Test::waitForWaylandPointer());
|
QVERIFY(Test::waitForWaylandPointer());
|
||||||
|
|
||||||
workspace()->setActiveOutput(QPoint(640, 512));
|
workspace()->setActiveOutput(QPoint(640, 512));
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include "workspace.h"
|
#include "workspace.h"
|
||||||
#include <kwineffects.h>
|
#include <kwineffects.h>
|
||||||
|
|
||||||
#include <KWayland/Client/server_decoration.h>
|
|
||||||
#include <KWayland/Client/surface.h>
|
#include <KWayland/Client/surface.h>
|
||||||
|
|
||||||
#include <KDecoration2/Decoration>
|
#include <KDecoration2/Decoration>
|
||||||
|
@ -72,7 +71,7 @@ void DontCrashNoBorder::initTestCase()
|
||||||
|
|
||||||
void DontCrashNoBorder::init()
|
void DontCrashNoBorder::init()
|
||||||
{
|
{
|
||||||
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Decoration));
|
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::XdgDecorationV1));
|
||||||
|
|
||||||
workspace()->setActiveOutput(QPoint(640, 512));
|
workspace()->setActiveOutput(QPoint(640, 512));
|
||||||
Cursors::self()->mouse()->setPos(QPoint(640, 512));
|
Cursors::self()->mouse()->setPos(QPoint(640, 512));
|
||||||
|
@ -86,20 +85,20 @@ void DontCrashNoBorder::cleanup()
|
||||||
void DontCrashNoBorder::testCreateWindow()
|
void DontCrashNoBorder::testCreateWindow()
|
||||||
{
|
{
|
||||||
// create a window and ensure that this doesn't crash
|
// create a window and ensure that this doesn't crash
|
||||||
using namespace KWayland::Client;
|
|
||||||
|
|
||||||
QScopedPointer<KWayland::Client::Surface> surface(Test::createSurface());
|
QScopedPointer<KWayland::Client::Surface> surface(Test::createSurface());
|
||||||
QVERIFY(!surface.isNull());
|
QScopedPointer<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.data(), Test::CreationSetup::CreateOnly));
|
||||||
QScopedPointer<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.data()));
|
QScopedPointer<Test::XdgToplevelDecorationV1> decoration(Test::createXdgToplevelDecorationV1(shellSurface.data()));
|
||||||
QVERIFY(shellSurface);
|
QSignalSpy decorationConfigureRequestedSpy(decoration.data(), &Test::XdgToplevelDecorationV1::configureRequested);
|
||||||
QScopedPointer<ServerSideDecoration> deco(Test::waylandServerSideDecoration()->create(surface.data()));
|
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
|
||||||
QSignalSpy decoSpy(deco.data(), &ServerSideDecoration::modeChanged);
|
|
||||||
QVERIFY(decoSpy.isValid());
|
// Initialize the xdg-toplevel surface.
|
||||||
QVERIFY(decoSpy.wait());
|
decoration->set_mode(Test::XdgToplevelDecorationV1::mode_server_side);
|
||||||
deco->requestMode(ServerSideDecoration::Mode::Server);
|
surface->commit(KWayland::Client::Surface::CommitFlag::None);
|
||||||
QVERIFY(decoSpy.wait());
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
QCOMPARE(deco->mode(), ServerSideDecoration::Mode::Server);
|
QCOMPARE(decorationConfigureRequestedSpy.last().at(0).value<Test::XdgToplevelDecorationV1::mode>(), Test::XdgToplevelDecorationV1::mode_client_side);
|
||||||
|
|
||||||
// let's render
|
// let's render
|
||||||
|
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||||
auto c = Test::renderAndWaitForShown(surface.data(), QSize(500, 50), Qt::blue);
|
auto c = Test::renderAndWaitForShown(surface.data(), QSize(500, 50), Qt::blue);
|
||||||
QVERIFY(c);
|
QVERIFY(c);
|
||||||
QCOMPARE(workspace()->activeClient(), c);
|
QCOMPARE(workspace()->activeClient(), c);
|
||||||
|
|
|
@ -213,11 +213,17 @@ void PopupOpenCloseAnimationTest::testAnimateDecorationTooltips()
|
||||||
using namespace KWayland::Client;
|
using namespace KWayland::Client;
|
||||||
QScopedPointer<KWayland::Client::Surface> surface(Test::createSurface());
|
QScopedPointer<KWayland::Client::Surface> surface(Test::createSurface());
|
||||||
QVERIFY(!surface.isNull());
|
QVERIFY(!surface.isNull());
|
||||||
QScopedPointer<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.data()));
|
QScopedPointer<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.data(), Test::CreationSetup::CreateOnly));
|
||||||
QVERIFY(!shellSurface.isNull());
|
QVERIFY(!shellSurface.isNull());
|
||||||
QScopedPointer<Test::XdgToplevelDecorationV1> deco(Test::createXdgToplevelDecorationV1(shellSurface.data()));
|
QScopedPointer<Test::XdgToplevelDecorationV1> deco(Test::createXdgToplevelDecorationV1(shellSurface.data()));
|
||||||
QVERIFY(!deco.isNull());
|
QVERIFY(!deco.isNull());
|
||||||
|
|
||||||
|
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
|
||||||
deco->set_mode(Test::XdgToplevelDecorationV1::mode_server_side);
|
deco->set_mode(Test::XdgToplevelDecorationV1::mode_server_side);
|
||||||
|
surface->commit(KWayland::Client::Surface::CommitFlag::None);
|
||||||
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
|
|
||||||
|
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||||
AbstractClient *client = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
AbstractClient *client = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
||||||
QVERIFY(client);
|
QVERIFY(client);
|
||||||
QVERIFY(client->isDecorated());
|
QVERIFY(client->isDecorated());
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include <KWayland/Client/compositor.h>
|
#include <KWayland/Client/compositor.h>
|
||||||
#include <KWayland/Client/shm_pool.h>
|
#include <KWayland/Client/shm_pool.h>
|
||||||
#include <KWayland/Client/surface.h>
|
#include <KWayland/Client/surface.h>
|
||||||
#include <KWayland/Client/server_decoration.h>
|
|
||||||
#include <KWayland/Client/plasmashell.h>
|
#include <KWayland/Client/plasmashell.h>
|
||||||
|
|
||||||
#include <KDecoration2/DecoratedClient>
|
#include <KDecoration2/DecoratedClient>
|
||||||
|
@ -68,8 +67,7 @@ void TestMaximized::initTestCase()
|
||||||
|
|
||||||
void TestMaximized::init()
|
void TestMaximized::init()
|
||||||
{
|
{
|
||||||
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Decoration |
|
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::XdgDecorationV1 |
|
||||||
Test::AdditionalWaylandInterface::XdgDecorationV1 |
|
|
||||||
Test::AdditionalWaylandInterface::PlasmaShell));
|
Test::AdditionalWaylandInterface::PlasmaShell));
|
||||||
|
|
||||||
workspace()->setActiveOutput(QPoint(640, 512));
|
workspace()->setActiveOutput(QPoint(640, 512));
|
||||||
|
@ -94,9 +92,15 @@ void TestMaximized::testMaximizedPassedToDeco()
|
||||||
|
|
||||||
// Create the test client.
|
// Create the test client.
|
||||||
QScopedPointer<KWayland::Client::Surface> surface(Test::createSurface());
|
QScopedPointer<KWayland::Client::Surface> surface(Test::createSurface());
|
||||||
QScopedPointer<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.data()));
|
QScopedPointer<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.data(), Test::CreationSetup::CreateOnly));
|
||||||
QScopedPointer<ServerSideDecoration> ssd(Test::waylandServerSideDecoration()->create(surface.data()));
|
QScopedPointer<Test::XdgToplevelDecorationV1> xdgDecoration(Test::createXdgToplevelDecorationV1(shellSurface.data()));
|
||||||
|
|
||||||
|
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.data(), &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 client = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
auto client = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
||||||
QVERIFY(client);
|
QVERIFY(client);
|
||||||
QVERIFY(client->isDecorated());
|
QVERIFY(client->isDecorated());
|
||||||
|
@ -106,10 +110,8 @@ void TestMaximized::testMaximizedPassedToDeco()
|
||||||
QCOMPARE(client->maximizeMode(), MaximizeMode::MaximizeRestore);
|
QCOMPARE(client->maximizeMode(), MaximizeMode::MaximizeRestore);
|
||||||
|
|
||||||
// Wait for configure event that signals the client is active now.
|
// Wait for configure event that signals the client is active now.
|
||||||
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.data(), &Test::XdgToplevel::configureRequested);
|
|
||||||
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
|
|
||||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
|
QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
|
||||||
|
|
||||||
// When there are no borders, there is no change to them when maximizing.
|
// When there are no borders, there is no change to them when maximizing.
|
||||||
// TODO: we should test both cases with fixed fake decoration for autotests.
|
// TODO: we should test both cases with fixed fake decoration for autotests.
|
||||||
|
@ -125,7 +127,7 @@ void TestMaximized::testMaximizedPassedToDeco()
|
||||||
|
|
||||||
workspace()->slotWindowMaximize();
|
workspace()->slotWindowMaximize();
|
||||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
|
QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
|
||||||
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(1280, 1024 - decoration->borderTop()));
|
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(1280, 1024 - decoration->borderTop()));
|
||||||
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||||
Test::render(surface.data(), toplevelConfigureRequestedSpy.last().at(0).toSize(), Qt::red);
|
Test::render(surface.data(), toplevelConfigureRequestedSpy.last().at(0).toSize(), Qt::red);
|
||||||
|
@ -145,7 +147,7 @@ void TestMaximized::testMaximizedPassedToDeco()
|
||||||
// now unmaximize again
|
// now unmaximize again
|
||||||
workspace()->slotWindowMaximize();
|
workspace()->slotWindowMaximize();
|
||||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
|
QCOMPARE(surfaceConfigureRequestedSpy.count(), 4);
|
||||||
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(100, 50));
|
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(100, 50));
|
||||||
|
|
||||||
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include <KWayland/Client/compositor.h>
|
#include <KWayland/Client/compositor.h>
|
||||||
#include <KWayland/Client/connection_thread.h>
|
#include <KWayland/Client/connection_thread.h>
|
||||||
#include <KWayland/Client/seat.h>
|
#include <KWayland/Client/seat.h>
|
||||||
#include <KWayland/Client/server_decoration.h>
|
|
||||||
#include <KWayland/Client/surface.h>
|
#include <KWayland/Client/surface.h>
|
||||||
#include <KWayland/Client/touch.h>
|
#include <KWayland/Client/touch.h>
|
||||||
|
|
||||||
|
@ -70,7 +69,6 @@ void TouchInputTest::init()
|
||||||
{
|
{
|
||||||
using namespace KWayland::Client;
|
using namespace KWayland::Client;
|
||||||
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat |
|
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat |
|
||||||
Test::AdditionalWaylandInterface::Decoration |
|
|
||||||
Test::AdditionalWaylandInterface::XdgDecorationV1));
|
Test::AdditionalWaylandInterface::XdgDecorationV1));
|
||||||
QVERIFY(Test::waitForWaylandTouch());
|
QVERIFY(Test::waitForWaylandTouch());
|
||||||
m_touch = Test::waylandSeat()->createTouch(Test::waylandSeat());
|
m_touch = Test::waylandSeat()->createTouch(Test::waylandSeat());
|
||||||
|
@ -100,18 +98,17 @@ AbstractClient *TouchInputTest::showWindow(bool decorated)
|
||||||
|
|
||||||
KWayland::Client::Surface *surface = Test::createSurface(Test::waylandCompositor());
|
KWayland::Client::Surface *surface = Test::createSurface(Test::waylandCompositor());
|
||||||
VERIFY(surface);
|
VERIFY(surface);
|
||||||
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface, surface);
|
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface, Test::CreationSetup::CreateOnly, surface);
|
||||||
VERIFY(shellSurface);
|
VERIFY(shellSurface);
|
||||||
if (decorated) {
|
if (decorated) {
|
||||||
auto deco = Test::waylandServerSideDecoration()->create(surface, surface);
|
auto decoration = Test::createXdgToplevelDecorationV1(shellSurface, shellSurface);
|
||||||
QSignalSpy decoSpy(deco, &ServerSideDecoration::modeChanged);
|
decoration->set_mode(Test::XdgToplevelDecorationV1::mode_server_side);
|
||||||
VERIFY(decoSpy.isValid());
|
|
||||||
VERIFY(decoSpy.wait());
|
|
||||||
deco->requestMode(ServerSideDecoration::Mode::Server);
|
|
||||||
VERIFY(decoSpy.wait());
|
|
||||||
COMPARE(deco->mode(), ServerSideDecoration::Mode::Server);
|
|
||||||
}
|
}
|
||||||
|
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
|
||||||
|
surface->commit(KWayland::Client::Surface::CommitFlag::None);
|
||||||
|
VERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
// let's render
|
// let's render
|
||||||
|
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||||
auto c = Test::renderAndWaitForShown(surface, QSize(100, 50), Qt::blue);
|
auto c = Test::renderAndWaitForShown(surface, QSize(100, 50), Qt::blue);
|
||||||
|
|
||||||
VERIFY(c);
|
VERIFY(c);
|
||||||
|
|
|
@ -83,7 +83,6 @@ private Q_SLOTS:
|
||||||
void testUnresponsiveWindow_data();
|
void testUnresponsiveWindow_data();
|
||||||
void testUnresponsiveWindow();
|
void testUnresponsiveWindow();
|
||||||
void testAppMenu();
|
void testAppMenu();
|
||||||
void testNoDecorationModeRequested();
|
|
||||||
void testSendClientWithTransientToDesktop();
|
void testSendClientWithTransientToDesktop();
|
||||||
void testMinimizeWindowWithTransients();
|
void testMinimizeWindowWithTransients();
|
||||||
void testXdgDecoration_data();
|
void testXdgDecoration_data();
|
||||||
|
@ -187,8 +186,7 @@ void TestXdgShellClient::initTestCase()
|
||||||
|
|
||||||
void TestXdgShellClient::init()
|
void TestXdgShellClient::init()
|
||||||
{
|
{
|
||||||
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Decoration |
|
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat |
|
||||||
Test::AdditionalWaylandInterface::Seat |
|
|
||||||
Test::AdditionalWaylandInterface::XdgDecorationV1 |
|
Test::AdditionalWaylandInterface::XdgDecorationV1 |
|
||||||
Test::AdditionalWaylandInterface::AppMenu));
|
Test::AdditionalWaylandInterface::AppMenu));
|
||||||
QVERIFY(Test::waitForWaylandPointer());
|
QVERIFY(Test::waitForWaylandPointer());
|
||||||
|
@ -369,10 +367,10 @@ void TestXdgShellClient::testMinimizeActiveWindow()
|
||||||
|
|
||||||
void TestXdgShellClient::testFullscreen_data()
|
void TestXdgShellClient::testFullscreen_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<ServerSideDecoration::Mode>("decoMode");
|
QTest::addColumn<Test::XdgToplevelDecorationV1::mode>("decoMode");
|
||||||
|
|
||||||
QTest::newRow("client-side deco") << ServerSideDecoration::Mode::Client;
|
QTest::newRow("client-side deco") << Test::XdgToplevelDecorationV1::mode_client_side;
|
||||||
QTest::newRow("server-side deco") << ServerSideDecoration::Mode::Server;
|
QTest::newRow("server-side deco") << Test::XdgToplevelDecorationV1::mode_server_side;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestXdgShellClient::testFullscreen()
|
void TestXdgShellClient::testFullscreen()
|
||||||
|
@ -382,49 +380,43 @@ void TestXdgShellClient::testFullscreen()
|
||||||
Test::XdgToplevel::States states;
|
Test::XdgToplevel::States states;
|
||||||
|
|
||||||
QScopedPointer<KWayland::Client::Surface> surface(Test::createSurface());
|
QScopedPointer<KWayland::Client::Surface> surface(Test::createSurface());
|
||||||
QScopedPointer<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.data()));
|
QScopedPointer<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.data(), Test::CreationSetup::CreateOnly));
|
||||||
QVERIFY(shellSurface);
|
QScopedPointer<Test::XdgToplevelDecorationV1> decoration(Test::createXdgToplevelDecorationV1(shellSurface.data()));
|
||||||
|
QSignalSpy decorationConfigureRequestedSpy(decoration.data(), &Test::XdgToplevelDecorationV1::configureRequested);
|
||||||
|
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.data(), &Test::XdgToplevel::configureRequested);
|
||||||
|
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
|
||||||
|
|
||||||
// create deco
|
// Initialize the xdg-toplevel surface.
|
||||||
QScopedPointer<ServerSideDecoration> deco(Test::waylandServerSideDecoration()->create(surface.data()));
|
QFETCH(Test::XdgToplevelDecorationV1::mode, decoMode);
|
||||||
QSignalSpy decoSpy(deco.data(), &ServerSideDecoration::modeChanged);
|
decoration->set_mode(decoMode);
|
||||||
QVERIFY(decoSpy.isValid());
|
surface->commit(KWayland::Client::Surface::CommitFlag::None);
|
||||||
QVERIFY(decoSpy.wait());
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
QFETCH(ServerSideDecoration::Mode, decoMode);
|
|
||||||
deco->requestMode(decoMode);
|
|
||||||
QVERIFY(decoSpy.wait());
|
|
||||||
QCOMPARE(deco->mode(), decoMode);
|
|
||||||
|
|
||||||
|
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||||
auto client = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
auto client = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
||||||
QVERIFY(client);
|
QVERIFY(client);
|
||||||
QVERIFY(client->isActive());
|
QVERIFY(client->isActive());
|
||||||
QCOMPARE(client->layer(), NormalLayer);
|
QCOMPARE(client->layer(), NormalLayer);
|
||||||
QVERIFY(!client->isFullScreen());
|
QVERIFY(!client->isFullScreen());
|
||||||
QCOMPARE(client->clientSize(), QSize(100, 50));
|
QCOMPARE(client->clientSize(), QSize(100, 50));
|
||||||
QCOMPARE(client->isDecorated(), decoMode == ServerSideDecoration::Mode::Server);
|
QCOMPARE(client->isDecorated(), decoMode == Test::XdgToplevelDecorationV1::mode_server_side);
|
||||||
QCOMPARE(client->clientSizeToFrameSize(client->clientSize()), client->size());
|
QCOMPARE(client->clientSizeToFrameSize(client->clientSize()), client->size());
|
||||||
|
|
||||||
QSignalSpy fullScreenChangedSpy(client, &AbstractClient::fullScreenChanged);
|
QSignalSpy fullScreenChangedSpy(client, &AbstractClient::fullScreenChanged);
|
||||||
QVERIFY(fullScreenChangedSpy.isValid());
|
QVERIFY(fullScreenChangedSpy.isValid());
|
||||||
QSignalSpy frameGeometryChangedSpy(client, &AbstractClient::frameGeometryChanged);
|
QSignalSpy frameGeometryChangedSpy(client, &AbstractClient::frameGeometryChanged);
|
||||||
QVERIFY(frameGeometryChangedSpy.isValid());
|
QVERIFY(frameGeometryChangedSpy.isValid());
|
||||||
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.data(), &Test::XdgToplevel::configureRequested);
|
|
||||||
QVERIFY(toplevelConfigureRequestedSpy.isValid());
|
|
||||||
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
|
|
||||||
QVERIFY(surfaceConfigureRequestedSpy.isValid());
|
|
||||||
|
|
||||||
// Wait for the compositor to send a configure event with the Activated state.
|
// Wait for the compositor to send a configure event with the Activated state.
|
||||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
|
QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
|
||||||
QCOMPARE(toplevelConfigureRequestedSpy.count(), 1);
|
|
||||||
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
||||||
QVERIFY(states & Test::XdgToplevel::State::Activated);
|
QVERIFY(states & Test::XdgToplevel::State::Activated);
|
||||||
|
|
||||||
// Ask the compositor to show the window in full screen mode.
|
// Ask the compositor to show the window in full screen mode.
|
||||||
shellSurface->set_fullscreen(nullptr);
|
shellSurface->set_fullscreen(nullptr);
|
||||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
|
QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
|
||||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
|
|
||||||
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
||||||
QVERIFY(states & Test::XdgToplevel::State::Fullscreen);
|
QVERIFY(states & Test::XdgToplevel::State::Fullscreen);
|
||||||
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), client->output()->geometry().size());
|
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), client->output()->geometry().size());
|
||||||
|
@ -442,8 +434,7 @@ void TestXdgShellClient::testFullscreen()
|
||||||
// Ask the compositor to show the window in normal mode.
|
// Ask the compositor to show the window in normal mode.
|
||||||
shellSurface->unset_fullscreen();
|
shellSurface->unset_fullscreen();
|
||||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
|
QCOMPARE(surfaceConfigureRequestedSpy.count(), 4);
|
||||||
QCOMPARE(toplevelConfigureRequestedSpy.count(), 3);
|
|
||||||
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
||||||
QVERIFY(!(states & Test::XdgToplevel::State::Fullscreen));
|
QVERIFY(!(states & Test::XdgToplevel::State::Fullscreen));
|
||||||
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(100, 50));
|
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(100, 50));
|
||||||
|
@ -455,7 +446,7 @@ void TestXdgShellClient::testFullscreen()
|
||||||
QCOMPARE(fullScreenChangedSpy.count(), 2);
|
QCOMPARE(fullScreenChangedSpy.count(), 2);
|
||||||
QCOMPARE(client->clientSize(), QSize(100, 50));
|
QCOMPARE(client->clientSize(), QSize(100, 50));
|
||||||
QVERIFY(!client->isFullScreen());
|
QVERIFY(!client->isFullScreen());
|
||||||
QCOMPARE(client->isDecorated(), decoMode == ServerSideDecoration::Mode::Server);
|
QCOMPARE(client->isDecorated(), decoMode == Test::XdgToplevelDecorationV1::mode_server_side);
|
||||||
QCOMPARE(client->layer(), NormalLayer);
|
QCOMPARE(client->layer(), NormalLayer);
|
||||||
|
|
||||||
// Destroy the client.
|
// Destroy the client.
|
||||||
|
@ -476,10 +467,10 @@ void TestXdgShellClient::testUserCanSetFullscreen()
|
||||||
|
|
||||||
void TestXdgShellClient::testMaximizedToFullscreen_data()
|
void TestXdgShellClient::testMaximizedToFullscreen_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<ServerSideDecoration::Mode>("decoMode");
|
QTest::addColumn<Test::XdgToplevelDecorationV1::mode>("decoMode");
|
||||||
|
|
||||||
QTest::newRow("client-side deco") << ServerSideDecoration::Mode::Client;
|
QTest::newRow("client-side deco") << Test::XdgToplevelDecorationV1::mode_client_side;
|
||||||
QTest::newRow("server-side deco") << ServerSideDecoration::Mode::Server;
|
QTest::newRow("server-side deco") << Test::XdgToplevelDecorationV1::mode_server_side;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestXdgShellClient::testMaximizedToFullscreen()
|
void TestXdgShellClient::testMaximizedToFullscreen()
|
||||||
|
@ -489,45 +480,41 @@ void TestXdgShellClient::testMaximizedToFullscreen()
|
||||||
Test::XdgToplevel::States states;
|
Test::XdgToplevel::States states;
|
||||||
|
|
||||||
QScopedPointer<KWayland::Client::Surface> surface(Test::createSurface());
|
QScopedPointer<KWayland::Client::Surface> surface(Test::createSurface());
|
||||||
QScopedPointer<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.data()));
|
QScopedPointer<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.data(), Test::CreationSetup::CreateOnly));
|
||||||
QVERIFY(shellSurface);
|
QScopedPointer<Test::XdgToplevelDecorationV1> decoration(Test::createXdgToplevelDecorationV1(shellSurface.data()));
|
||||||
|
QSignalSpy decorationConfigureRequestedSpy(decoration.data(), &Test::XdgToplevelDecorationV1::configureRequested);
|
||||||
|
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.data(), &Test::XdgToplevel::configureRequested);
|
||||||
|
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
|
||||||
|
|
||||||
// create deco
|
// Initialize the xdg-toplevel surface.
|
||||||
QScopedPointer<ServerSideDecoration> deco(Test::waylandServerSideDecoration()->create(surface.data()));
|
QFETCH(Test::XdgToplevelDecorationV1::mode, decoMode);
|
||||||
QSignalSpy decoSpy(deco.data(), &ServerSideDecoration::modeChanged);
|
decoration->set_mode(decoMode);
|
||||||
QVERIFY(decoSpy.isValid());
|
surface->commit(KWayland::Client::Surface::CommitFlag::None);
|
||||||
QVERIFY(decoSpy.wait());
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
QFETCH(ServerSideDecoration::Mode, decoMode);
|
|
||||||
deco->requestMode(decoMode);
|
|
||||||
QVERIFY(decoSpy.wait());
|
|
||||||
QCOMPARE(deco->mode(), decoMode);
|
|
||||||
|
|
||||||
|
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||||
auto client = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
auto client = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
||||||
QVERIFY(client);
|
QVERIFY(client);
|
||||||
QVERIFY(client->isActive());
|
QVERIFY(client->isActive());
|
||||||
QVERIFY(!client->isFullScreen());
|
QVERIFY(!client->isFullScreen());
|
||||||
QCOMPARE(client->clientSize(), QSize(100, 50));
|
QCOMPARE(client->clientSize(), QSize(100, 50));
|
||||||
QCOMPARE(client->isDecorated(), decoMode == ServerSideDecoration::Mode::Server);
|
QCOMPARE(client->isDecorated(), decoMode == Test::XdgToplevelDecorationV1::mode_server_side);
|
||||||
|
|
||||||
QSignalSpy fullscreenChangedSpy(client, &AbstractClient::fullScreenChanged);
|
QSignalSpy fullscreenChangedSpy(client, &AbstractClient::fullScreenChanged);
|
||||||
QVERIFY(fullscreenChangedSpy.isValid());
|
QVERIFY(fullscreenChangedSpy.isValid());
|
||||||
QSignalSpy frameGeometryChangedSpy(client, &AbstractClient::frameGeometryChanged);
|
QSignalSpy frameGeometryChangedSpy(client, &AbstractClient::frameGeometryChanged);
|
||||||
QVERIFY(frameGeometryChangedSpy.isValid());
|
QVERIFY(frameGeometryChangedSpy.isValid());
|
||||||
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.data(), &Test::XdgToplevel::configureRequested);
|
|
||||||
QVERIFY(toplevelConfigureRequestedSpy.isValid());
|
|
||||||
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
|
|
||||||
QVERIFY(surfaceConfigureRequestedSpy.isValid());
|
|
||||||
|
|
||||||
// Wait for the compositor to send a configure event with the Activated state.
|
// Wait for the compositor to send a configure event with the Activated state.
|
||||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
|
QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
|
||||||
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
||||||
QVERIFY(states & Test::XdgToplevel::State::Activated);
|
QVERIFY(states & Test::XdgToplevel::State::Activated);
|
||||||
|
|
||||||
// Ask the compositor to maximize the window.
|
// Ask the compositor to maximize the window.
|
||||||
shellSurface->set_maximized();
|
shellSurface->set_maximized();
|
||||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
|
QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
|
||||||
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
||||||
QVERIFY(states & Test::XdgToplevel::State::Maximized);
|
QVERIFY(states & Test::XdgToplevel::State::Maximized);
|
||||||
|
|
||||||
|
@ -539,7 +526,7 @@ void TestXdgShellClient::testMaximizedToFullscreen()
|
||||||
// Ask the compositor to show the window in full screen mode.
|
// Ask the compositor to show the window in full screen mode.
|
||||||
shellSurface->set_fullscreen(nullptr);
|
shellSurface->set_fullscreen(nullptr);
|
||||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
|
QCOMPARE(surfaceConfigureRequestedSpy.count(), 4);
|
||||||
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), client->output()->geometry().size());
|
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), client->output()->geometry().size());
|
||||||
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
||||||
QVERIFY(states & Test::XdgToplevel::State::Maximized);
|
QVERIFY(states & Test::XdgToplevel::State::Maximized);
|
||||||
|
@ -558,7 +545,7 @@ void TestXdgShellClient::testMaximizedToFullscreen()
|
||||||
shellSurface->unset_fullscreen();
|
shellSurface->unset_fullscreen();
|
||||||
shellSurface->unset_maximized();
|
shellSurface->unset_maximized();
|
||||||
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
QCOMPARE(surfaceConfigureRequestedSpy.count(), 4);
|
QCOMPARE(surfaceConfigureRequestedSpy.count(), 5);
|
||||||
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(100, 50));
|
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(100, 50));
|
||||||
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
|
||||||
QVERIFY(!(states & Test::XdgToplevel::State::Maximized));
|
QVERIFY(!(states & Test::XdgToplevel::State::Maximized));
|
||||||
|
@ -569,7 +556,7 @@ void TestXdgShellClient::testMaximizedToFullscreen()
|
||||||
|
|
||||||
QVERIFY(frameGeometryChangedSpy.wait());
|
QVERIFY(frameGeometryChangedSpy.wait());
|
||||||
QVERIFY(!client->isFullScreen());
|
QVERIFY(!client->isFullScreen());
|
||||||
QCOMPARE(client->isDecorated(), decoMode == ServerSideDecoration::Mode::Server);
|
QCOMPARE(client->isDecorated(), decoMode == Test::XdgToplevelDecorationV1::mode_server_side);
|
||||||
QCOMPARE(client->maximizeMode(), MaximizeRestore);
|
QCOMPARE(client->maximizeMode(), MaximizeRestore);
|
||||||
|
|
||||||
// Destroy the client.
|
// Destroy the client.
|
||||||
|
@ -634,18 +621,22 @@ void TestXdgShellClient::testWindowOpensLargerThanScreen()
|
||||||
{
|
{
|
||||||
// this test creates a window which is as large as the screen, but is decorated
|
// this test creates a window which is as large as the screen, but is decorated
|
||||||
// the window should get resized to fit into the screen, BUG: 366632
|
// the window should get resized to fit into the screen, BUG: 366632
|
||||||
|
|
||||||
QScopedPointer<KWayland::Client::Surface> surface(Test::createSurface());
|
QScopedPointer<KWayland::Client::Surface> surface(Test::createSurface());
|
||||||
QScopedPointer<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.data()));
|
QScopedPointer<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.data(), Test::CreationSetup::CreateOnly));
|
||||||
|
QScopedPointer<Test::XdgToplevelDecorationV1> decoration(Test::createXdgToplevelDecorationV1(shellSurface.data()));
|
||||||
|
QSignalSpy decorationConfigureRequestedSpy(decoration.data(), &Test::XdgToplevelDecorationV1::configureRequested);
|
||||||
|
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.data(), &Test::XdgToplevel::configureRequested);
|
||||||
|
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
|
||||||
|
|
||||||
// create deco
|
// Initialize the xdg-toplevel surface.
|
||||||
QScopedPointer<ServerSideDecoration> deco(Test::waylandServerSideDecoration()->create(surface.data()));
|
decoration->set_mode(Test::XdgToplevelDecorationV1::mode_server_side);
|
||||||
QSignalSpy decoSpy(deco.data(), &ServerSideDecoration::modeChanged);
|
surface->commit(KWayland::Client::Surface::CommitFlag::None);
|
||||||
QVERIFY(decoSpy.isValid());
|
|
||||||
QVERIFY(decoSpy.wait());
|
|
||||||
deco->requestMode(ServerSideDecoration::Mode::Server);
|
|
||||||
QVERIFY(decoSpy.wait());
|
|
||||||
QCOMPARE(deco->mode(), ServerSideDecoration::Mode::Server);
|
|
||||||
|
|
||||||
|
QVERIFY(surfaceConfigureRequestedSpy.wait());
|
||||||
|
QCOMPARE(decorationConfigureRequestedSpy.last().at(0).value<Test::XdgToplevelDecorationV1::mode>(), Test::XdgToplevelDecorationV1::mode_server_side);
|
||||||
|
|
||||||
|
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
|
||||||
AbstractOutput *output = workspace()->activeOutput();
|
AbstractOutput *output = workspace()->activeOutput();
|
||||||
auto c = Test::renderAndWaitForShown(surface.data(), output->geometry().size(), Qt::blue);
|
auto c = Test::renderAndWaitForShown(surface.data(), output->geometry().size(), Qt::blue);
|
||||||
QVERIFY(c);
|
QVERIFY(c);
|
||||||
|
@ -886,25 +877,6 @@ void TestXdgShellClient::testAppMenu()
|
||||||
QVERIFY (QDBusConnection::sessionBus().unregisterService("org.kde.kappmenu"));
|
QVERIFY (QDBusConnection::sessionBus().unregisterService("org.kde.kappmenu"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestXdgShellClient::testNoDecorationModeRequested()
|
|
||||||
{
|
|
||||||
// this test verifies that the decoration follows the default mode if no mode is explicitly requested
|
|
||||||
QScopedPointer<KWayland::Client::Surface> surface(Test::createSurface());
|
|
||||||
QScopedPointer<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.data()));
|
|
||||||
QScopedPointer<ServerSideDecoration> deco(Test::waylandServerSideDecoration()->create(surface.data()));
|
|
||||||
QSignalSpy decoSpy(deco.data(), &ServerSideDecoration::modeChanged);
|
|
||||||
QVERIFY(decoSpy.isValid());
|
|
||||||
if (deco->mode() != ServerSideDecoration::Mode::Server) {
|
|
||||||
QVERIFY(decoSpy.wait());
|
|
||||||
}
|
|
||||||
QCOMPARE(deco->mode(), ServerSideDecoration::Mode::Server);
|
|
||||||
|
|
||||||
auto c = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
|
||||||
QVERIFY(c);
|
|
||||||
QCOMPARE(c->noBorder(), false);
|
|
||||||
QCOMPARE(c->isDecorated(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestXdgShellClient::testSendClientWithTransientToDesktop()
|
void TestXdgShellClient::testSendClientWithTransientToDesktop()
|
||||||
{
|
{
|
||||||
// this test verifies that when sending a client to a desktop all transients are also send to that desktop
|
// this test verifies that when sending a client to a desktop all transients are also send to that desktop
|
||||||
|
|
|
@ -2310,7 +2310,7 @@ void AbstractClient::endInteractiveMoveResize()
|
||||||
|
|
||||||
void AbstractClient::createDecoration(const QRect &oldGeometry)
|
void AbstractClient::createDecoration(const QRect &oldGeometry)
|
||||||
{
|
{
|
||||||
setDecoration(Decoration::DecorationBridge::self()->createDecoration(this));
|
setDecoration(QSharedPointer<KDecoration2::Decoration>(Decoration::DecorationBridge::self()->createDecoration(this)));
|
||||||
moveResize(oldGeometry);
|
moveResize(oldGeometry);
|
||||||
|
|
||||||
Q_EMIT geometryShapeChanged(this, oldGeometry);
|
Q_EMIT geometryShapeChanged(this, oldGeometry);
|
||||||
|
@ -2323,19 +2323,19 @@ void AbstractClient::destroyDecoration()
|
||||||
resize(clientSize);
|
resize(clientSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractClient::setDecoration(KDecoration2::Decoration *decoration)
|
void AbstractClient::setDecoration(QSharedPointer<KDecoration2::Decoration> decoration)
|
||||||
{
|
{
|
||||||
if (m_decoration.decoration.data() == decoration) {
|
if (m_decoration.decoration.data() == decoration) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (decoration) {
|
if (decoration) {
|
||||||
QMetaObject::invokeMethod(decoration, QOverload<>::of(&KDecoration2::Decoration::update), Qt::QueuedConnection);
|
QMetaObject::invokeMethod(decoration.data(), QOverload<>::of(&KDecoration2::Decoration::update), Qt::QueuedConnection);
|
||||||
connect(decoration, &KDecoration2::Decoration::shadowChanged, this, &Toplevel::updateShadow);
|
connect(decoration.data(), &KDecoration2::Decoration::shadowChanged, this, &Toplevel::updateShadow);
|
||||||
connect(decoration, &KDecoration2::Decoration::bordersChanged,
|
connect(decoration.data(), &KDecoration2::Decoration::bordersChanged,
|
||||||
this, &AbstractClient::updateDecorationInputShape);
|
this, &AbstractClient::updateDecorationInputShape);
|
||||||
connect(decoration, &KDecoration2::Decoration::resizeOnlyBordersChanged,
|
connect(decoration.data(), &KDecoration2::Decoration::resizeOnlyBordersChanged,
|
||||||
this, &AbstractClient::updateDecorationInputShape);
|
this, &AbstractClient::updateDecorationInputShape);
|
||||||
connect(decoration, &KDecoration2::Decoration::bordersChanged, this, [this]() {
|
connect(decoration.data(), &KDecoration2::Decoration::bordersChanged, this, [this]() {
|
||||||
GeometryUpdatesBlocker blocker(this);
|
GeometryUpdatesBlocker blocker(this);
|
||||||
const QRect oldGeometry = frameGeometry();
|
const QRect oldGeometry = frameGeometry();
|
||||||
resize(implicitSize());
|
resize(implicitSize());
|
||||||
|
@ -2347,7 +2347,7 @@ void AbstractClient::setDecoration(KDecoration2::Decoration *decoration)
|
||||||
connect(decoratedClient()->decoratedClient(), &KDecoration2::DecoratedClient::sizeChanged,
|
connect(decoratedClient()->decoratedClient(), &KDecoration2::DecoratedClient::sizeChanged,
|
||||||
this, &AbstractClient::updateDecorationInputShape);
|
this, &AbstractClient::updateDecorationInputShape);
|
||||||
}
|
}
|
||||||
m_decoration.decoration.reset(decoration);
|
m_decoration.decoration = decoration;
|
||||||
updateDecorationInputShape();
|
updateDecorationInputShape();
|
||||||
Q_EMIT decorationChanged();
|
Q_EMIT decorationChanged();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1197,7 +1197,7 @@ protected:
|
||||||
s_haveResizeEffect = false;
|
s_haveResizeEffect = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDecoration(KDecoration2::Decoration *decoration);
|
void setDecoration(QSharedPointer<KDecoration2::Decoration> decoration);
|
||||||
virtual void createDecoration(const QRect &oldGeometry);
|
virtual void createDecoration(const QRect &oldGeometry);
|
||||||
virtual void destroyDecoration();
|
virtual void destroyDecoration();
|
||||||
void startDecorationDoubleClickTimer();
|
void startDecorationDoubleClickTimer();
|
||||||
|
@ -1313,7 +1313,7 @@ private:
|
||||||
} m_interactiveMoveResize;
|
} m_interactiveMoveResize;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
QScopedPointer<KDecoration2::Decoration> decoration;
|
QSharedPointer<KDecoration2::Decoration> decoration;
|
||||||
QPointer<Decoration::DecoratedClientImpl> client;
|
QPointer<Decoration::DecoratedClientImpl> client;
|
||||||
QElapsedTimer doubleClickTimer;
|
QElapsedTimer doubleClickTimer;
|
||||||
QRegion inputRegion;
|
QRegion inputRegion;
|
||||||
|
|
|
@ -1117,10 +1117,10 @@ void X11Client::invalidateDecoration()
|
||||||
|
|
||||||
void X11Client::createDecoration(const QRect& oldgeom)
|
void X11Client::createDecoration(const QRect& oldgeom)
|
||||||
{
|
{
|
||||||
KDecoration2::Decoration *decoration = Decoration::DecorationBridge::self()->createDecoration(this);
|
QSharedPointer<KDecoration2::Decoration> decoration(Decoration::DecorationBridge::self()->createDecoration(this));
|
||||||
if (decoration) {
|
if (decoration) {
|
||||||
connect(decoration, &KDecoration2::Decoration::resizeOnlyBordersChanged, this, &X11Client::updateInputWindow);
|
connect(decoration.data(), &KDecoration2::Decoration::resizeOnlyBordersChanged, this, &X11Client::updateInputWindow);
|
||||||
connect(decoration, &KDecoration2::Decoration::bordersChanged, this, &X11Client::updateFrameExtents);
|
connect(decoration.data(), &KDecoration2::Decoration::bordersChanged, this, &X11Client::updateFrameExtents);
|
||||||
connect(decoratedClient()->decoratedClient(), &KDecoration2::DecoratedClient::sizeChanged, this, &X11Client::updateInputWindow);
|
connect(decoratedClient()->decoratedClient(), &KDecoration2::DecoratedClient::sizeChanged, this, &X11Client::updateInputWindow);
|
||||||
}
|
}
|
||||||
setDecoration(decoration);
|
setDecoration(decoration);
|
||||||
|
|
|
@ -159,6 +159,7 @@ void XdgSurfaceClient::handleCommit()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleRolePrecommit();
|
||||||
if (haveNextWindowGeometry()) {
|
if (haveNextWindowGeometry()) {
|
||||||
handleNextWindowGeometry();
|
handleNextWindowGeometry();
|
||||||
resetHaveNextWindowGeometry();
|
resetHaveNextWindowGeometry();
|
||||||
|
@ -171,6 +172,10 @@ void XdgSurfaceClient::handleCommit()
|
||||||
updateDepth();
|
updateDepth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XdgSurfaceClient::handleRolePrecommit()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void XdgSurfaceClient::handleRoleCommit()
|
void XdgSurfaceClient::handleRoleCommit()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -738,6 +743,7 @@ bool XdgToplevelClient::userCanSetNoBorder() const
|
||||||
case XdgToplevelDecorationV1Interface::Mode::Server:
|
case XdgToplevelDecorationV1Interface::Mode::Server:
|
||||||
case XdgToplevelDecorationV1Interface::Mode::Undefined:
|
case XdgToplevelDecorationV1Interface::Mode::Undefined:
|
||||||
return Decoration::DecorationBridge::hasPlugin() && !isFullScreen() && !isShade();
|
return Decoration::DecorationBridge::hasPlugin() && !isFullScreen() && !isShade();
|
||||||
|
case XdgToplevelDecorationV1Interface::Mode::None:
|
||||||
case XdgToplevelDecorationV1Interface::Mode::Client:
|
case XdgToplevelDecorationV1Interface::Mode::Client:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -747,25 +753,7 @@ bool XdgToplevelClient::userCanSetNoBorder() const
|
||||||
|
|
||||||
bool XdgToplevelClient::noBorder() const
|
bool XdgToplevelClient::noBorder() const
|
||||||
{
|
{
|
||||||
if (m_serverDecoration) {
|
return m_userNoBorder || preferredDecorationMode() != DecorationMode::Server;
|
||||||
switch (m_serverDecoration->preferredMode()) {
|
|
||||||
case ServerSideDecorationManagerInterface::Mode::Server:
|
|
||||||
return m_userNoBorder || isRequestedFullScreen();
|
|
||||||
case ServerSideDecorationManagerInterface::Mode::Client:
|
|
||||||
case ServerSideDecorationManagerInterface::Mode::None:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m_xdgDecoration) {
|
|
||||||
switch (m_xdgDecoration->preferredMode()) {
|
|
||||||
case XdgToplevelDecorationV1Interface::Mode::Server:
|
|
||||||
case XdgToplevelDecorationV1Interface::Mode::Undefined:
|
|
||||||
return !Decoration::DecorationBridge::hasPlugin() || m_userNoBorder || isRequestedFullScreen();
|
|
||||||
case XdgToplevelDecorationV1Interface::Mode::Client:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XdgToplevelClient::setNoBorder(bool set)
|
void XdgToplevelClient::setNoBorder(bool set)
|
||||||
|
@ -778,45 +766,14 @@ void XdgToplevelClient::setNoBorder(bool set)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_userNoBorder = set;
|
m_userNoBorder = set;
|
||||||
updateDecoration(true, false);
|
configureDecoration();
|
||||||
updateWindowRules(Rules::NoBorder);
|
updateWindowRules(Rules::NoBorder);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XdgToplevelClient::updateDecoration(bool check_workspace_pos, bool force)
|
|
||||||
{
|
|
||||||
if (!force && ((!isDecorated() && noBorder()) || (isDecorated() && !noBorder()))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const QRect oldFrameGeometry = frameGeometry();
|
|
||||||
const QRect oldClientGeometry = clientGeometry();
|
|
||||||
if (force) {
|
|
||||||
destroyDecoration();
|
|
||||||
}
|
|
||||||
if (!noBorder()) {
|
|
||||||
createDecoration(oldFrameGeometry);
|
|
||||||
} else {
|
|
||||||
destroyDecoration();
|
|
||||||
}
|
|
||||||
if (m_serverDecoration && isDecorated()) {
|
|
||||||
m_serverDecoration->setMode(ServerSideDecorationManagerInterface::Mode::Server);
|
|
||||||
}
|
|
||||||
if (m_xdgDecoration) {
|
|
||||||
if (isDecorated() || m_userNoBorder) {
|
|
||||||
m_xdgDecoration->sendConfigure(XdgToplevelDecorationV1Interface::Mode::Server);
|
|
||||||
} else {
|
|
||||||
m_xdgDecoration->sendConfigure(XdgToplevelDecorationV1Interface::Mode::Client);
|
|
||||||
}
|
|
||||||
scheduleConfigure();
|
|
||||||
}
|
|
||||||
updateShadow();
|
|
||||||
if (check_workspace_pos) {
|
|
||||||
checkWorkspacePosition(oldFrameGeometry, oldClientGeometry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void XdgToplevelClient::invalidateDecoration()
|
void XdgToplevelClient::invalidateDecoration()
|
||||||
{
|
{
|
||||||
updateDecoration(true, true);
|
clearDecoration();
|
||||||
|
configureDecoration();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XdgToplevelClient::supportsWindowRules() const
|
bool XdgToplevelClient::supportsWindowRules() const
|
||||||
|
@ -902,24 +859,40 @@ void XdgToplevelClient::closeWindow()
|
||||||
|
|
||||||
XdgSurfaceConfigure *XdgToplevelClient::sendRoleConfigure() const
|
XdgSurfaceConfigure *XdgToplevelClient::sendRoleConfigure() const
|
||||||
{
|
{
|
||||||
const QSize requestedClientSize = frameSizeToClientSize(moveResizeGeometry().size());
|
QSize nextClientSize = moveResizeGeometry().size();
|
||||||
const quint32 serial = m_shellSurface->sendConfigure(requestedClientSize, m_requestedStates);
|
if (!nextClientSize.isEmpty()) {
|
||||||
|
if (m_nextDecoration) {
|
||||||
|
nextClientSize.rwidth() -= m_nextDecoration->borderLeft() + m_nextDecoration->borderRight();
|
||||||
|
nextClientSize.rheight() -= m_nextDecoration->borderTop() + m_nextDecoration->borderBottom();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const quint32 serial = m_shellSurface->sendConfigure(nextClientSize, m_requestedStates);
|
||||||
|
|
||||||
XdgToplevelConfigure *configureEvent = new XdgToplevelConfigure();
|
XdgToplevelConfigure *configureEvent = new XdgToplevelConfigure();
|
||||||
configureEvent->position = moveResizeGeometry().topLeft();
|
configureEvent->position = moveResizeGeometry().topLeft();
|
||||||
configureEvent->states = m_requestedStates;
|
configureEvent->states = m_requestedStates;
|
||||||
|
configureEvent->decoration = m_nextDecoration;
|
||||||
configureEvent->serial = serial;
|
configureEvent->serial = serial;
|
||||||
|
|
||||||
return configureEvent;
|
return configureEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XdgToplevelClient::handleRolePrecommit()
|
||||||
|
{
|
||||||
|
auto configureEvent = static_cast<XdgToplevelConfigure *>(lastAcknowledgedConfigure());
|
||||||
|
if (configureEvent && decoration() != configureEvent->decoration) {
|
||||||
|
setDecoration(configureEvent->decoration);
|
||||||
|
updateShadow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void XdgToplevelClient::handleRoleCommit()
|
void XdgToplevelClient::handleRoleCommit()
|
||||||
{
|
{
|
||||||
auto configureEvent = static_cast<XdgToplevelConfigure *>(lastAcknowledgedConfigure());
|
auto configureEvent = static_cast<XdgToplevelConfigure *>(lastAcknowledgedConfigure());
|
||||||
if (configureEvent) {
|
if (configureEvent) {
|
||||||
handleStatesAcknowledged(configureEvent->states);
|
handleStatesAcknowledged(configureEvent->states);
|
||||||
}
|
}
|
||||||
updateDecoration(true, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XdgToplevelClient::doMinimize()
|
void XdgToplevelClient::doMinimize()
|
||||||
|
@ -1365,11 +1338,6 @@ bool XdgToplevelClient::initialFullScreenMode() const
|
||||||
void XdgToplevelClient::initialize()
|
void XdgToplevelClient::initialize()
|
||||||
{
|
{
|
||||||
bool needsPlacement = isPlaceable();
|
bool needsPlacement = isPlaceable();
|
||||||
|
|
||||||
// Decoration update is forced so an xdg_toplevel_decoration.configure event
|
|
||||||
// is sent if the client has called the set_mode() request with csd mode.
|
|
||||||
updateDecoration(false, true);
|
|
||||||
|
|
||||||
setupWindowRules(false);
|
setupWindowRules(false);
|
||||||
|
|
||||||
// Move or resize the window only if enforced by a window rule.
|
// Move or resize the window only if enforced by a window rule.
|
||||||
|
@ -1420,6 +1388,7 @@ void XdgToplevelClient::initialize()
|
||||||
Placement::self()->place(this, area);
|
Placement::self()->place(this, area);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configureDecoration();
|
||||||
scheduleConfigure();
|
scheduleConfigure();
|
||||||
updateColorScheme();
|
updateColorScheme();
|
||||||
setupWindowManagementInterface();
|
setupWindowManagementInterface();
|
||||||
|
@ -1470,36 +1439,126 @@ void XdgToplevelClient::installAppMenu(AppMenuInterface *appMenu)
|
||||||
updateMenu(appMenu->address());
|
updateMenu(appMenu->address());
|
||||||
}
|
}
|
||||||
|
|
||||||
void XdgToplevelClient::installServerDecoration(ServerSideDecorationInterface *decoration)
|
XdgToplevelClient::DecorationMode XdgToplevelClient::preferredDecorationMode() const
|
||||||
{
|
{
|
||||||
m_serverDecoration = decoration;
|
if (!Decoration::DecorationBridge::hasPlugin()) {
|
||||||
|
return DecorationMode::Client;
|
||||||
connect(m_serverDecoration, &ServerSideDecorationInterface::destroyed, this, [this] {
|
} else if (m_userNoBorder || isRequestedFullScreen()) {
|
||||||
if (!isZombie() && readyForPainting()) {
|
return DecorationMode::None;
|
||||||
updateDecoration(/* check_workspace_pos */ true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
connect(m_serverDecoration, &ServerSideDecorationInterface::preferredModeChanged, this,
|
|
||||||
[this] () {
|
|
||||||
const bool changed = m_serverDecoration->preferredMode() != m_serverDecoration->mode();
|
|
||||||
if (changed && readyForPainting()) {
|
|
||||||
updateDecoration(/* check_workspace_pos */ true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if (readyForPainting()) {
|
|
||||||
updateDecoration(/* check_workspace_pos */ true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_xdgDecoration) {
|
||||||
|
switch (m_xdgDecoration->preferredMode()) {
|
||||||
|
case XdgToplevelDecorationV1Interface::Mode::Undefined:
|
||||||
|
return DecorationMode::Server;
|
||||||
|
case XdgToplevelDecorationV1Interface::Mode::None:
|
||||||
|
return DecorationMode::None;
|
||||||
|
case XdgToplevelDecorationV1Interface::Mode::Client:
|
||||||
|
return DecorationMode::Client;
|
||||||
|
case XdgToplevelDecorationV1Interface::Mode::Server:
|
||||||
|
return DecorationMode::Server;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_serverDecoration) {
|
||||||
|
switch (m_serverDecoration->preferredMode()) {
|
||||||
|
case ServerSideDecorationManagerInterface::Mode::None:
|
||||||
|
return DecorationMode::None;
|
||||||
|
case ServerSideDecorationManagerInterface::Mode::Client:
|
||||||
|
return DecorationMode::Client;
|
||||||
|
case ServerSideDecorationManagerInterface::Mode::Server:
|
||||||
|
return DecorationMode::Server;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DecorationMode::Client;
|
||||||
|
}
|
||||||
|
|
||||||
|
void XdgToplevelClient::clearDecoration()
|
||||||
|
{
|
||||||
|
m_nextDecoration = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void XdgToplevelClient::configureDecoration()
|
||||||
|
{
|
||||||
|
const DecorationMode decorationMode = preferredDecorationMode();
|
||||||
|
switch (decorationMode) {
|
||||||
|
case DecorationMode::None:
|
||||||
|
case DecorationMode::Client:
|
||||||
|
clearDecoration();
|
||||||
|
break;
|
||||||
|
case DecorationMode::Server:
|
||||||
|
if (!m_nextDecoration) {
|
||||||
|
m_nextDecoration.reset(Decoration::DecorationBridge::self()->createDecoration(this));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All decoration updates are synchronized to toplevel configure events.
|
||||||
|
if (m_xdgDecoration) {
|
||||||
|
configureXdgDecoration(decorationMode);
|
||||||
|
} else if (m_serverDecoration) {
|
||||||
|
configureServerDecoration(decorationMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void XdgToplevelClient::configureXdgDecoration(DecorationMode decorationMode)
|
||||||
|
{
|
||||||
|
switch (decorationMode) {
|
||||||
|
case DecorationMode::None: // Faked as server side mode under the hood.
|
||||||
|
m_xdgDecoration->sendConfigure(XdgToplevelDecorationV1Interface::Mode::None);
|
||||||
|
break;
|
||||||
|
case DecorationMode::Client:
|
||||||
|
m_xdgDecoration->sendConfigure(XdgToplevelDecorationV1Interface::Mode::Client);
|
||||||
|
break;
|
||||||
|
case DecorationMode::Server:
|
||||||
|
m_xdgDecoration->sendConfigure(XdgToplevelDecorationV1Interface::Mode::Server);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
scheduleConfigure();
|
||||||
|
}
|
||||||
|
|
||||||
|
void XdgToplevelClient::configureServerDecoration(DecorationMode decorationMode)
|
||||||
|
{
|
||||||
|
switch (decorationMode) {
|
||||||
|
case DecorationMode::None:
|
||||||
|
m_serverDecoration->setMode(ServerSideDecorationManagerInterface::Mode::None);
|
||||||
|
break;
|
||||||
|
case DecorationMode::Client:
|
||||||
|
m_serverDecoration->setMode(ServerSideDecorationManagerInterface::Mode::Client);
|
||||||
|
break;
|
||||||
|
case DecorationMode::Server:
|
||||||
|
m_serverDecoration->setMode(ServerSideDecorationManagerInterface::Mode::Server);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
scheduleConfigure();
|
||||||
}
|
}
|
||||||
|
|
||||||
void XdgToplevelClient::installXdgDecoration(XdgToplevelDecorationV1Interface *decoration)
|
void XdgToplevelClient::installXdgDecoration(XdgToplevelDecorationV1Interface *decoration)
|
||||||
{
|
{
|
||||||
m_xdgDecoration = decoration;
|
m_xdgDecoration = decoration;
|
||||||
|
|
||||||
|
connect(m_xdgDecoration, &XdgToplevelDecorationV1Interface::destroyed,
|
||||||
|
this, &XdgToplevelClient::clearDecoration);
|
||||||
connect(m_xdgDecoration, &XdgToplevelDecorationV1Interface::preferredModeChanged, this, [this] {
|
connect(m_xdgDecoration, &XdgToplevelDecorationV1Interface::preferredModeChanged, this, [this] {
|
||||||
if (m_isInitialized) {
|
if (m_isInitialized) {
|
||||||
// force is true as we must send a new configure response.
|
configureDecoration();
|
||||||
updateDecoration(/* check_workspace_pos */ false, /* force */ true);
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void XdgToplevelClient::installServerDecoration(ServerSideDecorationInterface *decoration)
|
||||||
|
{
|
||||||
|
m_serverDecoration = decoration;
|
||||||
|
if (m_isInitialized) {
|
||||||
|
configureDecoration();
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(m_serverDecoration, &ServerSideDecorationInterface::destroyed,
|
||||||
|
this, &XdgToplevelClient::clearDecoration);
|
||||||
|
connect(m_serverDecoration, &ServerSideDecorationInterface::preferredModeChanged, this, [this]() {
|
||||||
|
if (m_isInitialized) {
|
||||||
|
configureDecoration();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1542,7 +1601,7 @@ void XdgToplevelClient::setFullScreen(bool set, bool user)
|
||||||
dontInteractiveMoveResize();
|
dontInteractiveMoveResize();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDecoration(false, false);
|
configureDecoration();
|
||||||
|
|
||||||
if (set) {
|
if (set) {
|
||||||
const AbstractOutput *output = m_fullScreenRequestedOutput ? m_fullScreenRequestedOutput.data() : kwinApp()->platform()->outputAt(moveResizeGeometry().center());
|
const AbstractOutput *output = m_fullScreenRequestedOutput ? m_fullScreenRequestedOutput.data() : kwinApp()->platform()->outputAt(moveResizeGeometry().center());
|
||||||
|
|
|
@ -67,6 +67,7 @@ protected:
|
||||||
|
|
||||||
virtual XdgSurfaceConfigure *sendRoleConfigure() const = 0;
|
virtual XdgSurfaceConfigure *sendRoleConfigure() const = 0;
|
||||||
virtual void handleRoleCommit();
|
virtual void handleRoleCommit();
|
||||||
|
virtual void handleRolePrecommit();
|
||||||
|
|
||||||
XdgSurfaceConfigure *lastAcknowledgedConfigure() const;
|
XdgSurfaceConfigure *lastAcknowledgedConfigure() const;
|
||||||
void scheduleConfigure();
|
void scheduleConfigure();
|
||||||
|
@ -102,6 +103,7 @@ private:
|
||||||
class XdgToplevelConfigure final : public XdgSurfaceConfigure
|
class XdgToplevelConfigure final : public XdgSurfaceConfigure
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
QSharedPointer<KDecoration2::Decoration> decoration;
|
||||||
KWaylandServer::XdgToplevelInterface::States states;
|
KWaylandServer::XdgToplevelInterface::States states;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -114,6 +116,12 @@ class XdgToplevelClient final : public XdgSurfaceClient
|
||||||
FocusWindow,
|
FocusWindow,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class DecorationMode {
|
||||||
|
None,
|
||||||
|
Client,
|
||||||
|
Server,
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit XdgToplevelClient(KWaylandServer::XdgToplevelInterface *shellSurface);
|
explicit XdgToplevelClient(KWaylandServer::XdgToplevelInterface *shellSurface);
|
||||||
~XdgToplevelClient() override;
|
~XdgToplevelClient() override;
|
||||||
|
@ -159,6 +167,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
XdgSurfaceConfigure *sendRoleConfigure() const override;
|
XdgSurfaceConfigure *sendRoleConfigure() const override;
|
||||||
void handleRoleCommit() override;
|
void handleRoleCommit() override;
|
||||||
|
void handleRolePrecommit() override;
|
||||||
void doMinimize() override;
|
void doMinimize() override;
|
||||||
void doInteractiveResizeSync() override;
|
void doInteractiveResizeSync() override;
|
||||||
void doSetActive() override;
|
void doSetActive() override;
|
||||||
|
@ -197,7 +206,11 @@ private:
|
||||||
void sendPing(PingReason reason);
|
void sendPing(PingReason reason);
|
||||||
MaximizeMode initialMaximizeMode() const;
|
MaximizeMode initialMaximizeMode() const;
|
||||||
bool initialFullScreenMode() const;
|
bool initialFullScreenMode() const;
|
||||||
void updateDecoration(bool check_workspace_pos, bool force = false);
|
DecorationMode preferredDecorationMode() const;
|
||||||
|
void configureDecoration();
|
||||||
|
void configureXdgDecoration(DecorationMode decorationMode);
|
||||||
|
void configureServerDecoration(DecorationMode decorationMode);
|
||||||
|
void clearDecoration();
|
||||||
|
|
||||||
QPointer<KWaylandServer::AppMenuInterface> m_appMenuInterface;
|
QPointer<KWaylandServer::AppMenuInterface> m_appMenuInterface;
|
||||||
QPointer<KWaylandServer::ServerSideDecorationPaletteInterface> m_paletteInterface;
|
QPointer<KWaylandServer::ServerSideDecorationPaletteInterface> m_paletteInterface;
|
||||||
|
@ -216,6 +229,7 @@ private:
|
||||||
bool m_userNoBorder = false;
|
bool m_userNoBorder = false;
|
||||||
bool m_isTransient = false;
|
bool m_isTransient = false;
|
||||||
QPointer<AbstractOutput> m_fullScreenRequestedOutput;
|
QPointer<AbstractOutput> m_fullScreenRequestedOutput;
|
||||||
|
QSharedPointer<KDecoration2::Decoration> m_nextDecoration;
|
||||||
};
|
};
|
||||||
|
|
||||||
class XdgPopupClient final : public XdgSurfaceClient
|
class XdgPopupClient final : public XdgSurfaceClient
|
||||||
|
|
Loading…
Reference in a new issue