diff --git a/src/gui/ApplicationSettingsWidget.cpp b/src/gui/ApplicationSettingsWidget.cpp
index 7f4c10ce..4dbe4069 100644
--- a/src/gui/ApplicationSettingsWidget.cpp
+++ b/src/gui/ApplicationSettingsWidget.cpp
@@ -27,6 +27,7 @@
#include "core/Global.h"
#include "core/Resources.h"
#include "core/Translator.h"
+#include "gui/osutils/OSUtils.h"
#include "MessageBox.h"
#include "touchid/TouchID.h"
@@ -173,8 +174,10 @@ void ApplicationSettingsWidget::loadSettings()
#ifdef QT_DEBUG
m_generalUi->singleInstanceCheckBox->setEnabled(false);
+ m_generalUi->launchAtStartup->setEnabled(false);
#endif
m_generalUi->singleInstanceCheckBox->setChecked(config()->get(Config::SingleInstance).toBool());
+ m_generalUi->launchAtStartup->setChecked(osUtils->isLaunchAtStartupEnabled());
m_generalUi->rememberLastDatabasesCheckBox->setChecked(config()->get(Config::RememberLastDatabases).toBool());
m_generalUi->rememberLastKeyFilesCheckBox->setChecked(config()->get(Config::RememberLastKeyFiles).toBool());
m_generalUi->openPreviousDatabasesOnStartupCheckBox->setChecked(
@@ -299,6 +302,10 @@ void ApplicationSettingsWidget::saveSettings()
return;
}
+#ifndef QT_DEBUG
+ osUtils->setLaunchAtStartup(m_generalUi->launchAtStartup->isChecked());
+#endif
+
config()->set(Config::SingleInstance, m_generalUi->singleInstanceCheckBox->isChecked());
config()->set(Config::RememberLastDatabases, m_generalUi->rememberLastDatabasesCheckBox->isChecked());
config()->set(Config::RememberLastKeyFiles, m_generalUi->rememberLastKeyFilesCheckBox->isChecked());
diff --git a/src/gui/ApplicationSettingsWidgetGeneral.ui b/src/gui/ApplicationSettingsWidgetGeneral.ui
index 7a04217e..55cb28ac 100644
--- a/src/gui/ApplicationSettingsWidgetGeneral.ui
+++ b/src/gui/ApplicationSettingsWidgetGeneral.ui
@@ -6,8 +6,6 @@
0
0
- 499
- 1174
@@ -49,6 +47,13 @@
+ -
+
+
+ Automatically launch KeePassXC at system startup
+
+
+
-
diff --git a/src/gui/osutils/OSUtilsBase.h b/src/gui/osutils/OSUtilsBase.h
index 0606d322..340e9bf7 100644
--- a/src/gui/osutils/OSUtilsBase.h
+++ b/src/gui/osutils/OSUtilsBase.h
@@ -30,7 +30,24 @@ class OSUtilsBase : public QObject
Q_OBJECT
public:
- virtual bool isDarkMode() = 0;
+ /**
+ * @return OS dark mode enabled.
+ */
+ virtual bool isDarkMode() const = 0;
+
+ /**
+ * @return KeePassXC set to launch at system startup (autostart).
+ */
+ virtual bool isLaunchAtStartupEnabled() const = 0;
+
+ /**
+ * @param enable Add or remove KeePassXC from system autostart.
+ */
+ virtual void setLaunchAtStartup(bool enable) = 0;
+
+ /**
+ * @return OS caps lock enabled.
+ */
virtual bool isCapslockEnabled() = 0;
protected:
diff --git a/src/gui/osutils/macutils/MacUtils.cpp b/src/gui/osutils/macutils/MacUtils.cpp
index b888b18e..9203d73f 100644
--- a/src/gui/osutils/macutils/MacUtils.cpp
+++ b/src/gui/osutils/macutils/MacUtils.cpp
@@ -18,6 +18,10 @@
#include "MacUtils.h"
#include
+#include
+#include
+#include
+#include
#include
@@ -74,11 +78,6 @@ bool MacUtils::isHidden()
return m_appkit->isHidden(m_appkit->ownProcessId());
}
-bool MacUtils::isDarkMode()
-{
- return m_appkit->isDarkMode();
-}
-
bool MacUtils::enableAccessibility()
{
return m_appkit->enableAccessibility();
@@ -89,6 +88,37 @@ bool MacUtils::enableScreenRecording()
return m_appkit->enableScreenRecording();
}
+bool MacUtils::isDarkMode() const
+{
+ return m_appkit->isDarkMode();
+}
+
+QString MacUtils::getLaunchAgentFilename() const
+{
+ auto launchAgentDir = QDir(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QStringLiteral("/../LaunchAgents"));
+ return QFile(launchAgentDir.absoluteFilePath(
+ qApp->property("KPXC_QUALIFIED_APPNAME").toString().append(".plist"))).fileName();
+}
+
+bool MacUtils::isLaunchAtStartupEnabled() const
+{
+ return QFile::exists(getLaunchAgentFilename());
+}
+
+void MacUtils::setLaunchAtStartup(bool enable)
+{
+ if (enable) {
+ QSettings agent(getLaunchAgentFilename(), QSettings::NativeFormat);
+ agent.setValue("Label", qApp->property("KPXC_QUALIFIED_APPNAME").toString());
+ agent.setValue("ProgramArguments", QStringList() << QApplication::applicationFilePath());
+ agent.setValue("RunAtLoad", true);
+ agent.setValue("StandardErrorPath", "/dev/null");
+ agent.setValue("StandardOutPath", "/dev/null");
+ } else if (isLaunchAtStartupEnabled()) {
+ QFile::remove(getLaunchAgentFilename());
+ }
+}
+
bool MacUtils::isCapslockEnabled()
{
return (CGEventSourceFlagsState(kCGEventSourceStateHIDSystemState) & kCGEventFlagMaskAlphaShift) != 0;
diff --git a/src/gui/osutils/macutils/MacUtils.h b/src/gui/osutils/macutils/MacUtils.h
index b2180c30..ccabf678 100644
--- a/src/gui/osutils/macutils/MacUtils.h
+++ b/src/gui/osutils/macutils/MacUtils.h
@@ -33,7 +33,9 @@ class MacUtils : public OSUtilsBase
public:
static MacUtils* instance();
- bool isDarkMode() override;
+ bool isDarkMode() const override;
+ bool isLaunchAtStartupEnabled() const override;
+ void setLaunchAtStartup(bool enable) override;
bool isCapslockEnabled() override;
WId activeWindow();
@@ -53,6 +55,8 @@ protected:
~MacUtils() override;
private:
+ QString getLaunchAgentFilename() const;
+
QScopedPointer m_appkit;
static QPointer m_instance;
diff --git a/src/gui/osutils/nixutils/NixUtils.cpp b/src/gui/osutils/nixutils/NixUtils.cpp
index e4de7c9c..b252458e 100644
--- a/src/gui/osutils/nixutils/NixUtils.cpp
+++ b/src/gui/osutils/nixutils/NixUtils.cpp
@@ -16,11 +16,16 @@
*/
#include "NixUtils.h"
+
#include
#include
+#include
+#include
#include
#include
+#include
#include
+#include
#include
// namespace required to avoid name clashes with declarations in XKBlib.h
@@ -49,7 +54,7 @@ NixUtils::~NixUtils()
{
}
-bool NixUtils::isDarkMode()
+bool NixUtils::isDarkMode() const
{
if (!qApp || !qApp->style()) {
return false;
@@ -57,6 +62,58 @@ bool NixUtils::isDarkMode()
return qApp->style()->standardPalette().color(QPalette::Window).toHsl().lightness() < 110;
}
+QString NixUtils::getAutostartDesktopFilename(bool createDirs) const
+{
+ QDir autostartDir;
+ auto confHome = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
+ if (confHome.isEmpty()) {
+ return {};
+ }
+ autostartDir.setPath(confHome + QStringLiteral("/autostart"));
+ if (createDirs && !autostartDir.exists()) {
+ autostartDir.mkpath(".");
+ }
+
+ return QFile(autostartDir.absoluteFilePath(qApp->property("KPXC_QUALIFIED_APPNAME").toString().append(".desktop")))
+ .fileName();
+}
+
+bool NixUtils::isLaunchAtStartupEnabled() const
+{
+ return QFile::exists(getAutostartDesktopFilename());
+ ;
+}
+
+void NixUtils::setLaunchAtStartup(bool enable)
+{
+ if (enable) {
+ QFile desktopFile(getAutostartDesktopFilename(true));
+ if (!desktopFile.open(QIODevice::WriteOnly)) {
+ qWarning("Failed to create autostart desktop file.");
+ return;
+ }
+ QTextStream stream(&desktopFile);
+ stream.setCodec("UTF-8");
+ stream << QStringLiteral("[Desktop Entry]") << '\n'
+ << QStringLiteral("Name=") << QApplication::applicationDisplayName() << '\n'
+ << QStringLiteral("GenericName=") << tr("Password Manager") << '\n'
+ << QStringLiteral("Exec=") << QApplication::applicationFilePath() << '\n'
+ << QStringLiteral("TryExec=") << QApplication::applicationFilePath() << '\n'
+ << QStringLiteral("Icon=") << QApplication::applicationName().toLower() << '\n'
+ << QStringLiteral("StartupWMClass=keepassxc") << '\n'
+ << QStringLiteral("StartupNotify=true") << '\n'
+ << QStringLiteral("Terminal=false") << '\n'
+ << QStringLiteral("Type=Application") << '\n'
+ << QStringLiteral("Version=1.0") << "true" << '\n'
+ << QStringLiteral("Categories=Utility;Security;Qt;") << '\n'
+ << QStringLiteral("MimeType=application/x-keepass2;") << '\n'
+ << QStringLiteral("X-GNOME-Autostart-enabled=true") << endl;
+ desktopFile.close();
+ } else if (isLaunchAtStartupEnabled()) {
+ QFile::remove(getAutostartDesktopFilename());
+ }
+}
+
bool NixUtils::isCapslockEnabled()
{
QPlatformNativeInterface* native = QGuiApplication::platformNativeInterface();
diff --git a/src/gui/osutils/nixutils/NixUtils.h b/src/gui/osutils/nixutils/NixUtils.h
index b23cf143..c9158079 100644
--- a/src/gui/osutils/nixutils/NixUtils.h
+++ b/src/gui/osutils/nixutils/NixUtils.h
@@ -28,7 +28,9 @@ class NixUtils : public OSUtilsBase
public:
static NixUtils* instance();
- bool isDarkMode() override;
+ bool isDarkMode() const override;
+ bool isLaunchAtStartupEnabled() const override;
+ void setLaunchAtStartup(bool enable) override;
bool isCapslockEnabled() override;
private:
@@ -36,6 +38,8 @@ private:
~NixUtils() override;
private:
+ QString getAutostartDesktopFilename(bool createDirs = false) const;
+
static QPointer m_instance;
Q_DISABLE_COPY(NixUtils)
diff --git a/src/gui/osutils/winutils/WinUtils.cpp b/src/gui/osutils/winutils/WinUtils.cpp
index f3cd9e8a..44f77043 100644
--- a/src/gui/osutils/winutils/WinUtils.cpp
+++ b/src/gui/osutils/winutils/WinUtils.cpp
@@ -77,13 +77,30 @@ bool WinUtils::DWMEventFilter::nativeEventFilter(const QByteArray& eventType, vo
return false;
}
-bool WinUtils::isDarkMode()
+bool WinUtils::isDarkMode() const
{
QSettings settings(R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)",
QSettings::NativeFormat);
return settings.value("AppsUseLightTheme", 1).toInt() == 0;
}
+bool WinUtils::isLaunchAtStartupEnabled() const
+{
+ return QSettings(R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run)", QSettings::NativeFormat)
+ .contains(qAppName());
+ ;
+}
+
+void WinUtils::setLaunchAtStartup(bool enable)
+{
+ QSettings reg(R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run)", QSettings::NativeFormat);
+ if (enable) {
+ reg.setValue(qAppName(), QApplication::applicationFilePath());
+ } else {
+ reg.remove(qAppName());
+ }
+}
+
bool WinUtils::isCapslockEnabled()
{
return GetKeyState(VK_CAPITAL) == 1;
diff --git a/src/gui/osutils/winutils/WinUtils.h b/src/gui/osutils/winutils/WinUtils.h
index 0965074f..bf49f2c7 100644
--- a/src/gui/osutils/winutils/WinUtils.h
+++ b/src/gui/osutils/winutils/WinUtils.h
@@ -32,7 +32,9 @@ public:
static WinUtils* instance();
static void registerEventFilters();
- bool isDarkMode() override;
+ bool isDarkMode() const override;
+ bool isLaunchAtStartupEnabled() const override;
+ void setLaunchAtStartup(bool enable) override;
bool isCapslockEnabled() override;
protected:
diff --git a/src/main.cpp b/src/main.cpp
index c3494f02..89ea235a 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -53,13 +53,13 @@ int main(int argc, char** argv)
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
-#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
- QGuiApplication::setDesktopFileName("org.keepassxc.KeePassXC.desktop");
-#endif
-
Application app(argc, argv);
Application::setApplicationName("KeePassXC");
Application::setApplicationVersion(KEEPASSXC_VERSION);
+ app.setProperty("KPXC_QUALIFIED_APPNAME", "org.keepassxc.KeePassXC");
+#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
+ QGuiApplication::setDesktopFileName(app.property("KPXC_QUALIFIED_APPNAME").toString() + QStringLiteral(".desktop"));
+#endif
// don't set organizationName as that changes the return value of
// QStandardPaths::writableLocation(QDesktopServices::DataLocation)