changeset 228:37d5f4329449

Implement single running instance check to prevent problems with the SQLite database.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 20 Mar 2018 13:45:21 +0200
parents 07e7f254ef16
children fa4a628a4961
files Makefile.gen src/main.cpp src/runguard.cpp src/runguard.h
diffstat 4 files changed, 139 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.gen	Mon Mar 12 10:52:21 2018 +0200
+++ b/Makefile.gen	Tue Mar 20 13:45:21 2018 +0200
@@ -25,7 +25,7 @@
 APP_SRC=src/
 APP_IMG=img/
 APP_BIN=$(BINPATH)Syntilista$(EXEEXT)
-APP_OBJS=main.o sqlmodels.o printing.o resources.o moc_main.o
+APP_OBJS=main.o sqlmodels.o printing.o resources.o moc_main.o runguard.o
 APP_VERSION := $(shell cat VERSION)
 comma:= ,
 APP_VERSION_COM := $(subst .,$(comma),$(APP_VERSION))
--- a/src/main.cpp	Mon Mar 12 10:52:21 2018 +0200
+++ b/src/main.cpp	Tue Mar 20 13:45:21 2018 +0200
@@ -15,6 +15,7 @@
 #include "ui_editperson.h"
 #include "ui_aboutwindow.h"
 #include "ui_viewtransactions.h"
+#include "runguard.h"
 
 
 //
@@ -262,6 +263,20 @@
     QApplication sapp(argc, argv);
     QSettings tmpst(APP_VENDOR, APP_ID);
 
+    // Check for multiple instances
+    RunGuard guard(QStringLiteral(APP_VENDOR) + QStringLiteral(APP_ID));
+    if (!guard.tryToRun())
+    {
+        slErrorMsg(
+            QObject::tr("Virhe!"),
+            QObject::tr(
+            "Syntilista-sovellus on jo käynnissä. Sulje tämä ikkuna ja "
+            "etsi ajossa oleva Syntilista-sovellus tehtäväpalkista."
+            )
+            );
+        return 1;
+    }
+
     // Read configuration settings
     settings.uiPos = tmpst.value("pos", QPoint(100, 100)).toPoint();
     settings.uiSize = tmpst.value("size", QSize(1000, 600)).toSize();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/runguard.cpp	Tue Mar 20 13:45:21 2018 +0200
@@ -0,0 +1,88 @@
+//
+// Taken and modified from https://stackoverflow.com/questions/5006547/qt-best-practice-for-a-single-instance-app-protection
+//
+#include "runguard.h"
+#include <QCryptographicHash>
+
+
+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;
+}
+
+}
+
+
+RunGuard::RunGuard(const QString &key)
+    : key(key)
+    , memLockKey(generateKeyHash(key, "_memLockKey"))
+    , sharedmemKey(generateKeyHash(key, "_sharedmemKey"))
+    , sharedMem(sharedmemKey)
+    , memLock(memLockKey, 1)
+{
+    memLock.acquire();
+
+    QSharedMemory fix(sharedmemKey); // Fix for *nix: http://habrahabr.ru/post/173281/
+    fix.attach();
+
+    memLock.release();
+}
+
+
+RunGuard::~RunGuard()
+{
+    release();
+}
+
+
+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())
+        return false;
+
+    memLock.acquire();
+    const bool result = sharedMem.create(sizeof(quint64));
+    memLock.release();
+
+    if (!result)
+        release();
+
+    return result;
+}
+
+
+void RunGuard::release()
+{
+    memLock.acquire();
+
+    if (sharedMem.isAttached())
+        sharedMem.detach();
+
+    memLock.release();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/runguard.h	Tue Mar 20 13:45:21 2018 +0200
@@ -0,0 +1,35 @@
+//
+// Taken and modified from https://stackoverflow.com/questions/5006547/qt-best-practice-for-a-single-instance-app-protection
+//
+#ifndef RUNGUARD_H
+#define RUNGUARD_H
+
+#include <QObject>
+#include <QSharedMemory>
+#include <QSystemSemaphore>
+
+
+class RunGuard
+{
+
+public:
+    RunGuard(const QString &key);
+    ~RunGuard();
+
+    bool isAnotherRunning();
+    bool tryToRun();
+    void release();
+
+private:
+    const QString key;
+    const QString memLockKey;
+    const QString sharedmemKey;
+
+    QSharedMemory sharedMem;
+    QSystemSemaphore memLock;
+
+    Q_DISABLE_COPY(RunGuard)
+};
+
+
+#endif // RUNGUARD_H