diff --git a/kcmkwin/kwindesktop/CMakeLists.txt b/kcmkwin/kwindesktop/CMakeLists.txt --- a/kcmkwin/kwindesktop/CMakeLists.txt +++ b/kcmkwin/kwindesktop/CMakeLists.txt @@ -8,13 +8,19 @@ set(kcm_kwin_virtualdesktops_PART_SRCS virtualdesktops.cpp desktopsmodel.cpp ../../virtualdesktopsdbustypes.cpp) +qt5_add_dbus_interface(kcm_kwin_virtualdesktops_PART_SRCS + ${KWIN_SOURCE_DIR}/org.kde.kwin.Effects.xml kwin_effects_interface) + add_library(kcm_kwin_virtualdesktops MODULE ${kcm_kwin_virtualdesktops_PART_SRCS}) target_link_libraries(kcm_kwin_virtualdesktops Qt5::DBus KF5::I18n KF5::KCMUtils + KF5::Package KF5::QuickAddons + KF5::XmlGui + kwin4_effect_builtins ) kcoreaddons_desktop_to_json(kcm_kwin_virtualdesktops "kcm_kwin_virtualdesktops.desktop") diff --git a/kcmkwin/kwindesktop/package/contents/ui/main.qml b/kcmkwin/kwindesktop/package/contents/ui/main.qml --- a/kcmkwin/kwindesktop/package/contents/ui/main.qml +++ b/kcmkwin/kwindesktop/package/contents/ui/main.qml @@ -18,6 +18,7 @@ */ import QtQuick 2.1 +import QtQuick.Window 2.1 import QtQuick.Layouts 1.1 import QtQuick.Controls 2.4 as QtControls import org.kde.kirigami 2.5 as Kirigami @@ -181,13 +182,52 @@ Connections { target: kcm + onSwitchingEffectChanged: switchingEffect.currentIndex = kcm.switchingEffect + onNavWrapsChanged: navWraps.checked = kcm.navWraps onOsdEnabledChanged: osdEnabled.checked = kcm.osdEnabled onOsdDurationChanged: osdDuration.value = kcm.osdDuration onOsdTextOnlyChanged: osdTextOnly.checked = !kcm.osdTextOnly } + RowLayout { + Layout.fillWidth: true + + Kirigami.FormData.label: i18n("Animation:") + + QtControls.ComboBox { + id: switchingEffect + + model: kcm.switchingEffects + + currentIndex: kcm.switchingEffect + + onCurrentIndexChanged: kcm.switchingEffect = currentIndex + } + + QtControls.Button { + enabled: switchingEffect.currentIndex > 0 && switchingEffect.currentIndex < 3 + + icon.name: "configure" + + onClicked: kcm.configureEffect() + } + + QtControls.Button { + // Enabled for Slide and Cube. + enabled: switchingEffect.currentIndex > 0 + + icon.name: "dialog-information" + + onClicked: kcm.aboutEffect() + } + + Item { + Layout.fillWidth: true + } + } + QtControls.CheckBox { id: navWraps @@ -249,5 +289,7 @@ } } } + + Component.onCompleted: kcm.window = Window.window } diff --git a/kcmkwin/kwindesktop/virtualdesktops.h b/kcmkwin/kwindesktop/virtualdesktops.h --- a/kcmkwin/kwindesktop/virtualdesktops.h +++ b/kcmkwin/kwindesktop/virtualdesktops.h @@ -21,6 +21,8 @@ #include #include +class QWindow; + namespace KWin { @@ -35,6 +37,9 @@ Q_PROPERTY(bool osdEnabled READ osdEnabled WRITE setOsdEnabled NOTIFY osdEnabledChanged) Q_PROPERTY(int osdDuration READ osdDuration WRITE setOsdDuration NOTIFY osdDurationChanged) Q_PROPERTY(bool osdTextOnly READ osdTextOnly WRITE setOsdTextOnly NOTIFY osdTextOnlyChanged) + Q_PROPERTY(QStringList switchingEffects READ switchingEffects CONSTANT) + Q_PROPERTY(int switchingEffect READ switchingEffect WRITE setSwitchingEffect NOTIFY switchingEffectChanged) + Q_PROPERTY(QWindow* window READ window WRITE setWindow NOTIFY windowChanged) public: explicit VirtualDesktops(QObject *parent = nullptr, const QVariantList &list = QVariantList()); @@ -54,27 +59,43 @@ int osdTextOnly() const; void setOsdTextOnly(bool textOnly); + QStringList switchingEffects() const; + + int switchingEffect() const; + void setSwitchingEffect(int effect); + + QWindow *window() const; + void setWindow(QWindow *window); + Q_SIGNALS: void navWrapsChanged() const; void osdEnabledChanged() const; void osdDurationChanged() const; void osdTextOnlyChanged() const; + void switchingEffectChanged() const; + void windowChanged() const; public Q_SLOTS: void load() override; void save() override; void defaults() override; + void configureEffect(); + void aboutEffect(); private Q_SLOTS: void updateNeedsSave(); + int storedSwitchingEffect(const KConfigGroup &effectsConfig) const; private: KSharedConfigPtr m_kwinConfig; DesktopsModel *m_desktopsModel; bool m_navWraps; bool m_osdEnabled; int m_osdDuration; bool m_osdTextOnly; + QStringList m_switchingEffects; + int m_switchingEffect; + QWindow *m_window; }; } diff --git a/kcmkwin/kwindesktop/virtualdesktops.cpp b/kcmkwin/kwindesktop/virtualdesktops.cpp --- a/kcmkwin/kwindesktop/virtualdesktops.cpp +++ b/kcmkwin/kwindesktop/virtualdesktops.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2018 Eike Hein + * Copyright (C) 2009 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 @@ -18,10 +19,27 @@ #include "virtualdesktops.h" #include "desktopsmodel.h" +#include +#include +#include + #include +#include #include +#include #include +#include +#include #include +#include +#include +#include + +#include +#include +#include +#include +#include K_PLUGIN_FACTORY_WITH_JSON(VirtualDesktopsFactory, "kcm_kwin_virtualdesktops.json", registerPlugin();) @@ -36,6 +54,8 @@ , m_osdEnabled(false) , m_osdDuration(1000) , m_osdTextOnly(false) + , m_switchingEffect(1) + , m_window(nullptr) { KAboutData *about = new KAboutData(QStringLiteral("kcm_kwin_virtualdesktops"), i18n("Configure Virtual Desktops"), @@ -46,6 +66,18 @@ QObject::connect(m_desktopsModel, &KWin::DesktopsModel::userModifiedChanged, this, &VirtualDesktops::updateNeedsSave); + + // Build switching effects names list. + m_switchingEffects << i18n("No Animation"); + m_switchingEffects << BuiltInEffects::effectData(BuiltInEffect::Slide).displayName; + m_switchingEffects << BuiltInEffects::effectData(BuiltInEffect::CubeSlide).displayName; + + KServiceTypeTrader *trader = KServiceTypeTrader::self(); + KService::List services = trader->query("KWin/Effect", "[X-KDE-PluginInfo-Name] == 'kwin4_effect_fadedesktop'"); + + if (!services.isEmpty()) { + m_switchingEffects << services.first()->name(); + } } VirtualDesktops::~VirtualDesktops() @@ -121,17 +153,54 @@ } } +QStringList VirtualDesktops::switchingEffects() const +{ + return m_switchingEffects; +} + +int VirtualDesktops::switchingEffect() const +{ + return m_switchingEffect; +} + +void VirtualDesktops::setSwitchingEffect(int effect) +{ + if (m_switchingEffect != effect) { + m_switchingEffect = effect; + + emit switchingEffectChanged(); + + updateNeedsSave(); + } +} + +QWindow *VirtualDesktops::window() const +{ + return m_window; +} + +void VirtualDesktops::setWindow(QWindow *window) +{ + if (m_window != window) { + m_window = window; + + emit windowChanged(); + } +} + void VirtualDesktops::load() { KConfigGroup navConfig(m_kwinConfig, "Windows"); setNavWraps(navConfig.readEntry("RollOverDesktops", true)); - KConfigGroup osdConfig(m_kwinConfig, "Plugins"); - setOsdEnabled(osdConfig.readEntry("desktopchangeosdEnabled", false)); + KConfigGroup effectsConfig(m_kwinConfig, "Plugins"); + setOsdEnabled(effectsConfig.readEntry("desktopchangeosdEnabled", false)); KConfigGroup osdSettings(m_kwinConfig, "Script-desktopchangeosd"); setOsdDuration(osdSettings.readEntry("PopupHideDelay", 1000)); setOsdTextOnly(osdSettings.readEntry("TextOnly", false)); + + setSwitchingEffect(storedSwitchingEffect(effectsConfig)); } void VirtualDesktops::save() @@ -141,19 +210,61 @@ KConfigGroup navConfig(m_kwinConfig, "Windows"); navConfig.writeEntry("RollOverDesktops", m_navWraps); - KConfigGroup osdConfig(m_kwinConfig, "Plugins"); - osdConfig.writeEntry("desktopchangeosdEnabled", m_osdEnabled); + KConfigGroup effectsConfig(m_kwinConfig, "Plugins"); + effectsConfig.writeEntry("desktopchangeosdEnabled", m_osdEnabled); KConfigGroup osdSettings(m_kwinConfig, "Script-desktopchangeosd"); osdSettings.writeEntry("PopupHideDelay", m_osdDuration); osdSettings.writeEntry("TextOnly", m_osdTextOnly); + bool slideEnabled = false; + bool cubeSlideEnabled = false; + bool fadeEnabled = false; + + switch(m_switchingEffect) { + case 1: + slideEnabled = true; + break; + case 2: + cubeSlideEnabled = true; + break; + case 3: + fadeEnabled = true; + break; + } + + effectsConfig.writeEntry("slideEnabled", slideEnabled); + effectsConfig.writeEntry("cubeslideEnabled", cubeSlideEnabled); + effectsConfig.writeEntry("kwin4_effect_fadedesktopEnabled", fadeEnabled); + m_kwinConfig->sync(); QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"), QStringLiteral("org.kde.KWin"), QStringLiteral("reloadConfig")); QDBusConnection::sessionBus().send(message); + OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"), + QStringLiteral("/Effects"), + QDBusConnection::sessionBus()); + + if (slideEnabled) { + interface.loadEffect(BuiltInEffects::nameForEffect(BuiltInEffect::Slide)); + } else { + interface.unloadEffect(BuiltInEffects::nameForEffect(BuiltInEffect::Slide)); + } + + if (cubeSlideEnabled) { + interface.loadEffect(BuiltInEffects::nameForEffect(BuiltInEffect::CubeSlide)); + } else { + interface.unloadEffect(BuiltInEffects::nameForEffect(BuiltInEffect::CubeSlide)); + } + + if (fadeEnabled) { + interface.loadEffect(QStringLiteral("kwin4_effect_fadedesktop")); + } else { + interface.unloadEffect(QStringLiteral("kwin4_effect_fadedesktop")); + } + setNeedsSave(false); } @@ -165,6 +276,147 @@ setOsdEnabled(false); setOsdDuration(1000); setOsdTextOnly(false); + setSwitchingEffect(1); +} + +void VirtualDesktops::configureEffect() +{ + QString effect; + + switch(m_switchingEffect) { + case 1: + effect = BuiltInEffects::nameForEffect(BuiltInEffect::Slide); + break; + case 2: + effect = BuiltInEffects::nameForEffect(BuiltInEffect::CubeSlide); + break; + default: + return; + } + + QPointer configDialog = new QDialog(); + + if (m_window) { + configDialog->windowHandle()->setTransientParent(m_window); + } + + KCModule *kcm = KPluginTrader::createInstanceFromQuery(QStringLiteral("kwin/effects/configs/"), QString(), + QStringLiteral("'%1' in [X-KDE-ParentComponents]").arg(effect), + configDialog); + + if (!kcm) { + delete configDialog; + return; + } + + configDialog->setWindowTitle(m_switchingEffects.at(m_switchingEffect)); + configDialog->setLayout(new QVBoxLayout); + QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel|QDialogButtonBox::RestoreDefaults, configDialog); + QObject::connect(buttons, &QDialogButtonBox::accepted, configDialog, &QDialog::accept); + QObject::connect(buttons, &QDialogButtonBox::rejected, configDialog, &QDialog::reject); + QObject::connect(buttons->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, kcm, &KCModule::defaults); + + QWidget *showWidget = new QWidget(configDialog); + QVBoxLayout *layout = new QVBoxLayout; + showWidget->setLayout(layout); + layout->addWidget(kcm); + configDialog->layout()->addWidget(showWidget); + configDialog->layout()->addWidget(buttons); + + if (configDialog->exec() == QDialog::Accepted) { + kcm->save(); + } else { + kcm->load(); + } + + delete configDialog; +} + +void VirtualDesktops::aboutEffect() +{ + QString effect; + bool fromKService = false; + BuiltInEffect builtIn = BuiltInEffect::Invalid; + + switch(m_switchingEffect) { + case 1: + builtIn = BuiltInEffect::Slide; + break; + case 2: + builtIn = BuiltInEffect::CubeSlide; + break; + case 3: + effect = "fadedesktop"; + fromKService = true; + break; + default: + return; + } + + auto showDialog = [this](const KAboutData &aboutData) { + QPointer aboutPlugin = new KAboutApplicationDialog(aboutData); + + if (m_window) { + aboutPlugin->windowHandle()->setTransientParent(m_window); + } + + aboutPlugin->exec(); + delete aboutPlugin; + }; + + if (fromKService) { + const QString pluginId = QStringLiteral("kwin4_effect_%1").arg(effect); + const auto effectsMetaData = KPackage::PackageLoader::self()->findPackages( + QStringLiteral("KWin/Effect"), + QStringLiteral("kwin/effects/"), + [&pluginId](const KPluginMetaData &meta) { + return meta.pluginId() == pluginId; + }); + + if (effectsMetaData.isEmpty()) { + return; + } + + KPluginInfo pluginInfo(effectsMetaData.first()); + + const QString name = pluginInfo.name(); + const QString comment = pluginInfo.comment(); + const QString author = pluginInfo.author(); + const QString email = pluginInfo.email(); + const QString website = pluginInfo.website(); + const QString version = pluginInfo.version(); + const QString license = pluginInfo.license(); + const QString icon = pluginInfo.icon(); + + KAboutData aboutData(name, name, version, comment, KAboutLicense::byKeyword(license).key(), QString(), QString(), website.toLatin1()); + aboutData.setProgramLogo(icon); + const QStringList authors = author.split(','); + const QStringList emails = email.split(','); + int i = 0; + + if (authors.count() == emails.count()) { + foreach (const QString & author, authors) { + if (!author.isEmpty()) { + aboutData.addAuthor(i18n(author.toUtf8()), QString(), emails[i]); + } + i++; + } + } + + showDialog(aboutData); + } else { + const BuiltInEffects::EffectData &data = BuiltInEffects::effectData(builtIn); + + KAboutData aboutData(data.name, + data.displayName, + QStringLiteral(KWIN_VERSION_STRING), + data.comment, + KAboutLicense::GPL_V2); + aboutData.setProgramLogo(QIcon::fromTheme(QStringLiteral("preferences-system-windows"))); + aboutData.addAuthor(i18n("KWin development team")); + + showDialog(aboutData); + } } void VirtualDesktops::updateNeedsSave() @@ -181,9 +433,9 @@ needsSave = true; } - KConfigGroup osdConfig(m_kwinConfig, "Plugins"); + KConfigGroup effectsConfig(m_kwinConfig, "Plugins"); - if (m_osdEnabled != osdConfig.readEntry("desktopchangeosdEnabled", false)) { + if (m_osdEnabled != effectsConfig.readEntry("desktopchangeosdEnabled", false)) { needsSave = true; } @@ -197,9 +449,48 @@ needsSave = true; } + if (m_switchingEffect != storedSwitchingEffect(effectsConfig)) { + needsSave = true; + } + setNeedsSave(needsSave); } +int VirtualDesktops::storedSwitchingEffect(const KConfigGroup &effectsConfig) const +{ + auto builtInEffectEnabled = [&effectsConfig, this](BuiltInEffect effect) { + const QString key = BuiltInEffects::nameForEffect(effect) + QStringLiteral("Enabled"); + + if (effectsConfig.readEntry(key, BuiltInEffects::enabledByDefault(effect))) { + return true; + } + + return false; + }; + + auto effectEnabled = [&effectsConfig, this](const QString &effect) { + KService::List services = KServiceTypeTrader::self()->query( + "KWin/Effect", "[X-KDE-PluginInfo-Name] == 'kwin4_effect_" + effect + '\''); + + if (!services.isEmpty()) { + QVariant v = services.first()->property("X-KDE-PluginInfo-EnabledByDefault"); + return effectsConfig.readEntry("kwin4_effect_" + effect + "Enabled", v.toBool()); + } + + return false; + }; + + if (builtInEffectEnabled(BuiltInEffect::Slide)) { + return 1; + } else if (builtInEffectEnabled(BuiltInEffect::CubeSlide)) { + return 2; + } else if (effectEnabled("fadedesktop")) { + return 3; + } + + return 0; +} + } #include "virtualdesktops.moc"