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