mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
Replace the convergentwindows KWin script SSD toggling with KWin rules to ensure windows are maximized and have no window border (and toggle off for docked mode). KWin rules work immediately at window creation, which is more efficient than listening to window creation events and manually changing properties on them. Currently, window rules setting maximization don't seem to address all cases where a window gets unmaximized, so for the time being we will still need the logic in convergentwindows to handle any sidecases.
239 lines
8.8 KiB
C++
239 lines
8.8 KiB
C++
// SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
|
|
// SPDX-FileCopyrightText: 2024 Luis Büchi <luis.buechi@kdemail.net>
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include "settings.h"
|
|
#include "config.h"
|
|
#include "utils.h"
|
|
|
|
#include <KRuntimePlatform>
|
|
|
|
#include <QDBusConnection>
|
|
#include <QDBusMessage>
|
|
#include <QDebug>
|
|
#include <QProcess>
|
|
|
|
using namespace Qt::Literals::StringLiterals;
|
|
|
|
const QString CONFIG_FILE = u"plasmamobilerc"_s;
|
|
const QString SAVED_CONFIG_GROUP = u"SavedConfig"_s;
|
|
|
|
Settings::Settings(QObject *parent)
|
|
: QObject{parent}
|
|
, m_isMobilePlatform{KRuntimePlatform::runtimePlatform().contains(u"phone"_s)}
|
|
, m_mobileConfig{KSharedConfig::openConfig(CONFIG_FILE, KConfig::SimpleConfig)}
|
|
, m_kwinrcConfig{KSharedConfig::openConfig(u"kwinrc"_s, KConfig::SimpleConfig)}
|
|
, m_appBlacklistConfig{KSharedConfig::openConfig(u"applications-blacklistrc"_s, KConfig::SimpleConfig)}
|
|
, m_kdeglobalsConfig{KSharedConfig::openConfig(u"kdeglobals"_s, KConfig::SimpleConfig)}
|
|
, m_ksmServerConfig{KSharedConfig::openConfig(u"ksmserverrc"_s, KConfig::SimpleConfig)}
|
|
, m_kwinrulesrcConfig{KSharedConfig::openConfig(u"kwinrulesrc"_s, KConfig::SimpleConfig)}
|
|
, m_configWatcher{KConfigWatcher::create(m_mobileConfig)}
|
|
{
|
|
}
|
|
|
|
Settings &Settings::self()
|
|
{
|
|
static Settings settings;
|
|
return settings;
|
|
}
|
|
|
|
void Settings::applyConfiguration()
|
|
{
|
|
if (!m_isMobilePlatform) {
|
|
qCDebug(LOGGING_CATEGORY) << "Configuration will not be applied, as the session is not Plasma Mobile.";
|
|
qCDebug(LOGGING_CATEGORY) << "Restoring any previously saved configuration...";
|
|
loadSavedConfiguration();
|
|
return;
|
|
}
|
|
|
|
qCDebug(LOGGING_CATEGORY) << "Checking and applying mobile configuration...";
|
|
applyMobileConfiguration();
|
|
}
|
|
|
|
void Settings::loadSavedConfiguration()
|
|
{
|
|
// kwinrc
|
|
loadKeys(u"kwinrc"_s, m_kwinrcConfig, getKwinrcSettings(m_mobileConfig));
|
|
m_kwinrcConfig->sync();
|
|
|
|
// kwinrules
|
|
for (const auto &groupName : KWIN_RULES) {
|
|
m_kwinrulesrcConfig->deleteGroup(groupName);
|
|
}
|
|
writeKeys(u"kwinrulesrc"_s, m_kwinrulesrcConfig, getKwinrulesrcSettings(m_mobileConfig, false), false, false);
|
|
m_kwinrulesrcConfig->sync();
|
|
|
|
reloadKWinConfig();
|
|
|
|
// applications-blacklistrc
|
|
loadKeys(u"applications-blacklistrc"_s, m_appBlacklistConfig, APPLICATIONS_BLACKLIST_DEFAULT_SETTINGS);
|
|
m_appBlacklistConfig->sync();
|
|
|
|
// kdeglobals
|
|
loadKeys(u"kdeglobals"_s, m_kdeglobalsConfig, KDEGLOBALS_DEFAULT_SETTINGS);
|
|
loadKeys(u"kdeglobals"_s, m_kdeglobalsConfig, KDEGLOBALS_SETTINGS);
|
|
m_kdeglobalsConfig->sync();
|
|
|
|
// save our changes
|
|
m_mobileConfig->sync();
|
|
}
|
|
|
|
void Settings::applyMobileConfiguration()
|
|
{
|
|
// kwinrc
|
|
writeKeys(u"kwinrc"_s, m_kwinrcConfig, getKwinrcSettings(m_mobileConfig), false);
|
|
m_kwinrcConfig->sync();
|
|
|
|
// kwinrules
|
|
for (const auto &groupName : KWIN_RULES) {
|
|
m_kwinrulesrcConfig->deleteGroup(groupName);
|
|
}
|
|
writeKeys(u"kwinrulesrc"_s, m_kwinrulesrcConfig, getKwinrulesrcSettings(m_mobileConfig, true), false, false);
|
|
m_kwinrulesrcConfig->sync();
|
|
|
|
reloadKWinConfig();
|
|
|
|
// applications-blacklistrc
|
|
writeKeys(u"applications-blacklistrc"_s,
|
|
m_appBlacklistConfig,
|
|
APPLICATIONS_BLACKLIST_DEFAULT_SETTINGS,
|
|
true); // only write entries if they are not already defined in the config
|
|
m_appBlacklistConfig->sync();
|
|
|
|
// kdeglobals
|
|
writeKeys(u"kdeglobals"_s, m_kdeglobalsConfig, KDEGLOBALS_DEFAULT_SETTINGS,
|
|
true); // only write entries if they are not already defined in the config
|
|
writeKeys(u"kdeglobals"_s, m_kdeglobalsConfig, KDEGLOBALS_SETTINGS, false);
|
|
m_kdeglobalsConfig->sync();
|
|
|
|
// ksmserver
|
|
writeKeys(u"ksmserverrc"_s, m_ksmServerConfig, KSMSERVER_SETTINGS, false);
|
|
m_ksmServerConfig->sync();
|
|
|
|
// save our changes
|
|
m_mobileConfig->sync();
|
|
}
|
|
|
|
void Settings::writeKeys(const QString &fileName,
|
|
KSharedConfig::Ptr &config,
|
|
const QMap<QString, QMap<QString, QVariant>> &settings,
|
|
bool overwriteOnlyIfEmpty,
|
|
bool saveSettings)
|
|
{
|
|
const auto groupNames = settings.keys();
|
|
for (const auto &groupName : groupNames) {
|
|
auto group = KConfigGroup{config, groupName};
|
|
|
|
const auto keys = settings[groupName].keys();
|
|
for (const auto &key : keys) {
|
|
if (!group.hasKey(key) || !overwriteOnlyIfEmpty) {
|
|
// save key
|
|
if (saveSettings) {
|
|
saveConfigSetting(fileName, groupName, key, group.readEntry(key));
|
|
}
|
|
|
|
// overwrite with mobile setting
|
|
group.writeEntry(key, settings[groupName][key], KConfigGroup::Notify);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Settings::loadKeys(const QString &fileName, KSharedConfig::Ptr &config, const QMap<QString, QMap<QString, QVariant>> &settings)
|
|
{
|
|
const auto groupNames = settings.keys();
|
|
for (const auto &groupName : groupNames) {
|
|
const auto group = KConfigGroup{config, groupName};
|
|
|
|
const auto keys = settings[groupName].keys();
|
|
for (const auto &key : keys) {
|
|
loadSavedConfigSetting(config, fileName, groupName, key);
|
|
}
|
|
}
|
|
}
|
|
|
|
// NOTE: this only saves a value if it hasn't already been saved
|
|
void Settings::saveConfigSetting(const QString &fileName, const QString &group, const QString &key, const QVariant value)
|
|
{
|
|
// These are not const because we are writing an entry
|
|
auto savedGroup = KConfigGroup{m_mobileConfig, SAVED_CONFIG_GROUP};
|
|
auto fileGroup = KConfigGroup{&savedGroup, fileName};
|
|
auto keyGroup = KConfigGroup{&fileGroup, group};
|
|
|
|
if (!keyGroup.hasKey(key)) {
|
|
qCDebug(LOGGING_CATEGORY) << "In" << fileName << "saved" << key << "=" << value;
|
|
keyGroup.writeEntry(key, value);
|
|
}
|
|
}
|
|
|
|
// NOTE: this deletes the stored value from the config after loading
|
|
const QString Settings::loadSavedConfigSetting(KSharedConfig::Ptr &config, const QString &fileName, const QString &group, const QString &key, bool write)
|
|
{
|
|
auto savedGroup = KConfigGroup{m_mobileConfig, SAVED_CONFIG_GROUP};
|
|
auto fileGroup = KConfigGroup{&savedGroup, fileName};
|
|
auto keyGroup = KConfigGroup{&fileGroup, group};
|
|
|
|
if (!keyGroup.hasKey(key)) {
|
|
return {};
|
|
}
|
|
|
|
const auto value = keyGroup.readEntry(key);
|
|
|
|
// write to real config
|
|
auto configGroup = KConfigGroup{config, group};
|
|
|
|
if ((!configGroup.hasKey(key) || configGroup.readEntry(key) != value) && write) {
|
|
qCDebug(LOGGING_CATEGORY) << "In" << fileName << "loading saved value of" << key << "which is" << value << "in" << group;
|
|
|
|
if (value.isEmpty()) { // delete blank entries!
|
|
configGroup.deleteEntry(key);
|
|
} else {
|
|
configGroup.writeEntry(key, value, KConfigGroup::Notify);
|
|
}
|
|
}
|
|
|
|
// remove saved config option
|
|
keyGroup.deleteEntry(key);
|
|
return value;
|
|
}
|
|
|
|
void Settings::reloadKWinConfig()
|
|
{
|
|
// Reload config
|
|
QDBusMessage reloadMessage = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
|
|
QDBusConnection::sessionBus().send(reloadMessage);
|
|
|
|
// Effects need to manually be loaded/unloaded in a live KWin session.
|
|
|
|
KConfigGroup pluginsGroup{m_kwinrcConfig, QStringLiteral("Plugins")};
|
|
|
|
for (const auto &effect : KWIN_EFFECTS) {
|
|
// Read from the config whether the effect is enabled (settings are suffixed with "Enabled", ex. blurEnabled)
|
|
bool status = pluginsGroup.readEntry(effect + u"Enabled"_s, false);
|
|
const QString method = status ? u"loadEffect"_s : u"unloadEffect"_s;
|
|
|
|
QDBusMessage message = QDBusMessage::createMethodCall(u"org.kde.KWin"_s, u"/Effects"_s, u"org.kde.kwin.Effects"_s, method);
|
|
message.setArguments({effect});
|
|
QDBusConnection::sessionBus().send(message);
|
|
}
|
|
|
|
// Unload KWin scripts that are now disabled.
|
|
for (const auto &script : KWIN_SCRIPTS) {
|
|
// Read from the config whether the effect is enabled (settings are suffixed with "Enabled", ex. blurEnabled)
|
|
bool status = pluginsGroup.readEntry(script + u"Enabled"_s, false);
|
|
|
|
if (!status) {
|
|
QDBusMessage message = QDBusMessage::createMethodCall(u"org.kde.KWin"_s, u"/Scripting"_s, u"org.kde.kwin.Scripting"_s, u"unloadScript"_s);
|
|
message.setArguments({script});
|
|
QDBusConnection::sessionBus().send(message);
|
|
}
|
|
}
|
|
|
|
// Call "start" to load enabled KWin scripts.
|
|
QDBusMessage startScriptsMessage = QDBusMessage::createMethodCall(u"org.kde.KWin"_s, u"/Scripting"_s, u"org.kde.kwin.Scripting"_s, u"start"_s);
|
|
QDBusConnection::sessionBus().send(startScriptsMessage);
|
|
|
|
// Call reconfigure
|
|
QDBusMessage reconfigureMessage = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reconfigure");
|
|
QDBusConnection::sessionBus().send(reconfigureMessage);
|
|
}
|