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 }