Mercurial > hg > syntilista
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