kcm/kwinrules: Unify windows properties methods in KCM class

Put together the two methods about window properties and rules
into the same class, since they are tightly related and they seem
a bit out of place within RuleBookModel

Small refactor patch. No behavior changes
This commit is contained in:
Ismael Asensio 2021-03-20 23:34:15 +07:00
parent 6fdfd8be5f
commit 3048d92c09
4 changed files with 95 additions and 96 deletions

View file

@ -143,7 +143,7 @@ void KCMKWinRules::createRuleFromProperties()
return;
}
QModelIndex matchedIndex = m_ruleBookModel->findRuleWithProperties(m_winProperties, m_wholeApp);
QModelIndex matchedIndex = findRuleWithProperties(m_winProperties, m_wholeApp);
if (!matchedIndex.isValid()) {
m_ruleBookModel->insertRow(0);
m_ruleBookModel->setRuleAt(0, ruleForProperties(m_winProperties, m_wholeApp));
@ -331,14 +331,98 @@ void KCMKWinRules::importFromFile(const QUrl &path)
}
// Code adapted from original `findRule()` method in `kwin_rules_dialog::main.cpp`
Rules *KCMKWinRules::ruleForProperties(const QVariantMap &windowProperties, bool wholeApp) const
QModelIndex KCMKWinRules::findRuleWithProperties(const QVariantMap &info, bool wholeApp) const
{
const QByteArray wmclass_class = windowProperties.value("resourceClass").toByteArray().toLower();
const QByteArray wmclass_name = windowProperties.value("resourceName").toByteArray().toLower();
const QByteArray role = windowProperties.value("role").toByteArray().toLower();
const NET::WindowType type = static_cast<NET::WindowType>(windowProperties.value("type").toInt());
const QString title = windowProperties.value("caption").toString();
const QByteArray machine = windowProperties.value("clientMachine").toByteArray();
const QByteArray wmclass_class = info.value("resourceClass").toByteArray().toLower();
const QByteArray wmclass_name = info.value("resourceName").toByteArray().toLower();
const QByteArray role = info.value("role").toByteArray().toLower();
const NET::WindowType type = static_cast<NET::WindowType>(info.value("type").toInt());
const QString title = info.value("caption").toString();
const QByteArray machine = info.value("clientMachine").toByteArray();
const bool isLocalHost = info.value("localhost").toBool();
int bestMatchRow = -1;
int bestMatchScore = 0;
for (int row = 0; row < m_ruleBookModel->rowCount(); row++) {
Rules *rule = m_ruleBookModel->ruleAt(row);
/* clang-format off */
// If the rule doesn't match try the next one
if (!rule->matchWMClass(wmclass_class, wmclass_name)
|| !rule->matchType(type)
|| !rule->matchRole(role)
|| !rule->matchTitle(title)
|| !rule->matchClientMachine(machine, isLocalHost)) {
continue;
}
/* clang-format on */
if (rule->wmclassmatch != Rules::ExactMatch) {
continue; // too generic
}
// Now that the rule matches the window, check the quality of the match
// It stablishes a quality depending on the match policy of the rule
int score = 0;
bool generic = true;
// from now on, it matches the app - now try to match for a specific window
if (rule->wmclasscomplete) {
score += 1;
generic = false; // this can be considered specific enough (old X apps)
}
if (!wholeApp) {
if (rule->windowrolematch != Rules::UnimportantMatch) {
score += rule->windowrolematch == Rules::ExactMatch ? 5 : 1;
generic = false;
}
if (rule->titlematch != Rules::UnimportantMatch) {
score += rule->titlematch == Rules::ExactMatch ? 3 : 1;
generic = false;
}
if (rule->types != NET::AllTypesMask) {
// Checks that type fits the mask, and only one of the types
int bits = 0;
for (unsigned int bit = 1; bit < 1U << 31; bit <<= 1) {
if (rule->types & bit) {
++bits;
}
}
if (bits == 1) {
score += 2;
}
}
if (generic) { // ignore generic rules, use only the ones that are for this window
continue;
}
} else {
if (rule->types == NET::AllTypesMask) {
score += 2;
}
}
if (score > bestMatchScore) {
bestMatchRow = row;
bestMatchScore = score;
}
}
if (bestMatchRow < 0) {
return QModelIndex();
}
return m_ruleBookModel->index(bestMatchRow);
}
// Code adapted from original `findRule()` method in `kwin_rules_dialog::main.cpp`
Rules *KCMKWinRules::ruleForProperties(const QVariantMap &info, bool wholeApp) const
{
const QByteArray wmclass_class = info.value("resourceClass").toByteArray().toLower();
const QByteArray wmclass_name = info.value("resourceName").toByteArray().toLower();
const QByteArray role = info.value("role").toByteArray().toLower();
const NET::WindowType type = static_cast<NET::WindowType>(info.value("type").toInt());
const QString title = info.value("caption").toString();
const QByteArray machine = info.value("clientMachine").toByteArray();
Rules *rule = new Rules();

View file

@ -53,7 +53,9 @@ private:
void saveCurrentRule();
void parseArguments(const QStringList &args);
void createRuleFromProperties();
Rules *ruleForProperties(const QVariantMap &windowProperties, bool wholeApp) const;
QModelIndex findRuleWithProperties(const QVariantMap &info, bool wholeApp) const;
Rules *ruleForProperties(const QVariantMap &info, bool wholeApp) const;
private:
RuleBookModel *m_ruleBookModel;

View file

@ -1,5 +1,4 @@
/*
SPDX-FileCopyrightText: 2004 Lubos Lunak <l.lunak@kde.org>
SPDX-FileCopyrightText: 2020 Ismael Asensio <isma.af@gmail.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
@ -172,88 +171,4 @@ void RuleBookModel::save()
m_ruleBook->save();
}
// Code adapted from original `findRule()` method in `kwin_rules_dialog::main.cpp`
QModelIndex RuleBookModel::findRuleWithProperties(const QVariantMap &info, bool wholeApp) const
{
const QByteArray wmclass_class = info.value("resourceClass").toByteArray().toLower();
const QByteArray wmclass_name = info.value("resourceName").toByteArray().toLower();
const QByteArray role = info.value("role").toByteArray().toLower();
const NET::WindowType type = static_cast<NET::WindowType>(info.value("type").toInt());
const QString title = info.value("caption").toString();
const QByteArray machine = info.value("clientMachine").toByteArray();
const bool isLocalHost = info.value("localhost").toBool();
int bestMatchRow = -1;
int match_quality = 0;
for (int row = 0; row < m_rules.count(); row++) {
Rules *rule = m_rules.at(row);
/* clang-format off */
// If the rule doesn't match try the next one
if (!rule->matchWMClass(wmclass_class, wmclass_name)
|| !rule->matchType(type)
|| !rule->matchRole(role)
|| !rule->matchTitle(title)
|| !rule->matchClientMachine(machine, isLocalHost)) {
continue;
}
/* clang-format on */
if (rule->wmclassmatch != Rules::ExactMatch) {
continue; // too generic
}
// Now that the rule matches the window, check the quality of the match
// It stablishes a quality depending on the match policy of the rule
int quality = 0;
bool generic = true;
// from now on, it matches the app - now try to match for a specific window
if (rule->wmclasscomplete) {
quality += 1;
generic = false; // this can be considered specific enough (old X apps)
}
if (!wholeApp) {
if (rule->windowrolematch != Rules::UnimportantMatch) {
quality += rule->windowrolematch == Rules::ExactMatch ? 5 : 1;
generic = false;
}
if (rule->titlematch != Rules::UnimportantMatch) {
quality += rule->titlematch == Rules::ExactMatch ? 3 : 1;
generic = false;
}
if (rule->types != NET::AllTypesMask) {
// Checks that type fits the mask, and only one of the types
int bits = 0;
for (unsigned int bit = 1; bit < 1U << 31; bit <<= 1) {
if (rule->types & bit) {
++bits;
}
}
if (bits == 1) {
quality += 2;
}
}
if (generic) { // ignore generic rules, use only the ones that are for this window
continue;
}
} else {
if (rule->types == NET::AllTypesMask) {
quality += 2;
}
}
if (quality > match_quality) {
bestMatchRow = row;
match_quality = quality;
}
}
if (bestMatchRow < 0) {
return QModelIndex();
}
return index(bestMatchRow);
}
} // namespace

View file

@ -42,8 +42,6 @@ public:
void load();
void save();
QModelIndex findRuleWithProperties(const QVariantMap &info, bool wholeApp) const;
private:
RuleBookSettings *m_ruleBook;
QVector<Rules *> m_rules;