diff --git a/src/kwin/config/config.cpp b/src/kwin/config/config.cpp index 64ed240..7daa418 100644 --- a/src/kwin/config/config.cpp +++ b/src/kwin/config/config.cpp @@ -144,12 +144,12 @@ std::vector Config::readConditions(const KConfigGroup &group, std::sh { const auto conditionGroup = group.group(conditionGroupName); - const bool negate = conditionGroup.readEntry("Negate", false); + Condition condition(windowDataProvider); + condition.setNegate(conditionGroup.readEntry("Negate", false)); - std::optional windowClassRegex; - const auto windowClassRegexStr = conditionGroup.readEntry("WindowClassRegex", ""); - if (windowClassRegexStr != "") - windowClassRegex = QRegularExpression(windowClassRegexStr); + const auto windowClassRegex = conditionGroup.readEntry("WindowClassRegex", ""); + if (windowClassRegex != "") + condition.setWindowClassRegex(QRegularExpression(windowClassRegex)); auto windowState = WindowState::Unimportant; std::optional windowStateOpt; @@ -162,9 +162,9 @@ std::vector Config::readConditions(const KConfigGroup &group, std::sh windowState = windowState | WindowState::Maximized; } if (windowState) - windowStateOpt = windowState; + condition.setWindowState(windowState); - conditions.emplace_back(windowDataProvider, negate, windowClassRegex, windowStateOpt); + conditions.push_back(condition); } return conditions; diff --git a/src/libgestures/condition.cpp b/src/libgestures/condition.cpp index 5786ecf..02ed6f3 100644 --- a/src/libgestures/condition.cpp +++ b/src/libgestures/condition.cpp @@ -1,10 +1,7 @@ #include "condition.h" -Condition::Condition(std::shared_ptr windowDataProvider, bool negate, std::optional windowClassRegex, std::optional windowState) - : m_windowDataProvider(windowDataProvider), - m_negate(negate), - m_windowClassRegex(std::move(windowClassRegex)), - m_windowState(windowState) +Condition::Condition(std::shared_ptr windowDataProvider) + : m_windowDataProvider(windowDataProvider) { } @@ -14,19 +11,44 @@ bool Condition::isSatisfied() const if (!windowData) return false; - if ((m_windowClassRegex && !m_windowClassRegex.value().pattern().isEmpty()) - && !(m_windowClassRegex.value().match(windowData->resourceClass()).hasMatch() - || m_windowClassRegex.value().match(windowData->resourceName()).hasMatch())) - return m_negate; + return isWindowClassRegexSubConditionSatisfied(windowData.value()) + && isWindowStateSubConditionSatisfied(windowData.value()); +} + +void Condition::setNegate(const bool &negate) +{ + m_negate = negate; +} - if (m_windowState) { - bool satisfiesFullscreen = (m_windowState.value() & WindowState::Fullscreen) && (windowData->state() & WindowState::Fullscreen); - bool satisfiesMaximized = (m_windowState.value() & WindowState::Maximized) && (windowData->state() & WindowState::Maximized); +void Condition::setWindowClassRegex(const QRegularExpression &windowClassRegex) +{ + m_windowClassRegex = windowClassRegex; +} - return m_negate - ? (!satisfiesFullscreen && !satisfiesMaximized) - : (satisfiesFullscreen || satisfiesMaximized); - } +void Condition::setWindowState(const WindowState &windowState) +{ + m_windowState = windowState; +} + +bool Condition::isWindowClassRegexSubConditionSatisfied(const WindowData &data) const +{ + if (!m_windowClassRegex || m_windowClassRegex->pattern().isEmpty()) + return true; + + if (m_windowClassRegex.value().match(data.resourceClass()).hasMatch() + || m_windowClassRegex.value().match(data.resourceName()).hasMatch()) + return !m_negate; + + return m_negate; +} + +bool Condition::isWindowStateSubConditionSatisfied(const WindowData &data) const +{ + if (!m_windowState) + return true; - return !m_negate; + const bool satisfied = + ((m_windowState.value() & WindowState::Fullscreen) && (data.state() & WindowState::Fullscreen)) + || ((m_windowState.value() & WindowState::Maximized) && (data.state() & WindowState::Maximized)); + return m_negate == !satisfied; } \ No newline at end of file diff --git a/src/libgestures/condition.h b/src/libgestures/condition.h index f2e71f3..1f7490e 100644 --- a/src/libgestures/condition.h +++ b/src/libgestures/condition.h @@ -3,16 +3,24 @@ #include #include "windowdataprovider.h" - class Condition { public: - Condition(std::shared_ptr windowDataProvider, bool negate, std::optional windowClassRegex, std::optional windowState); + explicit Condition(std::shared_ptr windowDataProvider); bool isSatisfied() const; + + void setNegate(const bool &negate); + void setWindowClassRegex(const QRegularExpression &windowClassRegex); + void setWindowState(const WindowState &windowState); private: + bool isWindowClassRegexSubConditionSatisfied(const WindowData &data) const; + bool isWindowStateSubConditionSatisfied(const WindowData &data) const; + const std::shared_ptr m_windowDataProvider; - const bool m_negate; - const std::optional m_windowClassRegex; - const std::optional m_windowState; + bool m_negate = false; + std::optional m_windowClassRegex = std::nullopt; + std::optional m_windowState = std::nullopt; + + friend class TestCondition; }; \ No newline at end of file diff --git a/tests/libgestures/test_condition.cpp b/tests/libgestures/test_condition.cpp index bb090ab..4600e2f 100644 --- a/tests/libgestures/test_condition.cpp +++ b/tests/libgestures/test_condition.cpp @@ -1,162 +1,112 @@ -#include "condition.h" #include "test_condition.h" -TestCondition::TestCondition() - : m_noActiveWindow(std::make_shared(std::nullopt)), - m_normalWindow(std::make_shared(std::make_optional("Firefox", "firefox", "firefox", WindowState::Unimportant))), - m_maximizedWindow(std::make_shared(std::make_optional("Firefox", "firefox", "firefox", WindowState::Maximized))), - m_fullscreenWindow(std::make_shared(std::make_optional("Firefox", "firefox", "firefox", WindowState::Maximized))) +void TestCondition::init() { + m_condition = std::make_shared(m_normalWindowProvider); } void TestCondition::isSatisfied_noActiveWindow_returnsFalse() { - const auto condition = std::make_shared(m_noActiveWindow, false, std::nullopt, std::nullopt); - - QVERIFY(!condition->isSatisfied()); -} - -void TestCondition::isSatisfied_negatedAndNoActiveWindow_returnsFalse() -{ - const auto condition = std::make_shared(m_noActiveWindow, true, std::nullopt, std::nullopt); - - QVERIFY(!condition->isSatisfied()); + QVERIFY(!Condition(m_noActiveWindowProvider).isSatisfied()); } void TestCondition::isSatisfied_noSubConditions_returnsTrue() { - const auto condition = std::make_shared(m_normalWindow, false, std::nullopt, std::nullopt); - - QVERIFY(condition->isSatisfied()); -} - -void TestCondition::isSatisfied_negatedAndNoSubConditions_returnsFalse() -{ - const auto condition = std::make_shared(m_normalWindow, true, std::nullopt, std::nullopt); - - QVERIFY(!condition->isSatisfied()); -} - -void TestCondition::isSatisfied_windowClassRegexMatchesResourceClass_returnsTrue() -{ - const auto window = std::make_shared(std::make_optional("Firefox", "firefox", "", WindowState::Unimportant)); - const auto condition = std::make_shared(window, false, QRegularExpression("firefox"), std::nullopt); - - QVERIFY(condition->isSatisfied()); -} - -void TestCondition::isSatisfied_windowClassRegexMatchesResourceName_returnsTrue() -{ - const auto window = std::make_shared(std::make_optional("Firefox", "", "firefox", WindowState::Unimportant)); - const auto condition = std::make_shared(window, false, QRegularExpression("firefox"), std::nullopt); - - QVERIFY(condition->isSatisfied()); -} - -void TestCondition::isSatisfied_windowClassRegexDoesntMatch_returnsFalse() -{ - const auto condition = std::make_shared(m_normalWindow, false, QRegularExpression("firefoxx"), std::nullopt); - - QVERIFY(!condition->isSatisfied()); + QVERIFY(Condition(m_normalWindowProvider).isSatisfied()); } -void TestCondition::isSatisfied_negatedAndWindowClassRegexMatches_returnsFalse() +void TestCondition::isSatisfied_negatedAndNoSubConditions_returnsTrue() { - const auto window = std::make_shared(std::make_optional("Firefox", "firefox", "", WindowState::Unimportant)); - const auto condition = std::make_shared(window, true, QRegularExpression("firefox"), std::nullopt); + m_condition->setNegate(true); - QVERIFY(!condition->isSatisfied()); + QVERIFY(m_condition->isSatisfied()); } -void TestCondition::isSatisfied_negatedAndWindowClassRegexDoesntMatch_returnsTrue() +void TestCondition::isWindowClassRegexSubConditionSatisfied_subConditionNotSet_returnsTrue() { - const auto condition = std::make_shared(m_normalWindow, true, QRegularExpression("firefoxx"), std::nullopt); - - QVERIFY(condition->isSatisfied()); + QVERIFY(m_condition->isWindowClassRegexSubConditionSatisfied(m_normalWindow)); } -void TestCondition::isSatisfied_windowStateDoesntMatch_returnsFalse() +void TestCondition::isWindowClassRegexSubConditionSatisfied_negatedAndSubConditionNotSet_returnsTrue() { - const auto condition = std::make_shared(m_normalWindow, false, std::nullopt, WindowState::Maximized); + m_condition->setNegate(true); - QVERIFY(!condition->isSatisfied()); + QVERIFY(m_condition->isWindowClassRegexSubConditionSatisfied(m_normalWindow)); } -void TestCondition::isSatisfied_windowStateMatches_returnsTrue() +void TestCondition::isWindowClassRegexSubConditionSatisfied_data() { - const auto condition = std::make_shared(m_maximizedWindow, false, std::nullopt, WindowState::Maximized); + QTest::addColumn("negate"); + QTest::addColumn("regex"); + QTest::addColumn("resourceClass"); + QTest::addColumn("resourceName"); + QTest::addColumn("result"); - QVERIFY(condition->isSatisfied()); + QTest::newRow("resource class only") << false << s_windowClass << s_windowClass << "" << true; + QTest::newRow("resource name only") << false << s_windowClass << "" << s_windowClass << true; + QTest::newRow("no match") << false << s_windowClass << "" << "" << false; + QTest::newRow("negated match") << true << s_windowClass << s_windowClass << s_windowClass << false; + QTest::newRow("negated no match") << true << s_windowClass << "" << "" << true; } -void TestCondition::isSatisfied_windowStateMatchesEither_returnsTrue() +void TestCondition::isWindowClassRegexSubConditionSatisfied() { - const auto condition = std::make_shared(m_maximizedWindow, false, std::nullopt, WindowState::Fullscreen | WindowState::Maximized); - - QVERIFY(condition->isSatisfied()); -} + QFETCH(bool, negate); + QFETCH(QString, regex); + QFETCH(QString, resourceClass); + QFETCH(QString, resourceName); + QFETCH(bool, result); + const WindowData windowData(s_windowCaption, resourceClass, resourceName, WindowState::Unimportant); -void TestCondition::isSatisfied_negatedAndWindowStateDoesntMatch_returnsTrue() -{ - const auto condition = std::make_shared(m_normalWindow, true, std::nullopt, WindowState::Maximized); + m_condition->setNegate(negate); + m_condition->setWindowClassRegex(QRegularExpression(regex)); - QVERIFY(condition->isSatisfied()); + QCOMPARE(m_condition->isWindowClassRegexSubConditionSatisfied(windowData), result); } -void TestCondition::isSatisfied_negatedAndWindowStateMatches_returnsFalse() +void TestCondition::isWindowStateSubConditionSatisfied_subConditionNotSet_returnsTrue() { - const auto condition = std::make_shared(m_maximizedWindow, true, std::nullopt, WindowState::Maximized); - - QVERIFY(!condition->isSatisfied()); + QVERIFY(m_condition->isWindowStateSubConditionSatisfied(m_normalWindow)); } -void TestCondition::isSatisfied_negatedAndWindowStateMatchesEither_returnsFalse() +void TestCondition::isWindowStateSubConditionSatisfied_negatedAndSubConditionNotSet_returnsTrue() { - const auto condition = std::make_shared(m_maximizedWindow, true, std::nullopt, WindowState::Fullscreen | WindowState::Maximized); + m_condition->setNegate(true); - QVERIFY(!condition->isSatisfied()); + QVERIFY(m_condition->isWindowStateSubConditionSatisfied(m_normalWindow)); } -void TestCondition::isSatisfied_windowClassMatchesAndStateDoesnt_returnsFalse() +void TestCondition::isWindowStateSubConditionSatisfied_data() { - const auto condition = std::make_shared(m_normalWindow, false, QRegularExpression("firefox"), WindowState::Maximized); + QTest::addColumn("negate"); + QTest::addColumn("conditionWindowState"); + QTest::addColumn("windowState"); + QTest::addColumn("result"); - QVERIFY(!condition->isSatisfied()); + QTest::newRow("matches one") << false << static_cast(WindowState::Maximized) + << static_cast(WindowState::Maximized) << true; + QTest::newRow("matches all") << false << static_cast(WindowState::Maximized | WindowState::Fullscreen) + << static_cast(WindowState::Maximized | WindowState::Fullscreen) << true; + QTest::newRow("no match") << false << static_cast(WindowState::Maximized) << static_cast(WindowState::Fullscreen) << false; + QTest::newRow("negated matches one") << true << static_cast(WindowState::Maximized) + << static_cast(WindowState::Maximized) << false; + QTest::newRow("negated matches all") << true << static_cast(WindowState::Maximized | WindowState::Fullscreen) + << static_cast(WindowState::Maximized | WindowState::Fullscreen) << false; + QTest::newRow("negated no match") << true << static_cast(WindowState::Maximized) << static_cast(WindowState::Fullscreen) << true; } -void TestCondition::isSatisfied_windowClassDoesntMatchAndStateDoes_returnsFalse() +void TestCondition::isWindowStateSubConditionSatisfied() { - const auto condition = std::make_shared(m_maximizedWindow, false, QRegularExpression("firefoxx"), WindowState::Maximized); + QFETCH(bool, negate); + QFETCH(int, conditionWindowState); + QFETCH(int, windowState); + QFETCH(bool, result); + const WindowData windowData(s_windowCaption, s_windowClass, s_windowClass, static_cast(windowState)); - QVERIFY(!condition->isSatisfied()); -} - -void TestCondition::isSatisfied_windowClassMatchesAndStateMatches_returnsTrue() -{ - const auto condition = std::make_shared(m_maximizedWindow, false, QRegularExpression("firefox"), WindowState::Maximized); - - QVERIFY(condition->isSatisfied()); -} - -void TestCondition::isSatisfied_negatedAndWindowClassMatchesAndStateDoesnt_returnsTrue() -{ - const auto condition = std::make_shared(m_normalWindow, true, QRegularExpression("firefox"), WindowState::Maximized); - - QVERIFY(condition->isSatisfied()); -} - -void TestCondition::isSatisfied_negatedAndWindowClassDoesntMatchAndStateDoes_returnsTrue() -{ - const auto condition = std::make_shared(m_maximizedWindow, true, QRegularExpression("firefoxx"), WindowState::Maximized); - - QVERIFY(condition->isSatisfied()); -} - -void TestCondition::isSatisfied_negatedAndWindowClassMatchesAndStateMatches_returnsFalse() -{ - const auto condition = std::make_shared(m_maximizedWindow, true, QRegularExpression("firefox"), WindowState::Maximized); + m_condition->setNegate(negate); + m_condition->setWindowState(static_cast(conditionWindowState)); - QVERIFY(!condition->isSatisfied()); + QCOMPARE(m_condition->isWindowStateSubConditionSatisfied(windowData), result); } QTEST_MAIN(TestCondition) diff --git a/tests/libgestures/test_condition.h b/tests/libgestures/test_condition.h index 0ac7aa4..d8a92ee 100644 --- a/tests/libgestures/test_condition.h +++ b/tests/libgestures/test_condition.h @@ -1,39 +1,36 @@ #pragma once +#include "condition.h" #include "mockwindowdataprovider.h" #include +static const QString s_windowCaption = "Firefox"; +static const QString s_windowClass = "firefox"; + class TestCondition : public QObject { Q_OBJECT -public: - TestCondition(); private slots: + void init(); + void isSatisfied_noActiveWindow_returnsFalse(); - void isSatisfied_negatedAndNoActiveWindow_returnsFalse(); void isSatisfied_noSubConditions_returnsTrue(); - void isSatisfied_negatedAndNoSubConditions_returnsFalse(); - void isSatisfied_windowClassRegexMatchesResourceClass_returnsTrue(); - void isSatisfied_windowClassRegexMatchesResourceName_returnsTrue(); - void isSatisfied_windowClassRegexDoesntMatch_returnsFalse(); - void isSatisfied_negatedAndWindowClassRegexMatches_returnsFalse(); - void isSatisfied_negatedAndWindowClassRegexDoesntMatch_returnsTrue(); - void isSatisfied_windowStateDoesntMatch_returnsFalse(); - void isSatisfied_windowStateMatches_returnsTrue(); - void isSatisfied_windowStateMatchesEither_returnsTrue(); - void isSatisfied_negatedAndWindowStateDoesntMatch_returnsTrue(); - void isSatisfied_negatedAndWindowStateMatches_returnsFalse(); - void isSatisfied_negatedAndWindowStateMatchesEither_returnsFalse(); - void isSatisfied_windowClassMatchesAndStateDoesnt_returnsFalse(); - void isSatisfied_windowClassDoesntMatchAndStateDoes_returnsFalse(); - void isSatisfied_windowClassMatchesAndStateMatches_returnsTrue(); - void isSatisfied_negatedAndWindowClassMatchesAndStateDoesnt_returnsTrue(); - void isSatisfied_negatedAndWindowClassDoesntMatchAndStateDoes_returnsTrue(); - void isSatisfied_negatedAndWindowClassMatchesAndStateMatches_returnsFalse(); + void isSatisfied_negatedAndNoSubConditions_returnsTrue(); + + void isWindowClassRegexSubConditionSatisfied_subConditionNotSet_returnsTrue(); + void isWindowClassRegexSubConditionSatisfied_negatedAndSubConditionNotSet_returnsTrue(); + void isWindowClassRegexSubConditionSatisfied_data(); + void isWindowClassRegexSubConditionSatisfied(); + + void isWindowStateSubConditionSatisfied_subConditionNotSet_returnsTrue(); + void isWindowStateSubConditionSatisfied_negatedAndSubConditionNotSet_returnsTrue(); + void isWindowStateSubConditionSatisfied_data(); + void isWindowStateSubConditionSatisfied(); private: - const std::shared_ptr m_noActiveWindow; - const std::shared_ptr m_normalWindow; - const std::shared_ptr m_maximizedWindow; - const std::shared_ptr m_fullscreenWindow; + const std::shared_ptr m_noActiveWindowProvider = std::make_shared(std::nullopt); + const std::shared_ptr m_normalWindowProvider = std::make_shared(std::make_optional(s_windowCaption, s_windowClass, s_windowClass, WindowState::Unimportant)); + const WindowData m_normalWindow = m_normalWindowProvider->getDataForActiveWindow().value(); + + std::shared_ptr m_condition = std::make_shared(m_normalWindowProvider); };