Add Q_COREAPP_STARTUP_FUNCTION macro.

This is necessary for initializing things in a library, which require
a QCoreApplication instance (unlike Q_CONSTRUCTOR_FUNCTION, which runs
before that). Example use cases: KCrash (segv handler), and KCheckAccelerators
(debugging tool triggered by magic key combination).

Change-Id: I5f4c4699dd4d21aea72b007989ba57467e86ed10
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
David Faure 2013-01-14 12:58:31 +01:00 committed by The Qt Project
parent 3a1f1aecf9
commit d147285d64
4 changed files with 110 additions and 1 deletions

View File

@ -57,7 +57,14 @@ foreach (const QString &path, app.libraryPaths())
//! [3]
// Called once QCoreApplication exists
static void preRoutineMyDebugTool()
{
MyDebugTool* tool = new MyDebugTool(QCoreApplication::instance());
QCoreApplication::instance()->installEventFilter(tool);
}
Q_COREAPP_STARTUP_FUNCTION(preRoutineMyDebugTool)
//! [3]

View File

@ -194,8 +194,32 @@ extern "C" void Q_CORE_EXPORT qt_startup_hook()
{
}
typedef QList<QtStartUpFunction> QStartUpFuncList;
Q_GLOBAL_STATIC(QStartUpFuncList, preRList)
typedef QList<QtCleanUpFunction> QVFuncList;
Q_GLOBAL_STATIC(QVFuncList, postRList)
static QBasicMutex globalPreRoutinesMutex;
/*!
\internal
Adds a global routine that will be called from the QCoreApplication
constructor. The public API is Q_COREAPP_STARTUP_FUNCTION.
*/
void qAddPreRoutine(QtStartUpFunction p)
{
QStartUpFuncList *list = preRList();
if (!list)
return;
// Due to C++11 parallel dynamic initialization, this can be called
// from multiple threads.
#ifndef QT_NO_THREAD
QMutexLocker locker(&globalPreRoutinesMutex);
#endif
if (QCoreApplication::instance())
p();
list->prepend(p); // in case QCoreApplication is re-created, see qt_call_pre_routines
}
void qAddPostRoutine(QtCleanUpFunction p)
{
@ -213,6 +237,21 @@ void qRemovePostRoutine(QtCleanUpFunction p)
list->removeAll(p);
}
static void qt_call_pre_routines()
{
QStartUpFuncList *list = preRList();
if (!list)
return;
#ifndef QT_NO_THREAD
QMutexLocker locker(&globalPreRoutinesMutex);
#endif
// Unlike qt_call_post_routines, we don't empty the list, because
// Q_COREAPP_STARTUP_FUNCTION is a macro, so the user expects
// the function to be executed every time QCoreApplication is created.
for (int i = 0; i < list->count(); ++i)
list->at(i)();
}
void Q_CORE_EXPORT qt_call_post_routines()
{
QVFuncList *list = 0;
@ -637,6 +676,7 @@ void QCoreApplication::init()
d->processCommandLineArguments();
qt_call_pre_routines();
qt_startup_hook();
}
@ -2324,6 +2364,31 @@ void QCoreApplication::setEventDispatcher(QAbstractEventDispatcher *eventDispatc
mainThread->setEventDispatcher(eventDispatcher);
}
/*!
\macro Q_COREAPP_STARTUP_FUNCTION(QtStartUpFunction ptr)
\since 5.1
\relates QCoreApplication
\reentrant
Adds a global function that will be called from the QCoreApplication
constructor. This macro is normally used to initialize libraries
for program-wide functionality, without requiring the application to
call into the library for initialization.
The function specified by \a ptr should take no arguments and should
return nothing. For example:
\snippet code/src_corelib_kernel_qcoreapplication.cpp 3
Note that the startup function will run at the end of the QCoreApplication constructor,
before any GUI initialization. If GUI code is required in the function,
use a timer (or a queued invocation) to perform the initialization later on,
from the event loop.
If QCoreApplication is deleted and another QCoreApplication is created,
the startup function will be invoked again.
*/
/*!
\fn void qAddPostRoutine(QtCleanUpFunction ptr)
\relates QCoreApplication

View File

@ -220,12 +220,20 @@ public: \
{ return QCoreApplication::translate(#context, sourceText, disambiguation, n); } \
private:
typedef void (*QtStartUpFunction)();
typedef void (*QtCleanUpFunction)();
Q_CORE_EXPORT void qAddPreRoutine(QtStartUpFunction);
Q_CORE_EXPORT void qAddPostRoutine(QtCleanUpFunction);
Q_CORE_EXPORT void qRemovePostRoutine(QtCleanUpFunction);
Q_CORE_EXPORT QString qAppName(); // get application name
#define Q_COREAPP_STARTUP_FUNCTION(AFUNC) \
static void AFUNC ## _ctor_function() { \
qAddPreRoutine(AFUNC); \
} \
Q_CONSTRUCTOR_FUNCTION(AFUNC ## _ctor_function)
#if defined(Q_OS_WIN) && !defined(QT_NO_DEBUG_STREAM)
Q_CORE_EXPORT QString decodeMSG(const MSG &);
Q_CORE_EXPORT QDebug operator<<(QDebug, const MSG &);

View File

@ -55,6 +55,8 @@ private slots:
void checkptr();
void qstaticassert();
void qConstructorFunction();
void qCoreAppStartupFunction();
void qCoreAppStartupFunctionRestart();
void isEnum();
void qAlignOf();
};
@ -303,6 +305,33 @@ void tst_QGlobal::qConstructorFunction()
QCOMPARE(qConstructorFunctionValue, 123);
}
static int qStartupFunctionValue;
static void myStartupFunc()
{
Q_ASSERT(QCoreApplication::instance());
if (QCoreApplication::instance())
qStartupFunctionValue += 124;
}
Q_COREAPP_STARTUP_FUNCTION(myStartupFunc)
void tst_QGlobal::qCoreAppStartupFunction()
{
QCOMPARE(qStartupFunctionValue, 0);
int argc = 1;
char *argv[] = { const_cast<char*>("tst_qglobal") };
QCoreApplication app(argc, argv);
QCOMPARE(qStartupFunctionValue, 124);
}
void tst_QGlobal::qCoreAppStartupFunctionRestart()
{
qStartupFunctionValue = 0;
qCoreAppStartupFunction();
qStartupFunctionValue = 0;
qCoreAppStartupFunction();
}
struct isEnum_A {
int n_;
};
@ -532,5 +561,5 @@ void tst_QGlobal::qAlignOf()
#undef TEST_AlignOf_RValueRef
#undef TEST_AlignOf_impl
QTEST_MAIN(tst_QGlobal)
QTEST_APPLESS_MAIN(tst_QGlobal)
#include "tst_qglobal.moc"