qtbase/src/corelib/kernel/qcoreapplication.h

268 lines
9.2 KiB
C
Raw Normal View History

/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCOREAPPLICATION_H
#define QCOREAPPLICATION_H
#include <QtCore/qglobal.h>
#include <QtCore/qstring.h>
#ifndef QT_NO_QOBJECT
#include <QtCore/qcoreevent.h>
#include <QtCore/qeventloop.h>
#if QT_CONFIG(future)
#include <QtCore/qfuture.h>
#include <QtCore/qpermission.h>
#endif
#include <QtCore/qobject.h>
#else
#include <QtCore/qscopedpointer.h>
#endif
Rejig native interface plumbing The initial approach for providing public access to native interfaces via T::nativeInteface<I>() was based on the template not being defined, and then having explicit instantiations of the supported types in a source file, so that the accessors were exported and available to the user. This worked fine for "simple" types such as QOpenGLContext and QOffscreenSurface, but presented a problem in the context of classes with subclasses, such as Q{Core,Gui}Application. To ensure that a native interface for QCoreApplication was accessible both from QCoreApplication and its subclasses, while at the same time preventing a native interface for QGuiApplication to be accessible for QCoreApplication, the nativeInterface() template function had to be declared in each subclass. Which in turn meant specializing each native interface once for each subclass it was available in. This quickly became tedious to manage, and the requirements for exposing a new native interface wasn't very clear with all these template specializations and explicit instantiations spread around. To improve on this situation, while also squashing a few other birds at the same time, we change the approach to use type erasure. The definition of T::nativeInteface<I>() is now inline, passing on the requested interface to a per type (T, not I) helper function, with the interface type flattened to a std::type_info. The type_info requested by the user is then compared to the available types in a single per-type (T) "switch statement", which is a lot easier to follow for someone trying to trace the logic of how a native interface is resolved. We can safely rely on type_info being stable between the user application and the Qt library as a result of exporting the type info for each native interface, by explicitly ensuring they have a key function. This is the same mechanism that ensures we can safely dynamic_cast these interfaces, even across library boundaries. The use of a free standing templated helper function instead of a member function in the type T, is to avoid shadowing issues, and to not pollute the class namespace of T with the helper function. Since we are already changing the plumbing for how a user resolves a native interface for a type T, we take the opportunity to add a few extra safeguards to the machinery. First, we add a static assert in the T::nativeInteface<I>() definition, that ensures that only compatible interfaces, as declared by the interface themselves, are allowed. This ensures a compile time error when an incompatible interface is requested, which improves on the link time errors we had prior to this patch, and also offsets the one downside of type erasure, namely that errors are only caught at runtime. Secondly, each interface meant for public consumption through T::nativeInteface<I>() is declared with a revision, which is checked when requesting the interface. This allows us to bump the revision when we make breaking changes to the interface that would have otherwise been binary incompatible. Since the user will never see this interface due to the revision check, they will not end up calling methods that have been removed or renamed. One advantage of moving to a type-erased approach for the plumbing is that we're not longer exposing the native interface types as part of the T::nativeInteface symbols. This means that if we ever want to rename a native interface, the only exported symbol that the user code relies on is the type info. Renaming is then possible by just exporting the type info for the old interface, but leaving it empty. Since no class in Qt implements the old native interface, the user will just get a nullptr back, similarly to bumping the revision of an interface. Change-Id: Ie50d8fb536aafe2836370caacb22afbcfaf1712a Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
2021-05-07 11:16:36 +00:00
#include <QtCore/qnativeinterface.h>
#ifndef QT_NO_DEBUGSTREAM
#include <QtCore/qdebug.h>
#endif
#ifndef QT_NO_QOBJECT
#if defined(Q_OS_WIN) && !defined(tagMSG)
typedef struct tagMSG MSG;
#endif
#endif
QT_BEGIN_NAMESPACE
class QCoreApplicationPrivate;
class QTranslator;
class QPostEventList;
class QAbstractEventDispatcher;
class QAbstractNativeEventFilter;
#define qApp QCoreApplication::instance()
class Q_CORE_EXPORT QCoreApplication
#ifndef QT_NO_QOBJECT
: public QObject
#endif
{
#ifndef QT_NO_QOBJECT
Q_OBJECT
Q_PROPERTY(QString applicationName READ applicationName WRITE setApplicationName NOTIFY applicationNameChanged)
Q_PROPERTY(QString applicationVersion READ applicationVersion WRITE setApplicationVersion NOTIFY applicationVersionChanged)
Q_PROPERTY(QString organizationName READ organizationName WRITE setOrganizationName NOTIFY organizationNameChanged)
Q_PROPERTY(QString organizationDomain READ organizationDomain WRITE setOrganizationDomain NOTIFY organizationDomainChanged)
Q_PROPERTY(bool quitLockEnabled READ isQuitLockEnabled WRITE setQuitLockEnabled)
#endif
Q_DECLARE_PRIVATE(QCoreApplication)
public:
enum { ApplicationFlags = QT_VERSION
};
QCoreApplication(int &argc, char **argv
#ifndef Q_QDOC
, int = ApplicationFlags
#endif
);
~QCoreApplication();
static QStringList arguments();
static void setAttribute(Qt::ApplicationAttribute attribute, bool on = true);
static bool testAttribute(Qt::ApplicationAttribute attribute);
static void setOrganizationDomain(const QString &orgDomain);
static QString organizationDomain();
static void setOrganizationName(const QString &orgName);
static QString organizationName();
static void setApplicationName(const QString &application);
static QString applicationName();
static void setApplicationVersion(const QString &version);
static QString applicationVersion();
static void setSetuidAllowed(bool allow);
static bool isSetuidAllowed();
static QCoreApplication *instance() { return self; }
#ifndef QT_NO_QOBJECT
static int exec();
static void processEvents(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents);
static void processEvents(QEventLoop::ProcessEventsFlags flags, int maxtime);
static bool sendEvent(QObject *receiver, QEvent *event);
static void postEvent(QObject *receiver, QEvent *event, int priority = Qt::NormalEventPriority);
static void sendPostedEvents(QObject *receiver = nullptr, int event_type = 0);
static void removePostedEvents(QObject *receiver, int eventType = 0);
static QAbstractEventDispatcher *eventDispatcher();
static void setEventDispatcher(QAbstractEventDispatcher *eventDispatcher);
virtual bool notify(QObject *, QEvent *);
static bool startingUp();
static bool closingDown();
#endif
static QString applicationDirPath();
static QString applicationFilePath();
static qint64 applicationPid() Q_DECL_CONST_FUNCTION;
#if QT_CONFIG(library)
static void setLibraryPaths(const QStringList &);
static QStringList libraryPaths();
static void addLibraryPath(const QString &);
static void removeLibraryPath(const QString &);
#endif // QT_CONFIG(library)
#ifndef QT_NO_TRANSLATION
static bool installTranslator(QTranslator * messageFile);
static bool removeTranslator(QTranslator * messageFile);
#endif
static QString translate(const char * context,
const char * key,
const char * disambiguation = nullptr,
int n = -1);
Rejig native interface plumbing The initial approach for providing public access to native interfaces via T::nativeInteface<I>() was based on the template not being defined, and then having explicit instantiations of the supported types in a source file, so that the accessors were exported and available to the user. This worked fine for "simple" types such as QOpenGLContext and QOffscreenSurface, but presented a problem in the context of classes with subclasses, such as Q{Core,Gui}Application. To ensure that a native interface for QCoreApplication was accessible both from QCoreApplication and its subclasses, while at the same time preventing a native interface for QGuiApplication to be accessible for QCoreApplication, the nativeInterface() template function had to be declared in each subclass. Which in turn meant specializing each native interface once for each subclass it was available in. This quickly became tedious to manage, and the requirements for exposing a new native interface wasn't very clear with all these template specializations and explicit instantiations spread around. To improve on this situation, while also squashing a few other birds at the same time, we change the approach to use type erasure. The definition of T::nativeInteface<I>() is now inline, passing on the requested interface to a per type (T, not I) helper function, with the interface type flattened to a std::type_info. The type_info requested by the user is then compared to the available types in a single per-type (T) "switch statement", which is a lot easier to follow for someone trying to trace the logic of how a native interface is resolved. We can safely rely on type_info being stable between the user application and the Qt library as a result of exporting the type info for each native interface, by explicitly ensuring they have a key function. This is the same mechanism that ensures we can safely dynamic_cast these interfaces, even across library boundaries. The use of a free standing templated helper function instead of a member function in the type T, is to avoid shadowing issues, and to not pollute the class namespace of T with the helper function. Since we are already changing the plumbing for how a user resolves a native interface for a type T, we take the opportunity to add a few extra safeguards to the machinery. First, we add a static assert in the T::nativeInteface<I>() definition, that ensures that only compatible interfaces, as declared by the interface themselves, are allowed. This ensures a compile time error when an incompatible interface is requested, which improves on the link time errors we had prior to this patch, and also offsets the one downside of type erasure, namely that errors are only caught at runtime. Secondly, each interface meant for public consumption through T::nativeInteface<I>() is declared with a revision, which is checked when requesting the interface. This allows us to bump the revision when we make breaking changes to the interface that would have otherwise been binary incompatible. Since the user will never see this interface due to the revision check, they will not end up calling methods that have been removed or renamed. One advantage of moving to a type-erased approach for the plumbing is that we're not longer exposing the native interface types as part of the T::nativeInteface symbols. This means that if we ever want to rename a native interface, the only exported symbol that the user code relies on is the type info. Renaming is then possible by just exporting the type info for the old interface, but leaving it empty. Since no class in Qt implements the old native interface, the user will just get a nullptr back, similarly to bumping the revision of an interface. Change-Id: Ie50d8fb536aafe2836370caacb22afbcfaf1712a Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
2021-05-07 11:16:36 +00:00
QT_DECLARE_NATIVE_INTERFACE_ACCESSOR
#ifndef QT_NO_QOBJECT
#if QT_CONFIG(future)
static QFuture<QPermission::PermissionResult> requestPermission(
QPermission::PermisionType permission);
static QFuture<QPermission::PermissionResult> requestPermission(const QString &permission);
static QFuture<QPermission::PermissionResult> checkPermission(
QPermission::PermisionType permission);
static QFuture<QPermission::PermissionResult> checkPermission(const QString &permission);
#endif
void installNativeEventFilter(QAbstractNativeEventFilter *filterObj);
void removeNativeEventFilter(QAbstractNativeEventFilter *filterObj);
static bool isQuitLockEnabled();
static void setQuitLockEnabled(bool enabled);
public Q_SLOTS:
static void quit();
static void exit(int retcode = 0);
Q_SIGNALS:
void aboutToQuit(QPrivateSignal);
void organizationNameChanged();
void organizationDomainChanged();
void applicationNameChanged();
void applicationVersionChanged();
protected:
bool event(QEvent *) override;
virtual bool compressEvent(QEvent *, QObject *receiver, QPostEventList *);
#endif // QT_NO_QOBJECT
protected:
QCoreApplication(QCoreApplicationPrivate &p);
#ifdef QT_NO_QOBJECT
QScopedPointer<QCoreApplicationPrivate> d_ptr;
#endif
private:
#ifndef QT_NO_QOBJECT
static bool sendSpontaneousEvent(QObject *receiver, QEvent *event);
static bool notifyInternal2(QObject *receiver, QEvent *);
static bool forwardEvent(QObject *receiver, QEvent *event, QEvent *originatingEvent = nullptr);
#endif
#if QT_CONFIG(library)
static QStringList libraryPathsLocked();
#endif
static QCoreApplication *self;
Q_DISABLE_COPY(QCoreApplication)
friend class QApplication;
friend class QApplicationPrivate;
friend class QGuiApplication;
friend class QGuiApplicationPrivate;
friend class QWidget;
friend class QWidgetWindow;
friend class QWidgetPrivate;
#ifndef QT_NO_QOBJECT
friend class QEventDispatcherUNIXPrivate;
friend class QCocoaEventDispatcherPrivate;
friend bool qt_sendSpontaneousEvent(QObject *, QEvent *);
#endif
friend Q_CORE_EXPORT QString qAppName();
friend class QCommandLineParserPrivate;
};
#define Q_DECLARE_TR_FUNCTIONS(context) \
public: \
static inline QString tr(const char *sourceText, const char *disambiguation = nullptr, int n = -1) \
{ return QCoreApplication::translate(#context, sourceText, disambiguation, n); } \
private:
typedef void (*QtStartUpFunction)();
typedef void (*QtCleanUpFunction)();
Q_CORE_EXPORT void qAddPreRoutine(QtStartUpFunction);
Q_CORE_EXPORT void qAddPostRoutine(QtCleanUpFunction);
Q_CORE_EXPORT void qRemovePostRoutine(QtCleanUpFunction);
Q_CORE_EXPORT QString qAppName(); // get application name
#define Q_COREAPP_STARTUP_FUNCTION(AFUNC) \
static void AFUNC ## _ctor_function() { \
qAddPreRoutine(AFUNC); \
} \
Q_CONSTRUCTOR_FUNCTION(AFUNC ## _ctor_function)
#ifndef QT_NO_QOBJECT
#if defined(Q_OS_WIN) && !defined(QT_NO_DEBUG_STREAM)
Q_CORE_EXPORT QString decodeMSG(const MSG &);
Q_CORE_EXPORT QDebug operator<<(QDebug, const MSG &);
#endif
#endif
QT_END_NAMESPACE
#include <QtCore/qcoreapplication_platform.h>
#endif // QCOREAPPLICATION_H