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

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