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