diff options
Diffstat (limited to 'src/gui/kernel/qguiapplication.cpp')
-rw-r--r-- | src/gui/kernel/qguiapplication.cpp | 237 |
1 files changed, 154 insertions, 83 deletions
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 741a02875a..c97374e975 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -9,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> @@ -16,12 +17,15 @@ #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> @@ -50,6 +54,7 @@ #include <qpa/qwindowsysteminterface.h> #include <qpa/qwindowsysteminterface_p.h> #include "private/qwindow_p.h" +#include "private/qicon_p.h" #include "private/qcursor_p.h" #if QT_CONFIG(opengl) # include "private/qopenglcontext_p.h" @@ -96,12 +101,14 @@ #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(...) \ @@ -229,7 +236,7 @@ static void initThemeHints() static bool checkNeedPortalSupport() { #if QT_CONFIG(dbus) - return !QStandardPaths::locate(QStandardPaths::RuntimeLocation, "flatpak-info"_L1).isEmpty() || qEnvironmentVariableIsSet("SNAP"); + return QFileInfo::exists("/.flatpak-info"_L1) || qEnvironmentVariableIsSet("SNAP"); #else return false; #endif // QT_CONFIG(dbus) @@ -256,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); @@ -557,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 @@ -579,13 +588,10 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME \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 @@ -599,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. @@ -749,7 +756,8 @@ QString QGuiApplication::applicationDisplayName() 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. + 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 @@ -770,9 +778,9 @@ void QGuiApplication::setBadgeNumber(qint64 number) \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 @@ -786,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() @@ -812,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) @@ -946,6 +963,8 @@ bool QGuiApplicationPrivate::isWindowBlocked(QWindow *window, QWindow **blocking /*! Returns the QWindow that receives events tied to focus, such as key events. + + \sa QWindow::requestActivate() */ QWindow *QGuiApplication::focusWindow() { @@ -1175,14 +1194,26 @@ QWindow *QGuiApplication::topLevelAt(const QPoint &pos) \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"); @@ -1217,6 +1248,10 @@ static void init_platform(const QString &pluginNamesWithArguments, const QString 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."; @@ -1305,7 +1340,7 @@ static void init_platform(const QString &pluginNamesWithArguments, const QString if (!platformArguments.isEmpty()) { if (QObject *nativeInterface = QGuiApplicationPrivate::platform_integration->nativeInterface()) { for (const QString &argument : std::as_const(platformArguments)) { - const int equalsPos = argument.indexOf(u'='); + const qsizetype equalsPos = argument.indexOf(u'='); const QByteArray name = equalsPos != -1 ? argument.left(equalsPos).toUtf8() : argument.toUtf8(); const QVariant value = @@ -1325,7 +1360,7 @@ static void init_plugins(const QList<QByteArray> &pluginList) { 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(QLatin1StringView(pluginSpec), QString()); @@ -1496,7 +1531,7 @@ void QGuiApplicationPrivate::createPlatformIntegration() init_platform(QLatin1StringView(platformName), platformPluginPath, platformThemeName, argc, argv); if (const QPlatformTheme *theme = platformTheme()) - QStyleHintsPrivate::get(QGuiApplication::styleHints())->setAppearance(theme->appearance()); + QStyleHintsPrivate::get(QGuiApplication::styleHints())->updateColorScheme(theme->colorScheme()); if (!icon.isEmpty()) forcedWindowIcon = QDir::isAbsolutePath(icon) ? QIcon(icon) : QIcon::fromTheme(icon); @@ -1515,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(); @@ -1592,7 +1631,7 @@ void Q_TRACE_INSTRUMENT(qtgui) QGuiApplicationPrivate::init() ++i; if (argv[i] && *argv[i]) { session_id = QString::fromLatin1(argv[i]); - int p = session_id.indexOf(u'_'); + qsizetype p = session_id.indexOf(u'_'); if (p >= 0) { session_key = session_id.mid(p +1); session_id = session_id.left(p); @@ -1808,7 +1847,7 @@ Qt::KeyboardModifiers QGuiApplication::queryKeyboardModifiers() { CHECK_QAPP_INSTANCE(Qt::KeyboardModifiers{}) QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration(); - return pi->queryKeyboardModifiers(); + return pi->keyMapper()->queryKeyboardModifiers(); } /*! @@ -1866,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 @@ -1958,7 +1998,8 @@ bool QGuiApplication::notify(QObject *object, QEvent *event) */ bool QGuiApplication::event(QEvent *e) { - if (e->type() == QEvent::LanguageChange) { + 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); @@ -1966,13 +2007,15 @@ bool QGuiApplication::event(QEvent *e) 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()) { @@ -1984,8 +2027,10 @@ bool QGuiApplication::event(QEvent *e) return true; } } + break; + default: + break; } - return QCoreApplication::event(e); } @@ -2043,8 +2088,8 @@ void Q_TRACE_INSTRUMENT(qtgui) QGuiApplicationPrivate::processWindowSystemEvent( 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)); @@ -2052,6 +2097,9 @@ void Q_TRACE_INSTRUMENT(qtgui) QGuiApplicationPrivate::processWindowSystemEvent( 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; @@ -2209,12 +2257,14 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo 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 - persistentEPD->eventPoint.pressTimestamp() + doubleClick = e->timestamp - lastPressTimestamp < doubleClickInterval && button == mousePressButton; mousePressButton = button; + lastPressTimestamp = e ->timestamp; } } @@ -2354,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) @@ -2461,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; @@ -2552,28 +2603,28 @@ void QGuiApplicationPrivate::processWindowStateChangedEvent(QWindowSystemInterfa 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()) @@ -2590,31 +2641,23 @@ void QGuiApplicationPrivate::processThemeChanged(QWindowSystemInterfacePrivate:: if (self) 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); - - QStyleHintsPrivate::get(QGuiApplication::styleHints())->setAppearance(appearance()); -} - -/*! - \internal - \brief QGuiApplicationPrivate::appearance - \return the platform theme's appearance - or Qt::Appearance::Unknown if a platform theme cannot be established - Qt::Appearance. - */ -Qt::Appearance QGuiApplicationPrivate::appearance() -{ - return platformTheme() ? platformTheme()->appearance() - : Qt::Appearance::Unknown; } 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)) { @@ -2684,6 +2727,7 @@ void QGuiApplicationPrivate::processCloseEvent(QWindowSystemInterfacePrivate::Cl 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; } @@ -2880,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) { @@ -3156,6 +3200,10 @@ void QGuiApplicationPrivate::processScreenLogicalDotsPerInchChange(QWindowSystem s->d_func()->updateGeometry(); } + for (QWindow *window : QGuiApplication::allWindows()) + if (window->screen() == e->screen) + QWindowPrivate::get(window)->updateDevicePixelRatio(); + resetCachedDevicePixelRatio(); } @@ -3214,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); @@ -3439,7 +3497,8 @@ 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) @@ -3606,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() */ @@ -3664,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(); @@ -3728,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; } @@ -4318,7 +4389,7 @@ void *QGuiApplication::resolveInterface(const char *name, int revision) const #if QT_CONFIG(xcb) QT_NATIVE_INTERFACE_RETURN_IF(QX11Application, platformNativeInterface()); #endif -#if defined(Q_OS_UNIX) +#if QT_CONFIG(wayland) QT_NATIVE_INTERFACE_RETURN_IF(QWaylandApplication, platformNativeInterface()); #endif |