diff --git a/kcmkwin/CMakeLists.txt b/kcmkwin/CMakeLists.txt index 152ba322d..258650680 100644 --- a/kcmkwin/CMakeLists.txt +++ b/kcmkwin/CMakeLists.txt @@ -1,14 +1,15 @@ 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 ) add_subdirectory( kwinrules ) add_subdirectory( kwinscreenedges ) add_subdirectory( kwinscripts ) add_subdirectory( kwindesktop ) +add_subdirectory( kwineffects ) if( KWIN_BUILD_TABBOX ) add_subdirectory( kwintabbox ) endif() diff --git a/kcmkwin/common/effectmodel.cpp b/kcmkwin/common/effectmodel.cpp index 76615b373..a443a2a3b 100644 --- a/kcmkwin/common/effectmodel.cpp +++ b/kcmkwin/common/effectmodel.cpp @@ -1,528 +1,545 @@ /******************************************************************** 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 namespace KWin { 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 EffectModel::Status effectStatus(bool enabled) { return enabled ? EffectModel::Status::Enabled : EffectModel::Status::Disabled; } EffectModel::EffectModel(QObject *parent) : QAbstractItemModel(parent) { } QHash 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[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 {}; } return createIndex(row, column); } QModelIndex EffectModel::parent(const QModelIndex &child) const { Q_UNUSED(child) return {}; } 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 {}; } const EffectData effect = m_effectsList.at(index.row()); switch (role) { 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) { 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 = Status(value.toInt()); - data.changed = true; + data.changed = data.effectStatus != data.originalStatus; emit dataChanged(index, index); 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 = Status::Disabled; - otherData.changed = true; + otherData.changed = otherData.effectStatus != otherData.originalStatus; 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.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 = Status::EnabledUndeterminded; } else { effect.effectStatus = effectStatus(effect.enabledByDefault); } + effect.originalStatus = effect.effectStatus; effect.video = data.video; effect.website = QUrl(); effect.supported = true; effect.exclusiveGroup = data.exclusiveCategory; effect.internal = data.internal; effect.kind = Kind::BuiltIn; effect.configurable = std::any_of(configs.constBegin(), configs.constEnd(), [data](const KPluginInfo &info) { return info.property(QStringLiteral("X-KDE-ParentComponents")).toString() == data.name; } ); 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") ); 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.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.originalStatus = effect.effectStatus; effect.enabledByDefault = plugin.isPluginEnabledByDefault(); effect.enabledByDefaultFunction = false; effect.video = plugin.property(QStringLiteral("X-KWin-Video-Url")).toUrl(); effect.website = QUrl(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.kind = Kind::Scripted; 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; } if (shouldStore(effect)) { m_effectsList << effect; } } } void EffectModel::loadPluginEffects(const KConfigGroup &kwinConfig, const KPluginInfo::List &configs) { 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.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.kind = Kind::Binary; 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(); } effect.website = QUrl(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 = Status::EnabledUndeterminded; } else { effect.effectStatus = effectStatus(effect.enabledByDefault); } + effect.originalStatus = effect.effectStatus; + effect.configurable = std::any_of(configs.constBegin(), configs.constEnd(), [pluginEffect](const KPluginInfo &info) { return info.property(QStringLiteral("X-KDE-ParentComponents")).toString() == pluginEffect.pluginId(); } ); if (shouldStore(effect)) { m_effectsList << effect; } } } void EffectModel::load() { 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; 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 > reply = *self; QList 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); + QModelIndex i = findByPluginId(effectName); 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) { 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, Status effectState) { setData(rowIndex, static_cast(effectState), EffectModel::EffectStatusRole); } void EffectModel::save() { 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; + effect.originalStatus = effect.effectStatus; const QString key = effect.serviceName + QStringLiteral("Enabled"); const bool shouldEnable = (effect.effectStatus != Status::Disabled); const bool restoreToDefault = effect.enabledByDefaultFunction ? effect.effectStatus == Status::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 != Status::EnabledUndeterminded) { updateEffectStatus(index(i, 0), Status::EnabledUndeterminded); } else if ((bool)effect.effectStatus != effect.enabledByDefault) { updateEffectStatus(index(i, 0), effect.enabledByDefault ? Status::Enabled : Status::Disabled); } } } +bool EffectModel::needsSave() const +{ + return std::any_of(m_effectsList.constBegin(), m_effectsList.constEnd(), + [](const EffectData &data) { + return data.changed; + } + ); +} + +QModelIndex EffectModel::findByPluginId(const QString &pluginId) const +{ + auto it = std::find_if(m_effectsList.constBegin(), m_effectsList.constEnd(), + [pluginId](const EffectData &data) { + return data.serviceName == pluginId; + } + ); + if (it == m_effectsList.constEnd()) { + return {}; + } + return index(std::distance(m_effectsList.constBegin(), it), 0); +} + bool EffectModel::shouldStore(const EffectData &data) const { Q_UNUSED(data) return true; } } diff --git a/kcmkwin/common/effectmodel.h b/kcmkwin/common/effectmodel.h index e950f24dd..8c1ba7788 100644 --- a/kcmkwin/common/effectmodel.h +++ b/kcmkwin/common/effectmodel.h @@ -1,232 +1,242 @@ /******************************************************************** 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(); + /** + * Whether the model has unsaved changes. + **/ + bool needsSave() const; + + /** + * Finds an effect with the given plugin id. + **/ + QModelIndex findByPluginId(const QString &pluginId) const; + 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; + Status originalStatus; 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/CMakeLists.txt b/kcmkwin/kwincompositing/CMakeLists.txt index e7ae25c96..651993714 100644 --- a/kcmkwin/kwincompositing/CMakeLists.txt +++ b/kcmkwin/kwincompositing/CMakeLists.txt @@ -1,81 +1,33 @@ ######################################################################### # KI18N Translation Domain for this library add_definitions(-DTRANSLATION_DOMAIN=\"kcmkwincompositing\") add_definitions(-DQT_NO_URL_CAST_FROM_STRING) remove_definitions(-DQT_NO_CAST_FROM_ASCII -DQT_STRICT_ITERATORS -DQT_NO_CAST_FROM_BYTEARRAY) -include_directories(${KWIN_SOURCE_DIR}/effects) - ################# configure checks and create the configured files ################# set(kwincomposing_SRC - model.cpp main.cpp - compositing.cpp - effectconfig.cpp) + compositing.cpp) qt5_add_dbus_interface( kwincomposing_SRC ${KWIN_SOURCE_DIR}/org.kde.kwin.Compositing.xml kwin_compositing_interface) -qt5_add_dbus_interface( kwincomposing_SRC - ${KWIN_SOURCE_DIR}/org.kde.kwin.Effects.xml kwin_effects_interface) ki18n_wrap_ui(kwincomposing_SRC compositing.ui) add_library(kwincompositing MODULE ${kwincomposing_SRC}) target_link_libraries(kwincompositing - Qt5::Quick - Qt5::QuickWidgets Qt5::DBus Qt5::Widgets KF5::CoreAddons KF5::ConfigCore - KF5::Declarative KF5::I18n KF5::KCMUtils - KF5::NewStuff - kcmkwincommon ) -if (BUILD_TESTING) - include(ECMMarkAsTest) - - set(modelTest_SRC - model.cpp - effectconfig.cpp - compositing.cpp - test/effectmodeltest.cpp - test/modeltest.cpp) - - qt5_add_dbus_interface(modelTest_SRC - ${KWIN_SOURCE_DIR}/org.kde.kwin.Compositing.xml kwin_compositing_interface) - qt5_add_dbus_interface(modelTest_SRC - ${KWIN_SOURCE_DIR}/org.kde.kwin.Effects.xml kwin_effects_interface) - - add_executable(effectModelTest ${modelTest_SRC}) - ecm_mark_as_test(effectModelTest) - - target_link_libraries(effectModelTest - Qt5::Quick - Qt5::QuickWidgets - Qt5::DBus - Qt5::Test - Qt5::Widgets - KF5::CoreAddons - KF5::ConfigCore - KF5::Declarative - KF5::I18n - KF5::KCMUtils - KF5::NewStuff - kwineffects - kcmkwincommon - ) -endif() - -INSTALL(DIRECTORY qml DESTINATION ${DATA_INSTALL_DIR}/kwincompositing) INSTALL(TARGETS kwincompositing DESTINATION ${PLUGIN_INSTALL_DIR}) -install(FILES kwincompositing.desktop kcmkwineffects.desktop DESTINATION ${SERVICES_INSTALL_DIR}) -install(FILES kwineffect.knsrc DESTINATION ${CONFIG_INSTALL_DIR}) +install(FILES kwincompositing.desktop DESTINATION ${SERVICES_INSTALL_DIR}) ################# list the subdirectories ################# diff --git a/kcmkwin/kwincompositing/effectconfig.cpp b/kcmkwin/kwincompositing/effectconfig.cpp deleted file mode 100644 index ee4eb03f6..000000000 --- a/kcmkwin/kwincompositing/effectconfig.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/************************************************************************** -* 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 "effectconfig.h" - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -static const QString s_pluginDir = QStringLiteral("kwin/effects/configs/"); - -namespace KWin { -namespace Compositing { - -EffectConfig::EffectConfig(QObject *parent) - : QObject(parent) -{ -} - -void EffectConfig::openConfig(const QString &serviceName, bool scripted, const QString &title) -{ - //setup the UI - QDialog dialog; - dialog.setWindowTitle(title); - - // create the KCModule through the plugintrader - KCModule *kcm = nullptr; - if (scripted) { - // try generic module for scripted - const auto offers = KPluginTrader::self()->query(s_pluginDir, QString(), - QStringLiteral("[X-KDE-Library] == 'kcm_kwin4_genericscripted'")); - if (!offers.isEmpty()) { - const KPluginInfo &generic = offers.first(); - KPluginLoader loader(generic.libraryPath()); - KPluginFactory *factory = loader.factory(); - if (factory) { - kcm = factory->create(serviceName, &dialog); - } - } - } else { - kcm = KPluginTrader::createInstanceFromQuery(s_pluginDir, QString(), - QStringLiteral("'%1' in [X-KDE-ParentComponents]").arg(serviceName), - &dialog); - } - if (!kcm) { - return; - } - - connect(&dialog, &QDialog::accepted, kcm, &KCModule::save); - - QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | - QDialogButtonBox::Cancel | - QDialogButtonBox::Apply | - QDialogButtonBox::RestoreDefaults | - QDialogButtonBox::Reset, - &dialog); - - QPushButton *apply = buttons->button(QDialogButtonBox::Apply); - QPushButton *reset = buttons->button(QDialogButtonBox::Reset); - apply->setEnabled(false); - reset->setEnabled(false); - //Here we connect our buttons with the dialog - connect(buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); - connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); - connect(apply, &QPushButton::clicked, kcm, &KCModule::save); - connect(reset, &QPushButton::clicked, kcm, &KCModule::load); - auto changedSignal = static_cast(&KCModule::changed); - connect(kcm, changedSignal, apply, &QPushButton::setEnabled); - connect(kcm, changedSignal, reset, &QPushButton::setEnabled); - connect(buttons->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, kcm, &KCModule::defaults); - - QVBoxLayout *layout = new QVBoxLayout(&dialog); - layout->addWidget(kcm); - layout->addWidget(buttons); - dialog.exec(); -} - -void EffectConfig::openGHNS() -{ - QPointer downloadDialog = new KNS3::DownloadDialog(QStringLiteral("kwineffect.knsrc")); - if (downloadDialog->exec() == QDialog::Accepted) { - emit effectListChanged(); - } - - delete downloadDialog; -} - -}//end namespace Compositing -}//end namespace KWin diff --git a/kcmkwin/kwincompositing/effectconfig.h b/kcmkwin/kwincompositing/effectconfig.h deleted file mode 100644 index 73e20d124..000000000 --- a/kcmkwin/kwincompositing/effectconfig.h +++ /dev/null @@ -1,47 +0,0 @@ -/************************************************************************** - * 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 . * - **************************************************************************/ - - -#ifndef EFFECTCONFIG_H -#define EFFECTCONFIG_H -#include -class QString; - -namespace KWin { -namespace Compositing { - -class EffectConfig : public QObject -{ - - Q_OBJECT - -public: - explicit EffectConfig(QObject *parent = 0); - QString serviceName(const QString &serviceName); - - Q_INVOKABLE void openConfig(const QString &effectName, bool scripted, const QString &title); - Q_INVOKABLE void openGHNS(); - -Q_SIGNALS: - void effectListChanged(); -}; -}//end namespace Compositing -}//end namespace KWin -#endif diff --git a/kcmkwin/kwincompositing/main.cpp b/kcmkwin/kwincompositing/main.cpp index 8389b3d18..81f38ac92 100644 --- a/kcmkwin/kwincompositing/main.cpp +++ b/kcmkwin/kwincompositing/main.cpp @@ -1,274 +1,209 @@ /************************************************************************** * KWin - the KDE window manager * * This file is part of the KDE project. * * * * Copyright (C) 2013 Antonis Tsiapaliokas * * Copyright (C) 2013 Martin Gräßlin * * * * 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 "compositing.h" -#include "model.h" #include "ui_compositing.h" #include #include #include #include #include -class KWinCompositingKCM : public KCModule -{ - Q_OBJECT -public: - virtual ~KWinCompositingKCM(); - -public Q_SLOTS: - void save() override; - void load() override; - void defaults() override; - -protected: - explicit KWinCompositingKCM(QWidget* parent, const QVariantList& args, - KWin::Compositing::EffectView::ViewType viewType); - -private: - QScopedPointer m_view; -}; - -class KWinDesktopEffects : public KWinCompositingKCM -{ - Q_OBJECT -public: - explicit KWinDesktopEffects(QWidget* parent = 0, const QVariantList& args = QVariantList()) - : KWinCompositingKCM(parent, args, KWin::Compositing::EffectView::DesktopEffectsView) {} -}; - class KWinCompositingSettings : public KCModule { Q_OBJECT public: explicit KWinCompositingSettings(QWidget *parent = 0, const QVariantList &args = QVariantList()); public Q_SLOTS: void load() override; void save() override; void defaults() override; private: void init(); KWin::Compositing::Compositing *m_compositing; Ui_CompositingForm m_form; }; KWinCompositingSettings::KWinCompositingSettings(QWidget *parent, const QVariantList &args) : KCModule(parent, args) , m_compositing(new KWin::Compositing::Compositing(this)) { m_form.setupUi(this); m_form.glCrashedWarning->setIcon(QIcon::fromTheme(QStringLiteral("dialog-warning"))); QAction *reenableGLAction = new QAction(i18n("Re-enable OpenGL detection"), this); connect(reenableGLAction, &QAction::triggered, m_compositing, &KWin::Compositing::Compositing::reenableOpenGLDetection); connect(reenableGLAction, &QAction::triggered, m_form.glCrashedWarning, &KMessageWidget::animatedHide); m_form.glCrashedWarning->addAction(reenableGLAction); m_form.scaleWarning->setIcon(QIcon::fromTheme(QStringLiteral("dialog-warning"))); m_form.tearingWarning->setIcon(QIcon::fromTheme(QStringLiteral("dialog-warning"))); m_form.windowThumbnailWarning->setIcon(QIcon::fromTheme(QStringLiteral("dialog-warning"))); m_form.compositingEnabled->setVisible(!m_compositing->compositingRequired()); m_form.windowsBlockCompositing->setVisible(!m_compositing->compositingRequired()); init(); } void KWinCompositingSettings::init() { using namespace KWin::Compositing; auto currentIndexChangedSignal = static_cast(&QComboBox::currentIndexChanged); connect(m_compositing, &Compositing::changed, this, static_cast(&KWinCompositingSettings::changed)); // enabled check box m_form.compositingEnabled->setChecked(m_compositing->compositingEnabled()); connect(m_compositing, &Compositing::compositingEnabledChanged, m_form.compositingEnabled, &QCheckBox::setChecked); connect(m_form.compositingEnabled, &QCheckBox::toggled, m_compositing, &Compositing::setCompositingEnabled); // animation speed m_form.animationSpeed->setValue(m_compositing->animationSpeed()); connect(m_compositing, &Compositing::animationSpeedChanged, m_form.animationSpeed, &QSlider::setValue); connect(m_form.animationSpeed, &QSlider::valueChanged, m_compositing, &Compositing::setAnimationSpeed); // gl scale filter m_form.glScaleFilter->setCurrentIndex(m_compositing->glScaleFilter()); connect(m_compositing, &Compositing::glScaleFilterChanged, m_form.glScaleFilter, &QComboBox::setCurrentIndex); connect(m_form.glScaleFilter, currentIndexChangedSignal, m_compositing, &Compositing::setGlScaleFilter); connect(m_form.glScaleFilter, currentIndexChangedSignal, [this](int index) { if (index == 2) { m_form.scaleWarning->animatedShow(); } else { m_form.scaleWarning->animatedHide(); } } ); // xrender scale filter m_form.xrScaleFilter->setCurrentIndex(m_compositing->xrScaleFilter()); connect(m_compositing, &Compositing::xrScaleFilterChanged, m_form.xrScaleFilter, &QComboBox::setCurrentIndex); connect(m_form.xrScaleFilter, currentIndexChangedSignal, [this](int index) { if (index == 0) { m_compositing->setXrScaleFilter(false); } else { m_compositing->setXrScaleFilter(true); } }); // tearing prevention m_form.tearingPrevention->setCurrentIndex(m_compositing->glSwapStrategy()); connect(m_compositing, &Compositing::glSwapStrategyChanged, m_form.tearingPrevention, &QComboBox::setCurrentIndex); connect(m_form.tearingPrevention, currentIndexChangedSignal, m_compositing, &Compositing::setGlSwapStrategy); connect(m_form.tearingPrevention, currentIndexChangedSignal, [this](int index) { if (index == 2) { // only when cheap - tearing m_form.tearingWarning->setText(i18n("\"Only when cheap\" only prevents tearing for full screen changes like a video.")); m_form.tearingWarning->animatedShow(); } else if (index == 3) { // full screen repaints m_form.tearingWarning->setText(i18n("\"Full screen repaints\" can cause performance problems.")); m_form.tearingWarning->animatedShow(); } else if (index == 4) { // re-use screen content m_form.tearingWarning->setText(i18n("\"Re-use screen content\" causes severe performance problems on MESA drivers.")); m_form.tearingWarning->animatedShow(); } else { m_form.tearingWarning->animatedHide(); } } ); // windowThumbnail m_form.windowThumbnail->setCurrentIndex(m_compositing->windowThumbnail()); connect(m_compositing, &Compositing::windowThumbnailChanged, m_form.windowThumbnail, &QComboBox::setCurrentIndex); connect(m_form.windowThumbnail, currentIndexChangedSignal, m_compositing, &Compositing::setWindowThumbnail); connect(m_form.windowThumbnail, currentIndexChangedSignal, [this](int index) { if (index == 2) { m_form.windowThumbnailWarning->animatedShow(); } else { m_form.windowThumbnailWarning->animatedHide(); } } ); // windows blocking compositing m_form.windowsBlockCompositing->setChecked(m_compositing->windowsBlockCompositing()); connect(m_compositing, &Compositing::windowsBlockCompositingChanged, m_form.windowsBlockCompositing, &QCheckBox::setChecked); connect(m_form.windowsBlockCompositing, &QCheckBox::toggled, m_compositing, &Compositing::setWindowsBlockCompositing); // compositing type CompositingType *type = new CompositingType(this); m_form.type->setModel(type); auto updateCompositingType = [this, type]() { m_form.type->setCurrentIndex(type->indexForCompositingType(m_compositing->compositingType())); }; updateCompositingType(); connect(m_compositing, &Compositing::compositingTypeChanged, [updateCompositingType]() { updateCompositingType(); } ); auto showHideBasedOnType = [this, type]() { const int currentType = type->compositingTypeForIndex(m_form.type->currentIndex()); m_form.glScaleFilter->setVisible(currentType != CompositingType::XRENDER_INDEX); m_form.glScaleFilterLabel->setVisible(currentType != CompositingType::XRENDER_INDEX); m_form.xrScaleFilter->setVisible(currentType == CompositingType::XRENDER_INDEX); m_form.xrScaleFilterLabel->setVisible(currentType == CompositingType::XRENDER_INDEX); }; showHideBasedOnType(); connect(m_form.type, currentIndexChangedSignal, [this, type, showHideBasedOnType]() { m_compositing->setCompositingType(type->compositingTypeForIndex(m_form.type->currentIndex())); showHideBasedOnType(); } ); if (m_compositing->OpenGLIsUnsafe()) { m_form.glCrashedWarning->animatedShow(); } } void KWinCompositingSettings::load() { KCModule::load(); m_compositing->reset(); } void KWinCompositingSettings::defaults() { KCModule::defaults(); m_compositing->defaults(); } void KWinCompositingSettings::save() { KCModule::save(); m_compositing->save(); } -KWinCompositingKCM::KWinCompositingKCM(QWidget* parent, const QVariantList& args, KWin::Compositing::EffectView::ViewType viewType) - : KCModule(parent, args) - , m_view(new KWin::Compositing::EffectView(viewType)) -{ - QVBoxLayout *vl = new QVBoxLayout(this); - - vl->addWidget(m_view.data()); - setLayout(vl); - connect(m_view.data(), &KWin::Compositing::EffectView::changed, [this]{ - emit changed(true); - }); - m_view->setFocusPolicy(Qt::StrongFocus); -} - -KWinCompositingKCM::~KWinCompositingKCM() -{ -} - -void KWinCompositingKCM::save() -{ - m_view->save(); - KCModule::save(); -} - -void KWinCompositingKCM::load() -{ - m_view->load(); - KCModule::load(); -} - -void KWinCompositingKCM::defaults() -{ - m_view->defaults(); - KCModule::defaults(); -} - K_PLUGIN_FACTORY(KWinCompositingConfigFactory, - registerPlugin("effects"); registerPlugin("compositing"); ) #include "main.moc" diff --git a/kcmkwin/kwincompositing/model.cpp b/kcmkwin/kwincompositing/model.cpp deleted file mode 100644 index e4685188c..000000000 --- a/kcmkwin/kwincompositing/model.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/************************************************************************** -* 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 "effectmodel.h" -#include "compositing.h" -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace KWin { -namespace Compositing { - -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 -{ - return m_filter; -} - -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, EffectModel::Status(effectState)); -} - -void EffectFilterModel::syncConfig() -{ - m_effectModel->save(); -} - -void EffectFilterModel::load() -{ - m_effectModel->load(); -} - -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/model.h b/kcmkwin/kwincompositing/model.h deleted file mode 100644 index c0b4ad3d3..000000000 --- a/kcmkwin/kwincompositing/model.h +++ /dev/null @@ -1,121 +0,0 @@ -/************************************************************************** - * 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 . * - **************************************************************************/ - - -#ifndef MODEL_H -#define MODEL_H - -#include -#include -#include -#include -#include - -namespace KWin { - -class EffectModel; - -namespace Compositing { - -class EffectView : public QQuickWidget -{ - - Q_OBJECT - -public: - enum ViewType { - DesktopEffectsView, - CompositingSettingsView - }; - EffectView(ViewType type, QWidget *parent = 0); - - void save(); - void load(); - void defaults(); - -Q_SIGNALS: - void changed(); - -private Q_SLOTS: - void slotImplicitSizeChanged(); -private: - void init(ViewType type); -}; - - -class EffectFilterModel : public QSortFilterProxyModel -{ - Q_OBJECT - Q_PROPERTY(QString filter READ filter WRITE setFilter NOTIFY filterChanged) - /** - * If @c true not supported effects are excluded, if @c false no restriction on supported. - * Default value is @c true. - **/ - Q_PROPERTY(bool filterOutUnsupported MEMBER m_filterOutUnsupported NOTIFY filterOutUnsupportedChanged) - /** - * If @c true internal effects are excluded, if @c false no restriction on internal. - * Default value is @c true. - **/ - Q_PROPERTY(bool filterOutInternal MEMBER m_filterOutInternal NOTIFY filterOutInternalChanged) - Q_PROPERTY(QColor backgroundActiveColor READ backgroundActiveColor CONSTANT) - Q_PROPERTY(QColor backgroundNormalColor READ backgroundNormalColor CONSTANT) - Q_PROPERTY(QColor backgroundAlternateColor READ backgroundAlternateColor CONSTANT) - Q_PROPERTY(QColor sectionColor READ sectionColor CONSTANT) -public: - EffectFilterModel(QObject *parent = 0); - const QString &filter() const; - - Q_INVOKABLE void updateEffectStatus(int rowIndex, int effectState); - Q_INVOKABLE void syncConfig(); - Q_INVOKABLE void load(); - - QColor backgroundActiveColor() { return KColorScheme(QPalette::Active, KColorScheme::Selection, KSharedConfigPtr(0)).background(KColorScheme::LinkBackground).color(); }; - QColor backgroundNormalColor() { return KColorScheme(QPalette::Active, KColorScheme::View, KSharedConfigPtr(0)).background(KColorScheme::NormalBackground).color(); }; - QColor backgroundAlternateColor() { return KColorScheme(QPalette::Active, KColorScheme::View, KSharedConfigPtr(0)).background(KColorScheme::AlternateBackground).color(); }; - - QColor sectionColor() const { - QColor color = KColorScheme(QPalette::Active).foreground().color(); - color.setAlphaF(0.6); - return color; - } - - void defaults(); - -public Q_SLOTS: - void setFilter(const QString &filter); - -protected: - virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; - -Q_SIGNALS: - void effectModelChanged(); - void filterChanged(); - void filterOutUnsupportedChanged(); - void filterOutInternalChanged(); - -private: - EffectModel *m_effectModel; - QString m_filter; - bool m_filterOutUnsupported; - bool m_filterOutInternal; -}; -} -} -#endif diff --git a/kcmkwin/kwincompositing/qml/Effect.qml b/kcmkwin/kwincompositing/qml/Effect.qml deleted file mode 100644 index 84607d35d..000000000 --- a/kcmkwin/kwincompositing/qml/Effect.qml +++ /dev/null @@ -1,163 +0,0 @@ -/************************************************************************** -* 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 . * -**************************************************************************/ - - -import QtQuick 2.1 -import QtQuick.Controls 1.1 -import QtQuick.Controls 2.0 as QQC2 -import QtQuick.Layouts 1.0 -import org.kde.kwin.kwincompositing 1.0 - -Rectangle { - id: item - width: parent.width - height: rowEffect.implicitHeight - color: index % 2 ? effectView.backgroundNormalColor : effectView.backgroundAlternateColor - signal changed() - property int checkedState: model.EffectStatusRole - - RowLayout { - id: rowEffect - property int maximumWidth: parent.width - 2 * spacing - width: maximumWidth - Layout.maximumWidth: maximumWidth - x: spacing - - RowLayout { - id: checkBoxLayout - RadioButton { - id: exclusiveGroupButton - property bool exclusive: model.ExclusiveRole != "" - visible: exclusive - checked: model.EffectStatusRole - property bool actuallyChanged: true - property bool initiallyChecked: false - exclusiveGroup: exclusive ? effectView.exclusiveGroupForCategory(model.ExclusiveRole) : null - onCheckedChanged: { - if (!visible) { - return; - } - actuallyChanged = true; - item.checkedState = exclusiveGroupButton.checked ? Qt.Checked : Qt.Unchecked - item.changed(); - } - onClicked: { - if (!actuallyChanged || initiallyChecked) { - checked = false; - } - actuallyChanged = false; - initiallyChecked = false; - } - Component.onCompleted: { - exclusiveGroupButton.initiallyChecked = model.EffectStatusRole; - } - } - - CheckBox { - id: effectStatusCheckBox - checkedState: model.EffectStatusRole - visible: model.ExclusiveRole == "" - - onCheckedStateChanged: { - if (!visible) { - return; - } - item.checkedState = effectStatusCheckBox.checkedState; - item.changed(); - } - Connections { - target: searchModel - onDataChanged: { - effectStatusCheckBox.checkedState = model.EffectStatusRole; - } - } - } - } - - ColumnLayout { - id: effectItem - property int maximumWidth: parent.maximumWidth - checkBoxLayout.width - (videoButton.width + configureButton.width + aboutButton.width) - parent.spacing * 5 - Layout.maximumWidth: maximumWidth - QQC2.Label { - text: model.NameRole - font.weight: Font.Bold - wrapMode: Text.Wrap - Layout.maximumWidth: parent.maximumWidth - } - QQC2.Label { - id: desc - text: model.DescriptionRole - wrapMode: Text.Wrap - Layout.maximumWidth: parent.maximumWidth - } - QQC2.Label { - id:aboutItem - text: i18n("Author: %1\nLicense: %2", model.AuthorNameRole, model.LicenseRole) - font.weight: Font.Bold - visible: false - wrapMode: Text.Wrap - Layout.maximumWidth: parent.maximumWidth - } - Loader { - id: videoItem - active: false - visible: false - source: "Video.qml" - function showHide() { - if (!videoItem.active) { - videoItem.active = true; - videoItem.visible = true; - } else { - videoItem.active = false; - videoItem.visible = false; - } - } - } - } - Item { - // spacer - Layout.fillWidth: true - } - - Button { - id: videoButton - visible: model.VideoRole.toString() !== "" - iconName: "video" - onClicked: videoItem.showHide() - } - Button { - id: configureButton - visible: ConfigurableRole - enabled: item.checkedState != Qt.Unchecked - iconName: "configure" - onClicked: { - effectConfig.openConfig(model.ServiceNameRole, model.ScriptedRole, model.NameRole); - } - } - - Button { - id: aboutButton - iconName: "dialog-information" - onClicked: { - aboutItem.visible = !aboutItem.visible; - } - } - } //end Row -} //end Rectangle diff --git a/kcmkwin/kwincompositing/qml/EffectView.qml b/kcmkwin/kwincompositing/qml/EffectView.qml deleted file mode 100644 index 69384b0ff..000000000 --- a/kcmkwin/kwincompositing/qml/EffectView.qml +++ /dev/null @@ -1,179 +0,0 @@ -/************************************************************************** -* 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 . * -**************************************************************************/ - -import QtQuick 2.1 -import QtQuick.Controls 2.4 -import QtQuick.Layouts 1.0 -import org.kde.kwin.kwincompositing 1.0 - -Rectangle { - signal changed - implicitHeight: 500 - implicitWidth: 400 - - EffectConfig { - id: effectConfig - onEffectListChanged: { - searchModel.load() - } - } - - ColumnLayout { - id: col - anchors.fill: parent - - Label { - id: hint - Layout.fillWidth: true - Layout.alignment: Qt.AlignLeft - - text: i18n("Hint: To find out or configure how to activate an effect, look at the effect's settings.") - elide: Text.ElideRight - } - - RowLayout { - TextField { - // TODO: needs clear button, missing in Qt - id: searchField - placeholderText: i18n("Search...") - Layout.fillWidth: true - focus: true - } - - Button { - id: configureButton - icon.name: "configure" - ToolTip.visible: hovered - ToolTip.text: i18n("Configure filter") - onClicked: menu.opened ? menu.close() : menu.open() - } - Menu { - id: menu - y: configureButton.height - x: parent.width - width - MenuItem { - text: i18n("Exclude Desktop Effects not supported by the Compositor") - checkable: true - checked: searchModel.filterOutUnsupported - onToggled: { - searchModel.filterOutUnsupported = !searchModel.filterOutUnsupported; - } - } - MenuItem { - text: i18n("Exclude internal Desktop Effects") - checkable: true - checked: searchModel.filterOutInternal - onToggled: { - searchModel.filterOutInternal = !searchModel.filterOutInternal - } - } - } - } - - ScrollView { - Layout.fillWidth: true - Layout.fillHeight: true - clip: true - - // Draw a frame around the scrollview - Component.onCompleted: background.visible = true; - - ListView { - function exclusiveGroupForCategory(category) { - for (var i = 0; i < effectView.exclusiveGroups.length; ++i) { - var item = effectView.exclusiveGroups[i]; - if (item.category == category) { - return item.group; - } - } - var newGroup = Qt.createQmlObject('import QtQuick 2.1; import QtQuick.Controls 1.1; ExclusiveGroup {}', - effectView, - "dynamicExclusiveGroup" + effectView.exclusiveGroups.length); - effectView.exclusiveGroups[effectView.exclusiveGroups.length] = { - 'category': category, - 'group': newGroup - }; - return newGroup; - } - id: effectView - property var exclusiveGroups: [] - property color backgroundNormalColor: searchModel.backgroundNormalColor - property color backgroundAlternateColor: searchModel.backgroundAlternateColor - anchors.fill: parent - model: EffectFilterModel { - id: searchModel - objectName: "filterModel" - filter: searchField.text - } - delegate: Effect{ - id: effectDelegate - Connections { - id: effectStateConnection - target: null - onChanged: { - searchModel.updateEffectStatus(index, checkedState); - } - } - Component.onCompleted: { - effectStateConnection.target = effectDelegate - } - } - - section.property: "CategoryRole" - section.delegate: Rectangle { - width: parent.width - implicitHeight: sectionText.implicitHeight + 2 * col.spacing - color: searchModel.backgroundNormalColor - - Label { - id: sectionText - anchors.fill: parent - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - - text: section - font.weight: Font.Bold - color: searchModel.sectionColor - } - } - spacing: col.spacing - focus: true - } - } - - RowLayout { - Layout.fillWidth: true - - Item { - Layout.fillWidth: true - } - Button { - id: ghnsButton - text: i18n("Get New Desktop Effects...") - icon.name: "get-hot-new-stuff" - onClicked: effectConfig.openGHNS() - } - } - }//End ColumnLayout - Connections { - target: searchModel - onDataChanged: changed() - } -}//End Rectangle diff --git a/kcmkwin/kwincompositing/qml/main.qml b/kcmkwin/kwincompositing/qml/main.qml deleted file mode 100644 index b4ff1a395..000000000 --- a/kcmkwin/kwincompositing/qml/main.qml +++ /dev/null @@ -1,31 +0,0 @@ -/************************************************************************** -* 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 . * -**************************************************************************/ - -import QtQuick 2.1 -import QtQuick.Controls 1.0 -import QtQuick.Layouts 1.0 -import org.kde.kwin.kwincompositing 1.0 - -EffectView{ - id: view - onChanged: { - window.changed() - } -} diff --git a/kcmkwin/kwincompositing/test/effectmodeltest.cpp b/kcmkwin/kwincompositing/test/effectmodeltest.cpp deleted file mode 100644 index 1b56bac57..000000000 --- a/kcmkwin/kwincompositing/test/effectmodeltest.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/************************************************************************** -* 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 "modeltest.h" -#include "../model.h" -#include "effectmodeltest.h" - -#include "effectmodel.h" - -#include - -EffectModelTest::EffectModelTest(QObject *parent) - : QObject(parent) { - -} - -void EffectModelTest::testEffectModel() { - auto effectModel = new KWin::EffectModel(); - - new ModelTest(effectModel, this); -} - -void EffectModelTest::testEffectFilterModel() { - KWin::Compositing::EffectFilterModel *model = new KWin::Compositing::EffectFilterModel(); - - new ModelTest(model, this); -} - -QTEST_MAIN(EffectModelTest) diff --git a/kcmkwin/kwincompositing/test/effectmodeltest.h b/kcmkwin/kwincompositing/test/effectmodeltest.h deleted file mode 100644 index cb71a76df..000000000 --- a/kcmkwin/kwincompositing/test/effectmodeltest.h +++ /dev/null @@ -1,38 +0,0 @@ -/************************************************************************** - * 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 . * - **************************************************************************/ - - -#ifndef EFFECTMODELTEST_H -#define EFFECTMODELTEST_H - -#include - -class EffectModelTest : public QObject { - - Q_OBJECT - -public: - EffectModelTest(QObject *parent = 0); - -private Q_SLOTS: - void testEffectModel(); - void testEffectFilterModel(); -}; -#endif diff --git a/kcmkwin/kwincompositing/test/modeltest.cpp b/kcmkwin/kwincompositing/test/modeltest.cpp deleted file mode 100644 index ee92e9711..000000000 --- a/kcmkwin/kwincompositing/test/modeltest.cpp +++ /dev/null @@ -1,600 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include - -#include "modeltest.h" - -#include - -/*! - Connect to all of the models signals. Whenever anything happens recheck everything. -*/ -ModelTest::ModelTest ( QAbstractItemModel *_model, QObject *parent ) : QObject ( parent ), model ( _model ), fetchingMore ( false ) -{ - if (!model) - qFatal("%s: model must not be null", Q_FUNC_INFO); - - connect(model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)), - this, SLOT(runAllTests()) ); - connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)), - this, SLOT(runAllTests()) ); - connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)), - this, SLOT(runAllTests()) ); - connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)), - this, SLOT(runAllTests()) ); - connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), - this, SLOT(runAllTests()) ); - connect(model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), - this, SLOT(runAllTests()) ); - connect(model, SIGNAL(layoutAboutToBeChanged()), this, SLOT(runAllTests()) ); - connect(model, SIGNAL(layoutChanged()), this, SLOT(runAllTests()) ); - connect(model, SIGNAL(modelReset()), this, SLOT(runAllTests()) ); - connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), - this, SLOT(runAllTests()) ); - connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), - this, SLOT(runAllTests()) ); - connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), - this, SLOT(runAllTests()) ); - connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), - this, SLOT(runAllTests()) ); - - // Special checks for changes - connect(model, SIGNAL(layoutAboutToBeChanged()), - this, SLOT(layoutAboutToBeChanged()) ); - connect(model, SIGNAL(layoutChanged()), - this, SLOT(layoutChanged()) ); - - connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), - this, SLOT(rowsAboutToBeInserted(QModelIndex,int,int)) ); - connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), - this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)) ); - connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), - this, SLOT(rowsInserted(QModelIndex,int,int)) ); - connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), - this, SLOT(rowsRemoved(QModelIndex,int,int)) ); - connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), - this, SLOT(dataChanged(QModelIndex,QModelIndex)) ); - connect(model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), - this, SLOT(headerDataChanged(Qt::Orientation,int,int)) ); - - runAllTests(); -} - -void ModelTest::runAllTests() -{ - if ( fetchingMore ) - return; - nonDestructiveBasicTest(); - rowCount(); - columnCount(); - hasIndex(); - index(); - parent(); - data(); -} - -/*! - nonDestructiveBasicTest tries to call a number of the basic functions (not all) - to make sure the model doesn't outright segfault, testing the functions that makes sense. -*/ -void ModelTest::nonDestructiveBasicTest() -{ - QVERIFY( model->buddy ( QModelIndex() ) == QModelIndex() ); - model->canFetchMore ( QModelIndex() ); - QVERIFY( model->columnCount ( QModelIndex() ) >= 0 ); - QVERIFY( model->data ( QModelIndex() ) == QVariant() ); - fetchingMore = true; - model->fetchMore ( QModelIndex() ); - fetchingMore = false; - Qt::ItemFlags flags = model->flags ( QModelIndex() ); - QVERIFY( flags == Qt::ItemIsDropEnabled || flags == 0 ); - model->hasChildren ( QModelIndex() ); - model->hasIndex ( 0, 0 ); - model->headerData ( 0, Qt::Horizontal ); - model->index ( 0, 0 ); - model->itemData ( QModelIndex() ); - QVariant cache; - model->match ( QModelIndex(), -1, cache ); - model->mimeTypes(); - QVERIFY( model->parent ( QModelIndex() ) == QModelIndex() ); - QVERIFY( model->rowCount() >= 0 ); - QVariant variant; - model->setData ( QModelIndex(), variant, -1 ); - model->setHeaderData ( -1, Qt::Horizontal, QVariant() ); - model->setHeaderData ( 999999, Qt::Horizontal, QVariant() ); - QMap roles; - model->sibling ( 0, 0, QModelIndex() ); - model->span ( QModelIndex() ); - model->supportedDropActions(); -} - -/*! - Tests model's implementation of QAbstractItemModel::rowCount() and hasChildren() - - Models that are dynamically populated are not as fully tested here. - */ -void ModelTest::rowCount() -{ -// qDebug() << "rc"; - // check top row - QModelIndex topIndex = model->index ( 0, 0, QModelIndex() ); - int rows = model->rowCount ( topIndex ); - QVERIFY( rows >= 0 ); - if ( rows > 0 ) - QVERIFY( model->hasChildren ( topIndex ) ); - - QModelIndex secondLevelIndex = model->index ( 0, 0, topIndex ); - if ( secondLevelIndex.isValid() ) { // not the top level - // check a row count where parent is valid - rows = model->rowCount ( secondLevelIndex ); - QVERIFY( rows >= 0 ); - if ( rows > 0 ) - QVERIFY( model->hasChildren ( secondLevelIndex ) ); - } - - // The models rowCount() is tested more extensively in checkChildren(), - // but this catches the big mistakes -} - -/*! - Tests model's implementation of QAbstractItemModel::columnCount() and hasChildren() - */ -void ModelTest::columnCount() -{ - // check top row - QModelIndex topIndex = model->index ( 0, 0, QModelIndex() ); - QVERIFY( model->columnCount ( topIndex ) >= 0 ); - - // check a column count where parent is valid - QModelIndex childIndex = model->index ( 0, 0, topIndex ); - if ( childIndex.isValid() ) - QVERIFY( model->columnCount ( childIndex ) >= 0 ); - - // columnCount() is tested more extensively in checkChildren(), - // but this catches the big mistakes -} - -/*! - Tests model's implementation of QAbstractItemModel::hasIndex() - */ -void ModelTest::hasIndex() -{ -// qDebug() << "hi"; - // Make sure that invalid values returns an invalid index - QVERIFY( !model->hasIndex ( -2, -2 ) ); - QVERIFY( !model->hasIndex ( -2, 0 ) ); - QVERIFY( !model->hasIndex ( 0, -2 ) ); - - int rows = model->rowCount(); - int columns = model->columnCount(); - - // check out of bounds - QVERIFY( !model->hasIndex ( rows, columns ) ); - QVERIFY( !model->hasIndex ( rows + 1, columns + 1 ) ); - - if ( rows > 0 ) - QVERIFY( model->hasIndex ( 0, 0 ) ); - - // hasIndex() is tested more extensively in checkChildren(), - // but this catches the big mistakes -} - -/*! - Tests model's implementation of QAbstractItemModel::index() - */ -void ModelTest::index() -{ -// qDebug() << "i"; - // Make sure that invalid values returns an invalid index - QVERIFY( model->index ( -2, -2 ) == QModelIndex() ); - QVERIFY( model->index ( -2, 0 ) == QModelIndex() ); - QVERIFY( model->index ( 0, -2 ) == QModelIndex() ); - - int rows = model->rowCount(); - int columns = model->columnCount(); - - if ( rows == 0 ) - return; - - // Catch off by one errors - QVERIFY( model->index ( rows, columns ) == QModelIndex() ); - QVERIFY( model->index ( 0, 0 ).isValid() ); - - // Make sure that the same index is *always* returned - QModelIndex a = model->index ( 0, 0 ); - QModelIndex b = model->index ( 0, 0 ); - QVERIFY( a == b ); - - // index() is tested more extensively in checkChildren(), - // but this catches the big mistakes -} - -/*! - Tests model's implementation of QAbstractItemModel::parent() - */ -void ModelTest::parent() -{ -// qDebug() << "p"; - // Make sure the model won't crash and will return an invalid QModelIndex - // when asked for the parent of an invalid index. - QVERIFY( model->parent ( QModelIndex() ) == QModelIndex() ); - - if ( model->rowCount() == 0 ) - return; - - // Column 0 | Column 1 | - // QModelIndex() | | - // \- topIndex | topIndex1 | - // \- childIndex | childIndex1 | - - // Common error test #1, make sure that a top level index has a parent - // that is a invalid QModelIndex. - QModelIndex topIndex = model->index ( 0, 0, QModelIndex() ); - QVERIFY( model->parent ( topIndex ) == QModelIndex() ); - - // Common error test #2, make sure that a second level index has a parent - // that is the first level index. - if ( model->rowCount ( topIndex ) > 0 ) { - QModelIndex childIndex = model->index ( 0, 0, topIndex ); - QVERIFY( model->parent ( childIndex ) == topIndex ); - } - - // Common error test #3, the second column should NOT have the same children - // as the first column in a row. - // Usually the second column shouldn't have children. - QModelIndex topIndex1 = model->index ( 0, 1, QModelIndex() ); - if ( model->rowCount ( topIndex1 ) > 0 ) { - QModelIndex childIndex = model->index ( 0, 0, topIndex ); - QModelIndex childIndex1 = model->index ( 0, 0, topIndex1 ); - QVERIFY( childIndex != childIndex1 ); - } - - // Full test, walk n levels deep through the model making sure that all - // parent's children correctly specify their parent. - checkChildren ( QModelIndex() ); -} - -/*! - Called from the parent() test. - - A model that returns an index of parent X should also return X when asking - for the parent of the index. - - This recursive function does pretty extensive testing on the whole model in an - effort to catch edge cases. - - This function assumes that rowCount(), columnCount() and index() already work. - If they have a bug it will point it out, but the above tests should have already - found the basic bugs because it is easier to figure out the problem in - those tests then this one. - */ -void ModelTest::checkChildren ( const QModelIndex &parent, int currentDepth ) -{ - // First just try walking back up the tree. - QModelIndex p = parent; - while ( p.isValid() ) - p = p.parent(); - - // For models that are dynamically populated - if ( model->canFetchMore ( parent ) ) { - fetchingMore = true; - model->fetchMore ( parent ); - fetchingMore = false; - } - - int rows = model->rowCount ( parent ); - int columns = model->columnCount ( parent ); - - if ( rows > 0 ) - QVERIFY( model->hasChildren ( parent ) ); - - // Some further testing against rows(), columns(), and hasChildren() - QVERIFY( rows >= 0 ); - QVERIFY( columns >= 0 ); - if ( rows > 0 ) - QVERIFY( model->hasChildren ( parent ) ); - - //qDebug() << "parent:" << model->data(parent).toString() << "rows:" << rows - // << "columns:" << columns << "parent column:" << parent.column(); - - const QModelIndex topLeftChild = model->index( 0, 0, parent ); - - QVERIFY( !model->hasIndex ( rows + 1, 0, parent ) ); - for ( int r = 0; r < rows; ++r ) { - if ( model->canFetchMore ( parent ) ) { - fetchingMore = true; - model->fetchMore ( parent ); - fetchingMore = false; - } - QVERIFY( !model->hasIndex ( r, columns + 1, parent ) ); - for ( int c = 0; c < columns; ++c ) { - QVERIFY( model->hasIndex ( r, c, parent ) ); - QModelIndex index = model->index ( r, c, parent ); - // rowCount() and columnCount() said that it existed... - QVERIFY( index.isValid() ); - - // index() should always return the same index when called twice in a row - QModelIndex modifiedIndex = model->index ( r, c, parent ); - QVERIFY( index == modifiedIndex ); - - // Make sure we get the same index if we request it twice in a row - QModelIndex a = model->index ( r, c, parent ); - QModelIndex b = model->index ( r, c, parent ); - QVERIFY( a == b ); - - { - const QModelIndex sibling = model->sibling( r, c, topLeftChild ); - QVERIFY( index == sibling ); - } - { - const QModelIndex sibling = topLeftChild.sibling( r, c ); - QVERIFY( index == sibling ); - } - - // Some basic checking on the index that is returned - QVERIFY( index.model() == model ); - QCOMPARE( index.row(), r ); - QCOMPARE( index.column(), c ); - // While you can technically return a QVariant usually this is a sign - // of a bug in data(). Disable if this really is ok in your model. -// QVERIFY( model->data ( index, Qt::DisplayRole ).isValid() ); - - // If the next test fails here is some somewhat useful debug you play with. - - if (model->parent(index) != parent) { - qDebug() << r << c << currentDepth << model->data(index).toString() - << model->data(parent).toString(); - qDebug() << index << parent << model->parent(index); -// And a view that you can even use to show the model. -// QTreeView view; -// view.setModel(model); -// view.show(); - } - - // Check that we can get back our real parent. - QCOMPARE( model->parent ( index ), parent ); - - // recursively go down the children - if ( model->hasChildren ( index ) && currentDepth < 10 ) { - //qDebug() << r << c << "has children" << model->rowCount(index); - checkChildren ( index, ++currentDepth ); - }/* else { if (currentDepth >= 10) qDebug() << "checked 10 deep"; };*/ - - // make sure that after testing the children that the index doesn't change. - QModelIndex newerIndex = model->index ( r, c, parent ); - QVERIFY( index == newerIndex ); - } - } -} - -/*! - Tests model's implementation of QAbstractItemModel::data() - */ -void ModelTest::data() -{ - // Invalid index should return an invalid qvariant - QVERIFY( !model->data ( QModelIndex() ).isValid() ); - - if ( model->rowCount() == 0 ) - return; - - // A valid index should have a valid QVariant data - QVERIFY( model->index ( 0, 0 ).isValid() ); - - // shouldn't be able to set data on an invalid index - QVERIFY( !model->setData ( QModelIndex(), QLatin1String ( "foo" ), Qt::DisplayRole ) ); - - // General Purpose roles that should return a QString - QVariant variant = model->data ( model->index ( 0, 0 ), Qt::ToolTipRole ); - if ( variant.isValid() ) { - QVERIFY( variant.canConvert() ); - } - variant = model->data ( model->index ( 0, 0 ), Qt::StatusTipRole ); - if ( variant.isValid() ) { - QVERIFY( variant.canConvert() ); - } - variant = model->data ( model->index ( 0, 0 ), Qt::WhatsThisRole ); - if ( variant.isValid() ) { - QVERIFY( variant.canConvert() ); - } - - // General Purpose roles that should return a QSize - variant = model->data ( model->index ( 0, 0 ), Qt::SizeHintRole ); - if ( variant.isValid() ) { - QVERIFY( variant.canConvert() ); - } - - // General Purpose roles that should return a QFont - QVariant fontVariant = model->data ( model->index ( 0, 0 ), Qt::FontRole ); - if ( fontVariant.isValid() ) { - QVERIFY( fontVariant.canConvert() ); - } - - // Check that the alignment is one we know about - QVariant textAlignmentVariant = model->data ( model->index ( 0, 0 ), Qt::TextAlignmentRole ); - if ( textAlignmentVariant.isValid() ) { - unsigned int alignment = textAlignmentVariant.toUInt(); - QCOMPARE( alignment, ( alignment & ( Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask ) ) ); - } - - // General Purpose roles that should return a QColor - QVariant colorVariant = model->data ( model->index ( 0, 0 ), Qt::BackgroundRole ); - if ( colorVariant.isValid() ) { - QVERIFY( colorVariant.canConvert() ); - } - - colorVariant = model->data ( model->index ( 0, 0 ), Qt::ForegroundRole ); - if ( colorVariant.isValid() ) { - QVERIFY( colorVariant.canConvert() ); - } - - // Check that the "check state" is one we know about. - QVariant checkStateVariant = model->data ( model->index ( 0, 0 ), Qt::CheckStateRole ); - if ( checkStateVariant.isValid() ) { - int state = checkStateVariant.toInt(); - QVERIFY( state == Qt::Unchecked || - state == Qt::PartiallyChecked || - state == Qt::Checked ); - } -} - -/*! - Store what is about to be inserted to make sure it actually happens - - \sa rowsInserted() - */ -void ModelTest::rowsAboutToBeInserted ( const QModelIndex &parent, int start, int /* end */) -{ -// Q_UNUSED(end); -// qDebug() << "rowsAboutToBeInserted" << "start=" << start << "end=" << end << "parent=" << model->data ( parent ).toString() -// << "current count of parent=" << model->rowCount ( parent ); // << "display of last=" << model->data( model->index(start-1, 0, parent) ); -// qDebug() << model->index(start-1, 0, parent) << model->data( model->index(start-1, 0, parent) ); - Changing c; - c.parent = parent; - c.oldSize = model->rowCount ( parent ); - c.last = model->data ( model->index ( start - 1, 0, parent ) ); - c.next = model->data ( model->index ( start, 0, parent ) ); - insert.push ( c ); -} - -/*! - Confirm that what was said was going to happen actually did - - \sa rowsAboutToBeInserted() - */ -void ModelTest::rowsInserted ( const QModelIndex & parent, int start, int end ) -{ - Changing c = insert.pop(); - QVERIFY( c.parent == parent ); -// qDebug() << "rowsInserted" << "start=" << start << "end=" << end << "oldsize=" << c.oldSize -// << "parent=" << model->data ( parent ).toString() << "current rowcount of parent=" << model->rowCount ( parent ); - -// for (int ii=start; ii <= end; ii++) -// { -// qDebug() << "itemWasInserted:" << ii << model->data ( model->index ( ii, 0, parent )); -// } -// qDebug(); - - QVERIFY( c.oldSize + ( end - start + 1 ) == model->rowCount ( parent ) ); - QVERIFY( c.last == model->data ( model->index ( start - 1, 0, c.parent ) ) ); - - if (c.next != model->data(model->index(end + 1, 0, c.parent))) { - qDebug() << start << end; - for (int i=0; i < model->rowCount(); ++i) - qDebug() << model->index(i, 0).data().toString(); - qDebug() << c.next << model->data(model->index(end + 1, 0, c.parent)); - } - - QVERIFY( c.next == model->data ( model->index ( end + 1, 0, c.parent ) ) ); -} - -void ModelTest::layoutAboutToBeChanged() -{ - for ( int i = 0; i < qBound ( 0, model->rowCount(), 100 ); ++i ) - changing.append ( QPersistentModelIndex ( model->index ( i, 0 ) ) ); -} - -void ModelTest::layoutChanged() -{ - for ( int i = 0; i < changing.count(); ++i ) { - QPersistentModelIndex p = changing[i]; - QVERIFY( p == model->index ( p.row(), p.column(), p.parent() ) ); - } - changing.clear(); -} - -/*! - Store what is about to be inserted to make sure it actually happens - - \sa rowsRemoved() - */ -void ModelTest::rowsAboutToBeRemoved ( const QModelIndex &parent, int start, int end ) -{ -qDebug() << "ratbr" << parent << start << end; - Changing c; - c.parent = parent; - c.oldSize = model->rowCount ( parent ); - c.last = model->data ( model->index ( start - 1, 0, parent ) ); - c.next = model->data ( model->index ( end + 1, 0, parent ) ); - remove.push ( c ); -} - -/*! - Confirm that what was said was going to happen actually did - - \sa rowsAboutToBeRemoved() - */ -void ModelTest::rowsRemoved ( const QModelIndex & parent, int start, int end ) -{ - qDebug() << "rr" << parent << start << end; - Changing c = remove.pop(); - QVERIFY( c.parent == parent ); - QVERIFY( c.oldSize - ( end - start + 1 ) == model->rowCount ( parent ) ); - QVERIFY( c.last == model->data ( model->index ( start - 1, 0, c.parent ) ) ); - QVERIFY( c.next == model->data ( model->index ( start, 0, c.parent ) ) ); -} - -void ModelTest::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) -{ - QVERIFY(topLeft.isValid()); - QVERIFY(bottomRight.isValid()); - QModelIndex commonParent = bottomRight.parent(); - QVERIFY(topLeft.parent() == commonParent); - QVERIFY(topLeft.row() <= bottomRight.row()); - QVERIFY(topLeft.column() <= bottomRight.column()); - int rowCount = model->rowCount(commonParent); - int columnCount = model->columnCount(commonParent); - QVERIFY(bottomRight.row() < rowCount); - QVERIFY(bottomRight.column() < columnCount); -} - -void ModelTest::headerDataChanged(Qt::Orientation orientation, int start, int end) -{ - QVERIFY(start >= 0); - QVERIFY(end >= 0); - QVERIFY(start <= end); - int itemCount = orientation == Qt::Vertical ? model->rowCount() : model->columnCount(); - QVERIFY(start < itemCount); - QVERIFY(end < itemCount); -} - diff --git a/kcmkwin/kwincompositing/test/modeltest.h b/kcmkwin/kwincompositing/test/modeltest.h deleted file mode 100644 index 49d25d915..000000000 --- a/kcmkwin/kwincompositing/test/modeltest.h +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef MODELTEST_H -#define MODELTEST_H - -#include -#include -#include - -class ModelTest : public QObject -{ - Q_OBJECT - -public: - ModelTest( QAbstractItemModel *model, QObject *parent = 0 ); - -private Q_SLOTS: - void nonDestructiveBasicTest(); - void rowCount(); - void columnCount(); - void hasIndex(); - void index(); - void parent(); - void data(); - -protected Q_SLOTS: - void runAllTests(); - void layoutAboutToBeChanged(); - void layoutChanged(); - void rowsAboutToBeInserted( const QModelIndex &parent, int start, int end ); - void rowsInserted( const QModelIndex & parent, int start, int end ); - void rowsAboutToBeRemoved( const QModelIndex &parent, int start, int end ); - void rowsRemoved( const QModelIndex & parent, int start, int end ); - void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); - void headerDataChanged(Qt::Orientation orientation, int start, int end); - -private: - void checkChildren( const QModelIndex &parent, int currentDepth = 0 ); - - QAbstractItemModel *model; - - struct Changing { - QModelIndex parent; - int oldSize; - QVariant last; - QVariant next; - }; - QStack insert; - QStack remove; - - bool fetchingMore; - - QList changing; -}; - -#endif diff --git a/kcmkwin/kwineffects/CMakeLists.txt b/kcmkwin/kwineffects/CMakeLists.txt new file mode 100644 index 000000000..19c9ba229 --- /dev/null +++ b/kcmkwin/kwineffects/CMakeLists.txt @@ -0,0 +1,33 @@ +include(ECMQMLModules) +ecm_find_qmlmodule(org.kde.plasma.core 2.0) + +# KI18N Translation Domain for this library. +add_definitions(-DTRANSLATION_DOMAIN=\"kcm_kwin_effects\") + +########### next target ############### + +set(kcm_kwin_effects_PART_SRCS + kcm.cpp + effectsfilterproxymodel.cpp +) + +add_library(kcm_kwin_effects MODULE ${kcm_kwin_effects_PART_SRCS}) + +target_link_libraries(kcm_kwin_effects + Qt5::DBus + KF5::I18n + KF5::KCMUtils + KF5::NewStuff + KF5::QuickAddons + KF5::XmlGui + kcmkwincommon +) + +kcoreaddons_desktop_to_json(kcm_kwin_effects "kcm_kwin_effects.desktop") + +########### install files ############### + +install(TARGETS kcm_kwin_effects DESTINATION ${KDE_INSTALL_PLUGINDIR}/kcms) +install(FILES kcm_kwin_effects.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) +install(FILES kwineffect.knsrc DESTINATION ${CONFIG_INSTALL_DIR}) +kpackage_install_package(package kcm_kwin_effects kcms) diff --git a/kcmkwin/kwineffects/Messages.sh b/kcmkwin/kwineffects/Messages.sh new file mode 100644 index 000000000..6ff6bf8be --- /dev/null +++ b/kcmkwin/kwineffects/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT `find . -name \*.cpp -o -name \*.qml` -o $podir/kcm_kwin_effects.pot diff --git a/kcmkwin/kwineffects/effectsfilterproxymodel.cpp b/kcmkwin/kwineffects/effectsfilterproxymodel.cpp new file mode 100644 index 000000000..dfa7b98a1 --- /dev/null +++ b/kcmkwin/kwineffects/effectsfilterproxymodel.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2019 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 "effectsfilterproxymodel.h" + +#include "effectmodel.h" + +namespace KWin +{ + +EffectsFilterProxyModel::EffectsFilterProxyModel(QObject *parent) + : QSortFilterProxyModel(parent) +{ +} + +EffectsFilterProxyModel::~EffectsFilterProxyModel() +{ +} + +QString EffectsFilterProxyModel::query() const +{ + return m_query; +} + +void EffectsFilterProxyModel::setQuery(const QString &query) +{ + if (m_query != query) { + m_query = query; + emit queryChanged(); + invalidateFilter(); + } +} + +bool EffectsFilterProxyModel::excludeInternal() const +{ + return m_excludeInternal; +} + +void EffectsFilterProxyModel::setExcludeInternal(bool exclude) +{ + if (m_excludeInternal != exclude) { + m_excludeInternal = exclude; + emit excludeInternalChanged(); + invalidateFilter(); + } +} + +bool EffectsFilterProxyModel::excludeUnsupported() const +{ + return m_excludeUnsupported; +} + +void EffectsFilterProxyModel::setExcludeUnsupported(bool exclude) +{ + if (m_excludeUnsupported != exclude) { + m_excludeUnsupported = exclude; + emit excludeUnsupportedChanged(); + invalidateFilter(); + } +} + +bool EffectsFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + const QModelIndex idx = sourceModel()->index(sourceRow, 0, sourceParent); + + if (!m_query.isEmpty()) { + const bool matches = idx.data(EffectModel::NameRole).toString().contains(m_query, Qt::CaseInsensitive) || + idx.data(EffectModel::DescriptionRole).toString().contains(m_query, Qt::CaseInsensitive) || + idx.data(EffectModel::CategoryRole).toString().contains(m_query, Qt::CaseInsensitive); + if (!matches) { + return false; + } + } + + if (m_excludeInternal) { + if (idx.data(EffectModel::InternalRole).toBool()) { + return false; + } + } + + if (m_excludeUnsupported) { + if (!idx.data(EffectModel::SupportedRole).toBool()) { + return false; + } + } + + return true; +} + +} // namespace KWin diff --git a/kcmkwin/kwineffects/effectsfilterproxymodel.h b/kcmkwin/kwineffects/effectsfilterproxymodel.h new file mode 100644 index 000000000..841aba897 --- /dev/null +++ b/kcmkwin/kwineffects/effectsfilterproxymodel.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2019 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 + +namespace KWin +{ + +class EffectsFilterProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + Q_PROPERTY(QAbstractItemModel *sourceModel READ sourceModel WRITE setSourceModel) + Q_PROPERTY(QString query READ query WRITE setQuery NOTIFY queryChanged) + Q_PROPERTY(bool excludeInternal READ excludeInternal WRITE setExcludeInternal NOTIFY excludeInternalChanged) + Q_PROPERTY(bool excludeUnsupported READ excludeUnsupported WRITE setExcludeUnsupported NOTIFY excludeUnsupportedChanged) + +public: + explicit EffectsFilterProxyModel(QObject *parent = nullptr); + ~EffectsFilterProxyModel() override; + + QString query() const; + void setQuery(const QString &query); + + bool excludeInternal() const; + void setExcludeInternal(bool exclude); + + bool excludeUnsupported() const; + void setExcludeUnsupported(bool exclude); + +Q_SIGNALS: + void queryChanged(); + void excludeInternalChanged(); + void excludeUnsupportedChanged(); + +protected: + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; + +private: + QString m_query; + bool m_excludeInternal = true; + bool m_excludeUnsupported = true; + + Q_DISABLE_COPY(EffectsFilterProxyModel) +}; + +} // namespace KWin diff --git a/kcmkwin/kwineffects/kcm.cpp b/kcmkwin/kwineffects/kcm.cpp new file mode 100644 index 000000000..078a10481 --- /dev/null +++ b/kcmkwin/kwineffects/kcm.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2019 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 "kcm.h" +#include "effectmodel.h" +#include "effectsfilterproxymodel.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +K_PLUGIN_FACTORY_WITH_JSON(DesktopEffectsKCMFactory, + "kcm_kwin_effects.json", + registerPlugin();) + +namespace KWin +{ + +DesktopEffectsKCM::DesktopEffectsKCM(QObject *parent, const QVariantList &args) + : KQuickAddons::ConfigModule(parent, args) + , m_model(new EffectModel(this)) +{ + qmlRegisterType("org.kde.private.kcms.kwin.effects", 1, 0, "EffectsFilterProxyModel"); + + auto about = new KAboutData( + QStringLiteral("kcm_kwin_effects"), + i18n("Configure Desktop Effects"), + QStringLiteral("2.0"), + QString(), + KAboutLicense::GPL + ); + about->addAuthor(i18n("Vlad Zagorodniy"), QString(), QStringLiteral("vladzzag@gmail.com")); + setAboutData(about); + + setButtons(Apply | Default); + + connect(m_model, &EffectModel::dataChanged, this, &DesktopEffectsKCM::updateNeedsSave); +} + +DesktopEffectsKCM::~DesktopEffectsKCM() +{ +} + +QAbstractItemModel *DesktopEffectsKCM::effectsModel() const +{ + return m_model; +} + +void DesktopEffectsKCM::load() +{ + m_model->load(); + setNeedsSave(false); +} + +void DesktopEffectsKCM::save() +{ + m_model->save(); + setNeedsSave(false); +} + +void DesktopEffectsKCM::defaults() +{ + m_model->defaults(); + updateNeedsSave(); +} + +void DesktopEffectsKCM::openGHNS(QQuickItem *context) +{ + QPointer dialog = new KNS3::DownloadDialog(QStringLiteral("kwineffect.knsrc")); + dialog->setWindowTitle(i18n("Download New Desktop Effects")); + dialog->winId(); + + if (context && context->window()) { + dialog->windowHandle()->setTransientParent(context->window()); + } + + if (dialog->exec() == QDialog::Accepted) { + if (!dialog->changedEntries().isEmpty()) { + m_model->load(); + } + } + + delete dialog; +} + +static KCModule *findBinaryConfig(const QString &pluginId, QObject *parent) +{ + return KPluginTrader::createInstanceFromQuery( + QStringLiteral("kwin/effects/configs/"), + QString(), + QStringLiteral("'%1' in [X-KDE-ParentComponents]").arg(pluginId), + parent + ); +} + +static KCModule *findScriptedConfig(const QString &pluginId, QObject *parent) +{ + const auto offers = KPluginTrader::self()->query( + QStringLiteral("kwin/effects/configs/"), + QString(), + QStringLiteral("[X-KDE-Library] == 'kcm_kwin4_genericscripted'") + ); + + if (offers.isEmpty()) { + return nullptr; + } + + const KPluginInfo &generic = offers.first(); + KPluginLoader loader(generic.libraryPath()); + KPluginFactory *factory = loader.factory(); + if (!factory) { + return nullptr; + } + + return factory->create(pluginId, parent); +} + +void DesktopEffectsKCM::configure(const QString &pluginId, QQuickItem *context) +{ + const QModelIndex idx = m_model->findByPluginId(pluginId); + if (!idx.isValid()) { + return; + } + + QPointer dialog = new QDialog(); + + KCModule *module = idx.data(EffectModel::ScriptedRole).toBool() + ? findScriptedConfig(pluginId, dialog) + : findBinaryConfig(pluginId, dialog); + if (!module) { + delete dialog; + return; + } + + dialog->setWindowTitle(idx.data(EffectModel::NameRole).toString()); + dialog->winId(); + + auto buttons = new QDialogButtonBox( + QDialogButtonBox::Ok | + QDialogButtonBox::Cancel | + QDialogButtonBox::RestoreDefaults, + dialog + ); + connect(buttons, &QDialogButtonBox::accepted, dialog, &QDialog::accept); + connect(buttons, &QDialogButtonBox::rejected, dialog, &QDialog::reject); + connect(buttons->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, + module, &KCModule::defaults); + + auto layout = new QVBoxLayout(dialog); + layout->addWidget(module); + layout->addWidget(buttons); + + if (context && context->window()) { + dialog->windowHandle()->setTransientParent(context->window()); + } + + dialog->exec(); + + delete dialog; +} + +void DesktopEffectsKCM::updateNeedsSave() +{ + setNeedsSave(m_model->needsSave()); +} + +} // namespace KWin + +#include "kcm.moc" diff --git a/kcmkwin/kwineffects/kcm.h b/kcmkwin/kwineffects/kcm.h new file mode 100644 index 000000000..c8d8239d3 --- /dev/null +++ b/kcmkwin/kwineffects/kcm.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2019 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 + +namespace KWin +{ + +class EffectModel; + +class DesktopEffectsKCM : public KQuickAddons::ConfigModule +{ + Q_OBJECT + Q_PROPERTY(QAbstractItemModel *effectsModel READ effectsModel CONSTANT) + +public: + explicit DesktopEffectsKCM(QObject *parent = nullptr, const QVariantList &list = {}); + ~DesktopEffectsKCM() override; + + QAbstractItemModel *effectsModel() const; + +public Q_SLOTS: + void load() override; + void save() override; + void defaults() override; + + void openGHNS(QQuickItem *context); + void configure(const QString &pluginId, QQuickItem *context); + +private Q_SLOTS: + void updateNeedsSave(); + +private: + EffectModel *m_model; + + Q_DISABLE_COPY(DesktopEffectsKCM) +}; + +} // namespace KWin diff --git a/kcmkwin/kwincompositing/kcmkwineffects.desktop b/kcmkwin/kwineffects/kcm_kwin_effects.desktop similarity index 99% rename from kcmkwin/kwincompositing/kcmkwineffects.desktop rename to kcmkwin/kwineffects/kcm_kwin_effects.desktop index 3cc23fcd6..bfe9134d2 100644 --- a/kcmkwin/kwincompositing/kcmkwineffects.desktop +++ b/kcmkwin/kwineffects/kcm_kwin_effects.desktop @@ -1,130 +1,130 @@ [Desktop Entry] -Exec=kcmshell5 kwineffects +Exec=kcmshell5 kcm_kwin_effects Icon=preferences-desktop-effects Type=Service X-KDE-ServiceTypes=KCModule X-DocPath=kcontrol/kwineffects/index.html -X-KDE-Library=kwincompositing +X-KDE-Library=kcm_kwin_effects X-KDE-PluginKeyword=effects X-KDE-ParentApp=kcontrol X-KDE-System-Settings-Parent-Category=desktopbehavior X-KDE-Weight=50 Name=Desktop Effects Name[bs]=Efekti površi Name[ca]=Efectes d'escriptori Name[ca@valencia]=Efectes d'escriptori Name[cs]=Efekty na ploše Name[da]=Skrivebordseffekter Name[de]=Arbeitsflächen-Effekte Name[el]=Εφέ επιφάνειας εργασίας Name[en_GB]=Desktop Effects Name[es]=Efectos del escritorio Name[et]=Töölauaefektid Name[eu]=Mahaigaineko efektuak Name[fi]=Työpöytätehosteet Name[fr]=Effets de bureau Name[gl]=Efectos do escritorio Name[he]=הנפשות שולחן עבודה Name[hu]=Asztali effektusok Name[ia]=Effectos de scriptorio Name[id]=Efek Desktop Name[it]=Effetti del desktop Name[ja]=デスクトップ効果 Name[ko]=데스크톱 효과 Name[lt]=Darbalaukio efektai Name[nb]=Skrivebordseffekter Name[nds]=Schriefdischeffekten Name[nl]=Bureaubladeffecten Name[nn]=Skrivebords­effektar Name[pa]=ਡੈਸਕਟਾਪ ਪਰਭਾਵ Name[pl]=Efekty pulpitu Name[pt]=Efeitos do Ecrã Name[pt_BR]=Efeitos da área de trabalho Name[ro]=Efecte de birou Name[ru]=Эффекты Name[se]=Čállinbeavdeeffeavttat Name[sk]=Efekty plochy Name[sl]=Učinki namizja Name[sr]=Ефекти површи Name[sr@ijekavian]=Ефекти површи Name[sr@ijekavianlatin]=Efekti površi Name[sr@latin]=Efekti površi Name[sv]=Skrivbordseffekter Name[tr]=Masaüstü Efektleri Name[uk]=Ефекти стільниці Name[x-test]=xxDesktop Effectsxx Name[zh_CN]=桌面特效 Name[zh_TW]=桌面效果 Comment=Desktop Effects Comment[bs]=Efekti površi Comment[ca]=Efectes d'escriptori Comment[ca@valencia]=Efectes d'escriptori Comment[cs]=Efekty na ploše Comment[da]=Skrivebordseffekter Comment[de]=Arbeitsflächen-Effekte Comment[el]=Εφέ επιφάνειας εργασίας Comment[en_GB]=Desktop Effects Comment[es]=Efectos del escritorio Comment[et]=Töölauaefektid Comment[eu]=Mahaigaineko efektuak Comment[fi]=Työpöytätehosteet Comment[fr]=Effets de bureau Comment[gl]=Efectos do escritorio Comment[he]=הנפשות שולחן עבודה Comment[hu]=Asztali effektusok Comment[ia]=Effectos de scriptorio Comment[id]=Efek Desktop Comment[it]=Effetti del desktop Comment[ja]=デスクトップ効果 Comment[ko]=데스크톱 효과 Comment[lt]=Darbalaukio efektai Comment[nb]=Skrivebordseffekter Comment[nds]=Schriefdischeffekten Comment[nl]=Bureaubladeffecten Comment[nn]=Skrivebords­effektar Comment[pa]=ਡੈਸਕਟਾਪ ਪਰਭਾਵ Comment[pl]=Efekty pulpitu Comment[pt]=Efeitos do Ecrã Comment[pt_BR]=Efeitos da área de trabalho Comment[ro]=Efecte de birou Comment[ru]=Настройка эффектов рабочего стола Comment[sk]=Efekty plochy Comment[sl]=Učinki namizja Comment[sr]=Ефекти површи Comment[sr@ijekavian]=Ефекти површи Comment[sr@ijekavianlatin]=Efekti površi Comment[sr@latin]=Efekti površi Comment[sv]=Skrivbordseffekter Comment[tr]=Masaüstü Efektleri Comment[uk]=Ефекти стільниці Comment[x-test]=xxDesktop Effectsxx Comment[zh_CN]=桌面特效 Comment[zh_TW]=桌面效果 X-KDE-Keywords=kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window effect,login effect,logout effect,magic lamp effect,minimize animation effect,mouse mark effect,scale effect,screenshot effect,sheet effect,slide effect,sliding popups effect,thumbnail aside effect,translucency,translucency effect,transparency,window geometry effect,wobbly windows effect,startup feedback effect,dialog parent effect,dim inactive effect,dim screen effect,slide back effect,eye candy,candy,show FPS effect,show paint effect,cover switch effect,desktop cube effect,desktop cube animation effect,desktop grid effect,flip switch effect,present windows effect,resize window effect,background contrast effect X-KDE-Keywords[ca]=kwin,finestra,gestor,efecte,efectes 3D,efectes 2D,efectes gràfics,efectes d'escriptori,animacions,animacions diverses,efectes en la gestió de les finestres,efecte en el canvi de finestra,efecte en el canvi d'escriptori,animacions,animacions en l'escriptori,controladors,configuració dels controladors,renderització,render,efecte d'inversió,efecte d'aspecte de vidre,efecte de lupa,efecte ajudant del desplaçament,efecte de seguiment del ratolí,efecte de zoom,efecte de difuminat,efecte d'esvaïment,efecte d'esvaïment de l'escriptori,efecte de trencament,efecte de lliscament,efecte de ressaltat de la finestra,efecte en l'inici de la sessió,efecte en sortir de la sessió,efecte de làmpada màgica,efecte d'animació de la minimització,efecte de marca del ratolí,efecte d'apropament,efecte de captura de pantalla,efecte de full,efecte de diapositiva,efecte de missatges emergents lliscants,efecte de miniatures laterals,translucidesa,efecte de translucidesa,transparència,efecte de geometria de la finestra,efecte de finestres sacsejades,efecte de confirmació d'engegada,efecte de diàleg principal,efecte d'enfosquiment en estar inactiu,efecte d'enfosquiment de la pantalla,efecte de diapositiva prèvia,decoració,efecte per a mostrar els FPS,efecte de mostrar el pintat,efecte de canvi de coberta,efecte de cub de l'escriptori,efecte d'animació del cub de l'escriptori,efecte de quadrícula de l'escriptori,efecte de canvi en roda,efecte de presentació de les finestres,efecte de redimensionat de la finestra,efecte de contrast del fons X-KDE-Keywords[ca@valencia]=kwin,finestra,gestor,efecte,efectes 3D,efectes 2D,efectes gràfics,efectes d'escriptori,animacions,animacions diverses,efectes en la gestió de les finestres,efecte en el canvi de finestra,efecte en el canvi d'escriptori,animacions,animacions en l'escriptori,controladors,configuració dels controladors,renderització,render,efecte d'inversió,efecte d'aspecte de vidre,efecte de lupa,efecte ajudant del desplaçament,efecte de seguiment del ratolí,efecte de zoom,efecte de difuminat,efecte d'esvaïment,efecte d'esvaïment de l'escriptori,efecte de trencament,efecte de lliscament,efecte de ressaltat de la finestra,efecte en l'inici de la sessió,efecte en eixir de la sessió,efecte de làmpada màgica,efecte d'animació de la minimització,efecte de marca del ratolí,efecte d'apropament,efecte de captura de pantalla,efecte de full,efecte de diapositiva,efecte de missatges emergents lliscants,efecte de miniatures laterals,translucidesa,efecte de translucidesa,transparència,efecte de geometria de la finestra,efecte de finestres sacsejades,efecte de confirmació d'engegada,efecte de diàleg principal,efecte d'enfosquiment en estar inactiu,efecte d'enfosquiment de la pantalla,efecte de diapositiva prèvia,decoració,efecte per a mostrar els FPS,efecte de mostrar el pintat,efecte de canvi de coberta,efecte de cub de l'escriptori,efecte d'animació del cub de l'escriptori,efecte de quadrícula de l'escriptori,efecte de canvi en roda,efecte de presentació de les finestres,efecte de redimensionat de la finestra,efecte de contrast del fons X-KDE-Keywords[de]=KWin,Fenster,Verwaltung,Effekt,2D-Effekte,3D-Effekte,Grafische Effekte,Desktopeffekte,Arbeitsflächeneffekte,Animation,Fensterverwaltungs-Effekte,Fensterwechsel-Effekte,Desktop-Wechsel,Arbeitsflächenwechsel,Desktop-Animation,Arbeitsflächen-Animation,Treiber,Treibereinstellung,Rendering,Rendern,Invertierungseffekt,Bildschirmlupeneffekt,Vergrößerungseffekt,Einrasteffekt,Maus folgen,Zoomeffekt,Dashboard,Überblendungseffekt,Gleiteneffekt,Fensterhervorhebungs-Effekt,Anmeldungseffekt,Abmeldungseffekt,Animierter Minimierungseffekt,Mausmarkierungseffekt,Skalierungseffekt,Bildschirmeffekt,Blatteffekt,Folieneffekt,Vorschaueffekt,Durchsichtigkeit,Durchsichtigkeitseffekt,Fenstergeometrieffekt,Effekt Wabernde Fenster,Programmstartanzeigeneffekt,Inaktiveffekt,Bildschirmabdunkelungseffekt,FPS-Effekt,Zeichnungsbereicheffekt, 3D-Fenstergalerieeffekt,Desktopgittereffekt,3D-Fensterstapelumschalteffekt,Fensteranzeigeeffekt,Fenstergrößenänderungseffekt,Hintergrundkonstrasteffekt X-KDE-Keywords[en_GB]=kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window effect,login effect,logout effect,magic lamp effect,minimize animation effect,mouse mark effect,scale effect,screenshot effect,sheet effect,slide effect,sliding popups effect,thumbnail aside effect,translucency,translucency effect,transparency,window geometry effect,wobbly windows effect,startup feedback effect,dialog parent effect,dim inactive effect,dim screen effect,slide back effect,eye candy,candy,show FPS effect,show paint effect,cover switch effect,desktop cube effect,desktop cube animation effect,desktop grid effect,flip switch effect,present windows effect,resize window effect,background contrast effect X-KDE-Keywords[es]=kwin,ventana,gestor,efecto,efectos 3D,efectos 2D,efectos gráficos,efectos del escritorio,animaciones,animaciones diversas,efectos de la gestión de ventanas,efecto de cambio de ventana,efecto de cambio de escritorio,animaciones,animaciones del escritorio,controladores,preferencias del controlador,renderización,renderizar,efecto de inversión,efecto de espejo,efecto de lupa,efecto auxiliar de instantánea,efecto de seguimiento del ratón,efecto de ampliación,efecto borroso,efecto de desvanecimiento,efecto de desvanecimiento del escritorio,efecto de romper en pedazos,efecto de planeo,efecto de resaltar ventanas,efecto de inicio de sesión,efecto de final de sesión,efecto de lámpara mágica,efecto de animación al minimizar,efecto de marcas del ratón,efecto de escalado,efecto de captura de pantalla,efecto de hoja,efecto de deslizamiento,efecto de ventanas emergentes deslizantes,efecto de miniaturas laterales,transparencia,efecto de transparencia,efecto de geometría de las ventanas, efecto de ventanas gelatinosas,efecto de notificación de inicio,efecto de padre de la ventana,efecto de oscurecer inactiva,efecto de oscurecer la pantalla,efecto atrás,efectos atractivos,efecto de mostrar FPS,efecto de mostrar pintura,efecto de selección de ventana en modo carátula,efecto de cubo del escritorio,efecto de animación del cubo del escritorio,efecto de rejilla del escritorio,efecto de selección de ventana en modo cascada,efecto de presentación de ventanas,efecto de cambiar tamaño de las ventanas,efecto de contraste del fondo X-KDE-Keywords[eu]=kwin,leihoa,kudeatzailea,efektua,3D efektuak,2D efektuak,efektu grafikoak,mahaigaineko efektuak,animazioak,hainbat animazio,leiho kudeaketaren efektuak,leiho-aldatze efektuak,mahaigaina aldatzeko efektua,animazioak,mahaigaineko animazioak,gidariak,gidarien ezarpenak,errendatze,errendatu,alderantzikatu efektua,pantaila-lupa efektua,lupa efektua,atxikitze laguntzaile efektua,jarraitu saguari efektua,zoom efektua,lausotze efektua,desagertze efektua,mahaigain-desagertze efektua,puskatze efektua,irristatze efektua,leiho-nabarmentze efektua,saio-haste efektua,saio-ixte efektua,lanpara magiko efektua,minimizatze-animazio efektua, sagu-marka efektua,eskalatze efektua,pantaila-argazki efektua,orrialde efektua,diapositiba efektua,diapositiba gainerakor efektua,koadro txikiak alboan efektua,zeharrargitasuna,zeharrargitasun efektua,gardentasuna,leiho-geometria efektua,leiho dardartsuak efektua,abio berrelikadura efektua,guraso elkarrizketa-koadro efektua,itzaldu ez-aktiboa efektua,itzaldu pantaila efektua,diapositibak atzera efektua,ikusteko atsegina,atsegina,FPS erakuste efektua,erakutsi pintura efektua,azal aldaketa efektua,kubo-mahaigain efektua,kubo-mahaigain animazio efektua,mahaigain-sareta efektua,perspektiban pilatutako aldatze efektua,aurkeztu leihoak efektua,leihoaren neurri-aldatze efektua,atzealdeko kontraste efektua X-KDE-Keywords[fi]=kwin,ikkuna,hallinta,tehoste,3D-tehosteet,2D-tehosteet,graafiset tehosteet,työpöytätehosteet,animoinnit,eri animoinnit,ikkunanhallintatehosteet,ikkunanvaihtotehoste,työpöydänvaihtotehoste,animoinnit,työpöytäanimoinnit,ajurit,ajuriasetukset,hahmonnus,hahmonna,käänteistehoste,peilitehoste,suurennuslasitehoste,kiinnitysavustajatehoste,hiiren jäljitystehoste,suurennustehoste,sumennustehoste,häivytystehoste,työpöydän häivytystehoste,hajotustehoste,liukutehoste,ikkunan korostustehoste,kirjautumistehoste,uloskirjautumistehoste,taikalampputehoste,pienennyksen animointitehoste,hiiren jälki -tehoste,skaalaustehoste,ruudunkaappaustehoste,sheet effect,liukutehoste,liukuvat ponnahdusikkunat -tehoste,esikatselukuva reunalla -tehoste,läpikuultavuus,läpikuultavuustehoste,läpinäkyvyys,ikkunageometriatehoste,heiluvat ikkunat -tehoste,käynnistyspalautetehoste,kyselyikkunan isäntäikkuna -tehoste,himmennä passiivinen -tehoste,himmennä näyttö -tehoste,liuku taakse -tehoste,silmäkarkki,karkki,näytä FPS -tehoste,näytä näytönpiirto -tehoste,kansivaihtotehoste,työpöytäkuutiotehoste,työpöytäkuutioanimointitehoste,työpöytäruudukkotehoste,kääntövaihtotehoste,näytä ikkunat -tehoste,ikkunan koonmuuttamistehoste,taustakontrastitehoste X-KDE-Keywords[fr]=kwin, fenêtre, gestionnaire, effet, effets 3D, effets 2D, effets graphiques, effets de bureau, animations, animations variés, effets de gestion des fenêtres, effets de changement de fenêtre, effets de changement de bureau, animations, animation du bureau, pilotes, paramètres du pilote, rendu, rendre, effet d'inversion, effet de verre, effet de loupe, effet d'aide au positionnement, effet de repérage de la souris, effet de zoom, effet de flou, effet de fondu, effet de fondu du bureau, effet d'effondrement, effet de glissement, effet de mise en valeur de la fenêtre, effet de connexion, effet de déconnexion, effet de lampe magique, effet de minimisation de l'application, effet de marque de la souris, effet de gradation, effet de capture d'écran, effet de feuille, effet de glisse, effet d'annotations glissantes, effet vignettes sur le coté, translucidité, effet de translucidité, transparence, effet de géométrie de la fenêtre, effet de fenêtre en gélatine, effet du témoin de démarrage, effet de dialogue parent, effet d'obscurcissement de fenêtre inactive, effet d'obscurcissement du bureau, effet de glissement en arrière, confort visuel, beauté, effet d'affichage du FPS, effet d'affichage des zones peintes, effet de défilement circulaire, effet de bureaux en cube, effet d'animation de cube de bureaux, effet de bureaux en grille, effet d'empilement en perspective, effet de présentation des fenêtres, effet de redimensionnement des fenêtres, effet de contraste du bureau X-KDE-Keywords[gl]=kwin,window,xanela,manager,xestor,effect,efecto,3D effects,efectos 3D,2D effects,efectos 2D,configuración de vídeo,graphical effects,efectos gráficos,efectos visuais,desktop effects,efectos de escritorio,animations,animacións,various animations,animacións diversas,varias animacións,animacións variadas,window management effects,efectos de xestión de xanelas,window switching effect,efecto de cambio de xanela,desktop switching effect,efecto de cambio de escritorio,animations,animacións,desktop animations,animacións de escritorio,animacións dos escritorios,animacións do escritorio,drivers,controlador,controladores,driver settings,configuración dos controladores,configuración do controlador,rendering,renderización,renderizado,renderizamento,render,renderizar,invert effect,inverter un efecto,inverter efecto,reverter un efecto,reverter efecto,looking glass effect,efecto de lupa,efecto lupa,magnifier effect,snap helper effect,track mouse effect,efecto de seguir o rato,efecto de seguimento do rato,zoom effect,efecto de ampliación,blur effect,efecto borroso,fade effect,efecto de esvaer,fade desktop effect,efecto de esvaer o escritorio,fall apart effect,efecto de destrución,glide effect,efecto de brillo,highlight window effect,efecto de realzar a xanela,efecto de resaltar a xanela,efecto de salientar a xanela,efecto de salientar a xanela,login effect,efecto de acceder,logout effect,efecto de saír,magic lamp effect,efecto de lámpada máxica,minimize animation effect,efecto de minimizar,mouse mark effect,efecto de marca co rato,scale in effect,efecto de achegar,efecto de cambia de escala,screenshot effect,efecto de captura,sheet effect,efecto de folla,slide effect,efecto de dispositiva,sliding popups effect,thumbnail aside effect,translucency,transparencia,translucidez,translucency effect,efecto de translucidez,efecto de transparencia,transparency,transparencia,window geometry effect,efecto de xeometría da xanela,efecto de xeometría das xanelas,wobbly windows effect,efecto de xanelas a tremer,startup feedback effect,dialog parent effect,efecto do pai do diálogo,dim inactive effect,dim screen effect,efecto de escurecer,slide back effect,eye candy,candy,show FPS effect,efecto de mostrar os FPS,show paint effect,cover switch effect,desktop cube effect,efecto de cubo de escritorio,efecto do cubo de escritorio,efecto de cubo do escritorio,desktop cube animation effect,desktop grid effect,efecto de grade de escritorios,efecto de grade de escritorios,flip switch effect,efecto de interruptor,efecto de contorno,present windows effect,resize window effect,efecto de cambio de tamaño das xanelas,efecto de contraste de fondo X-KDE-Keywords[hu]=kwin,ablak,kezelő,hatás,3D hatás,2D hatás,grafikai hatások,asztali hatások,animációk,különféle animációk,ablakkezelő hatások,ablakváltó hatások,asztalváltó hatások,animációk,asztali animációk,meghajtók,meghajtó beállítások,leképezés,renderelés,fordított hatás,tükörhatás,nagyító hatás,elkapás segítő hatás,egérkövetés hatás,nagyítás hatás,elmosás,elhalványulás hatás,asztal elhalványulása hatás,széteső hatás,csúszás hatás,ablak kiemelése hatás,belépés hatás,kilépés hatás,varázslámpa hatás,minimalizálás animáció hatás,egérjelölés hatás,méretezés hatás,képernyőkép hatás,munkalap hatás,dia hatás,csúszó felugrók hatás,,bélyegképek félre hatás, áttetszőség,áttetszőség hatás,átlátszóság,ablak geometria hatás,ingó ablak hatás,indulási visszajelzés hatás,párbeszédablak szülő hatás,dim inaktív hatás,dim kijelző hatás,dia vissza hatás,látványelem,édesség,FPS megjelenítése hatás,festék megjelenése hatás,eltakarás váltás hatás,asztal kocka hatás,asztal kockaanimáció hatás,asztal rács hatás,tükrözésváltás hatás,jelenlegi ablakok hatás,ablak átméretezése hatás,háttérkontraszt hatás X-KDE-Keywords[id]=kwin,window,pengelola,efek,efek 3D,efek 2D,efek grafik,efek desktop,animasi,beragam animasi,efek pengelola window,efek beralih window,efek beralih desktop,animasi,animasi desktop,driver,setelan driver,rendering,render,efek kebalikan,efek seperti gelas,efek kaca pembesar,efek pembantu patah,efek lacak mouse,efek pembesaran,efek buram,efek lesap,efek desktop lesap,efek hancur,efek petak,efek window sorot,efek login,efek logout,efek lampu ajaib,efek animasi minimalkan,efek tanda mouse,efek skala,efek cuplikan layar,efek lembar,efek geser,efek sembul geser,efek thumbnail disamping,translusensi,efek translusensi,transparan,efek geometri window,efek window goyang,efek feedback pemulaian,efek induk dialog,efek layar suram,efek geser mundur,eye candy,candy,efek tampilkan FPS,efek tampilkan lukisan,efek alih kotak,efek alih sampul,efek kubus desktop,efek animasi kubus desktop,efek kisi desktop,efek alih lipat,efek window hadir,efek ubah ukuran window,efek kontras latarbelakang X-KDE-Keywords[it]=kwin,finestra,gestore,effetto,effetti 3D,effetti 2D,effetti grafici,effetti del desktop,animazioni,animazioni varie, effetti del gestore delle finestre,effetto dello scambiafinestre,effetto dello scambiatore di desktop,animazioni,animazioni del desktop,driver,impostazioni driver,rendering,render,effetto invertito,effetto vetro,effetto lente,effetto snap helper,effetto traccia mouse,effetto ingrandimento, effetto sfocatura,effetto dissolvenza,effetto dissolvenza desktop,effetto caduta,effetto planatura,effetto evidenziazione finestra,effetto schermata di accesso, effetto disconnessione,effetto lampada magica,effetto animazione di minimizzazione,effetto marcatura mouse, effetto scalatura,effetto schermata,effetto foglio,effetto diapositiva,effetto scivolamento,effetto miniature nella barra delle applicazioni,effetto miniatura su un lato,translucenza,effetto translucenza, trasparenza,effetto geometria finestra,effetto finestre tremolanti,effetto segnale di avvio,effetto finestra madre,effetto oscura finestra inattiva,effetto oscura schermo,effetto scivola all'indietro,gradevole,effetto gradevole,effetto mostra FPS,effetto ridisegno,effetto scambio cubi,effetto scambio copertina,effetto cubi del desktop,effetto animazione cubi del desktop,effetto griglia desktop,effetto scambiatore con inversione,effetto riquadro,effetto finestra presente,effetto ridimensionamento finestra,effetto contrasto dello sfondo X-KDE-Keywords[nl]=kwin,venster,beheerder,effect,3D effecten,2D effecten,grafische effecten,bureaubladeffecten,animaties,verrschillende animaties,vensterbeheereffecten,vensteromschakeleffect,bureaublad-omschakeleffect,animaties,bureaubladanimaties,stuurprogramma's,stuurprogramma-instellingen,rendering,render,inversieeffect,vergrootglaseffect,vergrotingseffect,snaphelpereffect,trackmuiseffect,zoomeffect,vervagingseffect,uitvaageffect,uitvaagbureaubladeffect,uiteenvaleffect,glijeffect,vensteraccentueringseffect,aanmeldeffect,afmeldeffect,magische lampeffect,animatie-effect minimaliseren,muismarkeringseffect,schaaleffect,schermafdrukeffect,bladeneffect,dia-effect,glijdende pop-upseffect,miniatuur-opzijeffect,doorzichtigheid,doorzichtigheidseffect,transparantie,vensterafmetingeneffect,wiebelende vensterseffect,opstartterugkoppeleffect,dialoogoudereffect,dim bij inactiviteitseffect,dim het schermeffect,schuif terugeffect,oogstrelend,snoepgoed,FPS toneneffect,verf toneneffect,vak deksel schakelaareffect,bureaublad kubuseffect,bureaublad kubus animatie-effect,bureaubladrastereffect,omschakeleffect,huidig venstereffect, wijzig grootte van venstereffect, achtergrondcontrasteffect X-KDE-Keywords[nn]=kwin,vindauge,handsamar,vindaugshandsamar,effekt,3D-effektar,2D-effektar,grafiske effektar,skrivebordeffektar,animasjonar,ymse animasjonar,vindaugsbyteeffektar,effektar ved skrivebordbyte,animasjonar,skrivebordsanimasjonar,drivarar,drivarinnstillingar,oppteikning,oppteiknar,inverteringseffekt,spegeleffekt,lupeeffekt,gripehjelpareffekt,musmerkeeffekt,forstørringseffekt,zoomeffekt,sløringseffekt,uklar-effekt,kontrollpulteffekt,uttoningseffekt,skrivebordtoningseffekt,gå-i-knas-effekt,glidareffekt,framhev vindauge-effekt,innloggingseffekt,utloggingsefffekt,magisk lampe-effekt,animasjonseffekt ved vindaugsminimering,musmerkeeffekt,skaleringseffekt,skjermdumpeffekt,ark-effekt,lysbileteffekt,glidande sprettopp-effekt,effekt for minibilete på sida,gjennomsiktseffekt,gjennomsikt,vindaugsgeometri-effekt,vaklande vindauge-effekt,effekt for oppstartsmelding,effekt for forelderdialog,effekt for mørk inaktiv,effekt for mørk skjerm,gli tilbake-effekt,augesnop,vis FPS-effekt,vis målingseffekt,omslagsbyteeffekt,skrivebordskube-effekt,effekt for animert skrivebordskube,effekt for skrivebordrutenett,effekt for flipp-byte,presenter vindauge-effekt,vindaugsskaleringseffekt,bakgrunnskontrast-effekt X-KDE-Keywords[pl]=kwin,okno,menadżer,efekt,efekty 3D,efekty 2D,efekty graficzne,efekty pulpitu,animacje,różne animacje,efekty zarządzania oknami,efekty przełączania okien,efekty przełączania pulpitów,animacje,animacje pulpitu,sterowniki,ustawienia sterowników,renderowania, efekt odwrócenia,szkło powiększające,efekt powiększenia,efekt pomocnika przyciągania, efekt śledzenia myszy,efekt przybliżenia,rozmycie,tablica,efekt eksplozji,efekt zanikania,efekt zanikania pulpitu,efekt rozpadania,efekt slajdu,efekt podświetlania okna, efekt logowania,efekt wylogowywania,efekt magicznej lampy,efekt animacji minimalizacji, efekt znacznika myszy,efekt skalowania,efekt zrzutu ekranu,efekt arkusza,efekt slajdu,efekt wysuwających się elementów wyskakujących,efekt prześwitywania,przezroczystość,efekt geometrii okna,efekt chwiejnych okien,efekt odczuć przy starcie,efekt okna rodzica,efekt przyciemniania nieaktywnych,efekt przyciemniania ekranu,efekt przesuwania do tył,efekt pokazania ilości klatek na sekundę X-KDE-Keywords[pt]=kwin,janela,gestor,composição,efeito,efeitos 3D,efeitos 2D,OpenGL,XRender,configuração do vídeo,efeitos gráficos,efeitos do ecrã,animações,animações diversas,efeitos de gestão das janelas,efeito de mudança de janelas,efeito de mudança de ecrãs,animações,velocidade da animação,animações do ecrã,controladores,configuração dos controladores,desenho,efeito de inversão,efeito de lupa,efeito de lente,efeito de ajuda no ajuste, efeito de seguimento do rato,efeito de ampliação,efeito de borrão,efeito de quadro,efeito de explosão,efeito de desvanecimento,efeito de desvanecimento do ecrã,efeito de destruição,efeito de deslizamento,efeito de realce da janela,efeito na autenticação,efeito do encerramento,efeito de lâmpada mágica,efeito de animação na minimização,efeito de marcação com rato,efeito de escala,efeito de captura do ecrã,efeito de folha,efeito de mensagens deslizantes,efeito de miniaturas na barra de tarefas,efeito de miniaturas laterais,efeito de janelas a tremer,efeito do arranque inicial,efeito da janela-mãe,efeito de escurecimento de janelas inactivas,efeito de deslize para trás,efeitos visuais,beleza,efeito de apresentação das IPS,efeito de pintura,efeito de mudança em caixa,efeito de mudança de capas, efeito de animação do cubo do ecrã,efeito de grelha do ecrã,efeito de mudança por viragem,efeito de destaque,efeito de apresentação das janelas,efeito de dimensionamento das janelas,efeito de contraste do fundo X-KDE-Keywords[pt_BR]=kwin,janela,gerenciador,efeito,efeitos 3D,efeitos 2D,efeitos gráficos,efeitos da área de trabalho,animações,animações diversas,efeitos do gerenciamento de janelas,efeito de mudança de janelas,efeito de mudança de área de trabalho,animações da área de trabalho,drivers,configuração dos drivers,desenho,renderização,efeito de inversão,efeito de lupa,efeito de lente,efeito de ajuda no ajuste,efeito de rastreamento do mouse,efeito de ampliação,efeito de borrão,efeito de escurecimento,efeito de escurecimento da área de trabalho,efeito de destruição,efeito de deslizamento,efeito de realce da janela,efeito na autenticação,efeito de encerramento de sessão,efeito de lâmpada mágica,efeito de animação na minimização,efeito de marcação com mouse,efeito em escala,efeito de captura de tela,efeito de folha,efeito de slide,efeito de mensagens deslizantes,efeito de miniaturas na barra de tarefas,transparência,efeito de transparência,efeito de geometria de janelas,efeito de janelas trêmulas,efeito do inicialização,efeito da janela-mãe,efeito de escurecimento de janelas inativas,efeito de deslize para trás,efeitos visuais,beleza,efeito de apresentação de FPS,efeito de pintura,efeito de mudança de capas,efeito de animação do cubo da área de trabalho,efeito de grade da área de trabalho,efeito de mudança em pilha,efeito de apresentação das janelas,efeito de dimensionamento das janelas,efeito de contraste de fundo X-KDE-Keywords[ru]=kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window effect,login effect,logout effect,magic lamp effect,minimize animation effect,mouse mark effect,scale effect,screenshot effect,sheet effect,slide effect,sliding popups effect,thumbnail aside effect,translucency,translucency effect,transparency,window geometry effect,wobbly windows effect,startup feedback effect,dialog parent effect,dim inactive effect,dim screen effect,slide back effect,eye candy,candy,show FPS effect,show paint effect,cover switch effect,desktop cube effect,desktop cube animation effect,desktop grid effect,flip switch effect,present windows effect,resize window effect,background contrast effect,эффекты рабочего стола,графические эффекты,рендеринг,параметры видео,настройка видео,трёхмерные эффекты,двумерные эффекты,эффекты управления окнами,эффекты диспетчера окон,анимация куба рабочих столов,плавная смена рабочих столов,прокрутка,анимация всплывающих окон,анимация появления окна,вход в систему,завершение сеанса,завершение работы,колышущиеся окна,болтающиеся окна,колыхание окон,край экрана,лист,анимация распахивания,анимация максимизации,максимизация окна,распахивание окна,миниатюры окон сбоку,миниатюры окон на краю экрана,полупрозрачность окон,размытие фона,размывание фона,распад закрывающихся окон,растворение закрывающихся окон,рисование на экране,рисование мышью на экране,скольжение окон,анимация сворачивания,сворачивание окон,волшебная лампа,график производительности,производительность эффектов,подсветка отрисовки,подсветка рендеринга,подсветка обновляемых частей экрана,анимация щелчка мышью,инверсия цветов,инвертирование цветов,поиск курсора мыши,разметка экрана,сетка на экране,линейки на экране,экранная разметка,экранная сетка,линза,искажение линзой,лупа,увеличение области экрана,масштаб рабочего стола,изменение масштаба рабочего стола,управление окнами,специальные возможности,инструменты,внешний вид,анимация переключения рабочих столов,все окна,просмотр всех окон,все рабочие столы,просмотр всех рабочих столов,изменение размера окна,масштабирование текстуры окна,куб с рабочими столами,перелистывание окон,управление фокусом,затемнение неактивных окон,затемнение основного окна,затемнение под диалогом,затемнение экрана при административной задаче,соскальзывание окон при смене фокуса,контрастность фона X-KDE-Keywords[sv]=kwin,fönster,hanterare,effekt,3D-effekter,grafiska effekter,skrivbordseffekter,animeringar,diverse animeringar,fönsterhanteringseffekter,fönsterbyteseffekt,skrivbordsbyteseffekt,skrivbordsanimeringar,drivrutiner,drivrutininställningar,återgivning,återge,inverteringseffekt,förstoringsglaseffekt,förstoringseffekt,låshjälpeffekt,musföljningseffekt,zoomeffekt,suddighetseffekt,explosionseffekt,borttoningseffekt,skrivbordsborttoningseffekt,sönderfallseffekt,glidningseffekt,fönstermarkeringseffekt,inloggningseffekt,utloggningseffekt,magisk lampeffekt,minimeringsanimeringseffekt,musmarkeringseffekt,inskalningseffekt,skärmbildseffekt,bladeffekt,skjuteffekt,glidande ruteffekt,miniatyrbilder i aktivitetsfältet,miniatyrbild vid sidan om,genomskinlighet,genomskinlighetseffekt,fönstergeometrieffekt,ostadiga fönstereffekt,startgensvarseffekt,dialogrutors ägareffekt,dämpa inaktiva effekt,dämpa skärmen effekt,glid tillbaka effekt,ögongodis,godis.visa ramar/s effekt, visa uppritningseffekt,byte med ruta effekt,skrivbordskubeffekt,animeringseffekt för skrivbordskub,skrivbordsrutnätseffekt,blädderbyteseffekt,befintliga fönstereffekt,ändra fönsterstorlekseffekt,bakgrundskontrasteffekt X-KDE-Keywords[uk]=kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window effect,login effect,logout effect,magic lamp effect,minimize animation effect,mouse mark effect,scale in effect,screenshot effect,sheet effect,slide effect,sliding popups effect,taskbar thumbnails effect,thumbnail aside effect,translucency,translucency effect,transparency,window geometry effect,wobbly windows effect,startup feedback effect,dialog parent effect,dim inactive effect,dim screen effect,slide back effect,eye candy,candy,show FPS effect,show paint effect,box switch effect,cover switch effect,desktop cube effect,desktop cube animation effect,desktop grid effect,flip switch effect,outline effect,present windows effect,resize window effect,вікно,керування вікнами,менеджер вікон,ефект,просторовий,плоский,параметри відео,графічні ефекти,анімації,анімація,перемикання вікон,драйвери,параметри драйверів,показ,відтворення,інвертування,інверсія,збільшувальне скло,збільшення,прилипання,шлейф за вказівником,шлейф,масштабування,масштаб,зміна розмірів,розмивання,панель,згасання,поява,ковзання,підсвічування,підсвічування вікон,вихід,магічна лампа,чарівна лампа,джин,аркуші,стос,знімок екрана,мініатюри панелі задач,мініатюри,прозорість,ефект прозорості,желе,желейні вікна,супровід запуску,стрибунець,притлумлення,сірість,прикраси,показ частоти,малювання,обкладинки,стрибання,контур,поточні вікна,зміна розмірів X-KDE-Keywords[x-test]=xxkwinxx,xxwindowxx,xxmanagerxx,xxeffectxx,xx3D effectsxx,xx2D effectsxx,xxgraphical effectsxx,xxdesktop effectsxx,xxanimationsxx,xxvarious animationsxx,xxwindow management effectsxx,xxwindow switching effectxx,xxdesktop switching effectxx,xxanimationsxx,xxdesktop animationsxx,xxdriversxx,xxdriver settingsxx,xxrenderingxx,xxrenderxx,xxinvert effectxx,xxlooking glass effectxx,xxmagnifier effectxx,xxsnap helper effectxx,xxtrack mouse effectxx,xxzoom effectxx,xxblur effectxx,xxfade effectxx,xxfade desktop effectxx,xxfall apart effectxx,xxglide effectxx,xxhighlight window effectxx,xxlogin effectxx,xxlogout effectxx,xxmagic lamp effectxx,xxminimize animation effectxx,xxmouse mark effectxx,xxscale effectxx,xxscreenshot effectxx,xxsheet effectxx,xxslide effectxx,xxsliding popups effectxx,xxthumbnail aside effectxx,xxtranslucencyxx,xxtranslucency effectxx,xxtransparencyxx,xxwindow geometry effectxx,xxwobbly windows effectxx,xxstartup feedback effectxx,xxdialog parent effectxx,xxdim inactive effectxx,xxdim screen effectxx,xxslide back effectxx,xxeye candyxx,xxcandyxx,xxshow FPS effectxx,xxshow paint effectxx,xxcover switch effectxx,xxdesktop cube effectxx,xxdesktop cube animation effectxx,xxdesktop grid effectxx,xxflip switch effectxx,xxpresent windows effectxx,xxresize window effectxx,xxbackground contrast effectxx X-KDE-Keywords[zh_CN]=kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,explosion effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window effect,login effect,logout effect,magic lamp effect,minimize animation effect,mouse mark effect,scale effect,screenshot effect,sheet effect,slide effect,sliding popups effect,thumbnail aside effect,translucency,translucency effect,transparency,window geometry effect,wobbly windows effect,startup feedback effect,dialog parent effect,dim inactive effect,dim screen effect,slide back effect,eye candy,candy,show FPS effect,show paint effect,cover switch effect,desktop cube effect,desktop cube animation effect,desktop grid effect,flip switch effect,present windows effect,resize window effect,background contrast effect,窗口,管理,特效,3D 特效,2D 特效,图形特效,桌面特效,动画,窗口管理特效,窗口切换特效,桌面切换特效,桌面动画,驱动,去掉设置,渲染,反色,放大镜特效,鼠标跟踪,缩放特效,模糊特效,渐变特效,破碎特效,滑动特效,高亮窗口,登录特效,注销特效,神灯特效,最小化动画,鼠标标记,截屏,飘落,滑动弹出窗口,缩略图置边,透明特效,摇摆窗口,启动反馈特效,黯淡对话框特效,黯淡屏幕特效,视觉效果,显示 FPS 特效,显示绘制区域特效,封面切换特效,桌面立方体特效,桌面立方体动画特效,翻转切换特效,展示窗口特效,调整窗口大小特效,背景对比特效 X-KDE-Keywords[zh_TW]=kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window effect,login effect,logout effect,magic lamp effect,minimize animation effect,mouse mark effect,scale effect,screenshot effect,sheet effect,slide effect,sliding popups effect,thumbnail aside effect,translucency,translucency effect,transparency,window geometry effect,wobbly windows effect,startup feedback effect,dialog parent effect,dim inactive effect,dim screen effect,slide back effect,eye candy,candy,show FPS effect,show paint effect,cover switch effect,desktop cube effect,desktop cube animation effect,desktop grid effect,flip switch effect,present windows effect,resize window effect,background contrast effect diff --git a/kcmkwin/kwincompositing/kwineffect.knsrc b/kcmkwin/kwineffects/kwineffect.knsrc similarity index 100% rename from kcmkwin/kwincompositing/kwineffect.knsrc rename to kcmkwin/kwineffects/kwineffect.knsrc diff --git a/kcmkwin/kwineffects/package/contents/ui/Effect.qml b/kcmkwin/kwineffects/package/contents/ui/Effect.qml new file mode 100644 index 000000000..8272ace2d --- /dev/null +++ b/kcmkwin/kwineffects/package/contents/ui/Effect.qml @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2013 Antonis Tsiapaliokas + * Copyright (C) 2019 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 . + * + */ + +import QtQuick 2.1 +import QtQuick.Controls 2.5 as QtControls +import QtQuick.Layouts 1.0 +import org.kde.kirigami 2.5 as Kirigami + +Rectangle { + height: row.implicitHeight + + Kirigami.Theme.inherit: false + Kirigami.Theme.colorSet: Kirigami.Theme.View + color: index % 2 ? Kirigami.Theme.backgroundColor : palette.alternateBase + + RowLayout { + id: row + + x: spacing + width: parent.width - 2 * spacing + + QtControls.RadioButton { + property bool _exclusive: model.ExclusiveRole != "" + property bool _toggled: false + + checked: model.EffectStatusRole + visible: _exclusive + QtControls.ButtonGroup.group: _exclusive ? effectsList.findButtonGroup(model.ExclusiveRole) : null + + onToggled: { + model.EffectStatusRole = checked ? Qt.Checked : Qt.Unchecked; + _toggled = true; + } + onClicked: { + // Uncheck the radio button if it's clicked. + if (checked && !_toggled) { + model.EffectStatusRole = Qt.Unchecked; + } + _toggled = false; + } + } + + QtControls.CheckBox { + checkState: model.EffectStatusRole + visible: model.ExclusiveRole == "" + + onToggled: model.EffectStatusRole = checkState + } + + ColumnLayout { + QtControls.Label { + Layout.fillWidth: true + + font.weight: Font.Bold + text: model.NameRole + wrapMode: Text.Wrap + } + + QtControls.Label { + Layout.fillWidth: true + + text: model.DescriptionRole + wrapMode: Text.Wrap + } + + QtControls.Label { + id: aboutItem + + Layout.fillWidth: true + + font.weight: Font.Bold + text: i18n("Author: %1\nLicense: %2", model.AuthorNameRole, model.LicenseRole) + visible: false + wrapMode: Text.Wrap + } + + Loader { + id: videoItem + + active: false + source: "Video.qml" + visible: false + + function showHide() { + if (!videoItem.active) { + videoItem.active = true; + videoItem.visible = true; + } else { + videoItem.active = false; + videoItem.visible = false; + } + } + } + } + + QtControls.Button { + icon.name: "video" + visible: model.VideoRole.toString() !== "" + + onClicked: videoItem.showHide() + } + + QtControls.Button { + enabled: model.EffectStatusRole != Qt.Unchecked + icon.name: "configure" + visible: model.ConfigurableRole + + onClicked: kcm.configure(model.ServiceNameRole, this) + } + + QtControls.Button { + icon.name: "dialog-information" + + onClicked: aboutItem.visible = !aboutItem.visible; + } + } + + // Kirigami.Theme doesn't provide alternate color. + SystemPalette { + id: palette + + colorGroup: SystemPalette.Active + } +} diff --git a/kcmkwin/kwincompositing/qml/Video.qml b/kcmkwin/kwineffects/package/contents/ui/Video.qml similarity index 100% rename from kcmkwin/kwincompositing/qml/Video.qml rename to kcmkwin/kwineffects/package/contents/ui/Video.qml diff --git a/kcmkwin/kwineffects/package/contents/ui/main.qml b/kcmkwin/kwineffects/package/contents/ui/main.qml new file mode 100644 index 000000000..d0ce35a70 --- /dev/null +++ b/kcmkwin/kwineffects/package/contents/ui/main.qml @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2013 Antonis Tsiapaliokas + * Copyright (C) 2019 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 . + */ + +import QtQuick 2.1 +import QtQuick.Controls 2.5 as QtControls +import QtQuick.Layouts 1.1 +import org.kde.kcm 1.2 +import org.kde.kconfig 1.0 +import org.kde.kirigami 2.5 as Kirigami +import org.kde.private.kcms.kwin.effects 1.0 as Private + +ScrollViewKCM { + ConfigModule.quickHelp: i18n("This module lets you configure desktop effects.") + + header: ColumnLayout { + QtControls.Label { + Layout.fillWidth: true + + elide: Text.ElideRight + text: i18n("Hint: To find out or configure how to activate an effect, look at the effect's settings.") + } + + RowLayout { + QtControls.TextField { + id: searchField + + Layout.fillWidth: true + + // TODO: Needs clear button, missing in Qt. + placeholderText: i18n("Search...") + } + + QtControls.Button { + id: configureButton + + QtControls.ToolTip.visible: hovered + QtControls.ToolTip.text: i18n("Configure filter") + + icon.name: "configure" + + onClicked: menu.opened ? menu.close() : menu.open() + } + + QtControls.Menu { + id: menu + + x: parent.width - width + y: configureButton.height + + QtControls.MenuItem { + checkable: true + checked: searchModel.excludeUnsupported + text: i18n("Exclude Desktop Effects not supported by the Compositor") + + onToggled: searchModel.excludeUnsupported = checked + } + + QtControls.MenuItem { + checkable: true + checked: searchModel.excludeInternal + text: i18n("Exclude internal Desktop Effects") + + onToggled: searchModel.excludeInternal = checked + } + } + } + } + + view: ListView { + id: effectsList + + property var _buttonGroups: [] + + spacing: Kirigami.Units.smallSpacing + + model: Private.EffectsFilterProxyModel { + id: searchModel + + query: searchField.text + sourceModel: kcm.effectsModel + } + + delegate: Effect { + width: effectsList.width + } + + section.property: "CategoryRole" + section.delegate: Item { + width: effectsList.width + height: sectionText.implicitHeight + 2 * Kirigami.Units.smallSpacing + + QtControls.Label { + id: sectionText + + anchors.fill: parent + + color: Kirigami.Theme.disabledTextColor + font.weight: Font.Bold + horizontalAlignment: Text.AlignHCenter + text: section + verticalAlignment: Text.AlignVCenter + } + } + + function findButtonGroup(name) { + for (let item of effectsList._buttonGroups) { + if (item.name == name) { + return item.group; + } + } + + let group = Qt.createQmlObject( + 'import QtQuick 2.1;' + + 'import QtQuick.Controls 2.5;' + + 'ButtonGroup {}', + effectsList, + "dynamicButtonGroup" + effectsList._buttonGroups.length + ); + + effectsList._buttonGroups.push({ name, group }); + + return group; + } + } + + footer: ColumnLayout { + RowLayout { + Layout.alignment: Qt.AlignRight + + QtControls.Button { + icon.name: "get-hot-new-stuff" + text: i18n("Get New Desktop Effects...") + visible: KAuthorized.authorize("ghns") + + onClicked: kcm.openGHNS(this) + } + } + } +} diff --git a/kcmkwin/kwineffects/package/metadata.desktop b/kcmkwin/kwineffects/package/metadata.desktop new file mode 100644 index 000000000..5c961e278 --- /dev/null +++ b/kcmkwin/kwineffects/package/metadata.desktop @@ -0,0 +1,102 @@ +[Desktop Entry] +Name=Desktop Effects +Name[bs]=Efekti površi +Name[ca]=Efectes d'escriptori +Name[ca@valencia]=Efectes d'escriptori +Name[cs]=Efekty na ploše +Name[da]=Skrivebordseffekter +Name[de]=Arbeitsflächen-Effekte +Name[el]=Εφέ επιφάνειας εργασίας +Name[en_GB]=Desktop Effects +Name[es]=Efectos del escritorio +Name[et]=Töölauaefektid +Name[eu]=Mahaigaineko efektuak +Name[fi]=Työpöytätehosteet +Name[fr]=Effets de bureau +Name[gl]=Efectos do escritorio +Name[he]=הנפשות שולחן עבודה +Name[hu]=Asztali effektusok +Name[ia]=Effectos de scriptorio +Name[id]=Efek Desktop +Name[it]=Effetti del desktop +Name[ja]=デスクトップ効果 +Name[ko]=데스크톱 효과 +Name[lt]=Darbalaukio efektai +Name[nb]=Skrivebordseffekter +Name[nds]=Schriefdischeffekten +Name[nl]=Bureaubladeffecten +Name[nn]=Skrivebords­effektar +Name[pa]=ਡੈਸਕਟਾਪ ਪਰਭਾਵ +Name[pl]=Efekty pulpitu +Name[pt]=Efeitos do Ecrã +Name[pt_BR]=Efeitos da área de trabalho +Name[ro]=Efecte de birou +Name[ru]=Эффекты +Name[se]=Čállinbeavdeeffeavttat +Name[sk]=Efekty plochy +Name[sl]=Učinki namizja +Name[sr]=Ефекти површи +Name[sr@ijekavian]=Ефекти површи +Name[sr@ijekavianlatin]=Efekti površi +Name[sr@latin]=Efekti površi +Name[sv]=Skrivbordseffekter +Name[tr]=Masaüstü Efektleri +Name[uk]=Ефекти стільниці +Name[x-test]=xxDesktop Effectsxx +Name[zh_CN]=桌面特效 +Name[zh_TW]=桌面效果 + +Comment=Desktop Effects +Comment[bs]=Efekti površi +Comment[ca]=Efectes d'escriptori +Comment[ca@valencia]=Efectes d'escriptori +Comment[cs]=Efekty na ploše +Comment[da]=Skrivebordseffekter +Comment[de]=Arbeitsflächen-Effekte +Comment[el]=Εφέ επιφάνειας εργασίας +Comment[en_GB]=Desktop Effects +Comment[es]=Efectos del escritorio +Comment[et]=Töölauaefektid +Comment[eu]=Mahaigaineko efektuak +Comment[fi]=Työpöytätehosteet +Comment[fr]=Effets de bureau +Comment[gl]=Efectos do escritorio +Comment[he]=הנפשות שולחן עבודה +Comment[hu]=Asztali effektusok +Comment[ia]=Effectos de scriptorio +Comment[id]=Efek Desktop +Comment[it]=Effetti del desktop +Comment[ja]=デスクトップ効果 +Comment[ko]=데스크톱 효과 +Comment[lt]=Darbalaukio efektai +Comment[nb]=Skrivebordseffekter +Comment[nds]=Schriefdischeffekten +Comment[nl]=Bureaubladeffecten +Comment[nn]=Skrivebords­effektar +Comment[pa]=ਡੈਸਕਟਾਪ ਪਰਭਾਵ +Comment[pl]=Efekty pulpitu +Comment[pt]=Efeitos do Ecrã +Comment[pt_BR]=Efeitos da Área de Trabalho +Comment[ro]=Efecte de birou +Comment[ru]=Настройка эффектов рабочего стола +Comment[sk]=Efekty plochy +Comment[sl]=Učinki namizja +Comment[sr]=Ефекти површи +Comment[sr@ijekavian]=Ефекти површи +Comment[sr@ijekavianlatin]=Efekti površi +Comment[sr@latin]=Efekti površi +Comment[sv]=Skrivbordseffekter +Comment[tr]=Masaüstü Efektleri +Comment[uk]=Ефекти стільниці +Comment[x-test]=xxDesktop Effectsxx +Comment[zh_CN]=桌面特效 +Comment[zh_TW]=桌面效果 + +Icon=preferences-desktop-effects +Type=Service +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-Name=kcm_kwin_effects +X-KDE-ServiceTypes=Plasma/Generic +X-Plasma-API=declarativeappletscript + +X-Plasma-MainScript=ui/main.qml