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