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
This commit is contained in:
Martin Flöser 2017-10-07 14:09:07 +02:00
parent 8c2b2faf9d
commit d3eccada62
4 changed files with 140 additions and 2 deletions

View file

@ -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)

View file

@ -0,0 +1,122 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2017 Martin Flöser <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#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 <KWayland/Client/surface.h>
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<KWin::ShellClient*>();
qRegisterMetaType<KWin::AbstractClient*>();
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<Test::ShellSurfaceType>("type");
QTest::addColumn<int>("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> surface(Test::createSurface());
QFETCH(Test::ShellSurfaceType, type);
QScopedPointer<QObject> 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"

View file

@ -2173,6 +2173,9 @@ void AbstractClient::blockGeometryUpdates(bool block)
void AbstractClient::maximize(MaximizeMode m)
{
if (m == maximizeMode()) {
return;
}
setMaximize(m & MaximizeVertical, m & MaximizeHorizontal);
}

View file

@ -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()