Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qguiapplication.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
7
8#include "private/qguiapplication_p.h"
9#include "private/qabstractfileiconprovider_p.h"
10#include <qpa/qplatformintegrationfactory_p.h>
11#include "private/qevent_p.h"
12#include "private/qeventpoint_p.h"
13#include "private/qiconloader_p.h"
14#include "qfont.h"
16#include <qpa/qplatformfontdatabase.h>
17#include <qpa/qplatformwindow.h>
18#include <qpa/qplatformnativeinterface.h>
19#include <qpa/qplatformtheme.h>
20#include <qpa/qplatformintegration.h>
21#include <qpa/qplatformkeymapper.h>
22
23#include <QtCore/QAbstractEventDispatcher>
24#include <QtCore/QFileInfo>
25#include <QtCore/QStandardPaths>
26#include <QtCore/QVariant>
27#include <QtCore/private/qcoreapplication_p.h>
28#include <QtCore/private/qabstracteventdispatcher_p.h>
29#include <QtCore/private/qminimalflatset_p.h>
30#include <QtCore/qmutex.h>
31#include <QtCore/private/qthread_p.h>
32#include <QtCore/private/qlocking_p.h>
33#include <QtCore/private/qflatmap_p.h>
34#include <QtCore/qdir.h>
35#include <QtCore/qlibraryinfo.h>
36#include <QtCore/private/qnumeric_p.h>
37#include <QtDebug>
38#if QT_CONFIG(accessibility)
39#include "qaccessible.h"
40#include <QtGui/private/qaccessiblewindow_p.h>
41#endif
42#include <qpalette.h>
43#include <qscreen.h>
45#include <private/qcolortrclut_p.h>
46#include <private/qscreen_p.h>
47
48#include <QtGui/qgenericpluginfactory.h>
49#include <QtGui/qstylehints.h>
50#include <QtGui/private/qstylehints_p.h>
51#include <QtGui/qinputmethod.h>
52#include <QtGui/qpixmapcache.h>
53#include <qpa/qplatforminputcontext.h>
54#include <qpa/qplatforminputcontext_p.h>
55
56#include <qpa/qwindowsysteminterface.h>
57#include <qpa/qwindowsysteminterface_p.h>
58#include "private/qwindow_p.h"
59#include "private/qicon_p.h"
60#include "private/qcursor_p.h"
61#if QT_CONFIG(opengl)
62# include "private/qopenglcontext_p.h"
63#endif
64#include "private/qinputdevicemanager_p.h"
65#include "private/qinputmethod_p.h"
66#include "private/qpointingdevice_p.h"
67
68#include <qpa/qplatformthemefactory_p.h>
69
70#if QT_CONFIG(draganddrop)
71#include <qpa/qplatformdrag.h>
72#include <private/qdnd_p.h>
73#endif
74
75#ifndef QT_NO_CURSOR
76#include <qpa/qplatformcursor.h>
77#endif
78
79#include <QtGui/QPixmap>
80
81#ifndef QT_NO_CLIPBOARD
82#include <QtGui/QClipboard>
83#endif
84
85#if QT_CONFIG(library)
86#include <QtCore/QLibrary>
87#endif
88
89#if defined(Q_OS_APPLE)
90# include "private/qcore_mac_p.h"
91#elif defined(Q_OS_WIN)
92# include <QtCore/qt_windows.h>
93# include <QtCore/QLibraryInfo>
94#endif // Q_OS_WIN
95
96#ifdef Q_OS_WASM
97#include <emscripten.h>
98#endif
99
100#if QT_CONFIG(vulkan)
101#include <private/qvulkandefaultinstance_p.h>
102#endif
103
104#if QT_CONFIG(thread)
105#include <QtCore/QThreadPool>
106#endif
107
108#include <qtgui_tracepoints_p.h>
109
110#include <private/qtools_p.h>
111
112#include <limits>
113
115
116Q_LOGGING_CATEGORY(lcPopup, "qt.gui.popup");
117Q_LOGGING_CATEGORY(lcVirtualKeyboard, "qt.gui.virtualkeyboard");
118
119using namespace Qt::StringLiterals;
120using namespace QtMiscUtils;
121
122// Helper macro for static functions to check on the existence of the application class.
123#define CHECK_QAPP_INSTANCE(...)
124 if (Q_LIKELY(QCoreApplication::instance())) {
125 } else {
126 qWarning("Must construct a QGuiApplication first.");
127 return __VA_ARGS__;
128 }
129
132
133Q_CONSTINIT Qt::MouseButtons QGuiApplicationPrivate::mouse_buttons = Qt::NoButton;
134Q_CONSTINIT Qt::KeyboardModifiers QGuiApplicationPrivate::modifier_buttons = Qt::NoModifier;
135
136Q_CONSTINIT QGuiApplicationPrivate::QLastCursorPosition QGuiApplicationPrivate::lastCursorPosition;
137
138Q_CONSTINIT QWindow *QGuiApplicationPrivate::currentMouseWindow = nullptr;
139
140Q_CONSTINIT QString QGuiApplicationPrivate::styleOverride;
141
142Q_CONSTINIT Qt::ApplicationState QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive;
143
144Q_CONSTINIT Qt::HighDpiScaleFactorRoundingPolicy QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy =
145 Qt::HighDpiScaleFactorRoundingPolicy::PassThrough;
146
147Q_CONSTINIT QPointer<QWindow> QGuiApplicationPrivate::currentDragWindow;
148
149Q_CONSTINIT QList<QGuiApplicationPrivate::TabletPointData> QGuiApplicationPrivate::tabletDevicePoints; // TODO remove
150
151Q_CONSTINIT QPlatformIntegration *QGuiApplicationPrivate::platform_integration = nullptr;
152Q_CONSTINIT QPlatformTheme *QGuiApplicationPrivate::platform_theme = nullptr;
153
154Q_CONSTINIT QList<QObject *> QGuiApplicationPrivate::generic_plugin_list;
155
160
162
163Q_CONSTINIT QIcon *QGuiApplicationPrivate::app_icon = nullptr;
164
165Q_CONSTINIT QString *QGuiApplicationPrivate::platform_name = nullptr;
166Q_CONSTINIT QString *QGuiApplicationPrivate::displayName = nullptr;
167Q_CONSTINIT QString *QGuiApplicationPrivate::desktopFileName = nullptr;
168
169Q_CONSTINIT QPalette *QGuiApplicationPrivate::app_pal = nullptr; // default application palette
170
171Q_CONSTINIT Qt::MouseButton QGuiApplicationPrivate::mousePressButton = Qt::NoButton;
172
175
176Q_CONSTINIT QWindow *QGuiApplicationPrivate::currentMousePressWindow = nullptr;
177
178Q_CONSTINIT static Qt::LayoutDirection layout_direction = Qt::LayoutDirectionAuto;
179Q_CONSTINIT static Qt::LayoutDirection effective_layout_direction = Qt::LeftToRight;
180Q_CONSTINIT static bool force_reverse = false;
181
182Q_DECL_DEPRECATED_X("Use QGuiApplicationPrivate::instance() instead")
183Q_CONSTINIT QGuiApplicationPrivate *QGuiApplicationPrivate::self = nullptr;
184
185Q_CONSTINIT int QGuiApplicationPrivate::m_fakeMouseSourcePointId = -1;
186
187#ifndef QT_NO_CLIPBOARD
188Q_CONSTINIT QClipboard *QGuiApplicationPrivate::qt_clipboard = nullptr;
189#endif
190
191Q_CONSTINIT QList<QScreen *> QGuiApplicationPrivate::screen_list;
192
193Q_CONSTINIT QWindowList QGuiApplicationPrivate::window_list;
194Q_CONSTINIT QWindowList QGuiApplicationPrivate::popup_list;
195Q_CONSTINIT const QWindow *QGuiApplicationPrivate::active_popup_on_press = nullptr;
196Q_CONSTINIT QWindow *QGuiApplicationPrivate::focus_window = nullptr;
197
198Q_CONSTINIT static QBasicMutex applicationFontMutex;
199Q_CONSTINIT QFont *QGuiApplicationPrivate::app_font = nullptr;
200Q_CONSTINIT QStyleHints *QGuiApplicationPrivate::styleHints = nullptr;
201Q_CONSTINIT bool QGuiApplicationPrivate::obey_desktop_settings = true;
202Q_CONSTINIT bool QGuiApplicationPrivate::popup_closed_on_press = false;
203
204Q_CONSTINIT QInputDeviceManager *QGuiApplicationPrivate::m_inputDeviceManager = nullptr;
205
206Q_CONSTINIT qreal QGuiApplicationPrivate::m_maxDevicePixelRatio = 0.0;
207Q_CONSTINIT QBasicAtomicInt QGuiApplicationPrivate::m_primaryScreenDpis = Q_BASIC_ATOMIC_INITIALIZER(0);
208
209Q_CONSTINIT static qreal fontSmoothingGamma = 1.7;
210
211Q_CONSTINIT bool QGuiApplicationPrivate::quitOnLastWindowClosed = true;
212
213extern void qRegisterGuiVariant();
214#if QT_CONFIG(animation)
215extern void qRegisterGuiGetInterpolator();
216#endif
217
219{
220 return force_reverse ^
221 (QGuiApplication::tr("QT_LAYOUT_DIRECTION",
222 "Translate this string to the string 'LTR' in left-to-right"
223 " languages or to 'RTL' in right-to-left languages (such as Hebrew"
224 " and Arabic) to get proper widget layout.") == "RTL"_L1);
225}
226
227static void initFontUnlocked()
228{
229 if (!QGuiApplicationPrivate::app_font) {
230 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
231 if (const QFont *font = theme->font(QPlatformTheme::SystemFont))
232 QGuiApplicationPrivate::app_font = new QFont(*font);
233 }
234 if (!QGuiApplicationPrivate::app_font)
235 QGuiApplicationPrivate::app_font =
236 new QFont(QGuiApplicationPrivate::platformIntegration()->fontDatabase()->defaultFont());
237}
238
239static inline void clearFontUnlocked()
240{
241 delete QGuiApplicationPrivate::app_font;
242 QGuiApplicationPrivate::app_font = nullptr;
243}
244
245static void initThemeHints()
246{
247 mouseDoubleClickDistance = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::MouseDoubleClickDistance).toInt();
248 touchDoubleTapDistance = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::TouchDoubleTapDistance).toInt();
249}
250
251#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
252static bool checkNeedPortalSupport()
253{
254#if QT_CONFIG(dbus)
255 return QFileInfo::exists("/.flatpak-info"_L1) || qEnvironmentVariableIsSet("SNAP");
256#else
257 return false;
258#endif // QT_CONFIG(dbus)
259}
260#endif
261
262// Using aggregate initialization instead of ctor so we can have a POD global static
263#define Q_WINDOW_GEOMETRY_SPECIFICATION_INITIALIZER { Qt::TopLeftCorner, -1, -1, -1, -1 }
264
265// Geometry specification for top level windows following the convention of the
266// -geometry command line arguments in X11 (see XParseGeometry).
268{
269 static QWindowGeometrySpecification fromArgument(const QByteArray &a);
270 void applyTo(QWindow *window) const;
271
275 int width;
277};
278
279// Parse a token of a X11 geometry specification "200x100+10-20".
280static inline int nextGeometryToken(const QByteArray &a, int &pos, char *op)
281{
282 *op = 0;
283 const qsizetype size = a.size();
284 if (pos >= size)
285 return -1;
286
287 *op = a.at(pos);
288 if (*op == '+' || *op == '-' || *op == 'x')
289 pos++;
290 else if (isAsciiDigit(*op))
291 *op = 'x'; // If it starts with a digit, it is supposed to be a width specification.
292 else
293 return -1;
294
295 const int numberPos = pos;
296 for ( ; pos < size && isAsciiDigit(a.at(pos)); ++pos) ;
297
298 bool ok;
299 const int result = a.mid(numberPos, pos - numberPos).toInt(&ok);
300 return ok ? result : -1;
301}
302
304{
306 int pos = 0;
307 for (int i = 0; i < 4; ++i) {
308 char op;
309 const int value = nextGeometryToken(a, pos, &op);
310 if (value < 0)
311 break;
312 switch (op) {
313 case 'x':
314 (result.width >= 0 ? result.height : result.width) = value;
315 break;
316 case '+':
317 case '-':
318 if (result.xOffset >= 0) {
319 result.yOffset = value;
320 if (op == '-')
321 result.corner = result.corner == Qt::TopRightCorner ? Qt::BottomRightCorner : Qt::BottomLeftCorner;
322 } else {
323 result.xOffset = value;
324 if (op == '-')
325 result.corner = Qt::TopRightCorner;
326 }
327 }
328 }
329 return result;
330}
331
332void QWindowGeometrySpecification::applyTo(QWindow *window) const
333{
334 QRect windowGeometry = window->frameGeometry();
335 QSize size = windowGeometry.size();
336 if (width >= 0 || height >= 0) {
337 const QSize windowMinimumSize = window->minimumSize();
338 const QSize windowMaximumSize = window->maximumSize();
339 if (width >= 0)
340 size.setWidth(qBound(windowMinimumSize.width(), width, windowMaximumSize.width()));
341 if (height >= 0)
342 size.setHeight(qBound(windowMinimumSize.height(), height, windowMaximumSize.height()));
343 window->resize(size);
344 }
345 if (xOffset >= 0 || yOffset >= 0) {
346 const QRect availableGeometry = window->screen()->virtualGeometry();
347 QPoint topLeft = windowGeometry.topLeft();
348 if (xOffset >= 0) {
349 topLeft.setX(corner == Qt::TopLeftCorner || corner == Qt::BottomLeftCorner ?
350 xOffset :
351 qMax(availableGeometry.right() - size.width() - xOffset, availableGeometry.left()));
352 }
353 if (yOffset >= 0) {
354 topLeft.setY(corner == Qt::TopLeftCorner || corner == Qt::TopRightCorner ?
355 yOffset :
356 qMax(availableGeometry.bottom() - size.height() - yOffset, availableGeometry.top()));
357 }
358 window->setFramePosition(topLeft);
359 }
360}
361
363
364/*!
365 \macro qGuiApp
366 \relates QGuiApplication
367
368 A global pointer referring to the unique application object.
369 Only valid for use when that object is a QGuiApplication.
370
371 \sa QCoreApplication::instance(), qApp
372*/
373
374/*!
375 \class QGuiApplication
376 \brief The QGuiApplication class manages the GUI application's control
377 flow and main settings.
378
379 \inmodule QtGui
380 \since 5.0
381
382 QGuiApplication contains the main event loop, where all events from the window
383 system and other sources are processed and dispatched. It also handles the
384 application's initialization and finalization, and provides session management.
385 In addition, QGuiApplication handles most of the system-wide and application-wide
386 settings.
387
388 For any GUI application using Qt, there is precisely \b one QGuiApplication
389 object no matter whether the application has 0, 1, 2 or more windows at
390 any given time. For non-GUI Qt applications, use QCoreApplication instead,
391 as it does not depend on the Qt GUI module. For QWidget based Qt applications,
392 use QApplication instead, as it provides some functionality needed for creating
393 QWidget instances.
394
395 The QGuiApplication object is accessible through the instance() function, which
396 returns a pointer equivalent to the global \l qApp pointer.
397
398 QGuiApplication's main areas of responsibility are:
399 \list
400 \li It initializes the application with the user's desktop settings,
401 such as palette(), font() and styleHints(). It keeps
402 track of these properties in case the user changes the desktop
403 globally, for example, through some kind of control panel.
404
405 \li It performs event handling, meaning that it receives events
406 from the underlying window system and dispatches them to the
407 relevant widgets. You can send your own events to windows by
408 using sendEvent() and postEvent().
409
410 \li It parses common command line arguments and sets its internal
411 state accordingly. See the \l{QGuiApplication::QGuiApplication()}
412 {constructor documentation} below for more details.
413
414 \li It provides localization of strings that are visible to the
415 user via translate().
416
417 \li It provides some magical objects like the clipboard().
418
419 \li It knows about the application's windows. You can ask which
420 window is at a certain position using topLevelAt(), get a list of
421 topLevelWindows(), etc.
422
423 \li It manages the application's mouse cursor handling, see
424 setOverrideCursor()
425
426 \li It provides support for sophisticated \l{Session Management}
427 {session management}. This makes it possible for applications
428 to terminate gracefully when the user logs out, to cancel a
429 shutdown process if termination isn't possible and even to
430 preserve the entire application's state for a future session.
431 See isSessionRestored(), sessionId() and commitDataRequest() and
432 saveStateRequest() for details.
433 \endlist
434
435 Since the QGuiApplication object does so much initialization, it \e{must} be
436 created before any other objects related to the user interface are created.
437 QGuiApplication also deals with common command line arguments. Hence, it is
438 usually a good idea to create it \e before any interpretation or
439 modification of \c argv is done in the application itself.
440
441 \table
442 \header
443 \li{2,1} Groups of functions
444
445 \row
446 \li System settings
447 \li desktopSettingsAware(),
448 setDesktopSettingsAware(),
449 styleHints(),
450 palette(),
451 setPalette(),
452 font(),
453 setFont().
454
455 \row
456 \li Event handling
457 \li exec(),
458 processEvents(),
459 exit(),
460 quit().
461 sendEvent(),
462 postEvent(),
463 sendPostedEvents(),
464 removePostedEvents(),
465 notify().
466
467 \row
468 \li Windows
469 \li allWindows(),
470 topLevelWindows(),
471 focusWindow(),
472 clipboard(),
473 topLevelAt().
474
475 \row
476 \li Advanced cursor handling
477 \li overrideCursor(),
478 setOverrideCursor(),
479 restoreOverrideCursor().
480
481 \row
482 \li Session management
483 \li isSessionRestored(),
484 sessionId(),
485 commitDataRequest(),
486 saveStateRequest().
487
488 \row
489 \li Miscellaneous
490 \li startingUp(),
491 closingDown().
492 \endtable
493
494 \sa QCoreApplication, QAbstractEventDispatcher, QEventLoop
495*/
496
497/*!
498 \class QGuiApplicationPrivate
499 \inmodule QtGui
500 \internal
501*/
502
503/*!
504 Initializes the window system and constructs an application object with
505 \a argc command line arguments in \a argv.
506
507 \warning The data referred to by \a argc and \a argv must stay valid for
508 the entire lifetime of the QGuiApplication object. In addition, \a argc must
509 be greater than zero and \a argv must contain at least one valid character
510 string.
511
512 The global \c qApp pointer refers to this application object. Only one
513 application object should be created.
514
515 This application object must be constructed before any \l{QPaintDevice}
516 {paint devices} (including pixmaps, bitmaps etc.).
517
518 \note \a argc and \a argv might be changed as Qt removes command line
519 arguments that it recognizes.
520
521 \section1 Supported Command Line Options
522
523 All Qt programs automatically support a set of command-line options that
524 allow modifying the way Qt will interact with the windowing system. Some of
525 the options are also accessible via environment variables, which are the
526 preferred form if the application can launch GUI sub-processes or other
527 applications (environment variables will be inherited by child processes).
528 When in doubt, use the environment variables.
529
530 The options currently supported are the following:
531 \list
532
533 \li \c{-platform} \e {platformName[:options]}, specifies the
534 \l{Qt Platform Abstraction} (QPA) plugin.
535
536 Overrides the \c QT_QPA_PLATFORM environment variable.
537 \li \c{-platformpluginpath} \e path, specifies the path to platform
538 plugins.
539
540 Overrides the \c QT_QPA_PLATFORM_PLUGIN_PATH environment variable.
541
542 \li \c{-platformtheme} \e platformTheme, specifies the platform theme.
543
544 Overrides the \c QT_QPA_PLATFORMTHEME environment variable.
545
546 \li \c{-plugin} \e plugin, specifies additional plugins to load. The argument
547 may appear multiple times.
548
549 Concatenated with the plugins in the \c QT_QPA_GENERIC_PLUGINS environment
550 variable.
551
552 \li \c{-qmljsdebugger=}, activates the QML/JS debugger with a specified port.
553 The value must be of format \c{port:1234}\e{[,block]}, where
554 \e block is optional
555 and will make the application wait until a debugger connects to it.
556 \li \c {-qwindowgeometry} \e geometry, specifies window geometry for
557 the main window using the X11-syntax. For example:
558 \c {-qwindowgeometry 100x100+50+50}
559 \li \c {-qwindowicon}, sets the default window icon
560 \li \c {-qwindowtitle}, sets the title of the first window
561 \li \c{-reverse}, sets the application's layout direction to
562 Qt::RightToLeft. This option is intended to aid debugging and should
563 not be used in production. The default value is automatically detected
564 from the user's locale (see also QLocale::textDirection()).
565 \li \c{-session} \e session, restores the application from an earlier
566 \l{Session Management}{session}.
567 \endlist
568
569 The following standard command line options are available for X11:
570
571 \list
572 \li \c {-display} \e {hostname:screen_number}, switches displays on X11.
573
574 Overrides the \c DISPLAY environment variable.
575 \li \c {-geometry} \e geometry, same as \c {-qwindowgeometry}.
576 \endlist
577
578 \section1 Platform-Specific Arguments
579
580 You can specify platform-specific arguments for the \c{-platform} option.
581 Place them after the platform plugin name following a colon as a
582 comma-separated list. For example,
583 \c{-platform windows:dialogs=xp,fontengine=freetype}.
584
585 The following parameters are available for \c {-platform windows}:
586
587 \list
588 \li \c {altgr}, detect the key \c {AltGr} found on some keyboards as
589 Qt::GroupSwitchModifier (since Qt 5.12).
590 \li \c {darkmode=[0|1|2]} controls how Qt responds to the activation
591 of the \e{Dark Mode for applications} introduced in Windows 10
592 1903 (since Qt 5.15).
593
594 A value of 0 disables dark mode support.
595
596 A value of 1 causes Qt to switch the window borders to black
597 when \e{Dark Mode for applications} is activated and no High
598 Contrast Theme is in use. This is intended for applications
599 that implement their own theming.
600
601 A value of 2 will in addition cause the Windows Vista style to
602 be deactivated and switch to the Windows style using a
603 simplified palette in dark mode. This is currently
604 experimental pending the introduction of new style that
605 properly adapts to dark mode.
606
607 As of Qt 6.5, the default value is 2; to disable dark mode
608 support, set the value to 0 or 1.
609
610 \li \c {dialogs=[xp|none]}, \c xp uses XP-style native dialogs and
611 \c none disables them.
612
613 \li \c {fontengine=freetype}, uses the FreeType font engine.
614 \li \c {fontengine=gdi}, uses the legacy GDI-based
615 font database and defaults to using the GDI font
616 engine (which is otherwise only used for some font types
617 or font properties.) (Since Qt 6.8).
618 \li \c {menus=[native|none]}, controls the use of native menus.
619
620 Native menus are implemented using Win32 API and are simpler than
621 QMenu-based menus in for example that they do allow for placing
622 widgets on them or changing properties like fonts and do not
623 provide hover signals. They are mainly intended for Qt Quick.
624 By default, they will be used if the application is not an
625 instance of QApplication or for Qt Quick Controls 2
626 applications (since Qt 5.10).
627
628 \li \c {nocolorfonts} Turn off DirectWrite Color fonts
629 (since Qt 5.8).
630
631 \li \c {nodirectwrite} Turn off DirectWrite fonts (since Qt 5.8). This implicitly
632 also selects the GDI font engine.
633
634 \li \c {nomousefromtouch} Ignores mouse events synthesized
635 from touch events by the operating system.
636
637 \li \c {nowmpointer} Switches from Pointer Input Messages handling
638 to legacy mouse handling (since Qt 5.12).
639 \li \c {reverse} Activates Right-to-left mode (experimental).
640 Windows title bars will be shown accordingly in Right-to-left locales
641 (since Qt 5.13).
642 \li \c {tabletabsoluterange=<value>} Sets a value for mouse mode detection
643 of WinTab tablets (Legacy, since Qt 5.3).
644 \endlist
645
646 The following parameter is available for \c {-platform cocoa} (on macOS):
647
648 \list
649 \li \c {fontengine=freetype}, uses the FreeType font engine.
650 \endlist
651
652 For more information about the platform-specific arguments available for
653 embedded Linux platforms, see \l{Qt for Embedded Linux}.
654
655 \sa arguments(), QGuiApplication::platformName
656*/
657#ifdef Q_QDOC
658QGuiApplication::QGuiApplication(int &argc, char **argv)
659#else
660QGuiApplication::QGuiApplication(int &argc, char **argv, int)
661#endif
662 : QCoreApplication(*new QGuiApplicationPrivate(argc, argv))
663{
664 d_func()->init();
665
666 QCoreApplicationPrivate::eventDispatcher->startingUp();
667}
668
669/*!
670 \internal
671*/
672QGuiApplication::QGuiApplication(QGuiApplicationPrivate &p)
673 : QCoreApplication(p)
674{
675}
676
677/*!
678 Destructs the application.
679*/
680QGuiApplication::~QGuiApplication()
681{
682 Q_D(QGuiApplication);
683
684 qt_call_post_routines();
685
686 d->eventDispatcher->closingDown();
687 d->eventDispatcher = nullptr;
688
689#ifndef QT_NO_CLIPBOARD
690 delete QGuiApplicationPrivate::qt_clipboard;
691 QGuiApplicationPrivate::qt_clipboard = nullptr;
692#endif
693
694#ifndef QT_NO_SESSIONMANAGER
695 delete d->session_manager;
696 d->session_manager = nullptr;
697#endif //QT_NO_SESSIONMANAGER
698
699 QGuiApplicationPrivate::clearPalette();
700 QFontDatabase::removeAllApplicationFonts();
701
702#ifndef QT_NO_CURSOR
703 d->cursor_list.clear();
704#endif
705
706#if QT_CONFIG(qtgui_threadpool)
707 // Synchronize and stop the gui thread pool threads.
708 QThreadPool *guiThreadPool = nullptr;
709 QT_TRY {
710 guiThreadPool = QGuiApplicationPrivate::qtGuiThreadPool();
711 } QT_CATCH (...) {
712 // swallow the exception, since destructors shouldn't throw
713 }
714 if (guiThreadPool) {
715 guiThreadPool->waitForDone();
716 delete guiThreadPool;
717 }
718#endif
719
720 delete QGuiApplicationPrivate::app_icon;
721 QGuiApplicationPrivate::app_icon = nullptr;
722 delete QGuiApplicationPrivate::platform_name;
723 QGuiApplicationPrivate::platform_name = nullptr;
724 delete QGuiApplicationPrivate::displayName;
725 QGuiApplicationPrivate::displayName = nullptr;
726 delete QGuiApplicationPrivate::m_inputDeviceManager;
727 QGuiApplicationPrivate::m_inputDeviceManager = nullptr;
728 delete QGuiApplicationPrivate::desktopFileName;
729 QGuiApplicationPrivate::desktopFileName = nullptr;
730 QGuiApplicationPrivate::mouse_buttons = Qt::NoButton;
731 QGuiApplicationPrivate::modifier_buttons = Qt::NoModifier;
732 QGuiApplicationPrivate::lastCursorPosition.reset();
733 QGuiApplicationPrivate::currentMousePressWindow = QGuiApplicationPrivate::currentMouseWindow = nullptr;
734 QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive;
735 QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy = Qt::HighDpiScaleFactorRoundingPolicy::PassThrough;
736 QGuiApplicationPrivate::currentDragWindow = nullptr;
737 QGuiApplicationPrivate::tabletDevicePoints.clear();
738 QGuiApplicationPrivate::m_primaryScreenDpis.storeRelaxed(0);
739}
740
741QGuiApplicationPrivate::QGuiApplicationPrivate(int &argc, char **argv)
742 : QCoreApplicationPrivate(argc, argv),
743 inputMethod(nullptr),
744 lastTouchType(QEvent::TouchEnd)
745{
746 // Note: Not same as QCoreApplication::self
747 QT_IGNORE_DEPRECATIONS(QGuiApplicationPrivate::self = this;)
748
749 application_type = QCoreApplicationPrivate::Gui;
750#ifndef QT_NO_SESSIONMANAGER
751 is_session_restored = false;
752 is_saving_session = false;
753#endif
754}
755
756/*!
757 \property QGuiApplication::applicationDisplayName
758 \brief the user-visible name of this application
759 \since 5.0
760
761 This name is shown to the user, for instance in window titles.
762 It can be translated, if necessary.
763
764 If not set, the application display name defaults to the application name.
765
766 \sa applicationName
767*/
768void QGuiApplication::setApplicationDisplayName(const QString &name)
769{
770 if (!QGuiApplicationPrivate::displayName) {
771 QGuiApplicationPrivate::displayName = new QString(name);
772 if (qGuiApp) {
773 disconnect(qGuiApp, &QGuiApplication::applicationNameChanged,
774 qGuiApp, &QGuiApplication::applicationDisplayNameChanged);
775
776 if (*QGuiApplicationPrivate::displayName != applicationName())
777 emit qGuiApp->applicationDisplayNameChanged();
778 }
779 } else if (name != *QGuiApplicationPrivate::displayName) {
780 *QGuiApplicationPrivate::displayName = name;
781 if (qGuiApp)
782 emit qGuiApp->applicationDisplayNameChanged();
783 }
784}
785
786QString QGuiApplication::applicationDisplayName()
787{
788 return QGuiApplicationPrivate::displayName ? *QGuiApplicationPrivate::displayName : applicationName();
789}
790
791/*!
792 Sets the application's badge to \a number.
793
794 Useful for providing feedback to the user about the number
795 of unread messages or similar.
796
797 The badge will be overlaid on the application's icon in the Dock
798 on \macos, the home screen icon on iOS, or the task bar on Windows
799 and Linux.
800
801 If the number is outside the range supported by the platform, the
802 number will be clamped to the supported range. If the number does
803 not fit within the badge, the number may be visually elided.
804
805 Setting the number to 0 will clear the badge.
806
807 \since 6.5
808 \sa applicationName
809*/
810void QGuiApplication::setBadgeNumber(qint64 number)
811{
812 QGuiApplicationPrivate::platformIntegration()->setApplicationBadge(number);
813}
814
815/*!
816 \property QGuiApplication::desktopFileName
817 \brief the base name of the desktop entry for this application
818 \since 5.7
819
820 This is the file name, without the full path or the trailing ".desktop"
821 extension of the desktop entry that represents this application
822 according to the freedesktop desktop entry specification.
823
824 This property gives a precise indication of what desktop entry represents
825 the application and it is needed by the windowing system to retrieve
826 such information without resorting to imprecise heuristics.
827
828 The latest version of the freedesktop desktop entry specification can be obtained
829 \l{http://standards.freedesktop.org/desktop-entry-spec/latest/}{here}.
830*/
831void QGuiApplication::setDesktopFileName(const QString &name)
832{
833 if (!QGuiApplicationPrivate::desktopFileName)
834 QGuiApplicationPrivate::desktopFileName = new QString;
835 *QGuiApplicationPrivate::desktopFileName = name;
836 if (name.endsWith(QLatin1String(".desktop"))) { // ### Qt 7: remove
837 const QString filePath = QStandardPaths::locate(QStandardPaths::ApplicationsLocation, name);
838 if (!filePath.isEmpty()) {
839 qWarning("QGuiApplication::setDesktopFileName: the specified desktop file name "
840 "ends with .desktop. For compatibility reasons, the .desktop suffix will "
841 "be removed. Please specify a desktop file name without .desktop suffix");
842 (*QGuiApplicationPrivate::desktopFileName).chop(8);
843 }
844 }
845}
846
847QString QGuiApplication::desktopFileName()
848{
849 return QGuiApplicationPrivate::desktopFileName ? *QGuiApplicationPrivate::desktopFileName : QString();
850}
851
852/*!
853 Returns the most recently shown modal window. If no modal windows are
854 visible, this function returns zero.
855
856 A modal window is a window which has its
857 \l{QWindow::modality}{modality} property set to Qt::WindowModal
858 or Qt::ApplicationModal. A modal window must be closed before the user can
859 continue with other parts of the program.
860
861 Modal window are organized in a stack. This function returns the modal
862 window at the top of the stack.
863
864 \sa Qt::WindowModality, QWindow::setModality()
865*/
866QWindow *QGuiApplication::modalWindow()
867{
868 CHECK_QAPP_INSTANCE(nullptr)
869 const auto &modalWindows = QGuiApplicationPrivate::instance()->modalWindowList;
870 if (modalWindows.isEmpty())
871 return nullptr;
872 return modalWindows.constFirst();
873}
874
875static void updateBlockedStatusRecursion(QWindow *window, bool shouldBeBlocked)
876{
877 QWindowPrivate *p = qt_window_private(window);
878 if (p->blockedByModalWindow != shouldBeBlocked) {
879 p->blockedByModalWindow = shouldBeBlocked;
880 QEvent e(shouldBeBlocked ? QEvent::WindowBlocked : QEvent::WindowUnblocked);
881 QGuiApplication::sendEvent(window, &e);
882 for (QObject *c : window->children()) {
883 if (c->isWindowType())
884 updateBlockedStatusRecursion(static_cast<QWindow *>(c), shouldBeBlocked);
885 }
886 }
887}
888
889void QGuiApplicationPrivate::updateBlockedStatus(QWindow *window)
890{
891 bool shouldBeBlocked = false;
892 const bool popupType = (window->type() == Qt::ToolTip) || (window->type() == Qt::Popup);
893 if (!popupType && !QGuiApplicationPrivate::instance()->modalWindowList.isEmpty())
894 shouldBeBlocked = QGuiApplicationPrivate::instance()->isWindowBlocked(window);
895 updateBlockedStatusRecursion(window, shouldBeBlocked);
896}
897
898// Return whether the window needs to be notified about window blocked events.
899// As opposed to QGuiApplication::topLevelWindows(), embedded windows are
900// included in this list (QTBUG-18099).
901static inline bool needsWindowBlockedEvent(const QWindow *w)
902{
903 return w->isTopLevel();
904}
905
906void QGuiApplicationPrivate::showModalWindow(QWindow *modal)
907{
908 auto *guiAppPrivate = QGuiApplicationPrivate::instance();
909 guiAppPrivate->modalWindowList.prepend(modal);
910
911 // Send leave for currently entered window if it should be blocked
912 if (currentMouseWindow && !QWindowPrivate::get(currentMouseWindow)->isPopup()) {
913 bool shouldBeBlocked = guiAppPrivate->isWindowBlocked(currentMouseWindow);
914 if (shouldBeBlocked) {
915 // Remove the new window from modalWindowList temporarily so leave can go through
916 guiAppPrivate->modalWindowList.removeFirst();
917 QEvent e(QEvent::Leave);
918 QGuiApplication::sendEvent(currentMouseWindow, &e);
919 currentMouseWindow = nullptr;
920 guiAppPrivate->modalWindowList.prepend(modal);
921 }
922 }
923
924 for (QWindow *window : std::as_const(QGuiApplicationPrivate::window_list)) {
925 if (needsWindowBlockedEvent(window) && !window->d_func()->blockedByModalWindow)
926 updateBlockedStatus(window);
927 }
928
929 updateBlockedStatus(modal);
930}
931
932void QGuiApplicationPrivate::hideModalWindow(QWindow *window)
933{
934 QGuiApplicationPrivate::instance()->modalWindowList.removeAll(window);
935
936 for (QWindow *window : std::as_const(QGuiApplicationPrivate::window_list)) {
937 if (needsWindowBlockedEvent(window) && window->d_func()->blockedByModalWindow)
938 updateBlockedStatus(window);
939 }
940}
941
942Qt::WindowModality QGuiApplicationPrivate::defaultModality() const
943{
944 return Qt::NonModal;
945}
946
947bool QGuiApplicationPrivate::windowNeverBlocked(QWindow *window) const
948{
949 Q_UNUSED(window);
950 return false;
951}
952
953/*
954 Returns \c true if \a window is blocked by a modal window. If \a
955 blockingWindow is non-zero, *blockingWindow will be set to the blocking
956 window (or to zero if \a window is not blocked).
957*/
958bool QGuiApplicationPrivate::isWindowBlocked(QWindow *window, QWindow **blockingWindow) const
959{
960 Q_ASSERT_X(window, Q_FUNC_INFO, "The window must not be null");
961
962 QWindow *unused = nullptr;
963 if (!blockingWindow)
964 blockingWindow = &unused;
965 *blockingWindow = nullptr;
966
967 if (modalWindowList.isEmpty() || windowNeverBlocked(window))
968 return false;
969
970 for (int i = 0; i < modalWindowList.size(); ++i) {
971 QWindow *modalWindow = modalWindowList.at(i);
972
973 // A window is not blocked by another modal window if the two are
974 // the same, or if the window is a child of the modal window.
975 if (window == modalWindow || modalWindow->isAncestorOf(window, QWindow::IncludeTransients))
976 return false;
977
978 switch (modalWindow->modality() == Qt::NonModal ? defaultModality()
979 : modalWindow->modality()) {
980 case Qt::ApplicationModal:
981 *blockingWindow = modalWindow;
982 return true;
983 case Qt::WindowModal: {
984 // Find the nearest ancestor of window which is also an ancestor of modal window to
985 // determine if the modal window blocks the window.
986 auto *current = window;
987 do {
988 if (current->isAncestorOf(modalWindow, QWindow::IncludeTransients)) {
989 *blockingWindow = modalWindow;
990 return true;
991 }
992 current = current->parent(QWindow::IncludeTransients);
993 } while (current);
994 break;
995 }
996 default:
997 Q_ASSERT_X(false, "QGuiApplication", "internal error, a modal widget cannot be modeless");
998 break;
999 }
1000 }
1001 return false;
1002}
1003
1004QWindow *QGuiApplicationPrivate::activePopupWindow()
1005{
1006 // might be the same as focusWindow() if that's a popup
1007 return QGuiApplicationPrivate::popup_list.isEmpty() ?
1008 nullptr : QGuiApplicationPrivate::popup_list.constLast();
1009}
1010
1011void QGuiApplicationPrivate::activatePopup(QWindow *popup)
1012{
1013 if (!popup->isVisible())
1014 return;
1015 popup_list.removeOne(popup); // ensure that there's only one entry, and it's the last
1016 qCDebug(lcPopup) << "appending popup" << popup << "to existing" << popup_list;
1017 popup_list.append(popup);
1018}
1019
1020bool QGuiApplicationPrivate::closePopup(QWindow *popup)
1021{
1022 const auto removed = QGuiApplicationPrivate::popup_list.removeAll(popup);
1023 qCDebug(lcPopup) << "removed?" << removed << "popup" << popup << "; remaining" << popup_list;
1024 return removed; // >= 1 if something was removed
1025}
1026
1027/*!
1028 Returns \c true if there are no more open popups.
1029*/
1030bool QGuiApplicationPrivate::closeAllPopups()
1031{
1032 // Close all popups: In case some popup refuses to close,
1033 // we give up after 1024 attempts (to avoid an infinite loop).
1034 int maxiter = 1024;
1035 QWindow *popup;
1036 while ((popup = activePopupWindow()) && maxiter--)
1037 popup->close(); // this will call QApplicationPrivate::closePopup
1038 return QGuiApplicationPrivate::popup_list.isEmpty();
1039}
1040
1041/*!
1042 Returns the QWindow that receives events tied to focus,
1043 such as key events.
1044
1045 \sa QWindow::requestActivate()
1046*/
1047QWindow *QGuiApplication::focusWindow()
1048{
1049 return QGuiApplicationPrivate::focus_window;
1050}
1051
1052/*!
1053 \fn QGuiApplication::focusObjectChanged(QObject *focusObject)
1054
1055 This signal is emitted when final receiver of events tied to focus is changed.
1056 \a focusObject is the new receiver.
1057
1058 \sa focusObject()
1059*/
1060
1061/*!
1062 \fn QGuiApplication::focusWindowChanged(QWindow *focusWindow)
1063
1064 This signal is emitted when the focused window changes.
1065 \a focusWindow is the new focused window.
1066
1067 \sa focusWindow()
1068*/
1069
1070/*!
1071 Returns the QObject in currently active window that will be final receiver of events
1072 tied to focus, such as key events.
1073 */
1074QObject *QGuiApplication::focusObject()
1075{
1076 if (focusWindow())
1077 return focusWindow()->focusObject();
1078 return nullptr;
1079}
1080
1081/*!
1082 \fn QGuiApplication::allWindows()
1083
1084 Returns a list of all the windows in the application.
1085
1086 The list is empty if there are no windows.
1087
1088 \sa topLevelWindows()
1089 */
1090QWindowList QGuiApplication::allWindows()
1091{
1092 return QGuiApplicationPrivate::window_list;
1093}
1094
1095/*!
1096 \fn QGuiApplication::topLevelWindows()
1097
1098 Returns a list of the top-level windows in the application.
1099
1100 \sa allWindows()
1101 */
1102QWindowList QGuiApplication::topLevelWindows()
1103{
1104 const QWindowList &list = QGuiApplicationPrivate::window_list;
1105 QWindowList topLevelWindows;
1106 for (int i = 0; i < list.size(); ++i) {
1107 QWindow *window = list.at(i);
1108 if (!window->isTopLevel())
1109 continue;
1110
1111 // Windows embedded in native windows do not have QWindow parents,
1112 // but they are not true top level windows, so do not include them.
1113 if (window->handle() && window->handle()->isEmbedded())
1114 continue;
1115
1116 topLevelWindows.prepend(window);
1117 }
1118
1119 return topLevelWindows;
1120}
1121
1122QScreen *QGuiApplication::primaryScreen()
1123{
1124 if (QGuiApplicationPrivate::screen_list.isEmpty())
1125 return nullptr;
1126 return QGuiApplicationPrivate::screen_list.at(0);
1127}
1128
1129/*!
1130 Returns a list of all the screens associated with the
1131 windowing system the application is connected to.
1132*/
1133QList<QScreen *> QGuiApplication::screens()
1134{
1135 return QGuiApplicationPrivate::screen_list;
1136}
1137
1138/*!
1139 Returns the screen at \a point, or \nullptr if outside of any screen.
1140
1141 The \a point is in relation to the virtualGeometry() of each set of virtual
1142 siblings. If the point maps to more than one set of virtual siblings the first
1143 match is returned. If you wish to search only the virtual desktop siblings
1144 of a known screen (for example siblings of the screen of your application
1145 window \c QWidget::windowHandle()->screen()), use QScreen::virtualSiblingAt().
1146
1147 \since 5.10
1148*/
1149QScreen *QGuiApplication::screenAt(const QPoint &point)
1150{
1151 QVarLengthArray<const QScreen *, 8> visitedScreens;
1152 for (const QScreen *screen : QGuiApplication::screens()) {
1153 if (visitedScreens.contains(screen))
1154 continue;
1155
1156 // The virtual siblings include the screen itself, so iterate directly
1157 for (QScreen *sibling : screen->virtualSiblings()) {
1158 if (sibling->geometry().contains(point))
1159 return sibling;
1160
1161 visitedScreens.append(sibling);
1162 }
1163 }
1164
1165 return nullptr;
1166}
1167
1168/*!
1169 \fn void QGuiApplication::screenAdded(QScreen *screen)
1170
1171 This signal is emitted whenever a new screen \a screen has been added to the system.
1172
1173 \sa screens(), primaryScreen, screenRemoved()
1174*/
1175
1176/*!
1177 \fn void QGuiApplication::screenRemoved(QScreen *screen)
1178
1179 This signal is emitted whenever a \a screen is removed from the system. It
1180 provides an opportunity to manage the windows on the screen before Qt falls back
1181 to moving them to the primary screen.
1182
1183 \sa screens(), screenAdded(), QObject::destroyed(), QWindow::setScreen()
1184
1185 \since 5.4
1186*/
1187
1188
1189/*!
1190 \property QGuiApplication::primaryScreen
1191
1192 \brief the primary (or default) screen of the application.
1193
1194 This will be the screen where QWindows are initially shown, unless otherwise specified.
1195
1196 The primaryScreenChanged signal was introduced in Qt 5.6.
1197
1198 \sa screens()
1199*/
1200
1201/*!
1202 Returns the highest screen device pixel ratio found on
1203 the system. This is the ratio between physical pixels and
1204 device-independent pixels.
1205
1206 Use this function only when you don't know which window you are targeting.
1207 If you do know the target window, use QWindow::devicePixelRatio() instead.
1208
1209 \sa QWindow::devicePixelRatio()
1210*/
1211qreal QGuiApplication::devicePixelRatio() const
1212{
1213 if (!qFuzzyIsNull(QGuiApplicationPrivate::m_maxDevicePixelRatio))
1214 return QGuiApplicationPrivate::m_maxDevicePixelRatio;
1215
1216 QGuiApplicationPrivate::m_maxDevicePixelRatio = 1.0; // make sure we never return 0.
1217 for (QScreen *screen : std::as_const(QGuiApplicationPrivate::screen_list))
1218 QGuiApplicationPrivate::m_maxDevicePixelRatio = qMax(QGuiApplicationPrivate::m_maxDevicePixelRatio, screen->devicePixelRatio());
1219
1220 return QGuiApplicationPrivate::m_maxDevicePixelRatio;
1221}
1222
1223void QGuiApplicationPrivate::resetCachedDevicePixelRatio()
1224{
1225 m_maxDevicePixelRatio = 0.0;
1226}
1227
1228void QGuiApplicationPrivate::_q_updatePrimaryScreenDpis()
1229{
1230 int dpis = 0;
1231 const QScreen *screen = QGuiApplication::primaryScreen();
1232 if (screen) {
1233 int dpiX = qRound(screen->logicalDotsPerInchX());
1234 int dpiY = qRound(screen->logicalDotsPerInchY());
1235 dpis = (dpiX << 16) | (dpiY & 0xffff);
1236 QObject::connect(screen, SIGNAL(logicalDotsPerInchChanged(qreal)),
1237 q_func(), SLOT(_q_updatePrimaryScreenDpis()), Qt::UniqueConnection);
1238 }
1239 m_primaryScreenDpis.storeRelaxed(dpis);
1240}
1241
1242/*!
1243 Returns the top level window at the given position \a pos, if any.
1244*/
1245QWindow *QGuiApplication::topLevelAt(const QPoint &pos)
1246{
1247 if (QScreen *windowScreen = screenAt(pos)) {
1248 const QPoint devicePosition = QHighDpi::toNativePixels(pos, windowScreen);
1249 return windowScreen->handle()->topLevelAt(devicePosition);
1250 }
1251 return nullptr;
1252}
1253
1254/*!
1255 \property QGuiApplication::platformName
1256 \brief The name of the underlying platform plugin.
1257
1258 The QPA platform plugins are located in \c {qtbase\src\plugins\platforms}.
1259 At the time of writing, the following platform plugin names are supported:
1260
1261 \list
1262 \li \c android
1263 \li \c cocoa is a platform plugin for \macos.
1264 \li \c directfb
1265 \li \c eglfs is a platform plugin for running Qt5 applications on top of
1266 EGL and OpenGL ES 2.0 without an actual windowing system (like X11
1267 or Wayland). For more information, see \l{EGLFS}.
1268 \li \c ios (also used for tvOS)
1269 \li \c linuxfb writes directly to the framebuffer. For more information,
1270 see \l{LinuxFB}.
1271 \li \c minimal is provided as an examples for developers who want to
1272 write their own platform plugins. However, you can use the plugin to
1273 run GUI applications in environments without a GUI, such as servers.
1274 \li \c minimalegl is an example plugin.
1275 \li \c offscreen
1276 \li \c qnx
1277 \li \c windows
1278 \li \c wayland is a platform plugin for the Wayland display server protocol,
1279 used on some Linux desktops and embedded systems.
1280 \li \c xcb is a plugin for the X11 window system, used on some desktop Linux platforms.
1281 \endlist
1282
1283 \note Calling this function without a QGuiApplication will return the default
1284 platform name, if available. The default platform name is not affected by the
1285 \c{-platform} command line option, or the \c QT_QPA_PLATFORM environment variable.
1286
1287 For more information about the platform plugins for embedded Linux devices,
1288 see \l{Qt for Embedded Linux}.
1289*/
1290
1291QString QGuiApplication::platformName()
1292{
1293 if (!QGuiApplication::instance()) {
1294#ifdef QT_QPA_DEFAULT_PLATFORM_NAME
1295 return QStringLiteral(QT_QPA_DEFAULT_PLATFORM_NAME);
1296#else
1297 return QString();
1298#endif
1299 } else {
1300 return QGuiApplicationPrivate::platform_name ?
1301 *QGuiApplicationPrivate::platform_name : QString();
1302 }
1303}
1304
1305Q_STATIC_LOGGING_CATEGORY(lcQpaPluginLoading, "qt.qpa.plugin");
1306Q_STATIC_LOGGING_CATEGORY(lcQpaTheme, "qt.qpa.theme");
1307Q_STATIC_LOGGING_CATEGORY(lcPtrDispatch, "qt.pointer.dispatch");
1308
1309static void init_platform(const QString &pluginNamesWithArguments, const QString &platformPluginPath, const QString &platformThemeName, int &argc, char **argv)
1310{
1311 qCDebug(lcQpaPluginLoading) << "init_platform called with"
1312 << "pluginNamesWithArguments" << pluginNamesWithArguments
1313 << "platformPluginPath" << platformPluginPath
1314 << "platformThemeName" << platformThemeName;
1315
1316 QStringList plugins = pluginNamesWithArguments.split(u';', Qt::SkipEmptyParts);
1317 QStringList platformArguments;
1318 QStringList availablePlugins = QPlatformIntegrationFactory::keys(platformPluginPath);
1319 for (const auto &pluginArgument : std::as_const(plugins)) {
1320 // Split into platform name and arguments
1321 QStringList arguments = pluginArgument.split(u':', Qt::SkipEmptyParts);
1322 if (arguments.isEmpty())
1323 continue;
1324 const QString name = arguments.takeFirst().toLower();
1325 QString argumentsKey = name;
1326 if (name.isEmpty())
1327 continue;
1328 argumentsKey[0] = argumentsKey.at(0).toUpper();
1329 arguments.append(QLibraryInfo::platformPluginArguments(argumentsKey));
1330
1331 qCDebug(lcQpaPluginLoading) << "Attempting to load Qt platform plugin" << name << "with arguments" << arguments;
1332
1333 // Create the platform integration.
1334 QGuiApplicationPrivate::platform_integration = QPlatformIntegrationFactory::create(name, arguments, argc, argv, platformPluginPath);
1335 if (Q_UNLIKELY(!QGuiApplicationPrivate::platform_integration)) {
1336 if (availablePlugins.contains(name)) {
1337 if (name == QStringLiteral("xcb") && QVersionNumber::compare(QLibraryInfo::version(), QVersionNumber(6, 5, 0)) >= 0) {
1338 qCWarning(lcQpaPluginLoading).nospace().noquote()
1339 << "From 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to load the Qt xcb platform plugin.";
1340 }
1341 qCInfo(lcQpaPluginLoading).nospace().noquote()
1342 << "Could not load the Qt platform plugin \"" << name << "\" in \""
1343 << QDir::toNativeSeparators(platformPluginPath) << "\" even though it was found.";
1344 } else {
1345 qCWarning(lcQpaPluginLoading).nospace().noquote()
1346 << "Could not find the Qt platform plugin \"" << name << "\" in \""
1347 << QDir::toNativeSeparators(platformPluginPath) << "\"";
1348 }
1349 } else {
1350 qCDebug(lcQpaPluginLoading) << "Successfully loaded Qt platform plugin" << name;
1351 QGuiApplicationPrivate::platform_name = new QString(name);
1352 platformArguments = arguments;
1353 break;
1354 }
1355 }
1356
1357 if (Q_UNLIKELY(!QGuiApplicationPrivate::platform_integration)) {
1358 QString fatalMessage = QStringLiteral("This application failed to start because no Qt platform plugin could be initialized. "
1359 "Reinstalling the application may fix this problem.\n");
1360
1361 if (!availablePlugins.isEmpty())
1362 fatalMessage += "\nAvailable platform plugins are: %1.\n"_L1.arg(availablePlugins.join(", "_L1));
1363
1364#if defined(Q_OS_WIN)
1365 // Windows: Display message box unless it is a console application
1366 // or debug build showing an assert box.
1367 if (!QLibraryInfo::isDebugBuild() && !GetConsoleWindow())
1368 MessageBox(0, (LPCTSTR)fatalMessage.utf16(), (LPCTSTR)(QCoreApplication::applicationName().utf16()), MB_OK | MB_ICONERROR);
1369#endif // Q_OS_WIN
1370 qFatal("%s", qPrintable(fatalMessage));
1371
1372 return;
1373 }
1374
1375 // Create the platform theme:
1376
1377 // 1) Try the platform name from the environment if present
1378 QStringList themeNames;
1379 if (!platformThemeName.isEmpty()) {
1380 qCDebug(lcQpaTheme) << "Adding" << platformThemeName << "from environment";
1381 themeNames.append(platformThemeName);
1382 }
1383
1384#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
1385 // 2) Special case - check whether it's a flatpak or snap app to use xdg-desktop-portal platform theme for portals support
1386 if (checkNeedPortalSupport()) {
1387 qCDebug(lcQpaTheme) << "Adding xdgdesktopportal to list of theme names";
1388 themeNames.append(QStringLiteral("xdgdesktopportal"));
1389 }
1390#endif
1391
1392 // 3) Ask the platform integration for a list of theme names
1393 const auto platformIntegrationThemeNames = QGuiApplicationPrivate::platform_integration->themeNames();
1394 qCDebug(lcQpaTheme) << "Adding platform integration's theme names to list of theme names:" << platformIntegrationThemeNames;
1395 themeNames.append(platformIntegrationThemeNames);
1396
1397 // 4) Look for a theme plugin.
1398 for (const QString &themeName : std::as_const(themeNames)) {
1399 qCDebug(lcQpaTheme) << "Attempting to create platform theme" << themeName << "via QPlatformThemeFactory::create";
1400 QGuiApplicationPrivate::platform_theme = QPlatformThemeFactory::create(themeName, platformPluginPath);
1401 if (QGuiApplicationPrivate::platform_theme) {
1402 qCDebug(lcQpaTheme) << "Successfully created platform theme" << themeName << "via QPlatformThemeFactory::create";
1403 break;
1404 }
1405 qCDebug(lcQpaTheme) << "Attempting to create platform theme" << themeName << "via createPlatformTheme";
1406 QGuiApplicationPrivate::platform_theme = QGuiApplicationPrivate::platform_integration->createPlatformTheme(themeName);
1407 if (QGuiApplicationPrivate::platform_theme) {
1408 qCDebug(lcQpaTheme) << "Successfully created platform theme" << themeName << "via createPlatformTheme";
1409 break;
1410 }
1411 }
1412
1413 // 5) Fall back on the built-in "null" platform theme.
1414 if (!QGuiApplicationPrivate::platform_theme) {
1415 qCDebug(lcQpaTheme) << "Failed to create platform theme; using \"null\" platform theme";
1416 QGuiApplicationPrivate::platform_theme = new QPlatformTheme;
1417 }
1418
1419 // Set arguments as dynamic properties on the native interface as
1420 // boolean 'foo' or strings: 'foo=bar'
1421 if (!platformArguments.isEmpty()) {
1422 if (QObject *nativeInterface = QGuiApplicationPrivate::platform_integration->nativeInterface()) {
1423 for (const QString &argument : std::as_const(platformArguments)) {
1424 const qsizetype equalsPos = argument.indexOf(u'=');
1425 const QByteArray name =
1426 equalsPos != -1 ? argument.left(equalsPos).toUtf8() : argument.toUtf8();
1427 QVariant value =
1428 equalsPos != -1 ? QVariant(argument.mid(equalsPos + 1)) : QVariant(true);
1429 nativeInterface->setProperty(name.constData(), std::move(value));
1430 }
1431 }
1432 }
1433
1434 const auto *platformIntegration = QGuiApplicationPrivate::platformIntegration();
1435 fontSmoothingGamma = platformIntegration->styleHint(QPlatformIntegration::FontSmoothingGamma).toReal();
1436 QCoreApplication::setAttribute(Qt::AA_DontShowShortcutsInContextMenus,
1437 !QGuiApplication::styleHints()->showShortcutsInContextMenus());
1438
1439 if (const auto *platformTheme = QGuiApplicationPrivate::platformTheme()) {
1440 QCoreApplication::setAttribute(Qt::AA_DontShowIconsInMenus,
1441 !platformTheme->themeHint(QPlatformTheme::ShowIconsInMenus).toBool());
1442 }
1443}
1444
1445static void init_plugins(const QList<QByteArray> &pluginList)
1446{
1447 for (int i = 0; i < pluginList.size(); ++i) {
1448 QByteArray pluginSpec = pluginList.at(i);
1449 qsizetype colonPos = pluginSpec.indexOf(':');
1450 QObject *plugin;
1451 if (colonPos < 0)
1452 plugin = QGenericPluginFactory::create(QLatin1StringView(pluginSpec), QString());
1453 else
1454 plugin = QGenericPluginFactory::create(QLatin1StringView(pluginSpec.mid(0, colonPos)),
1455 QLatin1StringView(pluginSpec.mid(colonPos+1)));
1456 if (plugin)
1457 QGuiApplicationPrivate::generic_plugin_list.append(plugin);
1458 else
1459 qWarning("No such plugin for spec \"%s\"", pluginSpec.constData());
1460 }
1461}
1462
1463#if QT_CONFIG(commandlineparser)
1464void QGuiApplicationPrivate::addQtOptions(QList<QCommandLineOption> *options)
1465{
1466 QCoreApplicationPrivate::addQtOptions(options);
1467
1468#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
1469 const QByteArray sessionType = qgetenv("XDG_SESSION_TYPE");
1470 const bool x11 = sessionType == "x11";
1471 // Technically the x11 aliases are only available if platformName is "xcb", but we can't know that here.
1472#else
1473 const bool x11 = false;
1474#endif
1475
1476 options->append(QCommandLineOption(QStringLiteral("platform"),
1477 QGuiApplication::tr("QPA plugin. See QGuiApplication documentation for available options for each plugin."), QStringLiteral("platformName[:options]")));
1478 options->append(QCommandLineOption(QStringLiteral("platformpluginpath"),
1479 QGuiApplication::tr("Path to the platform plugins."), QStringLiteral("path")));
1480 options->append(QCommandLineOption(QStringLiteral("platformtheme"),
1481 QGuiApplication::tr("Platform theme."), QStringLiteral("theme")));
1482 options->append(QCommandLineOption(QStringLiteral("plugin"),
1483 QGuiApplication::tr("Additional plugins to load, can be specified multiple times."), QStringLiteral("plugin")));
1484 options->append(QCommandLineOption(QStringLiteral("qwindowgeometry"),
1485 QGuiApplication::tr("Window geometry for the main window, using the X11-syntax, like 100x100+50+50."), QStringLiteral("geometry")));
1486 options->append(QCommandLineOption(QStringLiteral("qwindowicon"),
1487 QGuiApplication::tr("Default window icon."), QStringLiteral("icon")));
1488 options->append(QCommandLineOption(QStringLiteral("qwindowtitle"),
1489 QGuiApplication::tr("Title of the first window."), QStringLiteral("title")));
1490 options->append(QCommandLineOption(QStringLiteral("reverse"),
1491 QGuiApplication::tr("Sets the application's layout direction to Qt::RightToLeft (debugging helper).")));
1492 options->append(QCommandLineOption(QStringLiteral("session"),
1493 QGuiApplication::tr("Restores the application from an earlier session."), QStringLiteral("session")));
1494
1495 if (x11) {
1496 options->append(QCommandLineOption(QStringLiteral("display"),
1497 QGuiApplication::tr("Display name, overrides $DISPLAY."), QStringLiteral("display")));
1498 options->append(QCommandLineOption(QStringLiteral("name"),
1499 QGuiApplication::tr("Instance name according to ICCCM 4.1.2.5."), QStringLiteral("name")));
1500 options->append(QCommandLineOption(QStringLiteral("nograb"),
1501 QGuiApplication::tr("Disable mouse grabbing (useful in debuggers).")));
1502 options->append(QCommandLineOption(QStringLiteral("dograb"),
1503 QGuiApplication::tr("Force mouse grabbing (even when running in a debugger).")));
1504 options->append(QCommandLineOption(QStringLiteral("visual"),
1505 QGuiApplication::tr("ID of the X11 Visual to use."), QStringLiteral("id")));
1506 // Not using the "QStringList names" solution for those aliases, because it makes the first column too wide
1507 options->append(QCommandLineOption(QStringLiteral("geometry"),
1508 QGuiApplication::tr("Alias for --qwindowgeometry."), QStringLiteral("geometry")));
1509 options->append(QCommandLineOption(QStringLiteral("icon"),
1510 QGuiApplication::tr("Alias for --qwindowicon."), QStringLiteral("icon")));
1511 options->append(QCommandLineOption(QStringLiteral("title"),
1512 QGuiApplication::tr("Alias for --qwindowtitle."), QStringLiteral("title")));
1513 }
1514}
1515#endif // QT_CONFIG(commandlineparser)
1516
1517void QGuiApplicationPrivate::createPlatformIntegration()
1518{
1519 QHighDpiScaling::initHighDpiScaling();
1520
1521 // Load the platform integration
1522 QString platformPluginPath = qEnvironmentVariable("QT_QPA_PLATFORM_PLUGIN_PATH");
1523
1524
1525 QByteArray platformName;
1526#ifdef QT_QPA_DEFAULT_PLATFORM_NAME
1527 platformName = QT_QPA_DEFAULT_PLATFORM_NAME;
1528#endif
1529#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
1530 QList<QByteArray> platformArguments = platformName.split(':');
1531 QByteArray platformPluginBase = platformArguments.first();
1532
1533 const bool hasWaylandDisplay = qEnvironmentVariableIsSet("WAYLAND_DISPLAY");
1534 const bool isWaylandSessionType = qgetenv("XDG_SESSION_TYPE") == "wayland";
1535
1536 QVector<QByteArray> preferredPlatformOrder;
1537 const bool defaultIsXcb = platformPluginBase == "xcb";
1538 const QByteArray xcbPlatformName = defaultIsXcb ? platformName : "xcb";
1539 if (qEnvironmentVariableIsSet("DISPLAY")) {
1540 preferredPlatformOrder << xcbPlatformName;
1541 if (defaultIsXcb)
1542 platformName.clear();
1543 }
1544
1545 const bool defaultIsWayland = !defaultIsXcb && platformPluginBase.startsWith("wayland");
1546 const QByteArray waylandPlatformName = defaultIsWayland ? platformName : "wayland";
1547 if (hasWaylandDisplay || isWaylandSessionType) {
1548 preferredPlatformOrder.prepend(waylandPlatformName);
1549
1550 if (defaultIsWayland)
1551 platformName.clear();
1552 }
1553
1554 if (!platformName.isEmpty())
1555 preferredPlatformOrder.append(platformName);
1556
1557 platformName = preferredPlatformOrder.join(';');
1558#endif
1559
1560 bool platformExplicitlySelected = false;
1561 QByteArray platformNameEnv = qgetenv("QT_QPA_PLATFORM");
1562 if (!platformNameEnv.isEmpty()) {
1563 platformName = platformNameEnv;
1564 platformExplicitlySelected = true;
1565 }
1566
1567 QString platformThemeName = QString::fromLocal8Bit(qgetenv("QT_QPA_PLATFORMTHEME"));
1568
1569 // Get command line params
1570
1571 QString icon;
1572
1573 int j = argc ? 1 : 0;
1574 for (int i=1; i<argc; i++) {
1575 if (!argv[i])
1576 continue;
1577 if (*argv[i] != '-') {
1578 argv[j++] = argv[i];
1579 continue;
1580 }
1581 const bool xcbIsDefault = platformName.startsWith("xcb");
1582 const char *arg = argv[i];
1583 if (arg[1] == '-') // startsWith("--")
1584 ++arg;
1585 if (strcmp(arg, "-platformpluginpath") == 0) {
1586 if (++i < argc)
1587 platformPluginPath = QFile::decodeName(argv[i]);
1588 } else if (strcmp(arg, "-platform") == 0) {
1589 if (++i < argc) {
1590 platformExplicitlySelected = true;
1591 platformName = argv[i];
1592 }
1593 } else if (strcmp(arg, "-platformtheme") == 0) {
1594 if (++i < argc)
1595 platformThemeName = QString::fromLocal8Bit(argv[i]);
1596 } else if (strcmp(arg, "-qwindowgeometry") == 0 || (xcbIsDefault && strcmp(arg, "-geometry") == 0)) {
1597 if (++i < argc)
1598 windowGeometrySpecification = QWindowGeometrySpecification::fromArgument(argv[i]);
1599 } else if (strcmp(arg, "-qwindowtitle") == 0 || (xcbIsDefault && strcmp(arg, "-title") == 0)) {
1600 if (++i < argc)
1601 firstWindowTitle = QString::fromLocal8Bit(argv[i]);
1602 } else if (strcmp(arg, "-qwindowicon") == 0 || (xcbIsDefault && strcmp(arg, "-icon") == 0)) {
1603 if (++i < argc) {
1604 icon = QFile::decodeName(argv[i]);
1605 }
1606 } else {
1607 argv[j++] = argv[i];
1608 }
1609 }
1610
1611 if (j < argc) {
1612 argv[j] = nullptr;
1613 argc = j;
1614 }
1615
1616 Q_UNUSED(platformExplicitlySelected);
1617
1618 init_platform(QLatin1StringView(platformName), platformPluginPath, platformThemeName, argc, argv);
1619 QStyleHintsPrivate::get(QGuiApplication::styleHints())->update(platformTheme());
1620
1621 if (!icon.isEmpty())
1622 forcedWindowIcon = QDir::isAbsolutePath(icon) ? QIcon(icon) : QIcon::fromTheme(icon);
1623}
1624
1625/*!
1626 Called from QCoreApplication::init()
1627
1628 Responsible for creating an event dispatcher when QCoreApplication
1629 decides that it needs one (because a custom one has not been set).
1630*/
1631void QGuiApplicationPrivate::createEventDispatcher()
1632{
1633 Q_ASSERT(!eventDispatcher);
1634
1635 if (platform_integration == nullptr)
1636 createPlatformIntegration();
1637
1638 // The platform integration should not result in creating an event dispatcher
1639 Q_ASSERT_X(!threadData.loadRelaxed()->eventDispatcher, "QGuiApplication",
1640 "Creating the platform integration resulted in creating an event dispatcher");
1641
1642 // Nor should it mess with the QCoreApplication's event dispatcher
1643 Q_ASSERT(!eventDispatcher);
1644
1645 eventDispatcher = platform_integration->createEventDispatcher();
1646}
1647
1648void QGuiApplicationPrivate::eventDispatcherReady()
1649{
1650 if (platform_integration == nullptr)
1651 createPlatformIntegration();
1652
1653 platform_integration->initialize();
1654}
1655
1656void Q_TRACE_INSTRUMENT(qtgui) QGuiApplicationPrivate::init()
1657{
1658 Q_TRACE_SCOPE(QGuiApplicationPrivate_init);
1659
1660#if defined(Q_OS_MACOS)
1661 QMacAutoReleasePool pool;
1662#endif
1663
1664 QObject::connect(q_func(), SIGNAL(screenAdded(QScreen*)),
1665 q_func(), SLOT(_q_updatePrimaryScreenDpis()));
1666 QObject::connect(q_func(), SIGNAL(primaryScreenChanged(QScreen *)),
1667 q_func(), SLOT(_q_updatePrimaryScreenDpis()));
1668
1669 QCoreApplicationPrivate::init();
1670
1671 QCoreApplicationPrivate::is_app_running = false; // Starting up.
1672
1673 bool loadTestability = false;
1674 QList<QByteArray> pluginList;
1675 // Get command line params
1676#ifndef QT_NO_SESSIONMANAGER
1677 QString session_id;
1678 QString session_key;
1679# if defined(Q_OS_WIN)
1680 wchar_t guidstr[40];
1681 GUID guid;
1682 CoCreateGuid(&guid);
1683 StringFromGUID2(guid, guidstr, 40);
1684 session_id = QString::fromWCharArray(guidstr);
1685 CoCreateGuid(&guid);
1686 StringFromGUID2(guid, guidstr, 40);
1687 session_key = QString::fromWCharArray(guidstr);
1688# endif
1689#endif
1690 QString s;
1691 int j = argc ? 1 : 0;
1692 for (int i=1; i<argc; i++) {
1693 if (!argv[i])
1694 continue;
1695 if (*argv[i] != '-') {
1696 argv[j++] = argv[i];
1697 continue;
1698 }
1699 const char *arg = argv[i];
1700 if (arg[1] == '-') // startsWith("--")
1701 ++arg;
1702 if (strcmp(arg, "-plugin") == 0) {
1703 if (++i < argc)
1704 pluginList << argv[i];
1705 } else if (strcmp(arg, "-reverse") == 0) {
1706 force_reverse = true;
1707#ifdef Q_OS_MACOS
1708 } else if (strncmp(arg, "-psn_", 5) == 0) {
1709 // eat "-psn_xxxx" on Mac, which is passed when starting an app from Finder.
1710 // special hack to change working directory (for an app bundle) when running from finder
1711 if (QDir::currentPath() == "/"_L1) {
1712 QCFType<CFURLRef> bundleURL(CFBundleCopyBundleURL(CFBundleGetMainBundle()));
1713 QString qbundlePath = QCFString(CFURLCopyFileSystemPath(bundleURL,
1714 kCFURLPOSIXPathStyle));
1715 if (qbundlePath.endsWith(".app"_L1))
1716 QDir::setCurrent(qbundlePath.section(u'/', 0, -2));
1717 }
1718#endif
1719#ifndef QT_NO_SESSIONMANAGER
1720 } else if (strcmp(arg, "-session") == 0 && i < argc - 1) {
1721 ++i;
1722 if (argv[i] && *argv[i]) {
1723 session_id = QString::fromLatin1(argv[i]);
1724 qsizetype p = session_id.indexOf(u'_');
1725 if (p >= 0) {
1726 session_key = session_id.mid(p +1);
1727 session_id = session_id.left(p);
1728 }
1729 is_session_restored = true;
1730 }
1731#endif
1732 } else if (strcmp(arg, "-testability") == 0) {
1733 loadTestability = true;
1734 } else if (strncmp(arg, "-style=", 7) == 0) {
1735 s = QString::fromLocal8Bit(arg + 7);
1736 } else if (strcmp(arg, "-style") == 0 && i < argc - 1) {
1737 s = QString::fromLocal8Bit(argv[++i]);
1738 } else {
1739 argv[j++] = argv[i];
1740 }
1741
1742 if (!s.isEmpty())
1743 styleOverride = s;
1744 }
1745
1746 if (j < argc) {
1747 argv[j] = nullptr;
1748 argc = j;
1749 }
1750
1751 // Load environment exported generic plugins
1752 QByteArray envPlugins = qgetenv("QT_QPA_GENERIC_PLUGINS");
1753 if (!envPlugins.isEmpty())
1754 pluginList += envPlugins.split(',');
1755
1756 if (platform_integration == nullptr)
1757 createPlatformIntegration();
1758
1759 updatePalette();
1760 QFont::initialize();
1761 initThemeHints();
1762
1763#ifndef QT_NO_CURSOR
1764 QCursorData::initialize();
1765#endif
1766
1767 // trigger registering of QVariant's GUI types
1768 qRegisterGuiVariant();
1769
1770#if QT_CONFIG(animation)
1771 // trigger registering of animation interpolators
1772 qRegisterGuiGetInterpolator();
1773#endif
1774
1775 QWindowSystemInterfacePrivate::eventTime.start();
1776
1777#if QT_CONFIG(accessibility)
1778 QAccessible::installFactory([](const QString &classname, QObject *object)
1779 -> QAccessibleInterface * {
1780 if (classname == "QForeignWindow"_L1)
1781 return new QAccessibleWindow(static_cast<QWindow *>(object));
1782 return nullptr;
1783 });
1784#endif
1785
1786 is_app_running = true;
1787 init_plugins(pluginList);
1788 QWindowSystemInterface::flushWindowSystemEvents();
1789
1790 Q_Q(QGuiApplication);
1791#ifndef QT_NO_SESSIONMANAGER
1792 // connect to the session manager
1793 session_manager = new QSessionManager(q, session_id, session_key);
1794#endif
1795
1796#if QT_CONFIG(library)
1797 if (qEnvironmentVariableIntValue("QT_LOAD_TESTABILITY") > 0)
1798 loadTestability = true;
1799
1800 if (loadTestability) {
1801 QLibrary testLib(QStringLiteral("qttestability"));
1802 if (Q_UNLIKELY(!testLib.load())) {
1803 qCritical() << "Library qttestability load failed:" << testLib.errorString();
1804 } else {
1805 typedef void (*TasInitialize)(void);
1806 TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init");
1807 if (Q_UNLIKELY(!initFunction)) {
1808 qCritical("Library qttestability resolve failed!");
1809 } else {
1810 initFunction();
1811 }
1812 }
1813 }
1814#else
1815 Q_UNUSED(loadTestability);
1816#endif // QT_CONFIG(library)
1817
1818 // trigger changed signal and event delivery
1819 QGuiApplication::setLayoutDirection(layout_direction);
1820
1821 if (!QGuiApplicationPrivate::displayName)
1822 QObject::connect(q, &QGuiApplication::applicationNameChanged,
1823 q, &QGuiApplication::applicationDisplayNameChanged);
1824}
1825
1826extern void qt_cleanupFontDatabase();
1827
1828QGuiApplicationPrivate::~QGuiApplicationPrivate()
1829{
1830#if defined(Q_OS_MACOS)
1831 QMacAutoReleasePool pool;
1832#endif
1833
1834 is_app_closing = true;
1835 is_app_running = false;
1836
1837 for (int i = 0; i < generic_plugin_list.size(); ++i)
1838 delete generic_plugin_list.at(i);
1839 generic_plugin_list.clear();
1840
1841 clearFontUnlocked();
1842
1843 QFont::cleanup();
1844
1845#ifndef QT_NO_CURSOR
1846 QCursorData::cleanup();
1847#endif
1848
1849 layout_direction = Qt::LayoutDirectionAuto;
1850
1851 cleanupThreadData();
1852
1853 delete QGuiApplicationPrivate::styleHints;
1854 QGuiApplicationPrivate::styleHints = nullptr;
1855 delete inputMethod;
1856
1857 qt_cleanupFontDatabase();
1858
1859 QPixmapCache::clear();
1860
1861#ifndef QT_NO_OPENGL
1862 if (ownGlobalShareContext) {
1863 delete qt_gl_global_share_context();
1864 qt_gl_set_global_share_context(nullptr);
1865 }
1866#endif
1867
1868#if QT_CONFIG(vulkan)
1869 QVulkanDefaultInstance::cleanup();
1870#endif
1871
1872 platform_integration->destroy();
1873
1874 delete platform_theme;
1875 platform_theme = nullptr;
1876 delete platform_integration;
1877 platform_integration = nullptr;
1878
1879 window_list.clear();
1880 popup_list.clear();
1881 screen_list.clear();
1882
1883 // Note: Not same as QCoreApplication::self
1884 QT_IGNORE_DEPRECATIONS(QGuiApplicationPrivate::self = nullptr;)
1885}
1886
1887#if 0
1888#ifndef QT_NO_CURSOR
1889QCursor *overrideCursor();
1890void setOverrideCursor(const QCursor &);
1891void changeOverrideCursor(const QCursor &);
1892void restoreOverrideCursor();
1893#endif
1894
1895static QFont font();
1896static QFont font(const QWidget*);
1897static QFont font(const char *className);
1898static void setFont(const QFont &, const char *className = nullptr);
1899static QFontMetrics fontMetrics();
1900
1901#ifndef QT_NO_CLIPBOARD
1902static QClipboard *clipboard();
1903#endif
1904#endif
1905
1906/*!
1907 Returns the current state of the modifier keys on the keyboard. The current
1908 state is updated synchronously as the event queue is emptied of events that
1909 will spontaneously change the keyboard state (QEvent::KeyPress and
1910 QEvent::KeyRelease events).
1911
1912 It should be noted this may not reflect the actual keys held on the input
1913 device at the time of calling but rather the modifiers as last reported in
1914 one of the above events. If no keys are being held Qt::NoModifier is
1915 returned.
1916
1917 \sa mouseButtons(), queryKeyboardModifiers()
1918*/
1919Qt::KeyboardModifiers QGuiApplication::keyboardModifiers()
1920{
1921 return QGuiApplicationPrivate::modifier_buttons;
1922}
1923
1924/*!
1925 \fn Qt::KeyboardModifiers QGuiApplication::queryKeyboardModifiers()
1926
1927 Queries and returns the state of the modifier keys on the keyboard.
1928 Unlike keyboardModifiers, this method returns the actual keys held
1929 on the input device at the time of calling the method.
1930
1931 It does not rely on the keypress events having been received by this
1932 process, which makes it possible to check the modifiers while moving
1933 a window, for instance. Note that in most cases, you should use
1934 keyboardModifiers(), which is faster and more accurate since it contains
1935 the state of the modifiers as they were when the currently processed
1936 event was received.
1937
1938 \sa keyboardModifiers()
1939*/
1940Qt::KeyboardModifiers QGuiApplication::queryKeyboardModifiers()
1941{
1942 CHECK_QAPP_INSTANCE(Qt::KeyboardModifiers{})
1943 QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration();
1944 return pi->keyMapper()->queryKeyboardModifiers();
1945}
1946
1947/*!
1948 Returns the current state of the buttons on the mouse. The current state is
1949 updated synchronously as the event queue is emptied of events that will
1950 spontaneously change the mouse state (QEvent::MouseButtonPress and
1951 QEvent::MouseButtonRelease events).
1952
1953 It should be noted this may not reflect the actual buttons held on the
1954 input device at the time of calling but rather the mouse buttons as last
1955 reported in one of the above events. If no mouse buttons are being held
1956 Qt::NoButton is returned.
1957
1958 \sa keyboardModifiers()
1959*/
1960Qt::MouseButtons QGuiApplication::mouseButtons()
1961{
1962 return QGuiApplicationPrivate::mouse_buttons;
1963}
1964
1965/*!
1966 \internal
1967 Returns the platform's native interface, for platform specific
1968 functionality.
1969*/
1970QPlatformNativeInterface *QGuiApplication::platformNativeInterface()
1971{
1972 QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration();
1973 return pi ? pi->nativeInterface() : nullptr;
1974}
1975
1976/*!
1977 \internal
1978 Returns a function pointer from the platformplugin matching \a function
1979*/
1980QFunctionPointer QGuiApplication::platformFunction(const QByteArray &function)
1981{
1982 QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration();
1983 if (!pi) {
1984 qWarning("QGuiApplication::platformFunction(): Must construct a QGuiApplication before accessing a platform function");
1985 return nullptr;
1986 }
1987
1988 return pi->nativeInterface() ? pi->nativeInterface()->platformFunction(function) : nullptr;
1989}
1990
1991/*!
1992 Enters the main event loop and waits until exit() is called, and then
1993 returns the value that was set to exit() (which is 0 if exit() is called
1994 via quit()).
1995
1996 It is necessary to call this function to start event handling. The main
1997 event loop receives events from the window system and dispatches these to
1998 the application widgets.
1999
2000 Generally, no user interaction can take place before calling exec().
2001
2002 To make your application perform idle processing, e.g., executing a
2003 special function whenever there are no pending events, use a QChronoTimer
2004 with 0ns timeout. More advanced idle processing schemes can be achieved
2005 using processEvents().
2006
2007 We recommend that you connect clean-up code to the
2008 \l{QCoreApplication::}{aboutToQuit()} signal, instead of putting it in your
2009 application's \c{main()} function. This is because, on some platforms, the
2010 QApplication::exec() call may not return.
2011
2012 \sa quitOnLastWindowClosed, quit(), exit(), processEvents(),
2013 QCoreApplication::exec()
2014*/
2015int QGuiApplication::exec()
2016{
2017#if QT_CONFIG(accessibility)
2018 QAccessible::setRootObject(qApp);
2019#endif
2020 return QCoreApplication::exec();
2021}
2022
2023void QGuiApplicationPrivate::captureGlobalModifierState(QEvent *e)
2024{
2025 if (e->spontaneous()) {
2026 // Capture the current mouse and keyboard states. Doing so here is
2027 // required in order to support Qt Test synthesized events. Real mouse
2028 // and keyboard state updates from the platform plugin are managed by
2029 // QGuiApplicationPrivate::process(Mouse|Wheel|Key|Touch|Tablet)Event();
2030 // ### FIXME: Qt Test should not call qapp->notify(), but rather route
2031 // the events through the proper QPA interface. This is required to
2032 // properly generate all other events such as enter/leave etc.
2033 switch (e->type()) {
2034 case QEvent::MouseButtonPress: {
2035 QMouseEvent *me = static_cast<QMouseEvent *>(e);
2036 QGuiApplicationPrivate::modifier_buttons = me->modifiers();
2037 QGuiApplicationPrivate::mouse_buttons |= me->button();
2038 break;
2039 }
2040 case QEvent::MouseButtonDblClick: {
2041 QMouseEvent *me = static_cast<QMouseEvent *>(e);
2042 QGuiApplicationPrivate::modifier_buttons = me->modifiers();
2043 QGuiApplicationPrivate::mouse_buttons |= me->button();
2044 break;
2045 }
2046 case QEvent::MouseButtonRelease: {
2047 QMouseEvent *me = static_cast<QMouseEvent *>(e);
2048 QGuiApplicationPrivate::modifier_buttons = me->modifiers();
2049 QGuiApplicationPrivate::mouse_buttons &= ~me->button();
2050 break;
2051 }
2052 case QEvent::KeyPress:
2053 case QEvent::KeyRelease:
2054 case QEvent::MouseMove:
2055#if QT_CONFIG(wheelevent)
2056 case QEvent::Wheel:
2057#endif
2058 case QEvent::TouchBegin:
2059 case QEvent::TouchUpdate:
2060 case QEvent::TouchEnd:
2061#if QT_CONFIG(tabletevent)
2062 case QEvent::TabletMove:
2063 case QEvent::TabletPress:
2064 case QEvent::TabletRelease:
2065#endif
2066 {
2067 QInputEvent *ie = static_cast<QInputEvent *>(e);
2068 QGuiApplicationPrivate::modifier_buttons = ie->modifiers();
2069 break;
2070 }
2071 default:
2072 break;
2073 }
2074 }
2075}
2076
2077/*! \reimp
2078*/
2079bool QGuiApplication::notify(QObject *object, QEvent *event)
2080{
2081 Q_D(QGuiApplication);
2082 if (object->isWindowType()) {
2083 if (QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(static_cast<QWindow *>(object), event))
2084 return true; // Platform plugin ate the event
2085 }
2086
2087 switch (event->type()) {
2088 case QEvent::ApplicationDeactivate:
2089 case QEvent::OrientationChange:
2090 // Close all popups (triggers when switching applications
2091 // by pressing ALT-TAB on Windows, which is not received as a key event.
2092 // triggers when the screen rotates.)
2093 // This is also necessary on Wayland, and platforms where
2094 // QWindow::setMouseGrabEnabled(true) doesn't work.
2095 d->closeAllPopups();
2096 break;
2097 default:
2098 break;
2099 }
2100
2101 QGuiApplicationPrivate::captureGlobalModifierState(event);
2102
2103 return QCoreApplication::notify(object, event);
2104}
2105
2106/*! \reimp
2107*/
2108bool QGuiApplication::event(QEvent *e)
2109{
2110 switch (e->type()) {
2111 case QEvent::LanguageChange:
2112 // if the layout direction was set explicitly, then don't override it here
2113 if (layout_direction == Qt::LayoutDirectionAuto)
2114 setLayoutDirection(layout_direction);
2115 for (auto *topLevelWindow : QGuiApplication::topLevelWindows())
2116 postEvent(topLevelWindow, new QEvent(QEvent::LanguageChange));
2117 break;
2118 case QEvent::ApplicationFontChange:
2119 case QEvent::ApplicationPaletteChange:
2120 postEvent(QGuiApplication::styleHints(), e->clone());
2121 for (auto *topLevelWindow : QGuiApplication::topLevelWindows())
2122 postEvent(topLevelWindow, new QEvent(e->type()));
2123 break;
2124 case QEvent::ThemeChange:
2125 forwardEvent(QGuiApplication::styleHints(), e);
2126 for (auto *w : QGuiApplication::allWindows())
2127 forwardEvent(w, e);
2128 break;
2129 case QEvent::Quit:
2130 // Close open windows. This is done in order to deliver de-expose
2131 // events while the event loop is still running.
2132 for (QWindow *topLevelWindow : QGuiApplication::topLevelWindows()) {
2133 // Already closed windows will not have a platform window, skip those
2134 if (!topLevelWindow->handle())
2135 continue;
2136 if (!topLevelWindow->close()) {
2137 e->ignore();
2138 return true;
2139 }
2140 }
2141 break;
2142 default:
2143 break;
2144 }
2145 return QCoreApplication::event(e);
2146}
2147
2148#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
2149/*!
2150 \internal
2151*/
2152bool QGuiApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventList *postedEvents)
2153{
2154 QT_IGNORE_DEPRECATIONS(
2155 return QCoreApplication::compressEvent(event, receiver, postedEvents);
2156 )
2157}
2158#endif
2159
2160bool QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(QWindow *window, QEvent *event)
2161{
2162 if (!window)
2163 return false;
2164 QPlatformWindow *platformWindow = window->handle();
2165 if (!platformWindow)
2166 return false;
2167 // spontaneous events come from the platform integration already, we don't need to send the events back
2168 if (event->spontaneous())
2169 return false;
2170 // let the platform window do any handling it needs to as well
2171 return platformWindow->windowEvent(event);
2172}
2173
2174bool QGuiApplicationPrivate::processNativeEvent(QWindow *window, const QByteArray &eventType, void *message, qintptr *result)
2175{
2176 return window->nativeEvent(eventType, message, result);
2177}
2178
2179bool QGuiApplicationPrivate::isUsingVirtualKeyboard()
2180{
2181 static const bool usingVirtualKeyboard = getenv("QT_IM_MODULE") == QByteArrayView("qtvirtualkeyboard");
2182 return usingVirtualKeyboard;
2183}
2184
2185// If a virtual keyboard exists, forward mouse event
2186bool QGuiApplicationPrivate::maybeForwardEventToVirtualKeyboard(QEvent *e)
2187{
2188 if (!isUsingVirtualKeyboard()) {
2189 qCDebug(lcVirtualKeyboard) << "Virtual keyboard not supported.";
2190 return false;
2191 }
2192
2193 static QPointer<QWindow> virtualKeyboard;
2194 const QEvent::Type type = e->type();
2195 Q_ASSERT(type == QEvent::MouseButtonPress || type == QEvent::MouseButtonRelease);
2196 const auto me = static_cast<QMouseEvent *>(e);
2197 const QPointF posF = me->globalPosition();
2198 const QPoint pos = posF.toPoint();
2199
2200 // Is there a visible virtual keyboard at event position?
2201 if (!virtualKeyboard) {
2202 if (QWindow *win = QGuiApplication::topLevelAt(pos);
2203 win->inherits("QtVirtualKeyboard::InputView")) {
2204 virtualKeyboard = win;
2205 } else {
2206 qCDebug(lcVirtualKeyboard) << "Virtual keyboard supported, but inactive.";
2207 return false;
2208 }
2209 }
2210
2211 Q_ASSERT(virtualKeyboard);
2212 const bool virtualKeyboardUnderMouse = virtualKeyboard->isVisible()
2213 && virtualKeyboard->geometry().contains(pos);
2214
2215 if (!virtualKeyboardUnderMouse) {
2216 qCDebug(lcVirtualKeyboard) << type << "at" << pos << "is outside geometry"
2217 << virtualKeyboard->geometry() << "of" << virtualKeyboard.data();
2218 return false;
2219 }
2220
2221 QMouseEvent vkbEvent(type, virtualKeyboard->mapFromGlobal(pos), pos,
2222 me->button(), me->buttons(), me->modifiers(),
2223 me->pointingDevice());
2224
2225 QGuiApplication::sendEvent(virtualKeyboard, &vkbEvent);
2226 qCDebug(lcVirtualKeyboard) << "Forwarded" << type << "to" << virtualKeyboard.data()
2227 << "at" << pos;
2228
2229 return true;
2230}
2231
2232void Q_TRACE_INSTRUMENT(qtgui) QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e)
2233{
2234 Q_TRACE_PARAM_REPLACE(QWindowSystemInterfacePrivate::WindowSystemEvent *, int);
2235 Q_TRACE_SCOPE(QGuiApplicationPrivate_processWindowSystemEvent, e->type);
2236
2237 const bool haveGuiApplication = QGuiApplication::instance() && QGuiApplicationPrivate::instance();
2238 Q_ASSERT_X(haveGuiApplication, "QGuiApplication", "Asked to process QPA event without a QGuiApplication");
2239 if (!haveGuiApplication) {
2240 qWarning("QGuiApplication was asked to process QPA event without a QGuiApplication instance");
2241 e->eventAccepted = false;
2242 return;
2243 }
2244
2245 switch(e->type) {
2246 case QWindowSystemInterfacePrivate::Mouse:
2247 QGuiApplicationPrivate::processMouseEvent(static_cast<QWindowSystemInterfacePrivate::MouseEvent *>(e));
2248 break;
2249 case QWindowSystemInterfacePrivate::Wheel:
2250 QGuiApplicationPrivate::processWheelEvent(static_cast<QWindowSystemInterfacePrivate::WheelEvent *>(e));
2251 break;
2252 case QWindowSystemInterfacePrivate::Key:
2253 QGuiApplicationPrivate::processKeyEvent(static_cast<QWindowSystemInterfacePrivate::KeyEvent *>(e));
2254 break;
2255 case QWindowSystemInterfacePrivate::Touch:
2256 QGuiApplicationPrivate::processTouchEvent(static_cast<QWindowSystemInterfacePrivate::TouchEvent *>(e));
2257 break;
2258 case QWindowSystemInterfacePrivate::GeometryChange:
2259 QGuiApplicationPrivate::processGeometryChangeEvent(static_cast<QWindowSystemInterfacePrivate::GeometryChangeEvent*>(e));
2260 break;
2261 case QWindowSystemInterfacePrivate::Enter:
2262 QGuiApplicationPrivate::processEnterEvent(static_cast<QWindowSystemInterfacePrivate::EnterEvent *>(e));
2263 break;
2264 case QWindowSystemInterfacePrivate::Leave:
2265 QGuiApplicationPrivate::processLeaveEvent(static_cast<QWindowSystemInterfacePrivate::LeaveEvent *>(e));
2266 break;
2267 case QWindowSystemInterfacePrivate::FocusWindow:
2268 QGuiApplicationPrivate::processFocusWindowEvent(static_cast<QWindowSystemInterfacePrivate::FocusWindowEvent *>(e));
2269 break;
2270 case QWindowSystemInterfacePrivate::WindowStateChanged:
2271 QGuiApplicationPrivate::processWindowStateChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowStateChangedEvent *>(e));
2272 break;
2273 case QWindowSystemInterfacePrivate::WindowScreenChanged:
2274 QGuiApplicationPrivate::processWindowScreenChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowScreenChangedEvent *>(e));
2275 break;
2276 case QWindowSystemInterfacePrivate::WindowDevicePixelRatioChanged:
2277 QGuiApplicationPrivate::processWindowDevicePixelRatioChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowDevicePixelRatioChangedEvent *>(e));
2278 break;
2279 case QWindowSystemInterfacePrivate::SafeAreaMarginsChanged:
2280 QGuiApplicationPrivate::processSafeAreaMarginsChangedEvent(static_cast<QWindowSystemInterfacePrivate::SafeAreaMarginsChangedEvent *>(e));
2281 break;
2282 case QWindowSystemInterfacePrivate::ApplicationStateChanged: {
2283 QWindowSystemInterfacePrivate::ApplicationStateChangedEvent * changeEvent = static_cast<QWindowSystemInterfacePrivate::ApplicationStateChangedEvent *>(e);
2284 QGuiApplicationPrivate::setApplicationState(changeEvent->newState, changeEvent->forcePropagate); }
2285 break;
2286 case QWindowSystemInterfacePrivate::ApplicationTermination:
2287 QGuiApplicationPrivate::processApplicationTermination(e);
2288 break;
2289 case QWindowSystemInterfacePrivate::FlushEvents: {
2290 QWindowSystemInterfacePrivate::FlushEventsEvent *flushEventsEvent = static_cast<QWindowSystemInterfacePrivate::FlushEventsEvent *>(e);
2291 QWindowSystemInterface::deferredFlushWindowSystemEvents(flushEventsEvent->flags); }
2292 break;
2293 case QWindowSystemInterfacePrivate::Close:
2294 QGuiApplicationPrivate::processCloseEvent(
2295 static_cast<QWindowSystemInterfacePrivate::CloseEvent *>(e));
2296 break;
2297 case QWindowSystemInterfacePrivate::ScreenOrientation:
2298 QGuiApplicationPrivate::processScreenOrientationChange(
2299 static_cast<QWindowSystemInterfacePrivate::ScreenOrientationEvent *>(e));
2300 break;
2301 case QWindowSystemInterfacePrivate::ScreenGeometry:
2302 QGuiApplicationPrivate::processScreenGeometryChange(
2303 static_cast<QWindowSystemInterfacePrivate::ScreenGeometryEvent *>(e));
2304 break;
2305 case QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInch:
2306 QGuiApplicationPrivate::processScreenLogicalDotsPerInchChange(
2307 static_cast<QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *>(e));
2308 break;
2309 case QWindowSystemInterfacePrivate::ScreenRefreshRate:
2310 QGuiApplicationPrivate::processScreenRefreshRateChange(
2311 static_cast<QWindowSystemInterfacePrivate::ScreenRefreshRateEvent *>(e));
2312 break;
2313 case QWindowSystemInterfacePrivate::ThemeChange:
2314 QGuiApplicationPrivate::processThemeChanged(
2315 static_cast<QWindowSystemInterfacePrivate::ThemeChangeEvent *>(e));
2316 break;
2317 case QWindowSystemInterfacePrivate::Expose:
2318 QGuiApplicationPrivate::processExposeEvent(static_cast<QWindowSystemInterfacePrivate::ExposeEvent *>(e));
2319 break;
2320 case QWindowSystemInterfacePrivate::Paint:
2321 QGuiApplicationPrivate::processPaintEvent(static_cast<QWindowSystemInterfacePrivate::PaintEvent *>(e));
2322 break;
2323 case QWindowSystemInterfacePrivate::Tablet:
2324 QGuiApplicationPrivate::processTabletEvent(
2325 static_cast<QWindowSystemInterfacePrivate::TabletEvent *>(e));
2326 break;
2327 case QWindowSystemInterfacePrivate::TabletEnterProximity:
2328 QGuiApplicationPrivate::processTabletEnterProximityEvent(
2329 static_cast<QWindowSystemInterfacePrivate::TabletEnterProximityEvent *>(e));
2330 break;
2331 case QWindowSystemInterfacePrivate::TabletLeaveProximity:
2332 QGuiApplicationPrivate::processTabletLeaveProximityEvent(
2333 static_cast<QWindowSystemInterfacePrivate::TabletLeaveProximityEvent *>(e));
2334 break;
2335#ifndef QT_NO_GESTURES
2336 case QWindowSystemInterfacePrivate::Gesture:
2337 QGuiApplicationPrivate::processGestureEvent(
2338 static_cast<QWindowSystemInterfacePrivate::GestureEvent *>(e));
2339 break;
2340#endif
2341 case QWindowSystemInterfacePrivate::PlatformPanel:
2342 QGuiApplicationPrivate::processPlatformPanelEvent(
2343 static_cast<QWindowSystemInterfacePrivate::PlatformPanelEvent *>(e));
2344 break;
2345 case QWindowSystemInterfacePrivate::FileOpen:
2346 QGuiApplicationPrivate::processFileOpenEvent(
2347 static_cast<QWindowSystemInterfacePrivate::FileOpenEvent *>(e));
2348 break;
2349#ifndef QT_NO_CONTEXTMENU
2350 case QWindowSystemInterfacePrivate::ContextMenu:
2351 QGuiApplicationPrivate::processContextMenuEvent(
2352 static_cast<QWindowSystemInterfacePrivate::ContextMenuEvent *>(e));
2353 break;
2354#endif
2355 case QWindowSystemInterfacePrivate::EnterWhatsThisMode:
2356 QGuiApplication::postEvent(QGuiApplication::instance(), new QEvent(QEvent::EnterWhatsThisMode));
2357 break;
2358 default:
2359 qWarning() << "Unknown user input event type:" << e->type;
2360 break;
2361 }
2362}
2363
2364/*! \internal
2365
2366 History is silent on why Qt splits mouse events that change position and
2367 button state at the same time. We believe that this was done to emulate mouse
2368 behavior on touch screens. If mouse tracking is enabled, we will get move
2369 events before the button is pressed. A touch panel does not generally give
2370 move events when not pressed, so without event splitting code path we would
2371 only see a press in a new location without any intervening moves. This could
2372 confuse code that is written for a real mouse. The same is true for mouse
2373 release events that change position, see tst_QWidget::touchEventSynthesizedMouseEvent()
2374 and tst_QWindow::generatedMouseMove() auto tests.
2375*/
2376void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent *e)
2377{
2378 QEvent::Type type = QEvent::None;
2379 Qt::MouseButton button = Qt::NoButton;
2380 QWindow *window = e->window.data();
2381 const QPointingDevice *device = static_cast<const QPointingDevice *>(e->device);
2382 Q_ASSERT(device);
2383 QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(const_cast<QPointingDevice*>(device));
2384 bool positionChanged = QGuiApplicationPrivate::lastCursorPosition != e->globalPos;
2385 bool mouseMove = false;
2386 bool mousePress = false;
2387 const QPointF lastGlobalPosition = QGuiApplicationPrivate::lastCursorPosition;
2388 QPointF globalPoint = e->globalPos;
2389
2390 if (qIsNaN(e->globalPos.x()) || qIsNaN(e->globalPos.y())) {
2391 qWarning("QGuiApplicationPrivate::processMouseEvent: Got NaN in mouse position");
2392 return;
2393 }
2394
2395 type = e->buttonType;
2396 button = e->button;
2397
2398 if (type == QEvent::NonClientAreaMouseMove || type == QEvent::MouseMove)
2399 mouseMove = true;
2400 else if (type == QEvent::NonClientAreaMouseButtonPress || type == QEvent::MouseButtonPress)
2401 mousePress = true;
2402
2403 if (!mouseMove && positionChanged) {
2404 QWindowSystemInterfacePrivate::MouseEvent moveEvent(window, e->timestamp,
2405 e->localPos, e->globalPos, e->buttons ^ button, e->modifiers, Qt::NoButton,
2406 e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove,
2407 e->source, e->nonClientArea, device, e->eventPointId);
2408 if (e->synthetic())
2409 moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
2410 processMouseEvent(&moveEvent); // mouse move excluding state change
2411 processMouseEvent(e); // the original mouse event
2412 return;
2413 }
2414 if (type == QEvent::MouseMove && !positionChanged) {
2415 // On Windows, and possibly other platforms, a touchpad can send a mouse move
2416 // that does not change position, between a press and a release. This may
2417 // confuse applications, so we always filter out these mouse events for
2418 // consistent behavior among platforms.
2419 return;
2420 }
2421
2422 modifier_buttons = e->modifiers;
2423 QPointF localPoint = e->localPos;
2424 bool doubleClick = false;
2425 auto persistentEPD = devPriv->pointById(0);
2426
2427 if (e->synthetic(); auto *originalDeviceEPD = devPriv->queryPointById(e->eventPointId))
2428 QMutableEventPoint::update(originalDeviceEPD->eventPoint, persistentEPD->eventPoint);
2429
2430 if (mouseMove) {
2431 QGuiApplicationPrivate::lastCursorPosition = globalPoint;
2432 const auto doubleClickDistance = (e->device && e->device->type() == QInputDevice::DeviceType::Mouse ?
2433 mouseDoubleClickDistance : touchDoubleTapDistance);
2434 const auto pressPos = persistentEPD->eventPoint.globalPressPosition();
2435 if (qAbs(globalPoint.x() - pressPos.x()) > doubleClickDistance ||
2436 qAbs(globalPoint.y() - pressPos.y()) > doubleClickDistance)
2437 mousePressButton = Qt::NoButton;
2438 } else {
2439 static unsigned long lastPressTimestamp = 0;
2440 static QPointer<QWindow> lastPressWindow = nullptr;
2441 mouse_buttons = e->buttons;
2442 if (mousePress) {
2443 ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval());
2444 const auto timestampDelta = e->timestamp - lastPressTimestamp;
2445 doubleClick = timestampDelta > 0 && timestampDelta < doubleClickInterval
2446 && button == mousePressButton && lastPressWindow == e->window;
2447 mousePressButton = button;
2448 lastPressTimestamp = e ->timestamp;
2449 lastPressWindow = e->window;
2450 }
2451 }
2452
2453 if (e->nullWindow()) {
2454 window = QGuiApplication::topLevelAt(globalPoint.toPoint());
2455 if (window) {
2456 // Moves and the release following a press must go to the same
2457 // window, even if the cursor has moved on over another window.
2458 if (e->buttons != Qt::NoButton) {
2459 if (!currentMousePressWindow)
2460 currentMousePressWindow = window;
2461 else
2462 window = currentMousePressWindow;
2463 } else if (currentMousePressWindow) {
2464 window = currentMousePressWindow;
2465 currentMousePressWindow = nullptr;
2466 }
2467 localPoint = window->mapFromGlobal(globalPoint);
2468 }
2469 }
2470
2471 if (!window)
2472 return;
2473
2474#ifndef QT_NO_CURSOR
2475 if (!e->synthetic()) {
2476 if (const QScreen *screen = window->screen())
2477 if (QPlatformCursor *cursor = screen->handle()->cursor()) {
2478 const QPointF nativeLocalPoint = QHighDpi::toNativePixels(localPoint, screen);
2479 const QPointF nativeGlobalPoint = QHighDpi::toNativePixels(globalPoint, screen);
2480 QMouseEvent ev(type, nativeLocalPoint, nativeLocalPoint, nativeGlobalPoint,
2481 button, e->buttons, e->modifiers, e->source, device);
2482 // avoid incorrect velocity calculation: ev is in the native coordinate system,
2483 // but we need to consistently use the logical coordinate system for velocity
2484 // whenever QEventPoint::setTimestamp() is called
2485 ev.QInputEvent::setTimestamp(e->timestamp);
2486 cursor->pointerEvent(ev);
2487 }
2488 }
2489#endif
2490
2491 const auto *activePopup = activePopupWindow();
2492 if (type == QEvent::MouseButtonPress)
2493 active_popup_on_press = activePopup;
2494 if (window->d_func()->blockedByModalWindow && !activePopup) {
2495 // a modal window is blocking this window, don't allow mouse events through
2496 return;
2497 }
2498
2499 QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, e->buttons, e->modifiers, e->source, device);
2500 Q_ASSERT(devPriv->pointById(0) == persistentEPD); // we don't expect reallocation in QPlatformCursor::pointerEvenmt()
2501 // restore globalLastPosition to avoid invalidating the velocity calculations,
2502 // because the QPlatformCursor mouse event above was in native coordinates
2503 QMutableEventPoint::setGlobalLastPosition(persistentEPD->eventPoint, lastGlobalPosition);
2504 persistentEPD = nullptr; // incoming and synth events can cause reallocation during delivery, so don't use this again
2505 // ev now contains a detached copy of the QEventPoint from QPointingDevicePrivate::activePoints
2506 ev.setTimestamp(e->timestamp);
2507
2508 if (activePopup && activePopup != window && (!popup_closed_on_press || type == QEvent::MouseButtonRelease)) {
2509 // If the popup handles the event, we're done.
2510 auto *handlingPopup = window->d_func()->forwardToPopup(&ev, active_popup_on_press);
2511 if (handlingPopup) {
2512 if (type == QEvent::MouseButtonPress)
2513 active_popup_on_press = handlingPopup;
2514 return;
2515 }
2516 }
2517
2518 if (doubleClick && (ev.type() == QEvent::MouseButtonPress)) {
2519 // QtBUG-25831, used to suppress delivery in qwidgetwindow.cpp
2520 QMutableSinglePointEvent::setDoubleClick(&ev, true);
2521 }
2522
2523 QGuiApplication::sendSpontaneousEvent(window, &ev);
2524 e->eventAccepted = ev.isAccepted();
2525 if (!e->synthetic() && !ev.isAccepted()
2526 && !e->nonClientArea
2527 && qApp->testAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents)) {
2528 QList<QWindowSystemInterface::TouchPoint> points;
2529 QWindowSystemInterface::TouchPoint point;
2530 point.id = 1;
2531 point.area = QHighDpi::toNativePixels(QRectF(globalPoint.x() - 2, globalPoint.y() - 2, 4, 4), window);
2532
2533 // only translate left button related events to
2534 // avoid strange touch event sequences when several
2535 // buttons are pressed
2536 if (type == QEvent::MouseButtonPress && button == Qt::LeftButton) {
2537 point.state = QEventPoint::State::Pressed;
2538 } else if (type == QEvent::MouseButtonRelease && button == Qt::LeftButton) {
2539 point.state = QEventPoint::State::Released;
2540 } else if (type == QEvent::MouseMove && (e->buttons & Qt::LeftButton)) {
2541 point.state = QEventPoint::State::Updated;
2542 } else {
2543 return;
2544 }
2545
2546 points << point;
2547
2548 QEvent::Type type;
2549 const QList<QEventPoint> &touchPoints =
2550 QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, &type);
2551
2552 QWindowSystemInterfacePrivate::TouchEvent fake(window, e->timestamp, type, device, touchPoints, e->modifiers);
2553 fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
2554 processTouchEvent(&fake);
2555 }
2556 if (doubleClick) {
2557 mousePressButton = Qt::NoButton;
2558 if (!e->window.isNull() || e->nullWindow()) { // QTBUG-36364, check if window closed in response to press
2559 const QEvent::Type doubleClickType = e->nonClientArea ? QEvent::NonClientAreaMouseButtonDblClick : QEvent::MouseButtonDblClick;
2560 QMouseEvent dblClickEvent(doubleClickType, localPoint, localPoint, globalPoint,
2561 button, e->buttons, e->modifiers, e->source, device);
2562 dblClickEvent.setTimestamp(e->timestamp);
2563 QGuiApplication::sendSpontaneousEvent(window, &dblClickEvent);
2564 }
2565 }
2566 if (type == QEvent::MouseButtonRelease && e->buttons == Qt::NoButton) {
2567 popup_closed_on_press = false;
2568 if (auto *persistentEPD = devPriv->queryPointById(0)) {
2569 ev.setExclusiveGrabber(persistentEPD->eventPoint, nullptr);
2570 ev.clearPassiveGrabbers(persistentEPD->eventPoint);
2571 }
2572 }
2573}
2574
2575void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::WheelEvent *e)
2576{
2577#if QT_CONFIG(wheelevent)
2578 QWindow *window = e->window.data();
2579 QPointF globalPoint = e->globalPos;
2580 QPointF localPoint = e->localPos;
2581
2582 if (e->nullWindow()) {
2583 window = QGuiApplication::topLevelAt(globalPoint.toPoint());
2584 if (window)
2585 localPoint = window->mapFromGlobal(globalPoint);
2586 }
2587
2588 if (!window)
2589 return;
2590
2591 QGuiApplicationPrivate::lastCursorPosition = globalPoint;
2592 modifier_buttons = e->modifiers;
2593
2594 if (window->d_func()->blockedByModalWindow) {
2595 // a modal window is blocking this window, don't allow wheel events through
2596 return;
2597 }
2598
2599 const QPointingDevice *device = static_cast<const QPointingDevice *>(e->device);
2600 QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta,
2601 mouse_buttons, e->modifiers, e->phase, e->inverted, e->source, device);
2602 ev.setTimestamp(e->timestamp);
2603 QGuiApplication::sendSpontaneousEvent(window, &ev);
2604 e->eventAccepted = ev.isAccepted();
2605#else
2606 Q_UNUSED(e);
2607#endif // QT_CONFIG(wheelevent)
2608}
2609
2610void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyEvent *e)
2611{
2612 QWindow *window = e->window.data();
2613 modifier_buttons = e->modifiers;
2614 if (e->nullWindow())
2615 window = QGuiApplication::focusWindow();
2616
2617 if (!window) {
2618 e->eventAccepted = false;
2619 return;
2620 }
2621
2622#if !defined(Q_OS_MACOS)
2623 // FIXME: Include OS X in this code path by passing the key event through
2624 // QPlatformInputContext::filterEvent().
2625 if (e->keyType == QEvent::KeyPress) {
2626 if (QWindowSystemInterface::handleShortcutEvent(window, e->timestamp, e->key, e->modifiers,
2627 e->nativeScanCode, e->nativeVirtualKey, e->nativeModifiers, e->unicode, e->repeat, e->repeatCount)) {
2628 return;
2629 }
2630 }
2631#endif
2632
2633 QKeyEvent ev(e->keyType, e->key, e->modifiers,
2634 e->nativeScanCode, e->nativeVirtualKey, e->nativeModifiers,
2635 e->unicode, e->repeat, e->repeatCount);
2636 ev.setTimestamp(e->timestamp);
2637
2638 const auto *activePopup = activePopupWindow();
2639 if (activePopup && activePopup != window) {
2640 // If the popup handles the event, we're done.
2641 if (window->d_func()->forwardToPopup(&ev, active_popup_on_press))
2642 return;
2643 }
2644
2645 // only deliver key events when we have a window, and no modal window is blocking this window
2646
2647 if (!window->d_func()->blockedByModalWindow)
2648 QGuiApplication::sendSpontaneousEvent(window, &ev);
2649#ifdef Q_OS_ANDROID
2650 else
2651 ev.setAccepted(false);
2652#endif
2653 e->eventAccepted = ev.isAccepted();
2654}
2655
2656void QGuiApplicationPrivate::processEnterEvent(QWindowSystemInterfacePrivate::EnterEvent *e)
2657{
2658 if (!e->enter)
2659 return;
2660 if (e->enter.data()->d_func()->blockedByModalWindow) {
2661 // a modal window is blocking this window, don't allow enter events through
2662 return;
2663 }
2664
2665 currentMouseWindow = e->enter;
2666
2667 // TODO later: EnterEvent must report _which_ mouse entered the window; for now we assume primaryPointingDevice()
2668 QEnterEvent event(e->localPos, e->localPos, e->globalPos);
2669
2670 // Since we don't always track mouse moves that occur outside a window, any residual velocity
2671 // stored in the persistent QEventPoint may be inaccurate (especially in fast-moving autotests).
2672 // Reset the Kalman filter so that the velocity of the first mouse event after entering the window
2673 // will be based on a zero residual velocity (but the result can still be non-zero if the mouse
2674 // moves to a different position from where this enter event occurred; tests often do that).
2675 const QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(event.pointingDevice());
2676 auto epd = devPriv->queryPointById(event.points().first().id());
2677 Q_ASSERT(epd);
2678 QMutableEventPoint::setVelocity(epd->eventPoint, {});
2679
2680 QCoreApplication::sendSpontaneousEvent(e->enter.data(), &event);
2681}
2682
2683void QGuiApplicationPrivate::processLeaveEvent(QWindowSystemInterfacePrivate::LeaveEvent *e)
2684{
2685 if (!e->leave)
2686 return;
2687 if (e->leave.data()->d_func()->blockedByModalWindow) {
2688 // a modal window is blocking this window, don't allow leave events through
2689 return;
2690 }
2691
2692 currentMouseWindow = nullptr;
2693
2694 QEvent event(QEvent::Leave);
2695 QCoreApplication::sendSpontaneousEvent(e->leave.data(), &event);
2696}
2697
2698void QGuiApplicationPrivate::processFocusWindowEvent(QWindowSystemInterfacePrivate::FocusWindowEvent *e)
2699{
2700 QWindow *previous = QGuiApplicationPrivate::focus_window;
2701 QWindow *newFocus = e->focused.data();
2702
2703 if (previous == newFocus)
2704 return;
2705
2706 bool activatedPopup = false;
2707 if (newFocus) {
2708 if (QPlatformWindow *platformWindow = newFocus->handle())
2709 if (platformWindow->isAlertState())
2710 platformWindow->setAlertState(false);
2711 activatedPopup = (newFocus->flags() & Qt::WindowType_Mask) == Qt::Popup;
2712 if (activatedPopup)
2713 activatePopup(newFocus);
2714 }
2715
2716 QObject *previousFocusObject = previous ? previous->focusObject() : nullptr;
2717
2718 if (previous) {
2719 QFocusEvent focusAboutToChange(QEvent::FocusAboutToChange);
2720 QCoreApplication::sendSpontaneousEvent(previous, &focusAboutToChange);
2721 }
2722
2723 QGuiApplicationPrivate::focus_window = newFocus;
2724 if (!qApp)
2725 return;
2726
2727 if (previous) {
2728 Qt::FocusReason r = e->reason;
2729 if ((r == Qt::OtherFocusReason || r == Qt::ActiveWindowFocusReason) && activatedPopup)
2730 r = Qt::PopupFocusReason;
2731 QFocusEvent focusOut(QEvent::FocusOut, r);
2732 QCoreApplication::sendSpontaneousEvent(previous, &focusOut);
2733 QObject::disconnect(previous, SIGNAL(focusObjectChanged(QObject*)),
2734 qApp, SLOT(_q_updateFocusObject(QObject*)));
2735 } else if (!platformIntegration()->hasCapability(QPlatformIntegration::ApplicationState)) {
2736 setApplicationState(Qt::ApplicationActive);
2737 }
2738
2739 if (QGuiApplicationPrivate::focus_window) {
2740 Qt::FocusReason r = e->reason;
2741 if ((r == Qt::OtherFocusReason || r == Qt::ActiveWindowFocusReason) &&
2742 previous && (previous->flags() & Qt::Popup) == Qt::Popup)
2743 r = Qt::PopupFocusReason;
2744 QFocusEvent focusIn(QEvent::FocusIn, r);
2745 QCoreApplication::sendSpontaneousEvent(QGuiApplicationPrivate::focus_window, &focusIn);
2746 QObject::connect(QGuiApplicationPrivate::focus_window, SIGNAL(focusObjectChanged(QObject*)),
2747 qApp, SLOT(_q_updateFocusObject(QObject*)));
2748 } else if (!platformIntegration()->hasCapability(QPlatformIntegration::ApplicationState)) {
2749 setApplicationState(Qt::ApplicationInactive);
2750 }
2751
2752 if (auto *guiAppPrivate = QGuiApplicationPrivate::instance()) {
2753 guiAppPrivate->notifyActiveWindowChange(previous);
2754
2755 if (previousFocusObject != qApp->focusObject() ||
2756 // We are getting an activation change but there is no new focusObject, and we also
2757 // don't have a previousFocusObject in the previously active window anymore. This can
2758 // happen when window gets destroyed (see QWidgetWindow::focusObject returning nullptr
2759 // when already in the QWidget destructor), so update the focusObject to avoid dangling
2760 // pointers. See also QWidget::clearFocus(), which tries to cover for this as well.
2761 (previous && previousFocusObject == nullptr && qApp->focusObject() == nullptr)) {
2762 guiAppPrivate->_q_updateFocusObject(qApp->focusObject());
2763 }
2764 }
2765
2766 emit qApp->focusWindowChanged(newFocus);
2767 if (previous)
2768 emit previous->activeChanged();
2769 if (newFocus)
2770 emit newFocus->activeChanged();
2771}
2772
2773void QGuiApplicationPrivate::processWindowStateChangedEvent(QWindowSystemInterfacePrivate::WindowStateChangedEvent *wse)
2774{
2775 if (QWindow *window = wse->window.data()) {
2776 QWindowPrivate *windowPrivate = qt_window_private(window);
2777 const auto originalEffectiveState = QWindowPrivate::effectiveState(windowPrivate->windowState);
2778
2779 windowPrivate->windowState = wse->newState;
2780 const auto newEffectiveState = QWindowPrivate::effectiveState(windowPrivate->windowState);
2781 if (newEffectiveState != originalEffectiveState)
2782 emit window->windowStateChanged(newEffectiveState);
2783
2784 windowPrivate->updateVisibility();
2785
2786 QWindowStateChangeEvent e(wse->oldState);
2787 QGuiApplication::sendSpontaneousEvent(window, &e);
2788 }
2789}
2790
2791void QGuiApplicationPrivate::processWindowScreenChangedEvent(QWindowSystemInterfacePrivate::WindowScreenChangedEvent *wse)
2792{
2793 QWindow *window = wse->window.data();
2794 if (!window)
2795 return;
2796
2797 QScreen *screen = wse->screen.data();
2798 if (window->screen() == screen)
2799 return;
2800
2801 auto *windowPrivate = QWindowPrivate::get(window);
2802 QWindow *topLevelWindow = windowPrivate->topLevelWindow(QWindow::ExcludeTransients);
2803 if (window == topLevelWindow) {
2804 if (screen)
2805 topLevelWindow->d_func()->setTopLevelScreen(screen, false /* recreate */);
2806 else // Fall back to default behavior, and try to find some appropriate screen
2807 topLevelWindow->setScreen(nullptr);
2808 } else if (screen) {
2809 // Child windows reflect the screen of their top level parent. When a
2810 // window is reparented into a window that lives on a different screen
2811 // we don't need to update the top level screen, but do need to emit
2812 // screen changes for the child and its children,
2813 windowPrivate->emitScreenChangedRecursion(screen);
2814 }
2815}
2816
2817void QGuiApplicationPrivate::processWindowDevicePixelRatioChangedEvent(QWindowSystemInterfacePrivate::WindowDevicePixelRatioChangedEvent *wde)
2818{
2819 if (wde->window.isNull())
2820 return;
2821 QWindowPrivate::get(wde->window)->updateDevicePixelRatio();
2822}
2823
2824void QGuiApplicationPrivate::processSafeAreaMarginsChangedEvent(QWindowSystemInterfacePrivate::SafeAreaMarginsChangedEvent *wse)
2825{
2826 if (wse->window.isNull())
2827 return;
2828
2829 emit wse->window->safeAreaMarginsChanged(wse->window->safeAreaMargins());
2830
2831 QEvent event(QEvent::SafeAreaMarginsChange);
2832 QGuiApplication::sendSpontaneousEvent(wse->window, &event);
2833}
2834
2835void QGuiApplicationPrivate::processThemeChanged(QWindowSystemInterfacePrivate::ThemeChangeEvent *)
2836{
2837 // FIXME: Remove check once we ensure that the platform plugin is
2838 // torn down before QGuiApplication.
2839 if (!qGuiApp)
2840 return;
2841
2842 if (auto *guiAppPrivate = QGuiApplicationPrivate::instance())
2843 guiAppPrivate->handleThemeChanged();
2844
2845 QIconPrivate::clearIconCache();
2846
2847 QEvent themeChangeEvent(QEvent::ThemeChange);
2848 QGuiApplication::sendSpontaneousEvent(qGuiApp, &themeChangeEvent);
2849}
2850
2851void QGuiApplicationPrivate::handleThemeChanged()
2852{
2853 QStyleHintsPrivate::get(QGuiApplication::styleHints())->update(platformTheme());
2854 updatePalette();
2855
2856 QIconLoader::instance()->updateSystemTheme();
2857 QAbstractFileIconProviderPrivate::clearIconTypeCache();
2858
2859 if (!(applicationResourceFlags & ApplicationFontExplicitlySet)) {
2860 const auto locker = qt_scoped_lock(applicationFontMutex);
2861 clearFontUnlocked();
2862 initFontUnlocked();
2863 }
2864 initThemeHints();
2865}
2866
2867void QGuiApplicationPrivate::processGeometryChangeEvent(QWindowSystemInterfacePrivate::GeometryChangeEvent *e)
2868{
2869 if (e->window.isNull())
2870 return;
2871
2872 QWindow *window = e->window.data();
2873 if (!window)
2874 return;
2875
2876 const QRect lastReportedGeometry = window->d_func()->geometry;
2877 const QRect requestedGeometry = e->requestedGeometry;
2878 const QRect actualGeometry = e->newGeometry;
2879
2880 // We send size and move events only if the geometry has changed from
2881 // what was last reported, or if the user tried to set a new geometry,
2882 // but the window manager responded by keeping the old geometry. In the
2883 // latter case we send move/resize events with the same geometry as the
2884 // last reported geometry, to indicate that the window wasn't moved or
2885 // resized. Note that this logic does not apply to the property changes
2886 // of the window, as we don't treat them as part of this request/response
2887 // protocol of QWindow/QPA.
2888 const bool isResize = actualGeometry.size() != lastReportedGeometry.size()
2889 || requestedGeometry.size() != actualGeometry.size();
2890 const bool isMove = actualGeometry.topLeft() != lastReportedGeometry.topLeft()
2891 || requestedGeometry.topLeft() != actualGeometry.topLeft();
2892
2893 window->d_func()->geometry = actualGeometry;
2894
2895 if (isResize || window->d_func()->resizeEventPending) {
2896 QResizeEvent e(actualGeometry.size(), lastReportedGeometry.size());
2897 QGuiApplication::sendSpontaneousEvent(window, &e);
2898
2899 window->d_func()->resizeEventPending = false;
2900
2901 if (actualGeometry.width() != lastReportedGeometry.width())
2902 emit window->widthChanged(actualGeometry.width());
2903 if (actualGeometry.height() != lastReportedGeometry.height())
2904 emit window->heightChanged(actualGeometry.height());
2905 }
2906
2907 if (isMove) {
2908 //### frame geometry
2909 QMoveEvent e(actualGeometry.topLeft(), lastReportedGeometry.topLeft());
2910 QGuiApplication::sendSpontaneousEvent(window, &e);
2911
2912 if (actualGeometry.x() != lastReportedGeometry.x())
2913 emit window->xChanged(actualGeometry.x());
2914 if (actualGeometry.y() != lastReportedGeometry.y())
2915 emit window->yChanged(actualGeometry.y());
2916 }
2917}
2918
2919void QGuiApplicationPrivate::processCloseEvent(QWindowSystemInterfacePrivate::CloseEvent *e)
2920{
2921 if (e->window.isNull())
2922 return;
2923 if (e->window.data()->d_func()->blockedByModalWindow && !e->window.data()->d_func()->inClose) {
2924 // a modal window is blocking this window, don't allow close events through, unless they
2925 // originate from a call to QWindow::close.
2926 e->eventAccepted = false;
2927 return;
2928 }
2929
2930 QCloseEvent event;
2931 QGuiApplication::sendSpontaneousEvent(e->window.data(), &event);
2932
2933 e->eventAccepted = event.isAccepted();
2934}
2935
2936void QGuiApplicationPrivate::processFileOpenEvent(QWindowSystemInterfacePrivate::FileOpenEvent *e)
2937{
2938 if (e->url.isEmpty())
2939 return;
2940
2941 QFileOpenEvent event(e->url);
2942 QGuiApplication::sendSpontaneousEvent(qApp, &event);
2943}
2944
2945QGuiApplicationPrivate::TabletPointData &QGuiApplicationPrivate::tabletDevicePoint(qint64 deviceId)
2946{
2947 for (int i = 0; i < tabletDevicePoints.size(); ++i) {
2948 TabletPointData &pointData = tabletDevicePoints[i];
2949 if (pointData.deviceId == deviceId)
2950 return pointData;
2951 }
2952
2953 tabletDevicePoints.append(TabletPointData(deviceId));
2954 return tabletDevicePoints.last();
2955}
2956
2957void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::TabletEvent *e)
2958{
2959#if QT_CONFIG(tabletevent)
2960 const auto device = static_cast<const QPointingDevice *>(e->device);
2961 TabletPointData &pointData = tabletDevicePoint(device->uniqueId().numericId());
2962
2963 QEvent::Type type = QEvent::TabletMove;
2964 if (e->buttons != pointData.state)
2965 type = (e->buttons > pointData.state) ? QEvent::TabletPress : QEvent::TabletRelease;
2966
2967 QWindow *window = e->window.data();
2968 modifier_buttons = e->modifiers;
2969
2970 bool localValid = true;
2971 // If window is null, pick one based on the global position and make sure all
2972 // subsequent events up to the release are delivered to that same window.
2973 // If window is given, just send to that.
2974 if (type == QEvent::TabletPress) {
2975 if (e->nullWindow()) {
2976 window = QGuiApplication::topLevelAt(e->global.toPoint());
2977 localValid = false;
2978 }
2979 if (!window)
2980 return;
2981 active_popup_on_press = activePopupWindow();
2982 pointData.target = window;
2983 } else {
2984 if (e->nullWindow()) {
2985 window = pointData.target;
2986 localValid = false;
2987 }
2988 if (type == QEvent::TabletRelease)
2989 pointData.target = nullptr;
2990 if (!window)
2991 return;
2992 }
2993 QPointF local = e->local;
2994 if (!localValid) {
2995 QPointF delta = e->global - e->global.toPoint();
2996 local = window->mapFromGlobal(e->global.toPoint()) + delta;
2997 }
2998
2999 // TODO stop deducing the button state change here: rather require it from the platform plugin, as with mouse events
3000 Qt::MouseButtons stateChange = e->buttons ^ pointData.state;
3001 Qt::MouseButton button = Qt::NoButton;
3002 for (int check = Qt::LeftButton; check <= int(Qt::MaxMouseButton); check = check << 1) {
3003 if (check & stateChange) {
3004 button = Qt::MouseButton(check);
3005 break;
3006 }
3007 }
3008
3009 const auto *activePopup = activePopupWindow();
3010 if (window->d_func()->blockedByModalWindow && !activePopup) {
3011 // a modal window is blocking this window, don't allow events through
3012 return;
3013 }
3014
3015 QTabletEvent tabletEvent(type, device, local, e->global,
3016 e->pressure, e->xTilt, e->yTilt,
3017 e->tangentialPressure, e->rotation, e->z,
3018 e->modifiers, button, e->buttons);
3019 tabletEvent.setAccepted(false);
3020 tabletEvent.setTimestamp(e->timestamp);
3021
3022 if (activePopup && activePopup != window) {
3023 // If the popup handles the event, we're done.
3024 if (window->d_func()->forwardToPopup(&tabletEvent, active_popup_on_press))
3025 return;
3026 }
3027
3028 QGuiApplication::sendSpontaneousEvent(window, &tabletEvent);
3029 pointData.state = e->buttons;
3030 if (!tabletEvent.isAccepted()
3031 && !QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse
3032 && qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents)) {
3033
3034 const QEvent::Type mouseType = [&]() {
3035 switch (type) {
3036 case QEvent::TabletPress: return QEvent::MouseButtonPress;
3037 case QEvent::TabletMove: return QEvent::MouseMove;
3038 case QEvent::TabletRelease: return QEvent::MouseButtonRelease;
3039 default: Q_UNREACHABLE();
3040 }
3041 }();
3042 QWindowSystemInterfacePrivate::MouseEvent mouseEvent(window, e->timestamp, e->local,
3043 e->global, e->buttons, e->modifiers, button, mouseType, Qt::MouseEventNotSynthesized, false, device);
3044 mouseEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
3045 qCDebug(lcPtrDispatch) << "synthesizing mouse from tablet event" << mouseType
3046 << e->local << button << e->buttons << e->modifiers;
3047 processMouseEvent(&mouseEvent);
3048 }
3049#else
3050 Q_UNUSED(e);
3051#endif
3052}
3053
3054void QGuiApplicationPrivate::processTabletEnterProximityEvent(QWindowSystemInterfacePrivate::TabletEnterProximityEvent *e)
3055{
3056#if QT_CONFIG(tabletevent)
3057 const QPointingDevice *dev = static_cast<const QPointingDevice *>(e->device);
3058 QTabletEvent ev(QEvent::TabletEnterProximity, dev, e->local, e->global,
3059 e->pressure, e->xTilt, e->yTilt,
3060 e->tangentialPressure, e->rotation, e->z,
3061 e->modifiers, Qt::NoButton,
3062 tabletDevicePoint(dev->uniqueId().numericId()).state);
3063 ev.setTimestamp(e->timestamp);
3064 QGuiApplication::sendSpontaneousEvent(qGuiApp, &ev);
3065#else
3066 Q_UNUSED(e);
3067#endif
3068}
3069
3070void QGuiApplicationPrivate::processTabletLeaveProximityEvent(QWindowSystemInterfacePrivate::TabletLeaveProximityEvent *e)
3071{
3072#if QT_CONFIG(tabletevent)
3073 const QPointingDevice *dev = static_cast<const QPointingDevice *>(e->device);
3074 QTabletEvent ev(QEvent::TabletLeaveProximity, dev, e->local, e->global,
3075 e->pressure, e->xTilt, e->yTilt,
3076 e->tangentialPressure, e->rotation, e->z,
3077 e->modifiers, Qt::NoButton,
3078 tabletDevicePoint(dev->uniqueId().numericId()).state);
3079 ev.setTimestamp(e->timestamp);
3080 QGuiApplication::sendSpontaneousEvent(qGuiApp, &ev);
3081#else
3082 Q_UNUSED(e);
3083#endif
3084}
3085
3086#ifndef QT_NO_GESTURES
3087void QGuiApplicationPrivate::processGestureEvent(QWindowSystemInterfacePrivate::GestureEvent *e)
3088{
3089 if (e->window.isNull())
3090 return;
3091
3092 const QPointingDevice *device = static_cast<const QPointingDevice *>(e->device);
3093 QNativeGestureEvent ev(e->type, device, e->fingerCount, e->pos, e->pos, e->globalPos, (e->intValue ? e->intValue : e->realValue),
3094 e->delta, e->sequenceId);
3095 ev.setTimestamp(e->timestamp);
3096 QGuiApplication::sendSpontaneousEvent(e->window, &ev);
3097}
3098#endif // QT_NO_GESTURES
3099
3100void QGuiApplicationPrivate::processPlatformPanelEvent(QWindowSystemInterfacePrivate::PlatformPanelEvent *e)
3101{
3102 if (!e->window)
3103 return;
3104
3105 if (e->window->d_func()->blockedByModalWindow) {
3106 // a modal window is blocking this window, don't allow events through
3107 return;
3108 }
3109
3110 QEvent ev(QEvent::PlatformPanel);
3111 QGuiApplication::sendSpontaneousEvent(e->window.data(), &ev);
3112}
3113
3114#ifndef QT_NO_CONTEXTMENU
3115void QGuiApplicationPrivate::processContextMenuEvent(QWindowSystemInterfacePrivate::ContextMenuEvent *e)
3116{
3117 // Widgets do not care about mouse triggered context menu events. Also, do not forward event
3118 // to a window blocked by a modal window.
3119 if (!e->window || e->mouseTriggered || e->window->d_func()->blockedByModalWindow)
3120 return;
3121
3122 QContextMenuEvent ev(QContextMenuEvent::Keyboard, e->pos, e->globalPos, e->modifiers);
3123 QGuiApplication::sendSpontaneousEvent(e->window.data(), &ev);
3124 e->eventAccepted = ev.isAccepted();
3125}
3126#endif
3127
3128void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::TouchEvent *e)
3129{
3130 if (!QInputDevicePrivate::isRegistered(e->device))
3131 return;
3132
3133 modifier_buttons = e->modifiers;
3134 QPointingDevice *device = const_cast<QPointingDevice *>(static_cast<const QPointingDevice *>(e->device));
3135 QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(device);
3136
3137 auto *guiAppPrivate = QGuiApplicationPrivate::instance();
3138
3139 if (e->touchType == QEvent::TouchCancel) {
3140 // The touch sequence has been canceled (e.g. by the compositor).
3141 // Send the TouchCancel to all windows with active touches and clean up.
3142 QTouchEvent touchEvent(QEvent::TouchCancel, device, e->modifiers);
3143 touchEvent.setTimestamp(e->timestamp);
3144 constexpr qsizetype Prealloc = decltype(devPriv->activePoints)::mapped_container_type::PreallocatedSize;
3145 QMinimalVarLengthFlatSet<QWindow *, Prealloc> windowsNeedingCancel;
3146
3147 for (auto &epd : devPriv->activePoints.values()) {
3148 if (QWindow *w = QMutableEventPoint::window(epd.eventPoint))
3149 windowsNeedingCancel.insert(w);
3150 }
3151
3152 for (QWindow *w : windowsNeedingCancel)
3153 QGuiApplication::sendSpontaneousEvent(w, &touchEvent);
3154
3155 if (!guiAppPrivate->synthesizedMousePoints.isEmpty() && !e->synthetic()) {
3156 for (QHash<QWindow *, SynthesizedMouseData>::const_iterator synthIt = guiAppPrivate->synthesizedMousePoints.constBegin(),
3157 synthItEnd = guiAppPrivate->synthesizedMousePoints.constEnd(); synthIt != synthItEnd; ++synthIt) {
3158 if (!synthIt->window)
3159 continue;
3160 QWindowSystemInterfacePrivate::MouseEvent fake(synthIt->window.data(),
3161 e->timestamp,
3162 synthIt->pos,
3163 synthIt->screenPos,
3164 Qt::NoButton,
3165 e->modifiers,
3166 Qt::LeftButton,
3167 QEvent::MouseButtonRelease,
3168 Qt::MouseEventNotSynthesized,
3169 false,
3170 device);
3171 fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
3172 processMouseEvent(&fake);
3173 }
3174 guiAppPrivate->synthesizedMousePoints.clear();
3175 }
3176 guiAppPrivate->lastTouchType = e->touchType;
3177 return;
3178 }
3179
3180 // Prevent sending ill-formed event sequences: Cancel can only be followed by a Begin.
3181 if (guiAppPrivate->lastTouchType == QEvent::TouchCancel && e->touchType != QEvent::TouchBegin)
3182 return;
3183
3184 guiAppPrivate->lastTouchType = e->touchType;
3185
3186 QPointer<QWindow> window = e->window; // the platform hopefully tells us which window received the event
3187 QVarLengthArray<QMutableTouchEvent, 2> touchEvents;
3188
3189 // For each temporary QEventPoint from the QPA TouchEvent:
3190 // - update the persistent QEventPoint in QPointingDevicePrivate::activePoints with current values
3191 // - determine which window to deliver it to
3192 // - add it to the QTouchEvent instance for that window (QMutableTouchEvent::target() will be QWindow*, for now)
3193 for (auto &tempPt : e->points) {
3194 // update state
3195 auto epd = devPriv->pointById(tempPt.id());
3196 auto &ep = epd->eventPoint;
3197 epd->eventPoint.setAccepted(false);
3198 switch (tempPt.state()) {
3199 case QEventPoint::State::Pressed:
3200 // On touchpads, send all touch points to the same window.
3201 if (!window && e->device && e->device->type() == QInputDevice::DeviceType::TouchPad)
3202 window = devPriv->firstActiveWindow();
3203 // If the QPA event didn't tell us which window, find the one under the touchpoint position.
3204 if (!window)
3205 window = QGuiApplication::topLevelAt(tempPt.globalPosition().toPoint());
3206 QMutableEventPoint::setWindow(ep, window);
3207 active_popup_on_press = activePopupWindow();
3208 break;
3209
3210 case QEventPoint::State::Released:
3211 if (Q_UNLIKELY(!window.isNull() && window != QMutableEventPoint::window(ep)))
3212 qCDebug(lcPtrDispatch) << "delivering touch release to same window"
3213 << QMutableEventPoint::window(ep) << "not" << window.data();
3214 window = QMutableEventPoint::window(ep);
3215 break;
3216
3217 default: // update or stationary
3218 if (Q_UNLIKELY(!window.isNull() && window != QMutableEventPoint::window(ep)))
3219 qCDebug(lcPtrDispatch) << "delivering touch update to same window"
3220 << QMutableEventPoint::window(ep) << "not" << window.data();
3221 window = QMutableEventPoint::window(ep);
3222 break;
3223 }
3224 // If we somehow still don't have a window, we can't deliver this touchpoint. (should never happen)
3225 if (Q_UNLIKELY(!window)) {
3226 qCDebug(lcPtrDispatch) << "skipping" << &tempPt << ": no target window";
3227 continue;
3228 }
3229 QMutableEventPoint::update(tempPt, ep);
3230
3231 Q_ASSERT(window.data() != nullptr);
3232
3233 // make the *scene* position the same as the *global* position
3234 QMutableEventPoint::setScenePosition(ep, tempPt.globalPosition());
3235
3236 // store the scene position as local position, for now
3237 QMutableEventPoint::setPosition(ep, window->mapFromGlobal(tempPt.globalPosition()));
3238
3239 // setTimeStamp has side effects, so we do it last
3240 QMutableEventPoint::setTimestamp(ep, e->timestamp);
3241
3242 // add the touchpoint to the event that will be delivered to the window
3243 bool added = false;
3244 for (QMutableTouchEvent &ev : touchEvents) {
3245 if (ev.target() == window.data()) {
3246 ev.addPoint(ep);
3247 added = true;
3248 break;
3249 }
3250 }
3251 if (!added) {
3252 QMutableTouchEvent mte(e->touchType, device, e->modifiers, {ep});
3253 mte.setTimestamp(e->timestamp);
3254 mte.setTarget(window.data());
3255 touchEvents.append(mte);
3256 }
3257 }
3258
3259 if (touchEvents.isEmpty())
3260 return;
3261
3262 for (QMutableTouchEvent &touchEvent : touchEvents) {
3263 QWindow *window = static_cast<QWindow *>(touchEvent.target());
3264
3265 QEvent::Type eventType;
3266 switch (touchEvent.touchPointStates()) {
3267 case QEventPoint::State::Pressed:
3268 eventType = QEvent::TouchBegin;
3269 break;
3270 case QEventPoint::State::Released:
3271 eventType = QEvent::TouchEnd;
3272 break;
3273 default:
3274 eventType = QEvent::TouchUpdate;
3275 break;
3276 }
3277
3278 const auto *activePopup = activePopupWindow();
3279 if (window->d_func()->blockedByModalWindow && !activePopup) {
3280 // a modal window is blocking this window, don't allow touch events through
3281
3282 // QTBUG-37371 temporary fix; TODO: revisit when we have a forwarding solution
3283 if (touchEvent.type() == QEvent::TouchEnd) {
3284 // but don't leave dangling state: e.g.
3285 // QQuickWindowPrivate::itemForTouchPointId needs to be cleared.
3286 QTouchEvent touchEvent(QEvent::TouchCancel, device, e->modifiers);
3287 touchEvent.setTimestamp(e->timestamp);
3288 QGuiApplication::sendSpontaneousEvent(window, &touchEvent);
3289 }
3290 continue;
3291 }
3292
3293 if (activePopup && activePopup != window) {
3294 // If the popup handles the event, we're done.
3295 if (window->d_func()->forwardToPopup(&touchEvent, active_popup_on_press))
3296 return;
3297 }
3298
3299 // Note: after the call to sendSpontaneousEvent, touchEvent.position() will have
3300 // changed to reflect the local position inside the last (random) widget it tried
3301 // to deliver the touch event to, and will therefore be invalid afterwards.
3302 QGuiApplication::sendSpontaneousEvent(window, &touchEvent);
3303
3304 if (!e->synthetic() && !touchEvent.isAccepted() && qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) {
3305 // exclude devices which generate their own mouse events
3306 if (!(touchEvent.device()->capabilities().testFlag(QInputDevice::Capability::MouseEmulation))) {
3307
3308 QEvent::Type mouseEventType = QEvent::MouseMove;
3309 Qt::MouseButton button = Qt::NoButton;
3310 Qt::MouseButtons buttons = Qt::LeftButton;
3311 if (eventType == QEvent::TouchBegin || m_fakeMouseSourcePointId < 0) {
3312 m_fakeMouseSourcePointId = touchEvent.point(0).id();
3313 qCDebug(lcPtrDispatch) << "synthesizing mouse events from touchpoint" << m_fakeMouseSourcePointId;
3314 }
3315 if (m_fakeMouseSourcePointId >= 0) {
3316 const auto *touchPoint = touchEvent.pointById(m_fakeMouseSourcePointId);
3317 if (touchPoint) {
3318 switch (touchPoint->state()) {
3319 case QEventPoint::State::Pressed:
3320 mouseEventType = QEvent::MouseButtonPress;
3321 button = Qt::LeftButton;
3322 break;
3323 case QEventPoint::State::Released:
3324 mouseEventType = QEvent::MouseButtonRelease;
3325 button = Qt::LeftButton;
3326 buttons = Qt::NoButton;
3327 Q_ASSERT(m_fakeMouseSourcePointId == touchPoint->id());
3328 m_fakeMouseSourcePointId = -1;
3329 break;
3330 default:
3331 break;
3332 }
3333 if (touchPoint->state() != QEventPoint::State::Released) {
3334 guiAppPrivate->synthesizedMousePoints.insert(window, SynthesizedMouseData(
3335 touchPoint->position(), touchPoint->globalPosition(), window));
3336 }
3337 // All touch events that are not accepted by the application will be translated to
3338 // left mouse button events instead (see AA_SynthesizeMouseForUnhandledTouchEvents docs).
3339 // Sending a QPA event (rather than simply sending a QMouseEvent) takes care of
3340 // side-effects such as double-click synthesis.
3341 QWindowSystemInterfacePrivate::MouseEvent fake(window, e->timestamp,
3342 window->mapFromGlobal(touchPoint->globalPosition().toPoint()),
3343 touchPoint->globalPosition(),
3344 buttons,
3345 e->modifiers,
3346 button,
3347 mouseEventType,
3348 Qt::MouseEventSynthesizedByQt,
3349 false,
3350 device,
3351 touchPoint->id());
3352 fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
3353 processMouseEvent(&fake);
3354 }
3355 }
3356 if (eventType == QEvent::TouchEnd)
3357 guiAppPrivate->synthesizedMousePoints.clear();
3358 }
3359 }
3360 }
3361
3362 // Remove released points from QPointingDevicePrivate::activePoints only after the event is
3363 // delivered. Widgets and Qt Quick are allowed to access them at any time before this.
3364 for (const QEventPoint &touchPoint : e->points) {
3365 if (touchPoint.state() == QEventPoint::State::Released)
3366 devPriv->removePointById(touchPoint.id());
3367 }
3368}
3369
3370void QGuiApplicationPrivate::processScreenOrientationChange(QWindowSystemInterfacePrivate::ScreenOrientationEvent *e)
3371{
3372 // This operation only makes sense after the QGuiApplication constructor runs
3373 if (QCoreApplication::startingUp())
3374 return;
3375
3376 if (!e->screen)
3377 return;
3378
3379 QScreen *s = e->screen.data();
3380 s->d_func()->orientation = e->orientation;
3381
3382 emit s->orientationChanged(s->orientation());
3383
3384 QScreenOrientationChangeEvent event(s, s->orientation());
3385 QCoreApplication::sendEvent(QCoreApplication::instance(), &event);
3386}
3387
3388void QGuiApplicationPrivate::processScreenGeometryChange(QWindowSystemInterfacePrivate::ScreenGeometryEvent *e)
3389{
3390 // This operation only makes sense after the QGuiApplication constructor runs
3391 if (QCoreApplication::startingUp())
3392 return;
3393
3394 if (!e->screen)
3395 return;
3396
3397 {
3398 QScreen *s = e->screen.data();
3399 QScreenPrivate::UpdateEmitter updateEmitter(s);
3400
3401 // Note: The incoming geometries have already been scaled by QHighDpi
3402 // in the QWSI layer, so we don't need to call updateGeometry() here.
3403 s->d_func()->geometry = e->geometry;
3404 s->d_func()->availableGeometry = e->availableGeometry;
3405
3406 s->d_func()->updatePrimaryOrientation();
3407 }
3408
3409 resetCachedDevicePixelRatio();
3410}
3411
3412void QGuiApplicationPrivate::processScreenLogicalDotsPerInchChange(QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *e)
3413{
3414 // This operation only makes sense after the QGuiApplication constructor runs
3415 if (QCoreApplication::startingUp())
3416 return;
3417
3418 QHighDpiScaling::updateHighDpiScaling();
3419
3420 if (!e->screen)
3421 return;
3422
3423 {
3424 QScreen *s = e->screen.data();
3425 QScreenPrivate::UpdateEmitter updateEmitter(s);
3426 s->d_func()->logicalDpi = QDpi(e->dpiX, e->dpiY);
3427 s->d_func()->updateGeometry();
3428 }
3429
3430 for (QWindow *window : QGuiApplication::allWindows())
3431 if (window->screen() == e->screen)
3432 QWindowPrivate::get(window)->updateDevicePixelRatio();
3433
3434 resetCachedDevicePixelRatio();
3435}
3436
3437void QGuiApplicationPrivate::processScreenRefreshRateChange(QWindowSystemInterfacePrivate::ScreenRefreshRateEvent *e)
3438{
3439 // This operation only makes sense after the QGuiApplication constructor runs
3440 if (QCoreApplication::startingUp())
3441 return;
3442
3443 if (!e->screen)
3444 return;
3445
3446 QScreen *s = e->screen.data();
3447 qreal rate = e->rate;
3448 // safeguard ourselves against buggy platform behavior...
3449 if (rate < 1.0)
3450 rate = 60.0;
3451 if (!qFuzzyCompare(s->d_func()->refreshRate, rate)) {
3452 s->d_func()->refreshRate = rate;
3453 emit s->refreshRateChanged(s->refreshRate());
3454 }
3455}
3456
3457void QGuiApplicationPrivate::processExposeEvent(QWindowSystemInterfacePrivate::ExposeEvent *e)
3458{
3459 if (!e->window)
3460 return;
3461
3462 QWindow *window = e->window.data();
3463 if (!window)
3464 return;
3465 QWindowPrivate *p = qt_window_private(window);
3466
3467 if (e->isExposed) {
3468 // If the window has been automatically positioned or resized by the
3469 // window manager, we now assume those have taken effect, even for
3470 // asynchronous window managers. From this point on we want the window
3471 // to keep its geometry, even when recreated.
3472 p->positionAutomatic = false;
3473 p->resizeAutomatic = false;
3474 }
3475
3476 if (!p->receivedExpose) {
3477 if (p->resizeEventPending) {
3478 // as a convenience for plugins, send a resize event before the first expose event if they haven't done so
3479 // window->geometry() should have a valid size as soon as a handle exists.
3480 QResizeEvent e(window->geometry().size(), p->geometry.size());
3481 QGuiApplication::sendSpontaneousEvent(window, &e);
3482
3483 p->resizeEventPending = false;
3484 }
3485
3486 // FIXME: It would logically make sense to set this _after_ we've sent the
3487 // expose event to the window, to mark that it now has received an expose.
3488 // But some parts of Qt (mis)use this private member to check whether the
3489 // window has been mapped yet, which they do in code that is triggered
3490 // by the very same expose event we send below. To keep the code working
3491 // we need to set the variable up front, until the code has been fixed.
3492 p->receivedExpose = true;
3493 }
3494
3495 // If the platform does not send paint events we need to synthesize them from expose events
3496 const bool shouldSynthesizePaintEvents = !platformIntegration()->hasCapability(QPlatformIntegration::PaintEvents);
3497
3498 const bool wasExposed = p->exposed;
3499 p->exposed = e->isExposed && window->screen();
3500
3501 // We expect that the platform plugins send DevicePixelRatioChange events.
3502 // As a fail-safe make a final check here to make sure the cached DPR value is
3503 // always up to date before sending the expose event.
3504 if (e->isExposed && !e->region.isEmpty()) {
3505 const bool dprWasChanged = QWindowPrivate::get(window)->updateDevicePixelRatio();
3506 if (dprWasChanged)
3507 qWarning() << "The cached device pixel ratio value was stale on window expose. "
3508 << "Please file a QTBUG which explains how to reproduce.";
3509 }
3510
3511 // We treat expose events for an already exposed window as paint events
3512 if (wasExposed && p->exposed && shouldSynthesizePaintEvents) {
3513 QPaintEvent paintEvent(e->region);
3514 QCoreApplication::sendSpontaneousEvent(window, &paintEvent);
3515 if (paintEvent.isAccepted())
3516 return; // No need to send expose
3517
3518 // The paint event was not accepted, so we fall through and send an expose
3519 // event instead, to maintain compatibility for clients that haven't adopted
3520 // paint events yet.
3521 }
3522
3523 QExposeEvent exposeEvent(e->region);
3524 QCoreApplication::sendSpontaneousEvent(window, &exposeEvent);
3525 e->eventAccepted = exposeEvent.isAccepted();
3526
3527 // If the window was just exposed we also need to send a paint event,
3528 // so that clients that implement paint events will draw something.
3529 // Note that we we can not skip this based on the expose event being
3530 // accepted, as clients may implement exposeEvent to track the state
3531 // change, but without drawing anything.
3532 if (!wasExposed && p->exposed && shouldSynthesizePaintEvents) {
3533 QPaintEvent paintEvent(e->region);
3534 QCoreApplication::sendSpontaneousEvent(window, &paintEvent);
3535 }
3536}
3537
3538void QGuiApplicationPrivate::processPaintEvent(QWindowSystemInterfacePrivate::PaintEvent *e)
3539{
3540 Q_ASSERT_X(platformIntegration()->hasCapability(QPlatformIntegration::PaintEvents), "QGuiApplication",
3541 "The platform sent paint events without claiming support for it in QPlatformIntegration::capabilities()");
3542
3543 if (!e->window)
3544 return;
3545
3546 QPaintEvent paintEvent(e->region);
3547 QCoreApplication::sendSpontaneousEvent(e->window, &paintEvent);
3548
3549 // We report back the accepted state to the platform, so that it can
3550 // decide when the best time to send the fallback expose event is.
3551 e->eventAccepted = paintEvent.isAccepted();
3552}
3553
3554#if QT_CONFIG(draganddrop)
3555
3556/*! \internal
3557
3558 This function updates an internal state to keep the source compatibility.
3559 ### Qt 6 - Won't need after QTBUG-73829
3560*/
3561static void updateMouseAndModifierButtonState(Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
3562{
3563 QGuiApplicationPrivate::mouse_buttons = buttons;
3564 QGuiApplicationPrivate::modifier_buttons = modifiers;
3565}
3566
3567QPlatformDragQtResponse QGuiApplicationPrivate::processDrag(QWindow *w, const QMimeData *dropData,
3568 const QPoint &p, Qt::DropActions supportedActions,
3569 Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
3570{
3571 updateMouseAndModifierButtonState(buttons, modifiers);
3572
3573 static Qt::DropAction lastAcceptedDropAction = Qt::IgnoreAction;
3574 QPlatformDrag *platformDrag = platformIntegration()->drag();
3575 if (!platformDrag || (w && w->d_func()->blockedByModalWindow)) {
3576 lastAcceptedDropAction = Qt::IgnoreAction;
3577 return QPlatformDragQtResponse(false, lastAcceptedDropAction, QRect());
3578 }
3579
3580 if (!dropData) {
3581 currentDragWindow = nullptr;
3582 QDragLeaveEvent e;
3583 QGuiApplication::sendEvent(w, &e);
3584 lastAcceptedDropAction = Qt::IgnoreAction;
3585 return QPlatformDragQtResponse(false, lastAcceptedDropAction, QRect());
3586 }
3587 QDragMoveEvent me(QPointF(p), supportedActions, dropData, buttons, modifiers);
3588
3589 if (w != currentDragWindow) {
3590 lastAcceptedDropAction = Qt::IgnoreAction;
3591 if (currentDragWindow) {
3592 QDragLeaveEvent e;
3593 QGuiApplication::sendEvent(currentDragWindow, &e);
3594 }
3595 currentDragWindow = w;
3596 QDragEnterEvent e(QPointF(p), supportedActions, dropData, buttons, modifiers);
3597 QGuiApplication::sendEvent(w, &e);
3598 if (e.isAccepted() && e.dropAction() != Qt::IgnoreAction)
3599 lastAcceptedDropAction = e.dropAction();
3600 }
3601
3602 // Handling 'DragEnter' should suffice for the application.
3603 if (lastAcceptedDropAction != Qt::IgnoreAction
3604 && (supportedActions & lastAcceptedDropAction)) {
3605 me.setDropAction(lastAcceptedDropAction);
3606 me.accept();
3607 }
3608 QGuiApplication::sendEvent(w, &me);
3609 lastAcceptedDropAction = me.isAccepted() ?
3610 me.dropAction() : Qt::IgnoreAction;
3611 return QPlatformDragQtResponse(me.isAccepted(), lastAcceptedDropAction, me.answerRect());
3612}
3613
3614QPlatformDropQtResponse QGuiApplicationPrivate::processDrop(QWindow *w, const QMimeData *dropData,
3615 const QPoint &p, Qt::DropActions supportedActions,
3616 Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
3617{
3618 updateMouseAndModifierButtonState(buttons, modifiers);
3619
3620 currentDragWindow = nullptr;
3621
3622 QDropEvent de(p, supportedActions, dropData, buttons, modifiers);
3623 QGuiApplication::sendEvent(w, &de);
3624
3625 Qt::DropAction acceptedAction = de.isAccepted() ? de.dropAction() : Qt::IgnoreAction;
3626 QPlatformDropQtResponse response(de.isAccepted(),acceptedAction);
3627 return response;
3628}
3629
3630#endif // QT_CONFIG(draganddrop)
3631
3632#ifndef QT_NO_CLIPBOARD
3633/*!
3634 Returns the object for interacting with the clipboard.
3635*/
3636QClipboard * QGuiApplication::clipboard()
3637{
3638 if (QGuiApplicationPrivate::qt_clipboard == nullptr) {
3639 if (!qApp) {
3640 qWarning("QGuiApplication: Must construct a QGuiApplication before accessing a QClipboard");
3641 return nullptr;
3642 }
3643 QGuiApplicationPrivate::qt_clipboard = new QClipboard(nullptr);
3644 }
3645 return QGuiApplicationPrivate::qt_clipboard;
3646}
3647#endif
3648
3649/*!
3650 \since 5.4
3651 \fn void QGuiApplication::paletteChanged(const QPalette &palette)
3652 \deprecated [6.0] Handle QEvent::ApplicationPaletteChange instead.
3653
3654 This signal is emitted when the \a palette of the application changes. Use
3655 QEvent::ApplicationPaletteChanged instead.
3656
3657 \sa palette()
3658*/
3659
3660/*!
3661 Returns the current application palette.
3662
3663 Roles that have not been explicitly set will reflect the system's platform theme.
3664
3665 \sa setPalette()
3666*/
3667
3668QPalette QGuiApplication::palette()
3669{
3670 if (!QGuiApplicationPrivate::app_pal)
3671 QGuiApplicationPrivate::updatePalette();
3672
3673 return *QGuiApplicationPrivate::app_pal;
3674}
3675
3676void QGuiApplicationPrivate::updatePalette()
3677{
3678 if (app_pal) {
3679 if (setPalette(*app_pal) && qGuiApp)
3680 qGuiApp->d_func()->handlePaletteChanged();
3681 } else {
3682 setPalette(QPalette());
3683 }
3684}
3685
3686QEvent::Type QGuiApplicationPrivate::contextMenuEventType()
3687{
3688 switch (QGuiApplication::styleHints()->contextMenuTrigger()) {
3689 case Qt::ContextMenuTrigger::Press: return QEvent::MouseButtonPress;
3690 case Qt::ContextMenuTrigger::Release: return QEvent::MouseButtonRelease;
3691 }
3692 return QEvent::None;
3693}
3694
3695void QGuiApplicationPrivate::clearPalette()
3696{
3697 delete app_pal;
3698 app_pal = nullptr;
3699}
3700
3701/*!
3702 Changes the application palette to \a pal.
3703
3704 The color roles from this palette are combined with the system's platform
3705 theme to form the application's final palette.
3706
3707 \sa palette()
3708*/
3709void QGuiApplication::setPalette(const QPalette &pal)
3710{
3711 if (QGuiApplicationPrivate::setPalette(pal) && qGuiApp)
3712 qGuiApp->d_func()->handlePaletteChanged();
3713}
3714
3715bool QGuiApplicationPrivate::setPalette(const QPalette &palette)
3716{
3717 // Resolve the palette against the theme palette, filling in
3718 // any missing roles, while keeping the original resolve mask.
3719 QPalette basePalette = qGuiApp ? qGuiApp->d_func()->basePalette() : Qt::gray;
3720 basePalette.setResolveMask(0); // The base palette only contributes missing colors roles
3721 QPalette resolvedPalette = palette.resolve(basePalette);
3722
3723 if (app_pal && resolvedPalette == *app_pal && resolvedPalette.resolveMask() == app_pal->resolveMask())
3724 return false;
3725
3726 if (!app_pal)
3727 app_pal = new QPalette(resolvedPalette);
3728 else
3729 *app_pal = resolvedPalette;
3730
3731 QCoreApplication::setAttribute(Qt::AA_SetPalette, app_pal->resolveMask() != 0);
3732
3733 return true;
3734}
3735
3736/*
3737 Returns the base palette used to fill in missing roles in
3738 the current application palette.
3739
3740 Normally this is the theme palette, but QApplication
3741 overrides this for compatibility reasons.
3742*/
3743QPalette QGuiApplicationPrivate::basePalette() const
3744{
3745 const auto pf = platformTheme();
3746 return pf && pf->palette() ? *pf->palette() : Qt::gray;
3747}
3748
3749void QGuiApplicationPrivate::handlePaletteChanged(const char *className)
3750{
3751#if QT_DEPRECATED_SINCE(6, 0)
3752 if (!className) {
3753 Q_ASSERT(app_pal);
3754QT_WARNING_PUSH
3755QT_WARNING_DISABLE_DEPRECATED
3756 emit qGuiApp->paletteChanged(*QGuiApplicationPrivate::app_pal);
3757QT_WARNING_POP
3758 }
3759#else
3760 Q_UNUSED(className);
3761#endif // QT_DEPRECATED_SINCE(6, 0)
3762
3763 if (is_app_running && !is_app_closing) {
3764 QEvent event(QEvent::ApplicationPaletteChange);
3765 QGuiApplication::sendEvent(qGuiApp, &event);
3766 }
3767}
3768
3769void QGuiApplicationPrivate::applyWindowGeometrySpecificationTo(QWindow *window)
3770{
3771 windowGeometrySpecification.applyTo(window);
3772}
3773
3774/*!
3775 \since 5.11
3776 \fn void QGuiApplication::fontChanged(const QFont &font)
3777 \deprecated [6.0] Handle QEvent::ApplicationFontChange instead.
3778
3779 This signal is emitted when the \a font of the application changes. Use
3780 QEvent::ApplicationFontChanged instead.
3781
3782 \sa font()
3783*/
3784
3785/*!
3786 Returns the default application font.
3787
3788 \sa setFont()
3789*/
3790QFont QGuiApplication::font()
3791{
3792 const auto locker = qt_scoped_lock(applicationFontMutex);
3793 if (!QGuiApplicationPrivate::instance() && !QGuiApplicationPrivate::app_font) {
3794 qWarning("QGuiApplication::font(): no QGuiApplication instance and no application font set.");
3795 return QFont(); // in effect: QFont((QFontPrivate*)nullptr), so no recursion
3796 }
3797 initFontUnlocked();
3798 return *QGuiApplicationPrivate::app_font;
3799}
3800
3801/*!
3802 Changes the default application font to \a font.
3803
3804 \sa font()
3805*/
3806void QGuiApplication::setFont(const QFont &font)
3807{
3808 auto locker = qt_unique_lock(applicationFontMutex);
3809 const bool emitChange = !QGuiApplicationPrivate::app_font
3810 || (*QGuiApplicationPrivate::app_font != font);
3811 if (!QGuiApplicationPrivate::app_font)
3812 QGuiApplicationPrivate::app_font = new QFont(font);
3813 else
3814 *QGuiApplicationPrivate::app_font = font;
3815 applicationResourceFlags |= ApplicationFontExplicitlySet;
3816
3817 if (emitChange && qGuiApp) {
3818 auto font = *QGuiApplicationPrivate::app_font;
3819 locker.unlock();
3820#if QT_DEPRECATED_SINCE(6, 0)
3821QT_WARNING_PUSH
3822QT_WARNING_DISABLE_DEPRECATED
3823 emit qGuiApp->fontChanged(font);
3824QT_WARNING_POP
3825#else
3826 Q_UNUSED(font);
3827#endif // QT_DEPRECATED_SINCE(6, 0)
3828 QEvent event(QEvent::ApplicationFontChange);
3829 QGuiApplication::sendEvent(qGuiApp, &event);
3830 }
3831}
3832
3833/*!
3834 \fn bool QGuiApplication::isRightToLeft()
3835
3836 Returns \c true if the application's layout direction is
3837 Qt::RightToLeft; otherwise returns \c false.
3838
3839 \sa layoutDirection(), isLeftToRight()
3840*/
3841
3842/*!
3843 \fn bool QGuiApplication::isLeftToRight()
3844
3845 Returns \c true if the application's layout direction is
3846 Qt::LeftToRight; otherwise returns \c false.
3847
3848 \sa layoutDirection(), isRightToLeft()
3849*/
3850
3851void QGuiApplicationPrivate::notifyLayoutDirectionChange()
3852{
3853 const QWindowList list = QGuiApplication::topLevelWindows();
3854 for (int i = 0; i < list.size(); ++i) {
3855 QEvent ev(QEvent::ApplicationLayoutDirectionChange);
3856 QCoreApplication::sendEvent(list.at(i), &ev);
3857 }
3858}
3859
3860void QGuiApplicationPrivate::notifyActiveWindowChange(QWindow *prev)
3861{
3862 if (prev) {
3863 QEvent de(QEvent::WindowDeactivate);
3864 QCoreApplication::sendEvent(prev, &de);
3865 }
3866 if (QGuiApplicationPrivate::instance()->focus_window) {
3867 QEvent ae(QEvent::WindowActivate);
3868 QCoreApplication::sendEvent(focus_window, &ae);
3869 }
3870}
3871
3872/*!
3873 \property QGuiApplication::windowIcon
3874 \brief the default window icon
3875
3876 \sa QWindow::setIcon(), {Setting the Application Icon}
3877*/
3878QIcon QGuiApplication::windowIcon()
3879{
3880 return QGuiApplicationPrivate::app_icon ? *QGuiApplicationPrivate::app_icon : QIcon();
3881}
3882
3883void QGuiApplication::setWindowIcon(const QIcon &icon)
3884{
3885 if (!QGuiApplicationPrivate::app_icon)
3886 QGuiApplicationPrivate::app_icon = new QIcon();
3887 *QGuiApplicationPrivate::app_icon = icon;
3888 if (QGuiApplicationPrivate::platform_integration
3889 && QGuiApplicationPrivate::platform_integration->hasCapability(QPlatformIntegration::ApplicationIcon))
3890 QGuiApplicationPrivate::platform_integration->setApplicationIcon(icon);
3891 if (QGuiApplicationPrivate::is_app_running && !QGuiApplicationPrivate::is_app_closing)
3892 QGuiApplicationPrivate::instance()->notifyWindowIconChanged();
3893}
3894
3895void QGuiApplicationPrivate::notifyWindowIconChanged()
3896{
3897 QEvent ev(QEvent::ApplicationWindowIconChange);
3898 const QWindowList list = QGuiApplication::topLevelWindows();
3899 for (int i = 0; i < list.size(); ++i)
3900 QCoreApplication::sendEvent(list.at(i), &ev);
3901}
3902
3903
3904
3905/*!
3906 \property QGuiApplication::quitOnLastWindowClosed
3907
3908 \brief whether the application implicitly quits when the last window is
3909 closed.
3910
3911 The default is \c true.
3912
3913 If this property is \c true, the application will attempt to
3914 quit when the last visible \l{Primary and Secondary Windows}{primary window}
3915 (i.e. top level window with no transient parent) is closed.
3916
3917 Note that attempting a quit may not necessarily result in the
3918 application quitting, for example if there still are active
3919 QEventLoopLocker instances, or the QEvent::Quit event is ignored.
3920
3921 \sa quit(), QWindow::close()
3922 */
3923
3924void QGuiApplication::setQuitOnLastWindowClosed(bool quit)
3925{
3926 QGuiApplicationPrivate::quitOnLastWindowClosed = quit;
3927}
3928
3929bool QGuiApplication::quitOnLastWindowClosed()
3930{
3931 return QGuiApplicationPrivate::quitOnLastWindowClosed;
3932}
3933
3934void QGuiApplicationPrivate::maybeLastWindowClosed()
3935{
3936 if (!lastWindowClosed())
3937 return;
3938
3939 if (in_exec)
3940 emit q_func()->lastWindowClosed();
3941
3942 if (quitOnLastWindowClosed && canQuitAutomatically())
3943 quitAutomatically();
3944}
3945
3946/*!
3947 \fn void QGuiApplication::lastWindowClosed()
3948
3949 This signal is emitted from exec() when the last visible
3950 \l{Primary and Secondary Windows}{primary window} (i.e.
3951 top level window with no transient parent) is closed.
3952
3953 By default, QGuiApplication quits after this signal is emitted. This feature
3954 can be turned off by setting \l quitOnLastWindowClosed to \c false.
3955
3956 \sa QWindow::close(), QWindow::isTopLevel(), QWindow::transientParent()
3957*/
3958
3959bool QGuiApplicationPrivate::lastWindowClosed() const
3960{
3961 for (auto *window : QGuiApplication::topLevelWindows()) {
3962 auto *windowPrivate = qt_window_private(window);
3963 if (!windowPrivate->participatesInLastWindowClosed())
3964 continue;
3965
3966 if (windowPrivate->treatAsVisible())
3967 return false;
3968 }
3969
3970 return true;
3971}
3972
3973bool QGuiApplicationPrivate::canQuitAutomatically()
3974{
3975 // The automatic quit functionality is triggered by
3976 // both QEventLoopLocker and maybeLastWindowClosed.
3977 // Although the former is a QCoreApplication feature
3978 // we don't want to quit the application when there
3979 // are open windows, regardless of whether the app
3980 // also quits automatically on maybeLastWindowClosed.
3981 if (!lastWindowClosed())
3982 return false;
3983
3984 return QCoreApplicationPrivate::canQuitAutomatically();
3985}
3986
3987void QGuiApplicationPrivate::quit()
3988{
3989 if (auto *platformIntegration = QGuiApplicationPrivate::platformIntegration())
3990 platformIntegration->quit();
3991 else
3992 QCoreApplicationPrivate::quit();
3993}
3994
3995void QGuiApplicationPrivate::processApplicationTermination(QWindowSystemInterfacePrivate::WindowSystemEvent *windowSystemEvent)
3996{
3997 QEvent event(QEvent::Quit);
3998 QGuiApplication::sendSpontaneousEvent(QGuiApplication::instance(), &event);
3999 windowSystemEvent->eventAccepted = event.isAccepted();
4000}
4001
4002/*!
4003 \since 5.2
4004 \fn Qt::ApplicationState QGuiApplication::applicationState()
4005
4006
4007 Returns the current state of the application.
4008
4009 You can react to application state changes to perform actions such as
4010 stopping/resuming CPU-intensive tasks, freeing/loading resources or
4011 saving/restoring application data.
4012 */
4013
4014Qt::ApplicationState QGuiApplication::applicationState()
4015{
4016 return QGuiApplicationPrivate::applicationState;
4017}
4018
4019/*!
4020 \since 5.14
4021
4022 Sets the high-DPI scale factor rounding policy for the application. The
4023 \a policy decides how non-integer scale factors (such as Windows 150%) are
4024 handled.
4025
4026 The two principal options are whether fractional scale factors should
4027 be rounded to an integer or not. Keeping the scale factor as-is will
4028 make the user interface size match the OS setting exactly, but may cause
4029 painting errors, for example with the Windows style.
4030
4031 If rounding is wanted, then which type of rounding should be decided
4032 next. Mathematically correct rounding is supported but may not give
4033 the best visual results: Consider if you want to render 1.5x as 1x
4034 ("small UI") or as 2x ("large UI"). See the Qt::HighDpiScaleFactorRoundingPolicy
4035 enum for a complete list of all options.
4036
4037 This function must be called before creating the application object.
4038 The QGuiApplication::highDpiScaleFactorRoundingPolicy()
4039 accessor will reflect the environment, if set.
4040
4041 The default value is Qt::HighDpiScaleFactorRoundingPolicy::PassThrough.
4042*/
4043void QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy policy)
4044{
4045 if (qApp)
4046 qWarning("setHighDpiScaleFactorRoundingPolicy must be called before creating the QGuiApplication instance");
4047 QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy = policy;
4048}
4049
4050/*!
4051 \since 5.14
4052
4053 Returns the high-DPI scale factor rounding policy.
4054*/
4055Qt::HighDpiScaleFactorRoundingPolicy QGuiApplication::highDpiScaleFactorRoundingPolicy()
4056{
4057 return QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy;
4058}
4059
4060/*!
4061 \since 5.2
4062 \fn void QGuiApplication::applicationStateChanged(Qt::ApplicationState state)
4063
4064 This signal is emitted when the \a state of the application changes.
4065
4066 \sa applicationState()
4067*/
4068
4069void QGuiApplicationPrivate::setApplicationState(Qt::ApplicationState state, bool forcePropagate)
4070{
4071 if ((applicationState == state) && !forcePropagate)
4072 return;
4073
4074 applicationState = state;
4075
4076 switch (state) {
4077 case Qt::ApplicationActive: {
4078 QEvent appActivate(QEvent::ApplicationActivate);
4079 QCoreApplication::sendSpontaneousEvent(qApp, &appActivate);
4080 break; }
4081 case Qt::ApplicationInactive: {
4082 QEvent appDeactivate(QEvent::ApplicationDeactivate);
4083 QCoreApplication::sendSpontaneousEvent(qApp, &appDeactivate);
4084 break; }
4085 default:
4086 break;
4087 }
4088
4089 QApplicationStateChangeEvent event(applicationState);
4090 QCoreApplication::sendSpontaneousEvent(qApp, &event);
4091
4092 emit qApp->applicationStateChanged(applicationState);
4093}
4094
4095/*!
4096 \since 4.2
4097 \fn void QGuiApplication::commitDataRequest(QSessionManager &manager)
4098
4099 This signal deals with \l{Session Management}{session management}. It is
4100 emitted when the QSessionManager wants the application to commit all its
4101 data.
4102
4103 Usually this means saving all open files, after getting permission from
4104 the user. Furthermore you may want to provide a means by which the user
4105 can cancel the shutdown.
4106
4107 You should not exit the application within this signal. Instead,
4108 the session manager may or may not do this afterwards, depending on the
4109 context.
4110
4111 \warning Within this signal, no user interaction is possible, \e
4112 unless you ask the \a manager for explicit permission. See
4113 QSessionManager::allowsInteraction() and
4114 QSessionManager::allowsErrorInteraction() for details and example
4115 usage.
4116
4117 \note You should use Qt::DirectConnection when connecting to this signal.
4118
4119 \sa isSessionRestored(), sessionId(), saveStateRequest(), {Session Management}
4120*/
4121
4122/*!
4123 \since 4.2
4124 \fn void QGuiApplication::saveStateRequest(QSessionManager &manager)
4125
4126 This signal deals with \l{Session Management}{session management}. It is
4127 invoked when the \l{QSessionManager}{session manager} wants the application
4128 to preserve its state for a future session.
4129
4130 For example, a text editor would create a temporary file that includes the
4131 current contents of its edit buffers, the location of the cursor and other
4132 aspects of the current editing session.
4133
4134 You should never exit the application within this signal. Instead, the
4135 session manager may or may not do this afterwards, depending on the
4136 context. Furthermore, most session managers will very likely request a saved
4137 state immediately after the application has been started. This permits the
4138 session manager to learn about the application's restart policy.
4139
4140 \warning Within this signal, no user interaction is possible, \e
4141 unless you ask the \a manager for explicit permission. See
4142 QSessionManager::allowsInteraction() and
4143 QSessionManager::allowsErrorInteraction() for details.
4144
4145 \note You should use Qt::DirectConnection when connecting to this signal.
4146
4147 \sa isSessionRestored(), sessionId(), commitDataRequest(), {Session Management}
4148*/
4149
4150/*!
4151 \fn bool QGuiApplication::isSessionRestored() const
4152
4153 Returns \c true if the application has been restored from an earlier
4154 \l{Session Management}{session}; otherwise returns \c false.
4155
4156 \sa sessionId(), commitDataRequest(), saveStateRequest()
4157*/
4158
4159/*!
4160 \since 5.0
4161 \fn bool QGuiApplication::isSavingSession() const
4162
4163 Returns \c true if the application is currently saving the
4164 \l{Session Management}{session}; otherwise returns \c false.
4165
4166 This is \c true when commitDataRequest() and saveStateRequest() are emitted,
4167 but also when the windows are closed afterwards by session management.
4168
4169 \sa sessionId(), commitDataRequest(), saveStateRequest()
4170*/
4171
4172/*!
4173 \fn QString QGuiApplication::sessionId() const
4174
4175 Returns the current \l{Session Management}{session's} identifier.
4176
4177 If the application has been restored from an earlier session, this
4178 identifier is the same as it was in that previous session. The session
4179 identifier is guaranteed to be unique both for different applications
4180 and for different instances of the same application.
4181
4182 \sa isSessionRestored(), sessionKey(), commitDataRequest(), saveStateRequest()
4183*/
4184
4185/*!
4186 \fn QString QGuiApplication::sessionKey() const
4187
4188 Returns the session key in the current \l{Session Management}{session}.
4189
4190 If the application has been restored from an earlier session, this key is
4191 the same as it was when the previous session ended.
4192
4193 The session key changes every time the session is saved. If the shutdown process
4194 is cancelled, another session key will be used when shutting down again.
4195
4196 \sa isSessionRestored(), sessionId(), commitDataRequest(), saveStateRequest()
4197*/
4198#ifndef QT_NO_SESSIONMANAGER
4199bool QGuiApplication::isSessionRestored() const
4200{
4201 Q_D(const QGuiApplication);
4202 return d->is_session_restored;
4203}
4204
4205QString QGuiApplication::sessionId() const
4206{
4207 Q_D(const QGuiApplication);
4208 return d->session_manager->sessionId();
4209}
4210
4211QString QGuiApplication::sessionKey() const
4212{
4213 Q_D(const QGuiApplication);
4214 return d->session_manager->sessionKey();
4215}
4216
4217bool QGuiApplication::isSavingSession() const
4218{
4219 Q_D(const QGuiApplication);
4220 return d->is_saving_session;
4221}
4222
4223void QGuiApplicationPrivate::commitData()
4224{
4225 Q_Q(QGuiApplication);
4226 is_saving_session = true;
4227 emit q->commitDataRequest(*session_manager);
4228 is_saving_session = false;
4229}
4230
4231
4232void QGuiApplicationPrivate::saveState()
4233{
4234 Q_Q(QGuiApplication);
4235 is_saving_session = true;
4236 emit q->saveStateRequest(*session_manager);
4237 is_saving_session = false;
4238}
4239#endif //QT_NO_SESSIONMANAGER
4240
4241/*!
4242 \since 5.2
4243
4244 Function that can be used to sync Qt state with the Window Systems state.
4245
4246 This function will first empty Qts events by calling QCoreApplication::processEvents(),
4247 then the platform plugin will sync up with the windowsystem, and finally Qts events
4248 will be delived by another call to QCoreApplication::processEvents();
4249
4250 This function is timeconsuming and its use is discouraged.
4251*/
4252void QGuiApplication::sync()
4253{
4254 QCoreApplication::processEvents();
4255 if (QGuiApplicationPrivate::platform_integration
4256 && QGuiApplicationPrivate::platform_integration->hasCapability(QPlatformIntegration::SyncState)) {
4257 QGuiApplicationPrivate::platform_integration->sync();
4258 QCoreApplication::processEvents();
4259 QWindowSystemInterface::flushWindowSystemEvents();
4260 }
4261}
4262
4263/*!
4264 \property QGuiApplication::layoutDirection
4265 \brief the default layout direction for this application
4266
4267 On system start-up, or when the direction is explicitly set to
4268 Qt::LayoutDirectionAuto, the default layout direction depends on the
4269 application's language.
4270
4271 The notifier signal was introduced in Qt 5.4.
4272
4273 \sa QWidget::layoutDirection, isLeftToRight(), isRightToLeft()
4274 */
4275
4276void QGuiApplication::setLayoutDirection(Qt::LayoutDirection direction)
4277{
4278 layout_direction = direction;
4279 if (direction == Qt::LayoutDirectionAuto)
4280 direction = qt_detectRTLLanguage() ? Qt::RightToLeft : Qt::LeftToRight;
4281
4282 // no change to the explicitly set or auto-detected layout direction
4283 if (direction == effective_layout_direction)
4284 return;
4285
4286 effective_layout_direction = direction;
4287 if (qGuiApp) {
4288 emit qGuiApp->layoutDirectionChanged(direction);
4289 QGuiApplicationPrivate::instance()->notifyLayoutDirectionChange();
4290 }
4291}
4292
4293Qt::LayoutDirection QGuiApplication::layoutDirection()
4294{
4295 /*
4296 effective_layout_direction defaults to Qt::LeftToRight, and is updated with what is
4297 auto-detected by a call to setLayoutDirection(Qt::LayoutDirectionAuto). This happens in
4298 QGuiApplicationPrivate::init and when the language changes (or before if the application
4299 calls the static function, but then no translators are installed so the auto-detection
4300 always yields Qt::LeftToRight).
4301 So we can be certain that it's always the right value.
4302 */
4303 return effective_layout_direction;
4304}
4305
4306/*!
4307 \fn QCursor *QGuiApplication::overrideCursor()
4308
4309 Returns the active application override cursor.
4310
4311 This function returns \nullptr if no application cursor has been defined (i.e. the
4312 internal cursor stack is empty).
4313
4314 \sa setOverrideCursor(), restoreOverrideCursor()
4315*/
4316#ifndef QT_NO_CURSOR
4317QCursor *QGuiApplication::overrideCursor()
4318{
4319 CHECK_QAPP_INSTANCE(nullptr)
4320 return qGuiApp->d_func()->cursor_list.isEmpty() ? nullptr : &qGuiApp->d_func()->cursor_list.first();
4321}
4322
4323/*!
4324 Changes the currently active application override cursor to \a cursor.
4325
4326 This function has no effect if setOverrideCursor() was not called.
4327
4328 \sa setOverrideCursor(), overrideCursor(), restoreOverrideCursor(),
4329 QWidget::setCursor()
4330 */
4331void QGuiApplication::changeOverrideCursor(const QCursor &cursor)
4332{
4334 if (qGuiApp->d_func()->cursor_list.isEmpty())
4335 return;
4336 qGuiApp->d_func()->cursor_list.removeFirst();
4337 setOverrideCursor(cursor);
4338}
4339#endif
4340
4341
4342#ifndef QT_NO_CURSOR
4343static inline void applyCursor(QWindow *w, QCursor c)
4344{
4345 if (const QScreen *screen = w->screen())
4346 if (QPlatformCursor *cursor = screen->handle()->cursor())
4347 cursor->changeCursor(&c, w);
4348}
4349
4350static inline void unsetCursor(QWindow *w)
4351{
4352 if (const QScreen *screen = w->screen())
4353 if (QPlatformCursor *cursor = screen->handle()->cursor())
4354 cursor->changeCursor(nullptr, w);
4355}
4356
4357static inline void applyCursor(const QList<QWindow *> &l, const QCursor &c)
4358{
4359 for (int i = 0; i < l.size(); ++i) {
4360 QWindow *w = l.at(i);
4361 if (w->handle())
4362 applyCursor(w, c);
4363 }
4364}
4365
4366static inline void applyOverrideCursor(const QList<QScreen *> &screens, const QCursor &c)
4367{
4368 for (QScreen *screen : screens) {
4369 if (QPlatformCursor *cursor = screen->handle()->cursor())
4370 cursor->setOverrideCursor(c);
4371 }
4372}
4373
4374static inline void clearOverrideCursor(const QList<QScreen *> &screens)
4375{
4376 for (QScreen *screen : screens) {
4377 if (QPlatformCursor *cursor = screen->handle()->cursor())
4378 cursor->clearOverrideCursor();
4379 }
4380}
4381
4382static inline void applyWindowCursor(const QList<QWindow *> &l)
4383{
4384 for (int i = 0; i < l.size(); ++i) {
4385 QWindow *w = l.at(i);
4386 if (w->handle()) {
4387 if (qt_window_private(w)->hasCursor) {
4388 applyCursor(w, w->cursor());
4389 } else {
4390 unsetCursor(w);
4391 }
4392 }
4393 }
4394}
4395
4396/*!
4397 \fn void QGuiApplication::setOverrideCursor(const QCursor &cursor)
4398
4399 Sets the application override cursor to \a cursor.
4400
4401 Application override cursors are intended for showing the user that the
4402 application is in a special state, for example during an operation that
4403 might take some time.
4404
4405 This cursor will be displayed in all the application's widgets until
4406 restoreOverrideCursor() or another setOverrideCursor() is called.
4407
4408 Application cursors are stored on an internal stack. setOverrideCursor()
4409 pushes the cursor onto the stack, and restoreOverrideCursor() pops the
4410 active cursor off the stack. changeOverrideCursor() changes the currently
4411 active application override cursor.
4412
4413 Every setOverrideCursor() must eventually be followed by a corresponding
4414 restoreOverrideCursor(), otherwise the stack will never be emptied.
4415
4416 Example:
4417 \snippet code/src_gui_kernel_qguiapplication_x11.cpp 0
4418
4419 \sa overrideCursor(), restoreOverrideCursor(), changeOverrideCursor(),
4420 QWidget::setCursor()
4421*/
4422void QGuiApplication::setOverrideCursor(const QCursor &cursor)
4423{
4425 qGuiApp->d_func()->cursor_list.prepend(cursor);
4426 if (QPlatformCursor::capabilities().testFlag(QPlatformCursor::OverrideCursor))
4427 applyOverrideCursor(QGuiApplicationPrivate::screen_list, cursor);
4428 else
4429 applyCursor(QGuiApplicationPrivate::window_list, cursor);
4430}
4431
4432/*!
4433 \fn void QGuiApplication::restoreOverrideCursor()
4434
4435 Undoes the last setOverrideCursor().
4436
4437 If setOverrideCursor() has been called twice, calling
4438 restoreOverrideCursor() will activate the first cursor set. Calling this
4439 function a second time restores the original widgets' cursors.
4440
4441 \sa setOverrideCursor(), overrideCursor()
4442*/
4443void QGuiApplication::restoreOverrideCursor()
4444{
4446 if (qGuiApp->d_func()->cursor_list.isEmpty())
4447 return;
4448 qGuiApp->d_func()->cursor_list.removeFirst();
4449 if (qGuiApp->d_func()->cursor_list.size() > 0) {
4450 QCursor c(qGuiApp->d_func()->cursor_list.value(0));
4451 if (QPlatformCursor::capabilities().testFlag(QPlatformCursor::OverrideCursor))
4452 applyOverrideCursor(QGuiApplicationPrivate::screen_list, c);
4453 else
4454 applyCursor(QGuiApplicationPrivate::window_list, c);
4455 } else {
4456 if (QPlatformCursor::capabilities().testFlag(QPlatformCursor::OverrideCursor))
4457 clearOverrideCursor(QGuiApplicationPrivate::screen_list);
4458 applyWindowCursor(QGuiApplicationPrivate::window_list);
4459 }
4460}
4461#endif// QT_NO_CURSOR
4462
4463/*!
4464 Returns the application's style hints.
4465
4466 The style hints encapsulate a set of platform dependent properties
4467 such as double click intervals, full width selection and others.
4468
4469 The hints can be used to integrate tighter with the underlying platform.
4470
4471 \sa QStyleHints
4472 */
4473QStyleHints *QGuiApplication::styleHints()
4474{
4475 if (!QGuiApplicationPrivate::styleHints)
4476 QGuiApplicationPrivate::styleHints = new QStyleHints();
4477 return QGuiApplicationPrivate::styleHints;
4478}
4479
4480/*!
4481 Sets whether Qt should use the system's standard colors, fonts, etc., to
4482 \a on. By default, this is \c true.
4483
4484 This function must be called before creating the QGuiApplication object, like
4485 this:
4486
4487 \snippet code/src_gui_kernel_qguiapplication.cpp 0
4488
4489 \sa desktopSettingsAware()
4490*/
4491void QGuiApplication::setDesktopSettingsAware(bool on)
4492{
4493 QGuiApplicationPrivate::obey_desktop_settings = on;
4494}
4495
4496/*!
4497 Returns \c true if Qt is set to use the system's standard colors, fonts, etc.;
4498 otherwise returns \c false. The default is \c true.
4499
4500 \sa setDesktopSettingsAware()
4501*/
4502bool QGuiApplication::desktopSettingsAware()
4503{
4504 return QGuiApplicationPrivate::obey_desktop_settings;
4505}
4506
4507/*!
4508 returns the input method.
4509
4510 The input method returns properties about the state and position of
4511 the virtual keyboard. It also provides information about the position of the
4512 current focused input element.
4513
4514 \sa QInputMethod
4515 */
4516QInputMethod *QGuiApplication::inputMethod()
4517{
4518 CHECK_QAPP_INSTANCE(nullptr)
4519 if (!qGuiApp->d_func()->inputMethod)
4520 qGuiApp->d_func()->inputMethod = new QInputMethod();
4521 return qGuiApp->d_func()->inputMethod;
4522}
4523
4524/*!
4525 \fn void QGuiApplication::fontDatabaseChanged()
4526
4527 This signal is emitted when the available fonts have changed.
4528
4529 This can happen when application fonts are added or removed, or when the
4530 system fonts change.
4531
4532 \sa QFontDatabase::addApplicationFont(),
4533 QFontDatabase::addApplicationFontFromData(),
4534 QFontDatabase::removeAllApplicationFonts(),
4535 QFontDatabase::removeApplicationFont()
4536*/
4537
4538QPixmap QGuiApplicationPrivate::getPixmapCursor(Qt::CursorShape cshape)
4539{
4540 Q_UNUSED(cshape);
4541 return QPixmap();
4542}
4543
4544QPoint QGuiApplicationPrivate::QLastCursorPosition::toPoint() const noexcept
4545{
4546 // Guard against the default initialization of qInf() (avoid UB or SIGFPE in conversion).
4547 if (Q_UNLIKELY(qIsInf(thePoint.x())))
4548 return QPoint(std::numeric_limits<int>::max(), std::numeric_limits<int>::max());
4549 return thePoint.toPoint();
4550}
4551
4552#if QT_CONFIG(draganddrop)
4553void QGuiApplicationPrivate::notifyDragStarted(const QDrag *drag)
4554{
4555 Q_UNUSED(drag);
4556
4557}
4558#endif
4559
4560const QColorTrcLut *QGuiApplicationPrivate::colorProfileForA8Text()
4561{
4562#ifdef Q_OS_WIN
4563 if (!m_a8ColorProfile)
4564 m_a8ColorProfile = QColorTrcLut::fromGamma(2.31f); // This is a hard-coded thing for Windows text rendering
4565 return m_a8ColorProfile.get();
4566#else
4567 return colorProfileForA32Text();
4568#endif
4569}
4570
4571const QColorTrcLut *QGuiApplicationPrivate::colorProfileForA32Text()
4572{
4573 if (!m_a32ColorProfile)
4574 m_a32ColorProfile = QColorTrcLut::fromGamma(float(fontSmoothingGamma));
4575 return m_a32ColorProfile.get();
4576}
4577
4578void QGuiApplicationPrivate::_q_updateFocusObject(QObject *object)
4579{
4580 Q_Q(QGuiApplication);
4581
4582 QPlatformInputContext *inputContext = platformIntegration()->inputContext();
4583 const bool enabled = inputContext && QInputMethodPrivate::objectAcceptsInputMethod(object);
4584
4585 QPlatformInputContextPrivate::setInputMethodAccepted(enabled);
4586 if (inputContext)
4587 inputContext->setFocusObject(object);
4588 emit q->focusObjectChanged(object);
4589}
4590
4591enum MouseMasks {
4592 MouseCapsMask = 0xFF,
4593 MouseSourceMaskDst = 0xFF00,
4594 MouseSourceMaskSrc = MouseCapsMask,
4595 MouseSourceShift = 8,
4596 MouseFlagsCapsMask = 0xFF0000,
4597 MouseFlagsShift = 16
4598};
4599
4600QInputDeviceManager *QGuiApplicationPrivate::inputDeviceManager()
4601{
4602 Q_ASSERT(QGuiApplication::instance());
4603
4604 if (!m_inputDeviceManager)
4605 m_inputDeviceManager = new QInputDeviceManager(QGuiApplication::instance());
4606
4607 return m_inputDeviceManager;
4608}
4609
4610/*!
4611 Returns the QThreadPool instance for Qt Gui.
4612 \internal
4613*/
4614QThreadPool *QGuiApplicationPrivate::qtGuiThreadPool()
4615{
4616#if QT_CONFIG(qtgui_threadpool)
4617 Q_CONSTINIT static QPointer<QThreadPool> guiInstance;
4618 Q_CONSTINIT static QBasicMutex theMutex;
4619 const static bool runtime_disable = qEnvironmentVariableIsSet("QT_NO_GUI_THREADPOOL");
4620 if (runtime_disable)
4621 return nullptr;
4622 const QMutexLocker locker(&theMutex);
4623 if (guiInstance.isNull() && !QCoreApplication::closingDown()) {
4624 guiInstance = new QThreadPool();
4625 // Limit max thread to avoid too many parallel threads.
4626 // We are not optimized for much more than 4 or 8 threads.
4627 if (guiInstance && guiInstance->maxThreadCount() > 4)
4628 guiInstance->setMaxThreadCount(qBound(4, guiInstance->maxThreadCount() / 2, 8));
4629 }
4630 return guiInstance;
4631#else
4632 return nullptr;
4633#endif
4634}
4635
4636/*!
4637 \fn template <typename QNativeInterface> QNativeInterface *QGuiApplication::nativeInterface() const
4638
4639 Returns a native interface of the given type for the application.
4640
4641 This function provides access to platform specific functionality
4642 of QGuiApplication, as defined in the QNativeInterface namespace:
4643
4644 \annotatedlist native-interfaces-qguiapplication
4645
4646 If the requested interface is not available a \nullptr is returned.
4647 */
4648
4649void *QGuiApplication::resolveInterface(const char *name, int revision) const
4650{
4651 using namespace QNativeInterface;
4652 using namespace QNativeInterface::Private;
4653
4654 auto *platformIntegration = QGuiApplicationPrivate::platformIntegration();
4655 Q_UNUSED(platformIntegration);
4656
4657#if defined(Q_OS_WIN)
4658 QT_NATIVE_INTERFACE_RETURN_IF(QWindowsApplication, platformIntegration);
4659#endif
4660#if QT_CONFIG(xcb)
4661 QT_NATIVE_INTERFACE_RETURN_IF(QX11Application, platformNativeInterface());
4662#endif
4663#if QT_CONFIG(wayland)
4664 QT_NATIVE_INTERFACE_RETURN_IF(QWaylandApplication, platformNativeInterface());
4665#endif
4666#if defined(Q_OS_VISIONOS)
4667 QT_NATIVE_INTERFACE_RETURN_IF(QVisionOSApplication, platformIntegration);
4668#endif
4669
4670 return QCoreApplication::resolveInterface(name, revision);
4671}
4672
4673QT_END_NAMESPACE
4674
4675#include "moc_qguiapplication.cpp"
The QClipboard class provides access to the window system clipboard.
Definition qclipboard.h:21
\reentrant
Definition qfont.h:23
The QIcon class provides scalable icons in different modes and states.
Definition qicon.h:21
QInputDeviceManager acts as a communication hub between QtGui and the input handlers.
The QPalette class contains color groups for each widget state.
Definition qpalette.h:20
The QPlatformIntegration class is the entry for WindowSystem specific functionality.
The QPlatformTheme class allows customizing the UI based on themes.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:177
The QStyleHints class contains platform specific hints and settings. \inmodule QtGui.
Definition qstylehints.h:20
\inmodule QtGui
Definition qwindow.h:64
#define qApp
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
static bool needsWindowBlockedEvent(const QWindow *w)
Q_CORE_EXPORT void qt_call_post_routines()
static void init_plugins(const QList< QByteArray > &pluginList)
static void initFontUnlocked()
static void clearFontUnlocked()
void qRegisterGuiVariant()
static Q_CONSTINIT unsigned applicationResourceFlags
static Q_CONSTINIT int touchDoubleTapDistance
static QWindowGeometrySpecification windowGeometrySpecification
static bool qt_detectRTLLanguage()
Q_CONSTINIT Q_GUI_EXPORT bool qt_is_tty_app
static Q_CONSTINIT bool force_reverse
static Q_CONSTINIT int mouseDoubleClickDistance
#define Q_WINDOW_GEOMETRY_SPECIFICATION_INITIALIZER
static void init_platform(const QString &pluginNamesWithArguments, const QString &platformPluginPath, const QString &platformThemeName, int &argc, char **argv)
static void initThemeHints()
static int nextGeometryToken(const QByteArray &a, int &pos, char *op)
#define CHECK_QAPP_INSTANCE(...)
ApplicationResourceFlags
@ ApplicationFontExplicitlySet
static void updateBlockedStatusRecursion(QWindow *window, bool shouldBeBlocked)
#define qGuiApp
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
QDebug Q_GUI_EXPORT & operator<<(QDebug &s, const QVectorPath &path)
void applyTo(QWindow *window) const
static QWindowGeometrySpecification fromArgument(const QByteArray &a)