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