mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-06-11 16:57:43 +00:00
Expose theme and accent controls in MobileShellSettings and the\nAppearance KCM. Generate ShiftWallpaperDark/Light from Shift base\nschemes, apply them through KDE color tools, and debounce wallpaper\ncolor updates. Register a dedicated dynamic-theming regression test.
1000 lines
39 KiB
C++
1000 lines
39 KiB
C++
/*
|
|
* SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include "mobileshellsettings.h"
|
|
|
|
#include <KIO/CommandLauncherJob>
|
|
#include <KNotificationJobUiDelegate>
|
|
#include <KPluginFactory>
|
|
#include <KRuntimePlatform>
|
|
|
|
#include <QDBusConnection>
|
|
#include <QDBusMessage>
|
|
#include <QDBusPendingCall>
|
|
#include <QDebug>
|
|
#include <QDir>
|
|
#include <QFile>
|
|
#include <QProcess>
|
|
#include <QStandardPaths>
|
|
#include <QtMath>
|
|
|
|
const QString CONFIG_FILE = QStringLiteral("plasmamobilerc");
|
|
const QString GENERAL_CONFIG_GROUP = QStringLiteral("General");
|
|
const QString KDE_GLOBALS_CONFIG_GROUP = QStringLiteral("General");
|
|
const QString LOCKSCREEN_CONFIG_GROUP = QStringLiteral("Lockscreen");
|
|
const QString QUICKSETTINGS_CONFIG_GROUP = QStringLiteral("QuickSettings");
|
|
const QString WALLPAPER_THEME_MANUAL_DARK_KEY = QStringLiteral("wallpaperThemeManualDarkTheme");
|
|
const QString SHIFT_DARK_COLOR_SCHEME = QStringLiteral("ShiftDark");
|
|
const QString SHIFT_LIGHT_COLOR_SCHEME = QStringLiteral("ShiftLight");
|
|
const QString SHIFT_WALLPAPER_DARK_COLOR_SCHEME = QStringLiteral("ShiftWallpaperDark");
|
|
const QString SHIFT_WALLPAPER_LIGHT_COLOR_SCHEME = QStringLiteral("ShiftWallpaperLight");
|
|
const QString SHIFT_DARK_PLASMA_THEME = QStringLiteral("shift-dark");
|
|
const QString SHIFT_LIGHT_PLASMA_THEME = QStringLiteral("shift-light");
|
|
constexpr qreal MIN_NORMAL_CONTRAST = 4.5;
|
|
constexpr qreal MIN_INACTIVE_CONTRAST = 3.0;
|
|
constexpr qreal MIN_LINK_CONTRAST = 3.5;
|
|
|
|
namespace
|
|
{
|
|
QString baseColorSchemeName(bool dark)
|
|
{
|
|
return dark ? SHIFT_DARK_COLOR_SCHEME : SHIFT_LIGHT_COLOR_SCHEME;
|
|
}
|
|
|
|
QString wallpaperColorSchemeName(bool dark)
|
|
{
|
|
return dark ? SHIFT_WALLPAPER_DARK_COLOR_SCHEME : SHIFT_WALLPAPER_LIGHT_COLOR_SCHEME;
|
|
}
|
|
|
|
QString wallpaperColorSchemeDisplayName(bool dark)
|
|
{
|
|
return dark ? QStringLiteral("SHIFT Wallpaper Dark") : QStringLiteral("SHIFT Wallpaper Light");
|
|
}
|
|
|
|
QString rgbString(const QColor &color)
|
|
{
|
|
return QStringLiteral("%1,%2,%3").arg(color.red()).arg(color.green()).arg(color.blue());
|
|
}
|
|
|
|
qreal relativeLuminance(const QColor &color)
|
|
{
|
|
return 0.2126 * color.redF() + 0.7152 * color.greenF() + 0.0722 * color.blueF();
|
|
}
|
|
|
|
qreal linearizedChannel(qreal channel)
|
|
{
|
|
return channel <= 0.04045 ? channel / 12.92 : qPow((channel + 0.055) / 1.055, 2.4);
|
|
}
|
|
|
|
qreal wcagLuminance(const QColor &color)
|
|
{
|
|
return 0.2126 * linearizedChannel(color.redF()) + 0.7152 * linearizedChannel(color.greenF()) + 0.0722 * linearizedChannel(color.blueF());
|
|
}
|
|
|
|
qreal contrastRatio(const QColor &left, const QColor &right)
|
|
{
|
|
const qreal leftLum = wcagLuminance(left);
|
|
const qreal rightLum = wcagLuminance(right);
|
|
const qreal lighter = qMax(leftLum, rightLum);
|
|
const qreal darker = qMin(leftLum, rightLum);
|
|
return (lighter + 0.05) / (darker + 0.05);
|
|
}
|
|
|
|
QColor contrastingTextColor(const QColor &color);
|
|
QColor blendColors(const QColor &base, const QColor &overlay, qreal overlayAmount);
|
|
|
|
QColor ensureContrast(const QColor &foreground, const QColor &background, qreal minimumContrast)
|
|
{
|
|
if (contrastRatio(foreground, background) >= minimumContrast) {
|
|
return foreground;
|
|
}
|
|
|
|
const QColor highContrastTarget = contrastingTextColor(background);
|
|
for (int i = 1; i <= 12; ++i) {
|
|
const qreal amount = i / 12.0;
|
|
const QColor candidate = blendColors(foreground, highContrastTarget, amount);
|
|
if (contrastRatio(candidate, background) >= minimumContrast) {
|
|
return candidate;
|
|
}
|
|
}
|
|
|
|
return highContrastTarget;
|
|
}
|
|
|
|
QColor contrastingTextColor(const QColor &color)
|
|
{
|
|
const QColor white{Qt::white};
|
|
const QColor black{Qt::black};
|
|
return contrastRatio(color, white) >= contrastRatio(color, black) ? white : black;
|
|
}
|
|
|
|
QColor blendColors(const QColor &base, const QColor &overlay, qreal overlayAmount)
|
|
{
|
|
const qreal clampedAmount = qBound(0.0, overlayAmount, 1.0);
|
|
const qreal baseAmount = 1.0 - clampedAmount;
|
|
return QColor::fromRgbF(base.redF() * baseAmount + overlay.redF() * clampedAmount,
|
|
base.greenF() * baseAmount + overlay.greenF() * clampedAmount,
|
|
base.blueF() * baseAmount + overlay.blueF() * clampedAmount,
|
|
1.0);
|
|
}
|
|
|
|
void writeAccentEntries(const KSharedConfig::Ptr &config, const QString &groupName, const QColor &accentColor)
|
|
{
|
|
auto group = KConfigGroup{config, groupName};
|
|
group.writeEntry("DecorationFocus", rgbString(accentColor));
|
|
group.writeEntry("DecorationHover", rgbString(accentColor));
|
|
group.writeEntry("ForegroundActive", rgbString(accentColor));
|
|
}
|
|
|
|
void tintBackgroundEntries(const KSharedConfig::Ptr &config, const QString &groupName, const QColor &accentColor, bool dark)
|
|
{
|
|
auto group = KConfigGroup{config, groupName};
|
|
const QColor defaultBase = dark ? QColor(38, 41, 47) : QColor(244, 246, 251);
|
|
const QColor baseNormal = group.readEntry("BackgroundNormal", defaultBase);
|
|
const QColor baseAlternate = group.readEntry("BackgroundAlternate", baseNormal);
|
|
const qreal normalBlend = dark ? 0.22 : 0.12;
|
|
const qreal alternateBlend = dark ? 0.16 : 0.08;
|
|
|
|
group.writeEntry("BackgroundNormal", rgbString(blendColors(baseNormal, accentColor, normalBlend)));
|
|
group.writeEntry("BackgroundAlternate", rgbString(blendColors(baseAlternate, accentColor, alternateBlend)));
|
|
}
|
|
|
|
void tuneForegroundEntries(const KSharedConfig::Ptr &config, const QString &groupName, const QColor &accentColor, bool dark)
|
|
{
|
|
auto group = KConfigGroup{config, groupName};
|
|
const QColor bgNormal = group.readEntry("BackgroundNormal", dark ? QColor(34, 37, 50) : QColor(252, 252, 252));
|
|
const QColor baseNormal = contrastingTextColor(bgNormal);
|
|
const QColor baseInactive = blendColors(baseNormal, bgNormal, dark ? 0.44 : 0.56);
|
|
const QColor baseLink = dark ? blendColors(accentColor, QColor(Qt::white), 0.28) : blendColors(accentColor, QColor(Qt::black), 0.24);
|
|
const QColor fgNormal = ensureContrast(baseNormal, bgNormal, MIN_NORMAL_CONTRAST);
|
|
const QColor fgInactive = ensureContrast(baseInactive, bgNormal, MIN_INACTIVE_CONTRAST);
|
|
const QColor fgLink = ensureContrast(baseLink, bgNormal, MIN_LINK_CONTRAST);
|
|
const QColor fgActive = ensureContrast(accentColor, bgNormal, MIN_LINK_CONTRAST);
|
|
|
|
group.writeEntry("ForegroundNormal", rgbString(fgNormal));
|
|
group.writeEntry("ForegroundInactive", rgbString(fgInactive));
|
|
group.writeEntry("ForegroundActive", rgbString(fgActive));
|
|
group.writeEntry("ForegroundLink", rgbString(fgLink));
|
|
}
|
|
}
|
|
|
|
MobileShellSettings::MobileShellSettings(QObject *parent)
|
|
: QObject{parent}
|
|
, m_config{KSharedConfig::openConfig(CONFIG_FILE)}
|
|
, m_kdeGlobalsConfig{KSharedConfig::openConfig()}
|
|
{
|
|
m_wallpaperThemeTimer.setSingleShot(true);
|
|
m_wallpaperThemeTimer.setInterval(450);
|
|
connect(&m_wallpaperThemeTimer, &QTimer::timeout, this, [this]() -> void {
|
|
setDarkThemeEnabled(m_pendingWallpaperThemeDark);
|
|
});
|
|
|
|
m_configWatcher = KConfigWatcher::create(m_config);
|
|
connect(m_configWatcher.data(), &KConfigWatcher::configChanged, this, [this](const KConfigGroup &group, const QByteArrayList &names) -> void {
|
|
Q_UNUSED(names)
|
|
if (group.name() == GENERAL_CONFIG_GROUP) {
|
|
Q_EMIT vibrationsEnabledChanged();
|
|
Q_EMIT vibrationDurationChanged();
|
|
Q_EMIT animationsEnabledChanged();
|
|
Q_EMIT dateInStatusBarChanged();
|
|
Q_EMIT statusBarScaleFactorChanged();
|
|
Q_EMIT showBatteryPercentageChanged();
|
|
Q_EMIT navigationPanelEnabledChanged();
|
|
Q_EMIT gesturePanelEnabledChanged();
|
|
Q_EMIT alwaysShowKeyboardToggleOnNavigationPanelChanged();
|
|
Q_EMIT keyboardButtonEnabledChanged();
|
|
Q_EMIT taskSwitcherPreviewsEnabledChanged();
|
|
Q_EMIT actionDrawerTopLeftModeChanged();
|
|
Q_EMIT actionDrawerTopRightModeChanged();
|
|
Q_EMIT convergenceModeEnabledChanged();
|
|
Q_EMIT autoHidePanelsEnabledChanged();
|
|
Q_EMIT gamingModeEnabledChanged();
|
|
Q_EMIT gamingDismissHintEnabledChanged();
|
|
Q_EMIT dynamicTilingEnabledChanged();
|
|
Q_EMIT dynamicTilingWindowRequestChanged();
|
|
Q_EMIT dynamicTilingWindowStateChanged();
|
|
Q_EMIT dynamicTilingLayoutRequestChanged();
|
|
Q_EMIT dynamicTilingLayoutStateChanged();
|
|
Q_EMIT snapLayoutsEnabledChanged();
|
|
Q_EMIT allowLogoutChanged();
|
|
Q_EMIT wallpaperThemeEnabledChanged();
|
|
}
|
|
if (group.name() == LOCKSCREEN_CONFIG_GROUP) {
|
|
Q_EMIT lockscreenLeftButtonActionChanged();
|
|
Q_EMIT lockscreenRightButtonActionChanged();
|
|
}
|
|
if (group.name() == QUICKSETTINGS_CONFIG_GROUP) {
|
|
Q_EMIT quickSettingsColumnsChanged();
|
|
}
|
|
});
|
|
|
|
m_kdeGlobalsConfigWatcher = KConfigWatcher::create(m_kdeGlobalsConfig);
|
|
connect(m_kdeGlobalsConfigWatcher.data(), &KConfigWatcher::configChanged, this, [this](const KConfigGroup &group, const QByteArrayList &names) -> void {
|
|
if (group.name() != KDE_GLOBALS_CONFIG_GROUP) {
|
|
return;
|
|
}
|
|
|
|
if (names.contains(QByteArrayLiteral("ColorScheme"))) {
|
|
Q_EMIT colorSchemeChanged();
|
|
Q_EMIT darkThemeEnabledChanged();
|
|
}
|
|
if (names.contains(QByteArrayLiteral("AccentColor")) || names.contains(QByteArrayLiteral("LastUsedCustomAccentColor"))) {
|
|
Q_EMIT accentColorChanged();
|
|
}
|
|
if (names.contains(QByteArrayLiteral("accentColorFromWallpaper"))) {
|
|
Q_EMIT wallpaperAccentEnabledChanged();
|
|
}
|
|
});
|
|
}
|
|
|
|
bool MobileShellSettings::vibrationsEnabled() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("vibrationsEnabled", true);
|
|
}
|
|
|
|
void MobileShellSettings::setVibrationsEnabled(bool vibrationsEnabled)
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
group.writeEntry("vibrationsEnabled", vibrationsEnabled, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
}
|
|
|
|
int MobileShellSettings::vibrationDuration() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("vibrationDuration", 10);
|
|
}
|
|
|
|
void MobileShellSettings::setVibrationDuration(int vibrationDuration)
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
group.writeEntry("vibrationDuration", vibrationDuration, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
}
|
|
|
|
bool MobileShellSettings::animationsEnabled() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("animationsEnabled", true);
|
|
}
|
|
|
|
void MobileShellSettings::setAnimationsEnabled(bool animationsEnabled)
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
group.writeEntry("animationsEnabled", animationsEnabled, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
}
|
|
|
|
bool MobileShellSettings::dateInStatusBar() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("dateInStatusBar", false);
|
|
}
|
|
|
|
void MobileShellSettings::setDateInStatusBar(bool dateInStatusBar)
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
group.writeEntry("dateInStatusBar", dateInStatusBar, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
}
|
|
|
|
float MobileShellSettings::statusBarScaleFactor() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("statusBarScaleFactor", 1.0);
|
|
}
|
|
|
|
void MobileShellSettings::setStatusBarScaleFactor(float statusBarScaleFactor)
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
group.writeEntry("statusBarScaleFactor", statusBarScaleFactor, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
}
|
|
|
|
bool MobileShellSettings::showBatteryPercentage() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("showBatteryPercentage", true);
|
|
}
|
|
|
|
void MobileShellSettings::setShowBatteryPercentage(bool showBatteryPercentage)
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
group.writeEntry("showBatteryPercentage", showBatteryPercentage, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
}
|
|
|
|
bool MobileShellSettings::navigationPanelEnabled() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("navigationPanelEnabled", true);
|
|
}
|
|
|
|
void MobileShellSettings::setNavigationPanelEnabled(bool navigationPanelEnabled)
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
group.writeEntry("navigationPanelEnabled", navigationPanelEnabled, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
|
|
updateNavigationBarsInPlasma();
|
|
}
|
|
|
|
bool MobileShellSettings::gesturePanelEnabled() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("gesturePanelEnabled", true);
|
|
}
|
|
|
|
void MobileShellSettings::setGesturePanelEnabled(bool gesturePanelEnabled)
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
group.writeEntry("gesturePanelEnabled", gesturePanelEnabled, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
|
|
updateNavigationBarsInPlasma();
|
|
}
|
|
|
|
bool MobileShellSettings::alwaysShowKeyboardToggleOnNavigationPanel() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("alwaysShowKeyboardToggleOnNavigationPanel", false);
|
|
}
|
|
|
|
void MobileShellSettings::setAlwaysShowKeyboardToggleOnNavigationPanel(bool alwaysShowKeyboardToggleOnNavigationPanel)
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
group.writeEntry("alwaysShowKeyboardToggleOnNavigationPanel", alwaysShowKeyboardToggleOnNavigationPanel, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
}
|
|
|
|
MobileShellSettings::ActionDrawerMode MobileShellSettings::actionDrawerTopLeftMode() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return (ActionDrawerMode)group.readEntry("actionDrawerTopLeftMode", (int)ActionDrawerMode::Pinned);
|
|
}
|
|
|
|
void MobileShellSettings::setActionDrawerTopLeftMode(ActionDrawerMode actionDrawerMode)
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
group.writeEntry("actionDrawerTopLeftMode", (int)actionDrawerMode, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
}
|
|
|
|
int MobileShellSettings::quickSettingsColumns() const
|
|
{
|
|
auto group = KConfigGroup{m_config, QUICKSETTINGS_CONFIG_GROUP};
|
|
return group.readEntry("quickSettingsColumns", 3);
|
|
}
|
|
|
|
void MobileShellSettings::setQuickSettingsColumns(int columns)
|
|
{
|
|
auto group = KConfigGroup{m_config, QUICKSETTINGS_CONFIG_GROUP};
|
|
group.writeEntry("quickSettingsColumns", columns, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
}
|
|
|
|
MobileShellSettings::ActionDrawerMode MobileShellSettings::actionDrawerTopRightMode() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return (ActionDrawerMode)group.readEntry("actionDrawerTopRightMode", (int)ActionDrawerMode::Expanded);
|
|
}
|
|
|
|
void MobileShellSettings::setActionDrawerTopRightMode(ActionDrawerMode actionDrawerMode)
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
group.writeEntry("actionDrawerTopRightMode", (int)actionDrawerMode, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
}
|
|
|
|
bool MobileShellSettings::convergenceModeEnabled() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("convergenceModeEnabled", false);
|
|
}
|
|
|
|
void MobileShellSettings::setConvergenceModeEnabled(bool enabled)
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
group.writeEntry("convergenceModeEnabled", enabled, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
|
|
// update environment settings
|
|
auto *job = new KIO::CommandLauncherJob(QStringLiteral("plasma-mobile-envmanager --apply-settings"), {});
|
|
job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoErrorHandlingEnabled));
|
|
job->setDesktopName(QStringLiteral("org.kde.plasma-mobile-envmanager"));
|
|
job->start();
|
|
}
|
|
|
|
QString MobileShellSettings::colorScheme() const
|
|
{
|
|
auto group = KConfigGroup{m_kdeGlobalsConfig, KDE_GLOBALS_CONFIG_GROUP};
|
|
return group.readEntry("ColorScheme", SHIFT_DARK_COLOR_SCHEME);
|
|
}
|
|
|
|
bool MobileShellSettings::darkThemeEnabled() const
|
|
{
|
|
return isDarkColorScheme(colorScheme());
|
|
}
|
|
|
|
void MobileShellSettings::setDarkThemeEnabled(bool enabled)
|
|
{
|
|
const QString currentColorScheme = colorScheme();
|
|
const QString nextColorScheme = effectiveColorSchemeName(enabled);
|
|
const QString plasmaTheme = enabled ? SHIFT_DARK_PLASMA_THEME : SHIFT_LIGHT_PLASMA_THEME;
|
|
QColor accentOverride;
|
|
|
|
if (wallpaperAccentEnabled() && m_lastWallpaperThemeColor.isValid() && m_lastWallpaperThemeColor.alpha() != 0) {
|
|
accentOverride = m_lastWallpaperThemeColor;
|
|
} else if (!wallpaperAccentEnabled()) {
|
|
const QColor manualAccent = accentColor();
|
|
if (manualAccent.isValid() && manualAccent.alpha() != 0) {
|
|
accentOverride = manualAccent;
|
|
}
|
|
}
|
|
|
|
if (currentColorScheme == nextColorScheme && nextColorScheme == baseColorSchemeName(enabled)) {
|
|
return;
|
|
}
|
|
|
|
if (accentOverride.isValid() && accentOverride.alpha() != 0) {
|
|
applyColorScheme({QStringLiteral("--accent-color"), accentOverride.name(QColor::HexRgb), nextColorScheme});
|
|
} else {
|
|
QProcess::execute(QStringLiteral("plasma-apply-colorscheme"), {nextColorScheme});
|
|
m_kdeGlobalsConfig->reparseConfiguration();
|
|
}
|
|
QProcess::execute(QStringLiteral("plasma-apply-desktoptheme"), {plasmaTheme});
|
|
|
|
Q_EMIT colorSchemeChanged();
|
|
Q_EMIT darkThemeEnabledChanged();
|
|
}
|
|
|
|
bool MobileShellSettings::wallpaperThemeEnabled() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("wallpaperThemeEnabled", false);
|
|
}
|
|
|
|
void MobileShellSettings::setWallpaperThemeEnabled(bool enabled)
|
|
{
|
|
if (wallpaperThemeEnabled() == enabled) {
|
|
return;
|
|
}
|
|
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
if (enabled) {
|
|
group.writeEntry(WALLPAPER_THEME_MANUAL_DARK_KEY, darkThemeEnabled(), KConfigGroup::Notify);
|
|
}
|
|
group.writeEntry("wallpaperThemeEnabled", enabled, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
|
|
if (!enabled) {
|
|
m_wallpaperThemeTimer.stop();
|
|
setDarkThemeEnabled(group.readEntry(WALLPAPER_THEME_MANUAL_DARK_KEY, darkThemeEnabled()));
|
|
}
|
|
|
|
Q_EMIT wallpaperThemeEnabledChanged();
|
|
}
|
|
|
|
void MobileShellSettings::applyWallpaperThemeColor(const QColor &color)
|
|
{
|
|
if (!wallpaperThemeEnabled() || !color.isValid() || color.alpha() == 0) {
|
|
return;
|
|
}
|
|
|
|
QColor opaqueColor = color;
|
|
opaqueColor.setAlpha(255);
|
|
|
|
const bool colorChanged = m_lastWallpaperThemeColor != opaqueColor;
|
|
m_lastWallpaperThemeColor = opaqueColor;
|
|
|
|
if (colorChanged) {
|
|
Q_EMIT wallpaperThemeColorChanged();
|
|
}
|
|
|
|
const qreal luminance = relativeLuminance(opaqueColor);
|
|
const bool shouldUseDarkTheme = luminance < 0.5;
|
|
const bool sameThemeBucket = darkThemeEnabled() == shouldUseDarkTheme;
|
|
|
|
if (wallpaperAccentEnabled() && colorChanged && sameThemeBucket) {
|
|
applyColorScheme({QStringLiteral("--accent-color"), opaqueColor.name(QColor::HexRgb), colorScheme()});
|
|
}
|
|
|
|
if (!m_wallpaperThemeTimer.isActive() && darkThemeEnabled() == shouldUseDarkTheme && !colorChanged) {
|
|
return;
|
|
}
|
|
|
|
m_pendingWallpaperThemeDark = shouldUseDarkTheme;
|
|
m_wallpaperThemeTimer.start();
|
|
}
|
|
|
|
QColor MobileShellSettings::wallpaperThemeColor() const
|
|
{
|
|
return m_lastWallpaperThemeColor;
|
|
}
|
|
|
|
QColor MobileShellSettings::accentColor() const
|
|
{
|
|
auto group = KConfigGroup{m_kdeGlobalsConfig, KDE_GLOBALS_CONFIG_GROUP};
|
|
return group.readEntry("AccentColor", QColor(Qt::transparent));
|
|
}
|
|
|
|
void MobileShellSettings::setAccentColor(const QColor &color)
|
|
{
|
|
if (!color.isValid() || color.alpha() == 0) {
|
|
resetAccentColor();
|
|
return;
|
|
}
|
|
|
|
QColor opaqueColor = color;
|
|
opaqueColor.setAlpha(255);
|
|
|
|
auto group = KConfigGroup{m_kdeGlobalsConfig, KDE_GLOBALS_CONFIG_GROUP};
|
|
group.writeEntry("accentColorFromWallpaper", false, KConfigGroup::Notify);
|
|
group.writeEntry("LastUsedCustomAccentColor", opaqueColor, KConfigGroup::Notify);
|
|
m_kdeGlobalsConfig->sync();
|
|
|
|
applyColorScheme({QStringLiteral("--accent-color"), opaqueColor.name(QColor::HexRgb), colorScheme()});
|
|
|
|
Q_EMIT wallpaperAccentEnabledChanged();
|
|
Q_EMIT accentColorChanged();
|
|
}
|
|
|
|
bool MobileShellSettings::wallpaperAccentEnabled() const
|
|
{
|
|
auto group = KConfigGroup{m_kdeGlobalsConfig, KDE_GLOBALS_CONFIG_GROUP};
|
|
return group.readEntry("accentColorFromWallpaper", false);
|
|
}
|
|
|
|
void MobileShellSettings::setWallpaperAccentEnabled(bool enabled)
|
|
{
|
|
if (wallpaperAccentEnabled() == enabled) {
|
|
return;
|
|
}
|
|
|
|
auto group = KConfigGroup{m_kdeGlobalsConfig, KDE_GLOBALS_CONFIG_GROUP};
|
|
group.writeEntry("accentColorFromWallpaper", enabled, KConfigGroup::Notify);
|
|
m_kdeGlobalsConfig->sync();
|
|
|
|
if (enabled && m_lastWallpaperThemeColor.isValid() && m_lastWallpaperThemeColor.alpha() != 0) {
|
|
applyColorScheme({QStringLiteral("--accent-color"), m_lastWallpaperThemeColor.name(QColor::HexRgb), colorScheme()});
|
|
Q_EMIT accentColorChanged();
|
|
}
|
|
|
|
if (!enabled) {
|
|
const QColor lastCustomColor = lastUsedCustomAccentColor();
|
|
if (lastCustomColor.isValid() && lastCustomColor.alpha() != 0) {
|
|
applyColorScheme({QStringLiteral("--accent-color"), lastCustomColor.name(QColor::HexRgb), colorScheme()});
|
|
} else {
|
|
resetAccentColor();
|
|
return;
|
|
}
|
|
}
|
|
|
|
Q_EMIT wallpaperAccentEnabledChanged();
|
|
}
|
|
|
|
void MobileShellSettings::resetAccentColor()
|
|
{
|
|
auto group = KConfigGroup{m_kdeGlobalsConfig, KDE_GLOBALS_CONFIG_GROUP};
|
|
group.writeEntry("accentColorFromWallpaper", false, KConfigGroup::Notify);
|
|
group.deleteEntry("AccentColor", KConfigGroup::Notify);
|
|
m_kdeGlobalsConfig->sync();
|
|
|
|
applyColorScheme({colorScheme()});
|
|
|
|
Q_EMIT wallpaperAccentEnabledChanged();
|
|
Q_EMIT accentColorChanged();
|
|
}
|
|
|
|
QColor MobileShellSettings::lastUsedCustomAccentColor() const
|
|
{
|
|
auto group = KConfigGroup{m_kdeGlobalsConfig, KDE_GLOBALS_CONFIG_GROUP};
|
|
return group.readEntry("LastUsedCustomAccentColor", QColor(Qt::transparent));
|
|
}
|
|
|
|
void MobileShellSettings::applyColorScheme(const QStringList &arguments)
|
|
{
|
|
QProcess::execute(QStringLiteral("plasma-apply-colorscheme"), arguments);
|
|
m_kdeGlobalsConfig->reparseConfiguration();
|
|
}
|
|
|
|
QString MobileShellSettings::effectiveColorSchemeName(bool dark) const
|
|
{
|
|
if (!wallpaperThemeEnabled() || !m_lastWallpaperThemeColor.isValid() || m_lastWallpaperThemeColor.alpha() == 0) {
|
|
return baseColorSchemeName(dark);
|
|
}
|
|
|
|
if (!ensureWallpaperColorScheme(m_lastWallpaperThemeColor, dark)) {
|
|
return baseColorSchemeName(dark);
|
|
}
|
|
|
|
return wallpaperColorSchemeName(dark);
|
|
}
|
|
|
|
bool MobileShellSettings::isDarkColorScheme(const QString &schemeName) const
|
|
{
|
|
return schemeName == SHIFT_DARK_COLOR_SCHEME || schemeName == SHIFT_WALLPAPER_DARK_COLOR_SCHEME;
|
|
}
|
|
|
|
bool MobileShellSettings::ensureWallpaperColorScheme(const QColor &accentColor, bool dark) const
|
|
{
|
|
if (!accentColor.isValid() || accentColor.alpha() == 0) {
|
|
return false;
|
|
}
|
|
|
|
const QString sourcePath =
|
|
QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("color-schemes/%1.colors").arg(baseColorSchemeName(dark)));
|
|
if (sourcePath.isEmpty()) {
|
|
qWarning() << "Unable to locate base Shift color scheme for wallpaper generation:" << baseColorSchemeName(dark);
|
|
return false;
|
|
}
|
|
|
|
const QString outputDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/color-schemes");
|
|
if (!QDir().mkpath(outputDir)) {
|
|
qWarning() << "Unable to create dynamic color-scheme directory:" << outputDir;
|
|
return false;
|
|
}
|
|
|
|
const QString outputPath = outputDir + QStringLiteral("/%1.colors").arg(wallpaperColorSchemeName(dark));
|
|
QFile::remove(outputPath);
|
|
if (!QFile::copy(sourcePath, outputPath)) {
|
|
qWarning() << "Unable to create wallpaper-derived color scheme:" << outputPath;
|
|
return false;
|
|
}
|
|
|
|
auto generatedConfig = KSharedConfig::openConfig(outputPath, KConfig::SimpleConfig);
|
|
auto generalGroup = KConfigGroup{generatedConfig, QStringLiteral("General")};
|
|
generalGroup.writeEntry("ColorScheme", wallpaperColorSchemeName(dark));
|
|
generalGroup.writeEntry("Name", wallpaperColorSchemeDisplayName(dark));
|
|
|
|
writeAccentEntries(generatedConfig, QStringLiteral("Colors:Button"), accentColor);
|
|
writeAccentEntries(generatedConfig, QStringLiteral("Colors:Complementary"), accentColor);
|
|
writeAccentEntries(generatedConfig, QStringLiteral("Colors:Header"), accentColor);
|
|
writeAccentEntries(generatedConfig, QStringLiteral("Colors:Header][Inactive"), accentColor);
|
|
writeAccentEntries(generatedConfig, QStringLiteral("Colors:Tooltip"), accentColor);
|
|
writeAccentEntries(generatedConfig, QStringLiteral("Colors:View"), accentColor);
|
|
writeAccentEntries(generatedConfig, QStringLiteral("Colors:Window"), accentColor);
|
|
|
|
tintBackgroundEntries(generatedConfig, QStringLiteral("Colors:Button"), accentColor, dark);
|
|
tintBackgroundEntries(generatedConfig, QStringLiteral("Colors:View"), accentColor, dark);
|
|
tintBackgroundEntries(generatedConfig, QStringLiteral("Colors:Window"), accentColor, dark);
|
|
tintBackgroundEntries(generatedConfig, QStringLiteral("Colors:Header"), accentColor, dark);
|
|
tintBackgroundEntries(generatedConfig, QStringLiteral("Colors:Header][Inactive"), accentColor, dark);
|
|
tintBackgroundEntries(generatedConfig, QStringLiteral("Colors:Tooltip"), accentColor, dark);
|
|
|
|
tuneForegroundEntries(generatedConfig, QStringLiteral("Colors:Button"), accentColor, dark);
|
|
tuneForegroundEntries(generatedConfig, QStringLiteral("Colors:View"), accentColor, dark);
|
|
tuneForegroundEntries(generatedConfig, QStringLiteral("Colors:Window"), accentColor, dark);
|
|
tuneForegroundEntries(generatedConfig, QStringLiteral("Colors:Header"), accentColor, dark);
|
|
tuneForegroundEntries(generatedConfig, QStringLiteral("Colors:Header][Inactive"), accentColor, dark);
|
|
tuneForegroundEntries(generatedConfig, QStringLiteral("Colors:Tooltip"), accentColor, dark);
|
|
|
|
auto complementaryGroup = KConfigGroup{generatedConfig, QStringLiteral("Colors:Complementary")};
|
|
const QColor complementaryBase = complementaryGroup.readEntry("BackgroundNormal", dark ? QColor(24, 27, 38) : QColor(42, 46, 50));
|
|
complementaryGroup.writeEntry("BackgroundNormal", rgbString(blendColors(complementaryBase, accentColor, dark ? 0.18 : 0.14)));
|
|
complementaryGroup.writeEntry("BackgroundAlternate", rgbString(blendColors(complementaryBase, accentColor, dark ? 0.12 : 0.09)));
|
|
tuneForegroundEntries(generatedConfig, QStringLiteral("Colors:Complementary"), accentColor, dark);
|
|
|
|
auto selectionGroup = KConfigGroup{generatedConfig, QStringLiteral("Colors:Selection")};
|
|
const QColor selectionBackground = blendColors(accentColor, dark ? QColor(18, 20, 28) : QColor(255, 255, 255), dark ? 0.82 : 0.9);
|
|
const QColor selectionAlternate = blendColors(selectionBackground, dark ? QColor(0, 0, 0) : QColor(255, 255, 255), dark ? 0.16 : 0.24);
|
|
const QColor selectionForeground = ensureContrast(contrastingTextColor(selectionBackground), selectionBackground, MIN_NORMAL_CONTRAST);
|
|
const QColor selectionInactive =
|
|
ensureContrast(blendColors(selectionForeground, selectionBackground, dark ? 0.4 : 0.52), selectionBackground, MIN_INACTIVE_CONTRAST);
|
|
const QColor selectionLink = ensureContrast(blendColors(accentColor, selectionForeground, dark ? 0.3 : 0.2), selectionBackground, MIN_LINK_CONTRAST);
|
|
selectionGroup.writeEntry("BackgroundNormal", rgbString(selectionBackground));
|
|
selectionGroup.writeEntry("BackgroundAlternate", rgbString(selectionAlternate));
|
|
selectionGroup.writeEntry("DecorationFocus", rgbString(accentColor));
|
|
selectionGroup.writeEntry("DecorationHover", rgbString(accentColor));
|
|
selectionGroup.writeEntry("ForegroundActive", rgbString(selectionForeground));
|
|
selectionGroup.writeEntry("ForegroundNormal", rgbString(selectionForeground));
|
|
selectionGroup.writeEntry("ForegroundInactive", rgbString(selectionInactive));
|
|
selectionGroup.writeEntry("ForegroundLink", rgbString(selectionLink));
|
|
|
|
auto wmGroup = KConfigGroup{generatedConfig, QStringLiteral("WM")};
|
|
const QColor currentActiveBackground = wmGroup.readEntry("activeBackground", accentColor);
|
|
const QColor tintedActiveBackground = blendColors(currentActiveBackground, accentColor, dark ? 0.42 : 0.26);
|
|
const QColor currentInactiveBackground = wmGroup.readEntry("inactiveBackground", tintedActiveBackground);
|
|
const QColor tintedInactiveBackground = blendColors(currentInactiveBackground, accentColor, dark ? 0.24 : 0.14);
|
|
const QColor activeForeground = ensureContrast(contrastingTextColor(tintedActiveBackground), tintedActiveBackground, MIN_NORMAL_CONTRAST);
|
|
const QColor inactiveForeground = ensureContrast(blendColors(contrastingTextColor(tintedInactiveBackground), tintedInactiveBackground, dark ? 0.36 : 0.52),
|
|
tintedInactiveBackground,
|
|
MIN_INACTIVE_CONTRAST);
|
|
wmGroup.writeEntry("activeBackground", rgbString(tintedActiveBackground));
|
|
wmGroup.writeEntry("activeBlend", rgbString(activeForeground));
|
|
wmGroup.writeEntry("activeForeground", rgbString(activeForeground));
|
|
wmGroup.writeEntry("inactiveBackground", rgbString(tintedInactiveBackground));
|
|
wmGroup.writeEntry("inactiveBlend", rgbString(inactiveForeground));
|
|
wmGroup.writeEntry("inactiveForeground", rgbString(inactiveForeground));
|
|
|
|
generatedConfig->sync();
|
|
return true;
|
|
}
|
|
|
|
bool MobileShellSettings::autoHidePanelsEnabled() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("autoHidePanelsEnabled", false);
|
|
}
|
|
|
|
void MobileShellSettings::setAutoHidePanelsEnabled(bool enabled)
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
group.writeEntry("autoHidePanelsEnabled", enabled, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
}
|
|
|
|
bool MobileShellSettings::gamingModeEnabled() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("gamingModeEnabled", false);
|
|
}
|
|
|
|
void MobileShellSettings::setGamingModeEnabled(bool enabled)
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
group.writeEntry("gamingModeEnabled", enabled, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
}
|
|
|
|
bool MobileShellSettings::gamingDismissHintEnabled() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("gamingDismissHintEnabled", true);
|
|
}
|
|
|
|
void MobileShellSettings::setGamingDismissHintEnabled(bool enabled)
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
group.writeEntry("gamingDismissHintEnabled", enabled, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
}
|
|
|
|
bool MobileShellSettings::dynamicTilingEnabled() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("dynamicTilingEnabled", true);
|
|
}
|
|
|
|
void MobileShellSettings::setDynamicTilingEnabled(bool enabled)
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
group.writeEntry("dynamicTilingEnabled", enabled, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
}
|
|
|
|
QString MobileShellSettings::dynamicTilingWindowRequestAction() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("dynamicTilingWindowRequestAction", QString{});
|
|
}
|
|
|
|
QString MobileShellSettings::dynamicTilingWindowRequestId() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("dynamicTilingWindowRequestId", QString{});
|
|
}
|
|
|
|
int MobileShellSettings::dynamicTilingWindowRequestSerial() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("dynamicTilingWindowRequestSerial", 0);
|
|
}
|
|
|
|
void MobileShellSettings::requestDynamicTilingWindowAction(const QString &windowId, const QString &action)
|
|
{
|
|
if (windowId.isEmpty() || action.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
const int serial = group.readEntry("dynamicTilingWindowRequestSerial", 0) + 1;
|
|
group.writeEntry("dynamicTilingWindowRequestId", windowId, KConfigGroup::Notify);
|
|
group.writeEntry("dynamicTilingWindowRequestAction", action, KConfigGroup::Notify);
|
|
group.writeEntry("dynamicTilingWindowRequestSerial", serial, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
|
|
Q_EMIT dynamicTilingWindowRequestChanged();
|
|
}
|
|
|
|
QStringList MobileShellSettings::dynamicTilingMaximizedWindowIds() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("dynamicTilingMaximizedWindowIds", QStringList{});
|
|
}
|
|
|
|
int MobileShellSettings::dynamicTilingWindowStateSerial() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("dynamicTilingWindowStateSerial", 0);
|
|
}
|
|
|
|
bool MobileShellSettings::isDynamicTilingWindowMaximized(const QString &windowId) const
|
|
{
|
|
if (windowId.isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
return dynamicTilingMaximizedWindowIds().contains(windowId);
|
|
}
|
|
|
|
void MobileShellSettings::reportDynamicTilingWindowState(const QStringList &maximizedWindowIds)
|
|
{
|
|
QStringList normalizedIds;
|
|
for (const QString &windowId : maximizedWindowIds) {
|
|
if (!windowId.isEmpty() && !normalizedIds.contains(windowId)) {
|
|
normalizedIds.push_back(windowId);
|
|
}
|
|
}
|
|
normalizedIds.sort(Qt::CaseSensitive);
|
|
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
if (group.readEntry("dynamicTilingMaximizedWindowIds", QStringList{}) == normalizedIds) {
|
|
return;
|
|
}
|
|
|
|
const int serial = group.readEntry("dynamicTilingWindowStateSerial", 0) + 1;
|
|
group.writeEntry("dynamicTilingMaximizedWindowIds", normalizedIds, KConfigGroup::Notify);
|
|
group.writeEntry("dynamicTilingWindowStateSerial", serial, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
|
|
Q_EMIT dynamicTilingWindowStateChanged();
|
|
}
|
|
|
|
QString MobileShellSettings::dynamicTilingLayoutRequestMode() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("dynamicTilingLayoutRequestMode", QString{});
|
|
}
|
|
|
|
int MobileShellSettings::dynamicTilingLayoutRequestSerial() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("dynamicTilingLayoutRequestSerial", 0);
|
|
}
|
|
|
|
void MobileShellSettings::requestDynamicTilingLayoutMode(const QString &mode)
|
|
{
|
|
if (mode.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
const int serial = group.readEntry("dynamicTilingLayoutRequestSerial", 0) + 1;
|
|
group.writeEntry("dynamicTilingLayoutRequestMode", mode, KConfigGroup::Notify);
|
|
group.writeEntry("dynamicTilingLayoutRequestSerial", serial, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
|
|
Q_EMIT dynamicTilingLayoutRequestChanged();
|
|
}
|
|
|
|
QString MobileShellSettings::dynamicTilingLayoutMode() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("dynamicTilingLayoutMode", QString{});
|
|
}
|
|
|
|
int MobileShellSettings::dynamicTilingLayoutWindowCount() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("dynamicTilingLayoutWindowCount", 0);
|
|
}
|
|
|
|
int MobileShellSettings::dynamicTilingLayoutStateSerial() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("dynamicTilingLayoutStateSerial", 0);
|
|
}
|
|
|
|
void MobileShellSettings::reportDynamicTilingLayoutState(const QString &mode, int windowCount)
|
|
{
|
|
const int normalizedWindowCount = windowCount < 0 ? 0 : windowCount;
|
|
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
if (group.readEntry("dynamicTilingLayoutMode", QString{}) == mode && group.readEntry("dynamicTilingLayoutWindowCount", 0) == normalizedWindowCount) {
|
|
return;
|
|
}
|
|
|
|
const int serial = group.readEntry("dynamicTilingLayoutStateSerial", 0) + 1;
|
|
group.writeEntry("dynamicTilingLayoutMode", mode, KConfigGroup::Notify);
|
|
group.writeEntry("dynamicTilingLayoutWindowCount", normalizedWindowCount, KConfigGroup::Notify);
|
|
group.writeEntry("dynamicTilingLayoutStateSerial", serial, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
|
|
Q_EMIT dynamicTilingLayoutStateChanged();
|
|
}
|
|
|
|
bool MobileShellSettings::snapLayoutsEnabled() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("snapLayoutsEnabled", true);
|
|
}
|
|
|
|
void MobileShellSettings::setSnapLayoutsEnabled(bool enabled)
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
group.writeEntry("snapLayoutsEnabled", enabled, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
}
|
|
|
|
void MobileShellSettings::updateNavigationBarsInPlasma()
|
|
{
|
|
// Do not update panels when not in Plasma Mobile
|
|
bool isMobilePlatform = KRuntimePlatform::runtimePlatform().contains("phone");
|
|
if (!isMobilePlatform) {
|
|
return;
|
|
}
|
|
|
|
auto message = QDBusMessage::createMethodCall(QLatin1String("org.kde.plasmashell"),
|
|
QLatin1String("/PlasmaShell"),
|
|
QLatin1String("org.kde.PlasmaShell"),
|
|
QLatin1String("evaluateScript"));
|
|
|
|
if (navigationPanelEnabled() || gesturePanelEnabled()) {
|
|
QString createNavigationPanelScript = R"(
|
|
let allPanels = panels();
|
|
let foundPanel = false;
|
|
for (var i = 0; i < allPanels.length; i++) {
|
|
if (allPanels[i].type === "org.kde.plasma.mobile.taskpanel") {
|
|
foundPanel = true;
|
|
}
|
|
}
|
|
|
|
if (!foundPanel) {
|
|
loadTemplate("org.kde.plasma.mobile.defaultNavigationPanel");
|
|
}
|
|
)";
|
|
|
|
message << createNavigationPanelScript;
|
|
} else {
|
|
QString deleteNavigationPanelScript = R"(
|
|
let allPanels = panels();
|
|
for (var i = 0; i < allPanels.length; i++) {
|
|
if (allPanels[i].type === "org.kde.plasma.mobile.taskpanel") {
|
|
allPanels[i].remove();
|
|
}
|
|
}
|
|
)";
|
|
|
|
message << deleteNavigationPanelScript;
|
|
}
|
|
|
|
// TODO check for error response
|
|
QDBusConnection::sessionBus().asyncCall(message);
|
|
}
|
|
|
|
bool MobileShellSettings::allowLogout() const
|
|
{
|
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
return group.readEntry("allowLogout", true);
|
|
}
|
|
|
|
MobileShellSettings::LockscreenButtonAction MobileShellSettings::lockscreenLeftButtonAction() const
|
|
{
|
|
auto group = KConfigGroup{m_config, LOCKSCREEN_CONFIG_GROUP};
|
|
return (LockscreenButtonAction)group.readEntry("lockscreenLeftButtonAction", (int)LockscreenButtonAction::None);
|
|
}
|
|
|
|
void MobileShellSettings::setLockscreenLeftButtonAction(const LockscreenButtonAction action)
|
|
{
|
|
auto group = KConfigGroup{m_config, LOCKSCREEN_CONFIG_GROUP};
|
|
group.writeEntry("lockscreenLeftButtonAction", (int)action, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
}
|
|
|
|
MobileShellSettings::LockscreenButtonAction MobileShellSettings::lockscreenRightButtonAction() const
|
|
{
|
|
auto group = KConfigGroup{m_config, LOCKSCREEN_CONFIG_GROUP};
|
|
return (LockscreenButtonAction)group.readEntry("lockscreenRightButtonAction", (int)LockscreenButtonAction::None);
|
|
}
|
|
|
|
void MobileShellSettings::setLockscreenRightButtonAction(const LockscreenButtonAction action)
|
|
{
|
|
auto group = KConfigGroup{m_config, LOCKSCREEN_CONFIG_GROUP};
|
|
group.writeEntry("lockscreenRightButtonAction", (int)action, KConfigGroup::Notify);
|
|
m_config->sync();
|
|
}
|