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