support opening external files from context menu in system browser

This commit is contained in:
Le Tan 2017-07-17 22:16:41 +08:00
parent e33ff1fede
commit 0b9d259de6
12 changed files with 288 additions and 85 deletions

View File

@ -6,6 +6,8 @@
#include <QFile> #include <QFile>
#include <QTextCodec> #include <QTextCodec>
#include <QFileInfo> #include <QFileInfo>
#include <QStringList>
#include <QDir>
#include "utils/vutils.h" #include "utils/vutils.h"
#include "vsingleinstanceguard.h" #include "vsingleinstanceguard.h"
#include "vconfigmanager.h" #include "vconfigmanager.h"
@ -91,16 +93,18 @@ void VLogger(QtMsgType type, const QMessageLogContext &context, const QString &m
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
VSingleInstanceGuard guard;
bool canRun = guard.tryRun();
#if defined(QT_NO_DEBUG) #if defined(QT_NO_DEBUG)
if (canRun) {
g_logFile.setFileName(VConfigManager::getLogFilePath()); g_logFile.setFileName(VConfigManager::getLogFilePath());
g_logFile.open(QIODevice::WriteOnly); g_logFile.open(QIODevice::WriteOnly);
}
#endif #endif
if (canRun) {
qInstallMessageHandler(VLogger); qInstallMessageHandler(VLogger);
VSingleInstanceGuard guard;
if (!guard.tryRun()) {
return 0;
} }
QTextCodec *codec = QTextCodec::codecForName("UTF8"); QTextCodec *codec = QTextCodec::codecForName("UTF8");
@ -109,6 +113,35 @@ int main(int argc, char *argv[])
} }
QApplication app(argc, argv); QApplication app(argc, argv);
// The file path passed via command line arguments.
QStringList filePaths;
QStringList args = app.arguments();
for (int i = 1; i < args.size(); ++i) {
if (QFileInfo::exists(args[i])) {
QString filePath = args[i];
QFileInfo fi(filePath);
if (fi.isFile()) {
// Need to use absolute path here since VNote may be launched
// in different working directory.
filePath = QDir::cleanPath(fi.absoluteFilePath());
}
filePaths.append(filePath);
}
}
qDebug() << "command line arguments" << args;
if (!canRun) {
// Ask another instance to open files passed in.
if (!filePaths.isEmpty()) {
guard.openExternalFiles(filePaths);
}
return 0;
}
vconfig.initialize(); vconfig.initialize();
QString locale = VUtils::getLocale(); QString locale = VUtils::getLocale();
@ -119,6 +152,7 @@ int main(int argc, char *argv[])
if (!qtTranslator.load("qt_" + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) { if (!qtTranslator.load("qt_" + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
qtTranslator.load("qt_" + locale, "translations"); qtTranslator.load("qt_" + locale, "translations");
} }
app.installTranslator(&qtTranslator); app.installTranslator(&qtTranslator);
// load translation for vnote // load translation for vnote
@ -128,7 +162,7 @@ int main(int argc, char *argv[])
app.installTranslator(&translator); app.installTranslator(&translator);
} }
VMainWindow w; VMainWindow w(&guard);
QString style = VUtils::readFileFromDisk(":/resources/vnote.qss"); QString style = VUtils::readFileFromDisk(":/resources/vnote.qss");
if (!style.isEmpty()) { if (!style.isEmpty()) {
VUtils::processStyle(style, w.getPalette()); VUtils::processStyle(style, w.getPalette());
@ -137,5 +171,7 @@ int main(int argc, char *argv[])
w.show(); w.show();
w.openExternalFiles(filePaths);
return app.exec(); return app.exec();
} }

View File

@ -6,7 +6,7 @@
- `Ctrl+E E` - `Ctrl+E E`
Toggle expanding the edit area. Toggle expanding the edit area.
- `Ctrl+Alt+N` - `Ctrl+Alt+N`
Create a note in current directory. Create a note in current folder.
- `Ctrl+F` - `Ctrl+F`
Find/Replace in current note. Find/Replace in current note.
- `Ctrl+Q` - `Ctrl+Q`
@ -135,7 +135,7 @@ Number key 1 to 9 will jump to the tabs with corresponding sequence number.
- `0` - `0`
Jump to previous tab. Alternate between current and previous tab. Jump to previous tab. Alternate between current and previous tab.
- `D` - `D`
Locate to the directory of current note. Locate to the folder of current note.
- `Q` - `Q`
Discard current changes and exit edit mode. Discard current changes and exit edit mode.
- `V` - `V`

View File

@ -136,7 +136,7 @@ size=8
- `0` - `0`
跳转到前一个标签页(即前一个当前标签页)。实现当前标签页和前一个标签页之间的轮换。 跳转到前一个标签页(即前一个当前标签页)。实现当前标签页和前一个标签页之间的轮换。
- `D` - `D`
定位当前笔记所在目录 定位当前笔记所在文件夹
- `Q` - `Q`
放弃当前更改并退出编辑模式。 放弃当前更改并退出编辑模式。
- `V` - `V`

View File

@ -34,7 +34,7 @@ background: 005fff
editor-current-line editor-current-line
background: c5cae9 background: c5cae9
# [VNote] Vim insert mode cursor line background # [VNote] Vim insert mode cursor line background
vim-insert-background: cdc0b0 vim-insert-background: bcbcbc
# [VNote] Vim normal mode cursor line background # [VNote] Vim normal mode cursor line background
vim-normal-background: b0bec5 vim-normal-background: b0bec5
# [VNote] Vim visual mode cursor line background # [VNote] Vim visual mode cursor line background

View File

@ -131,6 +131,20 @@ void VEditWindow::initTabActions()
g_vnote->getMainWindow()->editOrphanFileInfo(file); g_vnote->getMainWindow()->editOrphanFileInfo(file);
} }
}); });
m_openLocationAct = new QAction(tr("Open Note Location"), this);
m_openLocationAct->setToolTip(tr("Open the folder containing this note in operating system"));
connect(m_openLocationAct, &QAction::triggered,
this, [this](){
int tab = this->m_closeTabAct->data().toInt();
Q_ASSERT(tab != -1);
VEditTab *editor = getTab(tab);
QPointer<VFile> file = editor->getFile();
Q_ASSERT(file);
QUrl url = QUrl::fromLocalFile(file->retriveBasePath());
QDesktopServices::openUrl(url);
});
} }
void VEditWindow::setupCornerWidget() void VEditWindow::setupCornerWidget()
@ -527,10 +541,17 @@ void VEditWindow::tabbarContextMenuRequested(QPoint p_pos)
// Locate to folder. // Locate to folder.
m_locateAct->setData(tab); m_locateAct->setData(tab);
menu.addAction(m_locateAct); menu.addAction(m_locateAct);
m_openLocationAct->setData(tab);
menu.addAction(m_openLocationAct);
m_noteInfoAct->setData(tab); m_noteInfoAct->setData(tab);
menu.addAction(m_noteInfoAct); menu.addAction(m_noteInfoAct);
} else if (file->getType() == FileType::Orphan } else if (file->getType() == FileType::Orphan
&& !dynamic_cast<VOrphanFile *>(file)->isSystemFile()) { && !dynamic_cast<VOrphanFile *>(file)->isSystemFile()) {
m_openLocationAct->setData(tab);
menu.addAction(m_openLocationAct);
m_noteInfoAct->setData(tab); m_noteInfoAct->setData(tab);
menu.addAction(m_noteInfoAct); menu.addAction(m_noteInfoAct);
} }

View File

@ -168,6 +168,9 @@ private:
// View and edit info about this note. // View and edit info about this note.
QAction *m_noteInfoAct; QAction *m_noteInfoAct;
// Open the location (the folder containing this file) of this note.
QAction *m_openLocationAct;
}; };
inline QString VEditWindow::generateTooltip(const VFile *p_file) const inline QString VEditWindow::generateTooltip(const VFile *p_file) const

View File

@ -25,17 +25,20 @@
#include "dialog/vupdater.h" #include "dialog/vupdater.h"
#include "vorphanfile.h" #include "vorphanfile.h"
#include "dialog/vorphanfileinfodialog.h" #include "dialog/vorphanfileinfodialog.h"
#include "vsingleinstanceguard.h"
extern VConfigManager vconfig; extern VConfigManager vconfig;
VNote *g_vnote; VNote *g_vnote;
const int VMainWindow::c_sharedMemTimerInterval = 1000;
#if defined(QT_NO_DEBUG) #if defined(QT_NO_DEBUG)
extern QFile g_logFile; extern QFile g_logFile;
#endif #endif
VMainWindow::VMainWindow(QWidget *parent) VMainWindow::VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent)
: QMainWindow(parent), m_onePanel(false) : QMainWindow(p_parent), m_onePanel(false), m_guard(p_guard)
{ {
setWindowIcon(QIcon(":/resources/icons/vnote.ico")); setWindowIcon(QIcon(":/resources/icons/vnote.ico"));
vnote = new VNote(this); vnote = new VNote(this);
@ -56,6 +59,19 @@ VMainWindow::VMainWindow(QWidget *parent)
notebookSelector->update(); notebookSelector->update();
initCaptain(); initCaptain();
initSharedMemoryWatcher();
}
void VMainWindow::initSharedMemoryWatcher()
{
m_sharedMemTimer = new QTimer(this);
m_sharedMemTimer->setSingleShot(false);
m_sharedMemTimer->setInterval(c_sharedMemTimerInterval);
connect(m_sharedMemTimer, &QTimer::timeout,
this, &VMainWindow::checkSharedMemory);
m_sharedMemTimer->start();
} }
void VMainWindow::initCaptain() void VMainWindow::initCaptain()
@ -1349,6 +1365,10 @@ void VMainWindow::setEditorStyle(QAction *p_action)
void VMainWindow::updateActionStateFromTabStatusChange(const VFile *p_file, void VMainWindow::updateActionStateFromTabStatusChange(const VFile *p_file,
bool p_editMode) bool p_editMode)
{ {
bool systemFile = p_file
&& p_file->getType() == FileType::Orphan
&& dynamic_cast<const VOrphanFile *>(p_file)->isSystemFile();
m_printAct->setEnabled(p_file && p_file->getDocType() == DocType::Markdown); m_printAct->setEnabled(p_file && p_file->getDocType() == DocType::Markdown);
m_exportAsPDFAct->setEnabled(p_file && p_file->getDocType() == DocType::Markdown); m_exportAsPDFAct->setEnabled(p_file && p_file->getDocType() == DocType::Markdown);
@ -1356,8 +1376,8 @@ void VMainWindow::updateActionStateFromTabStatusChange(const VFile *p_file,
discardExitAct->setVisible(p_file && p_editMode); discardExitAct->setVisible(p_file && p_editMode);
saveExitAct->setVisible(p_file && p_editMode); saveExitAct->setVisible(p_file && p_editMode);
saveNoteAct->setVisible(p_file && p_editMode); saveNoteAct->setVisible(p_file && p_editMode);
deleteNoteAct->setVisible(p_file && p_file->isModifiable()); deleteNoteAct->setVisible(p_file && p_file->getType() == FileType::Normal);
noteInfoAct->setVisible(p_file && p_file->getType() == FileType::Normal); noteInfoAct->setVisible(p_file && !systemFile);
m_closeNoteAct->setVisible(p_file); m_closeNoteAct->setVisible(p_file);
m_insertImageAct->setEnabled(p_file && p_editMode); m_insertImageAct->setEnabled(p_file && p_editMode);
@ -1483,17 +1503,25 @@ void VMainWindow::updateWindowTitle(const QString &str)
void VMainWindow::curEditFileInfo() void VMainWindow::curEditFileInfo()
{ {
if (!m_curFile || m_curFile->getType() != FileType::Normal) { Q_ASSERT(m_curFile);
return;
} if (m_curFile->getType() == FileType::Normal) {
fileList->fileInfo(m_curFile); fileList->fileInfo(m_curFile);
} else if (m_curFile->getType() == FileType::Orphan) {
VOrphanFile *file = dynamic_cast<VOrphanFile *>((VFile *)m_curFile);
Q_ASSERT(file);
if (!file->isSystemFile()) {
editOrphanFileInfo(m_curFile);
}
}
} }
void VMainWindow::deleteCurNote() void VMainWindow::deleteCurNote()
{ {
if (!m_curFile || !m_curFile->isModifiable()) { if (!m_curFile || m_curFile->getType() != FileType::Normal) {
return; return;
} }
fileList->deleteFile(m_curFile); fileList->deleteFile(m_curFile);
} }
@ -1828,3 +1856,16 @@ void VMainWindow::editOrphanFileInfo(VFile *p_file)
file->setImageFolder(imgFolder); file->setImageFolder(imgFolder);
} }
} }
void VMainWindow::checkSharedMemory()
{
QStringList files = m_guard->fetchFilesToOpen();
if (!files.isEmpty()) {
qDebug() << "shared memory fetch files" << files;
openExternalFiles(files);
show();
activateWindow();
QApplication::alert(this, 5000);
}
}

View File

@ -31,6 +31,8 @@ class VFindReplaceDialog;
class VCaptain; class VCaptain;
class VVimIndicator; class VVimIndicator;
class VTabIndicator; class VTabIndicator;
class VSingleInstanceGuard;
class QTimer;
class VMainWindow : public QMainWindow class VMainWindow : public QMainWindow
{ {
@ -39,7 +41,7 @@ class VMainWindow : public QMainWindow
public: public:
friend class VCaptain; friend class VCaptain;
VMainWindow(QWidget *parent = 0); VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent = 0);
const QVector<QPair<QString, QString> > &getPalette() const; const QVector<QPair<QString, QString> > &getPalette() const;
void locateFile(VFile *p_file); void locateFile(VFile *p_file);
void locateCurrentFile(); void locateCurrentFile();
@ -49,6 +51,9 @@ public:
// View and edit the information of @p_file, which is an orphan file. // View and edit the information of @p_file, which is an orphan file.
void editOrphanFileInfo(VFile *p_file); void editOrphanFileInfo(VFile *p_file);
// Open external files @p_files as orphan files.
void openExternalFiles(const QStringList &p_files);
private slots: private slots:
void importNoteFromFile(); void importNoteFromFile();
void viewSettings(); void viewSettings();
@ -100,6 +105,10 @@ private slots:
// Handle the status update of the current tab of VEditArea. // Handle the status update of the current tab of VEditArea.
void handleAreaTabStatusUpdated(const VEditTabInfo &p_info); void handleAreaTabStatusUpdated(const VEditTabInfo &p_info);
// Check the shared memory between different instances to see if we have
// files to open.
void checkSharedMemory();
protected: protected:
void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE; void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;
void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE; void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
@ -154,8 +163,9 @@ private:
const QString &p_text, const QString &p_text,
QObject *p_parent = nullptr); QObject *p_parent = nullptr);
// Open external files @p_files as orphan files. // Init a timer to watch the change of the shared memory between instances of
void openExternalFiles(const QStringList &p_files); // VNote.
void initSharedMemoryWatcher();
VNote *vnote; VNote *vnote;
QPointer<VFile> m_curFile; QPointer<VFile> m_curFile;
@ -216,6 +226,15 @@ private:
QToolBar *m_editToolBar; QToolBar *m_editToolBar;
QVector<QPixmap> predefinedColorPixmaps; QVector<QPixmap> predefinedColorPixmaps;
// Single instance guard.
VSingleInstanceGuard *m_guard;
// Timer to check the shared memory between instances of VNote.
QTimer *m_sharedMemTimer;
// Interval of the shared memory timer in ms.
static const int c_sharedMemTimerInterval;
}; };
inline VFileList *VMainWindow::getFileList() const inline VFileList *VMainWindow::getFileList() const

View File

@ -530,6 +530,7 @@ bool VMdEditOperations::handleKeyEsc(QKeyEvent *p_event)
bool VMdEditOperations::handleKeyReturn(QKeyEvent *p_event) bool VMdEditOperations::handleKeyReturn(QKeyEvent *p_event)
{ {
bool autolist = true;
if (p_event->modifiers() & Qt::ControlModifier) { if (p_event->modifiers() & Qt::ControlModifier) {
m_autoIndentPos = -1; m_autoIndentPos = -1;
return false; return false;
@ -543,7 +544,9 @@ bool VMdEditOperations::handleKeyReturn(QKeyEvent *p_event)
cursor.insertText(" "); cursor.insertText(" ");
cursor.endEditBlock(); cursor.endEditBlock();
// Let remaining logics handle inserting the new block. // Let remaining logics handle inserting the new block except that we
// do not need to insert auto list.
autolist = false;
} }
// See if we need to cancel auto indent. // See if we need to cancel auto indent.
@ -585,7 +588,7 @@ bool VMdEditOperations::handleKeyReturn(QKeyEvent *p_event)
textInserted = VEditUtils::insertBlockWithIndent(cursor); textInserted = VEditUtils::insertBlockWithIndent(cursor);
// Continue the list from previous line. // Continue the list from previous line.
if (vconfig.getAutoList()) { if (vconfig.getAutoList() && autolist) {
textInserted = VEditUtils::insertListMarkAsPreviousBlock(cursor) || textInserted; textInserted = VEditUtils::insertListMarkAsPreviousBlock(cursor) || textInserted;
} }

View File

@ -282,11 +282,12 @@ VFile *VNote::getOrphanFile(const QString &p_path, bool p_modifiable, bool p_sys
return NULL; return NULL;
} }
QString path = QDir::cleanPath(p_path);
// See if the file has already been opened before. // See if the file has already been opened before.
for (auto const &file : m_externalFiles) { for (auto const &file : m_externalFiles) {
Q_ASSERT(file->getType() == FileType::Orphan); Q_ASSERT(file->getType() == FileType::Orphan);
VOrphanFile *oFile = dynamic_cast<VOrphanFile *>(file); VOrphanFile *oFile = dynamic_cast<VOrphanFile *>(file);
if (oFile->retrivePath() == p_path) { if (VUtils::equalPath(QDir::cleanPath(oFile->retrivePath()), path)) {
Q_ASSERT(oFile->isModifiable() == p_modifiable); Q_ASSERT(oFile->isModifiable() == p_modifiable);
Q_ASSERT(oFile->isSystemFile() == p_systemFile); Q_ASSERT(oFile->isSystemFile() == p_systemFile);
return file; return file;
@ -303,8 +304,8 @@ VFile *VNote::getOrphanFile(const QString &p_path, bool p_modifiable, bool p_sys
} }
} }
// Create a VOrphanFile for p_path. // Create a VOrphanFile for path.
VOrphanFile *file = new VOrphanFile(p_path, this, p_modifiable, p_systemFile); VOrphanFile *file = new VOrphanFile(path, this, p_modifiable, p_systemFile);
m_externalFiles.append(file); m_externalFiles.append(file);
return file; return file;
} }

View File

@ -1,73 +1,132 @@
#include "vsingleinstanceguard.h" #include "vsingleinstanceguard.h"
#include <QDebug> #include <QDebug>
const QString VSingleInstanceGuard::m_memKey = "vnote_shared_memory"; #include "utils/vutils.h"
const QString VSingleInstanceGuard::m_semKey = "vnote_semaphore";
const int VSingleInstanceGuard::m_magic = 133191933; const QString VSingleInstanceGuard::c_memKey = "vnote_shared_memory";
const int VSingleInstanceGuard::c_magic = 133191933;
VSingleInstanceGuard::VSingleInstanceGuard() VSingleInstanceGuard::VSingleInstanceGuard()
: m_sharedMemory(m_memKey), m_sem(m_semKey, 1) : m_sharedMemory(c_memKey)
{ {
} }
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() bool VSingleInstanceGuard::tryRun()
{ {
// If we can attach to the sharedmemory, there is another instance running. // If we can attach to the sharedmemory, there is another instance running.
if (tryAttach()) { // In Linux, crashes may cause the shared memory segment remains. In this case,
// this will attach to the old segment, then exit, freeing the old segment.
if (m_sharedMemory.attach()) {
qDebug() << "another instance is running"; qDebug() << "another instance is running";
return false; return false;
} }
// Try to create it // Try to create it.
m_sem.acquire();
bool ret = m_sharedMemory.create(sizeof(SharedStruct)); bool ret = m_sharedMemory.create(sizeof(SharedStruct));
m_sem.release();
if (ret) { if (ret) {
// We created it // We created it.
m_sharedMemory.lock(); m_sharedMemory.lock();
SharedStruct *str = (SharedStruct *)m_sharedMemory.data(); SharedStruct *str = (SharedStruct *)m_sharedMemory.data();
str->m_magic = m_magic; str->m_magic = c_magic;
str->m_activeRequest = 0; str->m_filesBufIdx = 0;
m_sharedMemory.unlock(); m_sharedMemory.unlock();
return true; return true;
} else { } else {
// Maybe another thread create it qDebug() << "fail to create shared memory segment";
if (tryAttach()) {
qDebug() << "another instance is running";
return false; return false;
}
}
void VSingleInstanceGuard::openExternalFiles(const QStringList &p_files)
{
if (p_files.isEmpty()) {
return;
}
if (!m_sharedMemory.isAttached()) {
if (!m_sharedMemory.attach()) {
qDebug() << "fail to attach to the shared memory segment"
<< (m_sharedMemory.error() ? m_sharedMemory.errorString() : "");
return;
}
}
qDebug() << "try to request another instance to open files" << p_files;
int idx = 0;
int tryCount = 100;
while (tryCount--) {
qDebug() << "set shared memory one round" << idx << "of" << p_files.size();
m_sharedMemory.lock();
SharedStruct *str = (SharedStruct *)m_sharedMemory.data();
V_ASSERT(str->m_magic == c_magic);
for (; idx < p_files.size(); ++idx) {
if (p_files[idx].size() + 1 > FilesBufCount) {
qDebug() << "skip file since its long name" << p_files[idx];
// Skip this long long name file.
continue;
}
if (!appendFileToBuffer(str, p_files[idx])) {
break;
}
}
m_sharedMemory.unlock();
if (idx < p_files.size()) {
VUtils::sleepWait(500);
} else { } else {
// Something wrong here break;
qWarning() << "fail to create or attach shared memory segment"; }
}
}
bool VSingleInstanceGuard::appendFileToBuffer(SharedStruct *p_str, const QString &p_file)
{
if (p_file.isEmpty()) {
return true;
}
int strSize = p_file.size();
if (strSize + 1 > FilesBufCount - p_str->m_filesBufIdx) {
qDebug() << "no enough space for" << p_file;
return false; return false;
} }
// Put the size first.
p_str->m_filesBuf[p_str->m_filesBufIdx++] = (ushort)strSize;
const QChar *data = p_file.constData();
for (int i = 0; i < strSize; ++i) {
p_str->m_filesBuf[p_str->m_filesBufIdx++] = data[i].unicode();
} }
qDebug() << "after appended one file" << p_str->m_filesBufIdx << p_file;
return true;
}
QStringList VSingleInstanceGuard::fetchFilesToOpen()
{
QStringList files;
Q_ASSERT(m_sharedMemory.isAttached());
m_sharedMemory.lock();
SharedStruct *str = (SharedStruct *)m_sharedMemory.data();
Q_ASSERT(str->m_magic == c_magic);
Q_ASSERT(str->m_filesBufIdx <= FilesBufCount);
int idx = 0;
while (idx < str->m_filesBufIdx) {
int strSize = str->m_filesBuf[idx++];
Q_ASSERT(strSize <= str->m_filesBufIdx - idx);
QString file;
for (int i = 0; i < strSize; ++i) {
file.append(QChar(str->m_filesBuf[idx++]));
}
files.append(file);
}
str->m_filesBufIdx = 0;
m_sharedMemory.unlock();
return files;
} }

View File

@ -3,31 +3,51 @@
#include <QString> #include <QString>
#include <QSharedMemory> #include <QSharedMemory>
#include <QSystemSemaphore> #include <QStringList>
class VSingleInstanceGuard class VSingleInstanceGuard
{ {
public: public:
VSingleInstanceGuard(); VSingleInstanceGuard();
~VSingleInstanceGuard();
// Return ture if this is the only instance of VNote.
bool tryRun(); bool tryRun();
// There is already another instance running.
// Call this to ask that instance to open external files passed in
// via command line arguments.
void openExternalFiles(const QStringList &p_files);
// Fetch files from shared memory to open.
// Will clear the shared memory.
QStringList fetchFilesToOpen();
private: private:
void detachMemory(); // The count of the entries in the buffer to hold the path of the files to open.
bool tryAttach(); enum { FilesBufCount = 1024 };
struct SharedStruct { struct SharedStruct {
// A magic number to identify if this struct is initialized // A magic number to identify if this struct is initialized
int m_magic; int m_magic;
// If it is 1, then another instance ask this instance to show itself
int m_activeRequest; // Next empty entry in m_filesBuf.
int m_filesBufIdx;
// File paths to be opened.
// Encoded in this way with 2 bytes for each size part.
// [size of file1][file1][size of file2][file 2]
// Unicode representation of QString.
ushort m_filesBuf[FilesBufCount];
}; };
static const QString m_memKey; // Append @p_file to the shared struct files buffer.
static const QString m_semKey; // Returns true if succeeds or false if there is no enough space.
static const int m_magic; bool appendFileToBuffer(SharedStruct *p_str, const QString &p_file);
QSharedMemory m_sharedMemory; QSharedMemory m_sharedMemory;
QSystemSemaphore m_sem;
static const QString c_memKey;
static const int c_magic;
}; };
#endif // VSINGLEINSTANCEGUARD_H #endif // VSINGLEINSTANCEGUARD_H