File indexing completed on 2024-04-21 16:17:13

0001 /*
0002 *  Copyright 2017  Smith AR <audoban@openmailbox.org>
0003 *                  Michail Vourlakos <mvourlakos@gmail.com>
0004 *
0005 *  This file is part of Latte-Dock
0006 *
0007 *  Latte-Dock is free software; you can redistribute it and/or
0008 *  modify it under the terms of the GNU General Public License as
0009 *  published by the Free Software Foundation; either version 2 of
0010 *  the License, or (at your option) any later version.
0011 *
0012 *  Latte-Dock is distributed in the hope that it will be useful,
0013 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0014 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015 *  GNU General Public License for more details.
0016 *
0017 *  You should have received a copy of the GNU General Public License
0018 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0019 */
0020 
0021 #include "universalsettings.h"
0022 
0023 // local
0024 #include "../layouts/importer.h"
0025 #include "../layouts/manager.h"
0026 
0027 // Qt
0028 #include <QDebug>
0029 #include <QDir>
0030 #include <QProcess>
0031 #include <QtDBus>
0032 
0033 // KDE
0034 #include <KActivities/Consumer>
0035 #include <KDirWatch>
0036 
0037 #define KWINMETAFORWARDTOLATTESTRING "org.kde.lattedock,/Latte,org.kde.LatteDock,activateLauncherMenu"
0038 #define KWINMETAFORWARDTOPLASMASTRING "org.kde.plasmashell,/PlasmaShell,org.kde.PlasmaShell,activateLauncherMenu"
0039 
0040 #define KWINCOLORSSCRIPT "kwin/scripts/lattewindowcolors"
0041 #define KWINRC "/.config/kwinrc"
0042 
0043 namespace Latte {
0044 
0045 UniversalSettings::UniversalSettings(KSharedConfig::Ptr config, QObject *parent)
0046     : QObject(parent),
0047       m_config(config),
0048       m_universalGroup(KConfigGroup(config, QStringLiteral("UniversalSettings")))
0049 {
0050     m_corona = qobject_cast<Latte::Corona *>(parent);
0051 
0052     connect(this, &UniversalSettings::badges3DStyleChanged, this, &UniversalSettings::saveConfig);
0053     connect(this, &UniversalSettings::canDisableBordersChanged, this, &UniversalSettings::saveConfig);
0054     connect(this, &UniversalSettings::currentLayoutNameChanged, this, &UniversalSettings::saveConfig);
0055     connect(this, &UniversalSettings::downloadWindowSizeChanged, this, &UniversalSettings::saveConfig);
0056     connect(this, &UniversalSettings::lastNonAssignedLayoutNameChanged, this, &UniversalSettings::saveConfig);
0057     connect(this, &UniversalSettings::launchersChanged, this, &UniversalSettings::saveConfig);
0058     connect(this, &UniversalSettings::layoutsColumnWidthsChanged, this, &UniversalSettings::saveConfig);
0059     connect(this, &UniversalSettings::layoutsMemoryUsageChanged, this, &UniversalSettings::saveConfig);
0060     connect(this, &UniversalSettings::layoutsWindowSizeChanged, this, &UniversalSettings::saveConfig);
0061     connect(this, &UniversalSettings::metaPressAndHoldEnabledChanged, this, &UniversalSettings::saveConfig);
0062     connect(this, &UniversalSettings::mouseSensitivityChanged, this, &UniversalSettings::saveConfig);
0063     connect(this, &UniversalSettings::screenTrackerIntervalChanged, this, &UniversalSettings::saveConfig);
0064     connect(this, &UniversalSettings::showInfoWindowChanged, this, &UniversalSettings::saveConfig);
0065     connect(this, &UniversalSettings::versionChanged, this, &UniversalSettings::saveConfig);
0066 
0067     connect(this, &UniversalSettings::screenScalesChanged, this, &UniversalSettings::saveScalesConfig);
0068 
0069     connect(qGuiApp, &QGuiApplication::screenAdded, this, &UniversalSettings::screensCountChanged);
0070     connect(qGuiApp, &QGuiApplication::screenRemoved, this, &UniversalSettings::screensCountChanged);
0071 }
0072 
0073 UniversalSettings::~UniversalSettings()
0074 {
0075     saveConfig();
0076     cleanupSettings();
0077 }
0078 
0079 void UniversalSettings::load()
0080 {
0081     //! check if user has set the autostart option
0082     bool autostartUserSet = m_universalGroup.readEntry("userConfiguredAutostart", false);
0083 
0084     if (!autostartUserSet && !autostart()) {
0085         setAutostart(true);
0086     }
0087 
0088     //! init screen scales
0089     m_screenScalesGroup = m_universalGroup.group("ScreenScales");
0090 
0091     //! load configuration
0092     loadConfig();
0093 
0094     //! Track KWin Colors Script Presence
0095     updateColorsScriptIsPresent();
0096 
0097     QStringList colorsScriptPaths = Layouts::Importer::standardPathsFor(KWINCOLORSSCRIPT);
0098     for(auto path: colorsScriptPaths) {
0099         KDirWatch::self()->addDir(path);
0100     }
0101 
0102     //! Track KWin rc options
0103     const QString kwinrcFilePath = QDir::homePath() + KWINRC;
0104     KDirWatch::self()->addFile(kwinrcFilePath);
0105     recoverKWinOptions();
0106 
0107     connect(KDirWatch::self(), &KDirWatch::created, this, &UniversalSettings::trackedFileChanged);
0108     connect(KDirWatch::self(), &KDirWatch::deleted, this, &UniversalSettings::trackedFileChanged);
0109     connect(KDirWatch::self(), &KDirWatch::dirty, this, &UniversalSettings::trackedFileChanged);
0110 
0111     //! this is needed to inform globalshortcuts to update its modifiers tracking
0112     emit metaPressAndHoldEnabledChanged();
0113 }
0114 
0115 bool UniversalSettings::showInfoWindow() const
0116 {
0117     return m_showInfoWindow;
0118 }
0119 
0120 void UniversalSettings::setShowInfoWindow(bool show)
0121 {
0122     if (m_showInfoWindow == show) {
0123         return;
0124     }
0125 
0126     m_showInfoWindow = show;
0127     emit showInfoWindowChanged();
0128 }
0129 
0130 int UniversalSettings::version() const
0131 {
0132     return m_version;
0133 }
0134 
0135 void UniversalSettings::setVersion(int ver)
0136 {
0137     if (m_version == ver) {
0138         return;
0139     }
0140 
0141     m_version = ver;
0142     qDebug() << "Universal Settings version updated to : " << m_version;
0143 
0144     emit versionChanged();
0145 }
0146 
0147 int UniversalSettings::screenTrackerInterval() const
0148 {
0149     return m_screenTrackerInterval;
0150 }
0151 
0152 void UniversalSettings::setScreenTrackerInterval(int duration)
0153 {
0154     if (m_screenTrackerInterval == duration) {
0155         return;
0156     }
0157 
0158     m_screenTrackerInterval = duration;
0159     emit screenTrackerIntervalChanged();
0160 }
0161 
0162 QString UniversalSettings::currentLayoutName() const
0163 {
0164     return m_currentLayoutName;
0165 }
0166 
0167 void UniversalSettings::setCurrentLayoutName(QString layoutName)
0168 {
0169     if (m_currentLayoutName == layoutName) {
0170         return;
0171     }
0172 
0173     m_currentLayoutName = layoutName;
0174     emit currentLayoutNameChanged();
0175 }
0176 
0177 QString UniversalSettings::lastNonAssignedLayoutName() const
0178 {
0179     return m_lastNonAssignedLayoutName;
0180 }
0181 
0182 void UniversalSettings::setLastNonAssignedLayoutName(QString layoutName)
0183 {
0184     if (m_lastNonAssignedLayoutName == layoutName) {
0185         return;
0186     }
0187 
0188     m_lastNonAssignedLayoutName = layoutName;
0189     emit lastNonAssignedLayoutNameChanged();
0190 }
0191 
0192 QSize UniversalSettings::downloadWindowSize() const
0193 {
0194     return m_downloadWindowSize;
0195 }
0196 
0197 void UniversalSettings::setDownloadWindowSize(QSize size)
0198 {
0199     if (m_downloadWindowSize == size) {
0200         return;
0201     }
0202 
0203     m_downloadWindowSize = size;
0204     emit downloadWindowSizeChanged();
0205 }
0206 
0207 
0208 QSize UniversalSettings::layoutsWindowSize() const
0209 {
0210     return m_layoutsWindowSize;
0211 }
0212 
0213 void UniversalSettings::setLayoutsWindowSize(QSize size)
0214 {
0215     if (m_layoutsWindowSize == size) {
0216         return;
0217     }
0218 
0219     m_layoutsWindowSize = size;
0220     emit layoutsWindowSizeChanged();
0221 }
0222 
0223 QStringList UniversalSettings::layoutsColumnWidths() const
0224 {
0225     return m_layoutsColumnWidths;
0226 }
0227 
0228 void UniversalSettings::setLayoutsColumnWidths(QStringList widths)
0229 {
0230     if (m_layoutsColumnWidths == widths) {
0231         return;
0232     }
0233 
0234     m_layoutsColumnWidths = widths;
0235     emit layoutsColumnWidthsChanged();
0236 }
0237 
0238 QStringList UniversalSettings::launchers() const
0239 {
0240     return m_launchers;
0241 }
0242 
0243 void UniversalSettings::setLaunchers(QStringList launcherList)
0244 {
0245     if (m_launchers == launcherList) {
0246         return;
0247     }
0248 
0249     m_launchers = launcherList;
0250     emit launchersChanged();
0251 }
0252 
0253 
0254 bool UniversalSettings::autostart() const
0255 {
0256     QFile autostartFile(QDir::homePath() + "/.config/autostart/org.kde.latte-dock.desktop");
0257     return autostartFile.exists();
0258 }
0259 
0260 void UniversalSettings::setAutostart(bool state)
0261 {
0262     //! remove old autostart file
0263     QFile oldAutostartFile(QDir::homePath() + "/.config/autostart/latte-dock.desktop");
0264 
0265     if (oldAutostartFile.exists()) {
0266         oldAutostartFile.remove();
0267     }
0268 
0269     //! end of removal of old autostart file
0270 
0271     QFile autostartFile(QDir::homePath() + "/.config/autostart/org.kde.latte-dock.desktop");
0272     QFile metaFile(Layouts::Importer::standardPath("applications/org.kde.latte-dock.desktop", false));
0273 
0274     if (!state && autostartFile.exists()) {
0275         //! the first time that the user disables the autostart, this is recorded
0276         //! and from now own it will not be recreated it in the beginning
0277         if (!m_universalGroup.readEntry("userConfiguredAutostart", false)) {
0278             m_universalGroup.writeEntry("userConfiguredAutostart", true);
0279         }
0280 
0281         autostartFile.remove();
0282         emit autostartChanged();
0283     } else if (state && metaFile.exists()) {
0284         //! check if autostart folder exists and create otherwise
0285         QDir autostartDir(QDir::homePath() + "/.config/autostart");
0286         if (!autostartDir.exists()) {
0287             QDir configDir(QDir::homePath() + "/.config");
0288             configDir.mkdir("autostart");
0289         }
0290 
0291         metaFile.copy(autostartFile.fileName());
0292         //! I haven't added the flag "OnlyShowIn=KDE;" into the autostart file
0293         //! because I fall onto a Plasma 5.8 case that this flag
0294         //! didn't let the plasma desktop to start
0295         emit autostartChanged();
0296     }
0297 }
0298 
0299 bool UniversalSettings::badges3DStyle() const
0300 {
0301     return m_badges3DStyle;
0302 }
0303 
0304 void UniversalSettings::setBadges3DStyle(bool enable)
0305 {
0306     if (m_badges3DStyle == enable) {
0307         return;
0308     }
0309 
0310     m_badges3DStyle = enable;
0311     emit badges3DStyleChanged();
0312 }
0313 
0314 
0315 bool UniversalSettings::canDisableBorders() const
0316 {
0317     return m_canDisableBorders;
0318 }
0319 
0320 void UniversalSettings::setCanDisableBorders(bool enable)
0321 {
0322     if (m_canDisableBorders == enable) {
0323         return;
0324     }
0325 
0326     m_canDisableBorders = enable;
0327     emit canDisableBordersChanged();
0328 }
0329 
0330 bool UniversalSettings::colorsScriptIsPresent() const
0331 {
0332     return m_colorsScriptIsPresent;
0333 }
0334 
0335 void UniversalSettings::setColorsScriptIsPresent(bool present)
0336 {
0337     if (m_colorsScriptIsPresent == present) {
0338         return;
0339     }
0340 
0341     m_colorsScriptIsPresent = present;
0342     emit colorsScriptIsPresentChanged();
0343 }
0344 
0345 void UniversalSettings::updateColorsScriptIsPresent()
0346 {
0347     qDebug() << "Updating Latte Colors Script presence...";
0348 
0349     setColorsScriptIsPresent(!Layouts::Importer::standardPath(KWINCOLORSSCRIPT).isEmpty());
0350 }
0351 
0352 void UniversalSettings::trackedFileChanged(const QString &file)
0353 {    
0354     if (file.endsWith(KWINCOLORSSCRIPT)) {
0355         updateColorsScriptIsPresent();
0356     }
0357 
0358     if (file.endsWith(KWINRC)) {
0359         recoverKWinOptions();
0360     }
0361 }
0362 
0363 bool UniversalSettings::kwin_metaForwardedToLatte() const
0364 {
0365     return m_kwinMetaForwardedToLatte;
0366 }
0367 
0368 bool UniversalSettings::kwin_borderlessMaximizedWindowsEnabled() const
0369 {
0370     return m_kwinBorderlessMaximizedWindows;
0371 }
0372 
0373 void UniversalSettings::kwin_forwardMetaToLatte(bool forward)
0374 {
0375     if (m_kwinMetaForwardedToLatte == forward) {
0376         return;
0377     }
0378 
0379     QProcess process;
0380     QStringList parameters;
0381     parameters << "--file" << "kwinrc" << "--group" << "ModifierOnlyShortcuts" << "--key" << "Meta";
0382 
0383     if (forward) {
0384         parameters << KWINMETAFORWARDTOLATTESTRING;
0385     } else {
0386         parameters << KWINMETAFORWARDTOPLASMASTRING;
0387     }
0388 
0389     process.start("kwriteconfig5", parameters);
0390     process.waitForFinished();
0391 
0392     QDBusInterface iface("org.kde.KWin", "/KWin", "", QDBusConnection::sessionBus());
0393 
0394     if (iface.isValid()) {
0395         iface.call("reconfigure");
0396     }
0397 }
0398 
0399 void UniversalSettings::kwin_setDisabledMaximizedBorders(bool disable)
0400 {
0401     if (m_kwinBorderlessMaximizedWindows == disable) {
0402         return;
0403     }
0404 
0405     QString disableText = disable ? "true" : "false";
0406 
0407     QProcess process;
0408     QString commandStr = "kwriteconfig5 --file kwinrc --group Windows --key BorderlessMaximizedWindows --type bool " + disableText;
0409     process.start(commandStr);
0410     process.waitForFinished();
0411 
0412     QDBusInterface iface("org.kde.KWin", "/KWin", "", QDBusConnection::sessionBus());
0413 
0414     if (iface.isValid()) {
0415         iface.call("reconfigure");
0416     }
0417 }
0418 
0419 void UniversalSettings::recoverKWinOptions()
0420 {
0421     qDebug() << "kwinrc: recovering values...";
0422 
0423     //! Meta forwarded to Latte option
0424     QProcess process;
0425     process.start("kreadconfig5 --file kwinrc --group ModifierOnlyShortcuts --key Meta");
0426     process.waitForFinished();
0427     QString output(process.readAllStandardOutput());
0428     output = output.remove("\n");
0429 
0430     m_kwinMetaForwardedToLatte = (output == KWINMETAFORWARDTOLATTESTRING);
0431 
0432     //! BorderlessMaximizedWindows option
0433     process.start("kreadconfig5 --file kwinrc --group Windows --key BorderlessMaximizedWindows");
0434     process.waitForFinished();
0435     output = process.readAllStandardOutput();
0436     output = output.remove("\n");
0437     m_kwinBorderlessMaximizedWindows = (output == "true");
0438 }
0439 
0440 
0441 bool UniversalSettings::metaPressAndHoldEnabled() const
0442 {
0443     return m_metaPressAndHoldEnabled;
0444 }
0445 
0446 void UniversalSettings::setMetaPressAndHoldEnabled(bool enabled)
0447 {
0448     if (m_metaPressAndHoldEnabled == enabled) {
0449         return;
0450     }
0451 
0452     m_metaPressAndHoldEnabled = enabled;
0453 
0454     emit metaPressAndHoldEnabledChanged();
0455 }
0456 
0457 Types::LayoutsMemoryUsage UniversalSettings::layoutsMemoryUsage() const
0458 {
0459     return m_memoryUsage;
0460 }
0461 
0462 void UniversalSettings::setLayoutsMemoryUsage(Types::LayoutsMemoryUsage layoutsMemoryUsage)
0463 {
0464     if (m_memoryUsage == layoutsMemoryUsage) {
0465         return;
0466     }
0467 
0468     m_memoryUsage = layoutsMemoryUsage;
0469     emit layoutsMemoryUsageChanged();
0470 }
0471 
0472 Types::MouseSensitivity UniversalSettings::mouseSensitivity() const
0473 {
0474     return m_mouseSensitivity;
0475 }
0476 
0477 void UniversalSettings::setMouseSensitivity(Types::MouseSensitivity sensitivity)
0478 {
0479     if (m_mouseSensitivity == sensitivity) {
0480         return;
0481     }
0482 
0483     m_mouseSensitivity = sensitivity;
0484     emit mouseSensitivityChanged();
0485 }
0486 
0487 float UniversalSettings::screenWidthScale(QString screenName) const
0488 {
0489     if (!m_screenScales.contains(screenName)) {
0490         return 1;
0491     }
0492 
0493     return m_screenScales[screenName].first;
0494 }
0495 
0496 float UniversalSettings::screenHeightScale(QString screenName) const
0497 {
0498     if (!m_screenScales.contains(screenName)) {
0499         return 1;
0500     }
0501 
0502     return m_screenScales[screenName].second;
0503 }
0504 
0505 void UniversalSettings::setScreenScales(QString screenName, float widthScale, float heightScale)
0506 {
0507     if (!m_screenScales.contains(screenName)) {
0508         m_screenScales[screenName].first = widthScale;
0509         m_screenScales[screenName].second = heightScale;
0510     } else {
0511         if (m_screenScales[screenName].first == widthScale
0512                 && m_screenScales[screenName].second == heightScale) {
0513             return;
0514         }
0515 
0516         m_screenScales[screenName].first = widthScale;
0517         m_screenScales[screenName].second = heightScale;
0518     }
0519 
0520     emit screenScalesChanged();
0521 }
0522 
0523 void UniversalSettings::loadConfig()
0524 {
0525     m_version = m_universalGroup.readEntry("version", 1);
0526     m_badges3DStyle = m_universalGroup.readEntry("badges3DStyle", false);
0527     m_canDisableBorders = m_universalGroup.readEntry("canDisableBorders", false);
0528     m_currentLayoutName = m_universalGroup.readEntry("currentLayout", QString());
0529     m_downloadWindowSize = m_universalGroup.readEntry("downloadWindowSize", QSize(800, 550));
0530     m_lastNonAssignedLayoutName = m_universalGroup.readEntry("lastNonAssignedLayout", QString());
0531     m_layoutsWindowSize = m_universalGroup.readEntry("layoutsWindowSize", QSize(700, 450));
0532     m_layoutsColumnWidths = m_universalGroup.readEntry("layoutsColumnWidths", QStringList());
0533     m_launchers = m_universalGroup.readEntry("launchers", QStringList());
0534     m_metaPressAndHoldEnabled = m_universalGroup.readEntry("metaPressAndHoldEnabled", true);
0535     m_screenTrackerInterval = m_universalGroup.readEntry("screenTrackerInterval", 2500);
0536     m_showInfoWindow = m_universalGroup.readEntry("showInfoWindow", true);
0537     m_memoryUsage = static_cast<Types::LayoutsMemoryUsage>(m_universalGroup.readEntry("memoryUsage", (int)Types::SingleLayout));
0538     m_mouseSensitivity = static_cast<Types::MouseSensitivity>(m_universalGroup.readEntry("mouseSensitivity", (int)Types::HighSensitivity));
0539 
0540     loadScalesConfig();
0541 }
0542 
0543 void UniversalSettings::saveConfig()
0544 {
0545     m_universalGroup.writeEntry("version", m_version);
0546     m_universalGroup.writeEntry("badges3DStyle", m_badges3DStyle);
0547     m_universalGroup.writeEntry("canDisableBorders", m_canDisableBorders);
0548     m_universalGroup.writeEntry("currentLayout", m_currentLayoutName);
0549     m_universalGroup.writeEntry("downloadWindowSize", m_downloadWindowSize);
0550     m_universalGroup.writeEntry("lastNonAssignedLayout", m_lastNonAssignedLayoutName);
0551     m_universalGroup.writeEntry("layoutsWindowSize", m_layoutsWindowSize);
0552     m_universalGroup.writeEntry("layoutsColumnWidths", m_layoutsColumnWidths);
0553     m_universalGroup.writeEntry("launchers", m_launchers);
0554     m_universalGroup.writeEntry("metaPressAndHoldEnabled", m_metaPressAndHoldEnabled);
0555     m_universalGroup.writeEntry("screenTrackerInterval", m_screenTrackerInterval);
0556     m_universalGroup.writeEntry("showInfoWindow", m_showInfoWindow);
0557     m_universalGroup.writeEntry("memoryUsage", (int)m_memoryUsage);
0558     m_universalGroup.writeEntry("mouseSensitivity", (int)m_mouseSensitivity);
0559 
0560     m_universalGroup.sync();
0561 }
0562 
0563 void UniversalSettings::cleanupSettings()
0564 {
0565     KConfigGroup containments = KConfigGroup(m_config, QStringLiteral("Containments"));
0566     containments.deleteGroup();
0567 
0568     containments.sync();
0569 }
0570 
0571 QString UniversalSettings::splitterIconPath()
0572 {
0573     return m_corona->kPackage().filePath("splitter");
0574 }
0575 
0576 QString UniversalSettings::trademarkIconPath()
0577 {
0578     return m_corona->kPackage().filePath("trademark");
0579 }
0580 
0581 QQmlListProperty<QScreen> UniversalSettings::screens()
0582 {
0583     return QQmlListProperty<QScreen>(this, nullptr, &countScreens, &atScreens);
0584 }
0585 
0586 int UniversalSettings::countScreens(QQmlListProperty<QScreen> *property)
0587 {
0588     Q_UNUSED(property)
0589     return qGuiApp->screens().count();
0590 }
0591 
0592 QScreen *UniversalSettings::atScreens(QQmlListProperty<QScreen> *property, int index)
0593 {
0594     Q_UNUSED(property)
0595     return qGuiApp->screens().at(index);
0596 }
0597 
0598 void UniversalSettings::loadScalesConfig()
0599 {
0600     for (const auto &screenName : m_screenScalesGroup.keyList()) {
0601         QString scalesStr = m_screenScalesGroup.readEntry(screenName, QString());
0602         QStringList scales = scalesStr.split(";");
0603         if (scales.count() == 2) {
0604             m_screenScales[screenName] = qMakePair(scales[0].toFloat(), scales[1].toFloat());
0605         }
0606     }
0607 }
0608 
0609 void UniversalSettings::saveScalesConfig()
0610 {
0611     for (const auto &screenName : m_screenScales.keys()) {
0612         QStringList scales;
0613         scales << QString::number(m_screenScales[screenName].first) << QString::number(m_screenScales[screenName].second);
0614         m_screenScalesGroup.writeEntry(screenName, scales.join(";"));
0615     }
0616 
0617     m_screenScalesGroup.sync();
0618 }
0619 
0620 }