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.cpp732
1 files changed, 447 insertions, 285 deletions
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 313f1bcb54..c97374e975 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 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"
@@ -45,6 +9,7 @@
#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>
@@ -52,21 +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>
@@ -77,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>
@@ -85,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"
@@ -123,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())) { \
@@ -138,80 +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 =
+Q_CONSTINIT Qt::HighDpiScaleFactorRoundingPolicy QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy =
Qt::HighDpiScaleFactorRoundingPolicy::PassThrough;
-QPointer<QWindow> QGuiApplicationPrivate::currentDragWindow;
+Q_CONSTINIT QPointer<QWindow> QGuiApplicationPrivate::currentDragWindow;
-QList<QGuiApplicationPrivate::TabletPointData> QGuiApplicationPrivate::tabletDevicePoints; // TODO remove
+Q_CONSTINIT QList<QGuiApplicationPrivate::TabletPointData> QGuiApplicationPrivate::tabletDevicePoints; // TODO remove
-QPlatformIntegration *QGuiApplicationPrivate::platform_integration = nullptr;
-QPlatformTheme *QGuiApplicationPrivate::platform_theme = nullptr;
+Q_CONSTINIT QPlatformIntegration *QGuiApplicationPrivate::platform_integration = nullptr;
+Q_CONSTINIT QPlatformTheme *QGuiApplicationPrivate::platform_theme = nullptr;
-QList<QObject *> QGuiApplicationPrivate::generic_plugin_list;
+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
-Qt::MouseButton QGuiApplicationPrivate::mousePressButton = Qt::NoButton;
+Q_CONSTINIT Qt::MouseButton QGuiApplicationPrivate::mousePressButton = Qt::NoButton;
-static int mouseDoubleClickDistance = 0;
-static int touchDoubleTapDistance = 0;
+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;
-int QGuiApplicationPrivate::m_fakeMouseSourcePointId = -1;
+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;
-bool QGuiApplicationPrivate::quitOnLastWindowClosed = true;
+Q_CONSTINIT bool QGuiApplicationPrivate::quitOnLastWindowClosed = true;
extern void qRegisterGuiVariant();
#if QT_CONFIG(animation)
@@ -224,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()
@@ -254,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)
@@ -281,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);
@@ -582,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
@@ -597,17 +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 {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
@@ -621,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.
@@ -649,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();
@@ -707,15 +692,16 @@ QGuiApplication::~QGuiApplication()
QGuiApplicationPrivate::desktopFileName = nullptr;
QGuiApplicationPrivate::mouse_buttons = Qt::NoButton;
QGuiApplicationPrivate::modifier_buttons = Qt::NoModifier;
- QGuiApplicationPrivate::lastCursorPosition = {qreal(qInf()), qreal(qInf())};
+ QGuiApplicationPrivate::lastCursorPosition.reset();
QGuiApplicationPrivate::currentMousePressWindow = QGuiApplicationPrivate::currentMouseWindow = nullptr;
QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive;
+ QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy = Qt::HighDpiScaleFactorRoundingPolicy::PassThrough;
QGuiApplicationPrivate::currentDragWindow = nullptr;
QGuiApplicationPrivate::tabletDevicePoints.clear();
}
-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)
@@ -764,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
@@ -784,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()
@@ -810,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)
@@ -861,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);
}
@@ -873,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
@@ -886,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:
@@ -942,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()
{
@@ -1126,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;
@@ -1173,32 +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();
@@ -1208,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.";
@@ -1221,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;
@@ -1232,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
@@ -1249,45 +1290,57 @@ static void init_platform(const QString &pluginNamesWithArguments, const QString
// 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 =
@@ -1296,25 +1349,24 @@ static void init_platform(const QString &pluginNamesWithArguments, const QString
}
}
}
-#endif
const auto platformIntegration = QGuiApplicationPrivate::platformIntegration();
fontSmoothingGamma = platformIntegration->styleHint(QPlatformIntegration::FontSmoothingGamma).toReal();
QCoreApplication::setAttribute(Qt::AA_DontShowShortcutsInContextMenus,
- !platformIntegration->styleHint(QPlatformIntegration::ShowShortcutsInContextMenus).toBool());
+ !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
@@ -1477,7 +1529,9 @@ void QGuiApplicationPrivate::createPlatformIntegration()
Q_UNUSED(platformExplicitlySelected);
- init_platform(QLatin1String(platformName), platformPluginPath, platformThemeName, argc, argv);
+ 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);
@@ -1496,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();
@@ -1510,7 +1568,7 @@ void QGuiApplicationPrivate::eventDispatcherReady()
platform_integration->initialize();
}
-void QGuiApplicationPrivate::init()
+void Q_TRACE_INSTRUMENT(qtgui) QGuiApplicationPrivate::init()
{
Q_TRACE_SCOPE(QGuiApplicationPrivate_init);
@@ -1560,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
@@ -1573,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);
@@ -1669,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,
@@ -1684,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();
@@ -1696,7 +1754,7 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate()
QCursorData::cleanup();
#endif
- layout_direction = Qt::LeftToRight;
+ layout_direction = Qt::LayoutDirectionAuto;
cleanupThreadData();
@@ -1715,6 +1773,10 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate()
}
#endif
+#if QT_CONFIG(vulkan)
+ QVulkanDefaultInstance::cleanup();
+#endif
+
platform_integration->destroy();
delete platform_theme;
@@ -1785,7 +1847,7 @@ Qt::KeyboardModifiers QGuiApplication::queryKeyboardModifiers()
{
CHECK_QAPP_INSTANCE(Qt::KeyboardModifiers{})
QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration();
- return pi->queryKeyboardModifiers();
+ return pi->keyMapper()->queryKeyboardModifiers();
}
/*!
@@ -1843,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
@@ -1857,7 +1920,7 @@ QFunctionPointer QGuiApplication::platformFunction(const QByteArray &function)
*/
int QGuiApplication::exec()
{
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
QAccessible::setRootObject(qApp);
#endif
return QCoreApplication::exec();
@@ -1935,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()) {
@@ -1959,8 +2027,10 @@ bool QGuiApplication::event(QEvent *e)
return true;
}
}
+ break;
+ default:
+ break;
}
-
return QCoreApplication::event(e);
}
@@ -1991,8 +2061,9 @@ bool QGuiApplicationPrivate::processNativeEvent(QWindow *window, const QByteArra
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) {
@@ -2017,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));
@@ -2026,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;
@@ -2173,22 +2247,24 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
QPointF localPoint = e->localPos;
bool doubleClick = false;
auto persistentEPD = devPriv->pointById(0);
- const auto &persistentPoint = persistentEPD->eventPoint;
if (mouseMove) {
QGuiApplicationPrivate::lastCursorPosition = globalPoint;
const auto doubleClickDistance = (e->device && e->device->type() == QInputDevice::DeviceType::Mouse ?
mouseDoubleClickDistance : touchDoubleTapDistance);
- const auto pressPos = persistentPoint.globalPressPosition();
+ 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 - persistentPoint.pressTimestamp() < doubleClickInterval && button == mousePressButton;
+ doubleClick = e->timestamp - lastPressTimestamp
+ < doubleClickInterval && button == mousePressButton;
mousePressButton = button;
+ lastPressTimestamp = e ->timestamp;
}
}
@@ -2231,9 +2307,11 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
#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);
if (window->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) {
@@ -2290,8 +2368,10 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
}
}
if (type == QEvent::MouseButtonRelease && e->buttons == Qt::NoButton) {
- ev.setExclusiveGrabber(persistentPoint, nullptr);
- ev.clearPassiveGrabbers(persistentPoint);
+ if (auto *persistentEPD = devPriv->queryPointById(0)) {
+ ev.setExclusiveGrabber(persistentEPD->eventPoint, nullptr);
+ ev.clearPassiveGrabbers(persistentEPD->eventPoint);
+ }
}
}
@@ -2324,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)
@@ -2431,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;
@@ -2484,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);
@@ -2497,37 +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);
- }
+ QWindow *window = wse->window.data();
+ if (!window)
+ return;
- // We may have changed scaling; trigger resize event if needed,
- // except on Windows, where we send resize events during WM_DPICHANGED
- // event handling. FIXME: unify DPI change handling across all platforms.
-#ifndef Q_OS_WIN
- if (window->handle()) {
- QWindowSystemInterfacePrivate::GeometryChangeEvent gce(window, QHighDpi::fromNativePixels(window->handle()->geometry(), window));
- processGeometryChangeEvent(&gce);
- }
-#endif
+ 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())
@@ -2542,11 +2639,33 @@ 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();
+
+ QEvent themeChangeEvent(QEvent::ThemeChange);
+ const QWindowList windows = tce->window ? QWindowList{tce->window} : window_list;
+ for (auto *window : windows)
+ QGuiApplication::sendSpontaneousEvent(window, &themeChangeEvent);
+}
+
+void QGuiApplicationPrivate::handleThemeChanged()
+{
+ const auto newColorScheme = platformTheme() ? platformTheme()->colorScheme()
+ : Qt::ColorScheme::Unknown;
+ QStyleHintsPrivate::get(QGuiApplication::styleHints())->updateColorScheme(newColorScheme);
+
+ 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)
@@ -2605,8 +2724,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;
}
@@ -2711,6 +2832,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
@@ -2789,6 +2912,9 @@ void QGuiApplicationPrivate::processContextMenuEvent(QWindowSystemInterfacePriva
void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::TouchEvent *e)
{
+ if (!QInputDevicePrivate::isRegistered(e->device))
+ return;
+
modifier_buttons = e->modifiers;
QPointingDevice *device = const_cast<QPointingDevice *>(static_cast<const QPointingDevice *>(e->device));
QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(device);
@@ -2798,17 +2924,17 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
// Send the TouchCancel to all windows with active touches and clean up.
QTouchEvent touchEvent(QEvent::TouchCancel, device, e->modifiers);
touchEvent.setTimestamp(e->timestamp);
- QSet<QWindow *> windowsNeedingCancel;
+ 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);
}
- 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) {
@@ -2865,15 +2991,15 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
case QEventPoint::State::Released:
if (Q_UNLIKELY(!window.isNull() && window != QMutableEventPoint::window(ep)))
- qCWarning(lcPtrDispatch) << "delivering touch release to same window"
- << QMutableEventPoint::window(ep) << "not" << window.data();
+ qCDebug(lcPtrDispatch) << "delivering touch release to same window"
+ << QMutableEventPoint::window(ep) << "not" << window.data();
window = QMutableEventPoint::window(ep);
break;
default: // update or stationary
if (Q_UNLIKELY(!window.isNull() && window != QMutableEventPoint::window(ep)))
- qCWarning(lcPtrDispatch) << "delivering touch update to same window"
- << QMutableEventPoint::window(ep) << "not" << window.data();
+ qCDebug(lcPtrDispatch) << "delivering touch update to same window"
+ << QMutableEventPoint::window(ep) << "not" << window.data();
window = QMutableEventPoint::window(ep);
break;
}
@@ -2957,7 +3083,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
QEvent::Type mouseEventType = QEvent::MouseMove;
Qt::MouseButton button = Qt::NoButton;
Qt::MouseButtons buttons = Qt::LeftButton;
- if (eventType == QEvent::TouchBegin && m_fakeMouseSourcePointId < 0) {
+ if (eventType == QEvent::TouchBegin || m_fakeMouseSourcePointId < 0) {
m_fakeMouseSourcePointId = touchEvent.point(0).id();
qCDebug(lcPtrDispatch) << "synthesizing mouse events from touchpoint" << m_fakeMouseSourcePointId;
}
@@ -3041,26 +3167,16 @@ 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;
- const Qt::ScreenOrientation primaryOrientation = s->primaryOrientation();
- if (geometryChanged)
s->d_func()->updatePrimaryOrientation();
-
- s->d_func()->emitGeometryChangeSignals(geometryChanged, availableGeometryChanged);
-
- if (geometryChanged) {
- emit s->physicalSizeChanged(s->physicalSize());
- emit s->logicalDotsPerInchChanged(s->logicalDotsPerInch());
-
- if (s->primaryOrientation() != primaryOrientation)
- emit s->primaryOrientationChanged(s->primaryOrientation());
}
resetCachedDevicePixelRatio();
@@ -3077,11 +3193,16 @@ void QGuiApplicationPrivate::processScreenLogicalDotsPerInchChange(QWindowSystem
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();
}
@@ -3141,6 +3262,16 @@ void QGuiApplicationPrivate::processExposeEvent(QWindowSystemInterfacePrivate::E
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);
@@ -3366,11 +3497,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
@@ -3378,6 +3511,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);
@@ -3436,10 +3572,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);
}
@@ -3525,9 +3665,13 @@ void QGuiApplicationPrivate::notifyWindowIconChanged()
The default is \c true.
- If this property is \c true, the applications quits when the last visible
- \l{Primary and Secondary Windows}{primary window} (i.e. top level window
- with no transient parent) is closed.
+ If this property is \c true, the application will attempt to
+ quit when the last visible \l{Primary and Secondary Windows}{primary window}
+ (i.e. top level window with no transient parent) is closed.
+
+ Note that attempting a quit may not necessarily result in the
+ application quitting, for example if there still are active
+ QEventLoopLocker instances, or the QEvent::Quit event is ignored.
\sa quit(), QWindow::close()
*/
@@ -3583,7 +3727,13 @@ bool QGuiApplicationPrivate::lastWindowClosed() const
bool QGuiApplicationPrivate::canQuitAutomatically()
{
- if (quitOnLastWindowClosed && !lastWindowClosed())
+ // The automatic quit functionality is triggered by
+ // both QEventLoopLocker and maybeLastWindowClosed.
+ // Although the former is a QCoreApplication feature
+ // we don't want to quit the application when there
+ // are open windows, regardless of whether the app
+ // also quits automatically on maybeLastWindowClosed.
+ if (!lastWindowClosed())
return false;
return QCoreApplicationPrivate::canQuitAutomatically();
@@ -3647,6 +3797,8 @@ Qt::ApplicationState QGuiApplication::applicationState()
*/
void QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy policy)
{
+ if (qApp)
+ qWarning("setHighDpiScaleFactorRoundingPolicy must be called before creating the QGuiApplication instance");
QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy = policy;
}
@@ -3867,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.
@@ -3877,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();
@@ -3890,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;
}
/*!
@@ -4117,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(),
@@ -4131,18 +4296,12 @@ QPixmap QGuiApplicationPrivate::getPixmapCursor(Qt::CursorShape cshape)
return QPixmap();
}
-void QGuiApplicationPrivate::notifyThemeChanged()
+QPoint QGuiApplicationPrivate::QLastCursorPosition::toPoint() const noexcept
{
- updatePalette();
-
- QAbstractFileIconProviderPrivate::clearIconTypeCache();
-
- 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)
@@ -4230,10 +4389,13 @@ void *QGuiApplication::resolveInterface(const char *name, int revision) const
#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);
}
-#include "moc_qguiapplication.cpp"
-
QT_END_NAMESPACE
+
+#include "moc_qguiapplication.cpp"