diff --git a/assets/languages/de.ts b/assets/languages/de.ts
index 966bc5c98..b7f1a92a1 100644
--- a/assets/languages/de.ts
+++ b/assets/languages/de.ts
@@ -1599,6 +1599,10 @@ Server URL ist nicht konfiguriert.
dataTitle
UI-Daten
+
+ autoStartLabel
+
+
SettingsVideo
diff --git a/assets/languages/en.ts b/assets/languages/en.ts
index 326260e29..f9d32b5dd 100644
--- a/assets/languages/en.ts
+++ b/assets/languages/en.ts
@@ -1604,6 +1604,10 @@ your friend's SIP address or username.
dataTitle
UI Data
+
+ autoStartLabel
+ Autostart app
+
SettingsVideo
diff --git a/assets/languages/fr_FR.ts b/assets/languages/fr_FR.ts
index 26cd5476f..bb7f62ed7 100644
--- a/assets/languages/fr_FR.ts
+++ b/assets/languages/fr_FR.ts
@@ -1602,6 +1602,10 @@ Cliquez ici : <a href="%1">%1</a>
dataTitle
Données
+
+ autoStartLabel
+ Démarrer auto. l'app
+
SettingsVideo
diff --git a/assets/languages/ja.ts b/assets/languages/ja.ts
index 86e6feefb..24a044b1f 100644
--- a/assets/languages/ja.ts
+++ b/assets/languages/ja.ts
@@ -1599,6 +1599,10 @@
dataTitle
+
+ autoStartLabel
+
+
SettingsVideo
diff --git a/assets/languages/lt.ts b/assets/languages/lt.ts
index acec24439..bd0cbe16d 100644
--- a/assets/languages/lt.ts
+++ b/assets/languages/lt.ts
@@ -1604,6 +1604,10 @@ Tiesiog, įveskite savo draugo SIP adresą ar naudotojo vardą.
dataTitle
Naudotojo sąsajos duomenys
+
+ autoStartLabel
+
+
SettingsVideo
diff --git a/assets/languages/pt_BR.ts b/assets/languages/pt_BR.ts
index 1bdac6873..4c3173ddc 100644
--- a/assets/languages/pt_BR.ts
+++ b/assets/languages/pt_BR.ts
@@ -1604,6 +1604,10 @@ o endereço SIP ou nome de usuário do seu amigo.
dataTitle
Dados UI
+
+ autoStartLabel
+
+
SettingsVideo
diff --git a/assets/languages/ru.ts b/assets/languages/ru.ts
index 748bdce4d..0db4ea999 100644
--- a/assets/languages/ru.ts
+++ b/assets/languages/ru.ts
@@ -1602,6 +1602,10 @@
dataTitle
Данные пользовательского интерфейса
+
+ autoStartLabel
+
+
SettingsVideo
diff --git a/assets/languages/sv.ts b/assets/languages/sv.ts
index 08b2a386b..a252b33d7 100644
--- a/assets/languages/sv.ts
+++ b/assets/languages/sv.ts
@@ -1602,6 +1602,10 @@ Klicka här: <a href="%1">%1</a>
dataTitle
Användargränssnitt data
+
+ autoStartLabel
+
+
SettingsVideo
diff --git a/assets/languages/tr.ts b/assets/languages/tr.ts
index d38e215c5..4b049ee4c 100644
--- a/assets/languages/tr.ts
+++ b/assets/languages/tr.ts
@@ -1604,6 +1604,10 @@ arkadaşınızın SIP adresini veya kullanıcı adını girin.
dataTitle
Kullanıcı Arayüzü Verisi
+
+ autoStartLabel
+
+
SettingsVideo
diff --git a/src/app/App.cpp b/src/app/App.cpp
index 8b2a82669..727394650 100644
--- a/src/app/App.cpp
+++ b/src/app/App.cpp
@@ -31,6 +31,10 @@
#include
#include
+#ifdef Q_OS_WIN
+ #include
+#endif // ifdef Q_OS_WIN
+
#include "config.h"
#include "cli/Cli.hpp"
@@ -70,8 +74,86 @@ namespace {
constexpr char AboutPath[] = "qrc:/ui/views/App/Main/Dialogs/About.qml";
constexpr char AssistantViewName[] = "Assistant";
+
+ #ifdef Q_OS_LINUX
+ QString AutoStartDirectory(
+ QStandardPaths::standardLocations(QStandardPaths::ConfigLocation).at(0) + QLatin1String("/autostart/")
+ );
+ #elif defined(Q_OS_MACOS)
+ QString OsascriptExecutable("osascript");
+ #else
+ QString AutoStartSettingsFilePath("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run");
+ #endif // ifdef Q_OS_LINUX
}
+// -----------------------------------------------------------------------------
+
+#ifdef Q_OS_LINUX
+ static inline bool autoStartEnabled () {
+ return QDir(AutoStartDirectory).exists() && QFile(AutoStartDirectory + EXECUTABLE_NAME ".desktop").exists();
+ }
+#elif defined(Q_OS_MACOS)
+ static inline QString getMacOsBundlePath () {
+ QDir dir(QCoreApplication::applicationDirPath());
+ if (dir.dirName() != QLatin1String("MacOS"))
+ return QString();
+
+ dir.cdUp();
+ dir.cdUp();
+
+ QString path(dir.path());
+ if (path.length() > 0 && path.right(1) == "/")
+ path.chop(1);
+ return path;
+ }
+
+ static inline QString getMacOsBundleName () {
+ return QFileInfo(getMacOsBundlePath()).baseName();
+ }
+
+ static inline bool autoStartEnabled () {
+ const QByteArray expectedWord(getMacOsBundleName().toUtf8());
+ if (expectedWord.isEmpty()) {
+ qInfo() << QStringLiteral("Application is not installed. Autostart unavailable.");
+ return false;
+ }
+
+ QProcess process;
+ process.start(OsascriptExecutable, { "-e", "tell application \"System Events\" to get the name of every login item" });
+ if (!process.waitForFinished()) {
+ qWarning() << QStringLiteral("Unable to execute properly: `%1` (%2).").arg(OsascriptExecutable).arg(process.errorString());
+ return false;
+ }
+
+ // TODO: Move in utils?
+ const QByteArray buf(process.readAll());
+ for (const char *p = buf.data(), *word = p, *end = p + buf.length(); p <= end; ++p) {
+ switch (*p) {
+ case ' ':
+ case '\r':
+ case '\n':
+ case '\t':
+ case '\0':
+ if (word != p) {
+ if (!strncmp(word, expectedWord, size_t(p - word)))
+ return true;
+ word = p + 1;
+ }
+ default:
+ break;
+ }
+ }
+
+ return false;
+ }
+#else
+ static inline bool autoStartEnabled () {
+ return QSettings(AutoStartSettingsFilePath, QSettings::NativeFormat).value(EXECUTABLE_NAME).isValid();
+ }
+#endif // ifdef Q_OS_LINUX
+
+// -----------------------------------------------------------------------------
+
static inline bool installLocale (App &app, QTranslator &translator, const QLocale &locale) {
return translator.load(locale, LanguagePath) && app.installTranslator(&translator);
}
@@ -125,6 +207,8 @@ App::App (int &argc, char *argv[]) : SingleApplication(argc, argv, true, Mode::U
if (mParser->isSet("version"))
mParser->showVersion();
+ mAutoStart = autoStartEnabled();
+
qInfo() << QStringLiteral("Starting " APPLICATION_NAME " (bin: " EXECUTABLE_NAME ")");
qInfo() << QStringLiteral("Use locale: %1").arg(mLocale);
}
@@ -578,6 +662,100 @@ QString App::getLocale () const {
// -----------------------------------------------------------------------------
+#ifdef Q_OS_LINUX
+
+void App::setAutoStart (bool enabled) {
+ if (enabled == mAutoStart)
+ return;
+
+ QDir dir(AutoStartDirectory);
+ if (!dir.exists() && !dir.mkpath(AutoStartDirectory)) {
+ qWarning() << QStringLiteral("Unable to build autostart dir path: `%1`.").arg(AutoStartDirectory);
+ return;
+ }
+
+ QFile file(AutoStartDirectory + EXECUTABLE_NAME ".desktop");
+
+ if (!enabled) {
+ if (file.exists() && !file.remove()) {
+ qWarning() << QLatin1String("Unable to remove autostart file: `" EXECUTABLE_NAME ".desktop`.");
+ return;
+ }
+
+ mAutoStart = enabled;
+ emit autoStartChanged(enabled);
+ return;
+ }
+
+ if (!file.open(QFile::WriteOnly)) {
+ qWarning() << "Unable to open autostart file: `" EXECUTABLE_NAME ".desktop`.";
+ return;
+ }
+
+ QString fileContent(
+ "[Desktop Entry]\n"
+ "Name=" APPLICATION_NAME "\n"
+ "GenericName=SIP Phone\n"
+ "Comment=" APPLICATION_DESCRIPTION "\n"
+ "Type=Application\n"
+ "Exec=" + applicationFilePath() + "\n"
+ "Icon=\n"
+ "Terminal=false\n"
+ "Categories=Network;Telephony;\n"
+ "MimeType=x-scheme-handler/sip-linphone;x-scheme-handler/sip;x-scheme-handler/sips-linphone;x-scheme-handler/sips;\n"
+ );
+ QTextStream out(&file);
+ out << fileContent;
+
+ mAutoStart = enabled;
+ emit autoStartChanged(enabled);
+}
+
+#elif defined(Q_OS_MACOS)
+
+void App::setAutoStart (bool enabled) {
+ if (enabled == mAutoStart)
+ return;
+
+ if (getMacOsBundlePath().isEmpty()) {
+ qWarning() << QStringLiteral("Application is not installed. Unable to change autostart state.");
+ return;
+ }
+
+ if (enabled)
+ QProcess::execute(OsascriptExecutable, {
+ "-e", "tell application \"System Events\" to make login item at end with properties"
+ "{ path: \"" + getMacOsBundlePath() + "\", hidden: false }"
+ });
+ else
+ QProcess::execute(OsascriptExecutable, {
+ "-e", "tell application \"System Events\" to delete login item \"" + getMacOsBundleName() + "\""
+ });
+
+ mAutoStart = enabled;
+ emit autoStartChanged(enabled);
+}
+
+#else
+
+void App::setAutoStart (bool enabled) {
+ if (enabled == mAutoStart)
+ return;
+
+ QSettings settings(AutoStartSettingsFilePath, QSettings::NativeFormat);
+ if (enabled)
+ settings.setValue(EXECUTABLE_NAME, QDir::toNativeSeparators(applicationFilePath()));
+ else
+ settings.remove(EXECUTABLE_NAME);
+
+ mAutoStart = enabled;
+ emit autoStartChanged(enabled);
+}
+
+#endif // ifdef Q_OS_LINUX
+
+// -----------------------------------------------------------------------------
+
void App::openAppAfterInit (bool mustBeIconified) {
qInfo() << QStringLiteral("Open " APPLICATION_NAME " app.");
diff --git a/src/app/App.hpp b/src/app/App.hpp
index 867e15877..432b60d1c 100644
--- a/src/app/App.hpp
+++ b/src/app/App.hpp
@@ -50,6 +50,8 @@ class App : public SingleApplication {
Q_PROPERTY(QVariantList availableLocales READ getAvailableLocales CONSTANT);
Q_PROPERTY(QString qtVersion READ getQtVersion CONSTANT);
+ Q_PROPERTY(bool autoStart READ getAutoStart WRITE setAutoStart NOTIFY autoStartChanged);
+
public:
App (int &argc, char *argv[]);
~App ();
@@ -100,6 +102,8 @@ public:
signals:
void configLocaleChanged (const QString &locale);
+ void autoStartChanged (bool enabled);
+
private:
void createParser ();
@@ -122,6 +126,12 @@ private:
return mAvailableLocales;
}
+ bool getAutoStart () const {
+ return mAutoStart;
+ }
+
+ void setAutoStart (bool enabled);
+
void openAppAfterInit (bool mustBeIconified = false);
static void checkForUpdate ();
@@ -133,6 +143,8 @@ private:
QVariantList mAvailableLocales;
QString mLocale;
+ bool mAutoStart = false;
+
QCommandLineParser *mParser = nullptr;
QQmlApplicationEngine *mEngine = nullptr;
diff --git a/src/config.h.cmake b/src/config.h.cmake
index 06f848cb8..7c64f7c94 100644
--- a/src/config.h.cmake
+++ b/src/config.h.cmake
@@ -21,6 +21,7 @@
*******************************************************************************/
#cmakedefine APPLICATION_NAME "${APPLICATION_NAME}"
+#cmakedefine APPLICATION_DESCRIPTION "${APPLICATION_DESCRIPTION}"
#cmakedefine ENABLE_UPDATE_CHECK 1
#cmakedefine EXECUTABLE_NAME "${EXECUTABLE_NAME}"
#cmakedefine MSPLUGINS_DIR "${MSPLUGINS_DIR}"
diff --git a/ui/views/App/Settings/SettingsUi.qml b/ui/views/App/Settings/SettingsUi.qml
index e6dff7d7e..48a22b5f2 100644
--- a/ui/views/App/Settings/SettingsUi.qml
+++ b/ui/views/App/Settings/SettingsUi.qml
@@ -146,6 +146,16 @@ TabContainer {
onClicked: SettingsModel.exitOnClose = !checked
}
}
+
+ FormGroup {
+ label: qsTr('autoStartLabel')
+
+ Switch {
+ checked: App.autoStart
+
+ onClicked: App.autoStart = !checked
+ }
+ }
}
}
}