diff --git a/CMakeLists.txt b/CMakeLists.txt
index 39245b5bf7856ab4e9cb54001d8d64ab87f0528d..b9d94f24b92e66b995043419beb49863ca1764a1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -97,7 +97,7 @@ set(COMMON_SOURCES
     ${SRC_DIR}/bannedlistmodel.cpp
     ${SRC_DIR}/accountlistmodel.cpp
     ${SRC_DIR}/networkmanager.cpp
-    ${SRC_DIR}/runguard.cpp
+    ${SRC_DIR}/instancemanager.cpp
     ${SRC_DIR}/updatemanager.cpp
     ${SRC_DIR}/main.cpp
     ${SRC_DIR}/smartlistmodel.cpp
@@ -152,7 +152,7 @@ set(COMMON_HEADERS
     ${SRC_DIR}/bannedlistmodel.h
     ${SRC_DIR}/version.h
     ${SRC_DIR}/accountlistmodel.h
-    ${SRC_DIR}/runguard.h
+    ${SRC_DIR}/instancemanager.h
     ${SRC_DIR}/rendermanager.h
     ${SRC_DIR}/connectivitymonitor.h
     ${SRC_DIR}/jamiavatartheme.h
diff --git a/JamiInstaller/Config.wxi b/JamiInstaller/Config.wxi
index f24ee3ff2a76444a61c4d479aac7bdfafe02f96f..66157310bcb6399597d04fdae03855273fe52bdf 100644
--- a/JamiInstaller/Config.wxi
+++ b/JamiInstaller/Config.wxi
@@ -6,6 +6,8 @@
     <?define Name="Jami (BETA)" ?>
     <?endif ?>
 
+    <?define ExeName="Jami"?>
+
     <?if $(var.Configuration) = Release ?>
     <?define ReleaseDir="..\x64\Release"?>
     <?else?>
diff --git a/JamiInstaller/Product.wxs b/JamiInstaller/Product.wxs
index cf8b8f773680091df78ca6e3c4ec2680385531c9..112c31f944e206cbf0fc5d967a4e62d4745ad74b 100644
--- a/JamiInstaller/Product.wxs
+++ b/JamiInstaller/Product.wxs
@@ -5,7 +5,7 @@
     <Package InstallerVersion="301" Compressed="yes" InstallScope="perMachine" />
 
     <MajorUpgrade Schedule="afterInstallInitialize" AllowDowngrades="yes"/>
-    <MediaTemplate EmbedCab="yes" CompressionLevel="high" />
+    <MediaTemplate EmbedCab="yes" CompressionLevel="high" MaximumUncompressedMediaSize="4" />
 
     <!--Disables interaction of the package with the Restart Manager.-->
     <Property Id="MSIRESTARTMANAGERCONTROL" Value="Disable" />
@@ -44,7 +44,7 @@
     <WixVariable Id="WixUIDialogBmp" Value="main-banner.bmp" />
     <WixVariable Id="WixUISupportPerUser" Value="0" />
 
-    <CustomAction Id="removeOldJamiFiles"
+    <CustomAction Id="RemoveOldJamiFiles"
                   Directory="APPLICATIONFOLDER"
                   ExeCommand="cmd /c &quot;del vc_redist.x64.exe; del uninstall.exe; del WinSparkle.dll;&quot;"
                   Execute="deferred"
@@ -52,8 +52,9 @@
                   HideTarget="no"
                   Impersonate="no"/>
 
-    <Property Id="QtExecCmdLine" Value='"[WindowsFolder]\System32\taskkill.exe" /F /IM QtWebEngineProcess.exe /IM Jami.exe'/>
-    <CustomAction Id="JamiProcesses.TaskKill"
+    <Property Id="QtExecCmdLine"
+              Value='"[APPLICATIONFOLDER]/$(var.ExeName).exe" --term'/>
+    <CustomAction Id="TerminateAppProcess"
                   BinaryKey="WixCA"
                   DllEntry="CAQuietExec"
                   Execute="immediate"
@@ -123,8 +124,8 @@
       </InstallUISequence>
     </UI>
     <InstallExecuteSequence>
-      <Custom Action='JamiProcesses.TaskKill' Before='InstallValidate'/>
-      <Custom Action="removeOldJamiFiles" After="RemoveFiles" />
+      <Custom Action='TerminateAppProcess' Before='InstallValidate'/>
+      <Custom Action="RemoveOldJamiFiles" After="RemoveFiles" />
       <Custom Action="LaunchApplication_nonUI" After="InstallFinalize"> WIXNONUILAUNCH </Custom>
       <Custom Action="Overwrite_WixSetDefaultPerMachineFolder" After="WixSetDefaultPerMachineFolder" />
     </InstallExecuteSequence>
diff --git a/JamiInstaller/StandardComponents.wxs b/JamiInstaller/StandardComponents.wxs
index 85847159828e8c112bacb9366d9280311e1657a6..0876e216904d4c012bfc294cf543fb15463e0572 100644
--- a/JamiInstaller/StandardComponents.wxs
+++ b/JamiInstaller/StandardComponents.wxs
@@ -79,7 +79,7 @@
                 <File Id="filD6887AD9110E4A8D49143C9A8F0B5843" KeyPath="yes" Source="$(var.UcrtDir)\ucrtbase.dll" />
             </Component>
             <Component Id="cmp9CFEE34E3A162AB05264E8B756EC1DEC" Directory="APPLICATIONFOLDER" Guid="*">
-                <File Id="fileMain.exe" KeyPath="yes" Source="$(var.ReleaseDir)\Jami.exe" />
+                <File Id="fileMain.exe" KeyPath="yes" Source="$(var.ReleaseDir)\$(var.ExeName).exe" />
             </Component>
         </ComponentGroup>
     </Fragment>
diff --git a/src/instancemanager.cpp b/src/instancemanager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..11cf7fdec78300bc528c47d8d4ab8e234191eb4a
--- /dev/null
+++ b/src/instancemanager.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2019-2022 Savoir-faire Linux Inc.
+ * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "instancemanager.h"
+
+#include "mainapplication.h"
+
+#include <QCryptographicHash>
+#include <QLocalSocket>
+#include <QLocalServer>
+#include <QSharedMemory>
+#include <QSystemSemaphore>
+
+static QString
+generateKeyHash(const QString& key, const QString& salt)
+{
+    QByteArray data;
+    data.append(key.toUtf8());
+    data.append(salt.toUtf8());
+    data = QCryptographicHash::hash(data, QCryptographicHash::Sha1).toHex();
+    return data;
+}
+
+class InstanceManager::Impl : public QObject
+{
+    Q_OBJECT
+    Q_DISABLE_COPY(Impl)
+public:
+    Impl(const QString& key, MainApplication* mainApp)
+        : QObject(nullptr)
+        , mainAppInstance_(mainApp)
+        , key_(key)
+        , memLockKey_(generateKeyHash(key, "_memLockKey"))
+        , sharedmemKey_(generateKeyHash(key, "_sharedmemKey"))
+        , sharedMem_(sharedmemKey_)
+        , memLock_(memLockKey_, 1)
+    {}
+    ~Impl() = default;
+
+    bool tryToRun()
+    {
+        if (isAnotherRunning()) {
+            // This is a secondary instance,
+            // connect to the primary instance to trigger a restore
+            // then fail.
+            if (connectToLocal()) {
+                return false;
+            }
+            // If not connected, this means that the server doesn't exist
+            // and the app can be relaunched (can be the case after a client crash or Ctrl+C)
+        }
+
+        memLock_.acquire();
+        const bool result = sharedMem_.create(sizeof(quint64));
+        memLock_.release();
+        if (!result) {
+            release();
+            return false;
+        }
+
+        // This is the primary instance,
+        // listen for subsequent instances.
+        QLocalServer::removeServer(key_);
+        server_ = new QLocalServer();
+        server_->setSocketOptions(QLocalServer::UserAccessOption);
+        server_->listen(key_);
+        QObject::connect(server_,
+                         &QLocalServer::newConnection,
+                         this,
+                         &Impl::handleIncomingConnection);
+
+        return true;
+    };
+
+    void tryToKill()
+    {
+        if (!isAnotherRunning()) {
+            return;
+        }
+
+        // This is a secondary instance, connect to the primary
+        // instance to trigger a termination then fail.
+        if (!connectToLocal()) {
+            return;
+        }
+
+        socket_->write(reinterpret_cast<const char*>(terminateSeq_.data()), 4);
+        socket_->waitForBytesWritten();
+    };
+
+    void release()
+    {
+        memLock_.acquire();
+        if (sharedMem_.isAttached())
+            sharedMem_.detach();
+        memLock_.release();
+    };
+
+private Q_SLOTS:
+    bool connectToLocal()
+    {
+        if (!socket_)
+            socket_ = new QLocalSocket();
+        if (!socket_)
+            return false;
+        if (socket_->state() == QLocalSocket::UnconnectedState
+            || socket_->state() == QLocalSocket::ClosingState) {
+            socket_->connectToServer(key_);
+        }
+        if (socket_->state() == QLocalSocket::ConnectingState) {
+            socket_->waitForConnected(connectionTimeoutMs_);
+        }
+        return socket_->state() == QLocalSocket::ConnectedState;
+    }
+
+    void handleIncomingConnection()
+    {
+        connection_ = new QLocalSocket(this);
+        connection_ = server_->nextPendingConnection();
+        connect(connection_, &QLocalSocket::readyRead, this, [this] {
+            QLocalSocket* clientSocket = (QLocalSocket*) sender();
+            QByteArray recievedData;
+            recievedData = clientSocket->readAll();
+            if (recievedData == terminateSeq_) {
+                qWarning() << "Received terminate signal.";
+                mainAppInstance_->quit();
+            }
+        });
+
+        // Restore primary instance
+        mainAppInstance_->restoreApp();
+    };
+
+private:
+    MainApplication* mainAppInstance_;
+
+    const QString key_;
+    const QString memLockKey_;
+    const QString sharedmemKey_;
+
+    QSharedMemory sharedMem_;
+    QSystemSemaphore memLock_;
+
+    QLocalSocket* socket_ {nullptr};
+    QLocalServer* server_ {nullptr};
+    QLocalSocket* connection_ {nullptr};
+
+    const int connectionTimeoutMs_ {2000};
+    const QByteArray terminateSeq_ {QByteArrayLiteral("\xde\xad\xbe\xef")};
+
+    bool isAnotherRunning()
+    {
+        if (sharedMem_.isAttached())
+            return false;
+
+        memLock_.acquire();
+        const bool isRunning = sharedMem_.attach();
+        if (isRunning)
+            sharedMem_.detach();
+        memLock_.release();
+
+        return isRunning;
+    };
+};
+
+InstanceManager::InstanceManager(MainApplication* mainApp)
+    : QObject(mainApp)
+{
+    QCryptographicHash appData(QCryptographicHash::Sha256);
+    appData.addData(QApplication::applicationName().toUtf8());
+    appData.addData(QApplication::organizationDomain().toUtf8());
+    pimpl_ = std::make_unique<Impl>(appData.result(), mainApp);
+}
+
+InstanceManager::~InstanceManager()
+{
+    pimpl_->release();
+}
+
+bool
+InstanceManager::tryToRun()
+{
+    return pimpl_->tryToRun();
+}
+
+void
+InstanceManager::tryToKill()
+{
+    pimpl_->tryToKill();
+}
+
+#include "moc_instancemanager.cpp"
+#include "instancemanager.moc"
diff --git a/src/runguard.h b/src/instancemanager.h
similarity index 56%
rename from src/runguard.h
rename to src/instancemanager.h
index f1d1e287f7556c6eebb69b39a465e194ef064ac6..6da3056470a4706f4995511f90e910b79477734d 100644
--- a/src/runguard.h
+++ b/src/instancemanager.h
@@ -15,45 +15,27 @@
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
-// Based on: https://stackoverflow.com/a/28172162
 
 #pragma once
 
 #include <QObject>
-#include <QSharedMemory>
-#include <QSystemSemaphore>
-#include <QtNetwork/QLocalServer>
-#include <QtNetwork/QLocalSocket>
+
+#include <memory>
 
 class MainApplication;
 
-class RunGuard : public QObject
+class InstanceManager final : public QObject
 {
     Q_OBJECT;
-
+    Q_DISABLE_COPY(InstanceManager)
 public:
-    RunGuard(const QString& key, MainApplication* mainApp = nullptr);
-    ~RunGuard();
+    explicit InstanceManager(MainApplication* mainApp);
+    ~InstanceManager();
 
-    bool isAnotherRunning();
     bool tryToRun();
-    void release();
-
-private Q_SLOTS:
-    void tryRestorePrimaryInstance();
+    void tryToKill();
 
 private:
-    MainApplication* mainAppInstance_;
-
-    const QString key_;
-    const QString memLockKey_;
-    const QString sharedmemKey_;
-
-    QSharedMemory sharedMem_;
-    QSystemSemaphore memLock_;
-
-    QLocalSocket* socket_ {nullptr};
-    QLocalServer* server_ {nullptr};
-
-    Q_DISABLE_COPY(RunGuard)
+    class Impl;
+    std::unique_ptr<Impl> pimpl_;
 };
diff --git a/src/main.cpp b/src/main.cpp
index e8ab2806466da495f97f0f46e012df1b2f9903a9..52f6c9c9eff6770ac378bba436dcdbd8c0fad967 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,4 +1,4 @@
-/*!
+/*
  * Copyright (C) 2015-2022 Savoir-faire Linux Inc.
  * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>
  * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
@@ -19,7 +19,7 @@
  */
 
 #include "mainapplication.h"
-#include "runguard.h"
+#include "instancemanager.h"
 #include "version.h"
 
 #include <QCryptographicHash>
@@ -97,29 +97,24 @@ main(int argc, char* argv[])
 
     MainApplication app(argc, newArgv);
 
-    /*
-     * Runguard to make sure that only one instance runs at a time.
-     * Note: needs to be after the creation of the application
-     */
-    QCryptographicHash appData(QCryptographicHash::Sha256);
-    appData.addData(QApplication::applicationName().toUtf8());
-    appData.addData(QApplication::organizationDomain().toUtf8());
-    RunGuard guard(appData.result(), &app);
-    if (!guard.tryToRun()) {
+    // InstanceManager prevents multiple instances, and will handle
+    // IPC termination requests to and from secondary instances, which
+    // is used to gracefully terminate the app from an installer script
+    // during an update.
+    InstanceManager im(&app);
+    if (app.getOpt(MainApplication::Option::TerminationRequested).toBool()) {
+        qWarning() << "Attempting to terminate other instances.";
+        im.tryToKill();
+        return 0;
+    } else if (!im.tryToRun()) {
+        qWarning() << "Another instance is running.";
         return 0;
     }
 
     if (!app.init()) {
-        guard.release();
         return 0;
     }
 
-    /*
-     * Exec the application.
-     */
-    auto ret = app.exec();
-
-    guard.release();
-    return ret;
+    return app.exec();
 }
 #endif
diff --git a/src/mainapplication.cpp b/src/mainapplication.cpp
index 7bced74af70dcf057f372017a87f8a4ee2e4b4e9..8af2c3bbe2809c0bc56a89a739f07e2d1366ca74 100644
--- a/src/mainapplication.cpp
+++ b/src/mainapplication.cpp
@@ -53,16 +53,6 @@
 #include <gnutls/gnutls.h>
 #endif
 
-namespace opts {
-// Keys used to store command-line options.
-constexpr static const char STARTMINIMIZED[] = "STARTMINIMIZED";
-constexpr static const char DEBUG[] = "DEBUG";
-constexpr static const char DEBUGCONSOLE[] = "DEBUGCONSOLE";
-constexpr static const char DEBUGFILE[] = "DEBUGFILE";
-constexpr static const char UPDATEURL[] = "UPDATEURL";
-constexpr static const char MUTEDAEMON[] = "MUTEDAEMON";
-} // namespace opts
-
 static void
 consoleDebug()
 {
@@ -147,6 +137,7 @@ MainApplication::fileDebug(QFile* debugFile)
 MainApplication::MainApplication(int& argc, char** argv)
     : QApplication(argc, argv)
 {
+    parseArguments();
     QObject::connect(this, &QApplication::aboutToQuit, [this] { cleanup(); });
 }
 
@@ -179,9 +170,7 @@ MainApplication::init()
         setenv("QT_QPA_PLATFORMTHEME", "gtk3", true);
 #endif
 
-    auto results = parseArguments();
-
-    if (results[opts::DEBUG].toBool()) {
+    if (runOptions_[Option::Debug].toBool()) {
         consoleDebug();
     }
 
@@ -193,9 +182,9 @@ MainApplication::init()
     gnutls_global_init();
 #endif
 
-    initLrc(results[opts::UPDATEURL].toString(),
+    initLrc(runOptions_[Option::UpdateUrl].toString(),
             connectivityMonitor_.get(),
-            results[opts::DEBUG].toBool() && !results[opts::MUTEDAEMON].toBool());
+            runOptions_[Option::Debug].toBool() && !runOptions_[Option::MuteJamid].toBool());
 
 #if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
     using namespace Interfaces;
@@ -206,10 +195,12 @@ MainApplication::init()
         engine_->load(QUrl(QStringLiteral("qrc:/src/DaemonReconnectWindow.qml")));
         exec();
 
-        if ((!lrc::api::Lrc::isConnected()) || (!lrc::api::Lrc::dbusIsValid()))
+        if ((!lrc::api::Lrc::isConnected()) || (!lrc::api::Lrc::dbusIsValid())) {
+            qWarning() << "Can't connect to the daemon via D-Bus.";
             return false;
-        else
+        } else {
             engine_.reset(new QQmlApplicationEngine());
+        }
     }
 #endif
 
@@ -228,14 +219,14 @@ MainApplication::init()
         [this] { engine_->quit(); },
         Qt::DirectConnection);
 
-    if (results[opts::DEBUGFILE].toBool()) {
+    if (runOptions_[Option::DebugToFile].toBool()) {
         debugFile_.reset(new QFile(getDebugFilePath()));
         debugFile_->open(QIODevice::WriteOnly | QIODevice::Truncate);
         debugFile_->close();
         fileDebug(debugFile_.get());
     }
 
-    if (results[opts::DEBUGCONSOLE].toBool()) {
+    if (runOptions_[Option::DebugToConsole].toBool()) {
         vsConsoleDebug();
     }
 
@@ -253,7 +244,7 @@ MainApplication::init()
     initQmlLayer();
 
     settingsManager_->setValue(Settings::Key::StartMinimized,
-                               results[opts::STARTMINIMIZED].toBool());
+                               runOptions_[Option::StartMinimized].toBool());
 
     initSystray();
 
@@ -296,10 +287,9 @@ MainApplication::initLrc(const QString& downloadUrl, ConnectivityMonitor* cm, bo
     lrcInstance_->subscribeToDebugReceived();
 }
 
-const QVariantMap
+void
 MainApplication::parseArguments()
 {
-    QVariantMap results;
     QCommandLineParser parser;
     parser.addHelpOption();
     parser.addVersionOption();
@@ -325,32 +315,34 @@ MainApplication::parseArguments()
     QCommandLineOption debugOption({"d", "debug"}, "Debug out.");
     parser.addOption(debugOption);
 
+    QCommandLineOption debugFileOption({"f", "file"}, "Debug to file.");
+    parser.addOption(debugFileOption);
+
 #ifdef Q_OS_WINDOWS
     QCommandLineOption debugConsoleOption({"c", "console"}, "Debug out to IDE console.");
     parser.addOption(debugConsoleOption);
 
-    QCommandLineOption debugFileOption({"f", "file"}, "Debug to file.");
-    parser.addOption(debugFileOption);
-
     QCommandLineOption updateUrlOption({"u", "url"}, "<url> for debugging version queries.", "url");
     parser.addOption(updateUrlOption);
+
 #endif
+    QCommandLineOption terminateOption({"t", "term"}, "Terminate all instances.");
+    parser.addOption(terminateOption);
 
     QCommandLineOption muteDaemonOption({"q", "quiet"}, "Mute daemon logging. (only if debug)");
     parser.addOption(muteDaemonOption);
 
     parser.process(*this);
 
-    results[opts::STARTMINIMIZED] = parser.isSet(minimizedOption);
-    results[opts::DEBUG] = parser.isSet(debugOption);
+    runOptions_[Option::StartMinimized] = parser.isSet(minimizedOption);
+    runOptions_[Option::Debug] = parser.isSet(debugOption);
+    runOptions_[Option::DebugToFile] = parser.isSet(debugFileOption);
 #ifdef Q_OS_WINDOWS
-    results[opts::DEBUGCONSOLE] = parser.isSet(debugConsoleOption);
-    results[opts::DEBUGFILE] = parser.isSet(debugFileOption);
-    results[opts::UPDATEURL] = parser.value(updateUrlOption);
+    runOptions_[Option::DebugToConsole] = parser.isSet(debugConsoleOption);
+    runOptions_[Option::UpdateUrl] = parser.value(updateUrlOption);
 #endif
-    results[opts::MUTEDAEMON] = parser.isSet(muteDaemonOption);
-
-    return results;
+    runOptions_[Option::TerminationRequested] = parser.isSet(terminateOption);
+    runOptions_[Option::MuteJamid] = parser.isSet(muteDaemonOption);
 }
 
 void
diff --git a/src/mainapplication.h b/src/mainapplication.h
index 9de1b751fc5525a549e9134ec04693421800dfd8..f2b06d9747e88f97011fc7fa82abdaebdb792b79 100644
--- a/src/mainapplication.h
+++ b/src/mainapplication.h
@@ -57,6 +57,7 @@ private:
 class MainApplication : public QApplication
 {
     Q_OBJECT
+    Q_DISABLE_COPY(MainApplication)
 
 public:
     explicit MainApplication(int& argc, char** argv);
@@ -65,21 +66,36 @@ public:
     bool init();
     void restoreApp();
 
+    enum class Option {
+        StartMinimized = 0,
+        Debug,
+        DebugToConsole,
+        DebugToFile,
+        UpdateUrl,
+        MuteJamid,
+        TerminationRequested
+    };
+    QVariant getOpt(const Option opt)
+    {
+        return runOptions_[opt];
+    };
+
 Q_SIGNALS:
     void closeRequested();
 
 private:
     void vsConsoleDebug();
     void fileDebug(QFile* debugFile);
-
     void initLrc(const QString& downloadUrl, ConnectivityMonitor* cm, bool logDaemon);
-    const QVariantMap parseArguments();
+    void parseArguments();
     void setApplicationFont();
     void initQmlLayer();
     void initSystray();
     void cleanup();
 
 private:
+    std::map<Option, QVariant> runOptions_;
+
     QScopedPointer<QFile> debugFile_;
     QScopedPointer<QQmlApplicationEngine> engine_;
     QScopedPointer<LRCInstance> lrcInstance_;
diff --git a/src/runguard.cpp b/src/runguard.cpp
deleted file mode 100644
index 8c4d46b3ff55adc6b5aaa2ed5ac9b6f15ff28bdd..0000000000000000000000000000000000000000
--- a/src/runguard.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2019-2022 Savoir-faire Linux Inc.
- * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-// Based on: https://stackoverflow.com/a/28172162
-
-#include "runguard.h"
-
-#include "mainapplication.h"
-
-#include <QCryptographicHash>
-#include <QLocalSocket>
-
-namespace {
-
-QString
-generateKeyHash(const QString& key, const QString& salt)
-{
-    QByteArray data;
-
-    data.append(key.toUtf8());
-    data.append(salt.toUtf8());
-    data = QCryptographicHash::hash(data, QCryptographicHash::Sha1).toHex();
-
-    return data;
-}
-
-} // namespace
-
-RunGuard::RunGuard(const QString& key, MainApplication* mainApp)
-    : key_(key)
-    , memLockKey_(generateKeyHash(key, "_memLockKey"))
-    , sharedmemKey_(generateKeyHash(key, "_sharedmemKey"))
-    , sharedMem_(sharedmemKey_)
-    , memLock_(memLockKey_, 1)
-    , mainAppInstance_(mainApp)
-{}
-
-RunGuard::~RunGuard()
-{
-    release();
-}
-
-void
-RunGuard::tryRestorePrimaryInstance()
-{
-    mainAppInstance_->restoreApp();
-}
-
-bool
-RunGuard::isAnotherRunning()
-{
-    if (sharedMem_.isAttached())
-        return false;
-
-    memLock_.acquire();
-    const bool isRunning = sharedMem_.attach();
-    if (isRunning)
-        sharedMem_.detach();
-    memLock_.release();
-
-    return isRunning;
-}
-
-bool
-RunGuard::tryToRun()
-{
-    if (isAnotherRunning()) {
-        /*
-         * This is a secondary instance,
-         * connect to the primary instance to trigger a restore
-         * then fail.
-         */
-        if (!socket_)
-            socket_ = new QLocalSocket();
-        if (!socket_)
-            return false;
-        if (socket_->state() == QLocalSocket::UnconnectedState
-            || socket_->state() == QLocalSocket::ClosingState) {
-            socket_->connectToServer(key_);
-        }
-        if (socket_->state() == QLocalSocket::ConnectingState) {
-            socket_->waitForConnected();
-        }
-        if (socket_->state() == QLocalSocket::ConnectedState) {
-            return false;
-        }
-        // If not connected, this means that the server doesn't exists
-        // and the app can be relaunched (can be the case after a client crash or Ctrl+C)
-    }
-
-    memLock_.acquire();
-    const bool result = sharedMem_.create(sizeof(quint64));
-    memLock_.release();
-    if (!result) {
-        release();
-        return false;
-    }
-
-    /*
-     * This is the primary instance,
-     * listen for subsequent instances.
-     */
-    QLocalServer::removeServer(key_);
-    server_ = new QLocalServer();
-    server_->setSocketOptions(QLocalServer::UserAccessOption);
-    server_->listen(key_);
-    QObject::connect(server_,
-                     &QLocalServer::newConnection,
-                     this,
-                     &RunGuard::tryRestorePrimaryInstance);
-
-    return true;
-}
-
-void
-RunGuard::release()
-{
-    memLock_.acquire();
-    if (sharedMem_.isAttached())
-        sharedMem_.detach();
-    memLock_.release();
-}