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