mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
support opening external files from context menu in system browser
This commit is contained in:
parent
e33ff1fede
commit
0b9d259de6
46
src/main.cpp
46
src/main.cpp
@ -6,6 +6,8 @@
|
||||
#include <QFile>
|
||||
#include <QTextCodec>
|
||||
#include <QFileInfo>
|
||||
#include <QStringList>
|
||||
#include <QDir>
|
||||
#include "utils/vutils.h"
|
||||
#include "vsingleinstanceguard.h"
|
||||
#include "vconfigmanager.h"
|
||||
@ -91,16 +93,18 @@ void VLogger(QtMsgType type, const QMessageLogContext &context, const QString &m
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
VSingleInstanceGuard guard;
|
||||
bool canRun = guard.tryRun();
|
||||
|
||||
#if defined(QT_NO_DEBUG)
|
||||
if (canRun) {
|
||||
g_logFile.setFileName(VConfigManager::getLogFilePath());
|
||||
g_logFile.open(QIODevice::WriteOnly);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (canRun) {
|
||||
qInstallMessageHandler(VLogger);
|
||||
|
||||
VSingleInstanceGuard guard;
|
||||
if (!guard.tryRun()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
QTextCodec *codec = QTextCodec::codecForName("UTF8");
|
||||
@ -109,6 +113,35 @@ int main(int argc, char *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();
|
||||
|
||||
QString locale = VUtils::getLocale();
|
||||
@ -119,6 +152,7 @@ int main(int argc, char *argv[])
|
||||
if (!qtTranslator.load("qt_" + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
|
||||
qtTranslator.load("qt_" + locale, "translations");
|
||||
}
|
||||
|
||||
app.installTranslator(&qtTranslator);
|
||||
|
||||
// load translation for vnote
|
||||
@ -128,7 +162,7 @@ int main(int argc, char *argv[])
|
||||
app.installTranslator(&translator);
|
||||
}
|
||||
|
||||
VMainWindow w;
|
||||
VMainWindow w(&guard);
|
||||
QString style = VUtils::readFileFromDisk(":/resources/vnote.qss");
|
||||
if (!style.isEmpty()) {
|
||||
VUtils::processStyle(style, w.getPalette());
|
||||
@ -137,5 +171,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
w.show();
|
||||
|
||||
w.openExternalFiles(filePaths);
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
- `Ctrl+E E`
|
||||
Toggle expanding the edit area.
|
||||
- `Ctrl+Alt+N`
|
||||
Create a note in current directory.
|
||||
Create a note in current folder.
|
||||
- `Ctrl+F`
|
||||
Find/Replace in current note.
|
||||
- `Ctrl+Q`
|
||||
@ -135,7 +135,7 @@ Number key 1 to 9 will jump to the tabs with corresponding sequence number.
|
||||
- `0`
|
||||
Jump to previous tab. Alternate between current and previous tab.
|
||||
- `D`
|
||||
Locate to the directory of current note.
|
||||
Locate to the folder of current note.
|
||||
- `Q`
|
||||
Discard current changes and exit edit mode.
|
||||
- `V`
|
||||
|
@ -136,7 +136,7 @@ size=8
|
||||
- `0`
|
||||
跳转到前一个标签页(即前一个当前标签页)。实现当前标签页和前一个标签页之间的轮换。
|
||||
- `D`
|
||||
定位当前笔记所在目录。
|
||||
定位当前笔记所在文件夹。
|
||||
- `Q`
|
||||
放弃当前更改并退出编辑模式。
|
||||
- `V`
|
||||
|
@ -34,7 +34,7 @@ background: 005fff
|
||||
editor-current-line
|
||||
background: c5cae9
|
||||
# [VNote] Vim insert mode cursor line background
|
||||
vim-insert-background: cdc0b0
|
||||
vim-insert-background: bcbcbc
|
||||
# [VNote] Vim normal mode cursor line background
|
||||
vim-normal-background: b0bec5
|
||||
# [VNote] Vim visual mode cursor line background
|
||||
|
@ -131,6 +131,20 @@ void VEditWindow::initTabActions()
|
||||
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()
|
||||
@ -527,10 +541,17 @@ void VEditWindow::tabbarContextMenuRequested(QPoint p_pos)
|
||||
// Locate to folder.
|
||||
m_locateAct->setData(tab);
|
||||
menu.addAction(m_locateAct);
|
||||
|
||||
m_openLocationAct->setData(tab);
|
||||
menu.addAction(m_openLocationAct);
|
||||
|
||||
m_noteInfoAct->setData(tab);
|
||||
menu.addAction(m_noteInfoAct);
|
||||
} else if (file->getType() == FileType::Orphan
|
||||
&& !dynamic_cast<VOrphanFile *>(file)->isSystemFile()) {
|
||||
m_openLocationAct->setData(tab);
|
||||
menu.addAction(m_openLocationAct);
|
||||
|
||||
m_noteInfoAct->setData(tab);
|
||||
menu.addAction(m_noteInfoAct);
|
||||
}
|
||||
|
@ -168,6 +168,9 @@ private:
|
||||
|
||||
// View and edit info about this note.
|
||||
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
|
||||
|
@ -25,17 +25,20 @@
|
||||
#include "dialog/vupdater.h"
|
||||
#include "vorphanfile.h"
|
||||
#include "dialog/vorphanfileinfodialog.h"
|
||||
#include "vsingleinstanceguard.h"
|
||||
|
||||
extern VConfigManager vconfig;
|
||||
|
||||
VNote *g_vnote;
|
||||
|
||||
const int VMainWindow::c_sharedMemTimerInterval = 1000;
|
||||
|
||||
#if defined(QT_NO_DEBUG)
|
||||
extern QFile g_logFile;
|
||||
#endif
|
||||
|
||||
VMainWindow::VMainWindow(QWidget *parent)
|
||||
: QMainWindow(parent), m_onePanel(false)
|
||||
VMainWindow::VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent)
|
||||
: QMainWindow(p_parent), m_onePanel(false), m_guard(p_guard)
|
||||
{
|
||||
setWindowIcon(QIcon(":/resources/icons/vnote.ico"));
|
||||
vnote = new VNote(this);
|
||||
@ -56,6 +59,19 @@ VMainWindow::VMainWindow(QWidget *parent)
|
||||
notebookSelector->update();
|
||||
|
||||
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()
|
||||
@ -1349,6 +1365,10 @@ void VMainWindow::setEditorStyle(QAction *p_action)
|
||||
void VMainWindow::updateActionStateFromTabStatusChange(const VFile *p_file,
|
||||
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_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);
|
||||
saveExitAct->setVisible(p_file && p_editMode);
|
||||
saveNoteAct->setVisible(p_file && p_editMode);
|
||||
deleteNoteAct->setVisible(p_file && p_file->isModifiable());
|
||||
noteInfoAct->setVisible(p_file && p_file->getType() == FileType::Normal);
|
||||
deleteNoteAct->setVisible(p_file && p_file->getType() == FileType::Normal);
|
||||
noteInfoAct->setVisible(p_file && !systemFile);
|
||||
m_closeNoteAct->setVisible(p_file);
|
||||
|
||||
m_insertImageAct->setEnabled(p_file && p_editMode);
|
||||
@ -1483,17 +1503,25 @@ void VMainWindow::updateWindowTitle(const QString &str)
|
||||
|
||||
void VMainWindow::curEditFileInfo()
|
||||
{
|
||||
if (!m_curFile || m_curFile->getType() != FileType::Normal) {
|
||||
return;
|
||||
}
|
||||
Q_ASSERT(m_curFile);
|
||||
|
||||
if (m_curFile->getType() == FileType::Normal) {
|
||||
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()
|
||||
{
|
||||
if (!m_curFile || !m_curFile->isModifiable()) {
|
||||
if (!m_curFile || m_curFile->getType() != FileType::Normal) {
|
||||
return;
|
||||
}
|
||||
|
||||
fileList->deleteFile(m_curFile);
|
||||
}
|
||||
|
||||
@ -1828,3 +1856,16 @@ void VMainWindow::editOrphanFileInfo(VFile *p_file)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,8 @@ class VFindReplaceDialog;
|
||||
class VCaptain;
|
||||
class VVimIndicator;
|
||||
class VTabIndicator;
|
||||
class VSingleInstanceGuard;
|
||||
class QTimer;
|
||||
|
||||
class VMainWindow : public QMainWindow
|
||||
{
|
||||
@ -39,7 +41,7 @@ class VMainWindow : public QMainWindow
|
||||
public:
|
||||
friend class VCaptain;
|
||||
|
||||
VMainWindow(QWidget *parent = 0);
|
||||
VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent = 0);
|
||||
const QVector<QPair<QString, QString> > &getPalette() const;
|
||||
void locateFile(VFile *p_file);
|
||||
void locateCurrentFile();
|
||||
@ -49,6 +51,9 @@ public:
|
||||
// View and edit the information of @p_file, which is an orphan file.
|
||||
void editOrphanFileInfo(VFile *p_file);
|
||||
|
||||
// Open external files @p_files as orphan files.
|
||||
void openExternalFiles(const QStringList &p_files);
|
||||
|
||||
private slots:
|
||||
void importNoteFromFile();
|
||||
void viewSettings();
|
||||
@ -100,6 +105,10 @@ private slots:
|
||||
// Handle the status update of the current tab of VEditArea.
|
||||
void handleAreaTabStatusUpdated(const VEditTabInfo &p_info);
|
||||
|
||||
// Check the shared memory between different instances to see if we have
|
||||
// files to open.
|
||||
void checkSharedMemory();
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;
|
||||
void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
|
||||
@ -154,8 +163,9 @@ private:
|
||||
const QString &p_text,
|
||||
QObject *p_parent = nullptr);
|
||||
|
||||
// Open external files @p_files as orphan files.
|
||||
void openExternalFiles(const QStringList &p_files);
|
||||
// Init a timer to watch the change of the shared memory between instances of
|
||||
// VNote.
|
||||
void initSharedMemoryWatcher();
|
||||
|
||||
VNote *vnote;
|
||||
QPointer<VFile> m_curFile;
|
||||
@ -216,6 +226,15 @@ private:
|
||||
QToolBar *m_editToolBar;
|
||||
|
||||
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
|
||||
|
@ -530,6 +530,7 @@ bool VMdEditOperations::handleKeyEsc(QKeyEvent *p_event)
|
||||
|
||||
bool VMdEditOperations::handleKeyReturn(QKeyEvent *p_event)
|
||||
{
|
||||
bool autolist = true;
|
||||
if (p_event->modifiers() & Qt::ControlModifier) {
|
||||
m_autoIndentPos = -1;
|
||||
return false;
|
||||
@ -543,7 +544,9 @@ bool VMdEditOperations::handleKeyReturn(QKeyEvent *p_event)
|
||||
cursor.insertText(" ");
|
||||
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.
|
||||
@ -585,7 +588,7 @@ bool VMdEditOperations::handleKeyReturn(QKeyEvent *p_event)
|
||||
textInserted = VEditUtils::insertBlockWithIndent(cursor);
|
||||
|
||||
// Continue the list from previous line.
|
||||
if (vconfig.getAutoList()) {
|
||||
if (vconfig.getAutoList() && autolist) {
|
||||
textInserted = VEditUtils::insertListMarkAsPreviousBlock(cursor) || textInserted;
|
||||
}
|
||||
|
||||
|
@ -282,11 +282,12 @@ VFile *VNote::getOrphanFile(const QString &p_path, bool p_modifiable, bool p_sys
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QString path = QDir::cleanPath(p_path);
|
||||
// See if the file has already been opened before.
|
||||
for (auto const &file : m_externalFiles) {
|
||||
Q_ASSERT(file->getType() == FileType::Orphan);
|
||||
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->isSystemFile() == p_systemFile);
|
||||
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.
|
||||
VOrphanFile *file = new VOrphanFile(p_path, this, p_modifiable, p_systemFile);
|
||||
// Create a VOrphanFile for path.
|
||||
VOrphanFile *file = new VOrphanFile(path, this, p_modifiable, p_systemFile);
|
||||
m_externalFiles.append(file);
|
||||
return file;
|
||||
}
|
||||
|
@ -1,73 +1,132 @@
|
||||
#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;
|
||||
#include "utils/vutils.h"
|
||||
|
||||
const QString VSingleInstanceGuard::c_memKey = "vnote_shared_memory";
|
||||
const int VSingleInstanceGuard::c_magic = 133191933;
|
||||
|
||||
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()
|
||||
{
|
||||
// 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";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to create it
|
||||
m_sem.acquire();
|
||||
// Try to create it.
|
||||
bool ret = m_sharedMemory.create(sizeof(SharedStruct));
|
||||
m_sem.release();
|
||||
if (ret) {
|
||||
// We created it
|
||||
// We created it.
|
||||
m_sharedMemory.lock();
|
||||
SharedStruct *str = (SharedStruct *)m_sharedMemory.data();
|
||||
str->m_magic = m_magic;
|
||||
str->m_activeRequest = 0;
|
||||
str->m_magic = c_magic;
|
||||
str->m_filesBufIdx = 0;
|
||||
m_sharedMemory.unlock();
|
||||
return true;
|
||||
} else {
|
||||
// Maybe another thread create it
|
||||
if (tryAttach()) {
|
||||
qDebug() << "another instance is running";
|
||||
qDebug() << "fail to create shared memory segment";
|
||||
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 {
|
||||
// Something wrong here
|
||||
qWarning() << "fail to create or attach shared memory segment";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
@ -3,31 +3,51 @@
|
||||
|
||||
#include <QString>
|
||||
#include <QSharedMemory>
|
||||
#include <QSystemSemaphore>
|
||||
#include <QStringList>
|
||||
|
||||
class VSingleInstanceGuard
|
||||
{
|
||||
public:
|
||||
VSingleInstanceGuard();
|
||||
~VSingleInstanceGuard();
|
||||
|
||||
// Return ture if this is the only instance of VNote.
|
||||
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:
|
||||
void detachMemory();
|
||||
bool tryAttach();
|
||||
// The count of the entries in the buffer to hold the path of the files to open.
|
||||
enum { FilesBufCount = 1024 };
|
||||
|
||||
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;
|
||||
|
||||
// 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;
|
||||
static const QString m_semKey;
|
||||
static const int m_magic;
|
||||
// Append @p_file to the shared struct files buffer.
|
||||
// Returns true if succeeds or false if there is no enough space.
|
||||
bool appendFileToBuffer(SharedStruct *p_str, const QString &p_file);
|
||||
|
||||
QSharedMemory m_sharedMemory;
|
||||
QSystemSemaphore m_sem;
|
||||
|
||||
static const QString c_memKey;
|
||||
static const int c_magic;
|
||||
};
|
||||
|
||||
#endif // VSINGLEINSTANCEGUARD_H
|
||||
|
Loading…
x
Reference in New Issue
Block a user