Implemented single-instance support (Part #2).

This commit is contained in:
LoRd_MuldeR 2014-01-16 02:09:48 +01:00
parent b7c758e9fe
commit dd86f202f9
9 changed files with 387 additions and 106 deletions

View File

@ -130,6 +130,7 @@
<ClCompile Include="src\MainWindow.cpp" /> <ClCompile Include="src\MainWindow.cpp" />
<ClCompile Include="src\ShellExtension.cpp" /> <ClCompile Include="src\ShellExtension.cpp" />
<ClCompile Include="src\Utils.cpp" /> <ClCompile Include="src\Utils.cpp" />
<ClCompile Include="tmp\Common\moc\MOC_IPC.cpp" />
<ClCompile Include="tmp\Common\moc\MOC_MainWindow.cpp" /> <ClCompile Include="tmp\Common\moc\MOC_MainWindow.cpp" />
<ClCompile Include="tmp\Common\rcc\RCC_MediaInfoXP.cpp" /> <ClCompile Include="tmp\Common\rcc\RCC_MediaInfoXP.cpp" />
</ItemGroup> </ItemGroup>
@ -145,7 +146,14 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="src\Config.h" /> <ClInclude Include="src\Config.h" />
<ClInclude Include="src\IPC.h" /> <CustomBuild Include="src\IPC.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">MOC "$(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp"</Message>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MOC "$(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp"</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp;%(Outputs)</Outputs>
</CustomBuild>
<ClInclude Include="src\ShellExtension.h" /> <ClInclude Include="src\ShellExtension.h" />
<ClInclude Include="src\Utils.h" /> <ClInclude Include="src\Utils.h" />
</ItemGroup> </ItemGroup>

View File

@ -31,6 +31,9 @@
<CustomBuild Include="src\MainWindow.h"> <CustomBuild Include="src\MainWindow.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</CustomBuild> </CustomBuild>
<CustomBuild Include="src\IPC.h">
<Filter>Header Files</Filter>
</CustomBuild>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\Main.cpp"> <ClCompile Include="src\Main.cpp">
@ -54,6 +57,9 @@
<ClCompile Include="src\IPC.cpp"> <ClCompile Include="src\IPC.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="tmp\Common\moc\MOC_IPC.cpp">
<Filter>Source Files\Generated</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="src\Config.h"> <ClInclude Include="src\Config.h">
@ -65,9 +71,6 @@
<ClInclude Include="src\ShellExtension.h"> <ClInclude Include="src\ShellExtension.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\IPC.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="MediaInfoXP.rcx" /> <ResourceCompile Include="MediaInfoXP.rcx" />

View File

@ -25,7 +25,6 @@
#include <QSharedMemory> #include <QSharedMemory>
#include <QSystemSemaphore> #include <QSystemSemaphore>
#include <QThread>
static const size_t MAX_STR_LEN = 1024; static const size_t MAX_STR_LEN = 1024;
static const size_t MAX_ENTRIES = 16; static const size_t MAX_ENTRIES = 16;
@ -39,57 +38,101 @@ typedef struct
wchar_t data[MAX_ENTRIES][MAX_STR_LEN]; wchar_t data[MAX_ENTRIES][MAX_STR_LEN];
size_t posRd; size_t posRd;
size_t posWr; size_t posWr;
size_t counter;
} }
mixp_ipc_t; mixp_ipc_t;
///////////////////////////////////////////////////////////////////////////////
// Send Thread
///////////////////////////////////////////////////////////////////////////////
IPCSendThread::IPCSendThread(IPC *ipc, const QString &str)
:
m_ipc(ipc), m_str(str)
{
m_result = false;
}
void IPCSendThread::run(void)
{
try
{
m_result = m_ipc->pushStr(m_str);
}
catch(...)
{
m_result = false;
}
}
///////////////////////////////////////////////////////////////////////////////
// Receive Thread
///////////////////////////////////////////////////////////////////////////////
IPCReceiveThread::IPCReceiveThread(IPC *ipc)
:
m_ipc(ipc)
{
m_stopped = false;
}
void IPCReceiveThread::run(void)
{
try
{
receiveLoop();
}
catch(...)
{
qWarning("Exception in IPC receive thread!");
}
}
void IPCReceiveThread::receiveLoop(void)
{
while(!m_stopped)
{
QString temp;
if(m_ipc->popStr(temp))
{
if(!temp.isEmpty())
{
emit receivedStr(temp);
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
// IPC Class
///////////////////////////////////////////////////////////////////////////////
IPC::IPC(void) IPC::IPC(void)
{ {
m_initialized = -1; m_initialized = -1;
m_sharedMemory = NULL; m_sharedMemory = NULL;
m_semaphoreWr = NULL; m_semaphoreWr = NULL;
m_semaphoreRd = NULL; m_semaphoreRd = NULL;
m_recvThread = NULL;
} }
IPC::~IPC(void) IPC::~IPC(void)
{ {
if(m_recvThread && m_recvThread->isRunning())
{
qWarning("Receive thread still running -> terminating!");
m_recvThread->terminate();
m_recvThread->wait();
}
MIXP_DELETE_OBJ(m_recvThread);
MIXP_DELETE_OBJ(m_sharedMemory); MIXP_DELETE_OBJ(m_sharedMemory);
MIXP_DELETE_OBJ(m_semaphoreWr); MIXP_DELETE_OBJ(m_semaphoreWr);
MIXP_DELETE_OBJ(m_semaphoreRd); MIXP_DELETE_OBJ(m_semaphoreRd);
} }
/////////////////////////////////////////////////////////////////////////////// int IPC::initialize(void)
class SendThread : public QThread
{
public:
SendThread(IPC *ipc, const QString &str) : m_ipc(ipc), m_str(str)
{
m_result = false;
}
virtual void run(void)
{
try
{
m_result = m_ipc->pushStr(m_str);
}
catch(...)
{
m_result = false;
}
}
inline bool result(void) { return m_result; }
protected:
volatile bool m_result;
IPC *const m_ipc;
const QString m_str;
};
///////////////////////////////////////////////////////////////////////////////
int IPC::init(void)
{ {
if(m_initialized >= 0) if(m_initialized >= 0)
{ {
@ -148,11 +191,22 @@ bool IPC::pushStr(const QString &str)
return false; return false;
} }
bool success = true;
try try
{ {
mixp_ipc_t *memory = (mixp_ipc_t*) m_sharedMemory->data(); mixp_ipc_t *memory = (mixp_ipc_t*) m_sharedMemory->data();
wcsncpy_s(memory->data[memory->posWr], MAX_STR_LEN, (wchar_t*)str.utf16(), _TRUNCATE); if(memory->counter < MAX_ENTRIES)
memory->posWr = (memory->posWr + 1) % MAX_ENTRIES; {
wcsncpy_s(memory->data[memory->posWr], MAX_STR_LEN, (wchar_t*)str.utf16(), _TRUNCATE);
memory->posWr = (memory->posWr + 1) % MAX_ENTRIES;
memory->counter++;
}
else
{
qWarning("IPC: Shared memory is full -> cannot push string!");
success = false;
}
} }
catch(...) catch(...)
{ {
@ -160,9 +214,13 @@ bool IPC::pushStr(const QString &str)
} }
m_sharedMemory->unlock(); m_sharedMemory->unlock();
m_semaphoreRd->release();
return true; if(success)
{
m_semaphoreRd->release();
}
return success;
} }
bool IPC::popStr(QString &str) bool IPC::popStr(QString &str)
@ -185,11 +243,23 @@ bool IPC::popStr(QString &str)
return false; return false;
} }
bool success = true;
try try
{ {
mixp_ipc_t *memory = (mixp_ipc_t*) m_sharedMemory->data(); mixp_ipc_t *memory = (mixp_ipc_t*) m_sharedMemory->data();
str = QString::fromUtf16((const ushort*)memory->data[memory->posRd]); if(memory->counter > 0)
memory->posRd = (memory->posRd + 1) % MAX_ENTRIES; {
memory->data[memory->posRd][MAX_STR_LEN-1] = L'\0';
str = QString::fromUtf16((const ushort*)memory->data[memory->posRd]);
memory->posRd = (memory->posRd + 1) % MAX_ENTRIES;
memory->counter--;
}
else
{
qWarning("IPC: Shared memory is empty -> cannot pop string!");
success = false;
}
} }
catch(...) catch(...)
{ {
@ -197,14 +267,18 @@ bool IPC::popStr(QString &str)
} }
m_sharedMemory->unlock(); m_sharedMemory->unlock();
m_semaphoreWr->release();
return true; if(success)
{
m_semaphoreWr->release();
}
return success;
} }
bool IPC::sendAsync(const QString &str, const int timeout) bool IPC::sendAsync(const QString &str, const int timeout)
{ {
SendThread sendThread(this, str); IPCSendThread sendThread(this, str);
sendThread.start(); sendThread.start();
if(!sendThread.wait(timeout)) if(!sendThread.wait(timeout))
@ -217,3 +291,42 @@ bool IPC::sendAsync(const QString &str, const int timeout)
return sendThread.result(); return sendThread.result();
} }
void IPC::startListening(void)
{
if(!m_recvThread)
{
m_recvThread = new IPCReceiveThread(this);
connect(m_recvThread, SIGNAL(receivedStr(QString)), this, SIGNAL(receivedStr(QString)), Qt::QueuedConnection);
}
if(!m_recvThread->isRunning())
{
m_recvThread->start();
}
else
{
qWarning("Receive thread was already running!");
}
}
void IPC::stopListening(void)
{
if(m_recvThread && m_recvThread->isRunning())
{
m_recvThread->stop();
m_semaphoreRd->release();
if(!m_recvThread->wait(5000))
{
qWarning("Receive thread seems deadlocked -> terminating!");
m_recvThread->terminate();
m_recvThread->wait();
}
}
else
{
qWarning("Receive thread was not running!");
}
}

View File

@ -21,30 +21,80 @@
#pragma once #pragma once
#include <QObject> #include <QThread>
class QSharedMemory; class QSharedMemory;
class QSystemSemaphore; class QSystemSemaphore;
class IPCSendThread;
class IPCReceiveThread;
class IPC : public QObject class IPC : public QObject
{ {
Q_OBJECT
friend class IPCReceiveThread;
friend class IPCSendThread;
public: public:
IPC(void); IPC(void);
~IPC(void); ~IPC(void);
int init(void); int initialize(void);
//async support
bool sendAsync(const QString &str, const int timeout = 5000); bool sendAsync(const QString &str, const int timeout = 5000);
//blocking operations public slots:
bool pushStr(const QString &str); void startListening(void);
bool popStr(QString &str); void stopListening(void);
signals:
void receivedStr(const QString &str);
protected: protected:
bool popStr(QString &str);
bool pushStr(const QString &str);
int m_initialized; int m_initialized;
QSharedMemory *m_sharedMemory; QSharedMemory *m_sharedMemory;
QSystemSemaphore *m_semaphoreRd; QSystemSemaphore *m_semaphoreRd;
QSystemSemaphore *m_semaphoreWr; QSystemSemaphore *m_semaphoreWr;
IPCReceiveThread *m_recvThread;
};
///////////////////////////////////////////////////////////////////////////////
class IPCSendThread : public QThread
{
Q_OBJECT
friend class IPC;
protected:
IPCSendThread(IPC *ipc, const QString &str);
inline bool result(void) { return m_result; }
virtual void run(void);
private:
volatile bool m_result;
IPC *const m_ipc;
const QString m_str;
};
class IPCReceiveThread : public QThread
{
Q_OBJECT
friend class IPC;
protected:
IPCReceiveThread(IPC *ipc);
inline void stop(void) { m_stopped = true; }
virtual void run(void);
signals:
void receivedStr(const QString &str);
private:
void receiveLoop(void);
volatile bool m_stopped;
IPC *const m_ipc;
}; };

View File

@ -102,24 +102,45 @@ int mixp_main(int argc, char* argv[])
qDebug("Copyright (c) 2004-%s LoRd_MuldeR <mulder2@gmx.de>. Some rights reserved.", &mixp_buildDate[7]); qDebug("Copyright (c) 2004-%s LoRd_MuldeR <mulder2@gmx.de>. Some rights reserved.", &mixp_buildDate[7]);
qDebug("Built with Qt v%s, running with Qt v%s.\n", QT_VERSION_STR, qVersion()); qDebug("Built with Qt v%s, running with Qt v%s.\n", QT_VERSION_STR, qVersion());
//Initialize IPC //Create application
QApplication *application = new QApplication(argc, argv);
//Create IPC
IPC *ipc = new IPC(); IPC *ipc = new IPC();
if(ipc->init() == 0)
{
ipc->sendAsync("Test Hello World 123!");
return 0;
}
QString test; //Is this the *first* instance?
qDebug("Awaiting data from other instance..."); if(ipc->initialize() == 0)
if(ipc->popStr(test))
{ {
qDebug("Got the data: %s\n", test.toUtf8().constData()); //We are *not* the first instance -> pass all file names to the running instance
const QStringList arguments = qApp->arguments();
bool bHaveFile = false;
for(QStringList::ConstIterator iter = arguments.constBegin(); iter != arguments.constEnd(); iter++)
{
if(QString::compare(*iter, "--open", Qt::CaseInsensitive) == 0)
{
if(++iter != arguments.constEnd())
{
if(ipc->sendAsync(*iter))
{
bHaveFile = true;
continue;
}
}
break;
}
}
//If no file was sent, we will at least try to bring the other instance to front
if(!bHaveFile)
{
ipc->sendAsync("?");
}
MIXP_DELETE_OBJ(ipc);
MIXP_DELETE_OBJ(application);
return 42;
} }
QFile *lockFile = NULL;
//Get temp folder //Get temp folder
QFile *lockFile = NULL;
const QString tempFolder = mixp_getTempFolder(&lockFile); const QString tempFolder = mixp_getTempFolder(&lockFile);
if(tempFolder.isEmpty()) if(tempFolder.isEmpty())
{ {
@ -130,18 +151,17 @@ int mixp_main(int argc, char* argv[])
qDebug("TEMP folder is:\n%s\n", QDir::toNativeSeparators(tempFolder).toUtf8().constData()); qDebug("TEMP folder is:\n%s\n", QDir::toNativeSeparators(tempFolder).toUtf8().constData());
//Create application
QApplication *application = new QApplication(argc, argv);
application->setWindowIcon(QIcon(":/QtTestApp.ico"));
//Create main window //Create main window
CMainWindow *mainWindow = new CMainWindow(tempFolder); CMainWindow *mainWindow = new CMainWindow(tempFolder, ipc);
mainWindow->show(); mainWindow->show();
//Run application //Run application
const int exit_code = application->exec(); const int exit_code = application->exec();
qDebug("\nTime to say goodbye... (%d)\n", exit_code); qDebug("\nTime to say goodbye... (%d)\n", exit_code);
//Stop IPC
ipc->stopListening();
//Clean up //Clean up
MIXP_DELETE_OBJ(mainWindow); MIXP_DELETE_OBJ(mainWindow);
MIXP_DELETE_OBJ(application); MIXP_DELETE_OBJ(application);

View File

@ -39,18 +39,16 @@
//CRT //CRT
#include <ctime> #include <ctime>
//Win32
//#define WIN32_LEAN_AND_MEAN
//#include <Windows.h>
//Internal //Internal
#include "Config.h" #include "Config.h"
#include "Utils.h" #include "Utils.h"
#include "ShellExtension.h" #include "ShellExtension.h"
#include "IPC.h"
//Macros //Macros
#define SET_FONT_BOLD(WIDGET,BOLD) { QFont _font = WIDGET->font(); _font.setBold(BOLD); WIDGET->setFont(_font); } #define SET_FONT_BOLD(WIDGET,BOLD) { QFont _font = WIDGET->font(); _font.setBold(BOLD); WIDGET->setFont(_font); }
#define SET_TEXT_COLOR(WIDGET,COLOR) { QPalette _palette = WIDGET->palette(); _palette.setColor(QPalette::WindowText, (COLOR)); _palette.setColor(QPalette::Text, (COLOR)); WIDGET->setPalette(_palette); } #define SET_TEXT_COLOR(WIDGET,COLOR) { QPalette _palette = WIDGET->palette(); _palette.setColor(QPalette::WindowText, (COLOR)); _palette.setColor(QPalette::Text, (COLOR)); WIDGET->setPalette(_palette); }
#define APPLICATION_IS_IDLE (m_status == APP_STATUS_IDLE)
//Text //Text
const char *STATUS_BLNK = ">> You can drop any type of media files here <<"; const char *STATUS_BLNK = ">> You can drop any type of media files here <<";
@ -71,16 +69,20 @@ static QList<QPair<const QString, const QString>> HTML_ESCAPE(void)
return htmlEscape; return htmlEscape;
} }
//Const
static const int FILE_RECEIVE_DELAY = 1750;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Constructor // Constructor
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
CMainWindow::CMainWindow(const QString &tempFolder, QWidget *parent) CMainWindow::CMainWindow(const QString &tempFolder, IPC *const ipc, QWidget *parent)
: :
QMainWindow(parent), QMainWindow(parent),
m_tempFolder(tempFolder), m_tempFolder(tempFolder),
m_firstShow(true), m_ipc(ipc),
m_htmlEscape(HTML_ESCAPE()), m_htmlEscape(HTML_ESCAPE()),
m_status(APP_STATUS_STARTING),
ui(new Ui::MainWindow) ui(new Ui::MainWindow)
{ {
//Init UI //Init UI
@ -107,6 +109,7 @@ CMainWindow::CMainWindow(const QString &tempFolder, QWidget *parent)
connect(ui->actionLink_Discuss, SIGNAL(triggered()), this, SLOT(linkTriggered())); connect(ui->actionLink_Discuss, SIGNAL(triggered()), this, SLOT(linkTriggered()));
connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(showAboutScreen())); connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(showAboutScreen()));
connect(ui->actionShellExtension, SIGNAL(toggled(bool)), this, SLOT(updateShellExtension(bool))); connect(ui->actionShellExtension, SIGNAL(toggled(bool)), this, SLOT(updateShellExtension(bool)));
connect(m_ipc, SIGNAL(receivedStr(QString)), this, SLOT(fileReceived(QString)));
ui->versionLabel->installEventFilter(this); ui->versionLabel->installEventFilter(this);
//Context menu //Context menu
@ -168,10 +171,7 @@ void CMainWindow::showEvent(QShowEvent *event)
resizeEvent(NULL); resizeEvent(NULL);
QTimer::singleShot(0, this, SLOT(updateSize())); QTimer::singleShot(0, this, SLOT(updateSize()));
//Enable drag & drop support if(m_status == APP_STATUS_STARTING)
setAcceptDrops(true);
if(m_firstShow)
{ {
const QStringList arguments = qApp->arguments(); const QStringList arguments = qApp->arguments();
for(QStringList::ConstIterator iter = arguments.constBegin(); iter != arguments.constEnd(); iter++) for(QStringList::ConstIterator iter = arguments.constBegin(); iter != arguments.constEnd(); iter++)
@ -192,19 +192,28 @@ void CMainWindow::showEvent(QShowEvent *event)
} }
if(!m_pendingFiles.empty()) if(!m_pendingFiles.empty())
{ {
QTimer::singleShot(0, this, SLOT(analyzeFiles())); m_status = APP_STATUS_AWAITING;
QTimer::singleShot(FILE_RECEIVE_DELAY, this, SLOT(analyzeFiles()));
} }
QTimer::singleShot(1250, this, SLOT(initShellExtension())); QTimer::singleShot(125, m_ipc, SLOT(startListening()));
m_firstShow = false; QTimer::singleShot(250, this, SLOT(initShellExtension()));
if(m_status == APP_STATUS_STARTING)
{
m_status = APP_STATUS_IDLE;
}
} }
//Enable drag & drop support
setAcceptDrops(true);
} }
void CMainWindow::closeEvent(QCloseEvent *event) void CMainWindow::closeEvent(QCloseEvent *event)
{ {
if(m_process) if(m_process)
{ {
if(m_process->state() != QProcess::NotRunning) if(!APPLICATION_IS_IDLE)
{ {
event->ignore(); event->ignore();
} }
@ -238,9 +247,9 @@ void CMainWindow::dragEnterEvent(QDragEnterEvent *event)
void CMainWindow::dropEvent(QDropEvent *event) void CMainWindow::dropEvent(QDropEvent *event)
{ {
if(m_process && (m_process->state() != QProcess::NotRunning)) if(!APPLICATION_IS_IDLE)
{ {
qWarning("Process is still running!\n"); qWarning("Cannot process files at this time!\n");
return; return;
} }
@ -259,6 +268,7 @@ void CMainWindow::dropEvent(QDropEvent *event)
if(!m_pendingFiles.isEmpty()) if(!m_pendingFiles.isEmpty())
{ {
m_status = APP_STATUS_WORKING;
QTimer::singleShot(0, this, SLOT(analyzeFiles())); QTimer::singleShot(0, this, SLOT(analyzeFiles()));
} }
} }
@ -318,6 +328,8 @@ void CMainWindow::analyzeFiles(void)
return; return;
} }
m_status = APP_STATUS_WORKING;
//Clear data //Clear data
ui->textBrowser->clear(); ui->textBrowser->clear();
m_outputLines.clear(); m_outputLines.clear();
@ -336,9 +348,6 @@ void CMainWindow::analyzeFiles(void)
m_floatingLabel->setText(QString::fromLatin1(STATUS_WORK)); m_floatingLabel->setText(QString::fromLatin1(STATUS_WORK));
m_floatingLabel->setCursor(Qt::WaitCursor); m_floatingLabel->setCursor(Qt::WaitCursor);
//Trigger GUI update
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
//Give it a go! //Give it a go!
QTimer::singleShot(0, this, SLOT(analyzeNextFile())); QTimer::singleShot(0, this, SLOT(analyzeNextFile()));
} }
@ -351,6 +360,13 @@ void CMainWindow::analyzeNextFile(void)
return; return;
} }
//Still running?
if(m_process->state() != QProcess::NotRunning)
{
qWarning("Process is still running!\n");
return;
}
//Lookup MediaInfo path //Lookup MediaInfo path
const QString mediaInfoPath = getMediaInfoPath(); const QString mediaInfoPath = getMediaInfoPath();
if(mediaInfoPath.isEmpty()) if(mediaInfoPath.isEmpty())
@ -362,6 +378,7 @@ void CMainWindow::analyzeNextFile(void)
ui->analyzeButton->setEnabled(true); ui->analyzeButton->setEnabled(true);
ui->exitButton->setEnabled(true); ui->exitButton->setEnabled(true);
ui->menuPreferences->setEnabled(true); ui->menuPreferences->setEnabled(true);
m_status = APP_STATUS_IDLE;
return; return;
} }
@ -387,6 +404,7 @@ void CMainWindow::analyzeNextFile(void)
ui->analyzeButton->setEnabled(true); ui->analyzeButton->setEnabled(true);
ui->exitButton->setEnabled(true); ui->exitButton->setEnabled(true);
ui->menuPreferences->setEnabled(true); ui->menuPreferences->setEnabled(true);
m_status = APP_STATUS_IDLE;
return; return;
} }
@ -395,9 +413,9 @@ void CMainWindow::analyzeNextFile(void)
void CMainWindow::analyzeButtonClicked(void) void CMainWindow::analyzeButtonClicked(void)
{ {
if(m_process && (m_process->state() != QProcess::NotRunning)) if(!APPLICATION_IS_IDLE)
{ {
qWarning("Process is still running!\n"); qWarning("Cannot process files at this time!\n");
return; return;
} }
@ -406,15 +424,16 @@ void CMainWindow::analyzeButtonClicked(void)
{ {
m_pendingFiles.clear(); m_pendingFiles.clear();
m_pendingFiles << selectedFiles; m_pendingFiles << selectedFiles;
m_status = APP_STATUS_WORKING;
analyzeFiles(); analyzeFiles();
} }
} }
void CMainWindow::saveButtonClicked(void) void CMainWindow::saveButtonClicked(void)
{ {
if(m_process && (m_process->state() != QProcess::NotRunning)) if(!APPLICATION_IS_IDLE)
{ {
qWarning("Process is still running!\n"); qWarning("Cannot process files at this time!\n");
return; return;
} }
@ -437,9 +456,9 @@ void CMainWindow::saveButtonClicked(void)
void CMainWindow::copyToClipboardButtonClicked(void) void CMainWindow::copyToClipboardButtonClicked(void)
{ {
if(m_process && (m_process->state() != QProcess::NotRunning)) if(!APPLICATION_IS_IDLE)
{ {
qWarning("Process is still running!\n"); qWarning("Cannot process files at this time!\n");
return; return;
} }
@ -452,9 +471,9 @@ void CMainWindow::copyToClipboardButtonClicked(void)
void CMainWindow::clearButtonClicked(void) void CMainWindow::clearButtonClicked(void)
{ {
if(m_process && (m_process->state() != QProcess::NotRunning)) if(!APPLICATION_IS_IDLE)
{ {
qWarning("Process is still running!\n"); qWarning("Cannot process files at this time!\n");
return; return;
} }
@ -551,6 +570,8 @@ void CMainWindow::processFinished(void)
ui->analyzeButton->setEnabled(true); ui->analyzeButton->setEnabled(true);
ui->exitButton->setEnabled(true); ui->exitButton->setEnabled(true);
ui->menuPreferences->setEnabled(true); ui->menuPreferences->setEnabled(true);
m_status = APP_STATUS_IDLE;
} }
void CMainWindow::initShellExtension(void) void CMainWindow::initShellExtension(void)
@ -584,9 +605,9 @@ void CMainWindow::linkTriggered(void)
void CMainWindow::showAboutScreen(void) void CMainWindow::showAboutScreen(void)
{ {
if(m_process && (m_process->state() != QProcess::NotRunning)) if(!APPLICATION_IS_IDLE)
{ {
qWarning("Process is still running!\n"); qWarning("Cannot process files at this time!\n");
return; return;
} }
@ -645,6 +666,38 @@ void CMainWindow::updateSize(void)
} }
} }
void CMainWindow::fileReceived(const QString &str)
{
mixp_bring_to_front(this);
if(str.compare("?") != 0)
{
qDebug("Received file: %s", str.toUtf8().constData());
if((m_status != APP_STATUS_IDLE) && (m_status != APP_STATUS_AWAITING))
{
qWarning("Cannot process files at this time!\n");
return;
}
const QString absPath = QFileInfo(QDir::fromNativeSeparators(str)).absoluteFilePath();
QFileInfo fileInfo(absPath);
if(fileInfo.exists() && fileInfo.isFile())
{
m_pendingFiles << fileInfo.canonicalFilePath();
if(m_status == APP_STATUS_IDLE)
{
m_status = APP_STATUS_AWAITING;
QTimer::singleShot(FILE_RECEIVE_DELAY, this, SLOT(analyzeFiles()));
}
}
}
else
{
qDebug("Received ping from another instance!");
}
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS // PRIVATE FUNCTIONS
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -32,6 +32,7 @@ class QProcess;
class QLabel; class QLabel;
class QFile; class QFile;
class mixp_icon_t; class mixp_icon_t;
class IPC;
//MainWindow class //MainWindow class
class CMainWindow: public QMainWindow class CMainWindow: public QMainWindow
@ -39,7 +40,7 @@ class CMainWindow: public QMainWindow
Q_OBJECT Q_OBJECT
public: public:
CMainWindow(const QString &tempFolder, QWidget *parent = 0); CMainWindow(const QString &tempFolder, IPC *const ipc, QWidget *parent = 0);
~CMainWindow(void); ~CMainWindow(void);
private slots: private slots:
@ -56,6 +57,7 @@ private slots:
void updateSize(void); void updateSize(void);
void initShellExtension(void); void initShellExtension(void);
void updateShellExtension(bool checked); void updateShellExtension(bool checked);
void fileReceived(const QString &path);
protected: protected:
virtual void showEvent(QShowEvent *event); virtual void showEvent(QShowEvent *event);
@ -67,16 +69,27 @@ protected:
virtual void keyPressEvent(QKeyEvent *e); virtual void keyPressEvent(QKeyEvent *e);
private: private:
enum
{
APP_STATUS_STARTING = 0,
APP_STATUS_IDLE = 1,
APP_STATUS_AWAITING = 2,
APP_STATUS_WORKING = 3
}
status_t;
Ui::MainWindow *ui; //for Qt UIC Ui::MainWindow *ui; //for Qt UIC
int m_status;
const QString &m_tempFolder; const QString &m_tempFolder;
bool m_firstShow;
QFile *m_mediaInfoHandle; QFile *m_mediaInfoHandle;
QProcess *m_process; QProcess *m_process;
QLabel *m_floatingLabel; QLabel *m_floatingLabel;
QStringList m_pendingFiles; QStringList m_pendingFiles;
QStringList m_outputLines; QStringList m_outputLines;
mixp_icon_t *m_icon; mixp_icon_t *m_icon;
IPC *const m_ipc;
const QList<QPair<const QString, const QString>> m_htmlEscape; const QList<QPair<const QString, const QString>> m_htmlEscape;

View File

@ -478,6 +478,26 @@ bool mixp_beep(int beepType)
} }
} }
/*
* Bring the specifed window to the front
*/
bool mixp_bring_to_front(const QWidget *window)
{
bool ret = false;
if(window)
{
for(int i = 0; (i < 5) && (!ret); i++)
{
ret = (SetForegroundWindow(window->winId()) != FALSE);
SwitchToThisWindow(window->winId(), TRUE);
}
LockSetForegroundWindow(LSFW_LOCK);
}
return ret;
}
/* /*
* Registry root key * Registry root key
*/ */

View File

@ -60,6 +60,7 @@ QDate mixp_get_current_date(void);
mixp_icon_t *mixp_set_window_icon(QWidget *window, const QIcon &icon, const bool bIsBigIcon); mixp_icon_t *mixp_set_window_icon(QWidget *window, const QIcon &icon, const bool bIsBigIcon);
void mixp_free_window_icon(mixp_icon_t *icon); void mixp_free_window_icon(mixp_icon_t *icon);
bool mixp_beep(int beepType); bool mixp_beep(int beepType);
bool mixp_bring_to_front(const QWidget *window);
void mixp_shell_change_notification(void); void mixp_shell_change_notification(void);
//Regsitry //Regsitry