Coverage Report

Created: 2026-02-26 07:48

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