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