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

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