summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel/qguiapplication.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/kernel/qguiapplication.cpp')
-rw-r--r--src/gui/kernel/qguiapplication.cpp1572
1 files changed, 867 insertions, 705 deletions
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 2df5933879..444091afef 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -1,48 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qguiapplication.h"
#include "private/qguiapplication_p.h"
+#include "private/qabstractfileiconprovider_p.h"
#include <qpa/qplatformintegrationfactory_p.h>
#include "private/qevent_p.h"
+#include "private/qeventpoint_p.h"
+#include "private/qiconloader_p.h"
#include "qfont.h"
#include "qpointingdevice.h"
#include <qpa/qplatformfontdatabase.h>
@@ -50,20 +17,24 @@
#include <qpa/qplatformnativeinterface.h>
#include <qpa/qplatformtheme.h>
#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformkeymapper.h>
#include <QtCore/QAbstractEventDispatcher>
+#include <QtCore/QFileInfo>
#include <QtCore/QStandardPaths>
#include <QtCore/QVariant>
#include <QtCore/private/qcoreapplication_p.h>
#include <QtCore/private/qabstracteventdispatcher_p.h>
+#include <QtCore/private/qminimalflatset_p.h>
#include <QtCore/qmutex.h>
#include <QtCore/private/qthread_p.h>
#include <QtCore/private/qlocking_p.h>
+#include <QtCore/private/qflatmap_p.h>
#include <QtCore/qdir.h>
#include <QtCore/qlibraryinfo.h>
-#include <QtCore/qnumeric.h>
+#include <QtCore/private/qnumeric_p.h>
#include <QtDebug>
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
#include "qaccessible.h"
#endif
#include <qpalette.h>
@@ -74,6 +45,7 @@
#include <QtGui/qgenericpluginfactory.h>
#include <QtGui/qstylehints.h>
+#include <QtGui/private/qstylehints_p.h>
#include <QtGui/qinputmethod.h>
#include <QtGui/qpixmapcache.h>
#include <qpa/qplatforminputcontext.h>
@@ -82,8 +54,11 @@
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qwindowsysteminterface_p.h>
#include "private/qwindow_p.h"
+#include "private/qicon_p.h"
#include "private/qcursor_p.h"
-#include "private/qopenglcontext_p.h"
+#if QT_CONFIG(opengl)
+# include "private/qopenglcontext_p.h"
+#endif
#include "private/qinputdevicemanager_p.h"
#include "private/qinputmethod_p.h"
#include "private/qpointingdevice_p.h"
@@ -120,12 +95,21 @@
#include <emscripten.h>
#endif
+#if QT_CONFIG(vulkan)
+#include <private/qvulkandefaultinstance_p.h>
+#endif
+
#include <qtgui_tracepoints_p.h>
-#include <ctype.h>
+#include <private/qtools_p.h>
+
+#include <limits>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+using namespace QtMiscUtils;
+
// Helper macro for static functions to check on the existence of the application class.
#define CHECK_QAPP_INSTANCE(...) \
if (Q_LIKELY(QCoreApplication::instance())) { \
@@ -135,93 +119,81 @@ QT_BEGIN_NAMESPACE
}
Q_CORE_EXPORT void qt_call_post_routines();
-Q_GUI_EXPORT bool qt_is_gui_used = true;
+Q_CONSTINIT Q_GUI_EXPORT bool qt_is_tty_app = false;
-Qt::MouseButtons QGuiApplicationPrivate::mouse_buttons = Qt::NoButton;
-Qt::KeyboardModifiers QGuiApplicationPrivate::modifier_buttons = Qt::NoModifier;
+Q_CONSTINIT Qt::MouseButtons QGuiApplicationPrivate::mouse_buttons = Qt::NoButton;
+Q_CONSTINIT Qt::KeyboardModifiers QGuiApplicationPrivate::modifier_buttons = Qt::NoModifier;
-QPointF QGuiApplicationPrivate::lastCursorPosition(qInf(), qInf());
+Q_CONSTINIT QGuiApplicationPrivate::QLastCursorPosition QGuiApplicationPrivate::lastCursorPosition;
-QWindow *QGuiApplicationPrivate::currentMouseWindow = nullptr;
+Q_CONSTINIT QWindow *QGuiApplicationPrivate::currentMouseWindow = nullptr;
-QString QGuiApplicationPrivate::styleOverride;
+Q_CONSTINIT QString QGuiApplicationPrivate::styleOverride;
-Qt::ApplicationState QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive;
+Q_CONSTINIT Qt::ApplicationState QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive;
-Qt::HighDpiScaleFactorRoundingPolicy QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy =
-#ifdef Q_OS_ANDROID
- // On Android, Qt has newer rounded the scale factor. Preserve
- // that behavior by disabling rounding by default.
+Q_CONSTINIT Qt::HighDpiScaleFactorRoundingPolicy QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy =
Qt::HighDpiScaleFactorRoundingPolicy::PassThrough;
-#else
- Qt::HighDpiScaleFactorRoundingPolicy::Round;
-#endif
-bool QGuiApplicationPrivate::highDpiScalingUpdated = false;
-
-QPointer<QWindow> QGuiApplicationPrivate::currentDragWindow;
-QList<QGuiApplicationPrivate::TabletPointData> QGuiApplicationPrivate::tabletDevicePoints;
+Q_CONSTINIT QPointer<QWindow> QGuiApplicationPrivate::currentDragWindow;
-QPlatformIntegration *QGuiApplicationPrivate::platform_integration = nullptr;
-QPlatformTheme *QGuiApplicationPrivate::platform_theme = nullptr;
+Q_CONSTINIT QList<QGuiApplicationPrivate::TabletPointData> QGuiApplicationPrivate::tabletDevicePoints; // TODO remove
-QList<QObject *> QGuiApplicationPrivate::generic_plugin_list;
+Q_CONSTINIT QPlatformIntegration *QGuiApplicationPrivate::platform_integration = nullptr;
+Q_CONSTINIT QPlatformTheme *QGuiApplicationPrivate::platform_theme = nullptr;
-#ifndef QT_NO_SESSIONMANAGER
-bool QGuiApplicationPrivate::is_fallback_session_management_enabled = true;
-#endif
+Q_CONSTINIT QList<QObject *> QGuiApplicationPrivate::generic_plugin_list;
enum ApplicationResourceFlags
{
ApplicationFontExplicitlySet = 0x2
};
-static unsigned applicationResourceFlags = 0;
+Q_CONSTINIT static unsigned applicationResourceFlags = 0;
-QIcon *QGuiApplicationPrivate::app_icon = nullptr;
+Q_CONSTINIT QIcon *QGuiApplicationPrivate::app_icon = nullptr;
-QString *QGuiApplicationPrivate::platform_name = nullptr;
-QString *QGuiApplicationPrivate::displayName = nullptr;
-QString *QGuiApplicationPrivate::desktopFileName = nullptr;
+Q_CONSTINIT QString *QGuiApplicationPrivate::platform_name = nullptr;
+Q_CONSTINIT QString *QGuiApplicationPrivate::displayName = nullptr;
+Q_CONSTINIT QString *QGuiApplicationPrivate::desktopFileName = nullptr;
-QPalette *QGuiApplicationPrivate::app_pal = nullptr; // default application palette
+Q_CONSTINIT QPalette *QGuiApplicationPrivate::app_pal = nullptr; // default application palette
-ulong QGuiApplicationPrivate::mousePressTime = 0;
-Qt::MouseButton QGuiApplicationPrivate::mousePressButton = Qt::NoButton;
-int QGuiApplicationPrivate::mousePressX = 0; // TODO use QPointF and store it in QPointingDevicePrivate
-int QGuiApplicationPrivate::mousePressY = 0;
+Q_CONSTINIT Qt::MouseButton QGuiApplicationPrivate::mousePressButton = Qt::NoButton;
-static int mouseDoubleClickDistance = -1;
-static int touchDoubleTapDistance = -1;
+Q_CONSTINIT static int mouseDoubleClickDistance = 0;
+Q_CONSTINIT static int touchDoubleTapDistance = 0;
-QWindow *QGuiApplicationPrivate::currentMousePressWindow = nullptr;
+Q_CONSTINIT QWindow *QGuiApplicationPrivate::currentMousePressWindow = nullptr;
-static Qt::LayoutDirection layout_direction = Qt::LayoutDirectionAuto;
-static bool force_reverse = false;
+Q_CONSTINIT static Qt::LayoutDirection layout_direction = Qt::LayoutDirectionAuto;
+Q_CONSTINIT static Qt::LayoutDirection effective_layout_direction = Qt::LeftToRight;
+Q_CONSTINIT static bool force_reverse = false;
-QGuiApplicationPrivate *QGuiApplicationPrivate::self = nullptr;
-QPointingDevice *QGuiApplicationPrivate::m_fakeTouchDevice = nullptr;
-int QGuiApplicationPrivate::m_fakeMouseSourcePointId = 0;
+Q_CONSTINIT QGuiApplicationPrivate *QGuiApplicationPrivate::self = nullptr;
+Q_CONSTINIT int QGuiApplicationPrivate::m_fakeMouseSourcePointId = -1;
#ifndef QT_NO_CLIPBOARD
-QClipboard *QGuiApplicationPrivate::qt_clipboard = nullptr;
+Q_CONSTINIT QClipboard *QGuiApplicationPrivate::qt_clipboard = nullptr;
#endif
-QList<QScreen *> QGuiApplicationPrivate::screen_list;
+Q_CONSTINIT QList<QScreen *> QGuiApplicationPrivate::screen_list;
-QWindowList QGuiApplicationPrivate::window_list;
-QWindow *QGuiApplicationPrivate::focus_window = nullptr;
+Q_CONSTINIT QWindowList QGuiApplicationPrivate::window_list;
+Q_CONSTINIT QWindow *QGuiApplicationPrivate::focus_window = nullptr;
-static QBasicMutex applicationFontMutex;
-QFont *QGuiApplicationPrivate::app_font = nullptr;
-QStyleHints *QGuiApplicationPrivate::styleHints = nullptr;
-bool QGuiApplicationPrivate::obey_desktop_settings = true;
+Q_CONSTINIT static QBasicMutex applicationFontMutex;
+Q_CONSTINIT QFont *QGuiApplicationPrivate::app_font = nullptr;
+Q_CONSTINIT QStyleHints *QGuiApplicationPrivate::styleHints = nullptr;
+Q_CONSTINIT bool QGuiApplicationPrivate::obey_desktop_settings = true;
-QInputDeviceManager *QGuiApplicationPrivate::m_inputDeviceManager = nullptr;
+Q_CONSTINIT QInputDeviceManager *QGuiApplicationPrivate::m_inputDeviceManager = nullptr;
-qreal QGuiApplicationPrivate::m_maxDevicePixelRatio = 0.0;
+Q_CONSTINIT qreal QGuiApplicationPrivate::m_maxDevicePixelRatio = 0.0;
-static qreal fontSmoothingGamma = 1.7;
+Q_CONSTINIT static qreal fontSmoothingGamma = 1.7;
+
+Q_CONSTINIT bool QGuiApplicationPrivate::quitOnLastWindowClosed = true;
extern void qRegisterGuiVariant();
#if QT_CONFIG(animation)
@@ -234,7 +206,7 @@ static bool qt_detectRTLLanguage()
(QGuiApplication::tr("QT_LAYOUT_DIRECTION",
"Translate this string to the string 'LTR' in left-to-right"
" languages or to 'RTL' in right-to-left languages (such as Hebrew"
- " and Arabic) to get proper widget layout.") == QLatin1String("RTL"));
+ " and Arabic) to get proper widget layout.") == "RTL"_L1);
}
static void initFontUnlocked()
@@ -264,7 +236,7 @@ static void initThemeHints()
static bool checkNeedPortalSupport()
{
#if QT_CONFIG(dbus)
- return !QStandardPaths::locate(QStandardPaths::RuntimeLocation, QLatin1String("flatpak-info")).isEmpty() || qEnvironmentVariableIsSet("SNAP");
+ return QFileInfo::exists("/.flatpak-info"_L1) || qEnvironmentVariableIsSet("SNAP");
#else
return false;
#endif // QT_CONFIG(dbus)
@@ -291,20 +263,20 @@ struct QWindowGeometrySpecification
static inline int nextGeometryToken(const QByteArray &a, int &pos, char *op)
{
*op = 0;
- const int size = a.size();
+ const qsizetype size = a.size();
if (pos >= size)
return -1;
*op = a.at(pos);
if (*op == '+' || *op == '-' || *op == 'x')
pos++;
- else if (isdigit(*op))
+ else if (isAsciiDigit(*op))
*op = 'x'; // If it starts with a digit, it is supposed to be a width specification.
else
return -1;
const int numberPos = pos;
- for ( ; pos < size && isdigit(a.at(pos)); ++pos) ;
+ for ( ; pos < size && isAsciiDigit(a.at(pos)); ++pos) ;
bool ok;
const int result = a.mid(numberPos, pos - numberPos).toInt(&ok);
@@ -473,7 +445,6 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME
postEvent(),
sendPostedEvents(),
removePostedEvents(),
- hasPendingEvents(),
notify().
\row
@@ -593,10 +564,12 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME
\list
\li \c {altgr}, detect the key \c {AltGr} found on some keyboards as
Qt::GroupSwitchModifier (since Qt 5.12).
- \li \c {darkmode=[1|2]} controls how Qt responds to the activation
+ \li \c {darkmode=[0|1|2]} controls how Qt responds to the activation
of the \e{Dark Mode for applications} introduced in Windows 10
1903 (since Qt 5.15).
+ A value of 0 disables dark mode support.
+
A value of 1 causes Qt to switch the window borders to black
when \e{Dark Mode for applications} is activated and no High
Contrast Theme is in use. This is intended for applications
@@ -608,19 +581,17 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME
experimental pending the introduction of new style that
properly adapts to dark mode.
+ As of Qt 6.5, the default value is 2; to disable dark mode
+ support, set the value to 0 or 1.
+
\li \c {dialogs=[xp|none]}, \c xp uses XP-style native dialogs and
\c none disables them.
- \li \c {dpiawareness=[0|1|2]} Sets the DPI awareness of the process
- (see \l{High DPI Displays}, since Qt 5.4).
\li \c {fontengine=freetype}, uses the FreeType font engine.
- \li \c {fontengine=directwrite}, uses the experimental DirectWrite
- font database and defaults to using the DirectWrite font
+ \li \c {fontengine=gdi}, uses the legacy GDI-based
+ font database and defaults to using the GDI font
engine (which is otherwise only used for some font types
- or font properties.) This affects font selection and aims
- to provide font naming more consistent with other platforms,
- but does not support all font formats, such as Postscript
- Type-1 or Microsoft FNT fonts.
+ or font properties.) (Since Qt 6.8).
\li \c {menus=[native|none]}, controls the use of native menus.
Native menus are implemented using Win32 API and are simpler than
@@ -634,7 +605,8 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME
\li \c {nocolorfonts} Turn off DirectWrite Color fonts
(since Qt 5.8).
- \li \c {nodirectwrite} Turn off DirectWrite fonts (since Qt 5.8).
+ \li \c {nodirectwrite} Turn off DirectWrite fonts (since Qt 5.8). This implicitly
+ also selects the GDI font engine.
\li \c {nomousefromtouch} Ignores mouse events synthesized
from touch events by the operating system.
@@ -662,9 +634,9 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME
#ifdef Q_QDOC
QGuiApplication::QGuiApplication(int &argc, char **argv)
#else
-QGuiApplication::QGuiApplication(int &argc, char **argv, int flags)
+QGuiApplication::QGuiApplication(int &argc, char **argv, int)
#endif
- : QCoreApplication(*new QGuiApplicationPrivate(argc, argv, flags))
+ : QCoreApplication(*new QGuiApplicationPrivate(argc, argv))
{
d_func()->init();
@@ -720,21 +692,16 @@ QGuiApplication::~QGuiApplication()
QGuiApplicationPrivate::desktopFileName = nullptr;
QGuiApplicationPrivate::mouse_buttons = Qt::NoButton;
QGuiApplicationPrivate::modifier_buttons = Qt::NoModifier;
- QGuiApplicationPrivate::lastCursorPosition = {qInf(), qInf()};
+ QGuiApplicationPrivate::lastCursorPosition.reset();
QGuiApplicationPrivate::currentMousePressWindow = QGuiApplicationPrivate::currentMouseWindow = nullptr;
QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive;
- QGuiApplicationPrivate::highDpiScalingUpdated = false;
+ QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy = Qt::HighDpiScaleFactorRoundingPolicy::PassThrough;
QGuiApplicationPrivate::currentDragWindow = nullptr;
QGuiApplicationPrivate::tabletDevicePoints.clear();
-#ifndef QT_NO_SESSIONMANAGER
- QGuiApplicationPrivate::is_fallback_session_management_enabled = true;
-#endif
- QGuiApplicationPrivate::mousePressTime = 0;
- QGuiApplicationPrivate::mousePressX = QGuiApplicationPrivate::mousePressY = 0;
}
-QGuiApplicationPrivate::QGuiApplicationPrivate(int &argc, char **argv, int flags)
- : QCoreApplicationPrivate(argc, argv, flags),
+QGuiApplicationPrivate::QGuiApplicationPrivate(int &argc, char **argv)
+ : QCoreApplicationPrivate(argc, argv),
inputMethod(nullptr),
lastTouchType(QEvent::TouchEnd),
ownGlobalShareContext(false)
@@ -783,13 +750,37 @@ QString QGuiApplication::applicationDisplayName()
}
/*!
+ Sets the application's badge to \a number.
+
+ Useful for providing feedback to the user about the number
+ of unread messages or similar.
+
+ The badge will be overlaid on the application's icon in the Dock
+ on \macos, the home screen icon on iOS, or the task bar on Windows
+ and Linux.
+
+ If the number is outside the range supported by the platform, the
+ number will be clamped to the supported range. If the number does
+ not fit within the badge, the number may be visually elided.
+
+ Setting the number to 0 will clear the badge.
+
+ \since 6.5
+ \sa applicationName
+*/
+void QGuiApplication::setBadgeNumber(qint64 number)
+{
+ QGuiApplicationPrivate::platformIntegration()->setApplicationBadge(number);
+}
+
+/*!
\property QGuiApplication::desktopFileName
\brief the base name of the desktop entry for this application
\since 5.7
- This is the file name, without the full path, of the desktop entry
- that represents this application according to the freedesktop desktop
- entry specification.
+ This is the file name, without the full path or the trailing ".desktop"
+ extension of the desktop entry that represents this application
+ according to the freedesktop desktop entry specification.
This property gives a precise indication of what desktop entry represents
the application and it is needed by the windowing system to retrieve
@@ -803,6 +794,15 @@ void QGuiApplication::setDesktopFileName(const QString &name)
if (!QGuiApplicationPrivate::desktopFileName)
QGuiApplicationPrivate::desktopFileName = new QString;
*QGuiApplicationPrivate::desktopFileName = name;
+ if (name.endsWith(QLatin1String(".desktop"))) { // ### Qt 7: remove
+ const QString filePath = QStandardPaths::locate(QStandardPaths::ApplicationsLocation, name);
+ if (!filePath.isEmpty()) {
+ qWarning("QGuiApplication::setDesktopFileName: the specified desktop file name "
+ "ends with .desktop. For compatibility reasons, the .desktop suffix will "
+ "be removed. Please specify a desktop file name without .desktop suffix");
+ (*QGuiApplicationPrivate::desktopFileName).chop(8);
+ }
+ }
}
QString QGuiApplication::desktopFileName()
@@ -829,7 +829,7 @@ QWindow *QGuiApplication::modalWindow()
CHECK_QAPP_INSTANCE(nullptr)
if (QGuiApplicationPrivate::self->modalWindowList.isEmpty())
return nullptr;
- return QGuiApplicationPrivate::self->modalWindowList.first();
+ return QGuiApplicationPrivate::self->modalWindowList.constFirst();
}
static void updateBlockedStatusRecursion(QWindow *window, bool shouldBeBlocked)
@@ -880,7 +880,7 @@ void QGuiApplicationPrivate::showModalWindow(QWindow *modal)
}
}
- for (QWindow *window : qAsConst(QGuiApplicationPrivate::window_list)) {
+ for (QWindow *window : std::as_const(QGuiApplicationPrivate::window_list)) {
if (needsWindowBlockedEvent(window) && !window->d_func()->blockedByModalWindow)
updateBlockedStatus(window);
}
@@ -892,12 +892,23 @@ void QGuiApplicationPrivate::hideModalWindow(QWindow *window)
{
self->modalWindowList.removeAll(window);
- for (QWindow *window : qAsConst(QGuiApplicationPrivate::window_list)) {
+ for (QWindow *window : std::as_const(QGuiApplicationPrivate::window_list)) {
if (needsWindowBlockedEvent(window) && window->d_func()->blockedByModalWindow)
updateBlockedStatus(window);
}
}
+Qt::WindowModality QGuiApplicationPrivate::defaultModality() const
+{
+ return Qt::NonModal;
+}
+
+bool QGuiApplicationPrivate::windowNeverBlocked(QWindow *window) const
+{
+ Q_UNUSED(window);
+ return false;
+}
+
/*
Returns \c true if \a window is blocked by a modal window. If \a
blockingWindow is non-zero, *blockingWindow will be set to the blocking
@@ -905,55 +916,40 @@ void QGuiApplicationPrivate::hideModalWindow(QWindow *window)
*/
bool QGuiApplicationPrivate::isWindowBlocked(QWindow *window, QWindow **blockingWindow) const
{
+ Q_ASSERT_X(window, Q_FUNC_INFO, "The window must not be null");
+
QWindow *unused = nullptr;
if (!blockingWindow)
blockingWindow = &unused;
+ *blockingWindow = nullptr;
- if (modalWindowList.isEmpty()) {
- *blockingWindow = nullptr;
+ if (modalWindowList.isEmpty() || windowNeverBlocked(window))
return false;
- }
- for (int i = 0; i < modalWindowList.count(); ++i) {
+ for (int i = 0; i < modalWindowList.size(); ++i) {
QWindow *modalWindow = modalWindowList.at(i);
// A window is not blocked by another modal window if the two are
// the same, or if the window is a child of the modal window.
- if (window == modalWindow || modalWindow->isAncestorOf(window, QWindow::IncludeTransients)) {
- *blockingWindow = nullptr;
+ if (window == modalWindow || modalWindow->isAncestorOf(window, QWindow::IncludeTransients))
return false;
- }
- Qt::WindowModality windowModality = modalWindow->modality();
- switch (windowModality) {
+ switch (modalWindow->modality() == Qt::NonModal ? defaultModality()
+ : modalWindow->modality()) {
case Qt::ApplicationModal:
- {
- if (modalWindow != window) {
- *blockingWindow = modalWindow;
- return true;
- }
- break;
- }
- case Qt::WindowModal:
- {
- QWindow *w = window;
+ *blockingWindow = modalWindow;
+ return true;
+ case Qt::WindowModal: {
+ // Find the nearest ancestor of window which is also an ancestor of modal window to
+ // determine if the modal window blocks the window.
+ auto *current = window;
do {
- QWindow *m = modalWindow;
- do {
- if (m == w) {
- *blockingWindow = m;
- return true;
- }
- QWindow *p = m->parent();
- if (!p)
- p = m->transientParent();
- m = p;
- } while (m);
- QWindow *p = w->parent();
- if (!p)
- p = w->transientParent();
- w = p;
- } while (w);
+ if (current->isAncestorOf(modalWindow, QWindow::IncludeTransients)) {
+ *blockingWindow = modalWindow;
+ return true;
+ }
+ current = current->parent(QWindow::IncludeTransients);
+ } while (current);
break;
}
default:
@@ -961,13 +957,14 @@ bool QGuiApplicationPrivate::isWindowBlocked(QWindow *window, QWindow **blocking
break;
}
}
- *blockingWindow = nullptr;
return false;
}
/*!
Returns the QWindow that receives events tied to focus,
such as key events.
+
+ \sa QWindow::requestActivate()
*/
QWindow *QGuiApplication::focusWindow()
{
@@ -1145,7 +1142,7 @@ qreal QGuiApplication::devicePixelRatio() const
return QGuiApplicationPrivate::m_maxDevicePixelRatio;
QGuiApplicationPrivate::m_maxDevicePixelRatio = 1.0; // make sure we never return 0.
- for (QScreen *screen : qAsConst(QGuiApplicationPrivate::screen_list))
+ for (QScreen *screen : std::as_const(QGuiApplicationPrivate::screen_list))
QGuiApplicationPrivate::m_maxDevicePixelRatio = qMax(QGuiApplicationPrivate::m_maxDevicePixelRatio, screen->devicePixelRatio());
return QGuiApplicationPrivate::m_maxDevicePixelRatio;
@@ -1192,31 +1189,50 @@ QWindow *QGuiApplication::topLevelAt(const QPoint &pos)
\li \c offscreen
\li \c qnx
\li \c windows
- \li \c wayland is a platform plugin for modern Linux desktops and some
- embedded systems.
- \li \c xcb is the X11 plugin used on regular desktop Linux platforms.
+ \li \c wayland is a platform plugin for the Wayland display server protocol,
+ used on some Linux desktops and embedded systems.
+ \li \c xcb is a plugin for the X11 window system, used on some desktop Linux platforms.
\endlist
+ \note Calling this function without a QGuiApplication will return the default
+ platform name, if available. The default platform name is not affected by the
+ \c{-platform} command line option, or the \c QT_QPA_PLATFORM environment variable.
+
For more information about the platform plugins for embedded Linux devices,
see \l{Qt for Embedded Linux}.
*/
QString QGuiApplication::platformName()
{
- return QGuiApplicationPrivate::platform_name ?
- *QGuiApplicationPrivate::platform_name : QString();
+ if (!QGuiApplication::instance()) {
+#ifdef QT_QPA_DEFAULT_PLATFORM_NAME
+ return QStringLiteral(QT_QPA_DEFAULT_PLATFORM_NAME);
+#else
+ return QString();
+#endif
+ } else {
+ return QGuiApplicationPrivate::platform_name ?
+ *QGuiApplicationPrivate::platform_name : QString();
+ }
}
Q_LOGGING_CATEGORY(lcQpaPluginLoading, "qt.qpa.plugin");
+Q_LOGGING_CATEGORY(lcQpaTheme, "qt.qpa.theme");
+Q_LOGGING_CATEGORY(lcPtrDispatch, "qt.pointer.dispatch");
static void init_platform(const QString &pluginNamesWithArguments, const QString &platformPluginPath, const QString &platformThemeName, int &argc, char **argv)
{
- QStringList plugins = pluginNamesWithArguments.split(QLatin1Char(';'), Qt::SkipEmptyParts);
+ qCDebug(lcQpaPluginLoading) << "init_platform called with"
+ << "pluginNamesWithArguments" << pluginNamesWithArguments
+ << "platformPluginPath" << platformPluginPath
+ << "platformThemeName" << platformThemeName;
+
+ QStringList plugins = pluginNamesWithArguments.split(u';', Qt::SkipEmptyParts);
QStringList platformArguments;
QStringList availablePlugins = QPlatformIntegrationFactory::keys(platformPluginPath);
for (const auto &pluginArgument : plugins) {
// Split into platform name and arguments
- QStringList arguments = pluginArgument.split(QLatin1Char(':'), Qt::SkipEmptyParts);
+ QStringList arguments = pluginArgument.split(u':', Qt::SkipEmptyParts);
if (arguments.isEmpty())
continue;
const QString name = arguments.takeFirst().toLower();
@@ -1226,10 +1242,16 @@ static void init_platform(const QString &pluginNamesWithArguments, const QString
argumentsKey[0] = argumentsKey.at(0).toUpper();
arguments.append(QLibraryInfo::platformPluginArguments(argumentsKey));
+ qCDebug(lcQpaPluginLoading) << "Attempting to load Qt platform plugin" << name << "with arguments" << arguments;
+
// Create the platform integration.
QGuiApplicationPrivate::platform_integration = QPlatformIntegrationFactory::create(name, arguments, argc, argv, platformPluginPath);
if (Q_UNLIKELY(!QGuiApplicationPrivate::platform_integration)) {
if (availablePlugins.contains(name)) {
+ if (name == QStringLiteral("xcb") && QVersionNumber::compare(QLibraryInfo::version(), QVersionNumber(6, 5, 0)) >= 0) {
+ qCWarning(lcQpaPluginLoading).nospace().noquote()
+ << "From 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to load the Qt xcb platform plugin.";
+ }
qCInfo(lcQpaPluginLoading).nospace().noquote()
<< "Could not load the Qt platform plugin \"" << name << "\" in \""
<< QDir::toNativeSeparators(platformPluginPath) << "\" even though it was found.";
@@ -1239,6 +1261,7 @@ static void init_platform(const QString &pluginNamesWithArguments, const QString
<< QDir::toNativeSeparators(platformPluginPath) << "\"";
}
} else {
+ qCDebug(lcQpaPluginLoading) << "Successfully loaded Qt platform plugin" << name;
QGuiApplicationPrivate::platform_name = new QString(name);
platformArguments = arguments;
break;
@@ -1250,7 +1273,7 @@ static void init_platform(const QString &pluginNamesWithArguments, const QString
"Reinstalling the application may fix this problem.\n");
if (!availablePlugins.isEmpty())
- fatalMessage += QStringLiteral("\nAvailable platform plugins are: %1.\n").arg(availablePlugins.join(QLatin1String(", ")));
+ fatalMessage += "\nAvailable platform plugins are: %1.\n"_L1.arg(availablePlugins.join(", "_L1));
#if defined(Q_OS_WIN)
// Windows: Display message box unless it is a console application
@@ -1263,56 +1286,61 @@ static void init_platform(const QString &pluginNamesWithArguments, const QString
return;
}
- // Many platforms have created QScreens at this point. Finish initializing
- // QHighDpiScaling to be prepared for early calls to qt_defaultDpi().
- if (QGuiApplication::primaryScreen()) {
- QGuiApplicationPrivate::highDpiScalingUpdated = true;
- QHighDpiScaling::updateHighDpiScaling();
- }
-
// Create the platform theme:
// 1) Fetch the platform name from the environment if present.
QStringList themeNames;
- if (!platformThemeName.isEmpty())
+ if (!platformThemeName.isEmpty()) {
+ qCDebug(lcQpaTheme) << "Adding" << platformThemeName << "from environment to list of theme names";
themeNames.append(platformThemeName);
+ }
// 2) Special case - check whether it's a flatpak or snap app to use xdg-desktop-portal platform theme for portals support
if (checkNeedPortalSupport()) {
+ qCDebug(lcQpaTheme) << "Adding xdgdesktopportal to list of theme names";
themeNames.append(QStringLiteral("xdgdesktopportal"));
}
// 3) Ask the platform integration for a list of theme names
- themeNames += QGuiApplicationPrivate::platform_integration->themeNames();
+ const auto platformIntegrationThemeNames = QGuiApplicationPrivate::platform_integration->themeNames();
+ qCDebug(lcQpaTheme) << "Adding platform integration's theme names to list of theme names:" << platformIntegrationThemeNames;
+ themeNames += platformIntegrationThemeNames;
// 4) Look for a theme plugin.
- for (const QString &themeName : qAsConst(themeNames)) {
+ for (const QString &themeName : std::as_const(themeNames)) {
+ qCDebug(lcQpaTheme) << "Attempting to create platform theme" << themeName << "via QPlatformThemeFactory::create";
QGuiApplicationPrivate::platform_theme = QPlatformThemeFactory::create(themeName, platformPluginPath);
- if (QGuiApplicationPrivate::platform_theme)
+ if (QGuiApplicationPrivate::platform_theme) {
+ qCDebug(lcQpaTheme) << "Successfully created platform theme" << themeName;
break;
+ }
}
// 5) If no theme plugin was found ask the platform integration to
// create a theme
if (!QGuiApplicationPrivate::platform_theme) {
- for (const QString &themeName : qAsConst(themeNames)) {
+ for (const QString &themeName : std::as_const(themeNames)) {
+ qCDebug(lcQpaTheme) << "Attempting to create platform theme" << themeName << "via createPlatformTheme";
QGuiApplicationPrivate::platform_theme = QGuiApplicationPrivate::platform_integration->createPlatformTheme(themeName);
- if (QGuiApplicationPrivate::platform_theme)
+ if (QGuiApplicationPrivate::platform_theme) {
+ qCDebug(lcQpaTheme) << "Successfully created platform theme" << themeName;
break;
+ }
}
// No error message; not having a theme plugin is allowed.
}
// 6) Fall back on the built-in "null" platform theme.
- if (!QGuiApplicationPrivate::platform_theme)
+ if (!QGuiApplicationPrivate::platform_theme) {
+ qCDebug(lcQpaTheme) << "Failed to create platform theme; using \"null\" platform theme";
QGuiApplicationPrivate::platform_theme = new QPlatformTheme;
+ }
-#ifndef QT_NO_PROPERTIES
// Set arguments as dynamic properties on the native interface as
// boolean 'foo' or strings: 'foo=bar'
if (!platformArguments.isEmpty()) {
if (QObject *nativeInterface = QGuiApplicationPrivate::platform_integration->nativeInterface()) {
- for (const QString &argument : qAsConst(platformArguments)) {
- const int equalsPos = argument.indexOf(QLatin1Char('='));
+ for (const QString &argument : std::as_const(platformArguments)) {
+ const qsizetype equalsPos = argument.indexOf(u'=');
const QByteArray name =
equalsPos != -1 ? argument.left(equalsPos).toUtf8() : argument.toUtf8();
const QVariant value =
@@ -1321,22 +1349,24 @@ static void init_platform(const QString &pluginNamesWithArguments, const QString
}
}
}
-#endif
- fontSmoothingGamma = QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::FontSmoothingGamma).toReal();
+ const auto platformIntegration = QGuiApplicationPrivate::platformIntegration();
+ fontSmoothingGamma = platformIntegration->styleHint(QPlatformIntegration::FontSmoothingGamma).toReal();
+ QCoreApplication::setAttribute(Qt::AA_DontShowShortcutsInContextMenus,
+ !QGuiApplication::styleHints()->showShortcutsInContextMenus());
}
static void init_plugins(const QList<QByteArray> &pluginList)
{
- for (int i = 0; i < pluginList.count(); ++i) {
+ for (int i = 0; i < pluginList.size(); ++i) {
QByteArray pluginSpec = pluginList.at(i);
- int colonPos = pluginSpec.indexOf(':');
+ qsizetype colonPos = pluginSpec.indexOf(':');
QObject *plugin;
if (colonPos < 0)
- plugin = QGenericPluginFactory::create(QLatin1String(pluginSpec), QString());
+ plugin = QGenericPluginFactory::create(QLatin1StringView(pluginSpec), QString());
else
- plugin = QGenericPluginFactory::create(QLatin1String(pluginSpec.mid(0, colonPos)),
- QLatin1String(pluginSpec.mid(colonPos+1)));
+ plugin = QGenericPluginFactory::create(QLatin1StringView(pluginSpec.mid(0, colonPos)),
+ QLatin1StringView(pluginSpec.mid(colonPos+1)));
if (plugin)
QGuiApplicationPrivate::generic_plugin_list.append(plugin);
else
@@ -1389,11 +1419,11 @@ void QGuiApplicationPrivate::addQtOptions(QList<QCommandLineOption> *options)
QGuiApplication::tr("ID of the X11 Visual to use."), QStringLiteral("id")));
// Not using the "QStringList names" solution for those aliases, because it makes the first column too wide
options->append(QCommandLineOption(QStringLiteral("geometry"),
- QGuiApplication::tr("Alias for --windowgeometry."), QStringLiteral("geometry")));
+ QGuiApplication::tr("Alias for --qwindowgeometry."), QStringLiteral("geometry")));
options->append(QCommandLineOption(QStringLiteral("icon"),
- QGuiApplication::tr("Alias for --windowicon."), QStringLiteral("icon")));
+ QGuiApplication::tr("Alias for --qwindowicon."), QStringLiteral("icon")));
options->append(QCommandLineOption(QStringLiteral("title"),
- QGuiApplication::tr("Alias for --windowtitle."), QStringLiteral("title")));
+ QGuiApplication::tr("Alias for --qwindowtitle."), QStringLiteral("title")));
}
}
#endif // QT_CONFIG(commandlineparser)
@@ -1411,31 +1441,41 @@ void QGuiApplicationPrivate::createPlatformIntegration()
platformName = QT_QPA_DEFAULT_PLATFORM_NAME;
#endif
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
- QByteArray sessionType = qgetenv("XDG_SESSION_TYPE");
- if (!sessionType.isEmpty()) {
- if (sessionType == QByteArrayLiteral("x11") && !platformName.contains(QByteArrayLiteral("xcb"))) {
- platformName = QByteArrayLiteral("xcb");
- } else if (sessionType == QByteArrayLiteral("wayland") && !platformName.contains(QByteArrayLiteral("wayland"))) {
- QByteArray currentDesktop = qgetenv("XDG_CURRENT_DESKTOP").toLower();
- QByteArray sessionDesktop = qgetenv("XDG_SESSION_DESKTOP").toLower();
- if (currentDesktop.contains("gnome") || sessionDesktop.contains("gnome")) {
- qInfo() << "Warning: Ignoring XDG_SESSION_TYPE=wayland on Gnome."
- << "Use QT_QPA_PLATFORM=wayland to run on Wayland anyway.";
- } else {
- platformName = QByteArrayLiteral("wayland");
- }
- }
+ QList<QByteArray> platformArguments = platformName.split(':');
+ QByteArray platformPluginBase = platformArguments.first();
+
+ const bool hasWaylandDisplay = qEnvironmentVariableIsSet("WAYLAND_DISPLAY");
+ const bool isWaylandSessionType = qgetenv("XDG_SESSION_TYPE") == "wayland";
+
+ QVector<QByteArray> preferredPlatformOrder;
+ const bool defaultIsXcb = platformPluginBase == "xcb";
+ const QByteArray xcbPlatformName = defaultIsXcb ? platformName : "xcb";
+ if (qEnvironmentVariableIsSet("DISPLAY")) {
+ preferredPlatformOrder << xcbPlatformName;
+ if (defaultIsXcb)
+ platformName.clear();
}
-#ifdef QT_QPA_DEFAULT_PLATFORM_NAME
- // Add it as fallback in case XDG_SESSION_TYPE is something wrong
- if (!platformName.contains(QT_QPA_DEFAULT_PLATFORM_NAME))
- platformName += QByteArrayLiteral(";" QT_QPA_DEFAULT_PLATFORM_NAME);
-#endif
+
+ const bool defaultIsWayland = !defaultIsXcb && platformPluginBase.startsWith("wayland");
+ const QByteArray waylandPlatformName = defaultIsWayland ? platformName : "wayland";
+ if (hasWaylandDisplay || isWaylandSessionType) {
+ preferredPlatformOrder.prepend(waylandPlatformName);
+
+ if (defaultIsWayland)
+ platformName.clear();
+ }
+
+ if (!platformName.isEmpty())
+ preferredPlatformOrder.append(platformName);
+
+ platformName = preferredPlatformOrder.join(';');
#endif
+ bool platformExplicitlySelected = false;
QByteArray platformNameEnv = qgetenv("QT_QPA_PLATFORM");
if (!platformNameEnv.isEmpty()) {
platformName = platformNameEnv;
+ platformExplicitlySelected = true;
}
QString platformThemeName = QString::fromLocal8Bit(qgetenv("QT_QPA_PLATFORMTHEME"));
@@ -1458,10 +1498,12 @@ void QGuiApplicationPrivate::createPlatformIntegration()
++arg;
if (strcmp(arg, "-platformpluginpath") == 0) {
if (++i < argc)
- platformPluginPath = QString::fromLocal8Bit(argv[i]);
+ platformPluginPath = QFile::decodeName(argv[i]);
} else if (strcmp(arg, "-platform") == 0) {
- if (++i < argc)
+ if (++i < argc) {
+ platformExplicitlySelected = true;
platformName = argv[i];
+ }
} else if (strcmp(arg, "-platformtheme") == 0) {
if (++i < argc)
platformThemeName = QString::fromLocal8Bit(argv[i]);
@@ -1473,7 +1515,7 @@ void QGuiApplicationPrivate::createPlatformIntegration()
firstWindowTitle = QString::fromLocal8Bit(argv[i]);
} else if (strcmp(arg, "-qwindowicon") == 0 || (xcbIsDefault && strcmp(arg, "-icon") == 0)) {
if (++i < argc) {
- icon = QString::fromLocal8Bit(argv[i]);
+ icon = QFile::decodeName(argv[i]);
}
} else {
argv[j++] = argv[i];
@@ -1485,7 +1527,11 @@ void QGuiApplicationPrivate::createPlatformIntegration()
argc = j;
}
- init_platform(QLatin1String(platformName), platformPluginPath, platformThemeName, argc, argv);
+ Q_UNUSED(platformExplicitlySelected);
+
+ init_platform(QLatin1StringView(platformName), platformPluginPath, platformThemeName, argc, argv);
+ if (const QPlatformTheme *theme = platformTheme())
+ QStyleHintsPrivate::get(QGuiApplication::styleHints())->updateColorScheme(theme->colorScheme());
if (!icon.isEmpty())
forcedWindowIcon = QDir::isAbsolutePath(icon) ? QIcon(icon) : QIcon::fromTheme(icon);
@@ -1504,7 +1550,11 @@ void QGuiApplicationPrivate::createEventDispatcher()
if (platform_integration == nullptr)
createPlatformIntegration();
- // The platform integration should not mess with the event dispatcher
+ // The platform integration should not result in creating an event dispatcher
+ Q_ASSERT_X(!threadData.loadRelaxed()->eventDispatcher, "QGuiApplication",
+ "Creating the platform integration resulted in creating an event dispatcher");
+
+ // Nor should it mess with the QCoreApplication's event dispatcher
Q_ASSERT(!eventDispatcher);
eventDispatcher = platform_integration->createEventDispatcher();
@@ -1516,14 +1566,9 @@ void QGuiApplicationPrivate::eventDispatcherReady()
createPlatformIntegration();
platform_integration->initialize();
-
- // All platforms should have added screens at this point. Finish
- // QHighDpiScaling initialization if it has not been done so already.
- if (!QGuiApplicationPrivate::highDpiScalingUpdated)
- QHighDpiScaling::updateHighDpiScaling();
}
-void QGuiApplicationPrivate::init()
+void Q_TRACE_INSTRUMENT(qtgui) QGuiApplicationPrivate::init()
{
Q_TRACE_SCOPE(QGuiApplicationPrivate_init);
@@ -1573,12 +1618,12 @@ void QGuiApplicationPrivate::init()
} else if (strncmp(arg, "-psn_", 5) == 0) {
// eat "-psn_xxxx" on Mac, which is passed when starting an app from Finder.
// special hack to change working directory (for an app bundle) when running from finder
- if (QDir::currentPath() == QLatin1String("/")) {
+ if (QDir::currentPath() == "/"_L1) {
QCFType<CFURLRef> bundleURL(CFBundleCopyBundleURL(CFBundleGetMainBundle()));
QString qbundlePath = QCFString(CFURLCopyFileSystemPath(bundleURL,
kCFURLPOSIXPathStyle));
- if (qbundlePath.endsWith(QLatin1String(".app")))
- QDir::setCurrent(qbundlePath.section(QLatin1Char('/'), 0, -2));
+ if (qbundlePath.endsWith(".app"_L1))
+ QDir::setCurrent(qbundlePath.section(u'/', 0, -2));
}
#endif
#ifndef QT_NO_SESSIONMANAGER
@@ -1586,7 +1631,7 @@ void QGuiApplicationPrivate::init()
++i;
if (argv[i] && *argv[i]) {
session_id = QString::fromLatin1(argv[i]);
- int p = session_id.indexOf(QLatin1Char('_'));
+ qsizetype p = session_id.indexOf(u'_');
if (p >= 0) {
session_key = session_id.mid(p +1);
session_id = session_id.left(p);
@@ -1682,8 +1727,8 @@ void QGuiApplicationPrivate::init()
Q_UNUSED(loadTestability);
#endif // QT_CONFIG(library)
- if (layout_direction == Qt::LayoutDirectionAuto || force_reverse)
- QGuiApplication::setLayoutDirection(qt_detectRTLLanguage() ? Qt::RightToLeft : Qt::LeftToRight);
+ // trigger changed signal and event delivery
+ QGuiApplication::setLayoutDirection(layout_direction);
if (!QGuiApplicationPrivate::displayName)
QObject::connect(q, &QGuiApplication::applicationNameChanged,
@@ -1697,7 +1742,7 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate()
is_app_closing = true;
is_app_running = false;
- for (int i = 0; i < generic_plugin_list.count(); ++i)
+ for (int i = 0; i < generic_plugin_list.size(); ++i)
delete generic_plugin_list.at(i);
generic_plugin_list.clear();
@@ -1709,7 +1754,7 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate()
QCursorData::cleanup();
#endif
- layout_direction = Qt::LeftToRight;
+ layout_direction = Qt::LayoutDirectionAuto;
cleanupThreadData();
@@ -1728,6 +1773,10 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate()
}
#endif
+#if QT_CONFIG(vulkan)
+ QVulkanDefaultInstance::cleanup();
+#endif
+
platform_integration->destroy();
delete platform_theme;
@@ -1752,7 +1801,7 @@ void restoreOverrideCursor();
static QFont font();
static QFont font(const QWidget*);
static QFont font(const char *className);
-static void setFont(const QFont &, const char* className = 0);
+static void setFont(const QFont &, const char *className = nullptr);
static QFontMetrics fontMetrics();
#ifndef QT_NO_CLIPBOARD
@@ -1762,7 +1811,7 @@ static QClipboard *clipboard();
/*!
Returns the current state of the modifier keys on the keyboard. The current
- state is updated sychronously as the event queue is emptied of events that
+ state is updated synchronously as the event queue is emptied of events that
will spontaneously change the keyboard state (QEvent::KeyPress and
QEvent::KeyRelease events).
@@ -1798,7 +1847,7 @@ Qt::KeyboardModifiers QGuiApplication::queryKeyboardModifiers()
{
CHECK_QAPP_INSTANCE(Qt::KeyboardModifiers{})
QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration();
- return pi->queryKeyboardModifiers();
+ return pi->keyMapper()->queryKeyboardModifiers();
}
/*!
@@ -1856,9 +1905,10 @@ QFunctionPointer QGuiApplication::platformFunction(const QByteArray &function)
Generally, no user interaction can take place before calling exec().
- To make your application perform idle processing, e.g., executing a special
- function whenever there are no pending events, use a QTimer with 0 timeout.
- More advanced idle processing schemes can be achieved using processEvents().
+ To make your application perform idle processing, e.g., 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
@@ -1870,12 +1920,66 @@ QFunctionPointer QGuiApplication::platformFunction(const QByteArray &function)
*/
int QGuiApplication::exec()
{
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
QAccessible::setRootObject(qApp);
#endif
return QCoreApplication::exec();
}
+void QGuiApplicationPrivate::captureGlobalModifierState(QEvent *e)
+{
+ if (e->spontaneous()) {
+ // Capture the current mouse and keyboard states. Doing so here is
+ // required in order to support Qt Test synthesized events. Real mouse
+ // and keyboard state updates from the platform plugin are managed by
+ // QGuiApplicationPrivate::process(Mouse|Wheel|Key|Touch|Tablet)Event();
+ // ### FIXME: Qt Test should not call qapp->notify(), but rather route
+ // the events through the proper QPA interface. This is required to
+ // properly generate all other events such as enter/leave etc.
+ switch (e->type()) {
+ case QEvent::MouseButtonPress: {
+ QMouseEvent *me = static_cast<QMouseEvent *>(e);
+ QGuiApplicationPrivate::modifier_buttons = me->modifiers();
+ QGuiApplicationPrivate::mouse_buttons |= me->button();
+ break;
+ }
+ case QEvent::MouseButtonDblClick: {
+ QMouseEvent *me = static_cast<QMouseEvent *>(e);
+ QGuiApplicationPrivate::modifier_buttons = me->modifiers();
+ QGuiApplicationPrivate::mouse_buttons |= me->button();
+ break;
+ }
+ case QEvent::MouseButtonRelease: {
+ QMouseEvent *me = static_cast<QMouseEvent *>(e);
+ QGuiApplicationPrivate::modifier_buttons = me->modifiers();
+ QGuiApplicationPrivate::mouse_buttons &= ~me->button();
+ break;
+ }
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ case QEvent::MouseMove:
+#if QT_CONFIG(wheelevent)
+ case QEvent::Wheel:
+#endif
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+#if QT_CONFIG(tabletevent)
+ case QEvent::TabletMove:
+ case QEvent::TabletPress:
+ case QEvent::TabletRelease:
+#endif
+ {
+ QInputEvent *ie = static_cast<QInputEvent *>(e);
+ QGuiApplicationPrivate::modifier_buttons = ie->modifiers();
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
/*! \reimp
*/
bool QGuiApplication::notify(QObject *object, QEvent *event)
@@ -1885,6 +1989,8 @@ bool QGuiApplication::notify(QObject *object, QEvent *event)
return true; // Platform plugin ate the event
}
+ QGuiApplicationPrivate::captureGlobalModifierState(event);
+
return QCoreApplication::notify(object, event);
}
@@ -1892,19 +1998,24 @@ bool QGuiApplication::notify(QObject *object, QEvent *event)
*/
bool QGuiApplication::event(QEvent *e)
{
- if(e->type() == QEvent::LanguageChange) {
- setLayoutDirection(qt_detectRTLLanguage()?Qt::RightToLeft:Qt::LeftToRight);
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ // if the layout direction was set explicitly, then don't override it here
+ if (layout_direction == Qt::LayoutDirectionAuto)
+ setLayoutDirection(layout_direction);
for (auto *topLevelWindow : QGuiApplication::topLevelWindows()) {
if (topLevelWindow->flags() != Qt::Desktop)
postEvent(topLevelWindow, new QEvent(QEvent::LanguageChange));
}
- } else if (e->type() == QEvent::ApplicationFontChange ||
- e->type() == QEvent::ApplicationPaletteChange) {
+ break;
+ case QEvent::ApplicationFontChange:
+ case QEvent::ApplicationPaletteChange:
for (auto *topLevelWindow : QGuiApplication::topLevelWindows()) {
if (topLevelWindow->flags() != Qt::Desktop)
postEvent(topLevelWindow, new QEvent(e->type()));
}
- } else if (e->type() == QEvent::Quit) {
+ break;
+ case QEvent::Quit:
// Close open windows. This is done in order to deliver de-expose
// events while the event loop is still running.
for (QWindow *topLevelWindow : QGuiApplication::topLevelWindows()) {
@@ -1916,8 +2027,10 @@ bool QGuiApplication::event(QEvent *e)
return true;
}
}
+ break;
+ default:
+ break;
}
-
return QCoreApplication::event(e);
}
@@ -1943,17 +2056,14 @@ bool QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(QWindow *window,
return platformWindow->windowEvent(event);
}
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
bool QGuiApplicationPrivate::processNativeEvent(QWindow *window, const QByteArray &eventType, void *message, qintptr *result)
-#else
-bool QGuiApplicationPrivate::processNativeEvent(QWindow *window, const QByteArray &eventType, void *message, long *result)
-#endif
{
return window->nativeEvent(eventType, message, result);
}
-void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e)
+void Q_TRACE_INSTRUMENT(qtgui) QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e)
{
+ Q_TRACE_PARAM_REPLACE(QWindowSystemInterfacePrivate::WindowSystemEvent *, int);
Q_TRACE_SCOPE(QGuiApplicationPrivate_processWindowSystemEvent, e->type);
switch(e->type) {
@@ -1978,8 +2088,8 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv
case QWindowSystemInterfacePrivate::Leave:
QGuiApplicationPrivate::processLeaveEvent(static_cast<QWindowSystemInterfacePrivate::LeaveEvent *>(e));
break;
- case QWindowSystemInterfacePrivate::ActivatedWindow:
- QGuiApplicationPrivate::processActivatedEvent(static_cast<QWindowSystemInterfacePrivate::ActivatedWindowEvent *>(e));
+ case QWindowSystemInterfacePrivate::FocusWindow:
+ QGuiApplicationPrivate::processFocusWindowEvent(static_cast<QWindowSystemInterfacePrivate::FocusWindowEvent *>(e));
break;
case QWindowSystemInterfacePrivate::WindowStateChanged:
QGuiApplicationPrivate::processWindowStateChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowStateChangedEvent *>(e));
@@ -1987,6 +2097,9 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv
case QWindowSystemInterfacePrivate::WindowScreenChanged:
QGuiApplicationPrivate::processWindowScreenChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowScreenChangedEvent *>(e));
break;
+ case QWindowSystemInterfacePrivate::WindowDevicePixelRatioChanged:
+ QGuiApplicationPrivate::processWindowDevicePixelRatioChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowDevicePixelRatioChangedEvent *>(e));
+ break;
case QWindowSystemInterfacePrivate::SafeAreaMarginsChanged:
QGuiApplicationPrivate::processSafeAreaMarginsChangedEvent(static_cast<QWindowSystemInterfacePrivate::SafeAreaMarginsChangedEvent *>(e));
break;
@@ -2028,6 +2141,9 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv
case QWindowSystemInterfacePrivate::Expose:
QGuiApplicationPrivate::processExposeEvent(static_cast<QWindowSystemInterfacePrivate::ExposeEvent *>(e));
break;
+ case QWindowSystemInterfacePrivate::Paint:
+ QGuiApplicationPrivate::processPaintEvent(static_cast<QWindowSystemInterfacePrivate::PaintEvent *>(e));
+ break;
case QWindowSystemInterfacePrivate::Tablet:
QGuiApplicationPrivate::processTabletEvent(
static_cast<QWindowSystemInterfacePrivate::TabletEvent *>(e));
@@ -2086,102 +2202,69 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
QEvent::Type type = QEvent::None;
Qt::MouseButton button = Qt::NoButton;
QWindow *window = e->window.data();
+ const QPointingDevice *device = static_cast<const QPointingDevice *>(e->device);
+ Q_ASSERT(device);
+ QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(const_cast<QPointingDevice*>(device));
bool positionChanged = QGuiApplicationPrivate::lastCursorPosition != e->globalPos;
bool mouseMove = false;
bool mousePress = false;
+ const QPointF lastGlobalPosition = QGuiApplicationPrivate::lastCursorPosition;
+ QPointF globalPoint = e->globalPos;
- if (e->enhancedMouseEvent()) {
- type = e->buttonType;
- button = e->button;
-
- if (type == QEvent::NonClientAreaMouseMove || type == QEvent::MouseMove)
- mouseMove = true;
- else if (type == QEvent::NonClientAreaMouseButtonPress || type == QEvent::MouseButtonPress)
- mousePress = true;
-
- if (!mouseMove && positionChanged) {
- QWindowSystemInterfacePrivate::MouseEvent moveEvent(window, e->timestamp,
- e->localPos, e->globalPos, e->buttons ^ button, e->modifiers, Qt::NoButton,
- e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove,
- e->source, e->nonClientArea);
- if (e->synthetic())
- moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
- processMouseEvent(&moveEvent); // mouse move excluding state change
- processMouseEvent(e); // the original mouse event
- return;
- }
- if (mouseMove && !positionChanged) {
- // On Windows, and possibly other platforms, a touchpad can send a mouse move
- // that does not change position, between a press and a release. This may
- // confuse applications, so we always filter out these mouse events for
- // consistent behavior among platforms.
- return;
- }
- } else {
- Qt::MouseButtons stateChange = e->buttons ^ mouse_buttons;
- if (positionChanged && (stateChange != Qt::NoButton)) {
- QWindowSystemInterfacePrivate::MouseEvent moveEvent(window, e->timestamp, e->localPos,
- e->globalPos, mouse_buttons, e->modifiers, Qt::NoButton, QEvent::None, e->source,
- e->nonClientArea);
- if (e->synthetic())
- moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
- processMouseEvent(&moveEvent); // mouse move excluding state change
- processMouseEvent(e); // the original mouse event
- return;
- }
+ if (qIsNaN(e->globalPos.x()) || qIsNaN(e->globalPos.y())) {
+ qWarning("QGuiApplicationPrivate::processMouseEvent: Got NaN in mouse position");
+ return;
+ }
- // In the compatibility path we deduce event type and button that caused the event
- if (positionChanged) {
- mouseMove = true;
- type = e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove;
- } else {
- // Check to see if a new button has been pressed/released.
- for (uint mask = Qt::LeftButton; mask <= Qt::MaxMouseButton; mask <<= 1) {
- if (stateChange & mask) {
- button = Qt::MouseButton(mask);
- break;
- }
- }
- if (button == Qt::NoButton) {
- // Ignore mouse events that don't change the current state. This shouldn't
- // really happen, getting here can only mean that the stored button state
- // is out of sync with the actual physical button state.
- return;
- }
- if (button & e->buttons) {
- mousePress = true;
- type = e->nonClientArea ? QEvent::NonClientAreaMouseButtonPress
- : QEvent::MouseButtonPress;
- } else {
- type = e->nonClientArea ? QEvent::NonClientAreaMouseButtonRelease
- : QEvent::MouseButtonRelease;
- }
- }
+ type = e->buttonType;
+ button = e->button;
+
+ if (type == QEvent::NonClientAreaMouseMove || type == QEvent::MouseMove)
+ mouseMove = true;
+ else if (type == QEvent::NonClientAreaMouseButtonPress || type == QEvent::MouseButtonPress)
+ mousePress = true;
+
+ if (!mouseMove && positionChanged) {
+ QWindowSystemInterfacePrivate::MouseEvent moveEvent(window, e->timestamp,
+ e->localPos, e->globalPos, e->buttons ^ button, e->modifiers, Qt::NoButton,
+ e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove,
+ e->source, e->nonClientArea);
+ if (e->synthetic())
+ moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
+ processMouseEvent(&moveEvent); // mouse move excluding state change
+ processMouseEvent(e); // the original mouse event
+ return;
+ }
+ if (type == QEvent::MouseMove && !positionChanged) {
+ // On Windows, and possibly other platforms, a touchpad can send a mouse move
+ // that does not change position, between a press and a release. This may
+ // confuse applications, so we always filter out these mouse events for
+ // consistent behavior among platforms.
+ return;
}
modifier_buttons = e->modifiers;
QPointF localPoint = e->localPos;
- QPointF globalPoint = e->globalPos;
- const QPointF lastGlobalPosition = QGuiApplicationPrivate::lastCursorPosition;
bool doubleClick = false;
+ auto persistentEPD = devPriv->pointById(0);
if (mouseMove) {
QGuiApplicationPrivate::lastCursorPosition = globalPoint;
const auto doubleClickDistance = (e->device && e->device->type() == QInputDevice::DeviceType::Mouse ?
mouseDoubleClickDistance : touchDoubleTapDistance);
- if (qAbs(globalPoint.x() - mousePressX) > doubleClickDistance ||
- qAbs(globalPoint.y() - mousePressY) > doubleClickDistance)
+ const auto pressPos = persistentEPD->eventPoint.globalPressPosition();
+ if (qAbs(globalPoint.x() - pressPos.x()) > doubleClickDistance ||
+ qAbs(globalPoint.y() - pressPos.y()) > doubleClickDistance)
mousePressButton = Qt::NoButton;
} else {
+ static unsigned long lastPressTimestamp = 0;
mouse_buttons = e->buttons;
if (mousePress) {
ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval());
- doubleClick = e->timestamp - mousePressTime < doubleClickInterval && button == mousePressButton;
- mousePressTime = e->timestamp;
+ doubleClick = e->timestamp - lastPressTimestamp
+ < doubleClickInterval && button == mousePressButton;
mousePressButton = button;
- const QPoint point = QGuiApplicationPrivate::lastCursorPosition.toPoint();
- mousePressX = point.x();
- mousePressY = point.y();
+ lastPressTimestamp = e ->timestamp;
}
}
@@ -2206,7 +2289,6 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
if (!window)
return;
- const QPointingDevice *device = static_cast<const QPointingDevice *>(e->device);
#ifndef QT_NO_CURSOR
if (!e->synthetic()) {
if (const QScreen *screen = window->screen())
@@ -2215,18 +2297,23 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
const QPointF nativeGlobalPoint = QHighDpi::toNativePixels(globalPoint, screen);
QMouseEvent ev(type, nativeLocalPoint, nativeLocalPoint, nativeGlobalPoint,
button, e->buttons, e->modifiers, e->source, device);
- ev.setTimestamp(e->timestamp);
+ // avoid incorrect velocity calculation: ev is in the native coordinate system,
+ // but we need to consistently use the logical coordinate system for velocity
+ // whenever QEventPoint::setTimestamp() is called
+ ev.QInputEvent::setTimestamp(e->timestamp);
cursor->pointerEvent(ev);
}
}
#endif
QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, e->buttons, e->modifiers, e->source, device);
+ Q_ASSERT(devPriv->pointById(0) == persistentEPD); // we don't expect reallocation in QPlatformCursor::pointerEvenmt()
+ // restore globalLastPosition to avoid invalidating the velocity calculations,
+ // because the QPlatformCursor mouse event above was in native coordinates
+ QMutableEventPoint::setGlobalLastPosition(persistentEPD->eventPoint, lastGlobalPosition);
+ persistentEPD = nullptr; // incoming and synth events can cause reallocation during delivery, so don't use this again
+ // ev now contains a detached copy of the QEventPoint from QPointingDevicePrivate::activePoints
ev.setTimestamp(e->timestamp);
- QMutableEventPoint &mutPt = QMutableSinglePointEvent::from(ev).mutablePoint();
- mutPt.setGlobalLastPosition(lastGlobalPosition);
- mutPt.setGlobalPressPosition(QPointF(mousePressX, mousePressY));
-
if (window->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) {
// a modal window is blocking this window, don't allow mouse events through
return;
@@ -2242,14 +2329,10 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
if (!e->synthetic() && !ev.isAccepted()
&& !e->nonClientArea
&& qApp->testAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents)) {
- if (!m_fakeTouchDevice) {
- m_fakeTouchDevice = new QPointingDevice;
- QWindowSystemInterface::registerInputDevice(m_fakeTouchDevice);
- }
QList<QWindowSystemInterface::TouchPoint> points;
QWindowSystemInterface::TouchPoint point;
point.id = 1;
- point.area = QRectF(globalPoint.x() - 2, globalPoint.y() - 2, 4, 4);
+ point.area = QHighDpi::toNativePixels(QRectF(globalPoint.x() - 2, globalPoint.y() - 2, 4, 4), window);
// only translate left button related events to
// avoid strange touch event sequences when several
@@ -2270,7 +2353,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
const QList<QEventPoint> &touchPoints =
QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, &type);
- QWindowSystemInterfacePrivate::TouchEvent fake(window, e->timestamp, type, m_fakeTouchDevice, touchPoints, e->modifiers);
+ QWindowSystemInterfacePrivate::TouchEvent fake(window, e->timestamp, type, device, touchPoints, e->modifiers);
fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
processTouchEvent(&fake);
}
@@ -2284,6 +2367,12 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
QGuiApplication::sendSpontaneousEvent(window, &dblClickEvent);
}
}
+ if (type == QEvent::MouseButtonRelease && e->buttons == Qt::NoButton) {
+ if (auto *persistentEPD = devPriv->queryPointById(0)) {
+ ev.setExclusiveGrabber(persistentEPD->eventPoint, nullptr);
+ ev.clearPassiveGrabbers(persistentEPD->eventPoint);
+ }
+ }
}
void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::WheelEvent *e)
@@ -2315,6 +2404,7 @@ void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::Wh
mouse_buttons, e->modifiers, e->phase, e->inverted, e->source, device);
ev.setTimestamp(e->timestamp);
QGuiApplication::sendSpontaneousEvent(window, &ev);
+ e->eventAccepted = ev.isAccepted();
#else
Q_UNUSED(e);
#endif // QT_CONFIG(wheelevent)
@@ -2325,7 +2415,7 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE
QWindow *window = e->window.data();
modifier_buttons = e->modifiers;
if (e->nullWindow()
-#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
+#ifdef Q_OS_ANDROID
|| e->key == Qt::Key_Back || e->key == Qt::Key_Menu
#endif
) {
@@ -2361,7 +2451,7 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE
if (window && !window->d_func()->blockedByModalWindow)
QGuiApplication::sendSpontaneousEvent(window, &ev);
-#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
+#ifdef Q_OS_ANDROID
else
ev.setAccepted(false);
@@ -2391,7 +2481,19 @@ void QGuiApplicationPrivate::processEnterEvent(QWindowSystemInterfacePrivate::En
currentMouseWindow = e->enter;
+ // TODO later: EnterEvent must report _which_ mouse entered the window; for now we assume primaryPointingDevice()
QEnterEvent event(e->localPos, e->localPos, e->globalPos);
+
+ // Since we don't always track mouse moves that occur outside a window, any residual velocity
+ // stored in the persistent QEventPoint may be inaccurate (especially in fast-moving autotests).
+ // Reset the Kalman filter so that the velocity of the first mouse event after entering the window
+ // will be based on a zero residual velocity (but the result can still be non-zero if the mouse
+ // moves to a different position from where this enter event occurred; tests often do that).
+ const QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(event.pointingDevice());
+ auto epd = devPriv->queryPointById(event.points().first().id());
+ Q_ASSERT(epd);
+ QMutableEventPoint::setVelocity(epd->eventPoint, {});
+
QCoreApplication::sendSpontaneousEvent(e->enter.data(), &event);
}
@@ -2410,10 +2512,10 @@ void QGuiApplicationPrivate::processLeaveEvent(QWindowSystemInterfacePrivate::Le
QCoreApplication::sendSpontaneousEvent(e->leave.data(), &event);
}
-void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate::ActivatedWindowEvent *e)
+void QGuiApplicationPrivate::processFocusWindowEvent(QWindowSystemInterfacePrivate::FocusWindowEvent *e)
{
QWindow *previous = QGuiApplicationPrivate::focus_window;
- QWindow *newFocus = e->activated.data();
+ QWindow *newFocus = e->focused.data();
if (previous == newFocus)
return;
@@ -2463,8 +2565,15 @@ void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate
if (self) {
self->notifyActiveWindowChange(previous);
- if (previousFocusObject != qApp->focusObject())
+ if (previousFocusObject != qApp->focusObject() ||
+ // We are getting an activation change but there is no new focusObject, and we also
+ // don't have a previousFocusObject in the previously active window anymore. This can
+ // happen when window gets destroyed (see QWidgetWindow::focusObject returning nullptr
+ // when already in the QWidget destructor), so update the focusObject to avoid dangling
+ // pointers. See also QWidget::clearFocus(), which tries to cover for this as well.
+ (previous && previousFocusObject == nullptr && qApp->focusObject() == nullptr)) {
self->_q_updateFocusObject(qApp->focusObject());
+ }
}
emit qApp->focusWindowChanged(newFocus);
@@ -2476,32 +2585,46 @@ void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate
void QGuiApplicationPrivate::processWindowStateChangedEvent(QWindowSystemInterfacePrivate::WindowStateChangedEvent *wse)
{
- if (QWindow *window = wse->window.data()) {
+ if (QWindow *window = wse->window.data()) {
+ QWindowPrivate *windowPrivate = qt_window_private(window);
+ const auto originalEffectiveState = QWindowPrivate::effectiveState(windowPrivate->windowState);
+
+ windowPrivate->windowState = wse->newState;
+ const auto newEffectiveState = QWindowPrivate::effectiveState(windowPrivate->windowState);
+ if (newEffectiveState != originalEffectiveState)
+ emit window->windowStateChanged(newEffectiveState);
+
+ windowPrivate->updateVisibility();
+
QWindowStateChangeEvent e(wse->oldState);
- window->d_func()->windowState = wse->newState;
QGuiApplication::sendSpontaneousEvent(window, &e);
}
}
void QGuiApplicationPrivate::processWindowScreenChangedEvent(QWindowSystemInterfacePrivate::WindowScreenChangedEvent *wse)
{
- if (QWindow *window = wse->window.data()) {
- if (window->screen() == wse->screen.data())
- return;
- if (QWindow *topLevelWindow = window->d_func()->topLevelWindow(QWindow::ExcludeTransients)) {
- if (QScreen *screen = wse->screen.data())
- topLevelWindow->d_func()->setTopLevelScreen(screen, false /* recreate */);
- else // Fall back to default behavior, and try to find some appropriate screen
- topLevelWindow->setScreen(nullptr);
- }
- // we may have changed scaling, so trigger resize event if needed
- if (window->handle()) {
- QWindowSystemInterfacePrivate::GeometryChangeEvent gce(window, QHighDpi::fromNativePixels(window->handle()->geometry(), window));
- processGeometryChangeEvent(&gce);
- }
+ QWindow *window = wse->window.data();
+ if (!window)
+ return;
+
+ if (window->screen() == wse->screen.data())
+ return;
+
+ if (QWindow *topLevelWindow = window->d_func()->topLevelWindow(QWindow::ExcludeTransients)) {
+ if (QScreen *screen = wse->screen.data())
+ topLevelWindow->d_func()->setTopLevelScreen(screen, false /* recreate */);
+ else // Fall back to default behavior, and try to find some appropriate screen
+ topLevelWindow->setScreen(nullptr);
}
}
+void QGuiApplicationPrivate::processWindowDevicePixelRatioChangedEvent(QWindowSystemInterfacePrivate::WindowDevicePixelRatioChangedEvent *wde)
+{
+ if (wde->window.isNull())
+ return;
+ QWindowPrivate::get(wde->window)->updateDevicePixelRatio();
+}
+
void QGuiApplicationPrivate::processSafeAreaMarginsChangedEvent(QWindowSystemInterfacePrivate::SafeAreaMarginsChangedEvent *wse)
{
if (wse->window.isNull())
@@ -2516,11 +2639,43 @@ void QGuiApplicationPrivate::processSafeAreaMarginsChangedEvent(QWindowSystemInt
void QGuiApplicationPrivate::processThemeChanged(QWindowSystemInterfacePrivate::ThemeChangeEvent *tce)
{
if (self)
- self->notifyThemeChanged();
- if (QWindow *window = tce->window.data()) {
- QEvent e(QEvent::ThemeChange);
- QGuiApplication::sendSpontaneousEvent(window, &e);
+ self->handleThemeChanged();
+
+ QIconPrivate::clearIconCache();
+
+ QStyleHintsPrivate::get(QGuiApplication::styleHints())->updateColorScheme(colorScheme());
+
+ QEvent themeChangeEvent(QEvent::ThemeChange);
+ const QWindowList windows = tce->window ? QWindowList{tce->window} : window_list;
+ for (auto *window : windows)
+ QGuiApplication::sendSpontaneousEvent(window, &themeChangeEvent);
+}
+
+/*!
+ \internal
+ \brief QGuiApplicationPrivate::colorScheme
+ \return the platform theme's color scheme
+ or Qt::ColorScheme::Unknown if a platform theme cannot be established
+ */
+Qt::ColorScheme QGuiApplicationPrivate::colorScheme()
+{
+ return platformTheme() ? platformTheme()->colorScheme()
+ : Qt::ColorScheme::Unknown;
+}
+
+void QGuiApplicationPrivate::handleThemeChanged()
+{
+ updatePalette();
+
+ QIconLoader::instance()->updateSystemTheme();
+ QAbstractFileIconProviderPrivate::clearIconTypeCache();
+
+ if (!(applicationResourceFlags & ApplicationFontExplicitlySet)) {
+ const auto locker = qt_scoped_lock(applicationFontMutex);
+ clearFontUnlocked();
+ initFontUnlocked();
}
+ initThemeHints();
}
void QGuiApplicationPrivate::processGeometryChangeEvent(QWindowSystemInterfacePrivate::GeometryChangeEvent *e)
@@ -2579,8 +2734,10 @@ void QGuiApplicationPrivate::processCloseEvent(QWindowSystemInterfacePrivate::Cl
{
if (e->window.isNull())
return;
- if (e->window.data()->d_func()->blockedByModalWindow) {
- // a modal window is blocking this window, don't allow close events through
+ if (e->window.data()->d_func()->blockedByModalWindow && !e->window.data()->d_func()->inClose) {
+ // a modal window is blocking this window, don't allow close events through, unless they
+ // originate from a call to QWindow::close.
+ e->eventAccepted = false;
return;
}
@@ -2685,6 +2842,8 @@ void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::T
QWindowSystemInterfacePrivate::MouseEvent mouseEvent(window, e->timestamp, e->local,
e->global, e->buttons, e->modifiers, button, mouseType, Qt::MouseEventNotSynthesized, false, device);
mouseEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
+ qCDebug(lcPtrDispatch) << "synthesizing mouse from tablet event" << mouseType
+ << e->local << button << e->buttons << e->modifiers;
processMouseEvent(&mouseEvent);
}
#else
@@ -2727,7 +2886,8 @@ void QGuiApplicationPrivate::processGestureEvent(QWindowSystemInterfacePrivate::
return;
const QPointingDevice *device = static_cast<const QPointingDevice *>(e->device);
- QNativeGestureEvent ev(e->type, device, e->pos, e->pos, e->globalPos, e->realValue, e->sequenceId, e->intValue);
+ QNativeGestureEvent ev(e->type, device, e->fingerCount, e->pos, e->pos, e->globalPos, (e->intValue ? e->intValue : e->realValue),
+ e->delta, e->sequenceId);
ev.setTimestamp(e->timestamp);
QGuiApplication::sendSpontaneousEvent(e->window, &ev);
}
@@ -2760,42 +2920,31 @@ void QGuiApplicationPrivate::processContextMenuEvent(QWindowSystemInterfacePriva
}
#endif
-Q_GUI_EXPORT size_t qHash(const QGuiApplicationPrivate::ActiveTouchPointsKey &k, size_t seed)
-{
- return (qHash(k.device) + k.touchPointId) ^ seed;
-}
-
-Q_GUI_EXPORT bool operator==(const QGuiApplicationPrivate::ActiveTouchPointsKey &a,
- const QGuiApplicationPrivate::ActiveTouchPointsKey &b)
-{
- return a.device == b.device
- && a.touchPointId == b.touchPointId;
-}
-
void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::TouchEvent *e)
{
- QGuiApplicationPrivate *d = self;
+ if (!QInputDevicePrivate::isRegistered(e->device))
+ return;
+
modifier_buttons = e->modifiers;
- const QPointingDevice *device = static_cast<const QPointingDevice *>(e->device);
+ QPointingDevice *device = const_cast<QPointingDevice *>(static_cast<const QPointingDevice *>(e->device));
+ QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(device);
if (e->touchType == QEvent::TouchCancel) {
// The touch sequence has been canceled (e.g. by the compositor).
// Send the TouchCancel to all windows with active touches and clean up.
QTouchEvent touchEvent(QEvent::TouchCancel, device, e->modifiers);
touchEvent.setTimestamp(e->timestamp);
- QHash<ActiveTouchPointsKey, ActiveTouchPointsValue>::const_iterator it
- = self->activeTouchPoints.constBegin(), ite = self->activeTouchPoints.constEnd();
- QSet<QWindow *> windowsNeedingCancel;
- while (it != ite) {
- QWindow *w = it->window.data();
- if (w)
+ constexpr qsizetype Prealloc = decltype(devPriv->activePoints)::mapped_container_type::PreallocatedSize;
+ QMinimalVarLengthFlatSet<QWindow *, Prealloc> windowsNeedingCancel;
+
+ for (auto &epd : devPriv->activePoints.values()) {
+ if (QWindow *w = QMutableEventPoint::window(epd.eventPoint))
windowsNeedingCancel.insert(w);
- ++it;
- }
- for (QSet<QWindow *>::const_iterator winIt = windowsNeedingCancel.constBegin(),
- winItEnd = windowsNeedingCancel.constEnd(); winIt != winItEnd; ++winIt) {
- QGuiApplication::sendSpontaneousEvent(*winIt, &touchEvent);
}
+
+ for (QWindow *w : windowsNeedingCancel)
+ QGuiApplication::sendSpontaneousEvent(w, &touchEvent);
+
if (!self->synthesizedMousePoints.isEmpty() && !e->synthetic()) {
for (QHash<QWindow *, SynthesizedMouseData>::const_iterator synthIt = self->synthesizedMousePoints.constBegin(),
synthItEnd = self->synthesizedMousePoints.constEnd(); synthIt != synthItEnd; ++synthIt) {
@@ -2817,7 +2966,6 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
}
self->synthesizedMousePoints.clear();
}
- self->activeTouchPoints.clear();
self->lastTouchType = e->touchType;
return;
}
@@ -2828,208 +2976,177 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
self->lastTouchType = e->touchType;
- QWindow *window = e->window.data();
- // TODO get rid of this QPair; we don't need to accumulate combined states here anymore
- typedef QPair<QEventPoint::States, QList<QEventPoint> > StatesAndTouchPoints;
- QHash<QWindow *, StatesAndTouchPoints> windowsNeedingEvents;
- bool stationaryTouchPointChangedProperty = false;
-
- for (int i = 0; i < e->points.count(); ++i) {
- QMutableEventPoint touchPoint = QMutableEventPoint::from(e->points[i]);
+ QPointer<QWindow> window = e->window; // the platform hopefully tells us which window received the event
+ QVarLengthArray<QMutableTouchEvent, 2> touchEvents;
+ // For each temporary QEventPoint from the QPA TouchEvent:
+ // - update the persistent QEventPoint in QPointingDevicePrivate::activePoints with current values
+ // - determine which window to deliver it to
+ // - add it to the QTouchEvent instance for that window (QMutableTouchEvent::target() will be QWindow*, for now)
+ for (auto &tempPt : e->points) {
// update state
- QPointer<QWindow> w;
- QEventPoint previousTouchPoint;
- ActiveTouchPointsKey touchInfoKey(device, touchPoint.id());
- ActiveTouchPointsValue &touchInfo = d->activeTouchPoints[touchInfoKey];
- switch (touchPoint.state()) {
+ auto epd = devPriv->pointById(tempPt.id());
+ auto &ep = epd->eventPoint;
+ epd->eventPoint.setAccepted(false);
+ switch (tempPt.state()) {
case QEventPoint::State::Pressed:
- if (e->device && e->device->type() == QInputDevice::DeviceType::TouchPad) {
- // on touch-pads, send all touch points to the same widget
- w = d->activeTouchPoints.isEmpty()
- ? QPointer<QWindow>()
- : d->activeTouchPoints.constBegin().value().window;
- }
-
- if (!w) {
- // determine which window this event will go to
- if (!window)
- window = QGuiApplication::topLevelAt(touchPoint.globalPosition().toPoint());
- if (!window)
- continue;
- w = window;
- }
-
- touchInfo.window = w;
- touchPoint.setGlobalPressPosition(touchPoint.globalPosition());
- touchPoint.setGlobalLastPosition(touchPoint.globalPosition());
- if (touchPoint.pressure() < 0)
- touchPoint.setPressure(1);
-
- touchInfo.touchPoint = touchPoint;
+ // On touchpads, send all touch points to the same window.
+ if (!window && e->device && e->device->type() == QInputDevice::DeviceType::TouchPad)
+ window = devPriv->firstActiveWindow();
+ // If the QPA event didn't tell us which window, find the one under the touchpoint position.
+ if (!window)
+ window = QGuiApplication::topLevelAt(tempPt.globalPosition().toPoint());
+ QMutableEventPoint::setWindow(ep, window);
break;
case QEventPoint::State::Released:
- w = touchInfo.window;
- if (!w)
- continue;
-
- previousTouchPoint = touchInfo.touchPoint;
- touchPoint.setGlobalPressPosition(previousTouchPoint.globalPressPosition());
- touchPoint.setGlobalLastPosition(previousTouchPoint.globalPosition());
- touchPoint.setPressure(0);
-
+ if (Q_UNLIKELY(!window.isNull() && window != QMutableEventPoint::window(ep)))
+ qCDebug(lcPtrDispatch) << "delivering touch release to same window"
+ << QMutableEventPoint::window(ep) << "not" << window.data();
+ window = QMutableEventPoint::window(ep);
break;
- default:
- w = touchInfo.window;
- if (!w)
- continue;
-
- previousTouchPoint = touchInfo.touchPoint;
- touchPoint.setGlobalPressPosition(previousTouchPoint.globalPressPosition());
- touchPoint.setGlobalLastPosition(previousTouchPoint.globalPosition());
- if (touchPoint.pressure() < 0)
- touchPoint.setPressure(1);
-
- // Stationary points might not be delivered down to the receiving item
- // and get their position transformed, keep the old values instead.
- if (touchPoint.state() == QEventPoint::State::Stationary) {
- if (touchInfo.touchPoint.velocity() != touchPoint.velocity()) {
- touchInfo.touchPoint.setVelocity(touchPoint.velocity());
- touchPoint.setStationaryWithModifiedProperty();
- stationaryTouchPointChangedProperty = true;
- }
- if (!qFuzzyCompare(touchInfo.touchPoint.pressure(), touchPoint.pressure())) {
- touchInfo.touchPoint.setPressure(touchPoint.pressure());
- touchPoint.setStationaryWithModifiedProperty();
- stationaryTouchPointChangedProperty = true;
- }
- } else {
- touchInfo.touchPoint = touchPoint;
- }
+ default: // update or stationary
+ if (Q_UNLIKELY(!window.isNull() && window != QMutableEventPoint::window(ep)))
+ qCDebug(lcPtrDispatch) << "delivering touch update to same window"
+ << QMutableEventPoint::window(ep) << "not" << window.data();
+ window = QMutableEventPoint::window(ep);
break;
}
+ // If we somehow still don't have a window, we can't deliver this touchpoint. (should never happen)
+ if (Q_UNLIKELY(!window)) {
+ qCWarning(lcPtrDispatch) << "skipping" << &tempPt << ": no target window";
+ continue;
+ }
+ QMutableEventPoint::update(tempPt, ep);
- Q_ASSERT(w.data() != nullptr);
+ Q_ASSERT(window.data() != nullptr);
// make the *scene* position the same as the *global* position
- // Note: touchPoint is a reference to the one from activeTouchPoints, so we can modify it.
- touchPoint.setScenePosition(touchPoint.globalPosition());
+ QMutableEventPoint::setScenePosition(ep, tempPt.globalPosition());
+
+ // store the scene position as local position, for now
+ QMutableEventPoint::setPosition(ep, window->mapFromGlobal(tempPt.globalPosition()));
- StatesAndTouchPoints &maskAndPoints = windowsNeedingEvents[w.data()];
- maskAndPoints.first |= touchPoint.state();
- maskAndPoints.second.append(touchPoint);
+ // setTimeStamp has side effects, so we do it last
+ QMutableEventPoint::setTimestamp(ep, e->timestamp);
+
+ // add the touchpoint to the event that will be delivered to the window
+ bool added = false;
+ for (QMutableTouchEvent &ev : touchEvents) {
+ if (ev.target() == window.data()) {
+ ev.addPoint(ep);
+ added = true;
+ break;
+ }
+ }
+ if (!added) {
+ QMutableTouchEvent mte(e->touchType, device, e->modifiers, {ep});
+ mte.setTimestamp(e->timestamp);
+ mte.setTarget(window.data());
+ touchEvents.append(mte);
+ }
}
- if (windowsNeedingEvents.isEmpty())
+ if (touchEvents.isEmpty())
return;
- QHash<QWindow *, StatesAndTouchPoints>::ConstIterator it = windowsNeedingEvents.constBegin();
- const QHash<QWindow *, StatesAndTouchPoints>::ConstIterator end = windowsNeedingEvents.constEnd();
- for (; it != end; ++it) {
- QWindow *w = it.key();
+ for (QMutableTouchEvent &touchEvent : touchEvents) {
+ QWindow *window = static_cast<QWindow *>(touchEvent.target());
QEvent::Type eventType;
- switch (it.value().first) {
+ switch (touchEvent.touchPointStates()) {
case QEventPoint::State::Pressed:
eventType = QEvent::TouchBegin;
break;
case QEventPoint::State::Released:
eventType = QEvent::TouchEnd;
break;
- case QEventPoint::State::Stationary:
- // don't send the event if nothing changed
- if (!stationaryTouchPointChangedProperty)
- continue;
- Q_FALLTHROUGH();
default:
eventType = QEvent::TouchUpdate;
break;
}
- if (w->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) {
+ if (window->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) {
// a modal window is blocking this window, don't allow touch events through
- // QTBUG-37371 temporary fix; TODO: revisit in 5.4 when we have a forwarding solution
- if (eventType == QEvent::TouchEnd) {
+ // QTBUG-37371 temporary fix; TODO: revisit when we have a forwarding solution
+ if (touchEvent.type() == QEvent::TouchEnd) {
// but don't leave dangling state: e.g.
// QQuickWindowPrivate::itemForTouchPointId needs to be cleared.
- QTouchEvent touchEvent(QEvent::TouchCancel,
- device,
- e->modifiers);
+ QTouchEvent touchEvent(QEvent::TouchCancel, device, e->modifiers);
touchEvent.setTimestamp(e->timestamp);
- QGuiApplication::sendSpontaneousEvent(w, &touchEvent);
+ QGuiApplication::sendSpontaneousEvent(window, &touchEvent);
}
continue;
}
- const auto &touchpoints = it.value().second;
- QMutableTouchEvent touchEvent(eventType, device, e->modifiers, touchpoints);
- touchEvent.setTimestamp(e->timestamp);
-
- for (QEventPoint &pt : touchEvent.touchPoints()) {
- auto &touchPoint = QMutableEventPoint::from(pt);
- touchPoint.setPosition(w->mapFromGlobal(touchPoint.globalPosition()));
- }
+ // Note: after the call to sendSpontaneousEvent, touchEvent.position() will have
+ // changed to reflect the local position inside the last (random) widget it tried
+ // to deliver the touch event to, and will therefore be invalid afterwards.
+ QGuiApplication::sendSpontaneousEvent(window, &touchEvent);
- QGuiApplication::sendSpontaneousEvent(w, &touchEvent);
if (!e->synthetic() && !touchEvent.isAccepted() && qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) {
// exclude devices which generate their own mouse events
if (!(touchEvent.device()->capabilities().testFlag(QInputDevice::Capability::MouseEmulation))) {
- if (eventType == QEvent::TouchEnd)
- self->synthesizedMousePoints.clear();
-
- if (eventType == QEvent::TouchBegin)
+ QEvent::Type mouseEventType = QEvent::MouseMove;
+ Qt::MouseButton button = Qt::NoButton;
+ Qt::MouseButtons buttons = Qt::LeftButton;
+ if (eventType == QEvent::TouchBegin || m_fakeMouseSourcePointId < 0) {
m_fakeMouseSourcePointId = touchEvent.point(0).id();
-
- const QEvent::Type mouseType = [&]() {
- switch (eventType) {
- case QEvent::TouchBegin: return QEvent::MouseButtonPress;
- case QEvent::TouchUpdate: return QEvent::MouseMove;
- case QEvent::TouchEnd: return QEvent::MouseButtonRelease;
- default: Q_UNREACHABLE();
- }
- }();
-
- Qt::MouseButton button = mouseType == QEvent::MouseMove ? Qt::NoButton : Qt::LeftButton;
- Qt::MouseButtons buttons = mouseType == QEvent::MouseButtonRelease ? Qt::NoButton : Qt::LeftButton;
-
- const auto &points = touchEvent.touchPoints();
- for (const QEventPoint &touchPoint : points) {
- if (touchPoint.id() == m_fakeMouseSourcePointId) {
- if (eventType != QEvent::TouchEnd)
- self->synthesizedMousePoints.insert(w, SynthesizedMouseData(
- touchPoint.position(), touchPoint.globalPosition(), w));
+ qCDebug(lcPtrDispatch) << "synthesizing mouse events from touchpoint" << m_fakeMouseSourcePointId;
+ }
+ if (m_fakeMouseSourcePointId >= 0) {
+ const auto *touchPoint = touchEvent.pointById(m_fakeMouseSourcePointId);
+ if (touchPoint) {
+ switch (touchPoint->state()) {
+ case QEventPoint::State::Pressed:
+ mouseEventType = QEvent::MouseButtonPress;
+ button = Qt::LeftButton;
+ break;
+ case QEventPoint::State::Released:
+ mouseEventType = QEvent::MouseButtonRelease;
+ button = Qt::LeftButton;
+ buttons = Qt::NoButton;
+ Q_ASSERT(m_fakeMouseSourcePointId == touchPoint->id());
+ m_fakeMouseSourcePointId = -1;
+ break;
+ default:
+ break;
+ }
+ if (touchPoint->state() != QEventPoint::State::Released) {
+ self->synthesizedMousePoints.insert(window, SynthesizedMouseData(
+ touchPoint->position(), touchPoint->globalPosition(), window));
+ }
// All touch events that are not accepted by the application will be translated to
// left mouse button events instead (see AA_SynthesizeMouseForUnhandledTouchEvents docs).
- QWindowSystemInterfacePrivate::MouseEvent fake(w, e->timestamp,
- touchPoint.position(),
- touchPoint.globalPosition(),
+ // TODO why go through QPA? Why not just send a QMouseEvent right from here?
+ QWindowSystemInterfacePrivate::MouseEvent fake(window, e->timestamp,
+ window->mapFromGlobal(touchPoint->globalPosition().toPoint()),
+ touchPoint->globalPosition(),
buttons,
e->modifiers,
button,
- mouseType,
+ mouseEventType,
Qt::MouseEventSynthesizedByQt,
false,
device);
fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
processMouseEvent(&fake);
- break;
}
}
+ if (eventType == QEvent::TouchEnd)
+ self->synthesizedMousePoints.clear();
}
}
}
- // Remove released points from the hash table only after the event is
- // delivered. When the receiver is a widget, QApplication will access
- // activeTouchPoints during delivery and therefore nothing can be removed
- // before sending the event.
+ // Remove released points from QPointingDevicePrivate::activePoints only after the event is
+ // delivered. Widgets and Qt Quick are allowed to access them at any time before this.
for (const QEventPoint &touchPoint : e->points) {
if (touchPoint.state() == QEventPoint::State::Released)
- d->activeTouchPoints.remove(ActiveTouchPointsKey(device, touchPoint.id()));
+ devPriv->removePointById(touchPoint.id());
}
}
@@ -3060,29 +3177,18 @@ void QGuiApplicationPrivate::processScreenGeometryChange(QWindowSystemInterfaceP
if (!e->screen)
return;
- QScreen *s = e->screen.data();
-
- bool geometryChanged = e->geometry != s->d_func()->geometry;
- s->d_func()->geometry = e->geometry;
+ {
+ QScreen *s = e->screen.data();
+ QScreenPrivate::UpdateEmitter updateEmitter(s);
- bool availableGeometryChanged = e->availableGeometry != s->d_func()->availableGeometry;
- s->d_func()->availableGeometry = e->availableGeometry;
+ // Note: The incoming geometries have already been scaled by QHighDpi
+ // in the QWSI layer, so we don't need to call updateGeometry() here.
+ s->d_func()->geometry = e->geometry;
+ s->d_func()->availableGeometry = e->availableGeometry;
- if (geometryChanged) {
- Qt::ScreenOrientation primaryOrientation = s->primaryOrientation();
s->d_func()->updatePrimaryOrientation();
-
- emit s->geometryChanged(s->geometry());
- emit s->physicalSizeChanged(s->physicalSize());
- emit s->physicalDotsPerInchChanged(s->physicalDotsPerInch());
- emit s->logicalDotsPerInchChanged(s->logicalDotsPerInch());
-
- if (s->primaryOrientation() != primaryOrientation)
- emit s->primaryOrientationChanged(s->primaryOrientation());
}
- s->d_func()->emitGeometryChangeSignals(geometryChanged, availableGeometryChanged);
-
resetCachedDevicePixelRatio();
}
@@ -3092,14 +3198,21 @@ void QGuiApplicationPrivate::processScreenLogicalDotsPerInchChange(QWindowSystem
if (QCoreApplication::startingUp())
return;
+ QHighDpiScaling::updateHighDpiScaling();
+
if (!e->screen)
return;
- QScreen *s = e->screen.data();
- s->d_func()->logicalDpi = QDpi(e->dpiX, e->dpiY);
+ {
+ QScreen *s = e->screen.data();
+ QScreenPrivate::UpdateEmitter updateEmitter(s);
+ s->d_func()->logicalDpi = QDpi(e->dpiX, e->dpiY);
+ s->d_func()->updateGeometry();
+ }
- emit s->logicalDotsPerInchChanged(s->logicalDotsPerInch());
- s->d_func()->updateGeometriesWithSignals();
+ for (QWindow *window : QGuiApplication::allWindows())
+ if (window->screen() == e->screen)
+ QWindowPrivate::get(window)->updateDevicePixelRatio();
resetCachedDevicePixelRatio();
}
@@ -3144,13 +3257,72 @@ void QGuiApplicationPrivate::processExposeEvent(QWindowSystemInterfacePrivate::E
p->resizeEventPending = false;
}
+ // FIXME: It would logically make sense to set this _after_ we've sent the
+ // expose event to the window, to mark that it now has received an expose.
+ // But some parts of Qt (mis)use this private member to check whether the
+ // window has been mapped yet, which they do in code that is triggered
+ // by the very same expose event we send below. To keep the code working
+ // we need to set the variable up front, until the code has been fixed.
p->receivedExpose = true;
}
+ // If the platform does not send paint events we need to synthesize them from expose events
+ const bool shouldSynthesizePaintEvents = !platformIntegration()->hasCapability(QPlatformIntegration::PaintEvents);
+
+ const bool wasExposed = p->exposed;
p->exposed = e->isExposed && window->screen();
+ // We expect that the platform plugins send DevicePixelRatioChange events.
+ // As a fail-safe make a final check here to make sure the cached DPR value is
+ // always up to date before sending the expose event.
+ if (e->isExposed && !e->region.isEmpty()) {
+ const bool dprWasChanged = QWindowPrivate::get(window)->updateDevicePixelRatio();
+ if (dprWasChanged)
+ qWarning() << "The cached device pixel ratio value was stale on window expose. "
+ << "Please file a QTBUG which explains how to reproduce.";
+ }
+
+ // We treat expose events for an already exposed window as paint events
+ if (wasExposed && p->exposed && shouldSynthesizePaintEvents) {
+ QPaintEvent paintEvent(e->region);
+ QCoreApplication::sendSpontaneousEvent(window, &paintEvent);
+ if (paintEvent.isAccepted())
+ return; // No need to send expose
+
+ // The paint event was not accepted, so we fall through and send an expose
+ // event instead, to maintain compatibility for clients that haven't adopted
+ // paint events yet.
+ }
+
QExposeEvent exposeEvent(e->region);
QCoreApplication::sendSpontaneousEvent(window, &exposeEvent);
+ e->eventAccepted = exposeEvent.isAccepted();
+
+ // If the window was just exposed we also need to send a paint event,
+ // so that clients that implement paint events will draw something.
+ // Note that we we can not skip this based on the expose event being
+ // accepted, as clients may implement exposeEvent to track the state
+ // change, but without drawing anything.
+ if (!wasExposed && p->exposed && shouldSynthesizePaintEvents) {
+ QPaintEvent paintEvent(e->region);
+ QCoreApplication::sendSpontaneousEvent(window, &paintEvent);
+ }
+}
+
+void QGuiApplicationPrivate::processPaintEvent(QWindowSystemInterfacePrivate::PaintEvent *e)
+{
+ Q_ASSERT_X(platformIntegration()->hasCapability(QPlatformIntegration::PaintEvents), "QGuiApplication",
+ "The platform sent paint events without claiming support for it in QPlatformIntegration::capabilities()");
+
+ if (!e->window)
+ return;
+
+ QPaintEvent paintEvent(e->region);
+ QCoreApplication::sendSpontaneousEvent(e->window, &paintEvent);
+
+ // We report back the accepted state to the platform, so that it can
+ // decide when the best time to send the fallback expose event is.
+ e->eventAccepted = paintEvent.isAccepted();
}
#if QT_CONFIG(draganddrop)
@@ -3251,7 +3423,7 @@ QClipboard * QGuiApplication::clipboard()
/*!
\since 5.4
\fn void QGuiApplication::paletteChanged(const QPalette &palette)
- \obsolete
+ \deprecated [6.0] Handle QEvent::ApplicationPaletteChange instead.
This signal is emitted when the \a palette of the application changes. Use
QEvent::ApplicationPaletteChanged instead.
@@ -3310,10 +3482,10 @@ bool QGuiApplicationPrivate::setPalette(const QPalette &palette)
// Resolve the palette against the theme palette, filling in
// any missing roles, while keeping the original resolve mask.
QPalette basePalette = qGuiApp ? qGuiApp->d_func()->basePalette() : Qt::gray;
- basePalette.resolve(0); // The base palette only contributes missing colors roles
+ basePalette.setResolveMask(0); // The base palette only contributes missing colors roles
QPalette resolvedPalette = palette.resolve(basePalette);
- if (app_pal && resolvedPalette == *app_pal && resolvedPalette.resolve() == app_pal->resolve())
+ if (app_pal && resolvedPalette == *app_pal && resolvedPalette.resolveMask() == app_pal->resolveMask())
return false;
if (!app_pal)
@@ -3321,7 +3493,7 @@ bool QGuiApplicationPrivate::setPalette(const QPalette &palette)
else
*app_pal = resolvedPalette;
- QCoreApplication::setAttribute(Qt::AA_SetPalette, app_pal->resolve() != 0);
+ QCoreApplication::setAttribute(Qt::AA_SetPalette, app_pal->resolveMask() != 0);
return true;
}
@@ -3335,11 +3507,13 @@ bool QGuiApplicationPrivate::setPalette(const QPalette &palette)
*/
QPalette QGuiApplicationPrivate::basePalette() const
{
- return platformTheme() ? *platformTheme()->palette() : Qt::gray;
+ const auto pf = platformTheme();
+ return pf && pf->palette() ? *pf->palette() : Qt::gray;
}
void QGuiApplicationPrivate::handlePaletteChanged(const char *className)
{
+#if QT_DEPRECATED_SINCE(6, 0)
if (!className) {
Q_ASSERT(app_pal);
QT_WARNING_PUSH
@@ -3347,6 +3521,9 @@ QT_WARNING_DISABLE_DEPRECATED
emit qGuiApp->paletteChanged(*QGuiApplicationPrivate::app_pal);
QT_WARNING_POP
}
+#else
+ Q_UNUSED(className);
+#endif // QT_DEPRECATED_SINCE(6, 0)
if (is_app_running && !is_app_closing) {
QEvent event(QEvent::ApplicationPaletteChange);
@@ -3362,7 +3539,7 @@ void QGuiApplicationPrivate::applyWindowGeometrySpecificationTo(QWindow *window)
/*!
\since 5.11
\fn void QGuiApplication::fontChanged(const QFont &font)
- \obsolete
+ \deprecated [6.0] Handle QEvent::ApplicationFontChange instead.
This signal is emitted when the \a font of the application changes. Use
QEvent::ApplicationFontChanged instead.
@@ -3405,10 +3582,14 @@ void QGuiApplication::setFont(const QFont &font)
if (emitChange && qGuiApp) {
auto font = *QGuiApplicationPrivate::app_font;
locker.unlock();
+#if QT_DEPRECATED_SINCE(6, 0)
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
emit qGuiApp->fontChanged(font);
QT_WARNING_POP
+#else
+ Q_UNUSED(font);
+#endif // QT_DEPRECATED_SINCE(6, 0)
QEvent event(QEvent::ApplicationFontChange);
QGuiApplication::sendEvent(qGuiApp, &event);
}
@@ -3441,8 +3622,16 @@ void QGuiApplicationPrivate::notifyLayoutDirectionChange()
}
}
-void QGuiApplicationPrivate::notifyActiveWindowChange(QWindow *)
+void QGuiApplicationPrivate::notifyActiveWindowChange(QWindow *prev)
{
+ if (prev) {
+ QEvent de(QEvent::WindowDeactivate);
+ QCoreApplication::sendEvent(prev, &de);
+ }
+ if (self->focus_window) {
+ QEvent ae(QEvent::WindowActivate);
+ QCoreApplication::sendEvent(focus_window, &ae);
+ }
}
/*!
@@ -3487,82 +3676,75 @@ void QGuiApplicationPrivate::notifyWindowIconChanged()
The default is \c true.
If this property is \c true, the applications quits when the last visible
- primary window (i.e. window with no parent) is closed.
+ \l{Primary and Secondary Windows}{primary window} (i.e. top level window
+ with no transient parent) is closed.
\sa quit(), QWindow::close()
*/
void QGuiApplication::setQuitOnLastWindowClosed(bool quit)
{
- QCoreApplication::setQuitLockEnabled(quit);
+ QGuiApplicationPrivate::quitOnLastWindowClosed = quit;
}
-
-
bool QGuiApplication::quitOnLastWindowClosed()
{
- return QCoreApplication::isQuitLockEnabled();
+ return QGuiApplicationPrivate::quitOnLastWindowClosed;
}
+void QGuiApplicationPrivate::maybeLastWindowClosed()
+{
+ if (!lastWindowClosed())
+ return;
+
+ if (in_exec)
+ emit q_func()->lastWindowClosed();
+
+ if (quitOnLastWindowClosed && canQuitAutomatically())
+ quitAutomatically();
+}
/*!
\fn void QGuiApplication::lastWindowClosed()
This signal is emitted from exec() when the last visible
- primary window (i.e. window with no parent) is closed.
+ \l{Primary and Secondary Windows}{primary window} (i.e.
+ top level window with no transient parent) is closed.
By default, QGuiApplication quits after this signal is emitted. This feature
can be turned off by setting \l quitOnLastWindowClosed to \c false.
- \sa QWindow::close(), QWindow::isTopLevel()
+ \sa QWindow::close(), QWindow::isTopLevel(), QWindow::transientParent()
*/
-void QGuiApplicationPrivate::emitLastWindowClosed()
-{
- if (qGuiApp && qGuiApp->d_func()->in_exec) {
- emit qGuiApp->lastWindowClosed();
- }
-}
-
-bool QGuiApplicationPrivate::shouldQuit()
+bool QGuiApplicationPrivate::lastWindowClosed() const
{
- const QWindowList processedWindows;
- return shouldQuitInternal(processedWindows);
-}
-
-bool QGuiApplicationPrivate::shouldQuitInternal(const QWindowList &processedWindows)
-{
- /* if there is no visible top-level window left, we allow the quit */
- QWindowList list = QGuiApplication::topLevelWindows();
- for (int i = 0; i < list.size(); ++i) {
- QWindow *w = list.at(i);
- if (processedWindows.contains(w))
+ for (auto *window : QGuiApplication::topLevelWindows()) {
+ auto *windowPrivate = qt_window_private(window);
+ if (!windowPrivate->participatesInLastWindowClosed())
continue;
- if (w->isVisible() && !w->transientParent())
+
+ if (windowPrivate->treatAsVisible())
return false;
- }
- return true;
+ }
+
+ return true;
}
-bool QGuiApplicationPrivate::tryCloseAllWindows()
+bool QGuiApplicationPrivate::canQuitAutomatically()
{
- return tryCloseRemainingWindows(QWindowList());
+ if (quitOnLastWindowClosed && !lastWindowClosed())
+ return false;
+
+ return QCoreApplicationPrivate::canQuitAutomatically();
}
-bool QGuiApplicationPrivate::tryCloseRemainingWindows(QWindowList processedWindows)
+void QGuiApplicationPrivate::quit()
{
- QWindowList list = QGuiApplication::topLevelWindows();
- for (int i = 0; i < list.size(); ++i) {
- QWindow *w = list.at(i);
- if (w->isVisible() && !processedWindows.contains(w)) {
- if (!w->close())
- return false;
- processedWindows.append(w);
- list = QGuiApplication::topLevelWindows();
- i = -1;
- }
- }
- return true;
+ if (auto *platformIntegration = QGuiApplicationPrivate::platformIntegration())
+ platformIntegration->quit();
+ else
+ QCoreApplicationPrivate::quit();
}
void QGuiApplicationPrivate::processApplicationTermination(QWindowSystemInterfacePrivate::WindowSystemEvent *windowSystemEvent)
@@ -3594,7 +3776,7 @@ Qt::ApplicationState QGuiApplication::applicationState()
Sets the high-DPI scale factor rounding policy for the application. The
\a policy decides how non-integer scale factors (such as Windows 150%) are
- handled, for applications that have AA_EnableHighDpiScaling enabled.
+ handled.
The two principal options are whether fractional scale factors should
be rounded to an integer or not. Keeping the scale factor as-is will
@@ -3607,17 +3789,16 @@ Qt::ApplicationState QGuiApplication::applicationState()
("small UI") or as 2x ("large UI"). See the Qt::HighDpiScaleFactorRoundingPolicy
enum for a complete list of all options.
- This function must be called before creating the application object,
- and can be overridden by setting the QT_SCALE_FACTOR_ROUNDING_POLICY
- environment variable. The QGuiApplication::highDpiScaleFactorRoundingPolicy()
+ This function must be called before creating the application object.
+ The QGuiApplication::highDpiScaleFactorRoundingPolicy()
accessor will reflect the environment, if set.
- The default value is Qt::HighDpiScaleFactorRoundingPolicy::Round.
- On Qt for Android the default is Qt::HighDpiScaleFactorRoundingPolicy::PassThrough,
- which preserves historical behavior from earlier Qt versions.
+ The default value is Qt::HighDpiScaleFactorRoundingPolicy::PassThrough.
*/
void QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy policy)
{
+ if (qApp)
+ qWarning("setHighDpiScaleFactorRoundingPolicy must be called before creating the QGuiApplication instance");
QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy = policy;
}
@@ -3666,57 +3847,6 @@ void QGuiApplicationPrivate::setApplicationState(Qt::ApplicationState state, boo
emit qApp->applicationStateChanged(applicationState);
}
-#ifndef QT_NO_SESSIONMANAGER
-// ### Qt6: consider removing the feature or making it less intrusive
-/*!
- \since 5.6
-
- Returns whether QGuiApplication will use fallback session management.
-
- The default is \c true.
-
- If this is \c true and the session manager allows user interaction,
- QGuiApplication will try to close toplevel windows after
- commitDataRequest() has been emitted. If a window cannot be closed, session
- shutdown will be canceled and the application will keep running.
-
- Fallback session management only benefits applications that have an
- "are you sure you want to close this window?" feature or other logic that
- prevents closing a toplevel window depending on certain conditions, and
- that do nothing to explicitly implement session management. In applications
- that \e do implement session management using the proper session management
- API, fallback session management interferes and may break session
- management logic.
-
- \warning If all windows \e are closed due to fallback session management
- and quitOnLastWindowClosed() is \c true, the application will quit before
- it is explicitly instructed to quit through the platform's session
- management protocol. That violation of protocol may prevent the platform
- session manager from saving application state.
-
- \sa setFallbackSessionManagementEnabled(),
- QSessionManager::allowsInteraction(), saveStateRequest(),
- commitDataRequest(), {Session Management}
-*/
-bool QGuiApplication::isFallbackSessionManagementEnabled()
-{
- return QGuiApplicationPrivate::is_fallback_session_management_enabled;
-}
-
-/*!
- \since 5.6
-
- Sets whether QGuiApplication will use fallback session management to
- \a enabled.
-
- \sa isFallbackSessionManagementEnabled()
-*/
-void QGuiApplication::setFallbackSessionManagementEnabled(bool enabled)
-{
- QGuiApplicationPrivate::is_fallback_session_management_enabled = enabled;
-}
-#endif // QT_NO_SESSIONMANAGER
-
/*!
\since 4.2
\fn void QGuiApplication::commitDataRequest(QSessionManager &manager)
@@ -3741,8 +3871,7 @@ void QGuiApplication::setFallbackSessionManagementEnabled(bool enabled)
\note You should use Qt::DirectConnection when connecting to this signal.
- \sa setFallbackSessionManagementEnabled(), isSessionRestored(),
- sessionId(), saveStateRequest(), {Session Management}
+ \sa isSessionRestored(), sessionId(), saveStateRequest(), {Session Management}
*/
/*!
@@ -3850,13 +3979,7 @@ void QGuiApplicationPrivate::commitData()
{
Q_Q(QGuiApplication);
is_saving_session = true;
-
emit q->commitDataRequest(*session_manager);
- if (is_fallback_session_management_enabled && session_manager->allowsInteraction()
- && !tryCloseAllWindows()) {
- session_manager->cancel();
- }
-
is_saving_session = false;
}
@@ -3896,7 +4019,8 @@ void QGuiApplication::sync()
\property QGuiApplication::layoutDirection
\brief the default layout direction for this application
- On system start-up, the default layout direction depends on the
+ On system start-up, or when the direction is explicitly set to
+ Qt::LayoutDirectionAuto, the default layout direction depends on the
application's language.
The notifier signal was introduced in Qt 5.4.
@@ -3906,11 +4030,15 @@ void QGuiApplication::sync()
void QGuiApplication::setLayoutDirection(Qt::LayoutDirection direction)
{
- if (layout_direction == direction || direction == Qt::LayoutDirectionAuto)
- return;
-
layout_direction = direction;
+ if (direction == Qt::LayoutDirectionAuto)
+ direction = qt_detectRTLLanguage() ? Qt::RightToLeft : Qt::LeftToRight;
+ // no change to the explicitly set or auto-detected layout direction
+ if (direction == effective_layout_direction)
+ return;
+
+ effective_layout_direction = direction;
if (qGuiApp) {
emit qGuiApp->layoutDirectionChanged(direction);
QGuiApplicationPrivate::self->notifyLayoutDirectionChange();
@@ -3919,10 +4047,15 @@ void QGuiApplication::setLayoutDirection(Qt::LayoutDirection direction)
Qt::LayoutDirection QGuiApplication::layoutDirection()
{
- // layout_direction is only ever Qt::LayoutDirectionAuto if setLayoutDirection
- // was never called, or called with Qt::LayoutDirectionAuto (which is a no-op).
- // In that case we return the default LeftToRight.
- return layout_direction == Qt::LayoutDirectionAuto ? Qt::LeftToRight : layout_direction;
+ /*
+ effective_layout_direction defaults to Qt::LeftToRight, and is updated with what is
+ auto-detected by a call to setLayoutDirection(Qt::LayoutDirectionAuto). This happens in
+ QGuiApplicationPrivate::init and when the language changes (or before if the application
+ calls the static function, but then no translators are installed so the auto-detection
+ always yields Qt::LeftToRight).
+ So we can be certain that it's always the right value.
+ */
+ return effective_layout_direction;
}
/*!
@@ -4029,7 +4162,7 @@ static inline void applyWindowCursor(const QList<QWindow *> &l)
Application cursors are stored on an internal stack. setOverrideCursor()
pushes the cursor onto the stack, and restoreOverrideCursor() pops the
- active cursor off the stack. changeOverrideCursor() changes the curently
+ active cursor off the stack. changeOverrideCursor() changes the currently
active application override cursor.
Every setOverrideCursor() must eventually be followed by a corresponding
@@ -4146,7 +4279,10 @@ QInputMethod *QGuiApplication::inputMethod()
/*!
\fn void QGuiApplication::fontDatabaseChanged()
- This signal is emitted when application fonts are loaded or removed.
+ This signal is emitted when the available fonts have changed.
+
+ This can happen when application fonts are added or removed, or when the
+ system fonts change.
\sa QFontDatabase::addApplicationFont(),
QFontDatabase::addApplicationFontFromData(),
@@ -4160,16 +4296,12 @@ QPixmap QGuiApplicationPrivate::getPixmapCursor(Qt::CursorShape cshape)
return QPixmap();
}
-void QGuiApplicationPrivate::notifyThemeChanged()
+QPoint QGuiApplicationPrivate::QLastCursorPosition::toPoint() const noexcept
{
- updatePalette();
-
- if (!(applicationResourceFlags & ApplicationFontExplicitlySet)) {
- const auto locker = qt_scoped_lock(applicationFontMutex);
- clearFontUnlocked();
- initFontUnlocked();
- }
- initThemeHints();
+ // Guard against the default initialization of qInf() (avoid UB or SIGFPE in conversion).
+ if (Q_UNLIKELY(qIsInf(thePoint.x())))
+ return QPoint(std::numeric_limits<int>::max(), std::numeric_limits<int>::max());
+ return thePoint.toPoint();
}
#if QT_CONFIG(draganddrop)
@@ -4183,10 +4315,8 @@ void QGuiApplicationPrivate::notifyDragStarted(const QDrag *drag)
const QColorTrcLut *QGuiApplicationPrivate::colorProfileForA8Text()
{
#ifdef Q_OS_WIN
- if (!m_a8ColorProfile){
- QColorTrcLut *cs = QColorTrcLut::fromGamma(2.31); // This is a hard-coded thing for Windows text rendering
- m_a8ColorProfile.reset(cs);
- }
+ if (!m_a8ColorProfile)
+ m_a8ColorProfile = QColorTrcLut::fromGamma(2.31); // This is a hard-coded thing for Windows text rendering
return m_a8ColorProfile.get();
#else
return colorProfileForA32Text();
@@ -4195,10 +4325,8 @@ const QColorTrcLut *QGuiApplicationPrivate::colorProfileForA8Text()
const QColorTrcLut *QGuiApplicationPrivate::colorProfileForA32Text()
{
- if (!m_a32ColorProfile) {
- QColorTrcLut *cs = QColorTrcLut::fromGamma(fontSmoothingGamma);
- m_a32ColorProfile.reset(cs);
- }
+ if (!m_a32ColorProfile)
+ m_a32ColorProfile = QColorTrcLut::fromGamma(fontSmoothingGamma);
return m_a32ColorProfile.get();
}
@@ -4234,6 +4362,40 @@ QInputDeviceManager *QGuiApplicationPrivate::inputDeviceManager()
return m_inputDeviceManager;
}
-#include "moc_qguiapplication.cpp"
+/*!
+ \fn template <typename QNativeInterface> QNativeInterface *QGuiApplication::nativeInterface() const
+
+ Returns a native interface of the given type for the application.
+
+ This function provides access to platform specific functionality
+ of QGuiApplication, as defined in the QNativeInterface namespace:
+
+ \annotatedlist native-interfaces-qguiapplication
+
+ If the requested interface is not available a \nullptr is returned.
+ */
+
+void *QGuiApplication::resolveInterface(const char *name, int revision) const
+{
+ using namespace QNativeInterface;
+ using namespace QNativeInterface::Private;
+
+ auto *platformIntegration = QGuiApplicationPrivate::platformIntegration();
+ Q_UNUSED(platformIntegration);
+
+#if defined(Q_OS_WIN)
+ QT_NATIVE_INTERFACE_RETURN_IF(QWindowsApplication, platformIntegration);
+#endif
+#if QT_CONFIG(xcb)
+ QT_NATIVE_INTERFACE_RETURN_IF(QX11Application, platformNativeInterface());
+#endif
+#if QT_CONFIG(wayland)
+ QT_NATIVE_INTERFACE_RETURN_IF(QWaylandApplication, platformNativeInterface());
+#endif
+
+ return QCoreApplication::resolveInterface(name, revision);
+}
QT_END_NAMESPACE
+
+#include "moc_qguiapplication.cpp"