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_APPLE)
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_MACOS
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 QScreen *screen = wse->screen.data();
2814 if (window->screen() == screen)
2815 return;
2816
2817 auto *windowPrivate = QWindowPrivate::get(window);
2818 QWindow *topLevelWindow = windowPrivate->topLevelWindow(QWindow::ExcludeTransients);
2819 if (window == topLevelWindow) {
2820 if (screen)
2821 topLevelWindow->d_func()->setTopLevelScreen(screen, false /* recreate */);
2822 else // Fall back to default behavior, and try to find some appropriate screen
2823 topLevelWindow->setScreen(nullptr);
2824 } else if (screen) {
2825 // Child windows reflect the screen of their top level parent. When a
2826 // window is reparented into a window that lives on a different screen
2827 // we don't need to update the top level screen, but do need to emit
2828 // screen changes for the child and its children,
2829 windowPrivate->emitScreenChangedRecursion(screen);
2830 }
2831}
2832
2833void QGuiApplicationPrivate::processWindowDevicePixelRatioChangedEvent(QWindowSystemInterfacePrivate::WindowDevicePixelRatioChangedEvent *wde)
2834{
2835 if (wde->window.isNull())
2836 return;
2837 QWindowPrivate::get(wde->window)->updateDevicePixelRatio();
2838}
2839
2840void QGuiApplicationPrivate::processSafeAreaMarginsChangedEvent(QWindowSystemInterfacePrivate::SafeAreaMarginsChangedEvent *wse)
2841{
2842 if (wse->window.isNull())
2843 return;
2844
2845 emit wse->window->safeAreaMarginsChanged(wse->window->safeAreaMargins());
2846
2847 QEvent event(QEvent::SafeAreaMarginsChange);
2848 QGuiApplication::sendSpontaneousEvent(wse->window, &event);
2849}
2850
2851void QGuiApplicationPrivate::processThemeChanged(QWindowSystemInterfacePrivate::ThemeChangeEvent *)
2852{
2853 // FIXME: Remove check once we ensure that the platform plugin is
2854 // torn down before QGuiApplication.
2855 if (!qGuiApp)
2856 return;
2857
2858 if (auto *guiAppPrivate = QGuiApplicationPrivate::instance())
2859 guiAppPrivate->handleThemeChanged();
2860
2861 QIconPrivate::clearIconCache();
2862
2863 QEvent themeChangeEvent(QEvent::ThemeChange);
2864 QGuiApplication::sendSpontaneousEvent(qGuiApp, &themeChangeEvent);
2865}
2866
2867void QGuiApplicationPrivate::handleThemeChanged()
2868{
2869 QStyleHintsPrivate::get(QGuiApplication::styleHints())->update(platformTheme());
2870 updatePalette();
2871
2872 QIconLoader::instance()->updateSystemTheme();
2873 QAbstractFileIconProviderPrivate::clearIconTypeCache();
2874
2875 if (!(applicationResourceFlags & ApplicationFontExplicitlySet)) {
2876 const auto locker = qt_scoped_lock(applicationFontMutex);
2877 clearFontUnlocked();
2878 initFontUnlocked();
2879 }
2880 initThemeHints();
2881}
2882
2883void QGuiApplicationPrivate::processGeometryChangeEvent(QWindowSystemInterfacePrivate::GeometryChangeEvent *e)
2884{
2885 if (e->window.isNull())
2886 return;
2887
2888 QWindow *window = e->window.data();
2889 if (!window)
2890 return;
2891
2892 const QRect lastReportedGeometry = window->d_func()->geometry;
2893 const QRect requestedGeometry = e->requestedGeometry;
2894 const QRect actualGeometry = e->newGeometry;
2895
2896 // We send size and move events only if the geometry has changed from
2897 // what was last reported, or if the user tried to set a new geometry,
2898 // but the window manager responded by keeping the old geometry. In the
2899 // latter case we send move/resize events with the same geometry as the
2900 // last reported geometry, to indicate that the window wasn't moved or
2901 // resized. Note that this logic does not apply to the property changes
2902 // of the window, as we don't treat them as part of this request/response
2903 // protocol of QWindow/QPA.
2904 const bool isResize = actualGeometry.size() != lastReportedGeometry.size()
2905 || requestedGeometry.size() != actualGeometry.size();
2906 const bool isMove = actualGeometry.topLeft() != lastReportedGeometry.topLeft()
2907 || requestedGeometry.topLeft() != actualGeometry.topLeft();
2908
2909 window->d_func()->geometry = actualGeometry;
2910
2911 if (isResize || window->d_func()->resizeEventPending) {
2912 QResizeEvent e(actualGeometry.size(), lastReportedGeometry.size());
2913 QGuiApplication::sendSpontaneousEvent(window, &e);
2914
2915 window->d_func()->resizeEventPending = false;
2916
2917 if (actualGeometry.width() != lastReportedGeometry.width())
2918 emit window->widthChanged(actualGeometry.width());
2919 if (actualGeometry.height() != lastReportedGeometry.height())
2920 emit window->heightChanged(actualGeometry.height());
2921 }
2922
2923 if (isMove) {
2924 //### frame geometry
2925 QMoveEvent e(actualGeometry.topLeft(), lastReportedGeometry.topLeft());
2926 QGuiApplication::sendSpontaneousEvent(window, &e);
2927
2928 if (actualGeometry.x() != lastReportedGeometry.x())
2929 emit window->xChanged(actualGeometry.x());
2930 if (actualGeometry.y() != lastReportedGeometry.y())
2931 emit window->yChanged(actualGeometry.y());
2932 }
2933}
2934
2935void QGuiApplicationPrivate::processCloseEvent(QWindowSystemInterfacePrivate::CloseEvent *e)
2936{
2937 if (e->window.isNull())
2938 return;
2939 if (e->window.data()->d_func()->blockedByModalWindow && !e->window.data()->d_func()->inClose) {
2940 // a modal window is blocking this window, don't allow close events through, unless they
2941 // originate from a call to QWindow::close.
2942 e->eventAccepted = false;
2943 return;
2944 }
2945
2946 QCloseEvent event;
2947 QGuiApplication::sendSpontaneousEvent(e->window.data(), &event);
2948
2949 e->eventAccepted = event.isAccepted();
2950}
2951
2952void QGuiApplicationPrivate::processFileOpenEvent(QWindowSystemInterfacePrivate::FileOpenEvent *e)
2953{
2954 if (e->url.isEmpty())
2955 return;
2956
2957 QFileOpenEvent event(e->url);
2958 QGuiApplication::sendSpontaneousEvent(qApp, &event);
2959}
2960
2961QGuiApplicationPrivate::TabletPointData &QGuiApplicationPrivate::tabletDevicePoint(qint64 deviceId)
2962{
2963 for (int i = 0; i < tabletDevicePoints.size(); ++i) {
2964 TabletPointData &pointData = tabletDevicePoints[i];
2965 if (pointData.deviceId == deviceId)
2966 return pointData;
2967 }
2968
2969 tabletDevicePoints.append(TabletPointData(deviceId));
2970 return tabletDevicePoints.last();
2971}
2972
2973void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::TabletEvent *e)
2974{
2975#if QT_CONFIG(tabletevent)
2976 const auto device = static_cast<const QPointingDevice *>(e->device);
2977 TabletPointData &pointData = tabletDevicePoint(device->uniqueId().numericId());
2978
2979 QEvent::Type type = QEvent::TabletMove;
2980 if (e->buttons != pointData.state)
2981 type = (e->buttons > pointData.state) ? QEvent::TabletPress : QEvent::TabletRelease;
2982
2983 QWindow *window = e->window.data();
2984 modifier_buttons = e->modifiers;
2985
2986 bool localValid = true;
2987 // If window is null, pick one based on the global position and make sure all
2988 // subsequent events up to the release are delivered to that same window.
2989 // If window is given, just send to that.
2990 if (type == QEvent::TabletPress) {
2991 if (e->nullWindow()) {
2992 window = QGuiApplication::topLevelAt(e->global.toPoint());
2993 localValid = false;
2994 }
2995 if (!window)
2996 return;
2997 active_popup_on_press = activePopupWindow();
2998 pointData.target = window;
2999 } else {
3000 if (e->nullWindow()) {
3001 window = pointData.target;
3002 localValid = false;
3003 }
3004 if (type == QEvent::TabletRelease)
3005 pointData.target = nullptr;
3006 if (!window)
3007 return;
3008 }
3009 QPointF local = e->local;
3010 if (!localValid) {
3011 QPointF delta = e->global - e->global.toPoint();
3012 local = window->mapFromGlobal(e->global.toPoint()) + delta;
3013 }
3014
3015 // TODO stop deducing the button state change here: rather require it from the platform plugin, as with mouse events
3016 Qt::MouseButtons stateChange = e->buttons ^ pointData.state;
3017 Qt::MouseButton button = Qt::NoButton;
3018 for (int check = Qt::LeftButton; check <= int(Qt::MaxMouseButton); check = check << 1) {
3019 if (check & stateChange) {
3020 button = Qt::MouseButton(check);
3021 break;
3022 }
3023 }
3024
3025 const auto *activePopup = activePopupWindow();
3026 if (window->d_func()->blockedByModalWindow && !activePopup) {
3027 // a modal window is blocking this window, don't allow events through
3028 return;
3029 }
3030
3031 QTabletEvent tabletEvent(type, device, local, e->global,
3032 e->pressure, e->xTilt, e->yTilt,
3033 e->tangentialPressure, e->rotation, e->z,
3034 e->modifiers, button, e->buttons);
3035 tabletEvent.setAccepted(false);
3036 tabletEvent.setTimestamp(e->timestamp);
3037
3038 if (activePopup && activePopup != window) {
3039 // If the popup handles the event, we're done.
3040 if (window->d_func()->forwardToPopup(&tabletEvent, active_popup_on_press))
3041 return;
3042 }
3043
3044 QGuiApplication::sendSpontaneousEvent(window, &tabletEvent);
3045 pointData.state = e->buttons;
3046 if (!tabletEvent.isAccepted()
3047 && !QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse
3048 && qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents)) {
3049
3050 const QEvent::Type mouseType = [&]() {
3051 switch (type) {
3052 case QEvent::TabletPress: return QEvent::MouseButtonPress;
3053 case QEvent::TabletMove: return QEvent::MouseMove;
3054 case QEvent::TabletRelease: return QEvent::MouseButtonRelease;
3055 default: Q_UNREACHABLE();
3056 }
3057 }();
3058 QWindowSystemInterfacePrivate::MouseEvent mouseEvent(window, e->timestamp, e->local,
3059 e->global, e->buttons, e->modifiers, button, mouseType, Qt::MouseEventNotSynthesized, false, device);
3060 mouseEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
3061 qCDebug(lcPtrDispatch) << "synthesizing mouse from tablet event" << mouseType
3062 << e->local << button << e->buttons << e->modifiers;
3063 processMouseEvent(&mouseEvent);
3064 }
3065#else
3066 Q_UNUSED(e);
3067#endif
3068}
3069
3070void QGuiApplicationPrivate::processTabletEnterProximityEvent(QWindowSystemInterfacePrivate::TabletEnterProximityEvent *e)
3071{
3072#if QT_CONFIG(tabletevent)
3073 const QPointingDevice *dev = static_cast<const QPointingDevice *>(e->device);
3074 QTabletEvent ev(QEvent::TabletEnterProximity, dev, QPointF(), QPointF(),
3075 0, 0, 0, 0, 0, 0, e->modifiers, Qt::NoButton,
3076 tabletDevicePoint(dev->uniqueId().numericId()).state);
3077 ev.setTimestamp(e->timestamp);
3078 QGuiApplication::sendSpontaneousEvent(qGuiApp, &ev);
3079#else
3080 Q_UNUSED(e);
3081#endif
3082}
3083
3084void QGuiApplicationPrivate::processTabletLeaveProximityEvent(QWindowSystemInterfacePrivate::TabletLeaveProximityEvent *e)
3085{
3086#if QT_CONFIG(tabletevent)
3087 const QPointingDevice *dev = static_cast<const QPointingDevice *>(e->device);
3088 QTabletEvent ev(QEvent::TabletLeaveProximity, dev, QPointF(), QPointF(),
3089 0, 0, 0, 0, 0, 0, e->modifiers, Qt::NoButton,
3090 tabletDevicePoint(dev->uniqueId().numericId()).state);
3091 ev.setTimestamp(e->timestamp);
3092 QGuiApplication::sendSpontaneousEvent(qGuiApp, &ev);
3093#else
3094 Q_UNUSED(e);
3095#endif
3096}
3097
3098#ifndef QT_NO_GESTURES
3099void QGuiApplicationPrivate::processGestureEvent(QWindowSystemInterfacePrivate::GestureEvent *e)
3100{
3101 if (e->window.isNull())
3102 return;
3103
3104 const QPointingDevice *device = static_cast<const QPointingDevice *>(e->device);
3105 QNativeGestureEvent ev(e->type, device, e->fingerCount, e->pos, e->pos, e->globalPos, (e->intValue ? e->intValue : e->realValue),
3106 e->delta, e->sequenceId);
3107 ev.setTimestamp(e->timestamp);
3108 QGuiApplication::sendSpontaneousEvent(e->window, &ev);
3109}
3110#endif // QT_NO_GESTURES
3111
3112void QGuiApplicationPrivate::processPlatformPanelEvent(QWindowSystemInterfacePrivate::PlatformPanelEvent *e)
3113{
3114 if (!e->window)
3115 return;
3116
3117 if (e->window->d_func()->blockedByModalWindow) {
3118 // a modal window is blocking this window, don't allow events through
3119 return;
3120 }
3121
3122 QEvent ev(QEvent::PlatformPanel);
3123 QGuiApplication::sendSpontaneousEvent(e->window.data(), &ev);
3124}
3125
3126#ifndef QT_NO_CONTEXTMENU
3127void QGuiApplicationPrivate::processContextMenuEvent(QWindowSystemInterfacePrivate::ContextMenuEvent *e)
3128{
3129 // Widgets do not care about mouse triggered context menu events. Also, do not forward event
3130 // to a window blocked by a modal window.
3131 if (!e->window || e->mouseTriggered || e->window->d_func()->blockedByModalWindow)
3132 return;
3133
3134 QContextMenuEvent ev(QContextMenuEvent::Keyboard, e->pos, e->globalPos, e->modifiers);
3135 QGuiApplication::sendSpontaneousEvent(e->window.data(), &ev);
3136 e->eventAccepted = ev.isAccepted();
3137}
3138#endif
3139
3140void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::TouchEvent *e)
3141{
3142 if (!QInputDevicePrivate::isRegistered(e->device))
3143 return;
3144
3145 modifier_buttons = e->modifiers;
3146 QPointingDevice *device = const_cast<QPointingDevice *>(static_cast<const QPointingDevice *>(e->device));
3147 QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(device);
3148
3149 auto *guiAppPrivate = QGuiApplicationPrivate::instance();
3150
3151 if (e->touchType == QEvent::TouchCancel) {
3152 // The touch sequence has been canceled (e.g. by the compositor).
3153 // Send the TouchCancel to all windows with active touches and clean up.
3154 QTouchEvent touchEvent(QEvent::TouchCancel, device, e->modifiers);
3155 touchEvent.setTimestamp(e->timestamp);
3156 constexpr qsizetype Prealloc = decltype(devPriv->activePoints)::mapped_container_type::PreallocatedSize;
3157 QMinimalVarLengthFlatSet<QWindow *, Prealloc> windowsNeedingCancel;
3158
3159 for (auto &epd : devPriv->activePoints.values()) {
3160 if (QWindow *w = QMutableEventPoint::window(epd.eventPoint))
3161 windowsNeedingCancel.insert(w);
3162 }
3163
3164 for (QWindow *w : windowsNeedingCancel)
3165 QGuiApplication::sendSpontaneousEvent(w, &touchEvent);
3166
3167 if (!guiAppPrivate->synthesizedMousePoints.isEmpty() && !e->synthetic()) {
3168 for (QHash<QWindow *, SynthesizedMouseData>::const_iterator synthIt = guiAppPrivate->synthesizedMousePoints.constBegin(),
3169 synthItEnd = guiAppPrivate->synthesizedMousePoints.constEnd(); synthIt != synthItEnd; ++synthIt) {
3170 if (!synthIt->window)
3171 continue;
3172 QWindowSystemInterfacePrivate::MouseEvent fake(synthIt->window.data(),
3173 e->timestamp,
3174 synthIt->pos,
3175 synthIt->screenPos,
3176 Qt::NoButton,
3177 e->modifiers,
3178 Qt::LeftButton,
3179 QEvent::MouseButtonRelease,
3180 Qt::MouseEventNotSynthesized,
3181 false,
3182 device);
3183 fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
3184 processMouseEvent(&fake);
3185 }
3186 guiAppPrivate->synthesizedMousePoints.clear();
3187 }
3188 guiAppPrivate->lastTouchType = e->touchType;
3189 return;
3190 }
3191
3192 // Prevent sending ill-formed event sequences: Cancel can only be followed by a Begin.
3193 if (guiAppPrivate->lastTouchType == QEvent::TouchCancel && e->touchType != QEvent::TouchBegin)
3194 return;
3195
3196 guiAppPrivate->lastTouchType = e->touchType;
3197
3198 QPointer<QWindow> window = e->window; // the platform hopefully tells us which window received the event
3199 QVarLengthArray<QMutableTouchEvent, 2> touchEvents;
3200
3201 // For each temporary QEventPoint from the QPA TouchEvent:
3202 // - update the persistent QEventPoint in QPointingDevicePrivate::activePoints with current values
3203 // - determine which window to deliver it to
3204 // - add it to the QTouchEvent instance for that window (QMutableTouchEvent::target() will be QWindow*, for now)
3205 for (auto &tempPt : e->points) {
3206 // update state
3207 auto epd = devPriv->pointById(tempPt.id());
3208 auto &ep = epd->eventPoint;
3209 epd->eventPoint.setAccepted(false);
3210 switch (tempPt.state()) {
3211 case QEventPoint::State::Pressed:
3212 // On touchpads, send all touch points to the same window.
3213 if (!window && e->device && e->device->type() == QInputDevice::DeviceType::TouchPad)
3214 window = devPriv->firstActiveWindow();
3215 // If the QPA event didn't tell us which window, find the one under the touchpoint position.
3216 if (!window)
3217 window = QGuiApplication::topLevelAt(tempPt.globalPosition().toPoint());
3218 QMutableEventPoint::setWindow(ep, window);
3219 active_popup_on_press = activePopupWindow();
3220 break;
3221
3222 case QEventPoint::State::Released:
3223 if (Q_UNLIKELY(!window.isNull() && window != QMutableEventPoint::window(ep)))
3224 qCDebug(lcPtrDispatch) << "delivering touch release to same window"
3225 << QMutableEventPoint::window(ep) << "not" << window.data();
3226 window = QMutableEventPoint::window(ep);
3227 break;
3228
3229 default: // update or stationary
3230 if (Q_UNLIKELY(!window.isNull() && window != QMutableEventPoint::window(ep)))
3231 qCDebug(lcPtrDispatch) << "delivering touch update to same window"
3232 << QMutableEventPoint::window(ep) << "not" << window.data();
3233 window = QMutableEventPoint::window(ep);
3234 break;
3235 }
3236 // If we somehow still don't have a window, we can't deliver this touchpoint. (should never happen)
3237 if (Q_UNLIKELY(!window)) {
3238 qCDebug(lcPtrDispatch) << "skipping" << &tempPt << ": no target window";
3239 continue;
3240 }
3241 QMutableEventPoint::update(tempPt, ep);
3242
3243 Q_ASSERT(window.data() != nullptr);
3244
3245 // make the *scene* position the same as the *global* position
3246 QMutableEventPoint::setScenePosition(ep, tempPt.globalPosition());
3247
3248 // store the scene position as local position, for now
3249 QMutableEventPoint::setPosition(ep, window->mapFromGlobal(tempPt.globalPosition()));
3250
3251 // setTimeStamp has side effects, so we do it last
3252 QMutableEventPoint::setTimestamp(ep, e->timestamp);
3253
3254 // add the touchpoint to the event that will be delivered to the window
3255 bool added = false;
3256 for (QMutableTouchEvent &ev : touchEvents) {
3257 if (ev.target() == window.data()) {
3258 ev.addPoint(ep);
3259 added = true;
3260 break;
3261 }
3262 }
3263 if (!added) {
3264 QMutableTouchEvent mte(e->touchType, device, e->modifiers, {ep});
3265 mte.setTimestamp(e->timestamp);
3266 mte.setTarget(window.data());
3267 touchEvents.append(mte);
3268 }
3269 }
3270
3271 if (touchEvents.isEmpty())
3272 return;
3273
3274 for (QMutableTouchEvent &touchEvent : touchEvents) {
3275 QWindow *window = static_cast<QWindow *>(touchEvent.target());
3276
3277 QEvent::Type eventType;
3278 switch (touchEvent.touchPointStates()) {
3279 case QEventPoint::State::Pressed:
3280 eventType = QEvent::TouchBegin;
3281 break;
3282 case QEventPoint::State::Released:
3283 eventType = QEvent::TouchEnd;
3284 break;
3285 default:
3286 eventType = QEvent::TouchUpdate;
3287 break;
3288 }
3289
3290 const auto *activePopup = activePopupWindow();
3291 if (window->d_func()->blockedByModalWindow && !activePopup) {
3292 // a modal window is blocking this window, don't allow touch events through
3293
3294 // QTBUG-37371 temporary fix; TODO: revisit when we have a forwarding solution
3295 if (touchEvent.type() == QEvent::TouchEnd) {
3296 // but don't leave dangling state: e.g.
3297 // QQuickWindowPrivate::itemForTouchPointId needs to be cleared.
3298 QTouchEvent touchEvent(QEvent::TouchCancel, device, e->modifiers);
3299 touchEvent.setTimestamp(e->timestamp);
3300 QGuiApplication::sendSpontaneousEvent(window, &touchEvent);
3301 }
3302 continue;
3303 }
3304
3305 if (activePopup && activePopup != window) {
3306 // If the popup handles the event, we're done.
3307 if (window->d_func()->forwardToPopup(&touchEvent, active_popup_on_press))
3308 return;
3309 }
3310
3311 // Note: after the call to sendSpontaneousEvent, touchEvent.position() will have
3312 // changed to reflect the local position inside the last (random) widget it tried
3313 // to deliver the touch event to, and will therefore be invalid afterwards.
3314 QGuiApplication::sendSpontaneousEvent(window, &touchEvent);
3315
3316 if (!e->synthetic() && !touchEvent.isAccepted() && qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) {
3317 // exclude devices which generate their own mouse events
3318 if (!(touchEvent.device()->capabilities().testFlag(QInputDevice::Capability::MouseEmulation))) {
3319
3320 QEvent::Type mouseEventType = QEvent::MouseMove;
3321 Qt::MouseButton button = Qt::NoButton;
3322 Qt::MouseButtons buttons = Qt::LeftButton;
3323 if (eventType == QEvent::TouchBegin || m_fakeMouseSourcePointId < 0) {
3324 m_fakeMouseSourcePointId = touchEvent.point(0).id();
3325 qCDebug(lcPtrDispatch) << "synthesizing mouse events from touchpoint" << m_fakeMouseSourcePointId;
3326 }
3327 if (m_fakeMouseSourcePointId >= 0) {
3328 const auto *touchPoint = touchEvent.pointById(m_fakeMouseSourcePointId);
3329 if (touchPoint) {
3330 switch (touchPoint->state()) {
3331 case QEventPoint::State::Pressed:
3332 mouseEventType = QEvent::MouseButtonPress;
3333 button = Qt::LeftButton;
3334 break;
3335 case QEventPoint::State::Released:
3336 mouseEventType = QEvent::MouseButtonRelease;
3337 button = Qt::LeftButton;
3338 buttons = Qt::NoButton;
3339 Q_ASSERT(m_fakeMouseSourcePointId == touchPoint->id());
3340 m_fakeMouseSourcePointId = -1;
3341 break;
3342 default:
3343 break;
3344 }
3345 if (touchPoint->state() != QEventPoint::State::Released) {
3346 guiAppPrivate->synthesizedMousePoints.insert(window, SynthesizedMouseData(
3347 touchPoint->position(), touchPoint->globalPosition(), window));
3348 }
3349 // All touch events that are not accepted by the application will be translated to
3350 // left mouse button events instead (see AA_SynthesizeMouseForUnhandledTouchEvents docs).
3351 // Sending a QPA event (rather than simply sending a QMouseEvent) takes care of
3352 // side-effects such as double-click synthesis.
3353 QWindowSystemInterfacePrivate::MouseEvent fake(window, e->timestamp,
3354 window->mapFromGlobal(touchPoint->globalPosition().toPoint()),
3355 touchPoint->globalPosition(),
3356 buttons,
3357 e->modifiers,
3358 button,
3359 mouseEventType,
3360 Qt::MouseEventSynthesizedByQt,
3361 false,
3362 device,
3363 touchPoint->id());
3364 fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
3365 processMouseEvent(&fake);
3366 }
3367 }
3368 if (eventType == QEvent::TouchEnd)
3369 guiAppPrivate->synthesizedMousePoints.clear();
3370 }
3371 }
3372 }
3373
3374 // Remove released points from QPointingDevicePrivate::activePoints only after the event is
3375 // delivered. Widgets and Qt Quick are allowed to access them at any time before this.
3376 for (const QEventPoint &touchPoint : e->points) {
3377 if (touchPoint.state() == QEventPoint::State::Released)
3378 devPriv->removePointById(touchPoint.id());
3379 }
3380}
3381
3382void QGuiApplicationPrivate::processScreenOrientationChange(QWindowSystemInterfacePrivate::ScreenOrientationEvent *e)
3383{
3384 // This operation only makes sense after the QGuiApplication constructor runs
3385 if (QCoreApplication::startingUp())
3386 return;
3387
3388 if (!e->screen)
3389 return;
3390
3391 QScreen *s = e->screen.data();
3392 s->d_func()->orientation = e->orientation;
3393
3394 emit s->orientationChanged(s->orientation());
3395
3396 QScreenOrientationChangeEvent event(s, s->orientation());
3397 QCoreApplication::sendEvent(QCoreApplication::instance(), &event);
3398}
3399
3400void QGuiApplicationPrivate::processScreenGeometryChange(QWindowSystemInterfacePrivate::ScreenGeometryEvent *e)
3401{
3402 // This operation only makes sense after the QGuiApplication constructor runs
3403 if (QCoreApplication::startingUp())
3404 return;
3405
3406 if (!e->screen)
3407 return;
3408
3409 {
3410 QScreen *s = e->screen.data();
3411 QScreenPrivate::UpdateEmitter updateEmitter(s);
3412
3413 // Note: The incoming geometries have already been scaled by QHighDpi
3414 // in the QWSI layer, so we don't need to call updateGeometry() here.
3415 s->d_func()->geometry = e->geometry;
3416 s->d_func()->availableGeometry = e->availableGeometry;
3417
3418 s->d_func()->updatePrimaryOrientation();
3419 }
3420
3421 resetCachedDevicePixelRatio();
3422}
3423
3424void QGuiApplicationPrivate::processScreenLogicalDotsPerInchChange(QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *e)
3425{
3426 // This operation only makes sense after the QGuiApplication constructor runs
3427 if (QCoreApplication::startingUp())
3428 return;
3429
3430 QHighDpiScaling::updateHighDpiScaling();
3431
3432 if (!e->screen)
3433 return;
3434
3435 {
3436 QScreen *s = e->screen.data();
3437 QScreenPrivate::UpdateEmitter updateEmitter(s);
3438 s->d_func()->logicalDpi = QDpi(e->dpiX, e->dpiY);
3439 s->d_func()->updateGeometry();
3440 }
3441
3442 for (QWindow *window : QGuiApplication::allWindows())
3443 if (window->screen() == e->screen)
3444 QWindowPrivate::get(window)->updateDevicePixelRatio();
3445
3446 resetCachedDevicePixelRatio();
3447}
3448
3449void QGuiApplicationPrivate::processScreenRefreshRateChange(QWindowSystemInterfacePrivate::ScreenRefreshRateEvent *e)
3450{
3451 // This operation only makes sense after the QGuiApplication constructor runs
3452 if (QCoreApplication::startingUp())
3453 return;
3454
3455 if (!e->screen)
3456 return;
3457
3458 QScreen *s = e->screen.data();
3459 qreal rate = e->rate;
3460 // safeguard ourselves against buggy platform behavior...
3461 if (rate < 1.0)
3462 rate = 60.0;
3463 if (!qFuzzyCompare(s->d_func()->refreshRate, rate)) {
3464 s->d_func()->refreshRate = rate;
3465 emit s->refreshRateChanged(s->refreshRate());
3466 }
3467}
3468
3469void QGuiApplicationPrivate::processExposeEvent(QWindowSystemInterfacePrivate::ExposeEvent *e)
3470{
3471 if (!e->window)
3472 return;
3473
3474 QWindow *window = e->window.data();
3475 if (!window)
3476 return;
3477 QWindowPrivate *p = qt_window_private(window);
3478
3479 if (e->isExposed) {
3480 // If the window has been automatically positioned or resized by the
3481 // window manager, we now assume those have taken effect, even for
3482 // asynchronous window managers. From this point on we want the window
3483 // to keep its geometry, even when recreated.
3484 p->positionAutomatic = false;
3485 p->resizeAutomatic = false;
3486 }
3487
3488 if (!p->receivedExpose) {
3489 if (p->resizeEventPending) {
3490 // as a convenience for plugins, send a resize event before the first expose event if they haven't done so
3491 // window->geometry() should have a valid size as soon as a handle exists.
3492 QResizeEvent e(window->geometry().size(), p->geometry.size());
3493 QGuiApplication::sendSpontaneousEvent(window, &e);
3494
3495 p->resizeEventPending = false;
3496 }
3497
3498 // FIXME: It would logically make sense to set this _after_ we've sent the
3499 // expose event to the window, to mark that it now has received an expose.
3500 // But some parts of Qt (mis)use this private member to check whether the
3501 // window has been mapped yet, which they do in code that is triggered
3502 // by the very same expose event we send below. To keep the code working
3503 // we need to set the variable up front, until the code has been fixed.
3504 p->receivedExpose = true;
3505 }
3506
3507 // If the platform does not send paint events we need to synthesize them from expose events
3508 const bool shouldSynthesizePaintEvents = !platformIntegration()->hasCapability(QPlatformIntegration::PaintEvents);
3509
3510 const bool wasExposed = p->exposed;
3511 p->exposed = e->isExposed && window->screen();
3512
3513 // We expect that the platform plugins send DevicePixelRatioChange events.
3514 // As a fail-safe make a final check here to make sure the cached DPR value is
3515 // always up to date before sending the expose event.
3516 if (e->isExposed && !e->region.isEmpty()) {
3517 const bool dprWasChanged = QWindowPrivate::get(window)->updateDevicePixelRatio();
3518 if (dprWasChanged)
3519 qWarning() << "The cached device pixel ratio value was stale on window expose. "
3520 << "Please file a QTBUG which explains how to reproduce.";
3521 }
3522
3523 // We treat expose events for an already exposed window as paint events
3524 if (wasExposed && p->exposed && shouldSynthesizePaintEvents) {
3525 QPaintEvent paintEvent(e->region);
3526 QCoreApplication::sendSpontaneousEvent(window, &paintEvent);
3527 if (paintEvent.isAccepted())
3528 return; // No need to send expose
3529
3530 // The paint event was not accepted, so we fall through and send an expose
3531 // event instead, to maintain compatibility for clients that haven't adopted
3532 // paint events yet.
3533 }
3534
3535 QExposeEvent exposeEvent(e->region);
3536 QCoreApplication::sendSpontaneousEvent(window, &exposeEvent);
3537 e->eventAccepted = exposeEvent.isAccepted();
3538
3539 // If the window was just exposed we also need to send a paint event,
3540 // so that clients that implement paint events will draw something.
3541 // Note that we we can not skip this based on the expose event being
3542 // accepted, as clients may implement exposeEvent to track the state
3543 // change, but without drawing anything.
3544 if (!wasExposed && p->exposed && shouldSynthesizePaintEvents) {
3545 QPaintEvent paintEvent(e->region);
3546 QCoreApplication::sendSpontaneousEvent(window, &paintEvent);
3547 }
3548}
3549
3550void QGuiApplicationPrivate::processPaintEvent(QWindowSystemInterfacePrivate::PaintEvent *e)
3551{
3552 Q_ASSERT_X(platformIntegration()->hasCapability(QPlatformIntegration::PaintEvents), "QGuiApplication",
3553 "The platform sent paint events without claiming support for it in QPlatformIntegration::capabilities()");
3554
3555 if (!e->window)
3556 return;
3557
3558 QPaintEvent paintEvent(e->region);
3559 QCoreApplication::sendSpontaneousEvent(e->window, &paintEvent);
3560
3561 // We report back the accepted state to the platform, so that it can
3562 // decide when the best time to send the fallback expose event is.
3563 e->eventAccepted = paintEvent.isAccepted();
3564}
3565
3566#if QT_CONFIG(draganddrop)
3567
3568/*! \internal
3569
3570 This function updates an internal state to keep the source compatibility.
3571 ### Qt 6 - Won't need after QTBUG-73829
3572*/
3573static void updateMouseAndModifierButtonState(Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
3574{
3575 QGuiApplicationPrivate::mouse_buttons = buttons;
3576 QGuiApplicationPrivate::modifier_buttons = modifiers;
3577}
3578
3579QPlatformDragQtResponse QGuiApplicationPrivate::processDrag(QWindow *w, const QMimeData *dropData,
3580 const QPoint &p, Qt::DropActions supportedActions,
3581 Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
3582{
3583 updateMouseAndModifierButtonState(buttons, modifiers);
3584
3585 static Qt::DropAction lastAcceptedDropAction = Qt::IgnoreAction;
3586 QPlatformDrag *platformDrag = platformIntegration()->drag();
3587 if (!platformDrag || (w && w->d_func()->blockedByModalWindow)) {
3588 lastAcceptedDropAction = Qt::IgnoreAction;
3589 return QPlatformDragQtResponse(false, lastAcceptedDropAction, QRect());
3590 }
3591
3592 if (!dropData) {
3593 currentDragWindow = nullptr;
3594 QDragLeaveEvent e;
3595 QGuiApplication::sendEvent(w, &e);
3596 lastAcceptedDropAction = Qt::IgnoreAction;
3597 return QPlatformDragQtResponse(false, lastAcceptedDropAction, QRect());
3598 }
3599 QDragMoveEvent me(QPointF(p), supportedActions, dropData, buttons, modifiers);
3600
3601 if (w != currentDragWindow) {
3602 lastAcceptedDropAction = Qt::IgnoreAction;
3603 if (currentDragWindow) {
3604 QDragLeaveEvent e;
3605 QGuiApplication::sendEvent(currentDragWindow, &e);
3606 }
3607 currentDragWindow = w;
3608 QDragEnterEvent e(QPointF(p), supportedActions, dropData, buttons, modifiers);
3609 QGuiApplication::sendEvent(w, &e);
3610 if (e.isAccepted() && e.dropAction() != Qt::IgnoreAction)
3611 lastAcceptedDropAction = e.dropAction();
3612 }
3613
3614 // Handling 'DragEnter' should suffice for the application.
3615 if (lastAcceptedDropAction != Qt::IgnoreAction
3616 && (supportedActions & lastAcceptedDropAction)) {
3617 me.setDropAction(lastAcceptedDropAction);
3618 me.accept();
3619 }
3620 QGuiApplication::sendEvent(w, &me);
3621 lastAcceptedDropAction = me.isAccepted() ?
3622 me.dropAction() : Qt::IgnoreAction;
3623 return QPlatformDragQtResponse(me.isAccepted(), lastAcceptedDropAction, me.answerRect());
3624}
3625
3626QPlatformDropQtResponse QGuiApplicationPrivate::processDrop(QWindow *w, const QMimeData *dropData,
3627 const QPoint &p, Qt::DropActions supportedActions,
3628 Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
3629{
3630 updateMouseAndModifierButtonState(buttons, modifiers);
3631
3632 currentDragWindow = nullptr;
3633
3634 QDropEvent de(p, supportedActions, dropData, buttons, modifiers);
3635 QGuiApplication::sendEvent(w, &de);
3636
3637 Qt::DropAction acceptedAction = de.isAccepted() ? de.dropAction() : Qt::IgnoreAction;
3638 QPlatformDropQtResponse response(de.isAccepted(),acceptedAction);
3639 return response;
3640}
3641
3642#endif // QT_CONFIG(draganddrop)
3643
3644#ifndef QT_NO_CLIPBOARD
3645/*!
3646 Returns the object for interacting with the clipboard.
3647*/
3648QClipboard * QGuiApplication::clipboard()
3649{
3650 if (QGuiApplicationPrivate::qt_clipboard == nullptr) {
3651 if (!qApp) {
3652 qWarning("QGuiApplication: Must construct a QGuiApplication before accessing a QClipboard");
3653 return nullptr;
3654 }
3655 QGuiApplicationPrivate::qt_clipboard = new QClipboard(nullptr);
3656 }
3657 return QGuiApplicationPrivate::qt_clipboard;
3658}
3659#endif
3660
3661/*!
3662 \since 5.4
3663 \fn void QGuiApplication::paletteChanged(const QPalette &palette)
3664 \deprecated [6.0] Handle QEvent::ApplicationPaletteChange instead.
3665
3666 This signal is emitted when the \a palette of the application changes. Use
3667 QEvent::ApplicationPaletteChanged instead.
3668
3669 \sa palette()
3670*/
3671
3672/*!
3673 Returns the current application palette.
3674
3675 Roles that have not been explicitly set will reflect the system's platform theme.
3676
3677 \sa setPalette()
3678*/
3679
3680QPalette QGuiApplication::palette()
3681{
3682 if (!QGuiApplicationPrivate::app_pal)
3683 QGuiApplicationPrivate::updatePalette();
3684
3685 return *QGuiApplicationPrivate::app_pal;
3686}
3687
3688void QGuiApplicationPrivate::updatePalette()
3689{
3690 if (app_pal) {
3691 if (setPalette(*app_pal) && qGuiApp)
3692 qGuiApp->d_func()->handlePaletteChanged();
3693 } else {
3694 setPalette(QPalette());
3695 }
3696}
3697
3698QEvent::Type QGuiApplicationPrivate::contextMenuEventType()
3699{
3700 switch (QGuiApplication::styleHints()->contextMenuTrigger()) {
3701 case Qt::ContextMenuTrigger::Press: return QEvent::MouseButtonPress;
3702 case Qt::ContextMenuTrigger::Release: return QEvent::MouseButtonRelease;
3703 }
3704 return QEvent::None;
3705}
3706
3707void QGuiApplicationPrivate::clearPalette()
3708{
3709 delete app_pal;
3710 app_pal = nullptr;
3711}
3712
3713/*!
3714 Changes the application palette to \a pal.
3715
3716 The color roles from this palette are combined with the system's platform
3717 theme to form the application's final palette.
3718
3719 \sa palette()
3720*/
3721void QGuiApplication::setPalette(const QPalette &pal)
3722{
3723 if (QGuiApplicationPrivate::setPalette(pal) && qGuiApp)
3724 qGuiApp->d_func()->handlePaletteChanged();
3725}
3726
3727bool QGuiApplicationPrivate::setPalette(const QPalette &palette)
3728{
3729 // Resolve the palette against the theme palette, filling in
3730 // any missing roles, while keeping the original resolve mask.
3731 QPalette basePalette = qGuiApp ? qGuiApp->d_func()->basePalette() : Qt::gray;
3732 basePalette.setResolveMask(0); // The base palette only contributes missing colors roles
3733 QPalette resolvedPalette = palette.resolve(basePalette);
3734
3735 if (app_pal && resolvedPalette == *app_pal && resolvedPalette.resolveMask() == app_pal->resolveMask())
3736 return false;
3737
3738 if (!app_pal)
3739 app_pal = new QPalette(resolvedPalette);
3740 else
3741 *app_pal = resolvedPalette;
3742
3743 QCoreApplication::setAttribute(Qt::AA_SetPalette, app_pal->resolveMask() != 0);
3744
3745 return true;
3746}
3747
3748/*
3749 Returns the base palette used to fill in missing roles in
3750 the current application palette.
3751
3752 Normally this is the theme palette, but QApplication
3753 overrides this for compatibility reasons.
3754*/
3755QPalette QGuiApplicationPrivate::basePalette() const
3756{
3757 const auto pf = platformTheme();
3758 return pf && pf->palette() ? *pf->palette() : Qt::gray;
3759}
3760
3761void QGuiApplicationPrivate::handlePaletteChanged(const char *className)
3762{
3763#if QT_DEPRECATED_SINCE(6, 0)
3764 if (!className) {
3765 Q_ASSERT(app_pal);
3766QT_WARNING_PUSH
3767QT_WARNING_DISABLE_DEPRECATED
3768 emit qGuiApp->paletteChanged(*QGuiApplicationPrivate::app_pal);
3769QT_WARNING_POP
3770 }
3771#else
3772 Q_UNUSED(className);
3773#endif // QT_DEPRECATED_SINCE(6, 0)
3774
3775 if (is_app_running && !is_app_closing) {
3776 QEvent event(QEvent::ApplicationPaletteChange);
3777 QGuiApplication::sendEvent(qGuiApp, &event);
3778 }
3779}
3780
3781void QGuiApplicationPrivate::applyWindowGeometrySpecificationTo(QWindow *window)
3782{
3783 windowGeometrySpecification.applyTo(window);
3784}
3785
3786/*!
3787 \since 5.11
3788 \fn void QGuiApplication::fontChanged(const QFont &font)
3789 \deprecated [6.0] Handle QEvent::ApplicationFontChange instead.
3790
3791 This signal is emitted when the \a font of the application changes. Use
3792 QEvent::ApplicationFontChanged instead.
3793
3794 \sa font()
3795*/
3796
3797/*!
3798 Returns the default application font.
3799
3800 \sa setFont()
3801*/
3802QFont QGuiApplication::font()
3803{
3804 const auto locker = qt_scoped_lock(applicationFontMutex);
3805 if (!QGuiApplicationPrivate::instance() && !QGuiApplicationPrivate::app_font) {
3806 qWarning("QGuiApplication::font(): no QGuiApplication instance and no application font set.");
3807 return QFont(); // in effect: QFont((QFontPrivate*)nullptr), so no recursion
3808 }
3809 initFontUnlocked();
3810 return *QGuiApplicationPrivate::app_font;
3811}
3812
3813/*!
3814 Changes the default application font to \a font.
3815
3816 \sa font()
3817*/
3818void QGuiApplication::setFont(const QFont &font)
3819{
3820 auto locker = qt_unique_lock(applicationFontMutex);
3821 const bool emitChange = !QGuiApplicationPrivate::app_font
3822 || (*QGuiApplicationPrivate::app_font != font);
3823 if (!QGuiApplicationPrivate::app_font)
3824 QGuiApplicationPrivate::app_font = new QFont(font);
3825 else
3826 *QGuiApplicationPrivate::app_font = font;
3827 applicationResourceFlags |= ApplicationFontExplicitlySet;
3828
3829 if (emitChange && qGuiApp) {
3830 auto font = *QGuiApplicationPrivate::app_font;
3831 locker.unlock();
3832#if QT_DEPRECATED_SINCE(6, 0)
3833QT_WARNING_PUSH
3834QT_WARNING_DISABLE_DEPRECATED
3835 emit qGuiApp->fontChanged(font);
3836QT_WARNING_POP
3837#else
3838 Q_UNUSED(font);
3839#endif // QT_DEPRECATED_SINCE(6, 0)
3840 QEvent event(QEvent::ApplicationFontChange);
3841 QGuiApplication::sendEvent(qGuiApp, &event);
3842 }
3843}
3844
3845/*!
3846 \fn bool QGuiApplication::isRightToLeft()
3847
3848 Returns \c true if the application's layout direction is
3849 Qt::RightToLeft; otherwise returns \c false.
3850
3851 \sa layoutDirection(), isLeftToRight()
3852*/
3853
3854/*!
3855 \fn bool QGuiApplication::isLeftToRight()
3856
3857 Returns \c true if the application's layout direction is
3858 Qt::LeftToRight; otherwise returns \c false.
3859
3860 \sa layoutDirection(), isRightToLeft()
3861*/
3862
3863void QGuiApplicationPrivate::notifyLayoutDirectionChange()
3864{
3865 const QWindowList list = QGuiApplication::topLevelWindows();
3866 for (int i = 0; i < list.size(); ++i) {
3867 QEvent ev(QEvent::ApplicationLayoutDirectionChange);
3868 QCoreApplication::sendEvent(list.at(i), &ev);
3869 }
3870}
3871
3872void QGuiApplicationPrivate::notifyActiveWindowChange(QWindow *prev)
3873{
3874 if (prev) {
3875 QEvent de(QEvent::WindowDeactivate);
3876 QCoreApplication::sendEvent(prev, &de);
3877 }
3878 if (QGuiApplicationPrivate::instance()->focus_window) {
3879 QEvent ae(QEvent::WindowActivate);
3880 QCoreApplication::sendEvent(focus_window, &ae);
3881 }
3882}
3883
3884/*!
3885 \property QGuiApplication::windowIcon
3886 \brief the default window icon
3887
3888 \sa QWindow::setIcon(), {Setting the Application Icon}
3889*/
3890QIcon QGuiApplication::windowIcon()
3891{
3892 return QGuiApplicationPrivate::app_icon ? *QGuiApplicationPrivate::app_icon : QIcon();
3893}
3894
3895void QGuiApplication::setWindowIcon(const QIcon &icon)
3896{
3897 if (!QGuiApplicationPrivate::app_icon)
3898 QGuiApplicationPrivate::app_icon = new QIcon();
3899 *QGuiApplicationPrivate::app_icon = icon;
3900 if (QGuiApplicationPrivate::platform_integration
3901 && QGuiApplicationPrivate::platform_integration->hasCapability(QPlatformIntegration::ApplicationIcon))
3902 QGuiApplicationPrivate::platform_integration->setApplicationIcon(icon);
3903 if (QGuiApplicationPrivate::is_app_running && !QGuiApplicationPrivate::is_app_closing)
3904 QGuiApplicationPrivate::instance()->notifyWindowIconChanged();
3905}
3906
3907void QGuiApplicationPrivate::notifyWindowIconChanged()
3908{
3909 QEvent ev(QEvent::ApplicationWindowIconChange);
3910 const QWindowList list = QGuiApplication::topLevelWindows();
3911 for (int i = 0; i < list.size(); ++i)
3912 QCoreApplication::sendEvent(list.at(i), &ev);
3913}
3914
3915
3916
3917/*!
3918 \property QGuiApplication::quitOnLastWindowClosed
3919
3920 \brief whether the application implicitly quits when the last window is
3921 closed.
3922
3923 The default is \c true.
3924
3925 If this property is \c true, the application will attempt to
3926 quit when the last visible \l{Primary and Secondary Windows}{primary window}
3927 (i.e. top level window with no transient parent) is closed.
3928
3929 Note that attempting a quit may not necessarily result in the
3930 application quitting, for example if there still are active
3931 QEventLoopLocker instances, or the QEvent::Quit event is ignored.
3932
3933 \sa quit(), QWindow::close()
3934 */
3935
3936void QGuiApplication::setQuitOnLastWindowClosed(bool quit)
3937{
3938 QGuiApplicationPrivate::quitOnLastWindowClosed = quit;
3939}
3940
3941bool QGuiApplication::quitOnLastWindowClosed()
3942{
3943 return QGuiApplicationPrivate::quitOnLastWindowClosed;
3944}
3945
3946void QGuiApplicationPrivate::maybeLastWindowClosed()
3947{
3948 if (!lastWindowClosed())
3949 return;
3950
3951 if (in_exec)
3952 emit q_func()->lastWindowClosed();
3953
3954 if (quitOnLastWindowClosed && canQuitAutomatically())
3955 quitAutomatically();
3956}
3957
3958/*!
3959 \fn void QGuiApplication::lastWindowClosed()
3960
3961 This signal is emitted from exec() when the last visible
3962 \l{Primary and Secondary Windows}{primary window} (i.e.
3963 top level window with no transient parent) is closed.
3964
3965 By default, QGuiApplication quits after this signal is emitted. This feature
3966 can be turned off by setting \l quitOnLastWindowClosed to \c false.
3967
3968 \sa QWindow::close(), QWindow::isTopLevel(), QWindow::transientParent()
3969*/
3970
3971bool QGuiApplicationPrivate::lastWindowClosed() const
3972{
3973 for (auto *window : QGuiApplication::topLevelWindows()) {
3974 auto *windowPrivate = qt_window_private(window);
3975 if (!windowPrivate->participatesInLastWindowClosed())
3976 continue;
3977
3978 if (windowPrivate->treatAsVisible())
3979 return false;
3980 }
3981
3982 return true;
3983}
3984
3985bool QGuiApplicationPrivate::canQuitAutomatically()
3986{
3987 // The automatic quit functionality is triggered by
3988 // both QEventLoopLocker and maybeLastWindowClosed.
3989 // Although the former is a QCoreApplication feature
3990 // we don't want to quit the application when there
3991 // are open windows, regardless of whether the app
3992 // also quits automatically on maybeLastWindowClosed.
3993 if (!lastWindowClosed())
3994 return false;
3995
3996 return QCoreApplicationPrivate::canQuitAutomatically();
3997}
3998
3999void QGuiApplicationPrivate::quit()
4000{
4001 if (auto *platformIntegration = QGuiApplicationPrivate::platformIntegration())
4002 platformIntegration->quit();
4003 else
4004 QCoreApplicationPrivate::quit();
4005}
4006
4007void QGuiApplicationPrivate::processApplicationTermination(QWindowSystemInterfacePrivate::WindowSystemEvent *windowSystemEvent)
4008{
4009 QEvent event(QEvent::Quit);
4010 QGuiApplication::sendSpontaneousEvent(QGuiApplication::instance(), &event);
4011 windowSystemEvent->eventAccepted = event.isAccepted();
4012}
4013
4014/*!
4015 \since 5.2
4016 \fn Qt::ApplicationState QGuiApplication::applicationState()
4017
4018
4019 Returns the current state of the application.
4020
4021 You can react to application state changes to perform actions such as
4022 stopping/resuming CPU-intensive tasks, freeing/loading resources or
4023 saving/restoring application data.
4024 */
4025
4026Qt::ApplicationState QGuiApplication::applicationState()
4027{
4028 return QGuiApplicationPrivate::applicationState;
4029}
4030
4031/*!
4032 \since 5.14
4033
4034 Sets the high-DPI scale factor rounding policy for the application. The
4035 \a policy decides how non-integer scale factors (such as Windows 150%) are
4036 handled.
4037
4038 The two principal options are whether fractional scale factors should
4039 be rounded to an integer or not. Keeping the scale factor as-is will
4040 make the user interface size match the OS setting exactly, but may cause
4041 painting errors, for example with the Windows style.
4042
4043 If rounding is wanted, then which type of rounding should be decided
4044 next. Mathematically correct rounding is supported but may not give
4045 the best visual results: Consider if you want to render 1.5x as 1x
4046 ("small UI") or as 2x ("large UI"). See the Qt::HighDpiScaleFactorRoundingPolicy
4047 enum for a complete list of all options.
4048
4049 This function must be called before creating the application object.
4050 The QGuiApplication::highDpiScaleFactorRoundingPolicy()
4051 accessor will reflect the environment, if set.
4052
4053 The default value is Qt::HighDpiScaleFactorRoundingPolicy::PassThrough.
4054*/
4055void QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy policy)
4056{
4057 if (qApp)
4058 qWarning("setHighDpiScaleFactorRoundingPolicy must be called before creating the QGuiApplication instance");
4059 QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy = policy;
4060}
4061
4062/*!
4063 \since 5.14
4064
4065 Returns the high-DPI scale factor rounding policy.
4066*/
4067Qt::HighDpiScaleFactorRoundingPolicy QGuiApplication::highDpiScaleFactorRoundingPolicy()
4068{
4069 return QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy;
4070}
4071
4072/*!
4073 \since 5.2
4074 \fn void QGuiApplication::applicationStateChanged(Qt::ApplicationState state)
4075
4076 This signal is emitted when the \a state of the application changes.
4077
4078 \sa applicationState()
4079*/
4080
4081void QGuiApplicationPrivate::setApplicationState(Qt::ApplicationState state, bool forcePropagate)
4082{
4083 if ((applicationState == state) && !forcePropagate)
4084 return;
4085
4086 applicationState = state;
4087
4088 switch (state) {
4089 case Qt::ApplicationActive: {
4090 QEvent appActivate(QEvent::ApplicationActivate);
4091 QCoreApplication::sendSpontaneousEvent(qApp, &appActivate);
4092 break; }
4093 case Qt::ApplicationInactive: {
4094 QEvent appDeactivate(QEvent::ApplicationDeactivate);
4095 QCoreApplication::sendSpontaneousEvent(qApp, &appDeactivate);
4096 break; }
4097 default:
4098 break;
4099 }
4100
4101 QApplicationStateChangeEvent event(applicationState);
4102 QCoreApplication::sendSpontaneousEvent(qApp, &event);
4103
4104 emit qApp->applicationStateChanged(applicationState);
4105}
4106
4107/*!
4108 \since 4.2
4109 \fn void QGuiApplication::commitDataRequest(QSessionManager &manager)
4110
4111 This signal deals with \l{Session Management}{session management}. It is
4112 emitted when the QSessionManager wants the application to commit all its
4113 data.
4114
4115 Usually this means saving all open files, after getting permission from
4116 the user. Furthermore you may want to provide a means by which the user
4117 can cancel the shutdown.
4118
4119 You should not exit the application within this signal. Instead,
4120 the session manager may or may not do this afterwards, depending on the
4121 context.
4122
4123 \warning Within this signal, no user interaction is possible, \e
4124 unless you ask the \a manager for explicit permission. See
4125 QSessionManager::allowsInteraction() and
4126 QSessionManager::allowsErrorInteraction() for details and example
4127 usage.
4128
4129 \note You should use Qt::DirectConnection when connecting to this signal.
4130
4131 \sa isSessionRestored(), sessionId(), saveStateRequest(), {Session Management}
4132*/
4133
4134/*!
4135 \since 4.2
4136 \fn void QGuiApplication::saveStateRequest(QSessionManager &manager)
4137
4138 This signal deals with \l{Session Management}{session management}. It is
4139 invoked when the \l{QSessionManager}{session manager} wants the application
4140 to preserve its state for a future session.
4141
4142 For example, a text editor would create a temporary file that includes the
4143 current contents of its edit buffers, the location of the cursor and other
4144 aspects of the current editing session.
4145
4146 You should never exit the application within this signal. Instead, the
4147 session manager may or may not do this afterwards, depending on the
4148 context. Furthermore, most session managers will very likely request a saved
4149 state immediately after the application has been started. This permits the
4150 session manager to learn about the application's restart policy.
4151
4152 \warning Within this signal, no user interaction is possible, \e
4153 unless you ask the \a manager for explicit permission. See
4154 QSessionManager::allowsInteraction() and
4155 QSessionManager::allowsErrorInteraction() for details.
4156
4157 \note You should use Qt::DirectConnection when connecting to this signal.
4158
4159 \sa isSessionRestored(), sessionId(), commitDataRequest(), {Session Management}
4160*/
4161
4162/*!
4163 \fn bool QGuiApplication::isSessionRestored() const
4164
4165 Returns \c true if the application has been restored from an earlier
4166 \l{Session Management}{session}; otherwise returns \c false.
4167
4168 \sa sessionId(), commitDataRequest(), saveStateRequest()
4169*/
4170
4171/*!
4172 \since 5.0
4173 \fn bool QGuiApplication::isSavingSession() const
4174
4175 Returns \c true if the application is currently saving the
4176 \l{Session Management}{session}; otherwise returns \c false.
4177
4178 This is \c true when commitDataRequest() and saveStateRequest() are emitted,
4179 but also when the windows are closed afterwards by session management.
4180
4181 \sa sessionId(), commitDataRequest(), saveStateRequest()
4182*/
4183
4184/*!
4185 \fn QString QGuiApplication::sessionId() const
4186
4187 Returns the current \l{Session Management}{session's} identifier.
4188
4189 If the application has been restored from an earlier session, this
4190 identifier is the same as it was in that previous session. The session
4191 identifier is guaranteed to be unique both for different applications
4192 and for different instances of the same application.
4193
4194 \sa isSessionRestored(), sessionKey(), commitDataRequest(), saveStateRequest()
4195*/
4196
4197/*!
4198 \fn QString QGuiApplication::sessionKey() const
4199
4200 Returns the session key in the current \l{Session Management}{session}.
4201
4202 If the application has been restored from an earlier session, this key is
4203 the same as it was when the previous session ended.
4204
4205 The session key changes every time the session is saved. If the shutdown process
4206 is cancelled, another session key will be used when shutting down again.
4207
4208 \sa isSessionRestored(), sessionId(), commitDataRequest(), saveStateRequest()
4209*/
4210#ifndef QT_NO_SESSIONMANAGER
4211bool QGuiApplication::isSessionRestored() const
4212{
4213 Q_D(const QGuiApplication);
4214 return d->is_session_restored;
4215}
4216
4217QString QGuiApplication::sessionId() const
4218{
4219 Q_D(const QGuiApplication);
4220 return d->session_manager->sessionId();
4221}
4222
4223QString QGuiApplication::sessionKey() const
4224{
4225 Q_D(const QGuiApplication);
4226 return d->session_manager->sessionKey();
4227}
4228
4229bool QGuiApplication::isSavingSession() const
4230{
4231 Q_D(const QGuiApplication);
4232 return d->is_saving_session;
4233}
4234
4235void QGuiApplicationPrivate::commitData()
4236{
4237 Q_Q(QGuiApplication);
4238 is_saving_session = true;
4239 emit q->commitDataRequest(*session_manager);
4240 is_saving_session = false;
4241}
4242
4243
4244void QGuiApplicationPrivate::saveState()
4245{
4246 Q_Q(QGuiApplication);
4247 is_saving_session = true;
4248 emit q->saveStateRequest(*session_manager);
4249 is_saving_session = false;
4250}
4251#endif //QT_NO_SESSIONMANAGER
4252
4253/*!
4254 \since 5.2
4255
4256 Function that can be used to sync Qt state with the Window Systems state.
4257
4258 This function will first empty Qts events by calling QCoreApplication::processEvents(),
4259 then the platform plugin will sync up with the windowsystem, and finally Qts events
4260 will be delived by another call to QCoreApplication::processEvents();
4261
4262 This function is timeconsuming and its use is discouraged.
4263*/
4264void QGuiApplication::sync()
4265{
4266 QCoreApplication::processEvents();
4267 if (QGuiApplicationPrivate::platform_integration
4268 && QGuiApplicationPrivate::platform_integration->hasCapability(QPlatformIntegration::SyncState)) {
4269 QGuiApplicationPrivate::platform_integration->sync();
4270 QCoreApplication::processEvents();
4271 QWindowSystemInterface::flushWindowSystemEvents();
4272 }
4273}
4274
4275/*!
4276 \property QGuiApplication::layoutDirection
4277 \brief the default layout direction for this application
4278
4279 On system start-up, or when the direction is explicitly set to
4280 Qt::LayoutDirectionAuto, the default layout direction depends on the
4281 application's language.
4282
4283 The notifier signal was introduced in Qt 5.4.
4284
4285 \sa QWidget::layoutDirection, isLeftToRight(), isRightToLeft()
4286 */
4287
4288void QGuiApplication::setLayoutDirection(Qt::LayoutDirection direction)
4289{
4290 layout_direction = direction;
4291 if (direction == Qt::LayoutDirectionAuto)
4292 direction = qt_detectRTLLanguage() ? Qt::RightToLeft : Qt::LeftToRight;
4293
4294 // no change to the explicitly set or auto-detected layout direction
4295 if (direction == effective_layout_direction)
4296 return;
4297
4298 effective_layout_direction = direction;
4299 if (qGuiApp) {
4300 emit qGuiApp->layoutDirectionChanged(direction);
4301 QGuiApplicationPrivate::instance()->notifyLayoutDirectionChange();
4302 }
4303}
4304
4305Qt::LayoutDirection QGuiApplication::layoutDirection()
4306{
4307 /*
4308 effective_layout_direction defaults to Qt::LeftToRight, and is updated with what is
4309 auto-detected by a call to setLayoutDirection(Qt::LayoutDirectionAuto). This happens in
4310 QGuiApplicationPrivate::init and when the language changes (or before if the application
4311 calls the static function, but then no translators are installed so the auto-detection
4312 always yields Qt::LeftToRight).
4313 So we can be certain that it's always the right value.
4314 */
4315 return effective_layout_direction;
4316}
4317
4318/*!
4319 \fn QCursor *QGuiApplication::overrideCursor()
4320
4321 Returns the active application override cursor.
4322
4323 This function returns \nullptr if no application cursor has been defined (i.e. the
4324 internal cursor stack is empty).
4325
4326 \sa setOverrideCursor(), restoreOverrideCursor()
4327*/
4328#ifndef QT_NO_CURSOR
4329QCursor *QGuiApplication::overrideCursor()
4330{
4331 CHECK_QAPP_INSTANCE(nullptr)
4332 return qGuiApp->d_func()->cursor_list.isEmpty() ? nullptr : &qGuiApp->d_func()->cursor_list.first();
4333}
4334
4335/*!
4336 Changes the currently active application override cursor to \a cursor.
4337
4338 This function has no effect if setOverrideCursor() was not called.
4339
4340 \sa setOverrideCursor(), overrideCursor(), restoreOverrideCursor(),
4341 QWidget::setCursor()
4342 */
4343void QGuiApplication::changeOverrideCursor(const QCursor &cursor)
4344{
4346 if (qGuiApp->d_func()->cursor_list.isEmpty())
4347 return;
4348 qGuiApp->d_func()->cursor_list.removeFirst();
4349 setOverrideCursor(cursor);
4350}
4351#endif
4352
4353
4354#ifndef QT_NO_CURSOR
4355static inline void applyCursor(QWindow *w, QCursor c)
4356{
4357 if (const QScreen *screen = w->screen())
4358 if (QPlatformCursor *cursor = screen->handle()->cursor())
4359 cursor->changeCursor(&c, w);
4360}
4361
4362static inline void unsetCursor(QWindow *w)
4363{
4364 if (const QScreen *screen = w->screen())
4365 if (QPlatformCursor *cursor = screen->handle()->cursor())
4366 cursor->changeCursor(nullptr, w);
4367}
4368
4369static inline void applyCursor(const QList<QWindow *> &l, const QCursor &c)
4370{
4371 for (int i = 0; i < l.size(); ++i) {
4372 QWindow *w = l.at(i);
4373 if (w->handle())
4374 applyCursor(w, c);
4375 }
4376}
4377
4378static inline void applyOverrideCursor(const QList<QScreen *> &screens, const QCursor &c)
4379{
4380 for (QScreen *screen : screens) {
4381 if (QPlatformCursor *cursor = screen->handle()->cursor())
4382 cursor->setOverrideCursor(c);
4383 }
4384}
4385
4386static inline void clearOverrideCursor(const QList<QScreen *> &screens)
4387{
4388 for (QScreen *screen : screens) {
4389 if (QPlatformCursor *cursor = screen->handle()->cursor())
4390 cursor->clearOverrideCursor();
4391 }
4392}
4393
4394static inline void applyWindowCursor(const QList<QWindow *> &l)
4395{
4396 for (int i = 0; i < l.size(); ++i) {
4397 QWindow *w = l.at(i);
4398 if (w->handle()) {
4399 if (qt_window_private(w)->hasCursor) {
4400 applyCursor(w, w->cursor());
4401 } else {
4402 unsetCursor(w);
4403 }
4404 }
4405 }
4406}
4407
4408/*!
4409 \fn void QGuiApplication::setOverrideCursor(const QCursor &cursor)
4410
4411 Sets the application override cursor to \a cursor.
4412
4413 Application override cursors are intended for showing the user that the
4414 application is in a special state, for example during an operation that
4415 might take some time.
4416
4417 This cursor will be displayed in all the application's widgets until
4418 restoreOverrideCursor() or another setOverrideCursor() is called.
4419
4420 Application cursors are stored on an internal stack. setOverrideCursor()
4421 pushes the cursor onto the stack, and restoreOverrideCursor() pops the
4422 active cursor off the stack. changeOverrideCursor() changes the currently
4423 active application override cursor.
4424
4425 Every setOverrideCursor() must eventually be followed by a corresponding
4426 restoreOverrideCursor(), otherwise the stack will never be emptied.
4427
4428 Example:
4429 \snippet code/src_gui_kernel_qguiapplication_x11.cpp 0
4430
4431 \sa overrideCursor(), restoreOverrideCursor(), changeOverrideCursor(),
4432 QWidget::setCursor()
4433*/
4434void QGuiApplication::setOverrideCursor(const QCursor &cursor)
4435{
4437 qGuiApp->d_func()->cursor_list.prepend(cursor);
4438 if (QPlatformCursor::capabilities().testFlag(QPlatformCursor::OverrideCursor))
4439 applyOverrideCursor(QGuiApplicationPrivate::screen_list, cursor);
4440 else
4441 applyCursor(QGuiApplicationPrivate::window_list, cursor);
4442}
4443
4444/*!
4445 \fn void QGuiApplication::restoreOverrideCursor()
4446
4447 Undoes the last setOverrideCursor().
4448
4449 If setOverrideCursor() has been called twice, calling
4450 restoreOverrideCursor() will activate the first cursor set. Calling this
4451 function a second time restores the original widgets' cursors.
4452
4453 \sa setOverrideCursor(), overrideCursor()
4454*/
4455void QGuiApplication::restoreOverrideCursor()
4456{
4458 if (qGuiApp->d_func()->cursor_list.isEmpty())
4459 return;
4460 qGuiApp->d_func()->cursor_list.removeFirst();
4461 if (qGuiApp->d_func()->cursor_list.size() > 0) {
4462 QCursor c(qGuiApp->d_func()->cursor_list.value(0));
4463 if (QPlatformCursor::capabilities().testFlag(QPlatformCursor::OverrideCursor))
4464 applyOverrideCursor(QGuiApplicationPrivate::screen_list, c);
4465 else
4466 applyCursor(QGuiApplicationPrivate::window_list, c);
4467 } else {
4468 if (QPlatformCursor::capabilities().testFlag(QPlatformCursor::OverrideCursor))
4469 clearOverrideCursor(QGuiApplicationPrivate::screen_list);
4470 applyWindowCursor(QGuiApplicationPrivate::window_list);
4471 }
4472}
4473#endif// QT_NO_CURSOR
4474
4475/*!
4476 Returns the application's style hints.
4477
4478 The style hints encapsulate a set of platform dependent properties
4479 such as double click intervals, full width selection and others.
4480
4481 The hints can be used to integrate tighter with the underlying platform.
4482
4483 \sa QStyleHints
4484 */
4485QStyleHints *QGuiApplication::styleHints()
4486{
4487 if (!QGuiApplicationPrivate::styleHints)
4488 QGuiApplicationPrivate::styleHints = new QStyleHints();
4489 return QGuiApplicationPrivate::styleHints;
4490}
4491
4492/*!
4493 Sets whether Qt should use the system's standard colors, fonts, etc., to
4494 \a on. By default, this is \c true.
4495
4496 This function must be called before creating the QGuiApplication object, like
4497 this:
4498
4499 \snippet code/src_gui_kernel_qguiapplication.cpp 0
4500
4501 \sa desktopSettingsAware()
4502*/
4503void QGuiApplication::setDesktopSettingsAware(bool on)
4504{
4505 QGuiApplicationPrivate::obey_desktop_settings = on;
4506}
4507
4508/*!
4509 Returns \c true if Qt is set to use the system's standard colors, fonts, etc.;
4510 otherwise returns \c false. The default is \c true.
4511
4512 \sa setDesktopSettingsAware()
4513*/
4514bool QGuiApplication::desktopSettingsAware()
4515{
4516 return QGuiApplicationPrivate::obey_desktop_settings;
4517}
4518
4519/*!
4520 returns the input method.
4521
4522 The input method returns properties about the state and position of
4523 the virtual keyboard. It also provides information about the position of the
4524 current focused input element.
4525
4526 \sa QInputMethod
4527 */
4528QInputMethod *QGuiApplication::inputMethod()
4529{
4530 CHECK_QAPP_INSTANCE(nullptr)
4531 if (!qGuiApp->d_func()->inputMethod)
4532 qGuiApp->d_func()->inputMethod = new QInputMethod();
4533 return qGuiApp->d_func()->inputMethod;
4534}
4535
4536/*!
4537 \fn void QGuiApplication::fontDatabaseChanged()
4538
4539 This signal is emitted when the available fonts have changed.
4540
4541 This can happen when application fonts are added or removed, or when the
4542 system fonts change.
4543
4544 \sa QFontDatabase::addApplicationFont(),
4545 QFontDatabase::addApplicationFontFromData(),
4546 QFontDatabase::removeAllApplicationFonts(),
4547 QFontDatabase::removeApplicationFont()
4548*/
4549
4550QPixmap QGuiApplicationPrivate::getPixmapCursor(Qt::CursorShape cshape)
4551{
4552 Q_UNUSED(cshape);
4553 return QPixmap();
4554}
4555
4556QPoint QGuiApplicationPrivate::QLastCursorPosition::toPoint() const noexcept
4557{
4558 // Guard against the default initialization of qInf() (avoid UB or SIGFPE in conversion).
4559 if (Q_UNLIKELY(qIsInf(thePoint.x())))
4560 return QPoint(std::numeric_limits<int>::max(), std::numeric_limits<int>::max());
4561 return thePoint.toPoint();
4562}
4563
4564#if QT_CONFIG(draganddrop)
4565void QGuiApplicationPrivate::notifyDragStarted(const QDrag *drag)
4566{
4567 Q_UNUSED(drag);
4568
4569}
4570#endif
4571
4572const QColorTrcLut *QGuiApplicationPrivate::colorProfileForA8Text()
4573{
4574#ifdef Q_OS_WIN
4575 if (!m_a8ColorProfile)
4576 m_a8ColorProfile = QColorTrcLut::fromGamma(2.31f); // This is a hard-coded thing for Windows text rendering
4577 return m_a8ColorProfile.get();
4578#else
4579 return colorProfileForA32Text();
4580#endif
4581}
4582
4583const QColorTrcLut *QGuiApplicationPrivate::colorProfileForA32Text()
4584{
4585 if (!m_a32ColorProfile)
4586 m_a32ColorProfile = QColorTrcLut::fromGamma(float(fontSmoothingGamma));
4587 return m_a32ColorProfile.get();
4588}
4589
4590void QGuiApplicationPrivate::_q_updateFocusObject(QObject *object)
4591{
4592 Q_Q(QGuiApplication);
4593
4594 QPlatformInputContext *inputContext = platformIntegration()->inputContext();
4595 const bool enabled = inputContext && QInputMethodPrivate::objectAcceptsInputMethod(object);
4596
4597 QPlatformInputContextPrivate::setInputMethodAccepted(enabled);
4598 if (inputContext)
4599 inputContext->setFocusObject(object);
4600 emit q->focusObjectChanged(object);
4601}
4602
4603enum MouseMasks {
4604 MouseCapsMask = 0xFF,
4605 MouseSourceMaskDst = 0xFF00,
4606 MouseSourceMaskSrc = MouseCapsMask,
4607 MouseSourceShift = 8,
4608 MouseFlagsCapsMask = 0xFF0000,
4609 MouseFlagsShift = 16
4610};
4611
4612QInputDeviceManager *QGuiApplicationPrivate::inputDeviceManager()
4613{
4614 Q_ASSERT(QGuiApplication::instance());
4615
4616 if (!m_inputDeviceManager)
4617 m_inputDeviceManager = new QInputDeviceManager(QGuiApplication::instance());
4618
4619 return m_inputDeviceManager;
4620}
4621
4622/*!
4623 Returns the QThreadPool instance for Qt Gui.
4624 \internal
4625*/
4626QThreadPool *QGuiApplicationPrivate::qtGuiThreadPool()
4627{
4628#if QT_CONFIG(qtgui_threadpool)
4629 Q_CONSTINIT static QPointer<QThreadPool> guiInstance;
4630 Q_CONSTINIT static QBasicMutex theMutex;
4631 const static bool runtime_disable = qEnvironmentVariableIsSet("QT_NO_GUI_THREADPOOL");
4632 if (runtime_disable)
4633 return nullptr;
4634 const QMutexLocker locker(&theMutex);
4635 if (guiInstance.isNull() && !QCoreApplication::closingDown()) {
4636 guiInstance = new QThreadPool();
4637 // Limit max thread to avoid too many parallel threads.
4638 // We are not optimized for much more than 4 or 8 threads.
4639 if (guiInstance && guiInstance->maxThreadCount() > 4)
4640 guiInstance->setMaxThreadCount(qBound(4, guiInstance->maxThreadCount() / 2, 8));
4641 }
4642 return guiInstance;
4643#else
4644 return nullptr;
4645#endif
4646}
4647
4648/*!
4649 \fn template <typename QNativeInterface> QNativeInterface *QGuiApplication::nativeInterface() const
4650
4651 Returns a native interface of the given type for the application.
4652
4653 This function provides access to platform specific functionality
4654 of QGuiApplication, as defined in the QNativeInterface namespace:
4655
4656 \annotatedlist native-interfaces-qguiapplication
4657
4658 If the requested interface is not available a \nullptr is returned.
4659 */
4660
4661void *QGuiApplication::resolveInterface(const char *name, int revision) const
4662{
4663 using namespace QNativeInterface;
4664 using namespace QNativeInterface::Private;
4665
4666 auto *platformIntegration = QGuiApplicationPrivate::platformIntegration();
4667 Q_UNUSED(platformIntegration);
4668
4669#if defined(Q_OS_WIN)
4670 QT_NATIVE_INTERFACE_RETURN_IF(QWindowsApplication, platformIntegration);
4671#endif
4672#if QT_CONFIG(xcb)
4673 QT_NATIVE_INTERFACE_RETURN_IF(QX11Application, platformNativeInterface());
4674#endif
4675#if QT_CONFIG(wayland)
4676 QT_NATIVE_INTERFACE_RETURN_IF(QWaylandApplication, platformNativeInterface());
4677#endif
4678#if defined(Q_OS_VISIONOS)
4679 QT_NATIVE_INTERFACE_RETURN_IF(QVisionOSApplication, platformIntegration);
4680#endif
4681
4682 return QCoreApplication::resolveInterface(name, revision);
4683}
4684
4685QT_END_NAMESPACE
4686
4687#include "moc_qguiapplication.cpp"
The QClipboard class provides access to the window system clipboard.
Definition qclipboard.h:21
\reentrant
Definition qfont.h:23
The QIcon class provides scalable icons in different modes and states.
Definition qicon.h: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)