Revision control
++ // Copyright (C) 2021 The Qt Company Ltd.
++ // Copyright (C) 2021 Intel Corporation.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #include "qcoreapplication.h"
++ #include "qcoreapplication_p.h"
++
++ #ifndef QT_NO_QOBJECT
++ #include "qabstracteventdispatcher.h"
++ #include "qcoreevent.h"
++ #include "qcoreevent_p.h"
++ #include "qeventloop.h"
++ #endif
++ #include "qmetaobject.h"
++ #include <private/qproperty_p.h>
++ #include <qdatastream.h>
++ #include <qdebug.h>
++ #include <qdir.h>
++ #include <qfile.h>
++ #include <qfileinfo.h>
++ #include <private/qfilesystementry_p.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>
++ #if QT_CONFIG(future)
++ #include <QtCore/qpromise.h>
++ #endif
++ #include <private/qthread_p.h>
++ #if QT_CONFIG(thread)
++ #include <qthreadpool.h>
++ #include <private/qthreadpool_p.h>
++ #endif
++ #endif
++ #include <qlibraryinfo.h>
++ #include <qpointer.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>
++ #include <private/qnativeinterface_p.h>
++
++ #ifdef Q_OS_WASM
++ #include <private/qstdweb_p.h>
++ #endif
++
++ #if QT_CONFIG(permissions)
++ #include <private/qpermissions_p.h>
++ #endif
++
++ #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
++ # if !defined(Q_OS_WASM)
++ # include "qeventdispatcher_unix_p.h"
++ # endif
++ #endif
++ #ifdef Q_OS_WIN
++ #include "qeventdispatcher_win_p.h"
++ #endif
++ #endif // QT_NO_QOBJECT
++
++ #if defined(Q_OS_ANDROID)
++ #include <QtCore/qjniobject.h>
++ #endif
++
++ #if defined(Q_OS_HARMONY) && !defined(QT_BOOTSTRAPPED)
++ #include <QtCore/private/qcore_ohos_p.h>
++ #include <QtCore/private/qnapi_p.h>
++ #include <QtCore/private/qohosmemoizingjsthreadfetcher_p.h>
++ #endif
++
++ #ifdef Q_OS_DARWIN
++ # include "qcore_mac_p.h"
++ #endif
++
++ #include <stdlib.h>
++
++ #ifdef Q_OS_UNIX
++ # include <locale.h>
++ # ifndef Q_OS_INTEGRITY
++ # include <langinfo.h>
++ # endif
++ # include <unistd.h>
++ # include <sys/types.h>
++
++ # include "qcore_unix_p.h"
++ #endif
++
++ #if __has_include(<sys/auxv.h>) // Linux and FreeBSD
++ # include <sys/auxv.h>
++ #endif
++
++ #ifdef Q_OS_VXWORKS
++ # include <taskLib.h>
++ #endif
++
++ #ifdef Q_OS_WASM
++ #include <emscripten/val.h>
++ #endif
++
++ #ifdef QT_BOOTSTRAPPED
++ #include <private/qtrace_p.h>
++ #else
++ #include <qtcore_tracepoints_p.h>
++ #endif
++
++ #include <algorithm>
++ #include <memory>
++ #include <string>
++
++ #ifdef Q_OS_WIN
++ # include <qt_windows.h>
++ #endif
++
++ QT_BEGIN_NAMESPACE
++
++ using namespace Qt::StringLiterals;
++
++ Q_TRACE_PREFIX(qtcore,
++ "#include <qcoreevent.h>"
++ );
++ Q_TRACE_METADATA(qtcore, "ENUM { AUTO, RANGE User ... MaxUser } QEvent::Type;");
++ Q_TRACE_POINT(qtcore, QCoreApplication_postEvent_entry, QObject *receiver, QEvent *event, QEvent::Type type);
++ Q_TRACE_POINT(qtcore, QCoreApplication_postEvent_exit);
++ Q_TRACE_POINT(qtcore, QCoreApplication_postEvent_event_compressed, QObject *receiver, QEvent *event);
++ Q_TRACE_POINT(qtcore, QCoreApplication_postEvent_event_posted, QObject *receiver, QEvent *event, QEvent::Type type);
++ Q_TRACE_POINT(qtcore, QCoreApplication_sendEvent, QObject *receiver, QEvent *event, QEvent::Type type);
++ Q_TRACE_POINT(qtcore, QCoreApplication_sendSpontaneousEvent, QObject *receiver, QEvent *event, QEvent::Type type);
++ Q_TRACE_POINT(qtcore, QCoreApplication_notify_entry, QObject *receiver, QEvent *event, QEvent::Type type);
++ Q_TRACE_POINT(qtcore, QCoreApplication_notify_exit, bool consumed, bool filtered);
++
++ #if (defined(Q_OS_WIN) || defined(Q_OS_DARWIN)) && !defined(QT_BOOTSTRAPPED)
++ extern QString qAppFileName();
++ #endif
++
++ Q_CONSTINIT bool QCoreApplicationPrivate::setuidAllowed = false;
++
++ #if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
++ # warning "Audit remaining direct usages of this variable for memory ordering semantics"
++ Q_CONSTINIT QBasicAtomicPointer<QCoreApplication> QCoreApplication::self = nullptr;
++ #else
++ Q_CONSTINIT QCoreApplication *QCoreApplication::self = nullptr;
++ Q_CONSTINIT static QBasicAtomicPointer<QCoreApplication> g_self = nullptr;
++ # undef qApp
++ # define qApp g_self.loadRelaxed()
++
++ /*!
++ \internal
++
++ This function is a Qt 6 thread-safe (no data races) version of:
++ \code
++ QCoreApplication::instance() != nullptr
++ \endcode
++
++ We may remove it in Qt 7.0 because the above will be thread-safe.
++ */
++ bool QCoreApplication::instanceExists() noexcept
++ {
++ return qApp != nullptr;
++ }
++ #endif
++
++ #if !defined(Q_OS_WIN) || defined(QT_BOOTSTRAPPED)
++ #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;
++ }
++
++ #if defined(Q_OS_HARMONY) && !defined(QT_BOOTSTRAPPED)
++ static QOhosMemoizingJsThreadFetcher<QString> bundleVersionNameFetcher(
++ [](QOhosJsState &jsState) -> std::optional<QString> {
++ const auto flag = jsState.eval<QNapi::Number>(
++ "@ohos.bundle.bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION");
++ return QString::fromStdString(
++ jsState.eval<QNapi::String>(
++ "@ohos.bundle.bundleManager.getBundleInfoForSelfSync(*).versionName",
++ {flag}));
++ },
++ "BundleInfo.versionName");
++ #endif
++
++ QString QCoreApplicationPrivate::appVersion() const
++ {
++ QString applicationVersion;
++ #if defined(Q_OS_DARWIN)
++ applicationVersion = infoDictionaryStringProperty(QStringLiteral("CFBundleVersion"));
++ #elif defined(Q_OS_ANDROID) && !defined(QT_BOOTSTRAPPED)
++ QJniObject context(QNativeInterface::QAndroidApplication::context());
++ if (context.isValid()) {
++ QJniObject pm = context.callObjectMethod(
++ "getPackageManager", "()Landroid/content/pm/PackageManager;");
++ QJniObject pn = context.callObjectMethod<jstring>("getPackageName");
++ if (pm.isValid() && pn.isValid()) {
++ QJniObject packageInfo = pm.callObjectMethod(
++ "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;",
++ pn.object(), 0);
++ if (packageInfo.isValid()) {
++ QJniObject versionName = packageInfo.getObjectField(
++ "versionName", "Ljava/lang/String;");
++ if (versionName.isValid())
++ return versionName.toString();
++ }
++ }
++ }
++ #elif defined(Q_OS_HARMONY) && !defined(QT_BOOTSTRAPPED)
++ applicationVersion = bundleVersionNameFetcher.optValue().value_or(QString());
++ #endif
++ return applicationVersion;
++ }
++ #endif // !Q_OS_WIN || QT_BOOTSTRAPPED
++
++ bool QCoreApplicationPrivate::checkInstance(const char *function)
++ {
++ bool b = (qApp != 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
++ #ifdef QT_SHARED
++ Q_DECL_EXPORT_OVERRIDABLE
++ #endif
++ QT_MANGLE_NAMESPACE(qt_startup_hook)()
++ {
++ }
++
++ typedef QList<QtStartUpFunction> QStartUpFuncList;
++ Q_GLOBAL_STATIC(QStartUpFuncList, preRList)
++ typedef QList<QtCleanUpFunction> QVFuncList;
++ Q_GLOBAL_STATIC(QVFuncList, postRList)
++ Q_CONSTINIT static QBasicMutex globalRoutinesMutex;
++ Q_CONSTINIT static bool preRoutinesCalled = false;
++
++ /*!
++ \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 (preRoutinesCalled) {
++ Q_ASSERT(qApp);
++ 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()
++ {
++ // After will be allowed invoke QtStartUpFunction when calling qAddPreRoutine
++ preRoutinesCalled = true;
++
++ if (!preRList.exists())
++ return;
++
++ const QStartUpFuncList 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.
++ return *preRList;
++ }();
++
++ for (QtStartUpFunction f : list)
++ f();
++ }
++
++ 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 : std::as_const(list))
++ f();
++ }
++ }
++
++
++ #ifndef QT_NO_QOBJECT
++
++ // app starting up if false
++ Q_CONSTINIT bool QCoreApplicationPrivate::is_app_running = false;
++ // app closing down if true
++ Q_CONSTINIT bool QCoreApplicationPrivate::is_app_closing = false;
++
++ qsizetype qGlobalPostedEventsCount()
++ {
++ const QPostEventList &l = QThreadData::current()->postEventList;
++ return l.size() - l.startOffset;
++ }
++
++ Q_CONSTINIT QAbstractEventDispatcher *QCoreApplicationPrivate::eventDispatcher = nullptr;
++
++ #endif // QT_NO_QOBJECT
++
++ Q_CONSTINIT uint QCoreApplicationPrivate::attribs =
++ (1 << Qt::AA_SynthesizeMouseForUnhandledTouchEvents) |
++ (1 << Qt::AA_SynthesizeMouseForUnhandledTabletEvents);
++
++ struct QCoreApplicationData
++ {
++ QCoreApplicationData() noexcept {
++ applicationNameSet = false;
++ applicationVersionSet = false;
++ }
++
++ 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)
++ // QList does not have isNull()
++ bool libPathsInitialized() const noexcept
++ { return !app_libpaths.data_ptr().isNull(); }
++ bool libPathsManuallySet() const noexcept
++ { return !manual_libpaths.data_ptr().isNull(); }
++ QStringList app_libpaths;
++ QStringList manual_libpaths;
++ QRecursiveMutex libraryPathMutex; // protects this block
++ #endif
++
++ };
++
++ Q_GLOBAL_STATIC(QCoreApplicationData, coreappdata)
++
++ #ifndef QT_NO_QOBJECT
++ Q_CONSTINIT static bool quitLockEnabled = true;
++ #endif
++
++ #if defined(Q_OS_WIN)
++ // Check whether the command line arguments passed to QCoreApplication
++ // match those passed into main(), to see if the user has modified them
++ // before passing them on to us. We do this by comparing to the global
++ // __argv/__argc (MS extension). Deep comparison is required since
++ // argv/argc is rebuilt by our WinMain entrypoint.
++ 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
++
++ QCoreApplicationPrivate::QCoreApplicationPrivate(int &aargc, char **aargv)
++ : argc(aargc), argv(aargv)
++ {
++ static const char *const empty = "";
++ if (argc == 0 || argv == nullptr) {
++ argc = 0;
++ argv = const_cast<char **>(&empty);
++ }
++ #if defined(Q_OS_WIN)
++ if (!isArgvModified(argc, argv)) {
++ origArgc = argc;
++ origArgv = q20::make_unique_for_overwrite<char *[]>(argc);
++ std::copy(argv, argv + argc, origArgv.get());
++ }
++ #endif // Q_OS_WIN
++
++ #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
++
++ 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()
++ {
++ #ifndef QT_NO_QOBJECT
++ cleanupThreadData();
++ #endif
++ #if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
++ cleanupDebuggingConsole();
++ #endif
++ }
++
++ #ifndef QT_NO_QOBJECT
++
++ void QCoreApplicationPrivate::cleanupThreadData()
++ {
++ auto thisThreadData = threadData.loadRelaxed();
++
++ if (thisThreadData && !threadData_clean) {
++ #if QT_CONFIG(thread)
++ QThreadStoragePrivate::finish(&thisThreadData->tls);
++ #endif
++
++ // need to clear the state of the mainData, just in case a new QCoreApplication comes along.
++ thisThreadData->clearEvents();
++ thisThreadData->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()
++ {
++ }
++
++ Q_CONSTINIT QBasicAtomicPointer<QThread> QCoreApplicationPrivate::theMainThread = Q_BASIC_ATOMIC_INITIALIZER(nullptr);
++ Q_CONSTINIT QBasicAtomicPointer<void> QCoreApplicationPrivate::theMainThreadId = Q_BASIC_ATOMIC_INITIALIZER(nullptr);
++ QThread *QCoreApplicationPrivate::mainThread()
++ {
++ Q_ASSERT(theMainThread.loadRelaxed() != nullptr);
++ return theMainThread.loadRelaxed();
++ }
++
++ #endif // QT_NO_QOBJECT
++
++ QString qAppName()
++ {
++ if (!QCoreApplicationPrivate::checkInstance("qAppName"))
++ return QString();
++ return QCoreApplication::instance()->d_func()->appName();
++ }
++
++ void QCoreApplicationPrivate::initLocale()
++ {
++ #if defined(QT_BOOTSTRAPPED)
++ // Don't try to control bootstrap library locale or encoding.
++ #elif defined(Q_OS_UNIX)
++ Q_CONSTINIT static bool qt_locale_initialized = false;
++ if (qt_locale_initialized)
++ return;
++ qt_locale_initialized = true;
++
++ // By default the portable "C"/POSIX locale is selected and active.
++ // Apply the locale from the environment, via setlocale(), which will
++ // read LC_ALL, LC_<category>, and LANG, in order (for each category).
++ setlocale(LC_ALL, "");
++
++ // Next, let's ensure that LC_CTYPE is UTF-8, since QStringConverter's
++ // QLocal8Bit hard-codes this, and we need to be consistent.
++ # if defined(Q_OS_INTEGRITY)
++ setlocale(LC_CTYPE, "UTF-8");
++ # elif defined(Q_OS_QNX)
++ // QNX has no nl_langinfo, so we can't check.
++ // FIXME: Shouldn't we still setlocale("UTF-8")?
++ # elif defined(Q_OS_ANDROID) && __ANDROID_API__ < __ANDROID_API_O__
++ // Android 6 still lacks nl_langinfo(), so we can't check.
++ // FIXME: Shouldn't we still setlocale("UTF-8")?
++ # elif defined(Q_OS_VXWORKS)
++ // VxWorks has no nl_langinfo, so we can't check.
++ # else
++ // std::string's SSO usually saves this the need to allocate:
++ const std::string oldEncoding = nl_langinfo(CODESET);
++ if (!Q_LIKELY(qstricmp(oldEncoding.data(), "UTF-8") == 0
++ || qstricmp(oldEncoding.data(), "utf8") == 0)) {
++ const QByteArray oldLocale = setlocale(LC_ALL, nullptr);
++ QByteArray newLocale;
++ bool warnOnOverride = true;
++ # if defined(Q_OS_DARWIN)
++ // Don't warn unless the char encoding has been changed from the
++ // default "C" encoding, or the user touched any of the locale
++ // environment variables to force the "C" char encoding.
++ warnOnOverride = qstrcmp(setlocale(LC_CTYPE, nullptr), "C") != 0
++ || getenv("LC_ALL") || getenv("LC_CTYPE") || getenv("LANG");
++
++ // No need to try language or region specific CTYPEs, as they
++ // all point back to the same generic UTF-8 CTYPE.
++ newLocale = setlocale(LC_CTYPE, "UTF-8");
++ # else
++ newLocale = setlocale(LC_CTYPE, nullptr);
++ if (qsizetype dot = newLocale.indexOf('.'); dot != -1)
++ newLocale.truncate(dot); // remove encoding, if any
++ if (qsizetype at = newLocale.indexOf('@'); at != -1)
++ newLocale.truncate(at); // remove variant, as the old de_DE@euro
++ newLocale += ".UTF-8";
++ newLocale = setlocale(LC_CTYPE, newLocale);
++
++ // If that locale doesn't exist, try some fallbacks:
++ if (newLocale.isEmpty())
++ newLocale = setlocale(LC_CTYPE, "C.UTF-8");
++ if (newLocale.isEmpty())
++ newLocale = setlocale(LC_CTYPE, "C.utf8");
++ # endif
++
++ if (newLocale.isEmpty()) {
++ // Failed to set a UTF-8 locale.
++ qWarning("Detected locale \"%s\" with character encoding \"%s\", which is not UTF-8.\n"
++ "Qt depends on a UTF-8 locale, but has failed to switch to one.\n"
++ "If this causes problems, reconfigure your locale. See the locale(1) manual\n"
++ "for more information.", oldLocale.constData(), oldEncoding.data());
++ } else if (warnOnOverride) {
++ // Let the user know we over-rode their configuration.
++ qWarning("Detected locale \"%s\" with character encoding \"%s\", which is not UTF-8.\n"
++ "Qt depends on a UTF-8 locale, and has switched to \"%s\" instead.\n"
++ "If this causes problems, reconfigure your locale. See the locale(1) manual\n"
++ "for more information.",
++ oldLocale.constData(), oldEncoding.data(), newLocale.constData());
++ }
++ }
++ # endif // Platform choice
++ #endif // Unix
++ }
++
++
++ /*!
++ \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()
++ function is 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,
++ {Producer and Consumer using Semaphores},
++ {Producer and Consumer using Wait Conditions}
++ */
++
++ /*!
++ \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.
++
++ \b{Data race notice}: this function should not be used to test for the
++ existence of the QCoreApplication instance from auxiliary threads, unless
++ the caller code is compiled as C++20.
++ */
++
++ /*!
++ \internal
++ */
++ QCoreApplication::QCoreApplication(QCoreApplicationPrivate &p)
++ #ifdef QT_NO_QOBJECT
++ : d_ptr(&p)
++ #else
++ : QObject(p, nullptr)
++ #endif
++ {
++ d_func()->q_ptr = this;
++ // note: it is the subclasses' job to call
++ // QCoreApplicationPrivate::eventDispatcher->startingUp();
++ }
++
++ /*!
++ 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
++ #endif
++ )
++ #ifdef QT_NO_QOBJECT
++ : d_ptr(new QCoreApplicationPrivate(argc, argv))
++ #else
++ : QObject(*new QCoreApplicationPrivate(argc, argv))
++ #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 Q_TRACE_INSTRUMENT(qtcore) QCoreApplicationPrivate::init()
++ {
++ Q_TRACE_SCOPE(QCoreApplicationPrivate_init);
++
++ #if defined(Q_OS_MACOS)
++ QMacAutoReleasePool pool;
++ #endif
++
++ Q_Q(QCoreApplication);
++
++ #if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
++ initDebuggingConsole();
++ #endif
++
++ initLocale();
++
++ Q_ASSERT_X(!QCoreApplication::self, "QCoreApplication", "there should be only one application object");
++ #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
++ # ifdef __cpp_lib_atomic_ref
++ std::atomic_ref(QCoreApplication::self).store(q, std::memory_order_relaxed);
++ # else
++ QCoreApplication::self = q;
++ # endif
++ g_self.storeRelaxed(q);
++ #else
++ QCoreApplication::self.storeRelaxed(q);
++ #endif
++
++ #if QT_CONFIG(thread)
++ #ifdef Q_OS_WASM
++ emscripten::val hardwareConcurrency = emscripten::val::global("navigator")["hardwareConcurrency"];
++ if (hardwareConcurrency.isUndefined())
++ QThreadPrivate::idealThreadCount = 2;
++ else
++ QThreadPrivate::idealThreadCount = 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) || defined(Q_OS_HARMONY)) && !defined(QT_BOOTSTRAPPED)
++ // 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.
++ if (coreappdata->libPathsInitialized()) {
++ const QStringList appPaths = std::exchange(coreappdata->app_libpaths, {});
++ Q_ASSERT(!coreappdata->libPathsInitialized());
++
++ if (coreappdata->libPathsManuallySet()) {
++ const QStringList manualPaths = std::exchange(coreappdata->manual_libpaths, {});
++ Q_ASSERT(!coreappdata->libPathsManuallySet());
++
++ // 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 (qsizetype i = manualPaths.size(), j = appPaths.size(); 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.
++ }
++ }
++ coreappdata->manual_libpaths.swap(newPaths);
++ }
++ }
++ #endif
++
++ #ifndef QT_NO_QOBJECT
++ // use the event dispatcher created by the app programmer (if any)
++ Q_ASSERT(!eventDispatcher);
++ auto thisThreadData = threadData.loadRelaxed();
++ eventDispatcher = thisThreadData->eventDispatcher.loadRelaxed();
++
++ // otherwise we create one
++ if (!eventDispatcher)
++ createEventDispatcher();
++ Q_ASSERT(eventDispatcher);
++
++ if (!eventDispatcher->parent()) {
++ eventDispatcher->moveToThread(thisThreadData->thread.loadAcquire());
++ eventDispatcher->setParent(q);
++ }
++
++ thisThreadData->eventDispatcher = eventDispatcher;
++ eventDispatcherReady();
++ #endif
++
++ processCommandLineArguments();
++
++ qt_call_pre_routines();
++ QT_MANGLE_NAMESPACE(qt_startup_hook)();
++ #ifndef QT_BOOTSTRAPPED
++ QtPrivate::initBindingStatusThreadId();
++ 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()
++ {
++ preRoutinesCalled = false;
++
++ qt_call_post_routines();
++
++ #ifndef QT_NO_QOBJECT
++ QCoreApplicationPrivate::is_app_closing = true;
++ QCoreApplicationPrivate::is_app_running = false;
++ #endif
++
++ #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
++ # ifdef __cpp_lib_atomic_ref
++ std::atomic_ref(self).store(nullptr, std::memory_order_relaxed);
++ # else
++ self = nullptr;
++ # endif
++ g_self.storeRelaxed(nullptr);
++ #else
++ self.storeRelaxed(nullptr);
++ #endif
++
++ #if QT_CONFIG(thread)
++ // Synchronize and stop the global thread pool threads.
++ QThreadPoolPrivate::destroyGlobalThreadPool();
++ #endif
++
++ #ifndef QT_NO_QOBJECT
++ QCoreApplicationPrivate::destroyEventDispatcher();
++ #endif
++
++ #if QT_CONFIG(library)
++ if (coreappdata.exists()) {
++ // neither .clear(), .resize(), nor = {} will make isNull() == true
++ coreappdata->app_libpaths = QStringList();
++ coreappdata->manual_libpaths = QStringList();
++ Q_ASSERT(!coreappdata->libPathsManuallySet());
++ Q_ASSERT(!coreappdata->libPathsInitialized());
++ }
++ #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. If this application does enable the flag and
++ starts child processes, it should drop the privileges as early as possible
++ by calling \c{setuid(2)} for itself, or at the latest by using the
++ QProcess::UnixProcessParameters::ResetIds flag.
++ */
++ 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)
++ {
++ // Since we bit-shift these values, we can't go higher than 32 on 32 bit operating systems
++ // without changing the storage type of QCoreApplicationPrivate::attribs to quint64.
++ static_assert(Qt::AA_AttributeCount <= sizeof(QCoreApplicationPrivate::attribs) * CHAR_BIT);
++
++ 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_PluginApplication:
++ case Qt::AA_UseDesktopOpenGL:
++ case Qt::AA_UseOpenGLES:
++ case Qt::AA_UseSoftwareOpenGL:
++ #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.
++
++ When this property is \c true the release of the last remaining
++ QEventLoopLocker operating on the application will attempt to
++ quit the application.
++
++ Note that attempting a quit may not necessarily result in the
++ application quitting, for example if there still are open windows,
++ or the QEvent::Quit event is ignored.
++
++ The default is \c true.
++
++ \sa QEventLoopLocker
++ */
++
++ bool QCoreApplication::isQuitLockEnabled()
++ {
++ return quitLockEnabled;
++ }
++
++ static bool doNotify(QObject *, QEvent *);
++
++ void QCoreApplication::setQuitLockEnabled(bool enabled)
++ {
++ quitLockEnabled = enabled;
++ }
++
++ /*!
++ \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)
++ {
++ // 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.loadAcquire();
++ bool selfRequired = threadData->requiresCoreApplication;
++ if (selfRequired && !qApp)
++ 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;
++ }
++
++ QScopedScopeLevelCounter scopeLevelCounter(threadData);
++ if (!selfRequired)
++ return doNotify(receiver, event);
++
++ if (QCoreApplicationPrivate::is_app_closing)
++ return false; // no event delivery while the application is closing
++
++ #if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
++ if (!QThread::isMainThread())
++ return false;
++ #endif
++ return qApp->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->m_spont = originatingEvent->m_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 7. 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)
++ {
++ Q_ASSERT(receiver);
++ Q_ASSERT(event);
++
++ #if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
++ Q_ASSERT(receiver->d_func()->threadData.loadAcquire()->thread.loadRelaxed()
++ == QCoreApplicationPrivate::mainThread());
++ #endif
++
++ // 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)
++ {
++ Q_ASSERT(event);
++
++ // ### Qt 7: turn into an assert
++ if (receiver == nullptr) { // serious error
++ qWarning("QCoreApplication::notify: Unexpected null receiver");
++ return true;
++ }
++
++ QCoreApplicationPrivate::checkReceiverThread(receiver, "QCoreApplication::notify");
++
++ 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(QThread::isMainThread());
++
++ if (extraData) {
++ // application event filters are only called for objects in the GUI thread
++ for (qsizetype i = 0; i < extraData->eventFilters.size(); ++i) {
++ QObject *obj = extraData->eventFilters.at(i);
++ if (!obj)
++ continue;
++ if (obj->d_func()->threadData.loadRelaxed() != threadData.loadRelaxed()) {
++ 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 != qApp && receiver->d_func()->extraData) {
++ for (qsizetype 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.loadRelaxed() != receiver->d_func()->threadData.loadRelaxed()) {
++ 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 (QThread::isMainThread()
++ && QCoreApplication::self
++ && 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 some pending events for the calling thread according to
++ the specified \a flags.
++
++ Use of this function is discouraged. Instead, prefer to move long
++ operations out of the GUI thread into an auxiliary one and to completely
++ avoid nested event loop processing. If event processing is really
++ necessary, consider using \l QEventLoop instead.
++
++ 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, QChronoTimer, QEventLoop::processEvents(),
++ sendPostedEvents()
++ */
++ void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags)
++ {
++ QThreadData *data = QThreadData::current();
++ if (!data->hasEventDispatcher())
++ return;
++ data->eventDispatcher.loadRelaxed()->processEvents(flags);
++ }
++
++ /*!
++ \overload
++
++ Processes pending events for the calling thread for \a ms
++ milliseconds or until there are no more events to process,
++ whichever is shorter.
++
++ This is equivalent to calling:
++ \code
++ QCoreApplication::processEvents(flags, QDeadlineTimer(ms));
++ \endcode
++ */
++ void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, int ms)
++ {
++ QCoreApplication::processEvents(flags, QDeadlineTimer(ms));
++ }
++
++ /*!
++ \since 6.7
++ \overload
++
++ Processes pending events for the calling thread untile \a deadline has expired,
++ or until there are no more events to process, whichever happens first.
++
++ Use of this function is discouraged. Instead, prefer to move long
++ operations out of the GUI thread into an auxiliary one and to completely
++ avoid nested event loop processing. If event processing is really
++ necessary, consider using \l QEventLoop instead.
++
++ 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.
++
++ \note All events that were queued before the timeout will be processed,
++ however long it takes.
++
++ \threadsafe
++
++ \sa exec(), QTimer, QChronoTimer, QEventLoop::processEvents()
++ */
++ void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, QDeadlineTimer deadline)
++ {
++ // ### TODO: 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;
++
++ while (data->eventDispatcher.loadRelaxed()->processEvents(flags & ~QEventLoop::WaitForMoreEvents)) {
++ if (deadline.hasExpired())
++ 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 QChronoTimer
++ with 0ns 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.loadAcquire();
++ 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(QEventLoop::ApplicationExec);
++ 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.loadRelaxed()->quitNow = false;
++ in_exec = false;
++ QCoreApplication::sendPostedEvents(nullptr, 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.
++
++ Note also that this function is not thread-safe. It should be called only
++ from the main thread (the thread that the QCoreApplication object is
++ processing events on). To ask the application to exit from another thread,
++ either use QCoreApplication::quit() or instead call this function from the
++ main thread with QMetaMethod::invokeMethod().
++
++ \sa quit(), exec()
++ */
++ void QCoreApplication::exit(int returnCode)
++ {
++ if (!self)
++ return;
++
++ #ifdef Q_OS_WASM
++ if (!qstdweb::haveAsyncify())
++ qFatal("Terminating since we don't have asyncify");
++ #endif
++ QCoreApplicationPrivate *d = self->d_func();
++ if (!d->aboutToQuitEmitted) {
++ emit self->aboutToQuit(QCoreApplication::QPrivateSignal());
++ d->aboutToQuitEmitted = true;
++ }
++ QThreadData *data = d->threadData.loadRelaxed();
++ data->quitNow = true;
++ for (qsizetype 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_ASSERT_X(receiver, "QCoreApplication::sendEvent", "Unexpected null receiver");
++ Q_ASSERT_X(event, "QCoreApplication::sendEvent", "Unexpected null event");
++
++ Q_TRACE(QCoreApplication_sendEvent, receiver, event, event->type());
++
++ event->m_spont = false;
++ return notifyInternal2(receiver, event);
++ }
++
++ /*!
++ \internal
++ */
++ bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event)
++ {
++ Q_ASSERT_X(receiver, "QCoreApplication::sendSpontaneousEvent", "Unexpected null receiver");
++ Q_ASSERT_X(event, "QCoreApplication::sendSpontaneousEvent", "Unexpected null event");
++
++ Q_TRACE(QCoreApplication_sendSpontaneousEvent, receiver, event, event->type());
++
++ event->m_spont = true;
++ return notifyInternal2(receiver, event);
++ }
++
++ #endif // QT_NO_QOBJECT
++
++ QCoreApplicationPrivate::QPostEventListLocker QCoreApplicationPrivate::lockThreadPostEventList(QObject *object)
++ {
++ QPostEventListLocker locker;
++
++ if (!object) {
++ locker.threadData = QThreadData::current();
++ locker.locker = qt_unique_lock(locker.threadData->postEventList.mutex);
++ return locker;
++ }
++
++ auto &threadData = QObjectPrivate::get(object)->threadData;
++
++ // if object has moved to another thread, follow it
++ for (;;) {
++ // synchronizes with the storeRelease in QObject::moveToThread
++ locker.threadData = threadData.loadAcquire();
++ if (!locker.threadData) {
++ // destruction in progress
++ return locker;
++ }
++
++ auto temporaryLocker = qt_unique_lock(locker.threadData->postEventList.mutex);
++ if (locker.threadData == threadData.loadAcquire()) {
++ locker.locker = std::move(temporaryLocker);
++ break;
++ }
++ }
++
++ Q_ASSERT(locker.threadData);
++ return locker;
++ }
++
++ /*!
++ \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.
++
++ \note QObject::deleteLater() schedules the object for deferred
++ deletion, which is typically handled by the receiver's event
++ loop. If no event loop is running in the thread, the deletion
++ will be performed when the thread finishes. A common and safe
++ pattern is to connect the thread's finished() signal to the
++ object's deleteLater() slot:
++
++ \code
++ QObject::connect(thread, &QThread::finished, worker, &QObject::deleteLater);
++ \endcode
++
++ \threadsafe
++
++ \sa sendEvent(), notify(), sendPostedEvents(), Qt::EventPriority
++ */
++ void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority)
++ {
++ Q_ASSERT_X(event, "QCoreApplication::postEvent", "Unexpected null event");
++
++ Q_TRACE_SCOPE(QCoreApplication_postEvent, receiver, event, event->type());
++
++ // ### Qt 7: turn into an assert
++ if (receiver == nullptr) {
++ qWarning("QCoreApplication::postEvent: Unexpected null receiver");
++ delete event;
++ return;
++ }
++
++ auto locker = QCoreApplicationPrivate::lockThreadPostEventList(receiver);
++ if (!locker.threadData) {
++ // posting during destruction? just delete the event to prevent a leak
++ delete event;
++ return;
++ }
++
++ QThreadData *data = locker.threadData;
++
++ QT_WARNING_PUSH
++ QT_WARNING_DISABLE_DEPRECATED // compressEvent()
++ // if this is one of the compressible events, do compression
++ if (receiver->d_func()->postedEvents.loadAcquire()
++ && self && self->compressEvent(event, receiver, &data->postEventList)) {
++ Q_TRACE(QCoreApplication_postEvent_event_compressed, receiver, event);
++ return;
++ }
++ QT_WARNING_POP
++
++ // delete the event on exceptions to protect against memory leaks till the event is
++ // properly owned in the postEventList
++ std::unique_ptr<QEvent> eventDeleter(event);
++ Q_TRACE(QCoreApplication_postEvent_event_posted, receiver, event, event->type());
++ data->postEventList.addEvent(QPostEvent(receiver, event, priority));
++ Q_UNUSED(eventDeleter.release());
++ event->m_posted = true;
++ receiver->d_func()->postedEvents.fetchAndAddRelease(1);
++ 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.
++ */
++ #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
++ bool QCoreApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventList *postedEvents)
++ {
++ return d_func()->compressEvent(event, receiver, postedEvents);
++ }
++ #endif
++
++ bool QCoreApplicationPrivate::compressEvent(QEvent *event, QObject *receiver, QPostEventList *postedEvents)
++ {
++ Q_ASSERT(event);
++ Q_ASSERT(receiver);
++ Q_ASSERT(postedEvents);
++
++ // compress posted timers to this object.
++ if (event->type() == QEvent::Timer) {
++ const int timerId = static_cast<QTimerEvent *>(event)->timerId();
++ auto it = postedEvents->cbegin();
++ const auto end = postedEvents->cend();
++ while (it != end) {
++ if (it->event && it->event->type() == QEvent::Timer && it->receiver == receiver) {
++ if (static_cast<QTimerEvent *>(it->event)->timerId() == timerId) {
++ delete event;
++ return true;
++ }
++ }
++ ++it;
++ }
++ return false;
++ }
++
++ if (event->type() == QEvent::Quit) {
++ for (const QPostEvent &cur : std::as_const(*postedEvents)) {
++ if (cur.receiver != receiver
++ || cur.event == nullptr
++ || 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 postEvent()
++ */
++ void QCoreApplication::sendPostedEvents(QObject *receiver, int event_type)
++ {
++ // ### TODO: 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.loadRelaxed() != 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.loadAcquire())) {
++ --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.
++ qsizetype startOffset = data->postEventList.startOffset;
++ qsizetype &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 {
++ Q_DISABLE_COPY_MOVE(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.
++
++ const int eventLoopLevel = static_cast<QDeferredDeleteEvent *>(pe.event)->loopLevel();
++ const int eventScopeLevel = static_cast<QDeferredDeleteEvent *>(pe.event)->scopeLevel();
++
++ const bool postedBeforeOutermostLoop = eventLoopLevel == 0;
++ const bool allowDeferredDelete =
++ (eventLoopLevel + eventScopeLevel > data->loopLevel + data->scopeLevel
++ || (postedBeforeOutermostLoop && data->loopLevel > 0)
++ || (event_type == QEvent::DeferredDelete
++ && eventLoopLevel + eventScopeLevel == data->loopLevel + data->scopeLevel));
++ 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 = nullptr;
++
++ // 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->m_posted = false;
++ QEvent *e = pe.event;
++ QObject * r = pe.receiver;
++
++ [[maybe_unused]]
++ const auto previous = r->d_func()->postedEvents.fetchAndSubAcquire(1);
++ Q_ASSERT(previous > 0);
++
++ // next, update the data structure so that we're ready
++ // for the next event.
++ const_cast<QPostEvent &>(pe).event = nullptr;
++
++ locker.unlock();
++ const auto relocker = qScopeGuard([&locker] { locker.lock(); });
++
++ const std::unique_ptr<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)
++ {
++ auto locker = QCoreApplicationPrivate::lockThreadPostEventList(receiver);
++ QThreadData *data = locker.threadData;
++
++ // 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.loadAcquire())
++ return;
++
++ //we will collect all the posted events for the QObject
++ //and we'll delete after the mutex was unlocked
++ QVarLengthArray<QEvent*> events;
++ qsizetype n = data->postEventList.size();
++ qsizetype j = 0;
++
++ for (qsizetype 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.fetchAndSubAcquire(1);
++ pe.event->m_posted = false;
++ events.append(pe.event);
++ const_cast<QPostEvent &>(pe).event = nullptr;
++ } 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.loadRelaxed());
++ }
++ #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
++ \internal
++ */
++
++ void QCoreApplicationPrivate::removePostedEvent(QEvent * event)
++ {
++ if (!event || !event->m_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 (const QPostEvent &pe : std::as_const(data->postEventList)) {
++ 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.fetchAndSubAcquire(1);
++ pe.event->m_posted = false;
++ delete pe.event;
++ const_cast<QPostEvent &>(pe).event = nullptr;
++ return;
++ }
++ }
++ }
++
++ /*!\reimp
++
++ */
++ bool QCoreApplication::event(QEvent *e)
++ {
++ if (e->type() == QEvent::Quit) {
++ exit(0);
++ return true;
++ }
++ return QObject::event(e);
++ }
++
++ void QCoreApplicationPrivate::ref()
++ {
++ quitLockRef.ref();
++ }
++
++ void QCoreApplicationPrivate::deref()
++ {
++ quitLockRef.deref();
++
++ if (quitLockEnabled && canQuitAutomatically())
++ quitAutomatically();
++ }
++
++ bool QCoreApplicationPrivate::canQuitAutomatically()
++ {
++ if (!in_exec)
++ return false;
++
++ // The automatic quit functionality is triggered by
++ // both QEventLoopLocker and maybeLastWindowClosed.
++ // In either case, we don't want to quit if there
++ // are active QEventLoopLockers, even if quitLockEnabled
++ // is not enabled, as the property signals whether to
++ // trigger the automatic quit, not whether to block it.
++ if (quitLockRef.loadRelaxed())
++ return false;
++
++ return true;
++ }
++
++ void QCoreApplicationPrivate::quitAutomatically()
++ {
++ Q_Q(QCoreApplication);
++
++ // Explicit requests by the user to quit() is plumbed via the platform
++ // if possible, and delivers the quit event synchronously. For automatic
++ // quits we implicitly support cancelling the quit by showing another
++ // window, which currently relies on removing any posted quit events
++ // from the event queue. As a result, we can't use the normal quit()
++ // code path, and need to post manually.
++ QCoreApplication::postEvent(q, new QEvent(QEvent::Quit));
++ }
++
++ /*!
++ \threadsafe
++
++ Asks the application to quit.
++
++ The request may be ignored if the application prevents the quit,
++ for example if one of its windows can't be closed. The application
++ can affect this by handling the QEvent::Quit event on the application
++ level, or QEvent::Close events for the individual windows.
++
++ If the quit is not interrupted the application will exit with return
++ code 0 (success).
++
++ To exit the application without a chance of being interrupted, call
++ exit() directly. Note that method is not thread-safe.
++
++ 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
++
++ \b{Thread-safety note}: this function may be called from any thread to
++ thread-safely cause the currently-running main application loop to exit.
++ However, thread-safety is not guaranteed if the QCoreApplication object is
++ being destroyed at the same time.
++
++ \sa exit(), aboutToQuit()
++ */
++ void QCoreApplication::quit()
++ {
++ if (!self)
++ return;
++
++ if (!self->d_func()->in_exec)
++ return;
++
++ self->d_func()->quit();
++ }
++
++ void QCoreApplicationPrivate::quit()
++ {
++ Q_Q(QCoreApplication);
++
++ if (QThread::isMainThread()) {
++ QEvent quitEvent(QEvent::Quit);
++ QCoreApplication::sendEvent(q, &quitEvent);
++ } else {
++ QCoreApplication::postEvent(q, new QEvent(QEvent::Quit));
++ }
++ }
++
++ /*!
++ \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.
++
++ \note At this point the main event loop is still running, but will
++ not process further events on return except QEvent::DeferredDelete
++ events for objects deleted via deleteLater(). If event processing is
++ needed, use a nested event loop or call QCoreApplication::processEvents()
++ manually.
++
++ \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 \QD provide a \c retranslateUi() function that can be
++ called.
++
++ The function returns \c true on success and \c false on failure.
++
++ \note QCoreApplication does \e not take ownership of \a translationFile.
++ It is the responsibility of the application to ensure that, if the
++ function returned \c true, the \a translationFile object is alive until
++ either \l removeTranslator() is called for it, or the application exits.
++
++ \sa removeTranslator(), translate(), QTranslator::load(),
++ {Writing Source Code for Translation#Prepare for Dynamic Language Changes}{Prepare for Dynamic Language Changes}
++ */
++
++ 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);
++ }
++
++ if (translationFile->isEmpty())
++ return true;
++
++ #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) {
++ qsizetype percentPos = 0;
++ qsizetype len = 0;
++ while ((percentPos = result->indexOf(u'%', percentPos + len)) != -1) {
++ len = 1;
++ if (percentPos + len == result->size())
++ break;
++ QString fmt;
++ if (result->at(percentPos + len) == u'L') {
++ ++len;
++ if (percentPos + len == result->size())
++ break;
++ fmt = "%L1"_L1;
++ } else {
++ fmt = "%1"_L1;
++ }
++ if (result->at(percentPos + len) == u'n') {
++ fmt = fmt.arg(n);
++ ++len;
++ result->replace(percentPos, len, fmt);
++ len = fmt.size();
++ }
++ }
++ }
++ }
++
++ /*!
++ \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(),
++ {Internationalization and Translations}
++ */
++ 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;
++ }
++
++ // Declared in qglobal.h
++ QString qtTrId(const char *id, int n)
++ {
++ return QCoreApplication::translate(nullptr, id, nullptr, 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("%n"_L1, QString::number(n));
++ return ret;
++ }
++
++ #endif //QT_NO_TRANSLATION
++
++ #ifndef QT_BOOTSTRAPPED
++ /*!
++ 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).
++
++ On Android this will point to the directory actually containing the
++ executable, which may be inside the application APK (if it was built
++ with uncompressed libraries support).
++
++ \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();
++ }
++
++ QFileSystemEntry appFilePath(applicationFilePath(), QFileSystemEntry::FromInternalPath{});
++ return appFilePath.isEmpty() ? QString() : appFilePath.path();
++ }
++
++ #if !defined(Q_OS_WIN) && !defined(Q_OS_DARWIN)
++ // qcoreapplication_win.cpp or qcoreapplication_mac.cpp for those
++ static QString qAppFileName()
++ {
++ # if defined(Q_OS_ANDROID) || defined(Q_OS_HARMONY)
++ // the actual process on Android is the Java VM, so this doesn't help us
++ return QString();
++ # elif defined(Q_OS_LINUX)
++ // this includes the Embedded Android builds
++ return QFile::decodeName(qt_readlink("/proc/self/exe"));
++ # elif defined(AT_EXECPATH)
++ // seen on FreeBSD, but I suppose the other BSDs could adopt this API
++ char execfn[PATH_MAX];
++ if (elf_aux_info(AT_EXECPATH, execfn, sizeof(execfn)) != 0)
++ execfn[0] = '\0';
++
++ qsizetype len = qstrlen(execfn);
++ return QFile::decodeName(QByteArray::fromRawData(execfn, len));
++ # else
++ // other OS or something
++ return QString();
++ # endif
++ }
++ #endif // !Q_OS_WIN && !Q_OS_DARWIN
++
++ /*!
++ 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 != QByteArrayView(d->argv[0])) {
++ // clear the cache if the procname changes, so we reprocess it.
++ d->cachedApplicationFilePath = QString();
++ procName.assign(d->argv[0]);
++ }
++ }
++
++ if (!d->cachedApplicationFilePath.isNull())
++ return d->cachedApplicationFilePath;
++
++ QString absPath = qAppFileName();
++ if (Q_LIKELY(!absPath.isEmpty())) { // Darwin, FreeBSD, Linux, Windows
++ // the OS has canonicalized for us
++ return d->cachedApplicationFilePath = std::move(absPath);
++ }
++
++ if (const QStringList args = arguments(); !args.isEmpty()) {
++ const QString &argv0 = args[0];
++
++ if (!argv0.isEmpty() && argv0.at(0) == u'/') {
++ /*
++ If argv0 starts with a slash, it is already an absolute
++ file path.
++ */
++ absPath = argv0;
++ } else if (argv0.contains(u'/')) {
++ /*
++ 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 = QFileInfo(absPath).canonicalFilePath();
++ if (!absPath.isEmpty()) {
++ return d->cachedApplicationFilePath = std::move(absPath);
++ }
++ return QString();
++ }
++ #endif // !QT_BOOTSTRAPPED
++
++ /*!
++ \since 4.4
++
++ Returns the current process ID for the application.
++ */
++ qint64 QCoreApplication::applicationPid() noexcept
++ {
++ #if defined(Q_OS_WIN)
++ return GetCurrentProcessId();
++ #elif defined(Q_OS_VXWORKS)
++ return (pid_t) taskIdCurrent;
++ #else
++ return getpid();
++ #endif
++ }
++
++ #ifdef Q_OS_WIN
++ static QStringList winCmdArgs()
++ {
++ // On Windows, it is possible to pass Unicode arguments on
++ // the command line, but we don't implement any of the wide
++ // entry-points (wmain/wWinMain), so get the arguments from
++ // the Windows API instead of using argv. Note that we only
++ // do this when argv were not modified by the user in main().
++ QStringList result;
++ int size;
++ if (wchar_t **argv = CommandLineToArgvW(GetCommandLine(), &size)) {
++ result.reserve(size);
++ wchar_t **argvEnd = argv + size;
++ for (wchar_t **a = argv; a < argvEnd; ++a)
++ result.append(QString::fromWCharArray(*a));
++ LocalFree(argv);
++ }
++ return result;
++ }
++ #endif // Q_OS_WIN
++
++ /*!
++ \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{https://docs.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-getcommandlinea}{GetCommandLine()}.
++ As a result of this, the string given by arguments().at(0)
++ might not be the exact program used to start the application
++ on Windows.
++
++ \sa applicationFilePath(), QCommandLineParser
++ */
++
++ QStringList QCoreApplication::arguments()
++ {
++ QStringList list;
++
++ if (!self) {
++ qWarning("QCoreApplication::arguments: Please instantiate the QApplication object first");
++ return list;
++ }
++
++ const QCoreApplicationPrivate *d = self->d_func();
++
++ const int argc = d->argc;
++ char ** const argv = d->argv;
++ list.reserve(argc);
++
++ #if defined(Q_OS_WIN)
++ const bool argsModifiedByUser = d->origArgv == nullptr;
++ if (!argsModifiedByUser) {
++ QStringList commandLineArguments = winCmdArgs();
++
++ // Even if the user didn't modify argv before passing them
++ // on to QCoreApplication, derived QApplications might have.
++ // If that's the case argc will differ from origArgc.
++ if (argc != d->origArgc) {
++ // Note: On MingGW the arguments from GetCommandLine are
++ // not wildcard expanded (if wildcard expansion is enabled),
++ // as opposed to the arguments in argv. This means we can't
++ // compare commandLineArguments to argv/origArgc, but
++ // must remove elements by value, based on whether they
++ // were filtered out from argc.
++ for (int i = 0; i < d->origArgc; ++i) {
++ if (!contains(argc, argv, d->origArgv[i]))
++ commandLineArguments.removeAll(QString::fromLocal8Bit(d->origArgv[i]));
++ }
++ }
++
++ return commandLineArguments;
++ } // Fall back to rebuilding from argv/argc when a modified argv was passed.
++ #endif // defined(Q_OS_WIN)
++
++ for (int a = 0; a < argc; ++a)
++ list << QString::fromLocal8Bit(argv[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 default 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 default 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 application name is used in various Qt classes and modules,
++ most prominently in \l{QSettings} when it is constructed using the default constructor.
++ Other uses are in formatted logging output (see \l{qSetMessagePattern()}),
++ in output by \l{QCommandLineParser}, in \l{QTemporaryDir} and \l{QTemporaryFile}
++ default paths, and in some file locations of \l{QStandardPaths}.
++ \l{Qt D-Bus}, \l{Accessibility}, and the XCB platform integration make use
++ of the application name, too.
++
++ If not set, the application name defaults to the executable name.
++
++ \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();
++ }
++
++ /*!
++ \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 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
++ \row
++ \li HarmonyOS
++ \li versionName field of the app.json5 configuration file
++ \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(permissions) || defined(Q_QDOC)
++
++ /*!
++ Checks the status of the given \a permission
++
++ If the result is Qt::PermissionStatus::Undetermined then permission should be
++ requested via requestPermission() to determine the user's intent.
++
++ \since 6.5
++ \sa requestPermission(), {Application Permissions}
++ */
++ Qt::PermissionStatus QCoreApplication::checkPermission(const QPermission &permission)
++ {
++ return QPermissions::Private::checkPermission(permission);
++ }
++
++ /*!
++ \fn template <typename Functor> void QCoreApplication::requestPermission(
++ const QPermission &permission, Functor &&functor)
++
++ Requests the given \a permission.
++
++ \include permissions.qdocinc requestPermission-functor
++
++ The \a functor can be a free-standing or static member function:
++
++ \code
++ qApp->requestPermission(QCameraPermission{}, &permissionUpdated);
++ \endcode
++
++ or a lambda:
++
++ \code
++ qApp->requestPermission(QCameraPermission{}, [](const QPermission &permission) {
++ });
++ \endcode
++
++ \include permissions.qdocinc requestPermission-postamble
++
++ \since 6.5
++ \sa checkPermission(), {Application Permissions}
++ */
++
++ /*!
++ \fn template<typename Functor> void QCoreApplication::requestPermission(
++ const QPermission &permission, const QObject *context,
++ Functor functor)
++
++ Requests the given \a permission, in the context of \a context.
++
++ \include permissions.qdocinc requestPermission-functor
++
++ The \a functor can be a free-standing or static member function:
++
++ \code
++ qApp->requestPermission(QCameraPermission{}, context, &permissionUpdated);
++ \endcode
++
++ a lambda:
++
++ \code
++ qApp->requestPermission(QCameraPermission{}, context, [](const QPermission &permission) {
++ });
++ \endcode
++
++ or a slot in the \a context object:
++
++ \code
++ qApp->requestPermission(QCameraPermission{}, this, &CamerWidget::permissionUpdated);
++ \endcode
++
++ The \a functor will be called in the thread of the \a context object. If
++ \a context is destroyed before the request completes, the \a functor will
++ not be called.
++
++ \include permissions.qdocinc requestPermission-postamble
++
++ \since 6.5
++ \overload
++ \sa checkPermission(), {Application Permissions}
++ */
++
++ /*!
++ \internal
++
++ Called by the various requestPermission overloads to perform the request.
++
++ Calls the functor encapsulated in the \a slotObjRaw in the given \a context
++ (which may be \c nullptr).
++ */
++ void QCoreApplication::requestPermissionImpl(const QPermission &requestedPermission,
++ QtPrivate::QSlotObjectBase *slotObjRaw, const QObject *context)
++ {
++ QtPrivate::SlotObjUniquePtr slotObj{slotObjRaw}; // adopts
++ Q_ASSERT(slotObj);
++
++ if (!QThread::isMainThread()) {
++ qCWarning(lcPermissions, "Permissions can only be requested from the GUI (main) thread");
++ return;
++ }
++
++ class PermissionReceiver : public QObject
++ {
++ public:
++ explicit PermissionReceiver(QtPrivate::SlotObjUniquePtr &&slotObject, const QObject *context)
++ : slotObject(std::move(slotObject)), context(context ? context : this)
++ {
++ Q_ASSERT(this->context);
++ moveToThread(this->context->thread());
++ }
++
++ void finalizePermissionRequest(const QPermission &permission)
++ {
++ Q_ASSERT(slotObject);
++ // only execute if context object is still alive
++ if (context) {
++ void *args[] = { nullptr, const_cast<QPermission *>(&permission) };
++ slotObject->call(const_cast<QObject *>(context.data()), args);
++ }
++ }
++
++ private:
++ QtPrivate::SlotObjUniquePtr slotObject;
++ QPointer<const QObject> context;
++ };
++
++ // ### use unique_ptr once PermissionCallback is a move_only function
++ auto receiver = std::make_shared<PermissionReceiver>(std::move(slotObj), context);
++
++ QPermissions::Private::requestPermission(requestedPermission,
++ [=, receiver = std::move(receiver)](Qt::PermissionStatus status) mutable {
++ if (status == Qt::PermissionStatus::Undetermined) {
++ Q_ASSERT_X(false, "QPermission",
++ "Internal error: requestPermission() should never return Undetermined");
++ status = Qt::PermissionStatus::Denied;
++ }
++
++ if (QCoreApplication::self) {
++ QPermission permission = requestedPermission;
++ permission.m_status = status;
++ auto receiverObject = receiver.get();
++ QMetaObject::invokeMethod(receiverObject,
++ [receiver = std::move(receiver), permission] {
++ receiver->finalizePermissionRequest(permission);
++ }, Qt::QueuedConnection);
++ }
++ });
++ }
++
++ #endif // QT_CONFIG(permissions)
++
++ #if QT_CONFIG(library)
++ static QStringList libraryPathsLocked();
++
++ /*!
++ 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 directories for plugins if
++ they exist (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.
++
++ \warning This function does not currently include QLibraryInfo::LibrariesPath
++ in its default paths, and QLibrary does not currently use this function to look
++ up non-absolute library paths.
++
++ \sa setLibraryPaths(), addLibraryPath(), removeLibraryPath(), QLibrary,
++ {How to Create Qt Plugins}
++ */
++ QStringList QCoreApplication::libraryPaths()
++ {
++ QMutexLocker locker(&coreappdata->libraryPathMutex);
++ return libraryPathsLocked();
++ }
++
++ /*!
++ \internal
++ */
++ static QStringList libraryPathsLocked()
++ {
++ QCoreApplicationData *d = coreappdata;
++ if (d->libPathsManuallySet())
++ return d->manual_libpaths;
++
++ QStringList *app_libpaths = &d->app_libpaths;
++ if (!d->libPathsInitialized()) {
++
++ auto setPathsFromEnv = [&](QString libPathEnv) {
++ if (!libPathEnv.isEmpty()) {
++ QStringList paths = libPathEnv.split(QDir::listSeparator(), Qt::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"));
++
++ const auto pluginPaths = QLibraryInfo::paths(QLibraryInfo::PluginsPath);
++ for (auto path : pluginPaths) {
++ if (QFile::exists(path)) {
++ // Make sure we convert from backslashes to slashes.
++ path = QDir(path).canonicalPath();
++ if (!app_libpaths->contains(path))
++ app_libpaths->append(path);
++ }
++ }
++
++ // If QCoreApplication is not yet instantiated,
++ // make sure we add the application path when we construct the QCoreApplication
++ if (qApp) {
++ QString app_location = QCoreApplication::applicationFilePath();
++ app_location.truncate(app_location.lastIndexOf(u'/'));
++ app_location = QDir(app_location).canonicalPath();
++ if (QFile::exists(app_location) && !app_libpaths->contains(app_location))
++ app_libpaths->append(app_location);
++ }
++ if (app_libpaths->isEmpty())
++ app_libpaths->reserve(1); // detach from null
++ Q_ASSERT(d->libPathsInitialized());
++ }
++ return *app_libpaths;
++ }
++
++
++
++ /*!
++
++ Sets the list of directories to search when loading plugins with
++ QLibrary to \a paths. All existing paths will be deleted and the
++ path list will consist of the paths given in \a paths and the path
++ to the application.
++
++ The library paths are reset to the default when an instance of
++ QCoreApplication is destructed.
++
++ \warning QLibrary does not currently use the given paths to look
++ up non-absolute library paths.
++
++ \sa libraryPaths(), addLibraryPath(), removeLibraryPath(), QLibrary
++ */
++ void QCoreApplication::setLibraryPaths(const QStringList &paths)
++ {
++ QCoreApplicationData *d = coreappdata;
++ QMutexLocker locker(&d->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 (!d->libPathsInitialized())
++ libraryPathsLocked();
++
++ d->manual_libpaths = paths;
++ if (d->manual_libpaths.isEmpty())
++ d->manual_libpaths.reserve(1); // detach from null
++ Q_ASSERT(d->libPathsManuallySet());
++
++ 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 one or two entries. The first is the
++ installation directory for plugins, which is \c INSTALL/plugins, where \c
++ INSTALL is the directory where Qt was installed. The second is the
++ application's own directory (\b not the current directory), but only after
++ the QCoreApplication object is instantiated.
++
++ The library paths are reset to the default when an instance of
++ QCoreApplication is destructed.
++
++ \warning QLibrary does not currently use the given path to look
++ up non-absolute library paths.
++
++ \sa removeLibraryPath(), libraryPaths(), setLibraryPaths()
++ */
++ void QCoreApplication::addLibraryPath(const QString &path)
++ {
++ if (path.isEmpty())
++ return;
++
++ QString canonicalPath = QDir(path).canonicalPath();
++ if (canonicalPath.isEmpty())
++ return;
++
++ QCoreApplicationData *d = coreappdata;
++ QMutexLocker locker(&d->libraryPathMutex);
++
++ QStringList *libpaths = &d->manual_libpaths;
++ if (d->libPathsManuallySet()) {
++ if (d->manual_libpaths.contains(canonicalPath))
++ return;
++ } else {
++ // make sure that library paths are initialized
++ libraryPathsLocked();
++ QStringList *app_libpaths = &d->app_libpaths;
++ if (app_libpaths->contains(canonicalPath))
++ return;
++
++ *libpaths = *app_libpaths;
++ }
++
++ libpaths->prepend(canonicalPath);
++ Q_ASSERT(d->libPathsManuallySet());
++ 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.
++
++ \warning QLibrary does not currently use libraryPaths()
++ to look up non-absolute library paths.
++
++ \sa addLibraryPath(), libraryPaths(), setLibraryPaths()
++ */
++ void QCoreApplication::removeLibraryPath(const QString &path)
++ {
++ if (path.isEmpty())
++ return;
++
++ QString canonicalPath = QDir(path).canonicalPath();
++ if (canonicalPath.isEmpty())
++ return;
++
++ QCoreApplicationData *d = coreappdata;
++ QMutexLocker locker(&d->libraryPathMutex);
++
++ QStringList *libpaths = &d->manual_libpaths;
++ if (d->libPathsManuallySet()) {
++ if (libpaths->removeAll(canonicalPath) == 0)
++ return;
++ } else {
++ // make sure that library paths is initialized
++ libraryPathsLocked();
++ QStringList *app_libpaths = &d->app_libpaths;
++ if (!app_libpaths->contains(canonicalPath))
++ return;
++
++ *libpaths = *app_libpaths;
++ libpaths->removeAll(canonicalPath);
++ Q_ASSERT(d->libPathsManuallySet());
++ }
++
++ 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(QCoreApplicationPrivate::theMainThread.loadAcquire());
++ if (!filterObject || !eventDispatcher)
++ return;
++ eventDispatcher->removeNativeEventFilter(filterObject);
++ }
++
++ /*!
++ 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 nullptr;
++ }
++
++ /*!
++ 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);
++ }
++
++ void QCoreApplicationPrivate::destroyEventDispatcher()
++ {
++ // This function is called by either ~QCoreApplication or ~QGuiApplication
++ QThreadData *data = QThreadData::current();
++ Q_ASSERT(data->eventDispatcher.loadAcquire() == eventDispatcher);
++
++ // same sequence as QThread::finish() or cleanup(): first we set the
++ // global(s) to nullptr, then we emit the signal, then we delete.
++ QAbstractEventDispatcher *dispatcher = eventDispatcher;
++ eventDispatcher = nullptr;
++ data->eventDispatcher.storeRelaxed(nullptr);
++ if (dispatcher) {
++ dispatcher->closingDown();
++ delete dispatcher;
++ }
++ }
++ #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 the
++ translation function \c tr() with this signature:
++
++ \snippet code/src_corelib_kernel_qcoreapplication.cpp 6
++
++ This macro is useful if you want to use QObject::tr() 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()
++ */
++
++ void *QCoreApplication::resolveInterface(const char *name, int revision) const
++ {
++ #if defined(Q_OS_ANDROID)
++ // The QAndroidApplication is wrongly using static methods for
++ // its native interface (QTBUG-128796). Until we fix that we at
++ // least want the preferred way of resolving a native interface
++ // to work, so provide a minimal subclass of the interface.
++ using namespace QNativeInterface;
++ struct AndroidApplication : public QAndroidApplication {};
++ static AndroidApplication androidApplication;
++ QT_NATIVE_INTERFACE_RETURN_IF(QAndroidApplication, &androidApplication);
++ #endif
++ #if defined(Q_OS_HARMONY)
++ using namespace QNativeInterface;
++ struct HarmonyApplication : public QHarmonyApplication {};
++ static HarmonyApplication harmonyApplication;
++ QT_NATIVE_INTERFACE_RETURN_IF(QHarmonyApplication, &harmonyApplication);
++ #endif
++ Q_UNUSED(name); Q_UNUSED(revision);
++ return nullptr;
++ }
++
++ QT_END_NAMESPACE
++
++ #ifndef QT_NO_QOBJECT
++ #include "moc_qcoreapplication.cpp"
++ #endif