diff --git a/src/services/kautostart.cpp b/src/services/kautostart.cpp index 06030c4..76761c4 100644 --- a/src/services/kautostart.cpp +++ b/src/services/kautostart.cpp @@ -1,362 +1,367 @@ /* This file is part of the KDE libraries Copyright (C) 2006 Aaron Seigo This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kautostart.h" #include "kdesktopfile.h" #include "kconfiggroup.h" #include #include #include #include class KAutostartPrivate { public: KAutostartPrivate() : df(nullptr), copyIfNeededChecked(false) { } ~KAutostartPrivate() { delete df; } void copyIfNeeded(); QString name; KDesktopFile *df; bool copyIfNeededChecked; }; void KAutostartPrivate::copyIfNeeded() { if (copyIfNeededChecked) { return; } const QString local = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1String("/autostart/") + name; if (!QFile::exists(local)) { const QString global = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, QLatin1String("autostart/") + name); if (!global.isEmpty()) { KDesktopFile *newDf = df->copyTo(local); delete df; delete newDf; //Force sync-to-disk df = new KDesktopFile(QStandardPaths::GenericConfigLocation, QStringLiteral("autostart/") + name); //Recreate from disk } } copyIfNeededChecked = true; } KAutostart::KAutostart(const QString &entryName, QObject *parent) : QObject(parent), d(new KAutostartPrivate) { const bool isAbsolute = QDir::isAbsolutePath(entryName); if (isAbsolute) { d->name = entryName.mid(entryName.lastIndexOf(QLatin1Char('/')) + 1); } else { if (entryName.isEmpty()) { d->name = QCoreApplication::applicationName(); } else { d->name = entryName; } if (!d->name.endsWith(QLatin1String(".desktop"))) { d->name.append(QLatin1String(".desktop")); } } const QString path = isAbsolute ? entryName : QStandardPaths::locate(QStandardPaths::GenericConfigLocation, QLatin1String("autostart/") + d->name); if (path.isEmpty()) { // just a new KDesktopFile, since we have nothing to use d->df = new KDesktopFile(QStandardPaths::GenericConfigLocation, QLatin1String("autostart/") + d->name); d->copyIfNeededChecked = true; } else { d->df = new KDesktopFile(path); } } KAutostart::~KAutostart() { delete d; } void KAutostart::setAutostarts(bool autostart) { bool currentAutostartState = !d->df->desktopGroup().readEntry("Hidden", false); if (currentAutostartState == autostart) { return; } d->copyIfNeeded(); d->df->desktopGroup().writeEntry("Hidden", !autostart); } bool KAutostart::autostarts(const QString &environment, Conditions check) const { // check if this is actually a .desktop file bool starts = d->df->desktopGroup().exists(); // check the hidden field starts = starts && !d->df->desktopGroup().readEntry("Hidden", false); if (!environment.isEmpty()) { starts = starts && checkAllowedEnvironment(environment); } if (check & CheckCommand) { starts = starts && d->df->tryExec(); } if (check & CheckCondition) { starts = starts && checkStartCondition(); } return starts; } bool KAutostart::checkStartCondition() const { - QString condition = d->df->desktopGroup().readEntry("X-KDE-autostart-condition"); + return KAutostart::isStartConditionMet(d->df->desktopGroup().readEntry("X-KDE-autostart-condition")); +} + + +bool KAutostart::isStartConditionMet(const QString &condition) +{ if (condition.isEmpty()) { return true; } const QStringList list = condition.split(QLatin1Char(':')); if (list.count() < 4) { return true; } if (list[0].isEmpty() || list[2].isEmpty()) { return true; } KConfig config(list[0], KConfig::NoGlobals); KConfigGroup cg(&config, list[1]); const bool defaultValue = (list[3].toLower() == QLatin1String("true")); return cg.readEntry(list[2], defaultValue); } bool KAutostart::checkAllowedEnvironment(const QString &environment) const { const QStringList allowed = allowedEnvironments(); if (!allowed.isEmpty()) { return allowed.contains(environment); } const QStringList excluded = excludedEnvironments(); if (!excluded.isEmpty()) { return !excluded.contains(environment); } return true; } QString KAutostart::command() const { return d->df->desktopGroup().readEntry("Exec", QString()); } void KAutostart::setCommand(const QString &command) { if (d->df->desktopGroup().readEntry("Exec", QString()) == command) { return; } d->copyIfNeeded(); d->df->desktopGroup().writeEntry("Exec", command); } QString KAutostart::visibleName() const { return d->df->readName(); } void KAutostart::setVisibleName(const QString &name) { if (d->df->desktopGroup().readEntry("Name", QString()) == name) { return; } d->copyIfNeeded(); d->df->desktopGroup().writeEntry("Name", name); } bool KAutostart::isServiceRegistered(const QString &entryName) { const QString localDir = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1String("/autostart/"); return QFile::exists(localDir + entryName + QLatin1String(".desktop")); } QString KAutostart::commandToCheck() const { return d->df->desktopGroup().readPathEntry("TryExec", QString()); } void KAutostart::setCommandToCheck(const QString &exec) { if (d->df->desktopGroup().readEntry("TryExec", QString()) == exec) { return; } d->copyIfNeeded(); d->df->desktopGroup().writePathEntry("TryExec", exec); } // do not specialize the readEntry template - // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=100911 static KAutostart::StartPhase readEntry(const KConfigGroup &group, const char *key, KAutostart::StartPhase aDefault) { const QByteArray data = group.readEntry(key, QByteArray()); if (data.isNull()) { return aDefault; } if (data == "0" || data == "BaseDesktop") { return KAutostart::BaseDesktop; } else if (data == "1" || data == "DesktopServices") { return KAutostart::DesktopServices; } else if (data == "2" || data == "Applications") { return KAutostart::Applications; } return aDefault; } KAutostart::StartPhase KAutostart::startPhase() const { return readEntry(d->df->desktopGroup(), "X-KDE-autostart-phase", Applications); } void KAutostart::setStartPhase(KAutostart::StartPhase phase) { QString data = QStringLiteral("Applications"); switch (phase) { case BaseDesktop: data = QStringLiteral("BaseDesktop"); break; case DesktopServices: data = QStringLiteral("DesktopServices"); break; case Applications: // This is the default break; } if (d->df->desktopGroup().readEntry("X-KDE-autostart-phase", QString()) == data) { return; } d->copyIfNeeded(); d->df->desktopGroup().writeEntry("X-KDE-autostart-phase", data); } QStringList KAutostart::allowedEnvironments() const { return d->df->desktopGroup().readXdgListEntry("OnlyShowIn"); } void KAutostart::setAllowedEnvironments(const QStringList &environments) { if (d->df->desktopGroup().readEntry("OnlyShowIn", QStringList()) == environments) { return; } d->copyIfNeeded(); d->df->desktopGroup().writeXdgListEntry("OnlyShowIn", environments); } void KAutostart::addToAllowedEnvironments(const QString &environment) { QStringList envs = allowedEnvironments(); if (envs.contains(environment)) { return; } envs.append(environment); setAllowedEnvironments(envs); } void KAutostart::removeFromAllowedEnvironments(const QString &environment) { QStringList envs = allowedEnvironments(); int index = envs.indexOf(environment); if (index < 0) { return; } envs.removeAt(index); setAllowedEnvironments(envs); } QStringList KAutostart::excludedEnvironments() const { return d->df->desktopGroup().readXdgListEntry("NotShowIn"); } void KAutostart::setExcludedEnvironments(const QStringList &environments) { if (d->df->desktopGroup().readEntry("NotShowIn", QStringList()) == environments) { return; } d->copyIfNeeded(); d->df->desktopGroup().writeXdgListEntry("NotShowIn", environments); } void KAutostart::addToExcludedEnvironments(const QString &environment) { QStringList envs = excludedEnvironments(); if (envs.contains(environment)) { return; } envs.append(environment); setExcludedEnvironments(envs); } void KAutostart::removeFromExcludedEnvironments(const QString &environment) { QStringList envs = excludedEnvironments(); int index = envs.indexOf(environment); if (index < 0) { return; } envs.removeAt(index); setExcludedEnvironments(envs); } QString KAutostart::startAfter() const { return d->df->desktopGroup().readEntry("X-KDE-autostart-after"); } diff --git a/src/services/kautostart.h b/src/services/kautostart.h index 41a335f..6e01f41 100644 --- a/src/services/kautostart.h +++ b/src/services/kautostart.h @@ -1,291 +1,297 @@ /* This file is part of the KDE libraries Copyright (C) 2006 Aaron Seigo This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDELIBS_KAUTOSTART_H #define KDELIBS_KAUTOSTART_H #include #include class KAutostartPrivate; class QStringList; /** * @class KAutostart kautostart.h * * KAutostart provides a programmatic means to control the state of * autostart services on a per-user basis. This is useful for applications * that wish to offer a configurable means to allow the application to be * autostarted. * * By using this class you future-proof your applications against potential * future or platform-specific changes to the autostart mechanism(s). * * Typical usage might look like: * * @code * KAutostart autostart; // without an entryName arg, gets name from KAboutData * autostart.setAutostarts(true); // will now start up when the user logs in * * // set the value in our configuration settings to reflect whether or not * // we will actually start up on log in * config.setAutoStart(autostart.autoStarts()); * @endcode */ class KSERVICE_EXPORT KAutostart : public QObject { Q_OBJECT public: /** * Creates a new KAutostart object that represents the autostart * service "entryName". If the service already exists in the system * then the values associated with that service, such as the executable * command, will be loaded as well. * * Note that unless this service is explicitly set to autostart, * simply creating a KAutostart object will not result in the * service being autostarted on next log in. * * If no such service is already registered and the command to be * executed on startup is not the same as entryName, then you will want * to set the associated command with setExec(const QString&) * @see setExec * @param entryName the name used to identify the service. If none is * provided then it uses the name registered with KAboutData. * @param parent QObject * * @since 5.61 we are allowed to specify an absolute path to the service * description and it will still work. */ explicit KAutostart(const QString &entryName = QString(), QObject *parent = nullptr); ~KAutostart(); /** * Flags for each of the conditions that may affect whether or not * a service actually autostarted on login */ enum Condition { NoConditions = 0x0, /** * an executable that is checked for existence by name */ CheckCommand = 0x1, /** * autostart condition will be checked too (KDE-specific) * @since 4.3 */ CheckCondition = 0x2, /** * all necessary conditions will be checked * @since 4.3 */ CheckAll = 0xff }; Q_DECLARE_FLAGS(Conditions, Condition) /** * Enumerates the various autostart phases that occur during start-up. */ enum StartPhase { /** * the essential desktop services such as panels and window managers */ BaseDesktop = 0, /** * services that should be available before most interactive * applications start but that aren't part of the base desktop. * This would include things such as clipboard managers and * mouse gesture tools. */ DesktopServices = 1, /** * everything else that doesn't belong in the above two categories, * including most system tray applications, system monitors and * interactive applications */ Applications = 2 }; /** * Sets the given exec to start automatically at login * @param autostart will register with the autostart facility when true * and deregister when false * @see autostarts() */ void setAutostarts(bool autostart); /** * Returns whether or not the service represented by entryName in the * autostart system is set to autostart at login or not * @param environment if provided the check will be performed as if * being loaded in that environment * @param check autostart conditions to check for (see commandToCheck()) * @see setAutostarts() */ bool autostarts(const QString &environment = QString(), Conditions check = NoConditions) const; /** * Returns the associated command for this autostart service * @see setCommand() */ QString command() const; /** * Set the associated command for this autostart service * @see command() */ void setCommand(const QString &command); /** * Returns the user-visible name this autostart service is registered as * @see setVisibleName(), setEntryName() */ QString visibleName() const; /** * Sets the user-visible name for this autostart service. * @see visibleName() */ void setVisibleName(const QString &entryName); /** * Checks whether or not a service by the given name @p entryName is registered * with the autostart system. Does not check whether or not it is * set to actually autostart or not. * @param entryName the name of the service to check for */ static bool isServiceRegistered(const QString &entryName); /** * Returns the executable to check for when attempting to autostart * this service. If the executable is not found in the user's * environment, it will not autostart. * @see setCommandToCheck() */ QString commandToCheck() const; /** * Sets the executable to check for the existence of when * autostarting this service * @see commandToCheck() */ void setCommandToCheck(const QString &exec); /** * Returns the autostart phase this service is started in. * * Note that this is KDE specific and may not work in other * environments. * * @see StartPhase, setStartPhase() */ StartPhase startPhase() const; /** * Sets the service (by name) this service should be started after. * * Note that this is KDE specific and may not work in other * environments. * * @see StartPhase, startPhase() */ void setStartPhase(StartPhase phase); /** * Returns the list of environments (e.g. "KDE") this service is allowed * to start in. Use checkAllowedEnvironment() or autostarts() for actual * checks. * * This does not take other autostart conditions * into account. If any environment is added to the allowed environments * list, then only those environments will be allowed to * autoload the service. It is not allowed to specify both allowed and excluded * environments at the same time. * @see setAllowedEnvironments() */ QStringList allowedEnvironments() const; /** * Sets the environments this service is allowed to start in * @see allowedEnvironments(), addToAllowedEnvironments() */ void setAllowedEnvironments(const QStringList &environments); /** * Adds an environment to the list of environments this service may * start in. * @see setAllowedEnvironments(), removeFromAllowedEnvironments() */ void addToAllowedEnvironments(const QString &environment); /** * Removes an environment to the list of environments this service may * start in. * @see addToAllowedEnvironments() */ void removeFromAllowedEnvironments(const QString &environment); /** * Returns the list of environments this service is explicitly not * allowed to start in. Use checkAllowedEnvironment() or autostarts() for actual * checks. * * This does not take other autostart conditions * such as into account. It is not allowed to specify both allowed and excluded * environments at the same time. * @see setExcludedEnvironments() */ QStringList excludedEnvironments() const; /** * Sets the environments this service is not allowed to start in * @see excludedEnvironments(), addToExcludedEnvironments() */ void setExcludedEnvironments(const QStringList &environments); /** * Adds an environment to the list of environments this service may * not be autostarted in * @see removeFromExcludedEnvironments() */ void addToExcludedEnvironments(const QString &environment); /** * Removes an environment to the list of environments this service may * not be autostarted in * @see addToExcludedEnvironments() */ void removeFromExcludedEnvironments(const QString &environment); /** * Returns the name of another service that should be autostarted * before this one (if that service would be autostarted). * @internal * @since 4.3 */ QString startAfter() const; /** * Checks whether autostart is allowed in the given environment, * depending on allowedEnvironments() and excludedEnvironments(). * @since 4.3 */ bool checkAllowedEnvironment(const QString &environment) const; + /** + * Checks that a given autostart configuration condition is met. + * @param condition: config in the format "rcfile:group:entry:default" + */ + static bool isStartConditionMet(const QString &condition); + private: bool checkStartCondition() const; KAutostartPrivate *const d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(KAutostart::Conditions) #endif