Browse Source

support single instance app

Signed-off-by: Le Tan <[email protected]>
Le Tan 9 years ago
parent
commit
50db1a63ba
4 changed files with 116 additions and 2 deletions
  1. 6 0
      src/main.cpp
  2. 4 2
      src/src.pro
  3. 73 0
      src/vsingleinstanceguard.cpp
  4. 33 0
      src/vsingleinstanceguard.h

+ 6 - 0
src/main.cpp

@@ -3,9 +3,15 @@
 #include <QFile>
 #include <QTextCodec>
 #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");

+ 4 - 2
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

+ 73 - 0
src/vsingleinstanceguard.cpp

@@ -0,0 +1,73 @@
+#include "vsingleinstanceguard.h"
+#include <QDebug>
+
+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;
+        }
+    }
+}

+ 33 - 0
src/vsingleinstanceguard.h

@@ -0,0 +1,33 @@
+#ifndef VSINGLEINSTANCEGUARD_H
+#define VSINGLEINSTANCEGUARD_H
+
+#include <QString>
+#include <QSharedMemory>
+#include <QSystemSemaphore>
+
+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