diff options
author | Konstantinos Sideris <sideris.konstantin@gmail.com> | 2017-12-14 21:55:00 +0200 |
---|---|---|
committer | Konstantinos Sideris <sideris.konstantin@gmail.com> | 2017-12-14 21:55:00 +0200 |
commit | 65672d3dfbdf179df520bbaa5e7e7ba28a27db20 (patch) | |
tree | 3db1f2f563f989ecbc64af9048c2285268c2b59f | |
parent | Upgrade appveyor to Qt 5.9.2 (diff) | |
download | nheko-65672d3dfbdf179df520bbaa5e7e7ba28a27db20.tar.xz |
Allow only one application instance
fixes #141
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | include/RunGuard.h | 31 | ||||
-rw-r--r-- | src/RunGuard.cc | 84 | ||||
-rw-r--r-- | src/main.cc | 69 |
4 files changed, 180 insertions, 5 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a0a1360..de45f864 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -199,6 +199,7 @@ set(SRC_FILES src/RoomList.cc src/RoomMessages.cc src/RoomState.cc + src/RunGuard.cc src/SideBarActions.cc src/Splitter.cc src/TextInputWidget.cc diff --git a/include/RunGuard.h b/include/RunGuard.h new file mode 100644 index 00000000..f9a9641a --- /dev/null +++ b/include/RunGuard.h @@ -0,0 +1,31 @@ +#pragma once + +// +// Taken from +// https://stackoverflow.com/questions/5006547/qt-best-practice-for-a-single-instance-app-protection +// + +#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) +}; diff --git a/src/RunGuard.cc b/src/RunGuard.cc new file mode 100644 index 00000000..75833eb7 --- /dev/null +++ b/src/RunGuard.cc @@ -0,0 +1,84 @@ +#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(); + { + // Fix for *nix: http://habrahabr.ru/post/173281/ + QSharedMemory fix(sharedmemKey); + 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() +{ + // Extra check + if (isAnotherRunning()) + return false; + + memLock.acquire(); + const bool result = sharedMem.create(sizeof(quint64)); + memLock.release(); + + if (!result) { + release(); + return false; + } + + return true; +} + +void +RunGuard::release() +{ + memLock.acquire(); + + if (sharedMem.isAttached()) + sharedMem.detach(); + + memLock.release(); +} diff --git a/src/main.cc b/src/main.cc index 89731ec7..5138ec1b 100644 --- a/src/main.cc +++ b/src/main.cc @@ -19,12 +19,31 @@ #include <QDesktopWidget> #include <QFile> #include <QFontDatabase> +#include <QLabel> +#include <QLayout> #include <QLibraryInfo> #include <QNetworkProxy> +#include <QPalette> +#include <QPoint> +#include <QPushButton> #include <QSettings> #include <QTranslator> +#include "Config.h" #include "MainWindow.h" +#include "RaisedButton.h" +#include "RunGuard.h" + +QPoint +screenCenter(int width, int height) +{ + QRect screenGeometry = QApplication::desktop()->screenGeometry(); + + int x = (screenGeometry.width() - width) / 2; + int y = (screenGeometry.height() - height) / 2; + + return QPoint(x, y); +} void setupProxy() @@ -55,6 +74,50 @@ setupProxy() int main(int argc, char *argv[]) { + RunGuard guard("run_guard"); + + if (!guard.tryToRun()) { + QApplication a(argc, argv); + + QFont font; + font.setPointSize(15); + font.setWeight(60); + + QWidget widget; + QVBoxLayout layout(&widget); + layout.setContentsMargins(20, 10, 20, 20); + layout.setSpacing(0); + + QHBoxLayout btnLayout; + + QLabel msg("Another instance of nheko is currently running."); + msg.setWordWrap(true); + msg.setFont(font); + + QPalette pal; + + RaisedButton submitBtn("OK"); + submitBtn.setBackgroundColor(pal.color(QPalette::Button)); + submitBtn.setForegroundColor(pal.color(QPalette::ButtonText)); + submitBtn.setMinimumSize(120, 35); + submitBtn.setFontSize(conf::btn::fontSize); + submitBtn.setCornerRadius(conf::btn::cornerRadius); + + btnLayout.addStretch(1); + btnLayout.addWidget(&submitBtn); + + layout.addWidget(&msg); + layout.addLayout(&btnLayout); + + widget.setFixedSize(480, 180); + widget.move(screenCenter(widget.width(), widget.height())); + widget.show(); + + QObject::connect(&submitBtn, &QPushButton::clicked, &widget, &QWidget::close); + + return a.exec(); + } + QCoreApplication::setApplicationName("nheko"); QCoreApplication::setApplicationVersion("0.1.0"); QCoreApplication::setOrganizationName("nheko"); @@ -95,11 +158,7 @@ main(int argc, char *argv[]) MainWindow w; // Move the MainWindow to the center - QRect screenGeometry = QApplication::desktop()->screenGeometry(); - int x = (screenGeometry.width() - w.width()) / 2; - int y = (screenGeometry.height() - w.height()) / 2; - - w.move(x, y); + w.move(screenCenter(w.width(), w.height())); w.show(); QObject::connect(&app, &QApplication::aboutToQuit, &w, &MainWindow::saveCurrentWindowSize); |