diff --git a/autotests/integration/CMakeLists.txt b/autotests/integration/CMakeLists.txt index 1cdc83c5fb..7b12216850 100644 --- a/autotests/integration/CMakeLists.txt +++ b/autotests/integration/CMakeLists.txt @@ -54,6 +54,7 @@ integrationTest(WAYLAND_ONLY NAME testShowingDesktop SRCS showing_desktop_test.c integrationTest(NAME testDontCrashUseractionsMenu SRCS dont_crash_useractions_menu.cpp) integrationTest(WAYLAND_ONLY NAME testKWinBindings SRCS kwinbindings_test.cpp) integrationTest(WAYLAND_ONLY NAME testVirtualDesktop SRCS virtual_desktop_test.cpp) +integrationTest(WAYLAND_ONLY NAME testShellClientRules SRCS shell_client_rules_test.cpp) if (XCB_ICCCM_FOUND) integrationTest(NAME testMoveResize SRCS move_resize_window_test.cpp LIBS XCB::ICCCM) diff --git a/autotests/integration/shell_client_rules_test.cpp b/autotests/integration/shell_client_rules_test.cpp new file mode 100644 index 0000000000..c79290b642 --- /dev/null +++ b/autotests/integration/shell_client_rules_test.cpp @@ -0,0 +1,122 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2017 Martin Flöser + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "kwin_wayland_test.h" +#include "platform.h" +#include "rules.h" +#include "screens.h" +#include "shell_client.h" +#include "virtualdesktops.h" +#include "wayland_server.h" + +#include + +using namespace KWin; +using namespace KWayland::Client; + +static const QString s_socketName = QStringLiteral("wayland_test_kwin_shell_client_rules-0"); + + +class TestShellClientRules : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void init(); + void cleanup(); + + void testApplyInitialDesktop_data(); + void testApplyInitialDesktop(); +}; + +void TestShellClientRules::initTestCase() +{ + qRegisterMetaType(); + qRegisterMetaType(); + + QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated); + QVERIFY(workspaceCreatedSpy.isValid()); + kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024)); + QMetaObject::invokeMethod(kwinApp()->platform(), "setOutputCount", Qt::DirectConnection, Q_ARG(int, 2)); + QVERIFY(waylandServer()->init(s_socketName.toLocal8Bit())); + + kwinApp()->start(); + QVERIFY(workspaceCreatedSpy.wait()); + QCOMPARE(screens()->count(), 2); + QCOMPARE(screens()->geometry(0), QRect(0, 0, 1280, 1024)); + QCOMPARE(screens()->geometry(1), QRect(1280, 0, 1280, 1024)); + waylandServer()->initWorkspace(); +} + +void TestShellClientRules::init() +{ + QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Decoration)); + + screens()->setCurrent(0); +} + +void TestShellClientRules::cleanup() +{ + Test::destroyWaylandConnection(); +} + +void TestShellClientRules::testApplyInitialDesktop_data() +{ + QTest::addColumn("type"); + QTest::addColumn("ruleNumber"); + + QTest::newRow("wlShell|Force") << Test::ShellSurfaceType::WlShell << 2; + QTest::newRow("xdgShellV5|Force") << Test::ShellSurfaceType::XdgShellV5 << 2; + QTest::newRow("xdgShellV6|Force") << Test::ShellSurfaceType::XdgShellV6 << 2; + + QTest::newRow("wlShell|Apply") << Test::ShellSurfaceType::WlShell << 3; + QTest::newRow("xdgShellV5|Apply") << Test::ShellSurfaceType::XdgShellV5 << 3; + QTest::newRow("xdgShellV6|Apply") << Test::ShellSurfaceType::XdgShellV6 << 3; + + QTest::newRow("wlShell|ApplyNow") << Test::ShellSurfaceType::WlShell << 5; + QTest::newRow("xdgShellV5|ApplyNow") << Test::ShellSurfaceType::XdgShellV5 << 5; + QTest::newRow("xdgShellV6|ApplyNow") << Test::ShellSurfaceType::XdgShellV6 << 5; + + QTest::newRow("wlShell|ForceTemporarily") << Test::ShellSurfaceType::WlShell << 6; + QTest::newRow("xdgShellV5|ForceTemporarily") << Test::ShellSurfaceType::XdgShellV5 << 6; + QTest::newRow("xdgShellV6|ForceTemporarily") << Test::ShellSurfaceType::XdgShellV6 << 6; +} + +void TestShellClientRules::testApplyInitialDesktop() +{ + // ensure we have two desktops and are on first desktop + VirtualDesktopManager::self()->setCount(2); + VirtualDesktopManager::self()->setCurrent(VirtualDesktopManager::self()->desktops().first()); + + // install the temporary rule + QFETCH(int, ruleNumber); + QString rule = QStringLiteral("desktop=2\ndesktoprule=%1").arg(ruleNumber); + QMetaObject::invokeMethod(RuleBook::self(), "temporaryRulesMessage", Q_ARG(QString, rule)); + + QScopedPointer surface(Test::createSurface()); + QFETCH(Test::ShellSurfaceType, type); + QScopedPointer shellSurface(Test::createShellSurface(type, surface.data())); + + auto c = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue); + QVERIFY(c); + QCOMPARE(c->desktop(), 2); +} + +WAYLANDTEST_MAIN(TestShellClientRules) +#include "shell_client_rules_test.moc" diff --git a/geometry.cpp b/geometry.cpp index 85d582e54f..78d0e0b58a 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -2173,6 +2173,9 @@ void AbstractClient::blockGeometryUpdates(bool block) void AbstractClient::maximize(MaximizeMode m) { + if (m == maximizeMode()) { + return; + } setMaximize(m & MaximizeVertical, m & MaximizeHorizontal); } diff --git a/shell_client.cpp b/shell_client.cpp index 6b534227ed..8eaeeaf364 100644 --- a/shell_client.cpp +++ b/shell_client.cpp @@ -185,6 +185,10 @@ void ShellClient::initSurface(T *shellSurface) connect(this, &ShellClient::geometryChanged, this, &ShellClient::updateClientOutputs); connect(screens(), &Screens::changed, this, &ShellClient::updateClientOutputs); + + if (!m_internal) { + setupWindowRules(false); + } } void ShellClient::init() @@ -207,11 +211,9 @@ void ShellClient::init() } if (m_internalWindow) { updateInternalWindowGeometry(); - setOnAllDesktops(true); updateDecoration(true); } else { doSetGeometry(QRect(QPoint(0, 0), m_clientSize)); - setDesktop(VirtualDesktopManager::self()->current()); } if (waylandServer()->inputMethodConnection() == s->client()) { m_windowType = NET::OnScreenDisplay; @@ -311,6 +313,9 @@ void ShellClient::init() connect(m_xdgShellPopup, &XdgShellPopupInterface::destroyed, this, &ShellClient::destroyClient); } + // set initial desktop + setDesktop(rules()->checkDesktop(m_internal ? int(NET::OnAllDesktops) : VirtualDesktopManager::self()->current(), true)); + // setup shadow integration getShadow(); connect(s, &SurfaceInterface::shadowChanged, this, &Toplevel::getShadow); @@ -328,6 +333,13 @@ void ShellClient::init() AbstractClient::updateColorScheme(QString()); updateApplicationMenu(); + + if (!m_internal) { + discardTemporaryRules(); + applyWindowRules(); // Just in case + RuleBook::self()->discardUsed(this, false); // Remove ApplyNow rules + updateWindowRules(Rules::All); // Was blocked while !isManaged() + } } void ShellClient::destroyClient()