diff --git a/src/main.cpp b/src/main.cpp index 3eacdf9f..1c1fc2a6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,9 +3,15 @@ #include #include #include "utils/vutils.h" +#include "vsingleinstanceguard.h" int main(int argc, char *argv[]) { + VSingleInstanceGuard guard; + if (!guard.tryRun()) { + return 0; + } + QApplication app(argc, argv); QTextCodec *codec = QTextCodec::codecForName("UTF8"); diff --git a/src/src.pro b/src/src.pro index a03493c6..f79e117b 100644 --- a/src/src.pro +++ b/src/src.pro @@ -43,7 +43,8 @@ SOURCES += main.cpp\ vedittab.cpp \ voutline.cpp \ vtoc.cpp \ - vfilelocation.cpp + vfilelocation.cpp \ + vsingleinstanceguard.cpp HEADERS += vmainwindow.h \ vdirectorytree.h \ @@ -75,7 +76,8 @@ HEADERS += vmainwindow.h \ vedittab.h \ voutline.h \ vtoc.h \ - vfilelocation.h + vfilelocation.h \ + vsingleinstanceguard.h RESOURCES += \ vnote.qrc diff --git a/src/vsingleinstanceguard.cpp b/src/vsingleinstanceguard.cpp new file mode 100644 index 00000000..4d4b2a73 --- /dev/null +++ b/src/vsingleinstanceguard.cpp @@ -0,0 +1,73 @@ +#include "vsingleinstanceguard.h" +#include + +const QString VSingleInstanceGuard::m_memKey = "vnote_shared_memory"; +const QString VSingleInstanceGuard::m_semKey = "vnote_semaphore"; +const int VSingleInstanceGuard::m_magic = 133191933; + +VSingleInstanceGuard::VSingleInstanceGuard() + : m_sharedMemory(m_memKey), m_sem(m_semKey, 1) +{ +} + +VSingleInstanceGuard::~VSingleInstanceGuard() +{ + if (m_sharedMemory.isAttached()) { + detachMemory(); + } +} + +void VSingleInstanceGuard::detachMemory() +{ + m_sem.acquire(); + m_sharedMemory.detach(); + m_sem.release(); +} + +bool VSingleInstanceGuard::tryAttach() +{ + m_sem.acquire(); + bool ret = m_sharedMemory.attach(); + m_sem.release(); + if (ret) { + m_sharedMemory.lock(); + SharedStruct *str = (SharedStruct *)m_sharedMemory.data(); + str->m_activeRequest = 1; + m_sharedMemory.unlock(); + detachMemory(); + } + return ret; +} + +bool VSingleInstanceGuard::tryRun() +{ + // If we can attach to the sharedmemory, there is another instance running. + if (tryAttach()) { + qDebug() << "Another instance is running"; + return false; + } + + // Try to create it + m_sem.acquire(); + bool ret = m_sharedMemory.create(sizeof(SharedStruct)); + m_sem.release(); + if (ret) { + // We created it + m_sharedMemory.lock(); + SharedStruct *str = (SharedStruct *)m_sharedMemory.data(); + str->m_magic = m_magic; + str->m_activeRequest = 0; + m_sharedMemory.unlock(); + return true; + } else { + // Maybe another thread create it + if (tryAttach()) { + qDebug() << "Another instance is running"; + return false; + } else { + // Something wrong here + qWarning() << "error: failed to create or attach shared memory segment"; + return false; + } + } +} diff --git a/src/vsingleinstanceguard.h b/src/vsingleinstanceguard.h new file mode 100644 index 00000000..1a4cd6cb --- /dev/null +++ b/src/vsingleinstanceguard.h @@ -0,0 +1,33 @@ +#ifndef VSINGLEINSTANCEGUARD_H +#define VSINGLEINSTANCEGUARD_H + +#include +#include +#include + +class VSingleInstanceGuard +{ +public: + VSingleInstanceGuard(); + ~VSingleInstanceGuard(); + bool tryRun(); + +private: + void detachMemory(); + bool tryAttach(); + + struct SharedStruct { + // A magic number to identify if this struct is initialized + int m_magic; + // If it is 1, then another instance ask this instance to show itself + int m_activeRequest; + }; + + static const QString m_memKey; + static const QString m_semKey; + static const int m_magic; + QSharedMemory m_sharedMemory; + QSystemSemaphore m_sem; +}; + +#endif // VSINGLEINSTANCEGUARD_H