From d3eccada62729b6b5f21779aa8140d0e510650e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Fl=C3=B6ser?= Date: Sat, 7 Oct 2017 14:09:07 +0200 Subject: [PATCH] Implement Apply desktop rule for ShellClient Summary: This change sets up ShellClient for supporting window rules by reading in the rules once it gets created. As a first rule the Apply initially rule for desktop is implemented. Currently it is not yet possible to set window rules through the configuration menu. So far only injecting rules through the test framework (temporary rules) is implemented. The idea is to first implement all rules then to expose them to the UI. Test Plan: New test case Reviewers: #kwin, #plasma Subscribers: plasma-devel, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D8177 --- autotests/integration/CMakeLists.txt | 1 + .../integration/shell_client_rules_test.cpp | 122 ++++++++++++++++++ geometry.cpp | 3 + shell_client.cpp | 16 ++- 4 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 autotests/integration/shell_client_rules_test.cpp 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()