diff --git a/CMakeLists.txt b/CMakeLists.txt index faa27d3a..b97a9535 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,11 @@ include(FeatureSummary) add_definitions(-DQT_NO_URL_CAST_FROM_STRING) +ecm_setup_version(${PROJECT_VERSION} + VARIABLE_PREFIX PLASMA_MOBILE + VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/version.h +) + find_package(Qt${QT_MAJOR_VERSION} ${QT_MIN_VERSION} CONFIG REQUIRED Core Qml @@ -56,6 +61,7 @@ endif() find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS I18n KIO + DBusAddons Plasma PlasmaQuick Service @@ -90,6 +96,7 @@ add_subdirectory(containments) add_subdirectory(components) add_subdirectory(quicksettings) add_subdirectory(kcms) +add_subdirectory(kded) find_program(PlasmaOpenSettings plasma-open-settings) set_package_properties(PlasmaOpenSettings PROPERTIES diff --git a/components/mmplugin/CMakeLists.txt b/components/mmplugin/CMakeLists.txt index e8519c2d..07128ef4 100644 --- a/components/mmplugin/CMakeLists.txt +++ b/components/mmplugin/CMakeLists.txt @@ -11,6 +11,8 @@ target_link_libraries(ppc-mmqmlplugin Qt::Qml KF5::ModemManagerQt KF5::NetworkManagerQt + KF5::CoreAddons + KF5::I18n ) set_property(TARGET ppc-mmqmlplugin PROPERTY LIBRARY_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/org/kde/plasma/mm) diff --git a/components/mmplugin/signalindicator.cpp b/components/mmplugin/signalindicator.cpp index cf142880..3ebfd5b6 100644 --- a/components/mmplugin/signalindicator.cpp +++ b/components/mmplugin/signalindicator.cpp @@ -1,13 +1,15 @@ // SPDX-FileCopyrightText: 2021 Tobias Fella -// SPDX-FileCopyrightText: 2022 Devin Lin +// SPDX-FileCopyrightText: 2022-2023 Devin Lin // SPDX-License-Identifier: GPL-2.0-or-later +#include "signalindicator.h" + #include #include #include #include -#include "signalindicator.h" +#include SignalIndicator::SignalIndicator(QObject *parent) : QObject{parent} diff --git a/components/mmplugin/signalindicator.h b/components/mmplugin/signalindicator.h index e78a009f..e0f40005 100644 --- a/components/mmplugin/signalindicator.h +++ b/components/mmplugin/signalindicator.h @@ -22,8 +22,10 @@ class SignalIndicator : public QObject Q_PROPERTY(bool modemAvailable READ modemAvailable NOTIFY modemAvailableChanged) Q_PROPERTY(bool simLocked READ simLocked NOTIFY simLockedChanged) Q_PROPERTY(bool simEmpty READ simEmpty NOTIFY simEmptyChanged) + Q_PROPERTY(bool mobileDataSupported READ mobileDataSupported NOTIFY mobileDataSupportedChanged) Q_PROPERTY(bool mobileDataEnabled READ mobileDataEnabled WRITE setMobileDataEnabled NOTIFY mobileDataEnabledChanged) + Q_PROPERTY(bool needsAPNAdded READ needsAPNAdded NOTIFY mobileDataEnabledChanged) public: diff --git a/kded/CMakeLists.txt b/kded/CMakeLists.txt new file mode 100644 index 00000000..c144b57c --- /dev/null +++ b/kded/CMakeLists.txt @@ -0,0 +1,21 @@ +# SPDX-FileCopyrightText: 2023 Devin Lin +# SPDX-License-Identifier: GPL-2.0-or-later + +kcoreaddons_add_plugin(kded_plasma-mobile-start INSTALL_NAMESPACE "kf${QT_MAJOR_VERSION}/kded") + +target_sources(kded_plasma-mobile-start PRIVATE + startdaemon.cpp + settings.cpp + config.h + utils.h +) + +target_link_libraries(kded_plasma-mobile-start PRIVATE + Qt::Core + KF5::DBusAddons + KF5::ConfigWidgets + KF5::KIOGui + KF5::Notifications + KF5::Package +) + diff --git a/kded/config.h b/kded/config.h new file mode 100644 index 00000000..3443eca1 --- /dev/null +++ b/kded/config.h @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: 2023 Devin Lin +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include +#include +#include + +// kwinrc +const QMap> KWINRC_SETTINGS = { + {"Plugins", {{"blurEnabled", false}}}, + {"Wayland", {{"InputMethod", "/usr/share/applications/com.github.maliit.keyboard.desktop"}, {"VirtualKeyboardEnabled", true}}}, + {"Windows", + { + {"Placement", "Maximizing"}, + }}, + {"org.kde.kdecoration2", {{"NoPlugin", true}}}, +}; + +// applications-blacklistrc +// NOTE: we only write these entries if they are not already defined in the config +const QMap> APPLICATIONS_BLACKLIST_SETTINGS = { + {"Applications", + {{"blacklist", + "cuttlefish,org.kde.plasma.themeexplorer,org.kde.klipper,ciborium,syncmonitorhelper,org.kde.okular,wordview,assistant,assistant-qt5,designer,designer-" + "qt5,linguist,linguist-qt5,org.kde.perusecreator,UserFeedbackConsole,org.kde.kuserfeedback-console,avahi-discover,bssh,bvnc,ktelnetservice5,qv4l2," + "qvidcap"}}}}; + +// kdeglobals +// NOTE: we only write these entries if they are not already defined in the config +const QMap> KDEGLOBALS_SETTINGS = {{"General", {{"BrowserApplication", "angelfish"}}}}; diff --git a/kded/kded_plasma-mobile-start.json b/kded/kded_plasma-mobile-start.json new file mode 100644 index 00000000..03febd4d --- /dev/null +++ b/kded/kded_plasma-mobile-start.json @@ -0,0 +1,9 @@ +{ + "KPlugin": { + "Description": "Run initial tasks for Plasma Mobile during session startup", + "Name": "Plasma Mobile Start" + }, + "X-KDE-Kded-autoload": true, + "X-KDE-Kded-phase": 1, + "X-KDE-Library": "plasma-mobile" +} diff --git a/kded/settings.cpp b/kded/settings.cpp new file mode 100644 index 00000000..cb6f1e34 --- /dev/null +++ b/kded/settings.cpp @@ -0,0 +1,198 @@ +// SPDX-FileCopyrightText: 2023 Devin Lin +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "settings.h" +#include "config.h" +#include "utils.h" + +#include +#include + +#include +#include +#include +#include + +const QString CONFIG_FILE = QStringLiteral("plasmamobilerc"); +const QString INITIAL_START_CONFIG_GROUP = QStringLiteral("InitialStart"); +const QString SAVED_CONFIG_GROUP = QStringLiteral("SavedConfig"); + +const QString MOBILE_LOOK_AND_FEEL = QStringLiteral("org.kde.plasma.phone"); +const QString LOOK_AND_FEEL_KEY = QStringLiteral("LookAndFeelPackage"); + +Settings::Settings(QObject *parent) + : QObject{parent} + , m_isMobilePlatform{KRuntimePlatform::runtimePlatform().contains(QStringLiteral("phone"))} + , m_initialStartConfig{KSharedConfig::openConfig(CONFIG_FILE, KConfig::SimpleConfig)} + , m_kwinrcConfig{KSharedConfig::openConfig(QStringLiteral("kwinrc"), KConfig::SimpleConfig)} + , m_appBlacklistConfig{KSharedConfig::openConfig(QStringLiteral("applications-blacklistrc"), KConfig::SimpleConfig)} + , m_kdeglobalsConfig{KSharedConfig::openConfig(QStringLiteral("kdeglobals"), KConfig::SimpleConfig)} +{ +} + +Settings *Settings::self() +{ + static Settings *settings = new Settings; + return settings; +} + +bool Settings::shouldStartWizard() +{ + if (!m_isMobilePlatform) { + return false; + } + + const auto group = KConfigGroup{m_initialStartConfig, INITIAL_START_CONFIG_GROUP}; + return !group.readEntry("wizardRun", false); +} + +void Settings::setWizardFinished() +{ + auto group = KConfigGroup{m_initialStartConfig, INITIAL_START_CONFIG_GROUP}; + group.writeEntry("wizardRun", true, KConfigGroup::Notify); + m_initialStartConfig->sync(); +} + +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() +{ + // check look and feel + loadSavedConfigSetting(m_kdeglobalsConfig, QStringLiteral("kdeglobals"), QStringLiteral("KDE"), LOOK_AND_FEEL_KEY); + + // kwinrc + loadKeys(QStringLiteral("kwinrc"), m_kwinrcConfig, KWINRC_SETTINGS); + m_kwinrcConfig->sync(); + reloadKWinConfig(); + + // applications-blacklistrc + loadKeys(QStringLiteral("applications-blacklistrc"), m_appBlacklistConfig, APPLICATIONS_BLACKLIST_SETTINGS); + m_appBlacklistConfig->sync(); + + // kdeglobals + loadKeys(QStringLiteral("kdeglobals"), m_kdeglobalsConfig, KDEGLOBALS_SETTINGS); + m_kdeglobalsConfig->sync(); + + // save our changes + m_initialStartConfig->sync(); +} + +void Settings::applyMobileConfiguration() +{ + // check look and feel + KPackage::Package package = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/LookAndFeel")); + + if (package.path() != MOBILE_LOOK_AND_FEEL) { + // save it to be loaded when back on desktop + saveConfigSetting(QStringLiteral("kdeglobals"), QStringLiteral("KDE"), LOOK_AND_FEEL_KEY, package.path()); + + // ensure correct look and feel is applied + QProcess::execute("plasma-apply-lookandfeel", {"-a", MOBILE_LOOK_AND_FEEL}); + } + + // kwinrc + writeKeys(QStringLiteral("kwinrc"), m_kwinrcConfig, KWINRC_SETTINGS, false); + m_kwinrcConfig->sync(); + reloadKWinConfig(); + + // applications-blacklistrc + // NOTE: we only write entries if they are not already defined in the config + writeKeys(QStringLiteral("applications-blacklistrc"), m_appBlacklistConfig, APPLICATIONS_BLACKLIST_SETTINGS, true); + m_appBlacklistConfig->sync(); + + // kdeglobals + // NOTE: we only write entries if they are not already defined in the config + writeKeys(QStringLiteral("kdeglobals"), m_kdeglobalsConfig, KDEGLOBALS_SETTINGS, true); + m_kdeglobalsConfig->sync(); + + // save our changes + m_initialStartConfig->sync(); +} + +void Settings::writeKeys(const QString &fileName, KSharedConfig::Ptr &config, const QMap> &settings, bool overwriteOnlyIfEmpty) +{ + for (auto groupName : settings.keys()) { + auto group = KConfigGroup{config, groupName}; + + for (auto key : settings[groupName].keys()) { + if (!group.hasKey(key) || !overwriteOnlyIfEmpty) { + // save key + 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> &settings) +{ + for (auto groupName : settings.keys()) { + auto group = KConfigGroup{config, groupName}; + + for (auto key : settings[groupName].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) +{ + auto savedGroup = KConfigGroup{m_initialStartConfig, SAVED_CONFIG_GROUP}; + auto fileGroup = KConfigGroup{&savedGroup, fileName}; + auto keyGroup = KConfigGroup{&fileGroup, group}; + + if (!keyGroup.hasKey(key)) { + qCDebug(LOGGING_CATEGORY) << "In" << fileName << "set" << key << "to" << value; + keyGroup.writeEntry(key, value); + } +} + +// NOTE: this deletes the stored value from the config after loading +void Settings::loadSavedConfigSetting(KSharedConfig::Ptr &config, const QString &fileName, const QString &group, const QString &key) +{ + const auto savedGroup = KConfigGroup{m_initialStartConfig, SAVED_CONFIG_GROUP}; + const 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) { + qCDebug(LOGGING_CATEGORY) << "In" << fileName << "loading saved value of" << key << "which is" << value; + + if (value.isEmpty()) { // delete blank entries! + configGroup.deleteEntry(key); + } else { + configGroup.writeEntry(key, value, KConfigGroup::Notify); + } + } + + // remove saved config option + keyGroup.deleteEntry(key); +} + +void Settings::reloadKWinConfig() +{ + QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"), QStringLiteral("org.kde.KWin"), QStringLiteral("reloadConfig")); + QDBusConnection::sessionBus().send(message); +} diff --git a/kded/settings.h b/kded/settings.h new file mode 100644 index 00000000..28d3b179 --- /dev/null +++ b/kded/settings.h @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2023 Devin Lin +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include +#include + +class Settings : public QObject +{ + Q_OBJECT + +public: + Settings(QObject *parent = nullptr); + static Settings *self(); + + // whether the initial start wizard should be started + bool shouldStartWizard(); + + // set that the wizard has finished + void setWizardFinished(); + + // apply the configuration + void applyConfiguration(); + +private: + // loads the saved configuration, so it can be restored on desktop + void loadSavedConfiguration(); + + // applies our mobile configuration + void applyMobileConfiguration(); + + void writeKeys(const QString &fileName, KSharedConfig::Ptr &config, const QMap> &settings, bool overwriteOnlyIfEmpty); + void loadKeys(const QString &fileName, KSharedConfig::Ptr &config, const QMap> &settings); + void saveConfigSetting(const QString &fileName, const QString &group, const QString &key, const QVariant value); + void loadSavedConfigSetting(KSharedConfig::Ptr &config, const QString &fileName, const QString &group, const QString &key); + + void reloadKWinConfig(); + + // whether this is Plasma Mobile + bool m_isMobilePlatform; + + KSharedConfig::Ptr m_initialStartConfig; + KSharedConfig::Ptr m_kwinrcConfig; + KSharedConfig::Ptr m_appBlacklistConfig; + KSharedConfig::Ptr m_kdeglobalsConfig; +}; diff --git a/kded/startdaemon.cpp b/kded/startdaemon.cpp new file mode 100644 index 00000000..acfcf6d5 --- /dev/null +++ b/kded/startdaemon.cpp @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: 2023 Devin Lin +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include + +#include + +#include "settings.h" +#include "startdaemon.h" + +K_PLUGIN_CLASS_WITH_JSON(PlasmaMobileStartDaemon, "kded_plasma-mobile-start.json") + +PlasmaMobileStartDaemon::PlasmaMobileStartDaemon(QObject *parent, const QList &) + : KDEDModule{parent} +{ + // apply configuration + Settings::self()->applyConfiguration(); +} + +#include "startdaemon.moc" diff --git a/kded/startdaemon.h b/kded/startdaemon.h new file mode 100644 index 00000000..ce7fd2e4 --- /dev/null +++ b/kded/startdaemon.h @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Devin Lin +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +class PlasmaMobileStartDaemon : public KDEDModule +{ + Q_OBJECT + +public: + PlasmaMobileStartDaemon(QObject *parent, const QList &); +}; diff --git a/kded/utils.h b/kded/utils.h new file mode 100644 index 00000000..78050620 --- /dev/null +++ b/kded/utils.h @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2023 Devin Lin +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +static const QLoggingCategory &LOGGING_CATEGORY() +{ + static const QLoggingCategory category("plasma-mobile-initial-start"); + return category; +} diff --git a/look-and-feel/contents/defaults b/look-and-feel/contents/defaults index 92c73541..22ed036d 100644 --- a/look-and-feel/contents/defaults +++ b/look-and-feel/contents/defaults @@ -15,11 +15,3 @@ Theme=breeze [kdeglobals][General] ColorScheme=BreezeLight Name=Breeze - -## kwinrc - -[kwinrc][Windows] -Placement=Maximizing - -[kwinrc][org.kde.kdecoration2] -NoPlugin=true