Coverage Report

Created: 2026-10-14 06:45

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