From d073177da09e6703fce043fb570430e76f24a913 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 31 Aug 2018 15:29:31 +0200 Subject: [PATCH 1/3] feat(App): supports autostart on GNU/Linux --- assets/languages/de.ts | 4 ++ assets/languages/en.ts | 4 ++ assets/languages/fr_FR.ts | 4 ++ assets/languages/ja.ts | 4 ++ assets/languages/lt.ts | 4 ++ assets/languages/pt_BR.ts | 4 ++ assets/languages/ru.ts | 4 ++ assets/languages/sv.ts | 4 ++ assets/languages/tr.ts | 4 ++ src/app/App.cpp | 91 ++++++++++++++++++++++++++++ src/app/App.hpp | 12 ++++ src/config.h.cmake | 1 + ui/views/App/Settings/SettingsUi.qml | 10 +++ 13 files changed, 150 insertions(+) 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..4a017539e 100644 --- a/src/app/App.cpp +++ b/src/app/App.cpp @@ -70,8 +70,32 @@ namespace { constexpr char AboutPath[] = "qrc:/ui/views/App/Main/Dialogs/About.qml"; constexpr char AssistantViewName[] = "Assistant"; + + #ifdef Q_OS_LINUX + static QString AutoStartDirectory( + QStandardPaths::standardLocations(QStandardPaths::ConfigLocation).at(0) + QLatin1String("/autostart/") + ); + #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 bool autoStartEnabled () { + return false; + } +#else + static inline bool autoStartEnabled () { + return false; + } +#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 +149,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 +604,71 @@ 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) { + Q_UNUSED(enabled); +} + +#else + +void App::setAutoStart (bool enabled) { + Q_UNUSED(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 + } + } } } } From 3285fb8dbe21fdb07b2886c5dbba661732e4398c Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Fri, 31 Aug 2018 16:24:27 +0200 Subject: [PATCH 2/3] feat(App): supports autostart on Windows --- src/app/App.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/app/App.cpp b/src/app/App.cpp index 4a017539e..748e461cf 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" @@ -75,6 +79,10 @@ namespace { static QString AutoStartDirectory( QStandardPaths::standardLocations(QStandardPaths::ConfigLocation).at(0) + QLatin1String("/autostart/") ); + #elif defined(Q_OS_MACOS) + + #else + static QString AutoStartSettingsFilePath("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"); #endif // ifdef Q_OS_LINUX } @@ -90,7 +98,7 @@ namespace { } #else static inline bool autoStartEnabled () { - return false; + return QSettings(AutoStartSettingsFilePath, QSettings::NativeFormat).value(EXECUTABLE_NAME).isValid(); } #endif // ifdef Q_OS_LINUX @@ -662,7 +670,17 @@ void App::setAutoStart (bool enabled) { #else void App::setAutoStart (bool enabled) { - Q_UNUSED(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 From 766add98e3c1402afe3ce7d79a1418a2ef06a181 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Mon, 3 Sep 2018 13:51:57 +0200 Subject: [PATCH 3/3] feat(App): supports autostart on MacOS --- src/app/App.cpp | 77 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 4 deletions(-) diff --git a/src/app/App.cpp b/src/app/App.cpp index 748e461cf..727394650 100644 --- a/src/app/App.cpp +++ b/src/app/App.cpp @@ -76,13 +76,13 @@ namespace { constexpr char AssistantViewName[] = "Assistant"; #ifdef Q_OS_LINUX - static QString AutoStartDirectory( + QString AutoStartDirectory( QStandardPaths::standardLocations(QStandardPaths::ConfigLocation).at(0) + QLatin1String("/autostart/") ); #elif defined(Q_OS_MACOS) - + QString OsascriptExecutable("osascript"); #else - static QString AutoStartSettingsFilePath("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"); + QString AutoStartSettingsFilePath("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"); #endif // ifdef Q_OS_LINUX } @@ -93,7 +93,57 @@ namespace { 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 @@ -664,7 +714,26 @@ void App::setAutoStart (bool enabled) { #elif defined(Q_OS_MACOS) void App::setAutoStart (bool enabled) { - Q_UNUSED(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