diff --git a/kcmkwin/CMakeLists.txt b/kcmkwin/CMakeLists.txt --- a/kcmkwin/CMakeLists.txt +++ b/kcmkwin/CMakeLists.txt @@ -1,5 +1,6 @@ remove_definitions(-DQT_NO_CAST_FROM_ASCII -DQT_STRICT_ITERATORS -DQT_NO_CAST_FROM_BYTEARRAY -DQT_NO_KEYWORDS) +add_subdirectory( common ) add_subdirectory( kwincompositing ) add_subdirectory( kwinoptions ) add_subdirectory( kwindecoration ) diff --git a/kcmkwin/common/CMakeLists.txt b/kcmkwin/common/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/kcmkwin/common/CMakeLists.txt @@ -0,0 +1,32 @@ +# KI18N Translation Domain for this library +add_definitions(-DTRANSLATION_DOMAIN=\"kcmkwincommon\") + +include_directories(${KWIN_SOURCE_DIR}/effects) + +set(kcmkwincommon_SRC + effectmodel.cpp +) + +qt5_add_dbus_interface(kcmkwincommon_SRC + ${KWIN_SOURCE_DIR}/org.kde.kwin.Effects.xml kwin_effects_interface +) + +add_library(kcmkwincommon SHARED ${kcmkwincommon_SRC}) + +target_link_libraries(kcmkwincommon + Qt5::Core + Qt5::DBus + KF5::CoreAddons + KF5::ConfigCore + KF5::I18n + KF5::Package + KF5::KCMUtils + kwin4_effect_builtins +) + +set_target_properties(kcmkwincommon PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} +) + +install(TARGETS kcmkwincommon ${INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP) diff --git a/kcmkwin/common/Messages.sh b/kcmkwin/common/Messages.sh new file mode 100644 --- /dev/null +++ b/kcmkwin/common/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT `find . -name \*.cpp` -o $podir/kcmkwincommon.pot diff --git a/kcmkwin/common/effectmodel.h b/kcmkwin/common/effectmodel.h new file mode 100644 --- /dev/null +++ b/kcmkwin/common/effectmodel.h @@ -0,0 +1,232 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2013 Antonis Tsiapaliokas +Copyright (C) 2018 Vlad Zagorodniy + +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 . +*********************************************************************/ + +#pragma once + +#include + +#include +#include + +#include +#include +#include + +namespace KWin +{ + +class KWIN_EXPORT EffectModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + /** + * This enum type is used to specify data roles. + **/ + enum AdditionalRoles { + /** + * The user-friendly name of the effect. + **/ + NameRole = Qt::UserRole + 1, + /** + * The description of the effect. + **/ + DescriptionRole, + /** + * The name of the effect's author. If there are several authors, they + * will be comma separated. + **/ + AuthorNameRole, + /** + * The email of the effect's author. If there are several authors, the + * emails will be comma separated. + **/ + AuthorEmailRole, + /** + * The license of the effect. + **/ + LicenseRole, + /** + * The version of the effect. + **/ + VersionRole, + /** + * The category of the effect. + **/ + CategoryRole, + /** + * The service name(plugin name) of the effect. + **/ + ServiceNameRole, + /** + * The icon name of the effect. + **/ + IconNameRole, + /** + * Whether the effect is enabled or disabled. + **/ + EffectStatusRole, + /** + * Link to a video demonstration of the effect. + **/ + VideoRole, + /** + * Link to the home page of the effect. + **/ + WebsiteRole, + /** + * Whether the effect is supported. + **/ + SupportedRole, + /** + * The exclusive group of the effect. + **/ + ExclusiveRole, + /** + * Whether the effect is internal. + **/ + InternalRole, + /** + * Whether the effect has a KCM. + **/ + ConfigurableRole, + /** + * Whether this is a scripted effect. + **/ + ScriptedRole, + /** + * Whether the effect is enabled by default. + **/ + EnabledByDefaultRole + }; + + /** + * This enum type is used to specify the status of a given effect. + **/ + enum class Status { + /** + * The effect is disabled. + **/ + Disabled = Qt::Unchecked, + /** + * An enable function is used to determine whether the effect is enabled. + * For example, such function can be useful to disable the blur effect + * when running in a virtual machine. + **/ + EnabledUndeterminded = Qt::PartiallyChecked, + /** + * The effect is enabled. + **/ + Enabled = Qt::Checked + }; + + explicit EffectModel(QObject *parent = nullptr); + + // Reimplemented from QAbstractItemModel. + QHash roleNames() const override; + QModelIndex index(int row, int column, const QModelIndex &parent = {}) const override; + QModelIndex parent(const QModelIndex &child) const override; + int rowCount(const QModelIndex &parent = {}) const override; + int columnCount(const QModelIndex &parent = {}) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + + /** + * Changes the status of a given effect. + * + * @param rowIndex An effect represented by the given index. + * @param effectState The new state. + * @note In order to actually apply the change, you have to call save(). + **/ + void updateEffectStatus(const QModelIndex &rowIndex, Status effectState); + + /** + * Loads effects. + * + * You have to call this method in order to populate the model. + **/ + void load(); + + /** + * Saves status of each modified effect. + **/ + void save(); + + /** + * Resets the status of each effect to the default state. + * + * @note In order to actually apply the change, you have to call save(). + **/ + void defaults(); + +protected: + enum class Kind { + Builtin, + Binary, + Scripted + }; + + struct EffectData { + QString name; + QString description; + QString authorName; + QString authorEmail; + QString license; + QString version; + QString untranslatedCategory; + QString category; + QString serviceName; + QString iconName; + Status effectStatus; + bool enabledByDefault; + bool enabledByDefaultFunction; + QUrl video; + QUrl website; + bool supported; + QString exclusiveGroup; + bool internal; + bool configurable; + Kind kind; + bool changed = false; + }; + + /** + * Returns whether the given effect should be stored in the model. + * + * @param data The effect. + * @returns @c true if the effect should be stored, otherwise @c false. + **/ + virtual bool shouldStore(const EffectData &data) const; + +private: + void loadBuiltInEffects(const KConfigGroup &kwinConfig, const KPluginInfo::List &configs); + void loadJavascriptEffects(const KConfigGroup &kwinConfig); + void loadPluginEffects(const KConfigGroup &kwinConfig, const KPluginInfo::List &configs); + int findRowByServiceName(const QString &serviceName); + void syncEffectsToKWin(); + + QVector m_effectsList; + QVector m_effectsChanged; + + Q_DISABLE_COPY(EffectModel) +}; + +} diff --git a/kcmkwin/kwincompositing/model.cpp b/kcmkwin/common/effectmodel.cpp copy from kcmkwin/kwincompositing/model.cpp copy to kcmkwin/common/effectmodel.cpp --- a/kcmkwin/kwincompositing/model.cpp +++ b/kcmkwin/common/effectmodel.cpp @@ -1,60 +1,48 @@ -/************************************************************************** -* KWin - the KDE window manager * -* This file is part of the KDE project. * -* * -* Copyright (C) 2013 Antonis Tsiapaliokas * -* * -* 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 "model.h" -#include "effectconfig.h" -#include "compositing.h" +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2013 Antonis Tsiapaliokas +Copyright (C) 2018 Vlad Zagorodniy + +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 "effectmodel.h" + #include -#include #include +#include +#include #include -#include -#include #include -#include -#include #include #include -#include +#include -#include #include #include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace KWin { -namespace Compositing { +#include + +namespace KWin +{ static QString translatedCategory(const QString &category) { - static const QVector knownCategories = { + static const QVector knownCategories = { QStringLiteral("Accessibility"), QStringLiteral("Appearance"), QStringLiteral("Candy"), @@ -77,24 +65,27 @@ i18nc("Category of Desktop Effects, used as section header", "Window Management"), i18nc("Category of Desktop Effects, used as section header", "Window Open/Close Animation") }; + const int index = knownCategories.indexOf(category); if (index == -1) { qDebug() << "Unknown category '" << category << "' and thus not translated"; return category; } + return translatedCategories[index]; } -static EffectStatus effectStatus(bool enabled) +static EffectModel::Status effectStatus(bool enabled) { - return enabled ? EffectStatus::Enabled : EffectStatus::Disabled; + return enabled ? EffectModel::Status::Enabled : EffectModel::Status::Disabled; } EffectModel::EffectModel(QObject *parent) - : QAbstractItemModel(parent) { + : QAbstractItemModel(parent) +{ } -QHash< int, QByteArray > EffectModel::roleNames() const +QHash EffectModel::roleNames() const { QHash roleNames; roleNames[NameRole] = "NameRole"; @@ -105,29 +96,31 @@ roleNames[VersionRole] = "VersionRole"; roleNames[CategoryRole] = "CategoryRole"; roleNames[ServiceNameRole] = "ServiceNameRole"; + roleNames[IconNameRole] = "IconNameRole"; roleNames[EffectStatusRole] = "EffectStatusRole"; roleNames[VideoRole] = "VideoRole"; + roleNames[WebsiteRole] = "WebsiteRole"; roleNames[SupportedRole] = "SupportedRole"; roleNames[ExclusiveRole] = "ExclusiveRole"; roleNames[ConfigurableRole] = "ConfigurableRole"; roleNames[ScriptedRole] = QByteArrayLiteral("ScriptedRole"); + roleNames[EnabledByDefaultRole] = "EnabledByDefaultRole"; return roleNames; } QModelIndex EffectModel::index(int row, int column, const QModelIndex &parent) const { -if (parent.isValid() || column > 0 || column < 0 || row < 0 || row >= m_effectsList.count()) { - return QModelIndex(); + if (parent.isValid() || column > 0 || column < 0 || row < 0 || row >= m_effectsList.count()) { + return {}; } return createIndex(row, column); } QModelIndex EffectModel::parent(const QModelIndex &child) const { Q_UNUSED(child) - - return QModelIndex(); + return {}; } int EffectModel::columnCount(const QModelIndex &parent) const @@ -147,70 +140,77 @@ QVariant EffectModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { - return QVariant(); + return {}; } - EffectData currentEffect = m_effectsList.at(index.row()); + const EffectData effect = m_effectsList.at(index.row()); switch (role) { - case Qt::DisplayRole: - case NameRole: - return m_effectsList.at(index.row()).name; - case DescriptionRole: - return m_effectsList.at(index.row()).description; - case AuthorNameRole: - return m_effectsList.at(index.row()).authorName; - case AuthorEmailRole: - return m_effectsList.at(index.row()).authorEmail; - case LicenseRole: - return m_effectsList.at(index.row()).license; - case VersionRole: - return m_effectsList.at(index.row()).version; - case CategoryRole: - return m_effectsList.at(index.row()).category; - case ServiceNameRole: - return m_effectsList.at(index.row()).serviceName; - case EffectStatusRole: - return (int)m_effectsList.at(index.row()).effectStatus; - case VideoRole: - return m_effectsList.at(index.row()).video; - case SupportedRole: - return m_effectsList.at(index.row()).supported; - case ExclusiveRole: - return m_effectsList.at(index.row()).exclusiveGroup; - case InternalRole: - return m_effectsList.at(index.row()).internal; - case ConfigurableRole: - return m_effectsList.at(index.row()).configurable; - case ScriptedRole: - return m_effectsList.at(index.row()).scripted; - default: - return QVariant(); + case Qt::DisplayRole: + case NameRole: + return effect.name; + case DescriptionRole: + return effect.description; + case AuthorNameRole: + return effect.authorName; + case AuthorEmailRole: + return effect.authorEmail; + case LicenseRole: + return effect.license; + case VersionRole: + return effect.version; + case CategoryRole: + return effect.category; + case ServiceNameRole: + return effect.serviceName; + case IconNameRole: + return effect.iconName; + case EffectStatusRole: + return static_cast(effect.effectStatus); + case VideoRole: + return effect.video; + case WebsiteRole: + return effect.website; + case SupportedRole: + return effect.supported; + case ExclusiveRole: + return effect.exclusiveGroup; + case InternalRole: + return effect.internal; + case ConfigurableRole: + return effect.configurable; + case ScriptedRole: + return effect.kind == Kind::Scripted; + case EnabledByDefaultRole: + return effect.enabledByDefault; + default: + return {}; } } -bool EffectModel::setData(const QModelIndex& index, const QVariant& value, int role) +bool EffectModel::setData(const QModelIndex &index, const QVariant &value, int role) { - if (!index.isValid()) + if (!index.isValid()) { return QAbstractItemModel::setData(index, value, role); + } if (role == EffectModel::EffectStatusRole) { // note: whenever the StatusRole is modified (even to the same value) the entry // gets marked as changed and will get saved to the config file. This means the // config file could get polluted EffectData &data = m_effectsList[index.row()]; - data.effectStatus = EffectStatus(value.toInt()); + data.effectStatus = Status(value.toInt()); data.changed = true; emit dataChanged(index, index); - if (data.effectStatus == EffectStatus::Enabled && !data.exclusiveGroup.isEmpty()) { + if (data.effectStatus == Status::Enabled && !data.exclusiveGroup.isEmpty()) { // need to disable all other exclusive effects in the same category for (int i = 0; i < m_effectsList.size(); ++i) { if (i == index.row()) { continue; } EffectData &otherData = m_effectsList[i]; if (otherData.exclusiveGroup == data.exclusiveGroup) { - otherData.effectStatus = EffectStatus::Disabled; + otherData.effectStatus = Status::Disabled; otherData.changed = true; emit dataChanged(this->index(i, 0), this->index(i, 0)); } @@ -235,36 +235,45 @@ effect.authorEmail = QString(); // not used at all effect.license = QStringLiteral("GPL"); effect.version = QStringLiteral(KWIN_VERSION_STRING); + effect.untranslatedCategory = data.category; effect.category = translatedCategory(data.category); effect.serviceName = data.name; + effect.iconName = QStringLiteral("preferences-system-windows"); effect.enabledByDefault = data.enabled; effect.enabledByDefaultFunction = (data.enabledFunction != nullptr); const QString enabledKey = QStringLiteral("%1Enabled").arg(effect.serviceName); if (kwinConfig.hasKey(enabledKey)) { effect.effectStatus = effectStatus(kwinConfig.readEntry(effect.serviceName + "Enabled", effect.enabledByDefault)); } else if (data.enabledFunction != nullptr) { - effect.effectStatus = EffectStatus::EnabledUndeterminded; + effect.effectStatus = Status::EnabledUndeterminded; } else { effect.effectStatus = effectStatus(effect.enabledByDefault); } effect.video = data.video; + effect.website = QUrl(); effect.supported = true; effect.exclusiveGroup = data.exclusiveCategory; effect.internal = data.internal; - effect.scripted = false; + effect.kind = Kind::Builtin; - auto it = std::find_if(configs.begin(), configs.end(), [data](const KPluginInfo &info) { - return info.property(QStringLiteral("X-KDE-ParentComponents")).toString() == data.name; - }); - effect.configurable = it != configs.end(); + effect.configurable = std::any_of(configs.constBegin(), configs.constEnd(), + [data](const KPluginInfo &info) { + return info.property(QStringLiteral("X-KDE-ParentComponents")).toString() == data.name; + } + ); - m_effectsList << effect; + if (shouldStore(effect)) { + m_effectsList << effect; + } } } void EffectModel::loadJavascriptEffects(const KConfigGroup &kwinConfig) { - const auto plugins = KPackage::PackageLoader::self()->listPackages(QStringLiteral("KWin/Effect"), QStringLiteral("kwin/effects")); + const auto plugins = KPackage::PackageLoader::self()->listPackages( + QStringLiteral("KWin/Effect"), + QStringLiteral("kwin/effects") + ); for (const KPluginMetaData &metaData : plugins) { KPluginInfo plugin(metaData); EffectData effect; @@ -275,16 +284,19 @@ effect.authorEmail = plugin.email(); effect.license = plugin.license(); effect.version = plugin.version(); + effect.untranslatedCategory = plugin.category(); effect.category = translatedCategory(plugin.category()); effect.serviceName = plugin.pluginName(); + effect.iconName = plugin.icon(); effect.effectStatus = effectStatus(kwinConfig.readEntry(effect.serviceName + "Enabled", plugin.isPluginEnabledByDefault())); effect.enabledByDefault = plugin.isPluginEnabledByDefault(); effect.enabledByDefaultFunction = false; effect.video = plugin.property(QStringLiteral("X-KWin-Video-Url")).toUrl(); + effect.website = plugin.website(); effect.supported = true; effect.exclusiveGroup = plugin.property(QStringLiteral("X-KWin-Exclusive-Category")).toString(); effect.internal = plugin.property(QStringLiteral("X-KWin-Internal")).toBool(); - effect.scripted = true; + effect.kind = Kind::Scripted; const QString pluginKeyword = plugin.property(QStringLiteral("X-KDE-PluginKeyword")).toString(); if (!pluginKeyword.isEmpty()) { @@ -294,30 +306,38 @@ effect.configurable = false; } - m_effectsList << effect; + if (shouldStore(effect)) { + m_effectsList << effect; + } } } void EffectModel::loadPluginEffects(const KConfigGroup &kwinConfig, const KPluginInfo::List &configs) { - static const QString subDir(QStringLiteral("kwin/effects/plugins/")); - static const QString serviceType(QStringLiteral("KWin/Effect")); - const QVector pluginEffects = KPluginLoader::findPlugins(subDir, [] (const KPluginMetaData &data) { return data.serviceTypes().contains(serviceType); }); - for (KPluginMetaData pluginEffect : pluginEffects) { - if (!pluginEffect.isValid()) + const auto pluginEffects = KPluginLoader::findPlugins( + QStringLiteral("kwin/effects/plugins/"), + [](const KPluginMetaData &data) { + return data.serviceTypes().contains(QStringLiteral("KWin/Effect")); + } + ); + for (const KPluginMetaData &pluginEffect : pluginEffects) { + if (!pluginEffect.isValid()) { continue; + } EffectData effect; effect.name = pluginEffect.name(); effect.description = pluginEffect.description(); effect.license = pluginEffect.license(); effect.version = pluginEffect.version(); - effect.category = pluginEffect.category(); + effect.untranslatedCategory = pluginEffect.category(); + effect.category = translatedCategory(pluginEffect.category()); effect.serviceName = pluginEffect.pluginId(); + effect.iconName = pluginEffect.iconName(); effect.enabledByDefault = pluginEffect.isEnabledByDefault(); effect.supported = true; effect.enabledByDefaultFunction = false; effect.internal = false; - effect.scripted = false; + effect.kind = Kind::Binary; for (int i = 0; i < pluginEffect.authors().count(); ++i) { effect.authorName.append(pluginEffect.authors().at(i).name()); @@ -335,25 +355,30 @@ effect.enabledByDefaultFunction = d.value("enabledByDefaultMethod").toBool(); } + effect.website = pluginEffect.website(); + const QString enabledKey = QStringLiteral("%1Enabled").arg(effect.serviceName); if (kwinConfig.hasKey(enabledKey)) { effect.effectStatus = effectStatus(kwinConfig.readEntry(effect.serviceName + "Enabled", effect.enabledByDefault)); } else if (effect.enabledByDefaultFunction) { - effect.effectStatus = EffectStatus::EnabledUndeterminded; + effect.effectStatus = Status::EnabledUndeterminded; } else { effect.effectStatus = effectStatus(effect.enabledByDefault); } - auto it = std::find_if(configs.begin(), configs.end(), [pluginEffect](const KPluginInfo &info) { - return info.property(QStringLiteral("X-KDE-ParentComponents")).toString() == pluginEffect.pluginId(); - }); - effect.configurable = it != configs.end(); + effect.configurable = std::any_of(configs.constBegin(), configs.constEnd(), + [pluginEffect](const KPluginInfo &info) { + return info.property(QStringLiteral("X-KDE-ParentComponents")).toString() == pluginEffect.pluginId(); + } + ); - m_effectsList << effect; + if (shouldStore(effect)) { + m_effectsList << effect; + } } } -void EffectModel::loadEffects() +void EffectModel::load() { KConfigGroup kwinConfig(KSharedConfig::openConfig("kwinrc"), "Plugins"); @@ -376,19 +401,22 @@ }); OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"), - QStringLiteral("/Effects"), - QDBusConnection::sessionBus()); + QStringLiteral("/Effects"), + QDBusConnection::sessionBus()); + if (interface.isValid()) { QStringList effectNames; - std::for_each(m_effectsList.constBegin(), m_effectsList.constEnd(), [&effectNames](const EffectData &data) { - effectNames << data.serviceName; - }); + effectNames.reserve(m_effectsList.count()); + for (const EffectData &data : m_effectsList) { + effectNames.append(data.serviceName); + } + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(interface.areEffectsSupported(effectNames), this); watcher->setProperty("effectNames", effectNames); connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *self) { const QStringList effectNames = self->property("effectNames").toStringList(); - const QDBusPendingReply< QList< bool > > reply = *self; - QList< bool> supportValues; + const QDBusPendingReply > reply = *self; + QList supportValues; if (reply.isValid()) { supportValues.append(reply.value()); } @@ -431,27 +459,28 @@ void EffectModel::syncEffectsToKWin() { OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"), - QStringLiteral("/Effects"), - QDBusConnection::sessionBus()); + QStringLiteral("/Effects"), + QDBusConnection::sessionBus()); for (int it = 0; it < m_effectsList.size(); it++) { - if (m_effectsList.at(it).effectStatus != m_effectsChanged.at(it).effectStatus) { - if (m_effectsList.at(it).effectStatus != EffectStatus::Disabled) { - interface.loadEffect(m_effectsList.at(it).serviceName); - } else { - interface.unloadEffect(m_effectsList.at(it).serviceName); - } + if (m_effectsList.at(it).effectStatus == m_effectsChanged.at(it).effectStatus) { + continue; + } + if (m_effectsList.at(it).effectStatus != Status::Disabled) { + interface.loadEffect(m_effectsList.at(it).serviceName); + } else { + interface.unloadEffect(m_effectsList.at(it).serviceName); } } m_effectsChanged = m_effectsList; } -void EffectModel::updateEffectStatus(const QModelIndex &rowIndex, EffectStatus effectState) +void EffectModel::updateEffectStatus(const QModelIndex &rowIndex, Status effectState) { - setData(rowIndex, (int)effectState, EffectModel::EffectStatusRole); + setData(rowIndex, static_cast(effectState), EffectModel::EffectStatusRole); } -void EffectModel::syncConfig() +void EffectModel::save() { KConfigGroup kwinConfig(KSharedConfig::openConfig("kwinrc"), "Plugins"); @@ -463,10 +492,10 @@ effect.changed = false; const QString key = effect.serviceName + QStringLiteral("Enabled"); - const bool shouldEnable = (effect.effectStatus != EffectStatus::Disabled); + const bool shouldEnable = (effect.effectStatus != Status::Disabled); const bool restoreToDefault = effect.enabledByDefaultFunction - ? effect.effectStatus == EffectStatus::EnabledUndeterminded - : shouldEnable == effect.enabledByDefault; + ? effect.effectStatus == Status::EnabledUndeterminded + : shouldEnable == effect.enabledByDefault; if (restoreToDefault) { kwinConfig.deleteEntry(key); } else { @@ -482,181 +511,18 @@ { for (int i = 0; i < m_effectsList.count(); ++i) { const auto &effect = m_effectsList.at(i); - if (effect.enabledByDefaultFunction && effect.effectStatus != EffectStatus::EnabledUndeterminded) { - updateEffectStatus(index(i, 0), EffectStatus::EnabledUndeterminded); + if (effect.enabledByDefaultFunction && effect.effectStatus != Status::EnabledUndeterminded) { + updateEffectStatus(index(i, 0), Status::EnabledUndeterminded); } else if ((bool)effect.effectStatus != effect.enabledByDefault) { - updateEffectStatus(index(i, 0), effect.enabledByDefault ? EffectStatus::Enabled : EffectStatus::Disabled); + updateEffectStatus(index(i, 0), effect.enabledByDefault ? Status::Enabled : Status::Disabled); } } } -EffectFilterModel::EffectFilterModel(QObject *parent) - : QSortFilterProxyModel(parent) - , m_effectModel(new EffectModel(this)) - , m_filterOutUnsupported(true) - , m_filterOutInternal(true) -{ - setSourceModel(m_effectModel); - connect(this, &EffectFilterModel::filterOutUnsupportedChanged, this, &EffectFilterModel::invalidateFilter); - connect(this, &EffectFilterModel::filterOutInternalChanged, this, &EffectFilterModel::invalidateFilter); -} - -const QString &EffectFilterModel::filter() const +bool EffectModel::shouldStore(const EffectData &data) const { - return m_filter; + Q_UNUSED(data) + return true; } -void EffectFilterModel::setFilter(const QString &filter) -{ - if (filter == m_filter) { - return; - } - - m_filter = filter; - emit filterChanged(); - invalidateFilter(); } - -bool EffectFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const -{ - if (!m_effectModel) { - return false; - } - - QModelIndex index = m_effectModel->index(source_row, 0, source_parent); - if (!index.isValid()) { - return false; - } - - if (m_filterOutUnsupported) { - if (!index.data(EffectModel::SupportedRole).toBool()) { - return false; - } - } - - if (m_filterOutInternal) { - if (index.data(EffectModel::InternalRole).toBool()) { - return false; - } - } - - if (m_filter.isEmpty()) { - return true; - } - - QVariant data = index.data(); - if (!data.isValid()) { - //An invalid QVariant is valid data - return true; - } - - if (m_effectModel->data(index, EffectModel::NameRole).toString().contains(m_filter, Qt::CaseInsensitive)) { - return true; - } else if (m_effectModel->data(index, EffectModel::DescriptionRole).toString().contains(m_filter, Qt::CaseInsensitive)) { - return true; - } - if (index.data(EffectModel::CategoryRole).toString().contains(m_filter, Qt::CaseInsensitive)) { - return true; - } - - return false; -} - -void EffectFilterModel::updateEffectStatus(int rowIndex, int effectState) -{ - const QModelIndex sourceIndex = mapToSource(index(rowIndex, 0)); - - m_effectModel->updateEffectStatus(sourceIndex, EffectStatus(effectState)); -} - -void EffectFilterModel::syncConfig() -{ - m_effectModel->syncConfig(); -} - -void EffectFilterModel::load() -{ - m_effectModel->loadEffects(); -} - -void EffectFilterModel::defaults() -{ - m_effectModel->defaults(); -} - -EffectView::EffectView(ViewType type, QWidget *parent) - : QQuickWidget(parent) -{ - qRegisterMetaType(); - qmlRegisterType("org.kde.kwin.kwincompositing", 1, 0, "EffectConfig"); - qmlRegisterType("org.kde.kwin.kwincompositing", 1, 0, "EffectFilterModel"); - qmlRegisterType("org.kde.kwin.kwincompositing", 1, 0, "Compositing"); - qmlRegisterType("org.kde.kwin.kwincompositing", 1, 0, "CompositingType"); - init(type); -} - -void EffectView::init(ViewType type) -{ - KDeclarative::KDeclarative kdeclarative; - kdeclarative.setDeclarativeEngine(engine()); - kdeclarative.setTranslationDomain(QStringLiteral(TRANSLATION_DOMAIN)); - kdeclarative.setupContext(); - kdeclarative.setupEngine(engine()); - QString path; - switch (type) { - case CompositingSettingsView: - path = QStringLiteral("kwincompositing/qml/main-compositing.qml"); - break; - case DesktopEffectsView: - path = QStringLiteral("kwincompositing/qml/main.qml"); - break; - } - QString mainFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, path, QStandardPaths::LocateFile); - setResizeMode(QQuickWidget::SizeRootObjectToView); - setSource(QUrl(mainFile)); - rootObject()->setProperty("color", - KColorScheme(QPalette::Active, KColorScheme::Window, KSharedConfigPtr(0)).background(KColorScheme::NormalBackground).color()); - connect(rootObject(), SIGNAL(changed()), this, SIGNAL(changed())); - setMinimumSize(initialSize()); - connect(rootObject(), SIGNAL(implicitWidthChanged()), this, SLOT(slotImplicitSizeChanged())); - connect(rootObject(), SIGNAL(implicitHeightChanged()), this, SLOT(slotImplicitSizeChanged())); -} - -void EffectView::save() -{ - if (auto *model = rootObject()->findChild(QStringLiteral("filterModel"))) { - model->syncConfig(); - } - if (auto *compositing = rootObject()->findChild(QStringLiteral("compositing"))) { - compositing->save(); - } -} - -void EffectView::load() -{ - if (auto *model = rootObject()->findChild(QStringLiteral("filterModel"))) { - model->load(); - } - if (auto *compositing = rootObject()->findChild(QStringLiteral("compositing"))) { - compositing->reset(); - } -} - -void EffectView::defaults() -{ - if (auto *model = rootObject()->findChild(QStringLiteral("filterModel"))) { - model->defaults(); - } - if (auto *compositing = rootObject()->findChild(QStringLiteral("compositing"))) { - compositing->defaults(); - } -} - -void EffectView::slotImplicitSizeChanged() -{ - setMinimumSize(QSize(rootObject()->property("implicitWidth").toInt(), - rootObject()->property("implicitHeight").toInt())); -} - -}//end namespace Compositing -}//end namespace KWin diff --git a/kcmkwin/kwincompositing/CMakeLists.txt b/kcmkwin/kwincompositing/CMakeLists.txt --- a/kcmkwin/kwincompositing/CMakeLists.txt +++ b/kcmkwin/kwincompositing/CMakeLists.txt @@ -38,10 +38,9 @@ KF5::ConfigCore KF5::Declarative KF5::I18n - KF5::Package KF5::KCMUtils KF5::NewStuff - kwin4_effect_builtins + kcmkwincommon ) if (BUILD_TESTING) @@ -72,11 +71,10 @@ KF5::ConfigCore KF5::Declarative KF5::I18n - KF5::Package KF5::KCMUtils KF5::NewStuff kwineffects - kwin4_effect_builtins + kcmkwincommon ) endif() diff --git a/kcmkwin/kwincompositing/model.h b/kcmkwin/kwincompositing/model.h --- a/kcmkwin/kwincompositing/model.h +++ b/kcmkwin/kwincompositing/model.h @@ -24,95 +24,15 @@ #include #include -#include -#include -#include #include #include #include -#include namespace KWin { -namespace Compositing { - -enum class EffectStatus { - Disabled = Qt::Unchecked, - EnabledUndeterminded = Qt::PartiallyChecked, - Enabled = Qt::Checked -}; - -struct EffectData { - QString name; - QString description; - QString authorName; - QString authorEmail; - QString license; - QString version; - QString category; - QString serviceName; - EffectStatus effectStatus; - bool enabledByDefault; - bool enabledByDefaultFunction; - QUrl video; - bool supported; - QString exclusiveGroup; - bool internal; - bool configurable; - bool scripted; - bool changed = false; -}; - -class EffectModel : public QAbstractItemModel -{ - - Q_OBJECT - -public: - enum EffectRoles { - NameRole = Qt::UserRole + 1, - DescriptionRole, - AuthorNameRole, - AuthorEmailRole, - LicenseRole, - VersionRole, - CategoryRole, - ServiceNameRole, - EffectStatusRole, - VideoRole, - SupportedRole, - ExclusiveRole, - InternalRole, - ConfigurableRole, - ScriptedRole - }; - - explicit EffectModel(QObject *parent = 0); - - QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; - QModelIndex parent(const QModelIndex &child) const override; - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - int columnCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; - QString serviceName(const QString &effectName); - - virtual QHash< int, QByteArray > roleNames() const override; - void updateEffectStatus(const QModelIndex &rowIndex, EffectStatus effectState); - void syncEffectsToKWin(); - void syncConfig(); - void loadEffects(); - void defaults(); - -private: - void loadBuiltInEffects(const KConfigGroup &kwinConfig, const KPluginInfo::List &configs); - void loadJavascriptEffects(const KConfigGroup &kwinConfig); - void loadPluginEffects(const KConfigGroup &kwinConfig, const KPluginInfo::List &configs); - int findRowByServiceName(const QString &serviceName); - QList m_effectsList; - QList m_effectsChanged; +class EffectModel; -}; +namespace Compositing { class EffectView : public QQuickWidget { diff --git a/kcmkwin/kwincompositing/model.cpp b/kcmkwin/kwincompositing/model.cpp --- a/kcmkwin/kwincompositing/model.cpp +++ b/kcmkwin/kwincompositing/model.cpp @@ -20,29 +20,17 @@ #include "model.h" #include "effectconfig.h" +#include "effectmodel.h" #include "compositing.h" #include #include #include -#include #include #include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include #include #include #include @@ -52,444 +40,6 @@ namespace KWin { namespace Compositing { -static QString translatedCategory(const QString &category) -{ - static const QVector knownCategories = { - QStringLiteral("Accessibility"), - QStringLiteral("Appearance"), - QStringLiteral("Candy"), - QStringLiteral("Focus"), - QStringLiteral("Show Desktop Animation"), - QStringLiteral("Tools"), - QStringLiteral("Virtual Desktop Switching Animation"), - QStringLiteral("Window Management"), - QStringLiteral("Window Open/Close Animation") - }; - - static const QVector translatedCategories = { - i18nc("Category of Desktop Effects, used as section header", "Accessibility"), - i18nc("Category of Desktop Effects, used as section header", "Appearance"), - i18nc("Category of Desktop Effects, used as section header", "Candy"), - i18nc("Category of Desktop Effects, used as section header", "Focus"), - i18nc("Category of Desktop Effects, used as section header", "Show Desktop Animation"), - i18nc("Category of Desktop Effects, used as section header", "Tools"), - i18nc("Category of Desktop Effects, used as section header", "Virtual Desktop Switching Animation"), - i18nc("Category of Desktop Effects, used as section header", "Window Management"), - i18nc("Category of Desktop Effects, used as section header", "Window Open/Close Animation") - }; - const int index = knownCategories.indexOf(category); - if (index == -1) { - qDebug() << "Unknown category '" << category << "' and thus not translated"; - return category; - } - return translatedCategories[index]; -} - -static EffectStatus effectStatus(bool enabled) -{ - return enabled ? EffectStatus::Enabled : EffectStatus::Disabled; -} - -EffectModel::EffectModel(QObject *parent) - : QAbstractItemModel(parent) { -} - -QHash< int, QByteArray > EffectModel::roleNames() const -{ - QHash roleNames; - roleNames[NameRole] = "NameRole"; - roleNames[DescriptionRole] = "DescriptionRole"; - roleNames[AuthorNameRole] = "AuthorNameRole"; - roleNames[AuthorEmailRole] = "AuthorEmailRole"; - roleNames[LicenseRole] = "LicenseRole"; - roleNames[VersionRole] = "VersionRole"; - roleNames[CategoryRole] = "CategoryRole"; - roleNames[ServiceNameRole] = "ServiceNameRole"; - roleNames[EffectStatusRole] = "EffectStatusRole"; - roleNames[VideoRole] = "VideoRole"; - roleNames[SupportedRole] = "SupportedRole"; - roleNames[ExclusiveRole] = "ExclusiveRole"; - roleNames[ConfigurableRole] = "ConfigurableRole"; - roleNames[ScriptedRole] = QByteArrayLiteral("ScriptedRole"); - return roleNames; -} - -QModelIndex EffectModel::index(int row, int column, const QModelIndex &parent) const -{ -if (parent.isValid() || column > 0 || column < 0 || row < 0 || row >= m_effectsList.count()) { - return QModelIndex(); - } - - return createIndex(row, column); -} - -QModelIndex EffectModel::parent(const QModelIndex &child) const -{ - Q_UNUSED(child) - - return QModelIndex(); -} - -int EffectModel::columnCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent) - return 1; -} - -int EffectModel::rowCount(const QModelIndex &parent) const -{ - if (parent.isValid()) { - return 0; - } - return m_effectsList.count(); -} - -QVariant EffectModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) { - return QVariant(); - } - - EffectData currentEffect = m_effectsList.at(index.row()); - switch (role) { - case Qt::DisplayRole: - case NameRole: - return m_effectsList.at(index.row()).name; - case DescriptionRole: - return m_effectsList.at(index.row()).description; - case AuthorNameRole: - return m_effectsList.at(index.row()).authorName; - case AuthorEmailRole: - return m_effectsList.at(index.row()).authorEmail; - case LicenseRole: - return m_effectsList.at(index.row()).license; - case VersionRole: - return m_effectsList.at(index.row()).version; - case CategoryRole: - return m_effectsList.at(index.row()).category; - case ServiceNameRole: - return m_effectsList.at(index.row()).serviceName; - case EffectStatusRole: - return (int)m_effectsList.at(index.row()).effectStatus; - case VideoRole: - return m_effectsList.at(index.row()).video; - case SupportedRole: - return m_effectsList.at(index.row()).supported; - case ExclusiveRole: - return m_effectsList.at(index.row()).exclusiveGroup; - case InternalRole: - return m_effectsList.at(index.row()).internal; - case ConfigurableRole: - return m_effectsList.at(index.row()).configurable; - case ScriptedRole: - return m_effectsList.at(index.row()).scripted; - default: - return QVariant(); - } -} - -bool EffectModel::setData(const QModelIndex& index, const QVariant& value, int role) -{ - if (!index.isValid()) - return QAbstractItemModel::setData(index, value, role); - - if (role == EffectModel::EffectStatusRole) { - // note: whenever the StatusRole is modified (even to the same value) the entry - // gets marked as changed and will get saved to the config file. This means the - // config file could get polluted - EffectData &data = m_effectsList[index.row()]; - data.effectStatus = EffectStatus(value.toInt()); - data.changed = true; - emit dataChanged(index, index); - - if (data.effectStatus == EffectStatus::Enabled && !data.exclusiveGroup.isEmpty()) { - // need to disable all other exclusive effects in the same category - for (int i = 0; i < m_effectsList.size(); ++i) { - if (i == index.row()) { - continue; - } - EffectData &otherData = m_effectsList[i]; - if (otherData.exclusiveGroup == data.exclusiveGroup) { - otherData.effectStatus = EffectStatus::Disabled; - otherData.changed = true; - emit dataChanged(this->index(i, 0), this->index(i, 0)); - } - } - } - - return true; - } - - return QAbstractItemModel::setData(index, value, role); -} - -void EffectModel::loadBuiltInEffects(const KConfigGroup &kwinConfig, const KPluginInfo::List &configs) -{ - const auto builtins = BuiltInEffects::availableEffects(); - for (auto builtin : builtins) { - const BuiltInEffects::EffectData &data = BuiltInEffects::effectData(builtin); - EffectData effect; - effect.name = data.displayName; - effect.description = data.comment; - effect.authorName = i18n("KWin development team"); - effect.authorEmail = QString(); // not used at all - effect.license = QStringLiteral("GPL"); - effect.version = QStringLiteral(KWIN_VERSION_STRING); - effect.category = translatedCategory(data.category); - effect.serviceName = data.name; - effect.enabledByDefault = data.enabled; - effect.enabledByDefaultFunction = (data.enabledFunction != nullptr); - const QString enabledKey = QStringLiteral("%1Enabled").arg(effect.serviceName); - if (kwinConfig.hasKey(enabledKey)) { - effect.effectStatus = effectStatus(kwinConfig.readEntry(effect.serviceName + "Enabled", effect.enabledByDefault)); - } else if (data.enabledFunction != nullptr) { - effect.effectStatus = EffectStatus::EnabledUndeterminded; - } else { - effect.effectStatus = effectStatus(effect.enabledByDefault); - } - effect.video = data.video; - effect.supported = true; - effect.exclusiveGroup = data.exclusiveCategory; - effect.internal = data.internal; - effect.scripted = false; - - auto it = std::find_if(configs.begin(), configs.end(), [data](const KPluginInfo &info) { - return info.property(QStringLiteral("X-KDE-ParentComponents")).toString() == data.name; - }); - effect.configurable = it != configs.end(); - - m_effectsList << effect; - } -} - -void EffectModel::loadJavascriptEffects(const KConfigGroup &kwinConfig) -{ - const auto plugins = KPackage::PackageLoader::self()->listPackages(QStringLiteral("KWin/Effect"), QStringLiteral("kwin/effects")); - for (const KPluginMetaData &metaData : plugins) { - KPluginInfo plugin(metaData); - EffectData effect; - - effect.name = plugin.name(); - effect.description = plugin.comment(); - effect.authorName = plugin.author(); - effect.authorEmail = plugin.email(); - effect.license = plugin.license(); - effect.version = plugin.version(); - effect.category = translatedCategory(plugin.category()); - effect.serviceName = plugin.pluginName(); - effect.effectStatus = effectStatus(kwinConfig.readEntry(effect.serviceName + "Enabled", plugin.isPluginEnabledByDefault())); - effect.enabledByDefault = plugin.isPluginEnabledByDefault(); - effect.enabledByDefaultFunction = false; - effect.video = plugin.property(QStringLiteral("X-KWin-Video-Url")).toUrl(); - effect.supported = true; - effect.exclusiveGroup = plugin.property(QStringLiteral("X-KWin-Exclusive-Category")).toString(); - effect.internal = plugin.property(QStringLiteral("X-KWin-Internal")).toBool(); - effect.scripted = true; - - const QString pluginKeyword = plugin.property(QStringLiteral("X-KDE-PluginKeyword")).toString(); - if (!pluginKeyword.isEmpty()) { - // scripted effects have their pluginName() as the keyword - effect.configurable = plugin.property(QStringLiteral("X-KDE-ParentComponents")).toString() == pluginKeyword; - } else { - effect.configurable = false; - } - - m_effectsList << effect; - } -} - -void EffectModel::loadPluginEffects(const KConfigGroup &kwinConfig, const KPluginInfo::List &configs) -{ - static const QString subDir(QStringLiteral("kwin/effects/plugins/")); - static const QString serviceType(QStringLiteral("KWin/Effect")); - const QVector pluginEffects = KPluginLoader::findPlugins(subDir, [] (const KPluginMetaData &data) { return data.serviceTypes().contains(serviceType); }); - for (KPluginMetaData pluginEffect : pluginEffects) { - if (!pluginEffect.isValid()) - continue; - EffectData effect; - effect.name = pluginEffect.name(); - effect.description = pluginEffect.description(); - effect.license = pluginEffect.license(); - effect.version = pluginEffect.version(); - effect.category = pluginEffect.category(); - effect.serviceName = pluginEffect.pluginId(); - effect.enabledByDefault = pluginEffect.isEnabledByDefault(); - effect.supported = true; - effect.enabledByDefaultFunction = false; - effect.internal = false; - effect.scripted = false; - - for (int i = 0; i < pluginEffect.authors().count(); ++i) { - effect.authorName.append(pluginEffect.authors().at(i).name()); - effect.authorEmail.append(pluginEffect.authors().at(i).emailAddress()); - if (i+1 < pluginEffect.authors().count()) { - effect.authorName.append(", "); - effect.authorEmail.append(", "); - } - } - - if (pluginEffect.rawData().contains("org.kde.kwin.effect")) { - const QJsonObject d(pluginEffect.rawData().value("org.kde.kwin.effect").toObject()); - effect.exclusiveGroup = d.value("exclusiveGroup").toString(); - effect.video = QUrl::fromUserInput(d.value("video").toString()); - effect.enabledByDefaultFunction = d.value("enabledByDefaultMethod").toBool(); - } - - const QString enabledKey = QStringLiteral("%1Enabled").arg(effect.serviceName); - if (kwinConfig.hasKey(enabledKey)) { - effect.effectStatus = effectStatus(kwinConfig.readEntry(effect.serviceName + "Enabled", effect.enabledByDefault)); - } else if (effect.enabledByDefaultFunction) { - effect.effectStatus = EffectStatus::EnabledUndeterminded; - } else { - effect.effectStatus = effectStatus(effect.enabledByDefault); - } - - auto it = std::find_if(configs.begin(), configs.end(), [pluginEffect](const KPluginInfo &info) { - return info.property(QStringLiteral("X-KDE-ParentComponents")).toString() == pluginEffect.pluginId(); - }); - effect.configurable = it != configs.end(); - - m_effectsList << effect; - } -} - -void EffectModel::loadEffects() -{ - KConfigGroup kwinConfig(KSharedConfig::openConfig("kwinrc"), "Plugins"); - - beginResetModel(); - m_effectsChanged.clear(); - m_effectsList.clear(); - const KPluginInfo::List configs = KPluginTrader::self()->query(QStringLiteral("kwin/effects/configs/")); - loadBuiltInEffects(kwinConfig, configs); - loadJavascriptEffects(kwinConfig); - loadPluginEffects(kwinConfig, configs); - - qSort(m_effectsList.begin(), m_effectsList.end(), [](const EffectData &a, const EffectData &b) { - if (a.category == b.category) { - if (a.exclusiveGroup == b.exclusiveGroup) { - return a.name < b.name; - } - return a.exclusiveGroup < b.exclusiveGroup; - } - return a.category < b.category; - }); - - OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"), - QStringLiteral("/Effects"), - QDBusConnection::sessionBus()); - if (interface.isValid()) { - QStringList effectNames; - std::for_each(m_effectsList.constBegin(), m_effectsList.constEnd(), [&effectNames](const EffectData &data) { - effectNames << data.serviceName; - }); - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(interface.areEffectsSupported(effectNames), this); - watcher->setProperty("effectNames", effectNames); - connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *self) { - const QStringList effectNames = self->property("effectNames").toStringList(); - const QDBusPendingReply< QList< bool > > reply = *self; - QList< bool> supportValues; - if (reply.isValid()) { - supportValues.append(reply.value()); - } - if (effectNames.size() == supportValues.size()) { - for (int i = 0; i < effectNames.size(); ++i) { - const bool supportedValue = supportValues.at(i); - const QString &effectName = effectNames.at(i); - auto it = std::find_if(m_effectsList.begin(), m_effectsList.end(), [effectName](const EffectData &data) { - return data.serviceName == effectName; - }); - if (it != m_effectsList.end()) { - if ((*it).supported != supportedValue) { - (*it).supported = supportedValue; - QModelIndex i = index(findRowByServiceName(effectName), 0); - if (i.isValid()) { - emit dataChanged(i, i, QVector() << SupportedRole); - } - } - } - } - } - self->deleteLater(); - }); - } - - m_effectsChanged = m_effectsList; - endResetModel(); -} - -int EffectModel::findRowByServiceName(const QString &serviceName) -{ - for (int it = 0; it < m_effectsList.size(); it++) { - if (m_effectsList.at(it).serviceName == serviceName) { - return it; - } - } - return -1; -} - -void EffectModel::syncEffectsToKWin() -{ - OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"), - QStringLiteral("/Effects"), - QDBusConnection::sessionBus()); - for (int it = 0; it < m_effectsList.size(); it++) { - if (m_effectsList.at(it).effectStatus != m_effectsChanged.at(it).effectStatus) { - if (m_effectsList.at(it).effectStatus != EffectStatus::Disabled) { - interface.loadEffect(m_effectsList.at(it).serviceName); - } else { - interface.unloadEffect(m_effectsList.at(it).serviceName); - } - } - } - - m_effectsChanged = m_effectsList; -} - -void EffectModel::updateEffectStatus(const QModelIndex &rowIndex, EffectStatus effectState) -{ - setData(rowIndex, (int)effectState, EffectModel::EffectStatusRole); -} - -void EffectModel::syncConfig() -{ - KConfigGroup kwinConfig(KSharedConfig::openConfig("kwinrc"), "Plugins"); - - for (auto it = m_effectsList.begin(); it != m_effectsList.end(); it++) { - EffectData &effect = *(it); - if (!effect.changed) { - continue; - } - effect.changed = false; - - const QString key = effect.serviceName + QStringLiteral("Enabled"); - const bool shouldEnable = (effect.effectStatus != EffectStatus::Disabled); - const bool restoreToDefault = effect.enabledByDefaultFunction - ? effect.effectStatus == EffectStatus::EnabledUndeterminded - : shouldEnable == effect.enabledByDefault; - if (restoreToDefault) { - kwinConfig.deleteEntry(key); - } else { - kwinConfig.writeEntry(key, shouldEnable); - } - } - - kwinConfig.sync(); - syncEffectsToKWin(); -} - -void EffectModel::defaults() -{ - for (int i = 0; i < m_effectsList.count(); ++i) { - const auto &effect = m_effectsList.at(i); - if (effect.enabledByDefaultFunction && effect.effectStatus != EffectStatus::EnabledUndeterminded) { - updateEffectStatus(index(i, 0), EffectStatus::EnabledUndeterminded); - } else if ((bool)effect.effectStatus != effect.enabledByDefault) { - updateEffectStatus(index(i, 0), effect.enabledByDefault ? EffectStatus::Enabled : EffectStatus::Disabled); - } - } -} - EffectFilterModel::EffectFilterModel(QObject *parent) : QSortFilterProxyModel(parent) , m_effectModel(new EffectModel(this)) @@ -566,17 +116,17 @@ { const QModelIndex sourceIndex = mapToSource(index(rowIndex, 0)); - m_effectModel->updateEffectStatus(sourceIndex, EffectStatus(effectState)); + m_effectModel->updateEffectStatus(sourceIndex, EffectModel::Status(effectState)); } void EffectFilterModel::syncConfig() { - m_effectModel->syncConfig(); + m_effectModel->save(); } void EffectFilterModel::load() { - m_effectModel->loadEffects(); + m_effectModel->load(); } void EffectFilterModel::defaults() diff --git a/kcmkwin/kwincompositing/test/effectmodeltest.cpp b/kcmkwin/kwincompositing/test/effectmodeltest.cpp --- a/kcmkwin/kwincompositing/test/effectmodeltest.cpp +++ b/kcmkwin/kwincompositing/test/effectmodeltest.cpp @@ -21,15 +21,18 @@ #include "modeltest.h" #include "../model.h" #include "effectmodeltest.h" + +#include "effectmodel.h" + #include EffectModelTest::EffectModelTest(QObject *parent) : QObject(parent) { } void EffectModelTest::testEffectModel() { - KWin::Compositing::EffectModel *effectModel = new KWin::Compositing::EffectModel(); + auto effectModel = new KWin::EffectModel(); new ModelTest(effectModel, this); }