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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtbase/src/gui/kernel/qguiapplication.cpp