Git commit 93f9ef0304f300dc3952ac9a25cbd82996eec263 by Henri Chain. Committed on 28/04/2021 at 16:02. Pushed by hchain into branch 'master'.
[startplasma] Migrate autostart scripts to .desktop files M +7 -5 doc/kcontrol/autostart/index.docbook M +1 -1 kcms/autostart/CMakeLists.txt M +59 -72 kcms/autostart/autostartmodel.cpp M +7 -2 kcms/autostart/autostartmodel.h M +5 -2 kcms/autostart/package/contents/ui/main.qml M +2 -0 libkworkspace/CMakeLists.txt A +34 -0 libkworkspace/autostartscriptdesktopfile.cpp [License: LGPL(v2.1+)] A +32 -0 libkworkspace/autostartscriptdesktopfile.h [License: LGPL(v2.1+)] M +10 -38 startkde/plasma-session/startup.cpp M +48 -0 startkde/startplasma.cpp M +1 -0 startkde/startplasma.h https://invent.kde.org/plasma/plasma-workspace/commit/93f9ef0304f300dc3952ac9a25cbd82996eec263 diff --git a/doc/kcontrol/autostart/index.docbook b/doc/kcontrol/autostart/index.docbook index e5e7ed442..240f79ed0 100644 --- a/doc/kcontrol/autostart/index.docbook +++ b/doc/kcontrol/autostart/index.docbook @@ -31,8 +31,10 @@ <note><para>Please note that in this module all changes are immediately applied.</para></note> -<para>The program scans <filename>$HOME/.config/autostart/</filename>, -<filename class="directory">$HOME/.config/plasma-workspace/env</filename> and <filename class="directory">$HOME/.config/plasma-workspace/shutdown</filename> folders to check what programs and scripts are already there and displays them. It allows you to manage them easily. +<para>The program scans <filename>$HOME/.config/autostart/</filename> for applications and login scripts, <filename class="directory">$HOME/.config/plasma-workspace/env</filename> for pre-startup scripts and <filename class="directory">$HOME/.config/plasma-workspace/shutdown</filename> for logout scripts to check what programs and scripts are already there and displays them. It allows you to manage them easily. +</para> + +<para>Login scripts are <filename class="extension">.desktop</filename> files with a <literal>X-KDE-AutostartScript=true</literal> key. Pre-startup scripts are run earlier and can be used to set environment variables. </para> <note><para>Note that you can change the location of your <filename class="directory">Autostart</filename> @@ -87,10 +89,10 @@ This column shows the name of the program or script you want to start with &plas <varlistentry><term><guilabel>Properties</guilabel></term> <listitem> <para> -This button is only shown when you hover the item with the mouse pointer. The button (only enabled for programs &ie; <filename class="extension">.desktop</filename> files) allows you to change the properties of the program or script. You have general properties, permissions properties, a preview when applicable, and properties related to the application for programs. The default command is extracted from the <filename class="extension">.desktop</filename> file from the <literal>Exec</literal> key. +This button is only shown when you hover the item with the mouse pointer. The button (only enabled for programs and login scripts &ie; <filename class="extension">.desktop</filename> files) allows you to change the properties of the program or script. You have general properties, permissions properties, a preview when applicable, and properties related to the application or login script. The default command is extracted from the <filename class="extension">.desktop</filename> file from the <literal>Exec</literal> key. </para> <para> -For a script, the command is the path to the script and can not be modified. +For a logout script, the command is the path to the script and can not be modified. </para> </listitem> </varlistentry> @@ -126,7 +128,7 @@ This will copy the program <filename class="extension">.desktop</filename> file <varlistentry><term><guimenuitem>Add Login Script...</guimenuitem></term> <listitem> <para> -This item opens a dialog that asks you for the location of the script you want to add. Scripts set to run on login are copied or symlinked in <filename class="directory">$HOME/.config/autostart</filename> and will be run during Plasma startup. +This item opens a dialog that asks you for the location of the script you want to add. Scripts set to run on login will have a corresponding <filename class="extension">.desktop</filename> file created in your <filename class="directory">Autostart</filename> folder and will be run during Plasma startup. </para> </listitem> </varlistentry> diff --git a/kcms/autostart/CMakeLists.txt b/kcms/autostart/CMakeLists.txt index 93644f68c..f36f4d742 100644 --- a/kcms/autostart/CMakeLists.txt +++ b/kcms/autostart/CMakeLists.txt @@ -7,7 +7,7 @@ set(kcm_autostart_PART_SRCS add_library(kcm_autostart MODULE ${kcm_autostart_PART_SRCS}) -target_link_libraries(kcm_autostart KF5::I18n KF5::KIOCore KF5::KIOWidgets KF5::QuickAddons) +target_link_libraries(kcm_autostart KF5::I18n KF5::KIOCore KF5::KIOWidgets KF5::QuickAddons PW::KWorkspace) kcoreaddons_desktop_to_json(kcm_autostart "package/metadata.desktop") diff --git a/kcms/autostart/autostartmodel.cpp b/kcms/autostart/autostartmodel.cpp index 94d800c84..777e2b3f0 100644 --- a/kcms/autostart/autostartmodel.cpp +++ b/kcms/autostart/autostartmodel.cpp @@ -34,16 +34,15 @@ #include <KLocalizedString> #include <KOpenWithDialog> #include <KPropertiesDialog> - -#include <optional> +#include <autostartscriptdesktopfile.h> // FDO user autostart directories are -// .config/autostart which has .desktop files executed by klaunch +// .config/autostart which has .desktop files executed by klaunch or systemd, some of which might be scripts // Then we have Plasma-specific locations which run scripts -// .config/autostart-scripts which has scripts executed by ksmserver -// .config/plasma-workspace/shutdown which has scripts executed by startkde -// .config/plasma-workspace/env which has scripts executed by startkde +// .config/autostart-scripts which has scripts executed by plasma_session (now migrated to .desktop files) +// .config/plasma-workspace/shutdown which has scripts executed by plasma-shutdown +// .config/plasma-workspace/env which has scripts executed by startplasma // in the case of pre-startup they have to end in .sh // everywhere else it doesn't matter @@ -52,7 +51,7 @@ // share/autostart shouldn't be an option as this should be reserved for global autostart entries -static std::optional<AutostartEntry> loadDesktopEntry(const QString &fileName) +std::optional<AutostartEntry> AutostartModel::loadDesktopEntry(const QString &fileName) { KDesktopFile config(fileName); const KConfigGroup grp = config.desktopGroup(); @@ -75,7 +74,7 @@ static std::optional<AutostartEntry> loadDesktopEntry(const QString &fileName) const auto lstEntry = grp.readXdgListEntry("OnlyShowIn"); const bool onlyInPlasma = lstEntry.contains(QLatin1String("KDE")); const QString iconName = config.readIcon(); - + const auto kind = AutostartScriptDesktopFile::isAutostartScript(config) ? XdgScripts : XdgAutoStart; // .config/autostart load desktop at startup const QString tryCommand = grp.readEntry("TryExec"); // Try to filter out entries that point to nonexistant programs @@ -85,38 +84,28 @@ static std::optional<AutostartEntry> loadDesktopEntry(const QString &fileName) return {}; } - return std::optional<AutostartEntry>({name, - AutostartModel::AutostartEntrySource::XdgAutoStart, // .config/autostart load desktop at startup - enabled, - fileName, - onlyInPlasma, - iconName}); + return AutostartEntry{name, kind, enabled, fileName, onlyInPlasma, iconName}; } AutostartModel::AutostartModel(QObject *parent) : QAbstractListModel(parent) + , m_xdgConfigPath(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation)) + , m_xdgAutoStartPath(m_xdgConfigPath.filePath(QStringLiteral("autostart"))) { } -QString AutostartModel::XdgAutoStartPath() const -{ - return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1String("/autostart/"); -} - void AutostartModel::load() { beginResetModel(); m_entries.clear(); - QDir autostartdir(XdgAutoStartPath()); - if (!autostartdir.exists()) { - autostartdir.mkpath(XdgAutoStartPath()); - } - - autostartdir.setFilter(QDir::Files | QDir::NoDotAndDotDot); + // Creates if doesn't already exist + m_xdgAutoStartPath.mkpath(QStringLiteral(".")); - const auto filesInfo = autostartdir.entryInfoList(); + // Needed to add all script entries after application entries + QVector<AutostartEntry> scriptEntries; + const auto filesInfo = m_xdgAutoStartPath.entryInfoList(QDir::Files); for (const QFileInfo &fi : filesInfo) { if (!KDesktopFile::isDesktopFile(fi.fileName())) { continue; @@ -128,12 +117,16 @@ void AutostartModel::load() continue; } - m_entries.push_back(entry.value()); + if (entry->source == XdgScripts) { + scriptEntries.push_back(entry.value()); + } else { + m_entries.push_back(entry.value()); + } } - loadScriptsFromDir(QStringLiteral("/autostart-scripts/"), AutostartModel::AutostartEntrySource::XdgScripts); - // Treat them as XdgScripts so they appear together in the UI - loadScriptsFromDir(QStringLiteral("/plasma-workspace/env/"), AutostartModel::AutostartEntrySource::XdgScripts); + m_entries.append(scriptEntries); + + loadScriptsFromDir(QStringLiteral("/plasma-workspace/env/"), AutostartModel::AutostartEntrySource::PlasmaEnvScripts); loadScriptsFromDir(QStringLiteral("/plasma-workspace/shutdown/"), AutostartModel::AutostartEntrySource::PlasmaShutdown); @@ -142,15 +135,11 @@ void AutostartModel::load() void AutostartModel::loadScriptsFromDir(const QString &subDir, AutostartModel::AutostartEntrySource kind) { - const QString path = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + subDir; - QDir dir(path); - if (!dir.exists()) { - dir.mkpath(path); - } + QDir dir(m_xdgConfigPath.filePath(subDir)); + // Creates if doesn't already exist + dir.mkpath(QStringLiteral(".")); - dir.setFilter(QDir::Files | QDir::NoDotAndDotDot); - - const auto autostartDirFilesInfo = dir.entryInfoList(); + const auto autostartDirFilesInfo = dir.entryInfoList(QDir::Files); for (const QFileInfo &fi : autostartDirFilesInfo) { QString fileName = fi.absoluteFilePath(); const bool isSymlink = fi.isSymLink(); @@ -223,7 +212,7 @@ void AutostartModel::addApplication(const KService::Ptr &service) // https://bugs.launchpad.net/ubuntu/+source/kde-workspace/+bug/923360 if (service->desktopEntryName().isEmpty() || service->entryPath().isEmpty()) { // create a new desktop file in s_desktopPath - desktopPath = XdgAutoStartPath() + service->name() + QStringLiteral(".desktop"); + desktopPath = m_xdgAutoStartPath.filePath(service->name() + QStringLiteral(".desktop")); KDesktopFile desktopFile(desktopPath); KConfigGroup kcg = desktopFile.desktopGroup(); @@ -236,7 +225,7 @@ void AutostartModel::addApplication(const KService::Ptr &service) desktopFile.sync(); } else { - desktopPath = XdgAutoStartPath() + service->desktopEntryName() + QStringLiteral(".desktop"); + desktopPath = m_xdgAutoStartPath.filePath(service->desktopEntryName() + QStringLiteral(".desktop")); QFile::remove(desktopPath); @@ -320,8 +309,6 @@ void AutostartModel::addScript(const QUrl &url, AutostartModel::AutostartEntrySo } const QString fileName = url.fileName(); - int index = 0; - QString folder; if (kind == AutostartModel::AutostartEntrySource::XdgScripts) { int lastLoginScript = -1; @@ -332,44 +319,44 @@ void AutostartModel::addScript(const QUrl &url, AutostartModel::AutostartEntrySo ++lastLoginScript; } - index = lastLoginScript + 1; - folder = QStringLiteral("/autostart-scripts/"); + AutostartScriptDesktopFile desktopFile(fileName, file.filePath()); + insertScriptEntry(lastLoginScript + 1, fileName, desktopFile.fileName(), kind); } else if (kind == AutostartModel::AutostartEntrySource::PlasmaShutdown) { - index = m_entries.size(); - folder = QStringLiteral("/plasma-workspace/shutdown/"); + const QUrl destinationScript = QUrl::fromLocalFile(QDir(m_xdgConfigPath.filePath(QStringLiteral("/plasma-workspace/shutdown/"))).filePath(fileName)); + KIO::CopyJob *job = KIO::link(url, destinationScript, KIO::HideProgressInfo); + job->setAutoRename(true); + job->setProperty("finalUrl", destinationScript); + + connect(job, &KIO::CopyJob::renamed, this, [](KIO::Job *job, const QUrl &from, const QUrl &to) { + Q_UNUSED(from) + // in case the destination filename had to be renamed + job->setProperty("finalUrl", to); + }); + + connect(job, &KJob::finished, this, [this, url, kind](KJob *theJob) { + if (theJob->error()) { + qWarning() << "Could not add script entry" << theJob->errorString(); + return; + } + const QUrl dest = theJob->property("finalUrl").toUrl(); + insertScriptEntry(m_entries.size(), dest.fileName(), dest.path(), kind); + }); + + job->start(); } else { Q_ASSERT(0); } +} - QUrl destinationScript = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + folder + fileName); - KIO::CopyJob *job = KIO::link(url, destinationScript, KIO::HideProgressInfo); - job->setAutoRename(true); - job->setProperty("finalUrl", destinationScript); - - connect(job, &KIO::CopyJob::renamed, this, [](KIO::Job *job, const QUrl &from, const QUrl &to) { - Q_UNUSED(from) - // in case the destination filename had to be renamed - job->setProperty("finalUrl", to); - }); - - connect(job, &KJob::finished, this, [this, index, url, kind](KJob *theJob) { - if (theJob->error()) { - qWarning() << "Could add script entry" << theJob->errorString(); - return; - } - - beginInsertRows(QModelIndex(), index, index); - - const QUrl dest = theJob->property("finalUrl").toUrl(); - - AutostartEntry entry = AutostartEntry{dest.fileName(), kind, true, dest.path(), false, QStringLiteral("dialog-scripts")}; +void AutostartModel::insertScriptEntry(int index, const QString &name, const QString &path, AutostartEntrySource kind) +{ + beginInsertRows(QModelIndex(), index, index); - m_entries.insert(index, entry); + AutostartEntry entry = AutostartEntry{name, kind, true, path, false, QStringLiteral("dialog-scripts")}; - endInsertRows(); - }); + m_entries.insert(index, entry); - job->start(); + endInsertRows(); } void AutostartModel::removeEntry(int row) diff --git a/kcms/autostart/autostartmodel.h b/kcms/autostart/autostartmodel.h index 201725d5f..f12909f76 100644 --- a/kcms/autostart/autostartmodel.h +++ b/kcms/autostart/autostartmodel.h @@ -20,8 +20,10 @@ #define AUTOSTARTMODEL_H #include <QAbstractListModel> +#include <QDir> #include <KService> +#include <optional> struct AutostartEntry; class QQuickItem; @@ -46,7 +48,7 @@ public: XdgAutoStart = 0, XdgScripts = 1, PlasmaShutdown = 2, - PlasmaStart = 3, + PlasmaEnvScripts = 3, }; Q_ENUM(AutostartEntrySource) @@ -69,8 +71,11 @@ Q_SIGNALS: private: void addApplication(const KService::Ptr &service); void loadScriptsFromDir(const QString &subDir, AutostartEntrySource kind); - QString XdgAutoStartPath() const; + void insertScriptEntry(int index, const QString &name, const QString &path, AutostartModel::AutostartEntrySource kind); + static std::optional<AutostartEntry> loadDesktopEntry(const QString &fileName); + QDir m_xdgConfigPath; + QDir m_xdgAutoStartPath; QVector<AutostartEntry> m_entries; }; diff --git a/kcms/autostart/package/contents/ui/main.qml b/kcms/autostart/package/contents/ui/main.qml index 644c417cc..3ef2a2c5a 100644 --- a/kcms/autostart/package/contents/ui/main.qml +++ b/kcms/autostart/package/contents/ui/main.qml @@ -75,7 +75,7 @@ KCM.ScrollViewKCM { text: i18n("Properties") icon.name: "document-properties" onTriggered: kcm.model.editApplication(model.index, root) - visible: model.source === AutostartModel.XdgAutoStart + visible: model.source === AutostartModel.XdgAutoStart || model.source === AutostartModel.XdgScripts }, Kirigami.Action { text: i18n("Remove") @@ -91,9 +91,12 @@ KCM.ScrollViewKCM { if (section == AutostartModel.XdgAutoStart) { return i18n("Applications") } - if (section == AutostartModel.XdgScripts || section == AutostartModel.PlasmaStart) { + if (section == AutostartModel.XdgScripts) { return i18n("Login Scripts") } + if (section == AutostartModel.PlasmaEnvScripts) { + return i18n("Pre-startup Scripts") + } if (section == AutostartModel.PlasmaShutdown) { return i18n("Logout Scripts") } diff --git a/libkworkspace/CMakeLists.txt b/libkworkspace/CMakeLists.txt index cca11dc2a..015c5181f 100644 --- a/libkworkspace/CMakeLists.txt +++ b/libkworkspace/CMakeLists.txt @@ -4,6 +4,7 @@ set(kworkspace_LIB_SRCS kdisplaymanager.cpp sessionmanagement.cpp sessionmanagementbackend.cpp updatelaunchenvjob.cpp + autostartscriptdesktopfile.cpp ) add_definitions(-DTRANSLATION_DOMAIN=\"libkworkspace\") @@ -73,6 +74,7 @@ install( FILES kdisplaymanager.h kworkspace.h sessionmanagement.h updatelaunchenvjob.h + autostartscriptdesktopfile.h ${CMAKE_CURRENT_BINARY_DIR}/config-libkworkspace.h ${CMAKE_CURRENT_BINARY_DIR}/kworkspace_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR}/kworkspace5 COMPONENT Devel ) diff --git a/libkworkspace/autostartscriptdesktopfile.cpp b/libkworkspace/autostartscriptdesktopfile.cpp new file mode 100644 index 000000000..4211267e6 --- /dev/null +++ b/libkworkspace/autostartscriptdesktopfile.cpp @@ -0,0 +1,34 @@ +/* + * SPDX-FileCopyrightText: 2021 Henri Chain <[email protected]> + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include "autostartscriptdesktopfile.h" +#include <KConfigGroup> +#include <KDesktopFile> +#include <QDir> +#include <QStandardPaths> + +static const auto autostartScriptKey = QStringLiteral("X-KDE-AutostartScript"); + +QDir AutostartScriptDesktopFile::autostartLocation() +{ + return QDir(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation)).filePath("autostart"); +} + +AutostartScriptDesktopFile::AutostartScriptDesktopFile(const QString &name, const QString &execPath) + : KDesktopFile(autostartLocation().absoluteFilePath(name + QStringLiteral(".desktop"))) +{ + KConfigGroup kcg = desktopGroup(); + kcg.writeEntry("Type", "Application"); + kcg.writeEntry("Name", name); + kcg.writeEntry("Exec", execPath); + kcg.writeEntry("Icon", "dialog-scripts"); + kcg.writeEntry(autostartScriptKey, "true"); + kcg.writeEntry("Path", ""); +} + +bool AutostartScriptDesktopFile::isAutostartScript(const KDesktopFile &file) +{ + return file.desktopGroup().readEntry<bool>(autostartScriptKey, false); +} diff --git a/libkworkspace/autostartscriptdesktopfile.h b/libkworkspace/autostartscriptdesktopfile.h new file mode 100644 index 000000000..451c00262 --- /dev/null +++ b/libkworkspace/autostartscriptdesktopfile.h @@ -0,0 +1,32 @@ +/* + * SPDX-FileCopyrightText: 2021 Henri Chain <[email protected]> + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#pragma once +#include "kworkspace_export.h" + +#include <KDesktopFile> +#include <QDir> +#include <QString> + +/** + * Corresponds to a .desktop file in $XDG_CONFIG_HOME/autostart that points to + * an autostart script and has X-KDE-AutostartScript=true + */ +class KWORKSPACE_EXPORT AutostartScriptDesktopFile : public KDesktopFile +{ +public: + explicit AutostartScriptDesktopFile(const QString &name, const QString &execPath); + + /** + * Checks whether this KDesktopFile has X-KDE-AutostartScript=true + */ + static bool isAutostartScript(const KDesktopFile &file); + + /** + * The location of autostart .desktop application and script files + * ($XDG_CONFIG_HOME/autostart) + */ + static QDir autostartLocation(); +}; diff --git a/startkde/plasma-session/startup.cpp b/startkde/plasma-session/startup.cpp index e563e3b80..81afee89b 100644 --- a/startkde/plasma-session/startup.cpp +++ b/startkde/plasma-session/startup.cpp @@ -132,15 +132,14 @@ public: : Phase(autostart, parent) { } - void runUserAutostart(); - bool migrateKDE4Autostart(const QString &folder); + void migrateKDE4Autostart(); void start() override { qCDebug(PLASMA_SESSION) << "Phase 2"; + migrateKDE4Autostart(); addSubjob(new AutoStartAppsJob(m_autostart, 2)); addSubjob(new KDEDInitJob()); - runUserAutostart(); } }; @@ -352,48 +351,21 @@ void RestoreSessionJob::start() connect(watcher, &QDBusPendingCallWatcher::finished, watcher, &QObject::deleteLater); } -void StartupPhase2::runUserAutostart() +void StartupPhase2::migrateKDE4Autostart() { - // Now let's execute the scripts in the KDE-specific autostart-scripts folder. + // Migrate user autostart from kde4 + Kdelibs4Migration migration; + if (!migration.kdeHomeFound()) { + return; + } + const QString autostartFolder = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QDir::separator() + QStringLiteral("autostart-scripts"); - QDir dir(autostartFolder); if (!dir.exists()) { - // Create dir in all cases, so that users can find it :-) dir.mkpath(QStringLiteral(".")); - - if (!migrateKDE4Autostart(autostartFolder)) { - return; - } } - const QStringList entries = dir.entryList(QDir::Files); - for (const QString &file : entries) { - // Don't execute backup files - if (!file.endsWith(QLatin1Char('~')) && !file.endsWith(QLatin1String(".bak")) && (file[0] != QLatin1Char('%') || !file.endsWith(QLatin1Char('%'))) - && (file[0] != QLatin1Char('#') || !file.endsWith(QLatin1Char('#')))) { - const QString fullPath = dir.absolutePath() + QLatin1Char('/') + file; - - qCInfo(PLASMA_SESSION) << "Starting autostart script " << fullPath; - auto p = new KProcess; // deleted in onFinished lambda - p->setProgram(fullPath); - p->start(); - connect(p, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [p](int exitCode) { - qCInfo(PLASMA_SESSION) << "autostart script" << p->program() << "finished with exit code " << exitCode; - p->deleteLater(); - }); - } - } -} - -bool StartupPhase2::migrateKDE4Autostart(const QString &autostartFolder) -{ - // Migrate user autostart from kde4 - Kdelibs4Migration migration; - if (!migration.kdeHomeFound()) { - return false; - } // KDEHOME/Autostart was the default value for KGlobalSettings::autostart() QString oldAutostart = migration.kdeHome() + QStringLiteral("/Autostart"); // That path could be customized in kdeglobals @@ -420,7 +392,7 @@ bool StartupPhase2::migrateKDE4Autostart(const QString &autostartFolder) qCWarning(PLASMA_SESSION) << "Error copying" << src << "to" << dest; } } - return true; + return; } AutoStartAppsJob::AutoStartAppsJob(const AutoStart &autostart, int phase) diff --git a/startkde/startplasma.cpp b/startkde/startplasma.cpp index 997f91e88..f6b078e7e 100644 --- a/startkde/startplasma.cpp +++ b/startkde/startplasma.cpp @@ -34,6 +34,7 @@ #include <unistd.h> +#include <autostartscriptdesktopfile.h> #include <updatelaunchenvjob.h> #include "startplasma.h" @@ -538,6 +539,9 @@ bool startPlasmaSession(bool wayland) } }); + // Create .desktop files for the scripts in .config/autostart-scripts + migrateUserScriptsAutostart(); + if (!useSystemdBoot()) { qCDebug(PLASMA_STARTUP) << "Using classic boot"; QProcess startPlasmaSession; @@ -611,3 +615,47 @@ void waitForKonqi() } } } + +static void migrateUserScriptsAutostart() +{ + QDir configLocation(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation)); + QDir autostartScriptsLocation(configLocation.filePath(QStringLiteral("autostart-scripts"))); + if (!autostartScriptsLocation.exists()) { + return; + } + const QDir autostartScriptsMovedLocation(configLocation.filePath(QStringLiteral("old-autostart-scripts"))); + const auto entries = autostartScriptsLocation.entryInfoList(QDir::Files); + for (const auto &info : entries) { + const auto scriptName = info.fileName(); + const auto scriptPath = info.absoluteFilePath(); + const auto scriptMovedPath = autostartScriptsMovedLocation.filePath(scriptName); + + // Don't migrate backup files + if (scriptName.endsWith(QLatin1Char('~')) || scriptName.endsWith(QLatin1String(".bak")) + || (scriptName[0] == QLatin1Char('%') && scriptName.endsWith(QLatin1Char('%'))) + || (scriptName[0] == QLatin1Char('#') && scriptName.endsWith(QLatin1Char('#')))) { + qCDebug(PLASMA_STARTUP) << "Not migrating backup autostart script" << scriptName; + continue; + } + + // Migrate autostart script to a standard .desktop autostart file + AutostartScriptDesktopFile desktopFile(scriptName, info.isSymLink() ? info.symLinkTarget() : scriptMovedPath); + qCInfo(PLASMA_STARTUP) << "Migrated legacy autostart script" << scriptPath << "to" << desktopFile.fileName(); + + if (info.isSymLink() && QFile::remove(scriptPath)) { + qCInfo(PLASMA_STARTUP) << "Removed legacy autostart script" << scriptPath << "that pointed to" << info.symLinkTarget(); + } + } + // Delete or rename autostart-scripts to old-autostart-scripts to avoid running the migration again + if (autostartScriptsLocation.entryInfoList(QDir::Files).empty()) { + autostartScriptsLocation.removeRecursively(); + } else { + configLocation.rename(autostartScriptsLocation.dirName(), autostartScriptsMovedLocation.dirName()); + } + // Reload systemd so that the XDG autostart generator is run again to pick up the new .desktop files + QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.systemd1"), + QStringLiteral("/org/freedesktop/systemd1"), + QStringLiteral("org.freedesktop.systemd1.Manager"), + QStringLiteral("Reload")); + QDBusConnection::sessionBus().call(message); +} diff --git a/startkde/startplasma.h b/startkde/startplasma.h index 40a78a0c2..a7c9641b4 100644 --- a/startkde/startplasma.h +++ b/startkde/startplasma.h @@ -54,6 +54,7 @@ void waitForKonqi(); static void resetSystemdFailedUnits(); static bool hasSystemdService(const QString &serviceName); static bool useSystemdBoot(); +static void migrateUserScriptsAutostart(); struct KillBeforeDeleter { static inline void cleanup(QProcess *pointer)
