| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Copyright (C) 2016 Intel Corporation. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtCore module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qcoreapplication.h" |
| #include "qcoreapplication_p.h" |
| |
| #ifndef QT_NO_QOBJECT |
| #include "qabstracteventdispatcher.h" |
| #include "qcoreevent.h" |
| #include "qeventloop.h" |
| #endif |
| #include "qmetaobject.h" |
| #include "qcorecmdlineargs_p.h" |
| #include <qdatastream.h> |
| #include <qdebug.h> |
| #include <qdir.h> |
| #include <qfile.h> |
| #include <qfileinfo.h> |
| #include <qmutex.h> |
| #include <private/qloggingregistry_p.h> |
| #include <qscopeguard.h> |
| #include <qstandardpaths.h> |
| #ifndef QT_NO_QOBJECT |
| #include <qthread.h> |
| #include <qthreadstorage.h> |
| #include <private/qthread_p.h> |
| #if QT_CONFIG(thread) |
| #include <qthreadpool.h> |
| #endif |
| #endif |
| #include <qelapsedtimer.h> |
| #include <qlibraryinfo.h> |
| #include <qvarlengtharray.h> |
| #include <private/qfactoryloader_p.h> |
| #include <private/qfunctions_p.h> |
| #include <private/qlocale_p.h> |
| #include <private/qlocking_p.h> |
| #include <private/qhooks_p.h> |
| |
| #ifndef QT_NO_QOBJECT |
| #if defined(Q_OS_UNIX) |
| # if defined(Q_OS_DARWIN) |
| # include "qeventdispatcher_cf_p.h" |
| # else |
| # if !defined(QT_NO_GLIB) |
| # include "qeventdispatcher_glib_p.h" |
| # endif |
| # endif |
| # include "qeventdispatcher_unix_p.h" |
| #endif |
| #ifdef Q_OS_WIN |
| # ifdef Q_OS_WINRT |
| # include "qeventdispatcher_winrt_p.h" |
| # include "qfunctions_winrt.h" |
| # include <wrl.h> |
| # include <Windows.ApplicationModel.core.h> |
| using namespace ABI::Windows::ApplicationModel::Core; |
| using namespace Microsoft::WRL; |
| # else |
| # include "qeventdispatcher_win_p.h" |
| # endif |
| #endif |
| #endif // QT_NO_QOBJECT |
| |
| #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) |
| # include <private/qjni_p.h> |
| # include <private/qjnihelpers_p.h> |
| #endif |
| |
| #ifdef Q_OS_MAC |
| # include "qcore_mac_p.h" |
| #endif |
| |
| #include <stdlib.h> |
| |
| #ifdef Q_OS_UNIX |
| # include <locale.h> |
| # include <unistd.h> |
| # include <sys/types.h> |
| #endif |
| |
| #ifdef Q_OS_VXWORKS |
| # include <taskLib.h> |
| #endif |
| |
| #ifdef Q_OS_WASM |
| #include <emscripten.h> |
| #include <emscripten/val.h> |
| #endif |
| |
| #ifdef QT_BOOTSTRAPPED |
| #include <private/qtrace_p.h> |
| #else |
| #include <qtcore_tracepoints_p.h> |
| #endif |
| |
| #include <algorithm> |
| |
| QT_BEGIN_NAMESPACE |
| |
| #ifndef QT_NO_QOBJECT |
| class QMutexUnlocker |
| { |
| public: |
| inline explicit QMutexUnlocker(QMutex *m) |
| : mtx(m) |
| { } |
| inline ~QMutexUnlocker() { unlock(); } |
| inline void unlock() { if (mtx) mtx->unlock(); mtx = 0; } |
| |
| private: |
| Q_DISABLE_COPY(QMutexUnlocker) |
| |
| QMutex *mtx; |
| }; |
| #endif |
| |
| #if defined(Q_OS_WIN) || defined(Q_OS_MAC) |
| extern QString qAppFileName(); |
| #endif |
| |
| #if QT_VERSION >= 0x060000 |
| # error "Bump QCoreApplicatoinPrivate::app_compile_version to 0x060000" |
| #endif |
| int QCoreApplicationPrivate::app_compile_version = 0x050000; //we don't know exactly, but it's at least 5.0.0 |
| |
| bool QCoreApplicationPrivate::setuidAllowed = false; |
| |
| #if !defined(Q_OS_WIN) |
| #ifdef Q_OS_DARWIN |
| QString QCoreApplicationPrivate::infoDictionaryStringProperty(const QString &propertyName) |
| { |
| QString bundleName; |
| QCFString cfPropertyName = propertyName.toCFString(); |
| CFTypeRef string = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), |
| cfPropertyName); |
| if (string) |
| bundleName = QString::fromCFString(static_cast<CFStringRef>(string)); |
| return bundleName; |
| } |
| #endif |
| QString QCoreApplicationPrivate::appName() const |
| { |
| QString applicationName; |
| #ifdef Q_OS_DARWIN |
| applicationName = infoDictionaryStringProperty(QStringLiteral("CFBundleName")); |
| #endif |
| if (applicationName.isEmpty() && argv[0]) { |
| char *p = strrchr(argv[0], '/'); |
| applicationName = QString::fromLocal8Bit(p ? p + 1 : argv[0]); |
| } |
| |
| return applicationName; |
| } |
| QString QCoreApplicationPrivate::appVersion() const |
| { |
| QString applicationVersion; |
| #ifndef QT_BOOTSTRAPPED |
| # ifdef Q_OS_DARWIN |
| applicationVersion = infoDictionaryStringProperty(QStringLiteral("CFBundleVersion")); |
| # elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) |
| QJNIObjectPrivate context(QtAndroidPrivate::context()); |
| if (context.isValid()) { |
| QJNIObjectPrivate pm = context.callObjectMethod( |
| "getPackageManager", "()Landroid/content/pm/PackageManager;"); |
| QJNIObjectPrivate pn = context.callObjectMethod<jstring>("getPackageName"); |
| if (pm.isValid() && pn.isValid()) { |
| QJNIObjectPrivate packageInfo = pm.callObjectMethod( |
| "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;", |
| pn.object(), 0); |
| if (packageInfo.isValid()) { |
| QJNIObjectPrivate versionName = packageInfo.getObjectField( |
| "versionName", "Ljava/lang/String;"); |
| if (versionName.isValid()) |
| return versionName.toString(); |
| } |
| } |
| } |
| # endif |
| #endif |
| return applicationVersion; |
| } |
| #endif |
| |
| QString *QCoreApplicationPrivate::cachedApplicationFilePath = nullptr; |
| |
| bool QCoreApplicationPrivate::checkInstance(const char *function) |
| { |
| bool b = (QCoreApplication::self != nullptr); |
| if (!b) |
| qWarning("QApplication::%s: Please instantiate the QApplication object first", function); |
| return b; |
| } |
| |
| #if QT_CONFIG(commandlineparser) |
| void QCoreApplicationPrivate::addQtOptions(QList<QCommandLineOption> *options) |
| { |
| options->append(QCommandLineOption(QStringLiteral("qmljsdebugger"), |
| QStringLiteral("Activates the QML/JS debugger with a specified port. The value must be of format port:1234[,block]. \"block\" makes the application wait for a connection."), |
| QStringLiteral("value"))); |
| } |
| #endif |
| |
| void QCoreApplicationPrivate::processCommandLineArguments() |
| { |
| int j = argc ? 1 : 0; |
| for (int i = 1; i < argc; ++i) { |
| if (!argv[i]) |
| continue; |
| if (*argv[i] != '-') { |
| argv[j++] = argv[i]; |
| continue; |
| } |
| const char *arg = argv[i]; |
| if (arg[1] == '-') // startsWith("--") |
| ++arg; |
| if (strncmp(arg, "-qmljsdebugger=", 15) == 0) { |
| qmljs_debug_arguments = QString::fromLocal8Bit(arg + 15); |
| } else if (strcmp(arg, "-qmljsdebugger") == 0 && i < argc - 1) { |
| ++i; |
| qmljs_debug_arguments = QString::fromLocal8Bit(argv[i]); |
| } else { |
| argv[j++] = argv[i]; |
| } |
| } |
| |
| if (j < argc) { |
| argv[j] = nullptr; |
| argc = j; |
| } |
| } |
| |
| // Support for introspection |
| |
| 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 globalRoutinesMutex; |
| |
| /*! |
| \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; |
| |
| if (QCoreApplication::instance()) |
| p(); |
| |
| // Due to C++11 parallel dynamic initialization, this can be called |
| // from multiple threads. |
| const auto locker = qt_scoped_lock(globalRoutinesMutex); |
| list->prepend(p); // in case QCoreApplication is re-created, see qt_call_pre_routines |
| } |
| |
| void qAddPostRoutine(QtCleanUpFunction p) |
| { |
| QVFuncList *list = postRList(); |
| if (!list) |
| return; |
| const auto locker = qt_scoped_lock(globalRoutinesMutex); |
| list->prepend(p); |
| } |
| |
| void qRemovePostRoutine(QtCleanUpFunction p) |
| { |
| QVFuncList *list = postRList(); |
| if (!list) |
| return; |
| const auto locker = qt_scoped_lock(globalRoutinesMutex); |
| list->removeAll(p); |
| } |
| |
| static void qt_call_pre_routines() |
| { |
| if (!preRList.exists()) |
| return; |
| |
| QVFuncList list; |
| { |
| const auto locker = qt_scoped_lock(globalRoutinesMutex); |
| // 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. |
| list = *preRList; |
| } |
| for (int i = 0; i < list.count(); ++i) |
| list.at(i)(); |
| } |
| |
| void Q_CORE_EXPORT qt_call_post_routines() |
| { |
| if (!postRList.exists()) |
| return; |
| |
| forever { |
| QVFuncList list; |
| { |
| // extract the current list and make the stored list empty |
| const auto locker = qt_scoped_lock(globalRoutinesMutex); |
| qSwap(*postRList, list); |
| } |
| |
| if (list.isEmpty()) |
| break; |
| for (QtCleanUpFunction f : qAsConst(list)) |
| f(); |
| } |
| } |
| |
| |
| // initialized in qcoreapplication and in qtextstream autotest when setlocale is called. |
| static bool qt_locale_initialized = false; |
| |
| #ifndef QT_NO_QOBJECT |
| |
| // app starting up if false |
| bool QCoreApplicationPrivate::is_app_running = false; |
| // app closing down if true |
| bool QCoreApplicationPrivate::is_app_closing = false; |
| |
| Q_CORE_EXPORT uint qGlobalPostedEventsCount() |
| { |
| QThreadData *currentThreadData = QThreadData::current(); |
| return currentThreadData->postEventList.size() - currentThreadData->postEventList.startOffset; |
| } |
| |
| QAbstractEventDispatcher *QCoreApplicationPrivate::eventDispatcher = nullptr; |
| |
| #endif // QT_NO_QOBJECT |
| |
| QCoreApplication *QCoreApplication::self = nullptr; |
| uint QCoreApplicationPrivate::attribs = |
| (1 << Qt::AA_SynthesizeMouseForUnhandledTouchEvents) | |
| (1 << Qt::AA_SynthesizeMouseForUnhandledTabletEvents); |
| |
| struct QCoreApplicationData { |
| QCoreApplicationData() noexcept { |
| applicationNameSet = false; |
| applicationVersionSet = false; |
| } |
| ~QCoreApplicationData() { |
| #ifndef QT_NO_QOBJECT |
| // cleanup the QAdoptedThread created for the main() thread |
| if (auto *t = QCoreApplicationPrivate::theMainThread.loadAcquire()) { |
| QThreadData *data = QThreadData::get2(t); |
| data->deref(); // deletes the data and the adopted thread |
| } |
| #endif |
| } |
| |
| QString orgName, orgDomain; |
| QString application; // application name, initially from argv[0], can then be modified. |
| QString applicationVersion; |
| bool applicationNameSet; // true if setApplicationName was called |
| bool applicationVersionSet; // true if setApplicationVersion was called |
| |
| #if QT_CONFIG(library) |
| QScopedPointer<QStringList> app_libpaths; |
| QScopedPointer<QStringList> manual_libpaths; |
| #endif |
| |
| }; |
| |
| Q_GLOBAL_STATIC(QCoreApplicationData, coreappdata) |
| |
| #ifndef QT_NO_QOBJECT |
| static bool quitLockRefEnabled = true; |
| #endif |
| |
| #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) |
| // Check whether the command line arguments match those passed to main() |
| // by comparing to the global __argv/__argc (MS extension). |
| // Deep comparison is required since argv/argc is rebuilt by WinMain for |
| // GUI apps or when using MinGW due to its globbing. |
| static inline bool isArgvModified(int argc, char **argv) |
| { |
| if (__argc != argc || !__argv /* wmain() */) |
| return true; |
| if (__argv == argv) |
| return false; |
| for (int a = 0; a < argc; ++a) { |
| if (argv[a] != __argv[a] && strcmp(argv[a], __argv[a])) |
| return true; |
| } |
| return false; |
| } |
| |
| static inline bool contains(int argc, char **argv, const char *needle) |
| { |
| for (int a = 0; a < argc; ++a) { |
| if (!strcmp(argv[a], needle)) |
| return true; |
| } |
| return false; |
| } |
| #endif // Q_OS_WIN && !Q_OS_WINRT |
| |
| QCoreApplicationPrivate::QCoreApplicationPrivate(int &aargc, char **aargv, uint flags) |
| : |
| #ifndef QT_NO_QOBJECT |
| QObjectPrivate(), |
| #endif |
| argc(aargc) |
| , argv(aargv) |
| #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) |
| , origArgc(0) |
| , origArgv(nullptr) |
| #endif |
| , application_type(QCoreApplicationPrivate::Tty) |
| #ifndef QT_NO_QOBJECT |
| , in_exec(false) |
| , aboutToQuitEmitted(false) |
| , threadData_clean(false) |
| #else |
| , q_ptr(nullptr) |
| #endif |
| { |
| app_compile_version = flags & 0xffffff; |
| static const char *const empty = ""; |
| if (argc == 0 || argv == nullptr) { |
| argc = 0; |
| argv = const_cast<char **>(&empty); |
| } |
| #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) |
| if (!isArgvModified(argc, argv)) { |
| origArgc = argc; |
| origArgv = new char *[argc]; |
| std::copy(argv, argv + argc, QT_MAKE_CHECKED_ARRAY_ITERATOR(origArgv, argc)); |
| } |
| #endif // Q_OS_WIN && !Q_OS_WINRT |
| |
| #ifndef QT_NO_QOBJECT |
| QCoreApplicationPrivate::is_app_closing = false; |
| |
| # if defined(Q_OS_UNIX) |
| if (Q_UNLIKELY(!setuidAllowed && (geteuid() != getuid()))) |
| qFatal("FATAL: The application binary appears to be running setuid, this is a security hole."); |
| # endif // Q_OS_UNIX |
| |
| #ifdef Q_OS_WINRT |
| QThreadData::setMainThread(); |
| #endif |
| |
| QThread *cur = QThread::currentThread(); // note: this may end up setting theMainThread! |
| if (cur != theMainThread.loadAcquire()) |
| qWarning("WARNING: QApplication was not created in the main() thread."); |
| #endif |
| } |
| |
| QCoreApplicationPrivate::~QCoreApplicationPrivate() |
| { |
| #ifdef Q_OS_WASM |
| EM_ASM( |
| // unmount persistent directory as IDBFS |
| // see also QTBUG-70002 |
| FS.unmount('/home/web_user'); |
| ); |
| #endif |
| #ifndef QT_NO_QOBJECT |
| cleanupThreadData(); |
| #endif |
| #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) |
| delete [] origArgv; |
| #endif |
| QCoreApplicationPrivate::clearApplicationFilePath(); |
| } |
| |
| #ifndef QT_NO_QOBJECT |
| |
| void QCoreApplicationPrivate::cleanupThreadData() |
| { |
| if (threadData && !threadData_clean) { |
| #if QT_CONFIG(thread) |
| void *data = &threadData->tls; |
| QThreadStorageData::finish((void **)data); |
| #endif |
| |
| // need to clear the state of the mainData, just in case a new QCoreApplication comes along. |
| const auto locker = qt_scoped_lock(threadData->postEventList.mutex); |
| for (int i = 0; i < threadData->postEventList.size(); ++i) { |
| const QPostEvent &pe = threadData->postEventList.at(i); |
| if (pe.event) { |
| --pe.receiver->d_func()->postedEvents; |
| pe.event->posted = false; |
| delete pe.event; |
| } |
| } |
| threadData->postEventList.clear(); |
| threadData->postEventList.recursion = 0; |
| threadData->quitNow = false; |
| threadData_clean = true; |
| } |
| } |
| |
| void QCoreApplicationPrivate::createEventDispatcher() |
| { |
| Q_Q(QCoreApplication); |
| QThreadData *data = QThreadData::current(); |
| Q_ASSERT(!data->hasEventDispatcher()); |
| eventDispatcher = data->createEventDispatcher(); |
| eventDispatcher->setParent(q); |
| } |
| |
| void QCoreApplicationPrivate::eventDispatcherReady() |
| { |
| } |
| |
| QBasicAtomicPointer<QThread> QCoreApplicationPrivate::theMainThread = Q_BASIC_ATOMIC_INITIALIZER(0); |
| QThread *QCoreApplicationPrivate::mainThread() |
| { |
| Q_ASSERT(theMainThread.loadRelaxed() != 0); |
| return theMainThread.loadRelaxed(); |
| } |
| |
| bool QCoreApplicationPrivate::threadRequiresCoreApplication() |
| { |
| QThreadData *data = QThreadData::current(false); |
| if (!data) |
| return true; // default setting |
| return data->requiresCoreApplication; |
| } |
| |
| void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver) |
| { |
| QThread *currentThread = QThread::currentThread(); |
| QThread *thr = receiver->thread(); |
| Q_ASSERT_X(currentThread == thr || !thr, |
| "QCoreApplication::sendEvent", |
| QString::asprintf("Cannot send events to objects owned by a different thread. " |
| "Current thread 0x%p. Receiver '%ls' (of type '%s') was created in thread 0x%p", |
| currentThread, qUtf16Printable(receiver->objectName()), |
| receiver->metaObject()->className(), thr) |
| .toLocal8Bit().data()); |
| Q_UNUSED(currentThread); |
| Q_UNUSED(thr); |
| } |
| |
| #endif // QT_NO_QOBJECT |
| |
| void QCoreApplicationPrivate::appendApplicationPathToLibraryPaths() |
| { |
| #if QT_CONFIG(library) |
| QStringList *app_libpaths = coreappdata()->app_libpaths.data(); |
| if (!app_libpaths) |
| coreappdata()->app_libpaths.reset(app_libpaths = new QStringList); |
| QString app_location = QCoreApplication::applicationFilePath(); |
| app_location.truncate(app_location.lastIndexOf(QLatin1Char('/'))); |
| #ifdef Q_OS_WINRT |
| if (app_location.isEmpty()) |
| app_location.append(QLatin1Char('/')); |
| #endif |
| app_location = QDir(app_location).canonicalPath(); |
| if (QFile::exists(app_location) && !app_libpaths->contains(app_location)) |
| app_libpaths->append(app_location); |
| #endif |
| } |
| |
| QString qAppName() |
| { |
| if (!QCoreApplicationPrivate::checkInstance("qAppName")) |
| return QString(); |
| return QCoreApplication::instance()->d_func()->appName(); |
| } |
| |
| void QCoreApplicationPrivate::initLocale() |
| { |
| if (qt_locale_initialized) |
| return; |
| qt_locale_initialized = true; |
| #if defined(Q_OS_UNIX) && !defined(QT_BOOTSTRAPPED) |
| setlocale(LC_ALL, ""); |
| #endif |
| } |
| |
| |
| /*! |
| \class QCoreApplication |
| \inmodule QtCore |
| \brief The QCoreApplication class provides an event loop for Qt |
| applications without UI. |
| |
| This class is used by non-GUI applications to provide their event |
| loop. For non-GUI application that uses Qt, there should be exactly |
| one QCoreApplication object. For GUI applications, see |
| QGuiApplication. For applications that use the Qt Widgets module, |
| see QApplication. |
| |
| QCoreApplication contains the main event loop, where all events |
| from the operating system (e.g., timer and network events) and |
| other sources are processed and dispatched. It also handles the |
| application's initialization and finalization, as well as |
| system-wide and application-wide settings. |
| |
| \section1 The Event Loop and Event Handling |
| |
| The event loop is started with a call to exec(). Long-running |
| operations can call processEvents() to keep the application |
| responsive. |
| |
| In general, we recommend that you create a QCoreApplication, |
| QGuiApplication or a QApplication object in your \c main() |
| function as early as possible. exec() will not return until |
| the event loop exits; e.g., when quit() is called. |
| |
| Several static convenience functions are also provided. The |
| QCoreApplication object is available from instance(). Events can |
| be sent with sendEvent() or posted to an event queue with postEvent(). |
| Pending events can be removed with removePostedEvents() or dispatched |
| with sendPostedEvents(). |
| |
| The class provides a quit() slot and an aboutToQuit() signal. |
| |
| \section1 Application and Library Paths |
| |
| An application has an applicationDirPath() and an |
| applicationFilePath(). Library paths (see QLibrary) can be retrieved |
| with libraryPaths() and manipulated by setLibraryPaths(), addLibraryPath(), |
| and removeLibraryPath(). |
| |
| \section1 Internationalization and Translations |
| |
| Translation files can be added or removed |
| using installTranslator() and removeTranslator(). Application |
| strings can be translated using translate(). The QObject::tr() |
| and QObject::trUtf8() functions are implemented in terms of |
| translate(). |
| |
| \section1 Accessing Command Line Arguments |
| |
| The command line arguments which are passed to QCoreApplication's |
| constructor should be accessed using the arguments() function. |
| |
| \note QCoreApplication removes option \c -qmljsdebugger="...". It parses the |
| argument of \c qmljsdebugger, and then removes this option plus its argument. |
| |
| For more advanced command line option handling, create a QCommandLineParser. |
| |
| \section1 Locale Settings |
| |
| On Unix/Linux Qt is configured to use the system locale settings by |
| default. This can cause a conflict when using POSIX functions, for |
| instance, when converting between data types such as floats and |
| strings, since the notation may differ between locales. To get |
| around this problem, call the POSIX function \c{setlocale(LC_NUMERIC,"C")} |
| right after initializing QApplication, QGuiApplication or QCoreApplication |
| to reset the locale that is used for number formatting to "C"-locale. |
| |
| \sa QGuiApplication, QAbstractEventDispatcher, QEventLoop, |
| {Semaphores Example}, {Wait Conditions Example} |
| */ |
| |
| /*! |
| \fn static QCoreApplication *QCoreApplication::instance() |
| |
| Returns a pointer to the application's QCoreApplication (or |
| QGuiApplication/QApplication) instance. |
| |
| If no instance has been allocated, \nullptr is returned. |
| */ |
| |
| /*! |
| \internal |
| */ |
| QCoreApplication::QCoreApplication(QCoreApplicationPrivate &p) |
| #ifdef QT_NO_QOBJECT |
| : d_ptr(&p) |
| #else |
| : QObject(p, 0) |
| #endif |
| { |
| d_func()->q_ptr = this; |
| // note: it is the subclasses' job to call |
| // QCoreApplicationPrivate::eventDispatcher->startingUp(); |
| } |
| |
| #ifndef QT_NO_QOBJECT |
| /*! |
| \deprecated |
| This function is equivalent to calling \c {QCoreApplication::eventDispatcher()->flush()}, |
| which also is deprecated, see QAbstractEventDispatcher::flush(). Use sendPostedEvents() |
| and processEvents() for more fine-grained control of the event loop instead. |
| |
| Historically this functions was used to flush the platform-specific native event queues. |
| |
| \sa sendPostedEvents(), processEvents(), QAbstractEventDispatcher::flush() |
| */ |
| #if QT_DEPRECATED_SINCE(5, 9) |
| void QCoreApplication::flush() |
| { |
| if (self && self->d_func()->eventDispatcher) |
| self->d_func()->eventDispatcher->flush(); |
| } |
| #endif |
| #endif |
| |
| /*! |
| Constructs a Qt core application. Core applications are applications without |
| a graphical user interface. Such applications are used at the console or as |
| server processes. |
| |
| The \a argc and \a argv arguments are processed by the application, |
| and made available in a more convenient form by the arguments() |
| function. |
| |
| \warning The data referred to by \a argc and \a argv must stay valid |
| for the entire lifetime of the QCoreApplication object. In addition, |
| \a argc must be greater than zero and \a argv must contain at least |
| one valid character string. |
| */ |
| QCoreApplication::QCoreApplication(int &argc, char **argv |
| #ifndef Q_QDOC |
| , int _internal |
| #endif |
| ) |
| #ifdef QT_NO_QOBJECT |
| : d_ptr(new QCoreApplicationPrivate(argc, argv, _internal)) |
| #else |
| : QObject(*new QCoreApplicationPrivate(argc, argv, _internal)) |
| #endif |
| { |
| d_func()->q_ptr = this; |
| d_func()->init(); |
| #ifndef QT_NO_QOBJECT |
| QCoreApplicationPrivate::eventDispatcher->startingUp(); |
| #endif |
| } |
| |
| /*! |
| \enum QCoreApplication::anonymous |
| \internal |
| |
| \value ApplicationFlags QT_VERSION |
| */ |
| |
| void QCoreApplicationPrivate::init() |
| { |
| Q_TRACE_SCOPE(QCoreApplicationPrivate_init); |
| |
| #if defined(Q_OS_MACOS) |
| QMacAutoReleasePool pool; |
| #endif |
| |
| Q_Q(QCoreApplication); |
| |
| initLocale(); |
| |
| Q_ASSERT_X(!QCoreApplication::self, "QCoreApplication", "there should be only one application object"); |
| QCoreApplication::self = q; |
| |
| #ifdef Q_OS_WASM |
| EM_ASM( |
| // mount and sync persistent filesystem to sandbox |
| FS.mount(IDBFS, {}, '/home/web_user'); |
| FS.syncfs(true, function(err) { |
| if (err) |
| Module.print(err); |
| }); |
| ); |
| |
| #if QT_CONFIG(thread) |
| QThreadPrivate::idealThreadCount = emscripten::val::global("navigator")["hardwareConcurrency"].as<int>(); |
| #endif |
| #endif |
| |
| // Store app name/version (so they're still available after QCoreApplication is destroyed) |
| if (!coreappdata()->applicationNameSet) |
| coreappdata()->application = appName(); |
| |
| if (!coreappdata()->applicationVersionSet) |
| coreappdata()->applicationVersion = appVersion(); |
| |
| #if defined(Q_OS_ANDROID) |
| // We've deferred initializing the logging registry due to not being |
| // able to guarantee that logging happened on the same thread as the |
| // Qt main thread, but now that the Qt main thread is set up, we can |
| // enable categorized logging. |
| QLoggingRegistry::instance()->initializeRules(); |
| #endif |
| |
| #if QT_CONFIG(library) |
| // Reset the lib paths, so that they will be recomputed, taking the availability of argv[0] |
| // into account. If necessary, recompute right away and replay the manual changes on top of the |
| // new lib paths. |
| QStringList *appPaths = coreappdata()->app_libpaths.take(); |
| QStringList *manualPaths = coreappdata()->manual_libpaths.take(); |
| if (appPaths) { |
| if (manualPaths) { |
| // Replay the delta. As paths can only be prepended to the front or removed from |
| // anywhere in the list, we can just linearly scan the lists and find the items that |
| // have been removed. Once the original list is exhausted we know all the remaining |
| // items have been added. |
| QStringList newPaths(q->libraryPaths()); |
| for (int i = manualPaths->length(), j = appPaths->length(); i > 0 || j > 0; qt_noop()) { |
| if (--j < 0) { |
| newPaths.prepend((*manualPaths)[--i]); |
| } else if (--i < 0) { |
| newPaths.removeAll((*appPaths)[j]); |
| } else if ((*manualPaths)[i] != (*appPaths)[j]) { |
| newPaths.removeAll((*appPaths)[j]); |
| ++i; // try again with next item. |
| } |
| } |
| delete manualPaths; |
| coreappdata()->manual_libpaths.reset(new QStringList(newPaths)); |
| } |
| delete appPaths; |
| } |
| #endif |
| |
| #ifndef QT_NO_QOBJECT |
| // use the event dispatcher created by the app programmer (if any) |
| Q_ASSERT(!eventDispatcher); |
| eventDispatcher = threadData->eventDispatcher.loadRelaxed(); |
| |
| // otherwise we create one |
| if (!eventDispatcher) |
| createEventDispatcher(); |
| Q_ASSERT(eventDispatcher); |
| |
| if (!eventDispatcher->parent()) { |
| eventDispatcher->moveToThread(threadData->thread.loadAcquire()); |
| eventDispatcher->setParent(q); |
| } |
| |
| threadData->eventDispatcher = eventDispatcher; |
| eventDispatcherReady(); |
| #endif |
| |
| processCommandLineArguments(); |
| |
| qt_call_pre_routines(); |
| qt_startup_hook(); |
| #ifndef QT_BOOTSTRAPPED |
| if (Q_UNLIKELY(qtHookData[QHooks::Startup])) |
| reinterpret_cast<QHooks::StartupCallback>(qtHookData[QHooks::Startup])(); |
| #endif |
| |
| #ifndef QT_NO_QOBJECT |
| is_app_running = true; // No longer starting up. |
| #endif |
| } |
| |
| /*! |
| Destroys the QCoreApplication object. |
| */ |
| QCoreApplication::~QCoreApplication() |
| { |
| qt_call_post_routines(); |
| |
| self = nullptr; |
| #ifndef QT_NO_QOBJECT |
| QCoreApplicationPrivate::is_app_closing = true; |
| QCoreApplicationPrivate::is_app_running = false; |
| #endif |
| |
| #if QT_CONFIG(thread) |
| // Synchronize and stop the global thread pool threads. |
| QThreadPool *globalThreadPool = nullptr; |
| QT_TRY { |
| globalThreadPool = QThreadPool::globalInstance(); |
| } QT_CATCH (...) { |
| // swallow the exception, since destructors shouldn't throw |
| } |
| if (globalThreadPool) |
| globalThreadPool->waitForDone(); |
| #endif |
| |
| #ifndef QT_NO_QOBJECT |
| d_func()->threadData->eventDispatcher = nullptr; |
| if (QCoreApplicationPrivate::eventDispatcher) |
| QCoreApplicationPrivate::eventDispatcher->closingDown(); |
| QCoreApplicationPrivate::eventDispatcher = nullptr; |
| #endif |
| |
| #if QT_CONFIG(library) |
| coreappdata()->app_libpaths.reset(); |
| coreappdata()->manual_libpaths.reset(); |
| #endif |
| } |
| |
| /*! |
| \since 5.3 |
| |
| Allows the application to run setuid on UNIX platforms if \a allow |
| is true. |
| |
| If \a allow is false (the default) and Qt detects the application is |
| running with an effective user id different than the real user id, |
| the application will be aborted when a QCoreApplication instance is |
| created. |
| |
| Qt is not an appropriate solution for setuid programs due to its |
| large attack surface. However some applications may be required |
| to run in this manner for historical reasons. This flag will |
| prevent Qt from aborting the application when this is detected, |
| and must be set before a QCoreApplication instance is created. |
| |
| \note It is strongly recommended not to enable this option since |
| it introduces security risks. |
| */ |
| void QCoreApplication::setSetuidAllowed(bool allow) |
| { |
| QCoreApplicationPrivate::setuidAllowed = allow; |
| } |
| |
| /*! |
| \since 5.3 |
| |
| Returns true if the application is allowed to run setuid on UNIX |
| platforms. |
| |
| \sa QCoreApplication::setSetuidAllowed() |
| */ |
| bool QCoreApplication::isSetuidAllowed() |
| { |
| return QCoreApplicationPrivate::setuidAllowed; |
| } |
| |
| |
| /*! |
| Sets the attribute \a attribute if \a on is true; |
| otherwise clears the attribute. |
| |
| \note Some application attributes must be set \b before creating a |
| QCoreApplication instance. Refer to the Qt::ApplicationAttribute |
| documentation for more information. |
| |
| \sa testAttribute() |
| */ |
| void QCoreApplication::setAttribute(Qt::ApplicationAttribute attribute, bool on) |
| { |
| if (on) |
| QCoreApplicationPrivate::attribs |= 1 << attribute; |
| else |
| QCoreApplicationPrivate::attribs &= ~(1 << attribute); |
| #if defined(QT_NO_QOBJECT) |
| if (Q_UNLIKELY(qApp)) { |
| #else |
| if (Q_UNLIKELY(QCoreApplicationPrivate::is_app_running)) { |
| #endif |
| switch (attribute) { |
| case Qt::AA_EnableHighDpiScaling: |
| case Qt::AA_DisableHighDpiScaling: |
| case Qt::AA_PluginApplication: |
| case Qt::AA_UseDesktopOpenGL: |
| case Qt::AA_UseOpenGLES: |
| case Qt::AA_UseSoftwareOpenGL: |
| case Qt::AA_ShareOpenGLContexts: |
| #ifdef QT_BOOTSTRAPPED |
| qWarning("Attribute %d must be set before QCoreApplication is created.", |
| attribute); |
| #else |
| qWarning("Attribute Qt::%s must be set before QCoreApplication is created.", |
| QMetaEnum::fromType<Qt::ApplicationAttribute>().valueToKey(attribute)); |
| #endif |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| /*! |
| Returns \c true if attribute \a attribute is set; |
| otherwise returns \c false. |
| |
| \sa setAttribute() |
| */ |
| bool QCoreApplication::testAttribute(Qt::ApplicationAttribute attribute) |
| { |
| return QCoreApplicationPrivate::testAttribute(attribute); |
| } |
| |
| |
| #ifndef QT_NO_QOBJECT |
| |
| /*! |
| \property QCoreApplication::quitLockEnabled |
| |
| \brief Whether the use of the QEventLoopLocker feature can cause the |
| application to quit. |
| |
| The default is \c true. |
| |
| \sa QEventLoopLocker |
| */ |
| |
| bool QCoreApplication::isQuitLockEnabled() |
| { |
| return quitLockRefEnabled; |
| } |
| |
| static bool doNotify(QObject *, QEvent *); |
| |
| void QCoreApplication::setQuitLockEnabled(bool enabled) |
| { |
| quitLockRefEnabled = enabled; |
| } |
| |
| #if QT_DEPRECATED_SINCE(5, 6) |
| /*! |
| \internal |
| \deprecated |
| |
| This function is here to make it possible for Qt extensions to |
| hook into event notification without subclassing QApplication |
| */ |
| bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event) |
| { |
| return notifyInternal2(receiver, event); |
| } |
| #endif |
| |
| /*! |
| \internal |
| \since 5.6 |
| |
| This function is here to make it possible for Qt extensions to |
| hook into event notification without subclassing QApplication. |
| */ |
| bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event) |
| { |
| bool selfRequired = QCoreApplicationPrivate::threadRequiresCoreApplication(); |
| if (!self && selfRequired) |
| return false; |
| |
| // Make it possible for Qt Script to hook into events even |
| // though QApplication is subclassed... |
| bool result = false; |
| void *cbdata[] = { receiver, event, &result }; |
| if (QInternal::activateCallbacks(QInternal::EventNotifyCallback, cbdata)) { |
| return result; |
| } |
| |
| // Qt enforces the rule that events can only be sent to objects in |
| // the current thread, so receiver->d_func()->threadData is |
| // equivalent to QThreadData::current(), just without the function |
| // call overhead. |
| QObjectPrivate *d = receiver->d_func(); |
| QThreadData *threadData = d->threadData; |
| QScopedScopeLevelCounter scopeLevelCounter(threadData); |
| if (!selfRequired) |
| return doNotify(receiver, event); |
| return self->notify(receiver, event); |
| } |
| |
| /*! |
| \internal |
| \since 5.10 |
| |
| Forwards the \a event to the \a receiver, using the spontaneous |
| state of the \a originatingEvent if specified. |
| */ |
| bool QCoreApplication::forwardEvent(QObject *receiver, QEvent *event, QEvent *originatingEvent) |
| { |
| if (event && originatingEvent) |
| event->spont = originatingEvent->spont; |
| |
| return notifyInternal2(receiver, event); |
| } |
| |
| /*! |
| Sends \a event to \a receiver: \a {receiver}->event(\a event). |
| Returns the value that is returned from the receiver's event |
| handler. Note that this function is called for all events sent to |
| any object in any thread. |
| |
| For certain types of events (e.g. mouse and key events), |
| the event will be propagated to the receiver's parent and so on up to |
| the top-level object if the receiver is not interested in the event |
| (i.e., it returns \c false). |
| |
| There are five different ways that events can be processed; |
| reimplementing this virtual function is just one of them. All five |
| approaches are listed below: |
| \list 1 |
| \li Reimplementing \l {QWidget::}{paintEvent()}, \l {QWidget::}{mousePressEvent()} and so |
| on. This is the most common, easiest, and least powerful way. |
| |
| \li Reimplementing this function. This is very powerful, providing |
| complete control; but only one subclass can be active at a time. |
| |
| \li Installing an event filter on QCoreApplication::instance(). Such |
| an event filter is able to process all events for all widgets, so |
| it's just as powerful as reimplementing notify(); furthermore, it's |
| possible to have more than one application-global event filter. |
| Global event filters even see mouse events for |
| \l{QWidget::isEnabled()}{disabled widgets}. Note that application |
| event filters are only called for objects that live in the main |
| thread. |
| |
| \li Reimplementing QObject::event() (as QWidget does). If you do |
| this you get Tab key presses, and you get to see the events before |
| any widget-specific event filters. |
| |
| \li Installing an event filter on the object. Such an event filter gets all |
| the events, including Tab and Shift+Tab key press events, as long as they |
| do not change the focus widget. |
| \endlist |
| |
| \b{Future direction:} This function will not be called for objects that live |
| outside the main thread in Qt 6. Applications that need that functionality |
| should find other solutions for their event inspection needs in the meantime. |
| The change may be extended to the main thread, causing this function to be |
| deprecated. |
| |
| \warning If you override this function, you must ensure all threads that |
| process events stop doing so before your application object begins |
| destruction. This includes threads started by other libraries that you may be |
| using, but does not apply to Qt's own threads. |
| |
| \sa QObject::event(), installNativeEventFilter() |
| */ |
| |
| bool QCoreApplication::notify(QObject *receiver, QEvent *event) |
| { |
| // no events are delivered after ~QCoreApplication() has started |
| if (QCoreApplicationPrivate::is_app_closing) |
| return true; |
| return doNotify(receiver, event); |
| } |
| |
| static bool doNotify(QObject *receiver, QEvent *event) |
| { |
| if (receiver == 0) { // serious error |
| qWarning("QCoreApplication::notify: Unexpected null receiver"); |
| return true; |
| } |
| |
| #ifndef QT_NO_DEBUG |
| QCoreApplicationPrivate::checkReceiverThread(receiver); |
| #endif |
| |
| return receiver->isWidgetType() ? false : QCoreApplicationPrivate::notify_helper(receiver, event); |
| } |
| |
| bool QCoreApplicationPrivate::sendThroughApplicationEventFilters(QObject *receiver, QEvent *event) |
| { |
| // We can't access the application event filters outside of the main thread (race conditions) |
| Q_ASSERT(receiver->d_func()->threadData->thread.loadAcquire() == mainThread()); |
| |
| if (extraData) { |
| // application event filters are only called for objects in the GUI thread |
| for (int i = 0; i < extraData->eventFilters.size(); ++i) { |
| QObject *obj = extraData->eventFilters.at(i); |
| if (!obj) |
| continue; |
| if (obj->d_func()->threadData != threadData) { |
| qWarning("QCoreApplication: Application event filter cannot be in a different thread."); |
| continue; |
| } |
| if (obj->eventFilter(receiver, event)) |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject *receiver, QEvent *event) |
| { |
| if (receiver != QCoreApplication::instance() && receiver->d_func()->extraData) { |
| for (int i = 0; i < receiver->d_func()->extraData->eventFilters.size(); ++i) { |
| QObject *obj = receiver->d_func()->extraData->eventFilters.at(i); |
| if (!obj) |
| continue; |
| if (obj->d_func()->threadData != receiver->d_func()->threadData) { |
| qWarning("QCoreApplication: Object event filter cannot be in a different thread."); |
| continue; |
| } |
| if (obj->eventFilter(receiver, event)) |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /*! |
| \internal |
| |
| Helper function called by QCoreApplicationPrivate::notify() and qapplication.cpp |
| */ |
| bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event) |
| { |
| // Note: when adjusting the tracepoints in here |
| // consider adjusting QApplicationPrivate::notify_helper too. |
| Q_TRACE(QCoreApplication_notify_entry, receiver, event, event->type()); |
| bool consumed = false; |
| bool filtered = false; |
| Q_TRACE_EXIT(QCoreApplication_notify_exit, consumed, filtered); |
| |
| // send to all application event filters (only does anything in the main thread) |
| if (QCoreApplication::self |
| && receiver->d_func()->threadData->thread.loadAcquire() == mainThread() |
| && QCoreApplication::self->d_func()->sendThroughApplicationEventFilters(receiver, event)) { |
| filtered = true; |
| return filtered; |
| } |
| // send to all receiver event filters |
| if (sendThroughObjectEventFilters(receiver, event)) { |
| filtered = true; |
| return filtered; |
| } |
| |
| // deliver the event |
| consumed = receiver->event(event); |
| return consumed; |
| } |
| |
| /*! |
| Returns \c true if an application object has not been created yet; |
| otherwise returns \c false. |
| |
| \sa closingDown() |
| */ |
| |
| bool QCoreApplication::startingUp() |
| { |
| return !QCoreApplicationPrivate::is_app_running; |
| } |
| |
| /*! |
| Returns \c true if the application objects are being destroyed; |
| otherwise returns \c false. |
| |
| \sa startingUp() |
| */ |
| |
| bool QCoreApplication::closingDown() |
| { |
| return QCoreApplicationPrivate::is_app_closing; |
| } |
| |
| |
| /*! |
| Processes all pending events for the calling thread according to |
| the specified \a flags until there are no more events to process. |
| |
| You can call this function occasionally when your program is busy |
| performing a long operation (e.g. copying a file). |
| |
| In the event that you are running a local loop which calls this function |
| continuously, without an event loop, the |
| \l{QEvent::DeferredDelete}{DeferredDelete} events will |
| not be processed. This can affect the behaviour of widgets, |
| e.g. QToolTip, that rely on \l{QEvent::DeferredDelete}{DeferredDelete} |
| events to function properly. An alternative would be to call |
| \l{QCoreApplication::sendPostedEvents()}{sendPostedEvents()} from |
| within that local loop. |
| |
| Calling this function processes events only for the calling thread, |
| and returns after all available events have been processed. Available |
| events are events queued before the function call. This means that |
| events that are posted while the function runs will be queued until |
| a later round of event processing. |
| |
| \threadsafe |
| |
| \sa exec(), QTimer, QEventLoop::processEvents(), flush(), sendPostedEvents() |
| */ |
| void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags) |
| { |
| QThreadData *data = QThreadData::current(); |
| if (!data->hasEventDispatcher()) |
| return; |
| data->eventDispatcher.loadRelaxed()->processEvents(flags); |
| } |
| |
| /*! |
| \overload processEvents() |
| |
| Processes pending events for the calling thread for \a ms |
| milliseconds or until there are no more events to process, |
| whichever is shorter. |
| |
| You can call this function occasionally when your program is busy |
| doing a long operation (e.g. copying a file). |
| |
| Calling this function processes events only for the calling thread. |
| |
| \note Unlike the \l{QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags)}{processEvents()} |
| overload, this function also processes events that are posted while the function runs. |
| |
| \threadsafe |
| |
| \sa exec(), QTimer, QEventLoop::processEvents() |
| */ |
| void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, int ms) |
| { |
| // ### Qt 6: consider splitting this method into a public and a private |
| // one, so that a user-invoked processEvents can be detected |
| // and handled properly. |
| QThreadData *data = QThreadData::current(); |
| if (!data->hasEventDispatcher()) |
| return; |
| QElapsedTimer start; |
| start.start(); |
| while (data->eventDispatcher.loadRelaxed()->processEvents(flags & ~QEventLoop::WaitForMoreEvents)) { |
| if (start.elapsed() > ms) |
| break; |
| } |
| } |
| |
| /***************************************************************************** |
| Main event loop wrappers |
| *****************************************************************************/ |
| |
| /*! |
| Enters the main event loop and waits until exit() is called. Returns |
| the value that was passed to exit() (which is 0 if exit() is called via |
| quit()). |
| |
| It is necessary to call this function to start event handling. The |
| main event loop receives events from the window system and |
| dispatches these to the application widgets. |
| |
| To make your application perform idle processing (by executing a |
| special function whenever there are no pending events), use a |
| QTimer with 0 timeout. More advanced idle processing schemes can |
| be achieved using processEvents(). |
| |
| We recommend that you connect clean-up code to the |
| \l{QCoreApplication::}{aboutToQuit()} signal, instead of putting it in |
| your application's \c{main()} function because on some platforms the |
| exec() call may not return. For example, on Windows |
| when the user logs off, the system terminates the process after Qt |
| closes all top-level windows. Hence, there is no guarantee that the |
| application will have time to exit its event loop and execute code at |
| the end of the \c{main()} function after the exec() |
| call. |
| |
| \sa quit(), exit(), processEvents(), QApplication::exec() |
| */ |
| int QCoreApplication::exec() |
| { |
| if (!QCoreApplicationPrivate::checkInstance("exec")) |
| return -1; |
| |
| QThreadData *threadData = self->d_func()->threadData; |
| if (threadData != QThreadData::current()) { |
| qWarning("%s::exec: Must be called from the main thread", self->metaObject()->className()); |
| return -1; |
| } |
| if (!threadData->eventLoops.isEmpty()) { |
| qWarning("QCoreApplication::exec: The event loop is already running"); |
| return -1; |
| } |
| |
| threadData->quitNow = false; |
| QEventLoop eventLoop; |
| self->d_func()->in_exec = true; |
| self->d_func()->aboutToQuitEmitted = false; |
| int returnCode = eventLoop.exec(); |
| threadData->quitNow = false; |
| |
| if (self) |
| self->d_func()->execCleanup(); |
| |
| return returnCode; |
| } |
| |
| |
| // Cleanup after eventLoop is done executing in QCoreApplication::exec(). |
| // This is for use cases in which QCoreApplication is instantiated by a |
| // library and not by an application executable, for example, Active X |
| // servers. |
| |
| void QCoreApplicationPrivate::execCleanup() |
| { |
| threadData->quitNow = false; |
| in_exec = false; |
| if (!aboutToQuitEmitted) |
| emit q_func()->aboutToQuit(QCoreApplication::QPrivateSignal()); |
| aboutToQuitEmitted = true; |
| QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); |
| } |
| |
| |
| /*! |
| Tells the application to exit with a return code. |
| |
| After this function has been called, the application leaves the |
| main event loop and returns from the call to exec(). The exec() |
| function returns \a returnCode. If the event loop is not running, |
| this function does nothing. |
| |
| By convention, a \a returnCode of 0 means success, and any non-zero |
| value indicates an error. |
| |
| It's good practice to always connect signals to this slot using a |
| \l{Qt::}{QueuedConnection}. If a signal connected (non-queued) to this slot |
| is emitted before control enters the main event loop (such as before |
| "int main" calls \l{QCoreApplication::}{exec()}), the slot has no effect |
| and the application never exits. Using a queued connection ensures that the |
| slot will not be invoked until after control enters the main event loop. |
| |
| Note that unlike the C library function of the same name, this |
| function \e does return to the caller -- it is event processing that |
| stops. |
| |
| \sa quit(), exec() |
| */ |
| void QCoreApplication::exit(int returnCode) |
| { |
| if (!self) |
| return; |
| QThreadData *data = self->d_func()->threadData; |
| data->quitNow = true; |
| for (int i = 0; i < data->eventLoops.size(); ++i) { |
| QEventLoop *eventLoop = data->eventLoops.at(i); |
| eventLoop->exit(returnCode); |
| } |
| } |
| |
| /***************************************************************************** |
| QCoreApplication management of posted events |
| *****************************************************************************/ |
| |
| #ifndef QT_NO_QOBJECT |
| /*! |
| \fn bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event) |
| |
| Sends event \a event directly to receiver \a receiver, using the |
| notify() function. Returns the value that was returned from the |
| event handler. |
| |
| The event is \e not deleted when the event has been sent. The normal |
| approach is to create the event on the stack, for example: |
| |
| \snippet code/src_corelib_kernel_qcoreapplication.cpp 0 |
| |
| \sa postEvent(), notify() |
| */ |
| bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event) |
| { |
| Q_TRACE(QCoreApplication_sendEvent, receiver, event, event->type()); |
| |
| if (event) |
| event->spont = false; |
| return notifyInternal2(receiver, event); |
| } |
| |
| /*! |
| \internal |
| */ |
| bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event) |
| { |
| Q_TRACE(QCoreApplication_sendSpontaneousEvent, receiver, event, event->type()); |
| |
| if (event) |
| event->spont = true; |
| return notifyInternal2(receiver, event); |
| } |
| |
| #endif // QT_NO_QOBJECT |
| |
| /*! |
| \since 4.3 |
| |
| Adds the event \a event, with the object \a receiver as the |
| receiver of the event, to an event queue and returns immediately. |
| |
| The event must be allocated on the heap since the post event queue |
| will take ownership of the event and delete it once it has been |
| posted. It is \e {not safe} to access the event after |
| it has been posted. |
| |
| When control returns to the main event loop, all events that are |
| stored in the queue will be sent using the notify() function. |
| |
| Events are sorted in descending \a priority order, i.e. events |
| with a high \a priority are queued before events with a lower \a |
| priority. The \a priority can be any integer value, i.e. between |
| INT_MAX and INT_MIN, inclusive; see Qt::EventPriority for more |
| details. Events with equal \a priority will be processed in the |
| order posted. |
| |
| \threadsafe |
| |
| \sa sendEvent(), notify(), sendPostedEvents(), Qt::EventPriority |
| */ |
| void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority) |
| { |
| Q_TRACE_SCOPE(QCoreApplication_postEvent, receiver, event, event->type()); |
| |
| if (receiver == 0) { |
| qWarning("QCoreApplication::postEvent: Unexpected null receiver"); |
| delete event; |
| return; |
| } |
| |
| QThreadData * volatile * pdata = &receiver->d_func()->threadData; |
| QThreadData *data = *pdata; |
| if (!data) { |
| // posting during destruction? just delete the event to prevent a leak |
| delete event; |
| return; |
| } |
| |
| // lock the post event mutex |
| data->postEventList.mutex.lock(); |
| |
| // if object has moved to another thread, follow it |
| while (data != *pdata) { |
| data->postEventList.mutex.unlock(); |
| |
| data = *pdata; |
| if (!data) { |
| // posting during destruction? just delete the event to prevent a leak |
| delete event; |
| return; |
| } |
| |
| data->postEventList.mutex.lock(); |
| } |
| |
| QMutexUnlocker locker(&data->postEventList.mutex); |
| |
| // if this is one of the compressible events, do compression |
| if (receiver->d_func()->postedEvents |
| && self && self->compressEvent(event, receiver, &data->postEventList)) { |
| Q_TRACE(QCoreApplication_postEvent_event_compressed, receiver, event); |
| return; |
| } |
| |
| if (event->type() == QEvent::DeferredDelete) |
| receiver->d_ptr->deleteLaterCalled = true; |
| |
| if (event->type() == QEvent::DeferredDelete && data == QThreadData::current()) { |
| // remember the current running eventloop for DeferredDelete |
| // events posted in the receiver's thread. |
| |
| // Events sent by non-Qt event handlers (such as glib) may not |
| // have the scopeLevel set correctly. The scope level makes sure that |
| // code like this: |
| // foo->deleteLater(); |
| // qApp->processEvents(); // without passing QEvent::DeferredDelete |
| // will not cause "foo" to be deleted before returning to the event loop. |
| |
| // If the scope level is 0 while loopLevel != 0, we are called from a |
| // non-conformant code path, and our best guess is that the scope level |
| // should be 1. (Loop level 0 is special: it means that no event loops |
| // are running.) |
| int loopLevel = data->loopLevel; |
| int scopeLevel = data->scopeLevel; |
| if (scopeLevel == 0 && loopLevel != 0) |
| scopeLevel = 1; |
| static_cast<QDeferredDeleteEvent *>(event)->level = loopLevel + scopeLevel; |
| } |
| |
| // delete the event on exceptions to protect against memory leaks till the event is |
| // properly owned in the postEventList |
| QScopedPointer<QEvent> eventDeleter(event); |
| Q_TRACE(QCoreApplication_postEvent_event_posted, receiver, event, event->type()); |
| data->postEventList.addEvent(QPostEvent(receiver, event, priority)); |
| eventDeleter.take(); |
| event->posted = true; |
| ++receiver->d_func()->postedEvents; |
| data->canWait = false; |
| locker.unlock(); |
| |
| QAbstractEventDispatcher* dispatcher = data->eventDispatcher.loadAcquire(); |
| if (dispatcher) |
| dispatcher->wakeUp(); |
| } |
| |
| /*! |
| \internal |
| Returns \c true if \a event was compressed away (possibly deleted) and should not be added to the list. |
| */ |
| bool QCoreApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventList *postedEvents) |
| { |
| #ifdef Q_OS_WIN |
| Q_ASSERT(event); |
| Q_ASSERT(receiver); |
| Q_ASSERT(postedEvents); |
| |
| // compress posted timers to this object. |
| if (event->type() == QEvent::Timer && receiver->d_func()->postedEvents > 0) { |
| int timerId = ((QTimerEvent *) event)->timerId(); |
| for (int i=0; i<postedEvents->size(); ++i) { |
| const QPostEvent &e = postedEvents->at(i); |
| if (e.receiver == receiver && e.event && e.event->type() == QEvent::Timer |
| && ((QTimerEvent *) e.event)->timerId() == timerId) { |
| delete event; |
| return true; |
| } |
| } |
| return false; |
| } |
| #endif |
| |
| if (event->type() == QEvent::DeferredDelete) { |
| if (receiver->d_ptr->deleteLaterCalled) { |
| // there was a previous DeferredDelete event, so we can drop the new one |
| delete event; |
| return true; |
| } |
| // deleteLaterCalled is set to true in postedEvents when queueing the very first |
| // deferred deletion event. |
| return false; |
| } |
| |
| if (event->type() == QEvent::Quit && receiver->d_func()->postedEvents > 0) { |
| for (int i = 0; i < postedEvents->size(); ++i) { |
| const QPostEvent &cur = postedEvents->at(i); |
| if (cur.receiver != receiver |
| || cur.event == 0 |
| || cur.event->type() != event->type()) |
| continue; |
| // found an event for this receiver |
| delete event; |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| /*! |
| Immediately dispatches all events which have been previously queued |
| with QCoreApplication::postEvent() and which are for the object \a |
| receiver and have the event type \a event_type. |
| |
| Events from the window system are \e not dispatched by this |
| function, but by processEvents(). |
| |
| If \a receiver is \nullptr, the events of \a event_type are sent for |
| all objects. If \a event_type is 0, all the events are sent for |
| \a receiver. |
| |
| \note This method must be called from the thread in which its QObject |
| parameter, \a receiver, lives. |
| |
| \sa flush(), postEvent() |
| */ |
| void QCoreApplication::sendPostedEvents(QObject *receiver, int event_type) |
| { |
| // ### Qt 6: consider splitting this method into a public and a private |
| // one, so that a user-invoked sendPostedEvents can be detected |
| // and handled properly. |
| QThreadData *data = QThreadData::current(); |
| |
| QCoreApplicationPrivate::sendPostedEvents(receiver, event_type, data); |
| } |
| |
| void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type, |
| QThreadData *data) |
| { |
| if (event_type == -1) { |
| // we were called by an obsolete event dispatcher. |
| event_type = 0; |
| } |
| |
| if (receiver && receiver->d_func()->threadData != data) { |
| qWarning("QCoreApplication::sendPostedEvents: Cannot send " |
| "posted events for objects in another thread"); |
| return; |
| } |
| |
| ++data->postEventList.recursion; |
| |
| auto locker = qt_unique_lock(data->postEventList.mutex); |
| |
| // by default, we assume that the event dispatcher can go to sleep after |
| // processing all events. if any new events are posted while we send |
| // events, canWait will be set to false. |
| data->canWait = (data->postEventList.size() == 0); |
| |
| if (data->postEventList.size() == 0 || (receiver && !receiver->d_func()->postedEvents)) { |
| --data->postEventList.recursion; |
| return; |
| } |
| |
| data->canWait = true; |
| |
| // okay. here is the tricky loop. be careful about optimizing |
| // this, it looks the way it does for good reasons. |
| int startOffset = data->postEventList.startOffset; |
| int &i = (!event_type && !receiver) ? data->postEventList.startOffset : startOffset; |
| data->postEventList.insertionOffset = data->postEventList.size(); |
| |
| // Exception-safe cleaning up without the need for a try/catch block |
| struct CleanUp { |
| QObject *receiver; |
| int event_type; |
| QThreadData *data; |
| bool exceptionCaught; |
| |
| inline CleanUp(QObject *receiver, int event_type, QThreadData *data) : |
| receiver(receiver), event_type(event_type), data(data), exceptionCaught(true) |
| {} |
| inline ~CleanUp() |
| { |
| if (exceptionCaught) { |
| // since we were interrupted, we need another pass to make sure we clean everything up |
| data->canWait = false; |
| } |
| |
| --data->postEventList.recursion; |
| if (!data->postEventList.recursion && !data->canWait && data->hasEventDispatcher()) |
| data->eventDispatcher.loadRelaxed()->wakeUp(); |
| |
| // clear the global list, i.e. remove everything that was |
| // delivered. |
| if (!event_type && !receiver && data->postEventList.startOffset >= 0) { |
| const QPostEventList::iterator it = data->postEventList.begin(); |
| data->postEventList.erase(it, it + data->postEventList.startOffset); |
| data->postEventList.insertionOffset -= data->postEventList.startOffset; |
| Q_ASSERT(data->postEventList.insertionOffset >= 0); |
| data->postEventList.startOffset = 0; |
| } |
| } |
| }; |
| CleanUp cleanup(receiver, event_type, data); |
| |
| while (i < data->postEventList.size()) { |
| // avoid live-lock |
| if (i >= data->postEventList.insertionOffset) |
| break; |
| |
| const QPostEvent &pe = data->postEventList.at(i); |
| ++i; |
| |
| if (!pe.event) |
| continue; |
| if ((receiver && receiver != pe.receiver) || (event_type && event_type != pe.event->type())) { |
| data->canWait = false; |
| continue; |
| } |
| |
| if (pe.event->type() == QEvent::DeferredDelete) { |
| // DeferredDelete events are sent either |
| // 1) when the event loop that posted the event has returned; or |
| // 2) if explicitly requested (with QEvent::DeferredDelete) for |
| // events posted by the current event loop; or |
| // 3) if the event was posted before the outermost event loop. |
| |
| int eventLevel = static_cast<QDeferredDeleteEvent *>(pe.event)->loopLevel(); |
| int loopLevel = data->loopLevel + data->scopeLevel; |
| const bool allowDeferredDelete = |
| (eventLevel > loopLevel |
| || (!eventLevel && loopLevel > 0) |
| || (event_type == QEvent::DeferredDelete |
| && eventLevel == loopLevel)); |
| if (!allowDeferredDelete) { |
| // cannot send deferred delete |
| if (!event_type && !receiver) { |
| // we must copy it first; we want to re-post the event |
| // with the event pointer intact, but we can't delay |
| // nulling the event ptr until after re-posting, as |
| // addEvent may invalidate pe. |
| QPostEvent pe_copy = pe; |
| |
| // null out the event so if sendPostedEvents recurses, it |
| // will ignore this one, as it's been re-posted. |
| const_cast<QPostEvent &>(pe).event = 0; |
| |
| // re-post the copied event so it isn't lost |
| data->postEventList.addEvent(pe_copy); |
| } |
| continue; |
| } |
| } |
| |
| // first, we diddle the event so that we can deliver |
| // it, and that no one will try to touch it later. |
| pe.event->posted = false; |
| QEvent *e = pe.event; |
| QObject * r = pe.receiver; |
| |
| --r->d_func()->postedEvents; |
| Q_ASSERT(r->d_func()->postedEvents >= 0); |
| |
| // next, update the data structure so that we're ready |
| // for the next event. |
| const_cast<QPostEvent &>(pe).event = 0; |
| |
| locker.unlock(); |
| const auto relocker = qScopeGuard([&locker] { locker.lock(); }); |
| |
| QScopedPointer<QEvent> event_deleter(e); // will delete the event (with the mutex unlocked) |
| |
| // after all that work, it's time to deliver the event. |
| QCoreApplication::sendEvent(r, e); |
| |
| // careful when adding anything below this point - the |
| // sendEvent() call might invalidate any invariants this |
| // function depends on. |
| } |
| |
| cleanup.exceptionCaught = false; |
| } |
| |
| /*! |
| \since 4.3 |
| |
| Removes all events of the given \a eventType that were posted |
| using postEvent() for \a receiver. |
| |
| The events are \e not dispatched, instead they are removed from |
| the queue. You should never need to call this function. If you do |
| call it, be aware that killing events may cause \a receiver to |
| break one or more invariants. |
| |
| If \a receiver is \nullptr, the events of \a eventType are removed |
| for all objects. If \a eventType is 0, all the events are removed |
| for \a receiver. You should never call this function with \a |
| eventType of 0. |
| |
| \threadsafe |
| */ |
| |
| void QCoreApplication::removePostedEvents(QObject *receiver, int eventType) |
| { |
| QThreadData *data = receiver ? receiver->d_func()->threadData : QThreadData::current(); |
| auto locker = qt_unique_lock(data->postEventList.mutex); |
| |
| // the QObject destructor calls this function directly. this can |
| // happen while the event loop is in the middle of posting events, |
| // and when we get here, we may not have any more posted events |
| // for this object. |
| if (receiver && !receiver->d_func()->postedEvents) |
| return; |
| |
| //we will collect all the posted events for the QObject |
| //and we'll delete after the mutex was unlocked |
| QVarLengthArray<QEvent*> events; |
| int n = data->postEventList.size(); |
| int j = 0; |
| |
| for (int i = 0; i < n; ++i) { |
| const QPostEvent &pe = data->postEventList.at(i); |
| |
| if ((!receiver || pe.receiver == receiver) |
| && (pe.event && (eventType == 0 || pe.event->type() == eventType))) { |
| --pe.receiver->d_func()->postedEvents; |
| pe.event->posted = false; |
| events.append(pe.event); |
| const_cast<QPostEvent &>(pe).event = 0; |
| } else if (!data->postEventList.recursion) { |
| if (i != j) |
| qSwap(data->postEventList[i], data->postEventList[j]); |
| ++j; |
| } |
| } |
| |
| #ifdef QT_DEBUG |
| if (receiver && eventType == 0) { |
| Q_ASSERT(!receiver->d_func()->postedEvents); |
| } |
| #endif |
| |
| if (!data->postEventList.recursion) { |
| // truncate list |
| data->postEventList.erase(data->postEventList.begin() + j, data->postEventList.end()); |
| } |
| |
| locker.unlock(); |
| qDeleteAll(events); |
| } |
| |
| /*! |
| Removes \a event from the queue of posted events, and emits a |
| warning message if appropriate. |
| |
| \warning This function can be \e really slow. Avoid using it, if |
| possible. |
| |
| \threadsafe |
| */ |
| |
| void QCoreApplicationPrivate::removePostedEvent(QEvent * event) |
| { |
| if (!event || !event->posted) |
| return; |
| |
| QThreadData *data = QThreadData::current(); |
| |
| const auto locker = qt_scoped_lock(data->postEventList.mutex); |
| |
| if (data->postEventList.size() == 0) { |
| #if defined(QT_DEBUG) |
| qDebug("QCoreApplication::removePostedEvent: Internal error: %p %d is posted", |
| (void*)event, event->type()); |
| return; |
| #endif |
| } |
| |
| for (int i = 0; i < data->postEventList.size(); ++i) { |
| const QPostEvent & pe = data->postEventList.at(i); |
| if (pe.event == event) { |
| #ifndef QT_NO_DEBUG |
| qWarning("QCoreApplication::removePostedEvent: Event of type %d deleted while posted to %s %s", |
| event->type(), |
| pe.receiver->metaObject()->className(), |
| pe.receiver->objectName().toLocal8Bit().data()); |
| #endif |
| --pe.receiver->d_func()->postedEvents; |
| pe.event->posted = false; |
| delete pe.event; |
| const_cast<QPostEvent &>(pe).event = 0; |
| return; |
| } |
| } |
| } |
| |
| /*!\reimp |
| |
| */ |
| bool QCoreApplication::event(QEvent *e) |
| { |
| if (e->type() == QEvent::Quit) { |
| quit(); |
| return true; |
| } |
| return QObject::event(e); |
| } |
| |
| /*! \enum QCoreApplication::Encoding |
| \obsolete |
| |
| This enum type used to define the 8-bit encoding of character string |
| arguments to translate(). This enum is now obsolete and UTF-8 will be |
| used in all cases. |
| |
| \value UnicodeUTF8 UTF-8. |
| \omitvalue Latin1 |
| \omitvalue DefaultCodec \omit UTF-8. \endomit |
| \omitvalue CodecForTr |
| |
| \sa QObject::tr(), QString::fromUtf8() |
| */ |
| |
| void QCoreApplicationPrivate::ref() |
| { |
| quitLockRef.ref(); |
| } |
| |
| void QCoreApplicationPrivate::deref() |
| { |
| if (!quitLockRef.deref()) |
| maybeQuit(); |
| } |
| |
| void QCoreApplicationPrivate::maybeQuit() |
| { |
| if (quitLockRef.loadRelaxed() == 0 && in_exec && quitLockRefEnabled && shouldQuit()) |
| QCoreApplication::postEvent(QCoreApplication::instance(), new QEvent(QEvent::Quit)); |
| } |
| |
| /*! |
| Tells the application to exit with return code 0 (success). |
| Equivalent to calling QCoreApplication::exit(0). |
| |
| It's common to connect the QGuiApplication::lastWindowClosed() signal |
| to quit(), and you also often connect e.g. QAbstractButton::clicked() or |
| signals in QAction, QMenu, or QMenuBar to it. |
| |
| It's good practice to always connect signals to this slot using a |
| \l{Qt::}{QueuedConnection}. If a signal connected (non-queued) to this slot |
| is emitted before control enters the main event loop (such as before |
| "int main" calls \l{QCoreApplication::}{exec()}), the slot has no effect |
| and the application never exits. Using a queued connection ensures that the |
| slot will not be invoked until after control enters the main event loop. |
| |
| Example: |
| |
| \snippet code/src_corelib_kernel_qcoreapplication.cpp 1 |
| |
| \sa exit(), aboutToQuit(), QGuiApplication::lastWindowClosed() |
| */ |
| |
| void QCoreApplication::quit() |
| { |
| exit(0); |
| } |
| |
| /*! |
| \fn void QCoreApplication::aboutToQuit() |
| |
| This signal is emitted when the application is about to quit the |
| main event loop, e.g. when the event loop level drops to zero. |
| This may happen either after a call to quit() from inside the |
| application or when the user shuts down the entire desktop session. |
| |
| The signal is particularly useful if your application has to do some |
| last-second cleanup. Note that no user interaction is possible in |
| this state. |
| |
| \sa quit() |
| */ |
| |
| #endif // QT_NO_QOBJECT |
| |
| #ifndef QT_NO_TRANSLATION |
| /*! |
| Adds the translation file \a translationFile to the list of |
| translation files to be used for translations. |
| |
| Multiple translation files can be installed. Translations are |
| searched for in the reverse order in which they were installed, |
| so the most recently installed translation file is searched first |
| and the first translation file installed is searched last. |
| The search stops as soon as a translation containing a matching |
| string is found. |
| |
| Installing or removing a QTranslator, or changing an installed QTranslator |
| generates a \l{QEvent::LanguageChange}{LanguageChange} event for the |
| QCoreApplication instance. A QApplication instance will propagate the event |
| to all toplevel widgets, where a reimplementation of changeEvent can |
| re-translate the user interface by passing user-visible strings via the |
| tr() function to the respective property setters. User-interface classes |
| generated by Qt Designer provide a \c retranslateUi() function that can be |
| called. |
| |
| The function returns \c true on success and false on failure. |
| |
| \sa removeTranslator(), translate(), QTranslator::load(), {Dynamic Translation} |
| */ |
| |
| bool QCoreApplication::installTranslator(QTranslator *translationFile) |
| { |
| if (!translationFile) |
| return false; |
| |
| if (!QCoreApplicationPrivate::checkInstance("installTranslator")) |
| return false; |
| QCoreApplicationPrivate *d = self->d_func(); |
| { |
| QWriteLocker locker(&d->translateMutex); |
| d->translators.prepend(translationFile); |
| } |
| |
| #ifndef QT_NO_TRANSLATION_BUILDER |
| if (translationFile->isEmpty()) |
| return false; |
| #endif |
| |
| #ifndef QT_NO_QOBJECT |
| QEvent ev(QEvent::LanguageChange); |
| QCoreApplication::sendEvent(self, &ev); |
| #endif |
| |
| return true; |
| } |
| |
| /*! |
| Removes the translation file \a translationFile from the list of |
| translation files used by this application. (It does not delete the |
| translation file from the file system.) |
| |
| The function returns \c true on success and false on failure. |
| |
| \sa installTranslator(), translate(), QObject::tr() |
| */ |
| |
| bool QCoreApplication::removeTranslator(QTranslator *translationFile) |
| { |
| if (!translationFile) |
| return false; |
| if (!QCoreApplicationPrivate::checkInstance("removeTranslator")) |
| return false; |
| QCoreApplicationPrivate *d = self->d_func(); |
| QWriteLocker locker(&d->translateMutex); |
| if (d->translators.removeAll(translationFile)) { |
| #ifndef QT_NO_QOBJECT |
| locker.unlock(); |
| if (!self->closingDown()) { |
| QEvent ev(QEvent::LanguageChange); |
| QCoreApplication::sendEvent(self, &ev); |
| } |
| #endif |
| return true; |
| } |
| return false; |
| } |
| |
| static void replacePercentN(QString *result, int n) |
| { |
| if (n >= 0) { |
| int percentPos = 0; |
| int len = 0; |
| while ((percentPos = result->indexOf(QLatin1Char('%'), percentPos + len)) != -1) { |
| len = 1; |
| if (percentPos + len == result->length()) |
| break; |
| QString fmt; |
| if (result->at(percentPos + len) == QLatin1Char('L')) { |
| ++len; |
| if (percentPos + len == result->length()) |
| break; |
| fmt = QLatin1String("%L1"); |
| } else { |
| fmt = QLatin1String("%1"); |
| } |
| if (result->at(percentPos + len) == QLatin1Char('n')) { |
| fmt = fmt.arg(n); |
| ++len; |
| result->replace(percentPos, len, fmt); |
| len = fmt.length(); |
| } |
| } |
| } |
| } |
| |
| /*! |
| \threadsafe |
| |
| Returns the translation text for \a sourceText, by querying the |
| installed translation files. The translation files are searched |
| from the most recently installed file back to the first |
| installed file. |
| |
| QObject::tr() provides this functionality more conveniently. |
| |
| \a context is typically a class name (e.g., "MyDialog") and \a |
| sourceText is either English text or a short identifying text. |
| |
| \a disambiguation is an identifying string, for when the same \a |
| sourceText is used in different roles within the same context. By |
| default, it is \nullptr. |
| |
| See the \l QTranslator and \l QObject::tr() documentation for |
| more information about contexts, disambiguations and comments. |
| |
| \a n is used in conjunction with \c %n to support plural forms. |
| See QObject::tr() for details. |
| |
| If none of the translation files contain a translation for \a |
| sourceText in \a context, this function returns a QString |
| equivalent of \a sourceText. |
| |
| This function is not virtual. You can use alternative translation |
| techniques by subclassing \l QTranslator. |
| |
| \sa QObject::tr(), installTranslator(), removeTranslator(), translate() |
| */ |
| QString QCoreApplication::translate(const char *context, const char *sourceText, |
| const char *disambiguation, int n) |
| { |
| QString result; |
| |
| if (!sourceText) |
| return result; |
| |
| if (self) { |
| QCoreApplicationPrivate *d = self->d_func(); |
| QReadLocker locker(&d->translateMutex); |
| if (!d->translators.isEmpty()) { |
| QList<QTranslator*>::ConstIterator it; |
| QTranslator *translationFile; |
| for (it = d->translators.constBegin(); it != d->translators.constEnd(); ++it) { |
| translationFile = *it; |
| result = translationFile->translate(context, sourceText, disambiguation, n); |
| if (!result.isNull()) |
| break; |
| } |
| } |
| } |
| |
| if (result.isNull()) |
| result = QString::fromUtf8(sourceText); |
| |
| replacePercentN(&result, n); |
| return result; |
| } |
| |
| /*! \fn static QString QCoreApplication::translate(const char *context, const char *key, const char *disambiguation, Encoding encoding, int n = -1) |
| |
| \obsolete |
| */ |
| |
| // Declared in qglobal.h |
| QString qtTrId(const char *id, int n) |
| { |
| return QCoreApplication::translate(0, id, 0, n); |
| } |
| |
| bool QCoreApplicationPrivate::isTranslatorInstalled(QTranslator *translator) |
| { |
| if (!QCoreApplication::self) |
| return false; |
| QCoreApplicationPrivate *d = QCoreApplication::self->d_func(); |
| QReadLocker locker(&d->translateMutex); |
| return d->translators.contains(translator); |
| } |
| |
| #else |
| |
| QString QCoreApplication::translate(const char *context, const char *sourceText, |
| const char *disambiguation, int n) |
| { |
| Q_UNUSED(context) |
| Q_UNUSED(disambiguation) |
| QString ret = QString::fromUtf8(sourceText); |
| if (n >= 0) |
| ret.replace(QLatin1String("%n"), QString::number(n)); |
| return ret; |
| } |
| |
| #endif //QT_NO_TRANSLATION |
| |
| // Makes it possible to point QCoreApplication to a custom location to ensure |
| // the directory is added to the patch, and qt.conf and deployed plugins are |
| // found from there. This is for use cases in which QGuiApplication is |
| // instantiated by a library and not by an application executable, for example, |
| // Active X servers. |
| |
| void QCoreApplicationPrivate::setApplicationFilePath(const QString &path) |
| { |
| if (QCoreApplicationPrivate::cachedApplicationFilePath) |
| *QCoreApplicationPrivate::cachedApplicationFilePath = path; |
| else |
| QCoreApplicationPrivate::cachedApplicationFilePath = new QString(path); |
| } |
| |
| /*! |
| Returns the directory that contains the application executable. |
| |
| For example, if you have installed Qt in the \c{C:\Qt} |
| directory, and you run the \c{regexp} example, this function will |
| return "C:/Qt/examples/tools/regexp". |
| |
| On \macos and iOS this will point to the directory actually containing |
| the executable, which may be inside an application bundle (if the |
| application is bundled). |
| |
| \warning On Linux, this function will try to get the path from the |
| \c {/proc} file system. If that fails, it assumes that \c |
| {argv[0]} contains the absolute file name of the executable. The |
| function also assumes that the current directory has not been |
| changed by the application. |
| |
| \sa applicationFilePath() |
| */ |
| QString QCoreApplication::applicationDirPath() |
| { |
| if (!self) { |
| qWarning("QCoreApplication::applicationDirPath: Please instantiate the QApplication object first"); |
| return QString(); |
| } |
| |
| QCoreApplicationPrivate *d = self->d_func(); |
| if (d->cachedApplicationDirPath.isNull()) |
| d->cachedApplicationDirPath = QFileInfo(applicationFilePath()).path(); |
| return d->cachedApplicationDirPath; |
| } |
| |
| /*! |
| Returns the file path of the application executable. |
| |
| For example, if you have installed Qt in the \c{/usr/local/qt} |
| directory, and you run the \c{regexp} example, this function will |
| return "/usr/local/qt/examples/tools/regexp/regexp". |
| |
| \warning On Linux, this function will try to get the path from the |
| \c {/proc} file system. If that fails, it assumes that \c |
| {argv[0]} contains the absolute file name of the executable. The |
| function also assumes that the current directory has not been |
| changed by the application. |
| |
| \sa applicationDirPath() |
| */ |
| QString QCoreApplication::applicationFilePath() |
| { |
| if (!self) { |
| qWarning("QCoreApplication::applicationFilePath: Please instantiate the QApplication object first"); |
| return QString(); |
| } |
| |
| QCoreApplicationPrivate *d = self->d_func(); |
| |
| if (d->argc) { |
| static QByteArray procName = QByteArray(d->argv[0]); |
| if (procName != d->argv[0]) { |
| // clear the cache if the procname changes, so we reprocess it. |
| QCoreApplicationPrivate::clearApplicationFilePath(); |
| procName = QByteArray(d->argv[0]); |
| } |
| } |
| |
| if (QCoreApplicationPrivate::cachedApplicationFilePath) |
| return *QCoreApplicationPrivate::cachedApplicationFilePath; |
| |
| #if defined(Q_OS_WIN) |
| QCoreApplicationPrivate::setApplicationFilePath(QFileInfo(qAppFileName()).filePath()); |
| return *QCoreApplicationPrivate::cachedApplicationFilePath; |
| #elif defined(Q_OS_MAC) |
| QString qAppFileName_str = qAppFileName(); |
| if(!qAppFileName_str.isEmpty()) { |
| QFileInfo fi(qAppFileName_str); |
| if (fi.exists()) { |
| QCoreApplicationPrivate::setApplicationFilePath(fi.canonicalFilePath()); |
| return *QCoreApplicationPrivate::cachedApplicationFilePath; |
| } |
| } |
| #endif |
| #if defined( Q_OS_UNIX ) |
| # if defined(Q_OS_LINUX) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_EMBEDDED)) |
| // Try looking for a /proc/<pid>/exe symlink first which points to |
| // the absolute path of the executable |
| QFileInfo pfi(QString::fromLatin1("/proc/%1/exe").arg(getpid())); |
| if (pfi.exists() && pfi.isSymLink()) { |
| QCoreApplicationPrivate::setApplicationFilePath(pfi.canonicalFilePath()); |
| return *QCoreApplicationPrivate::cachedApplicationFilePath; |
| } |
| # endif |
| if (!arguments().isEmpty()) { |
| QString argv0 = QFile::decodeName(arguments().at(0).toLocal8Bit()); |
| QString absPath; |
| |
| if (!argv0.isEmpty() && argv0.at(0) == QLatin1Char('/')) { |
| /* |
| If argv0 starts with a slash, it is already an absolute |
| file path. |
| */ |
| absPath = argv0; |
| } else if (argv0.contains(QLatin1Char('/'))) { |
| /* |
| If argv0 contains one or more slashes, it is a file path |
| relative to the current directory. |
| */ |
| absPath = QDir::current().absoluteFilePath(argv0); |
| } else { |
| /* |
| Otherwise, the file path has to be determined using the |
| PATH environment variable. |
| */ |
| absPath = QStandardPaths::findExecutable(argv0); |
| } |
| |
| absPath = QDir::cleanPath(absPath); |
| |
| QFileInfo fi(absPath); |
| if (fi.exists()) { |
| QCoreApplicationPrivate::setApplicationFilePath(fi.canonicalFilePath()); |
| return *QCoreApplicationPrivate::cachedApplicationFilePath; |
| } |
| } |
| |
| #endif |
| return QString(); |
| } |
| |
| /*! |
| \since 4.4 |
| |
| Returns the current process ID for the application. |
| */ |
| qint64 QCoreApplication::applicationPid() |
| { |
| #if defined(Q_OS_WIN) |
| return GetCurrentProcessId(); |
| #elif defined(Q_OS_VXWORKS) |
| return (pid_t) taskIdCurrent; |
| #else |
| return getpid(); |
| #endif |
| } |
| |
| /*! |
| \since 4.1 |
| |
| Returns the list of command-line arguments. |
| |
| Usually arguments().at(0) is the program name, arguments().at(1) |
| is the first argument, and arguments().last() is the last |
| argument. See the note below about Windows. |
| |
| Calling this function is slow - you should store the result in a variable |
| when parsing the command line. |
| |
| \warning On Unix, this list is built from the argc and argv parameters passed |
| to the constructor in the main() function. The string-data in argv is |
| interpreted using QString::fromLocal8Bit(); hence it is not possible to |
| pass, for example, Japanese command line arguments on a system that runs in a |
| Latin1 locale. Most modern Unix systems do not have this limitation, as they are |
| Unicode-based. |
| |
| On Windows, the list is built from the argc and argv parameters only if |
| modified argv/argc parameters are passed to the constructor. In that case, |
| encoding problems might occur. |
| |
| Otherwise, the arguments() are constructed from the return value of |
| \l{http://msdn2.microsoft.com/en-us/library/ms683156(VS.85).aspx}{GetCommandLine()}. |
| As a result of this, the string given by arguments().at(0) might not be |
| the program name on Windows, depending on how the application was started. |
| |
| \sa applicationFilePath(), QCommandLineParser |
| */ |
| |
| QStringList QCoreApplication::arguments() |
| { |
| QStringList list; |
| |
| if (!self) { |
| qWarning("QCoreApplication::arguments: Please instantiate the QApplication object first"); |
| return list; |
| } |
| const int ac = self->d_func()->argc; |
| char ** const av = self->d_func()->argv; |
| list.reserve(ac); |
| |
| #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) |
| // On Windows, it is possible to pass Unicode arguments on |
| // the command line. To restore those, we split the command line |
| // and filter out arguments that were deleted by derived application |
| // classes by index. |
| QString cmdline = QString::fromWCharArray(GetCommandLine()); |
| |
| const QCoreApplicationPrivate *d = self->d_func(); |
| if (d->origArgv) { |
| const QStringList allArguments = qWinCmdArgs(cmdline); |
| Q_ASSERT(allArguments.size() == d->origArgc); |
| for (int i = 0; i < d->origArgc; ++i) { |
| if (contains(ac, av, d->origArgv[i])) |
| list.append(allArguments.at(i)); |
| } |
| return list; |
| } // Fall back to rebuilding from argv/argc when a modified argv was passed. |
| #endif // defined(Q_OS_WIN) && !defined(Q_OS_WINRT) |
| |
| for (int a = 0; a < ac; ++a) { |
| list << QString::fromLocal8Bit(av[a]); |
| } |
| |
| return list; |
| } |
| |
| /*! |
| \property QCoreApplication::organizationName |
| \brief the name of the organization that wrote this application |
| |
| The value is used by the QSettings class when it is constructed |
| using the empty constructor. This saves having to repeat this |
| information each time a QSettings object is created. |
| |
| On Mac, QSettings uses \l {QCoreApplication::}{organizationDomain()} as the organization |
| if it's not an empty string; otherwise it uses |
| organizationName(). On all other platforms, QSettings uses |
| organizationName() as the organization. |
| |
| \sa organizationDomain, applicationName |
| */ |
| |
| /*! |
| \fn void QCoreApplication::organizationNameChanged() |
| \internal |
| |
| While not useful from C++ due to how organizationName is normally set once on |
| startup, this is still needed for QML so that bindings are reevaluated after |
| that initial change. |
| */ |
| void QCoreApplication::setOrganizationName(const QString &orgName) |
| { |
| if (coreappdata()->orgName == orgName) |
| return; |
| coreappdata()->orgName = orgName; |
| #ifndef QT_NO_QOBJECT |
| if (QCoreApplication::self) |
| emit QCoreApplication::self->organizationNameChanged(); |
| #endif |
| } |
| |
| QString QCoreApplication::organizationName() |
| { |
| return coreappdata()->orgName; |
| } |
| |
| /*! |
| \property QCoreApplication::organizationDomain |
| \brief the Internet domain of the organization that wrote this application |
| |
| The value is used by the QSettings class when it is constructed |
| using the empty constructor. This saves having to repeat this |
| information each time a QSettings object is created. |
| |
| On Mac, QSettings uses organizationDomain() as the organization |
| if it's not an empty string; otherwise it uses organizationName(). |
| On all other platforms, QSettings uses organizationName() as the |
| organization. |
| |
| \sa organizationName, applicationName, applicationVersion |
| */ |
| /*! |
| \fn void QCoreApplication::organizationDomainChanged() |
| \internal |
| |
| Primarily for QML, see organizationNameChanged. |
| */ |
| void QCoreApplication::setOrganizationDomain(const QString &orgDomain) |
| { |
| if (coreappdata()->orgDomain == orgDomain) |
| return; |
| coreappdata()->orgDomain = orgDomain; |
| #ifndef QT_NO_QOBJECT |
| if (QCoreApplication::self) |
| emit QCoreApplication::self->organizationDomainChanged(); |
| #endif |
| } |
| |
| QString QCoreApplication::organizationDomain() |
| { |
| return coreappdata()->orgDomain; |
| } |
| |
| /*! |
| \property QCoreApplication::applicationName |
| \brief the name of this application |
| |
| The value is used by the QSettings class when it is constructed |
| using the empty constructor. This saves having to repeat this |
| information each time a QSettings object is created. |
| |
| If not set, the application name defaults to the executable name (since 5.0). |
| |
| \sa organizationName, organizationDomain, applicationVersion, applicationFilePath() |
| */ |
| /*! |
| \fn void QCoreApplication::applicationNameChanged() |
| \internal |
| |
| Primarily for QML, see organizationNameChanged. |
| */ |
| void QCoreApplication::setApplicationName(const QString &application) |
| { |
| coreappdata()->applicationNameSet = !application.isEmpty(); |
| QString newAppName = application; |
| if (newAppName.isEmpty() && QCoreApplication::self) |
| newAppName = QCoreApplication::self->d_func()->appName(); |
| if (coreappdata()->application == newAppName) |
| return; |
| coreappdata()->application = newAppName; |
| #ifndef QT_NO_QOBJECT |
| if (QCoreApplication::self) |
| emit QCoreApplication::self->applicationNameChanged(); |
| #endif |
| } |
| |
| QString QCoreApplication::applicationName() |
| { |
| return coreappdata() ? coreappdata()->application : QString(); |
| } |
| |
| // Exported for QDesktopServices (Qt4 behavior compatibility) |
| Q_CORE_EXPORT QString qt_applicationName_noFallback() |
| { |
| return coreappdata()->applicationNameSet ? coreappdata()->application : QString(); |
| } |
| |
| /*! |
| \property QCoreApplication::applicationVersion |
| \since 4.4 |
| \brief the version of this application |
| |
| If not set, the application version defaults to a platform-specific value |
| determined from the main application executable or package (since Qt 5.9): |
| |
| \table |
| \header |
| \li Platform |
| \li Source |
| \row |
| \li Windows (classic desktop) |
| \li PRODUCTVERSION parameter of the VERSIONINFO resource |
| \row |
| \li Universal Windows Platform |
| \li version attribute of the application package manifest |
| \row |
| \li macOS, iOS, tvOS, watchOS |
| \li CFBundleVersion property of the information property list |
| \row |
| \li Android |
| \li android:versionName property of the AndroidManifest.xml manifest element |
| \endtable |
| |
| On other platforms, the default is the empty string. |
| |
| \sa applicationName, organizationName, organizationDomain |
| */ |
| /*! |
| \fn void QCoreApplication::applicationVersionChanged() |
| \internal |
| |
| Primarily for QML, see organizationNameChanged. |
| */ |
| void QCoreApplication::setApplicationVersion(const QString &version) |
| { |
| coreappdata()->applicationVersionSet = !version.isEmpty(); |
| QString newVersion = version; |
| if (newVersion.isEmpty() && QCoreApplication::self) |
| newVersion = QCoreApplication::self->d_func()->appVersion(); |
| if (coreappdata()->applicationVersion == newVersion) |
| return; |
| coreappdata()->applicationVersion = newVersion; |
| #ifndef QT_NO_QOBJECT |
| if (QCoreApplication::self) |
| emit QCoreApplication::self->applicationVersionChanged(); |
| #endif |
| } |
| |
| QString QCoreApplication::applicationVersion() |
| { |
| return coreappdata() ? coreappdata()->applicationVersion : QString(); |
| } |
| |
| #if QT_CONFIG(library) |
| |
| Q_GLOBAL_STATIC(QRecursiveMutex, libraryPathMutex) |
| |
| /*! |
| Returns a list of paths that the application will search when |
| dynamically loading libraries. |
| |
| The return value of this function may change when a QCoreApplication |
| is created. It is not recommended to call it before creating a |
| QCoreApplication. The directory of the application executable (\b not |
| the working directory) is part of the list if it is known. In order |
| to make it known a QCoreApplication has to be constructed as it will |
| use \c {argv[0]} to find it. |
| |
| Qt provides default library paths, but they can also be set using |
| a \l{Using qt.conf}{qt.conf} file. Paths specified in this file |
| will override default values. Note that if the qt.conf file is in |
| the directory of the application executable, it may not be found |
| until a QCoreApplication is created. If it is not found when calling |
| this function, the default library paths will be used. |
| |
| The list will include the installation directory for plugins if |
| it exists (the default installation directory for plugins is \c |
| INSTALL/plugins, where \c INSTALL is the directory where Qt was |
| installed). The colon separated entries of the \c QT_PLUGIN_PATH |
| environment variable are always added. The plugin installation |
| directory (and its existence) may change when the directory of |
| the application executable becomes known. |
| |
| If you want to iterate over the list, you can use the \l foreach |
| pseudo-keyword: |
| |
| \snippet code/src_corelib_kernel_qcoreapplication.cpp 2 |
| |
| \sa setLibraryPaths(), addLibraryPath(), removeLibraryPath(), QLibrary, |
| {How to Create Qt Plugins} |
| */ |
| QStringList QCoreApplication::libraryPaths() |
| { |
| QMutexLocker locker(libraryPathMutex()); |
| return libraryPathsLocked(); |
| } |
| |
| /*! |
| \internal |
| */ |
| QStringList QCoreApplication::libraryPathsLocked() |
| { |
| if (coreappdata()->manual_libpaths) |
| return *(coreappdata()->manual_libpaths); |
| |
| if (!coreappdata()->app_libpaths) { |
| QStringList *app_libpaths = new QStringList; |
| coreappdata()->app_libpaths.reset(app_libpaths); |
| |
| auto setPathsFromEnv = [&](QString libPathEnv) { |
| if (!libPathEnv.isEmpty()) { |
| QStringList paths = libPathEnv.split(QDir::listSeparator(), QString::SkipEmptyParts); |
| for (QStringList::const_iterator it = paths.constBegin(); it != paths.constEnd(); ++it) { |
| QString canonicalPath = QDir(*it).canonicalPath(); |
| if (!canonicalPath.isEmpty() |
| && !app_libpaths->contains(canonicalPath)) { |
| app_libpaths->append(canonicalPath); |
| } |
| } |
| } |
| }; |
| setPathsFromEnv(qEnvironmentVariable("QT_PLUGIN_PATH")); |
| #ifdef Q_OS_ANDROID |
| setPathsFromEnv(qEnvironmentVariable("QT_BUNDLED_LIBS_PATH")); |
| #endif |
| #ifdef Q_OS_DARWIN |
| // Check the main bundle's PlugIns directory as this is a standard location for Apple OSes. |
| // Note that the QLibraryInfo::PluginsPath below will coincidentally be the same as this value |
| // but with a different casing, so it can't be relied upon when the underlying filesystem |
| // is case sensitive (and this is always the case on newer OSes like iOS). |
| if (CFBundleRef bundleRef = CFBundleGetMainBundle()) { |
| if (QCFType<CFURLRef> urlRef = CFBundleCopyBuiltInPlugInsURL(bundleRef)) { |
| if (QCFType<CFURLRef> absoluteUrlRef = CFURLCopyAbsoluteURL(urlRef)) { |
| if (QCFString path = CFURLCopyFileSystemPath(absoluteUrlRef, kCFURLPOSIXPathStyle)) { |
| if (QFile::exists(path)) { |
| path = QDir(path).canonicalPath(); |
| if (!app_libpaths->contains(path)) |
| app_libpaths->append(path); |
| } |
| } |
| } |
| } |
| } |
| #endif // Q_OS_DARWIN |
| |
| QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath); |
| if (QFile::exists(installPathPlugins)) { |
| // Make sure we convert from backslashes to slashes. |
| installPathPlugins = QDir(installPathPlugins).canonicalPath(); |
| if (!app_libpaths->contains(installPathPlugins)) |
| app_libpaths->append(installPathPlugins); |
| } |
| |
| // If QCoreApplication is not yet instantiated, |
| // make sure we add the application path when we construct the QCoreApplication |
| if (self) self->d_func()->appendApplicationPathToLibraryPaths(); |
| } |
| return *(coreappdata()->app_libpaths); |
| } |
| |
| |
| |
| /*! |
| |
| Sets the list of directories to search when loading libraries to |
| \a paths. All existing paths will be deleted and the path list |
| will consist of the paths given in \a paths. |
| |
| The library paths are reset to the default when an instance of |
| QCoreApplication is destructed. |
| |
| \sa libraryPaths(), addLibraryPath(), removeLibraryPath(), QLibrary |
| */ |
| void QCoreApplication::setLibraryPaths(const QStringList &paths) |
| { |
| QMutexLocker locker(libraryPathMutex()); |
| |
| // setLibraryPaths() is considered a "remove everything and then add some new ones" operation. |
| // When the application is constructed it should still amend the paths. So we keep the originals |
| // around, and even create them if they don't exist, yet. |
| if (!coreappdata()->app_libpaths) |
| libraryPathsLocked(); |
| |
| if (coreappdata()->manual_libpaths) |
| *(coreappdata()->manual_libpaths) = paths; |
| else |
| coreappdata()->manual_libpaths.reset(new QStringList(paths)); |
| |
| locker.unlock(); |
| QFactoryLoader::refreshAll(); |
| } |
| |
| /*! |
| Prepends \a path to the beginning of the library path list, ensuring that |
| it is searched for libraries first. If \a path is empty or already in the |
| path list, the path list is not changed. |
| |
| The default path list consists of a single entry, the installation |
| directory for plugins. The default installation directory for plugins |
| is \c INSTALL/plugins, where \c INSTALL is the directory where Qt was |
| installed. |
| |
| The library paths are reset to the default when an instance of |
| QCoreApplication is destructed. |
| |
| \sa removeLibraryPath(), libraryPaths(), setLibraryPaths() |
| */ |
| void QCoreApplication::addLibraryPath(const QString &path) |
| { |
| if (path.isEmpty()) |
| return; |
| |
| QString canonicalPath = QDir(path).canonicalPath(); |
| if (canonicalPath.isEmpty()) |
| return; |
| |
| QMutexLocker locker(libraryPathMutex()); |
| |
| QStringList *libpaths = coreappdata()->manual_libpaths.data(); |
| if (libpaths) { |
| if (libpaths->contains(canonicalPath)) |
| return; |
| } else { |
| // make sure that library paths are initialized |
| libraryPathsLocked(); |
| QStringList *app_libpaths = coreappdata()->app_libpaths.data(); |
| if (app_libpaths->contains(canonicalPath)) |
| return; |
| |
| coreappdata()->manual_libpaths.reset(libpaths = new QStringList(*app_libpaths)); |
| } |
| |
| libpaths->prepend(canonicalPath); |
| locker.unlock(); |
| QFactoryLoader::refreshAll(); |
| } |
| |
| /*! |
| Removes \a path from the library path list. If \a path is empty or not |
| in the path list, the list is not changed. |
| |
| The library paths are reset to the default when an instance of |
| QCoreApplication is destructed. |
| |
| \sa addLibraryPath(), libraryPaths(), setLibraryPaths() |
| */ |
| void QCoreApplication::removeLibraryPath(const QString &path) |
| { |
| if (path.isEmpty()) |
| return; |
| |
| QString canonicalPath = QDir(path).canonicalPath(); |
| if (canonicalPath.isEmpty()) |
| return; |
| |
| QMutexLocker locker(libraryPathMutex()); |
| |
| QStringList *libpaths = coreappdata()->manual_libpaths.data(); |
| if (libpaths) { |
| if (libpaths->removeAll(canonicalPath) == 0) |
| return; |
| } else { |
| // make sure that library paths is initialized |
| libraryPathsLocked(); |
| QStringList *app_libpaths = coreappdata()->app_libpaths.data(); |
| if (!app_libpaths->contains(canonicalPath)) |
| return; |
| |
| coreappdata()->manual_libpaths.reset(libpaths = new QStringList(*app_libpaths)); |
| libpaths->removeAll(canonicalPath); |
| } |
| |
| locker.unlock(); |
| QFactoryLoader::refreshAll(); |
| } |
| |
| #endif // QT_CONFIG(library) |
| |
| #ifndef QT_NO_QOBJECT |
| |
| /*! |
| Installs an event filter \a filterObj for all native events |
| received by the application in the main thread. |
| |
| The event filter \a filterObj receives events via its \l {QAbstractNativeEventFilter::}{nativeEventFilter()} |
| function, which is called for all native events received in the main thread. |
| |
| The QAbstractNativeEventFilter::nativeEventFilter() function should |
| return true if the event should be filtered, i.e. stopped. It should |
| return false to allow normal Qt processing to continue: the native |
| event can then be translated into a QEvent and handled by the standard |
| Qt \l{QEvent} {event} filtering, e.g. QObject::installEventFilter(). |
| |
| If multiple event filters are installed, the filter that was |
| installed last is activated first. |
| |
| \note The filter function set here receives native messages, |
| i.e. MSG or XCB event structs. |
| |
| \note Native event filters will be disabled in the application when the |
| Qt::AA_PluginApplication attribute is set. |
| |
| For maximum portability, you should always try to use QEvent |
| and QObject::installEventFilter() whenever possible. |
| |
| \sa QObject::installEventFilter() |
| |
| \since 5.0 |
| */ |
| void QCoreApplication::installNativeEventFilter(QAbstractNativeEventFilter *filterObj) |
| { |
| if (QCoreApplication::testAttribute(Qt::AA_PluginApplication)) { |
| qWarning("Native event filters are not applied when the Qt::AA_PluginApplication attribute is set"); |
| return; |
| } |
| |
| QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance(QCoreApplicationPrivate::theMainThread.loadAcquire()); |
| if (!filterObj || !eventDispatcher) |
| return; |
| eventDispatcher->installNativeEventFilter(filterObj); |
| } |
| |
| /*! |
| Removes an event \a filterObject from this object. The |
| request is ignored if such an event filter has not been installed. |
| |
| All event filters for this object are automatically removed when |
| this object is destroyed. |
| |
| It is always safe to remove an event filter, even during event |
| filter activation (i.e. from the nativeEventFilter() function). |
| |
| \sa installNativeEventFilter() |
| \since 5.0 |
| */ |
| void QCoreApplication::removeNativeEventFilter(QAbstractNativeEventFilter *filterObject) |
| { |
| QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance(); |
| if (!filterObject || !eventDispatcher) |
| return; |
| eventDispatcher->removeNativeEventFilter(filterObject); |
| } |
| |
| /*! |
| \deprecated |
| |
| This function returns \c true if there are pending events; otherwise |
| returns \c false. Pending events can be either from the window |
| system or posted events using postEvent(). |
| |
| \note this function is not thread-safe. It may only be called in the main |
| thread and only if there are no other threads running in the application |
| (including threads Qt starts for its own purposes). |
| |
| \sa QAbstractEventDispatcher::hasPendingEvents() |
| */ |
| #if QT_DEPRECATED_SINCE(5, 3) |
| bool QCoreApplication::hasPendingEvents() |
| { |
| QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance(); |
| if (eventDispatcher) |
| return eventDispatcher->hasPendingEvents(); |
| return false; |
| } |
| #endif |
| |
| /*! |
| Returns a pointer to the event dispatcher object for the main thread. If no |
| event dispatcher exists for the thread, this function returns \nullptr. |
| */ |
| QAbstractEventDispatcher *QCoreApplication::eventDispatcher() |
| { |
| if (QCoreApplicationPrivate::theMainThread.loadAcquire()) |
| return QCoreApplicationPrivate::theMainThread.loadRelaxed()->eventDispatcher(); |
| return 0; |
| } |
| |
| /*! |
| Sets the event dispatcher for the main thread to \a eventDispatcher. This |
| is only possible as long as there is no event dispatcher installed yet. That |
| is, before QCoreApplication has been instantiated. This method takes |
| ownership of the object. |
| */ |
| void QCoreApplication::setEventDispatcher(QAbstractEventDispatcher *eventDispatcher) |
| { |
| QThread *mainThread = QCoreApplicationPrivate::theMainThread.loadAcquire(); |
| if (!mainThread) |
| mainThread = QThread::currentThread(); // will also setup theMainThread |
| mainThread->setEventDispatcher(eventDispatcher); |
| } |
| |
| #endif // QT_NO_QOBJECT |
| |
| /*! |
| \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. |
| |
| \note This macro is not suitable for use in library code that is then |
| statically linked into an application since the function may not be called |
| at all due to being eliminated by the linker. |
| */ |
| |
| /*! |
| \fn void qAddPostRoutine(QtCleanUpFunction ptr) |
| \threadsafe |
| \relates QCoreApplication |
| |
| Adds a global routine that will be called from the QCoreApplication |
| destructor. This function is normally used to add cleanup routines |
| for program-wide functionality. |
| |
| The cleanup routines are called in the reverse order of their addition. |
| |
| The function specified by \a ptr should take no arguments and should |
| return nothing. For example: |
| |
| \snippet code/src_corelib_kernel_qcoreapplication.cpp 4 |
| |
| Note that for an application- or module-wide cleanup, qAddPostRoutine() |
| is often not suitable. For example, if the program is split into dynamically |
| loaded modules, the relevant module may be unloaded long before the |
| QCoreApplication destructor is called. In such cases, if using qAddPostRoutine() |
| is still desirable, qRemovePostRoutine() can be used to prevent a routine |
| from being called by the QCoreApplication destructor. For example, if that |
| routine was called before the module was unloaded. |
| |
| For modules and libraries, using a reference-counted |
| initialization manager or Qt's parent-child deletion mechanism may |
| be better. Here is an example of a private class that uses the |
| parent-child mechanism to call a cleanup function at the right |
| time: |
| |
| \snippet code/src_corelib_kernel_qcoreapplication.cpp 5 |
| |
| By selecting the right parent object, this can often be made to |
| clean up the module's data at the right moment. |
| |
| \note This function has been thread-safe since Qt 5.10. |
| |
| \sa qRemovePostRoutine() |
| */ |
| |
| /*! |
| \fn void qRemovePostRoutine(QtCleanUpFunction ptr) |
| \threadsafe |
| \relates QCoreApplication |
| \since 5.3 |
| |
| Removes the cleanup routine specified by \a ptr from the list of |
| routines called by the QCoreApplication destructor. The routine |
| must have been previously added to the list by a call to |
| qAddPostRoutine(), otherwise this function has no effect. |
| |
| \note This function has been thread-safe since Qt 5.10. |
| |
| \sa qAddPostRoutine() |
| */ |
| |
| /*! |
| \macro Q_DECLARE_TR_FUNCTIONS(context) |
| \relates QCoreApplication |
| |
| The Q_DECLARE_TR_FUNCTIONS() macro declares and implements two |
| translation functions, \c tr() and \c trUtf8(), with these |
| signatures: |
| |
| \snippet code/src_corelib_kernel_qcoreapplication.cpp 6 |
| |
| This macro is useful if you want to use QObject::tr() or |
| QObject::trUtf8() in classes that don't inherit from QObject. |
| |
| Q_DECLARE_TR_FUNCTIONS() must appear at the very top of the |
| class definition (before the first \c{public:} or \c{protected:}). |
| For example: |
| |
| \snippet code/src_corelib_kernel_qcoreapplication.cpp 7 |
| |
| The \a context parameter is normally the class name, but it can |
| be any text. |
| |
| \sa Q_OBJECT, QObject::tr(), QObject::trUtf8() |
| */ |
| |
| QT_END_NAMESPACE |
| |
| #ifndef QT_NO_QOBJECT |
| #include "moc_qcoreapplication.cpp" |
| #endif |