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

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