1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qplatformdefs.h"
41 #include "qabstracteventdispatcher.h"
42 #include "qapplication.h"
43 #include "qclipboard.h"
44 #include "qcursor.h"
45 #include "qdesktopwidget.h"
46 #include "qdir.h"
47 #include "qevent.h"
48 #include "qfile.h"
49 #include "qfileinfo.h"
50 #if QT_CONFIG(graphicsview)
51 #include "qgraphicsscene.h"
52 #include <QtWidgets/qgraphicsproxywidget.h>
53 #endif
54 #include "qhash.h"
55 #include "qset.h"
56 #include "qlayout.h"
57 #include "qpixmapcache.h"
58 #include "qstyle.h"
59 #include "qstyleoption.h"
60 #include "qstylefactory.h"
61 #include "qtooltip.h"
62 #include "qtranslator.h"
63 #include "qvariant.h"
64 #include "qwidget.h"
65 #if QT_CONFIG(draganddrop)
66 #include <private/qdnd_p.h>
67 #endif
68 #include "private/qguiapplication_p.h"
69 #include "qcolormap.h"
70 #include "qdebug.h"
71 #include "private/qstylesheetstyle_p.h"
72 #include "private/qstyle_p.h"
73 #if QT_CONFIG(messagebox)
74 #include "qmessagebox.h"
75 #endif
76 #include "qwidgetwindow_p.h"
77 #include <QtGui/qstylehints.h>
78 #include <QtGui/qinputmethod.h>
79 #include <QtGui/private/qwindow_p.h>
80 #include <QtGui/qtouchdevice.h>
81 #include <qpa/qplatformtheme.h>
82 #if QT_CONFIG(whatsthis)
83 #include <QtWidgets/QWhatsThis>
84 #endif
85 
86 #include "private/qkeymapper_p.h"
87 #include "private/qaccessiblewidgetfactory_p.h"
88 
89 #include <qthread.h>
90 #include <private/qthread_p.h>
91 
92 #include <private/qfont_p.h>
93 
94 #include <stdlib.h>
95 
96 #include "qapplication_p.h"
97 #include "private/qevent_p.h"
98 #include "qwidget_p.h"
99 
100 #include "qgesture.h"
101 #include "private/qgesturemanager_p.h"
102 #include <qpa/qplatformfontdatabase.h>
103 
104 #ifdef Q_OS_WIN
105 #include <QtCore/qt_windows.h> // for qt_win_display_dc()
106 #endif
107 
108 #include "qdatetime.h"
109 
110 #include <qpa/qplatformwindow.h>
111 
112 #include <qtwidgets_tracepoints_p.h>
113 
114 #include <algorithm>
115 #include <iterator>
116 
117 //#define ALIEN_DEBUG
118 
initResources()119 static void initResources()
120 {
121     Q_INIT_RESOURCE(qstyle);
122 
123 #if QT_CONFIG(messagebox)
124     Q_INIT_RESOURCE(qmessagebox);
125 #endif
126 }
127 
128 QT_BEGIN_NAMESPACE
129 
130 // Helper macro for static functions to check on the existence of the application class.
131 #define CHECK_QAPP_INSTANCE(...) \
132     if (Q_LIKELY(QCoreApplication::instance())) { \
133     } else { \
134         qWarning("Must construct a QApplication first."); \
135         return __VA_ARGS__; \
136     }
137 
138 Q_CORE_EXPORT void qt_call_post_routines();
139 Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, const QString &text = QString(), bool autorep = false, ushort count = 1);
140 
141 QApplicationPrivate *QApplicationPrivate::self = nullptr;
142 
143 bool QApplicationPrivate::autoSipEnabled = true;
144 
QApplicationPrivate(int & argc,char ** argv,int flags)145 QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, int flags)
146     : QApplicationPrivateBase(argc, argv, flags)
147 {
148     application_type = QApplicationPrivate::Gui;
149 
150 #ifndef QT_NO_GESTURES
151     gestureManager = nullptr;
152     gestureWidget = nullptr;
153 #endif // QT_NO_GESTURES
154 
155     if (!self)
156         self = this;
157 }
158 
~QApplicationPrivate()159 QApplicationPrivate::~QApplicationPrivate()
160 {
161     if (self == this)
162         self = nullptr;
163 }
164 
createEventDispatcher()165 void QApplicationPrivate::createEventDispatcher()
166 {
167     QGuiApplicationPrivate::createEventDispatcher();
168 }
169 
170 /*!
171     \class QApplication
172     \brief The QApplication class manages the GUI application's control
173     flow and main settings.
174 
175     \inmodule QtWidgets
176 
177     QApplication specializes QGuiApplication with some functionality needed
178     for QWidget-based applications. It handles widget specific initialization,
179     finalization.
180 
181     For any GUI application using Qt, there is precisely \b one QApplication
182     object, no matter whether the application has 0, 1, 2 or more windows at
183     any given time. For non-QWidget based Qt applications, use QGuiApplication instead,
184     as it does not depend on the \l QtWidgets library.
185 
186     Some GUI applications provide a special batch mode ie. provide command line
187     arguments for executing tasks without manual intervention. In such non-GUI
188     mode, it is often sufficient to instantiate a plain QCoreApplication to
189     avoid unnecessarily initializing resources needed for a graphical user
190     interface. The following example shows how to dynamically create an
191     appropriate type of application instance:
192 
193     \snippet code/src_gui_kernel_qapplication.cpp 0
194 
195     The QApplication object is accessible through the instance() function that
196     returns a pointer equivalent to the global qApp pointer.
197 
198     QApplication's main areas of responsibility are:
199         \list
200             \li  It initializes the application with the user's desktop settings
201                 such as palette(), font() and doubleClickInterval(). It keeps
202                 track of these properties in case the user changes the desktop
203                 globally, for example through some kind of control panel.
204 
205             \li  It performs event handling, meaning that it receives events
206                 from the underlying window system and dispatches them to the
207                 relevant widgets. By using sendEvent() and postEvent() you can
208                 send your own events to widgets.
209 
210             \li  It parses common command line arguments and sets its internal
211                 state accordingly. See the \l{QApplication::QApplication()}
212                 {constructor documentation} below for more details.
213 
214             \li  It defines the application's look and feel, which is
215                 encapsulated in a QStyle object. This can be changed at runtime
216                 with setStyle().
217 
218             \li  It provides localization of strings that are visible to the
219                 user via translate().
220 
221             \li  It provides some magical objects like the desktop() and the
222                 clipboard().
223 
224             \li  It knows about the application's windows. You can ask which
225                 widget is at a certain position using widgetAt(), get a list of
226                 topLevelWidgets() and closeAllWindows(), etc.
227 
228             \li  It manages the application's mouse cursor handling, see
229                 setOverrideCursor()
230         \endlist
231 
232     Since the QApplication object does so much initialization, it \e{must} be
233     created before any other objects related to the user interface are created.
234     QApplication also deals with common command line arguments. Hence, it is
235     usually a good idea to create it \e before any interpretation or
236     modification of \c argv is done in the application itself.
237 
238     \table
239     \header
240         \li{2,1} Groups of functions
241 
242         \row
243         \li  System settings
244         \li  desktopSettingsAware(),
245             setDesktopSettingsAware(),
246             cursorFlashTime(),
247             setCursorFlashTime(),
248             doubleClickInterval(),
249             setDoubleClickInterval(),
250             setKeyboardInputInterval(),
251             wheelScrollLines(),
252             setWheelScrollLines(),
253             palette(),
254             setPalette(),
255             font(),
256             setFont(),
257             fontMetrics().
258 
259         \row
260         \li  Event handling
261         \li  exec(),
262             processEvents(),
263             exit(),
264             quit().
265             sendEvent(),
266             postEvent(),
267             sendPostedEvents(),
268             removePostedEvents(),
269             hasPendingEvents(),
270             notify().
271 
272         \row
273         \li  GUI Styles
274         \li  style(),
275             setStyle().
276 
277         \row
278         \li  Text handling
279         \li  installTranslator(),
280             removeTranslator()
281             translate().
282 
283         \row
284         \li  Widgets
285         \li  allWidgets(),
286             topLevelWidgets(),
287             desktop(),
288             activePopupWidget(),
289             activeModalWidget(),
290             clipboard(),
291             focusWidget(),
292             activeWindow(),
293             widgetAt().
294 
295         \row
296         \li  Advanced cursor handling
297         \li  overrideCursor(),
298             setOverrideCursor(),
299             restoreOverrideCursor().
300 
301         \row
302         \li  Miscellaneous
303         \li  closeAllWindows(),
304             startingUp(),
305             closingDown().
306     \endtable
307 
308     \sa QCoreApplication, QAbstractEventDispatcher, QEventLoop, QSettings
309 */
310 
311 #if QT_DEPRECATED_SINCE(5, 8)
312 // ### fixme: Qt 6: Remove ColorSpec and accessors.
313 /*!
314     \enum QApplication::ColorSpec
315     \obsolete
316 
317     \value NormalColor the default color allocation policy
318     \value CustomColor the same as NormalColor for X11; allocates colors
319     to a palette on demand under Windows
320     \value ManyColor the right choice for applications that use thousands of
321     colors
322 
323     See setColorSpec() for full details.
324 */
325 #endif
326 
327 /*!
328     \fn QWidget *QApplication::topLevelAt(const QPoint &point)
329 
330     Returns the top-level widget at the given \a point; returns \nullptr if
331     there is no such widget.
332 */
topLevelAt(const QPoint & pos)333 QWidget *QApplication::topLevelAt(const QPoint &pos)
334 {
335     if (const QWindow *window = QGuiApplication::topLevelAt(pos)) {
336         if (const QWidgetWindow *widgetWindow = qobject_cast<const QWidgetWindow *>(window))
337             return widgetWindow->widget();
338     }
339     return nullptr;
340 }
341 
342 /*!
343     \fn QWidget *QApplication::topLevelAt(int x, int y)
344 
345     \overload
346 
347     Returns the top-level widget at the point (\a{x}, \a{y}); returns
348     0 if there is no such widget.
349 */
350 
351 void qt_init_tooltip_palette();
352 void qt_cleanup();
353 
354 QStyle *QApplicationPrivate::app_style = nullptr;        // default application style
355 #ifndef QT_NO_STYLE_STYLESHEET
356 QString QApplicationPrivate::styleSheet;           // default application stylesheet
357 #endif
358 QPointer<QWidget> QApplicationPrivate::leaveAfterRelease = nullptr;
359 
360 QFont *QApplicationPrivate::sys_font = nullptr;        // default system font
361 QFont *QApplicationPrivate::set_font = nullptr;        // default font set by programmer
362 
363 QWidget *QApplicationPrivate::main_widget = nullptr;        // main application widget
364 QWidget *QApplicationPrivate::focus_widget = nullptr;        // has keyboard input focus
365 QWidget *QApplicationPrivate::hidden_focus_widget = nullptr; // will get keyboard input focus after show()
366 QWidget *QApplicationPrivate::active_window = nullptr;        // toplevel with keyboard focus
367 #if QT_CONFIG(wheelevent)
368 QPointer<QWidget> QApplicationPrivate::wheel_widget;
369 #endif
370 bool qt_in_tab_key_event = false;
371 int qt_antialiasing_threshold = -1;
372 QSize QApplicationPrivate::app_strut = QSize(0,0); // no default application strut
373 int QApplicationPrivate::enabledAnimations = QPlatformTheme::GeneralUiEffect;
374 bool QApplicationPrivate::widgetCount = false;
375 #ifdef QT_KEYPAD_NAVIGATION
376 Qt::NavigationMode QApplicationPrivate::navigationMode = Qt::NavigationModeKeypadTabOrder;
377 QWidget *QApplicationPrivate::oldEditFocus = 0;
378 #endif
379 
isAlien(QWidget * widget)380 inline bool QApplicationPrivate::isAlien(QWidget *widget)
381 {
382     return widget && !widget->isWindow();
383 }
384 
qt_tab_all_widgets()385 bool Q_WIDGETS_EXPORT qt_tab_all_widgets()
386 {
387     return QGuiApplication::styleHints()->tabFocusBehavior() == Qt::TabFocusAllControls;
388 }
389 
390 // ######## move to QApplicationPrivate
391 // Default fonts (per widget type)
Q_GLOBAL_STATIC(FontHash,app_fonts)392 Q_GLOBAL_STATIC(FontHash, app_fonts)
393 // Exported accessor for use outside of this file
394 FontHash *qt_app_fonts_hash() { return app_fonts(); }
395 
396 QWidgetList *QApplicationPrivate::popupWidgets = nullptr;        // has keyboard input focus
397 
398 QDesktopWidget *qt_desktopWidget = nullptr;                // root window widgets
399 
400 /*!
401     \internal
402 */
process_cmdline()403 void QApplicationPrivate::process_cmdline()
404 {
405     if (styleOverride.isEmpty() && qEnvironmentVariableIsSet("QT_STYLE_OVERRIDE"))
406         styleOverride = QString::fromLocal8Bit(qgetenv("QT_STYLE_OVERRIDE"));
407 
408     // process platform-indep command line
409     if (!qt_is_gui_used || !argc)
410         return;
411 
412     int i, j;
413 
414     j = 1;
415     for (i=1; i<argc; i++) { // if you add anything here, modify QCoreApplication::arguments()
416         if (!argv[i])
417             continue;
418         if (*argv[i] != '-') {
419             argv[j++] = argv[i];
420             continue;
421         }
422         const char *arg = argv[i];
423         if (arg[1] == '-') // startsWith("--")
424             ++arg;
425         if (strcmp(arg, "-qdevel") == 0 || strcmp(arg, "-qdebug") == 0) {
426             // obsolete argument
427 #ifndef QT_NO_STYLE_STYLESHEET
428         } else if (strcmp(arg, "-stylesheet") == 0 && i < argc -1) {
429             styleSheet = QLatin1String("file:///");
430             styleSheet.append(QString::fromLocal8Bit(argv[++i]));
431         } else if (strncmp(arg, "-stylesheet=", 12) == 0) {
432             styleSheet = QLatin1String("file:///");
433             styleSheet.append(QString::fromLocal8Bit(arg + 12));
434 #endif
435         } else if (qstrcmp(arg, "-widgetcount") == 0) {
436             widgetCount = true;
437         } else {
438             argv[j++] = argv[i];
439         }
440     }
441 
442     if(j < argc) {
443         argv[j] = nullptr;
444         argc = j;
445     }
446 }
447 
448 /*!
449     Initializes the window system and constructs an application object with
450     \a argc command line arguments in \a argv.
451 
452     \warning The data referred to by \a argc and \a argv must stay valid for
453     the entire lifetime of the QApplication object. In addition, \a argc must
454     be greater than zero and \a argv must contain at least one valid character
455     string.
456 
457     The global \c qApp pointer refers to this application object. Only one
458     application object should be created.
459 
460     This application object must be constructed before any \l{QPaintDevice}
461     {paint devices} (including widgets, pixmaps, bitmaps etc.).
462 
463     \note \a argc and \a argv might be changed as Qt removes command line
464     arguments that it recognizes.
465 
466     All Qt programs automatically support the following command line options:
467     \list
468         \li  -style= \e style, sets the application GUI style. Possible values
469             depend on your system configuration. If you compiled Qt with
470             additional styles or have additional styles as plugins these will
471             be available to the \c -style command line option.  You can also
472             set the style for all Qt applications by setting the
473             \c QT_STYLE_OVERRIDE environment variable.
474         \li  -style \e style, is the same as listed above.
475         \li  -stylesheet= \e stylesheet, sets the application \l styleSheet. The
476             value must be a path to a file that contains the Style Sheet.
477             \note Relative URLs in the Style Sheet file are relative to the
478             Style Sheet file's path.
479         \li  -stylesheet \e stylesheet, is the same as listed above.
480         \li  -widgetcount, prints debug message at the end about number of
481             widgets left undestroyed and maximum number of widgets existed at
482             the same time
483         \li  -reverse, sets the application's layout direction to
484             Qt::RightToLeft
485         \li  -qmljsdebugger=, activates the QML/JS debugger with a specified port.
486             The value must be of format port:1234[,block], where block is optional
487             and will make the application wait until a debugger connects to it.
488     \endlist
489 
490     \sa QCoreApplication::arguments()
491 */
492 
493 #ifdef Q_QDOC
QApplication(int & argc,char ** argv)494 QApplication::QApplication(int &argc, char **argv)
495 #else
496 QApplication::QApplication(int &argc, char **argv, int _internal)
497 #endif
498     : QGuiApplication(*new QApplicationPrivate(argc, argv, _internal))
499 {
500     Q_D(QApplication);
501     d->init();
502 }
503 
504 /*!
505     \internal
506 */
init()507 void QApplicationPrivate::init()
508 {
509 #if defined(Q_OS_MACOS)
510     QMacAutoReleasePool pool;
511 #endif
512 
513     QGuiApplicationPrivate::init();
514 
515     initResources();
516 
517     qt_is_gui_used = (application_type != QApplicationPrivate::Tty);
518     process_cmdline();
519 
520     // Must be called before initialize()
521     QColormap::initialize();
522     initializeWidgetPalettesFromTheme();
523     qt_init_tooltip_palette();
524     QApplicationPrivate::initializeWidgetFontHash();
525 
526     initialize();
527     eventDispatcher->startingUp();
528 
529 #ifndef QT_NO_ACCESSIBILITY
530     // factory for accessible interfaces for widgets shipped with Qt
531     QAccessible::installFactory(&qAccessibleFactory);
532 #endif
533 
534 }
535 
qt_init_tooltip_palette()536 void qt_init_tooltip_palette()
537 {
538 #ifndef QT_NO_TOOLTIP
539     if (const QPalette *toolTipPalette = QGuiApplicationPrivate::platformTheme()->palette(QPlatformTheme::ToolTipPalette))
540         QToolTip::setPalette(*toolTipPalette);
541 #endif
542 }
543 
544 #if QT_CONFIG(statemachine)
545 void qRegisterGuiStateMachine();
546 void qUnregisterGuiStateMachine();
547 #endif
548 extern void qRegisterWidgetsVariant();
549 
550 /*!
551   \fn void QApplicationPrivate::initialize()
552 
553   Initializes the QApplication object, called from the constructors.
554 */
initialize()555 void QApplicationPrivate::initialize()
556 {
557     is_app_running = false; // Starting up.
558 
559     QWidgetPrivate::mapper = new QWidgetMapper;
560     QWidgetPrivate::allWidgets = new QWidgetSet;
561 
562     // needed for a static build.
563     qRegisterWidgetsVariant();
564 
565     // needed for widgets in QML
566     QAbstractDeclarativeData::setWidgetParent = QWidgetPrivate::setWidgetParentHelper;
567 
568     if (application_type != QApplicationPrivate::Tty) {
569         if (!styleOverride.isEmpty()) {
570             if (auto *style = QStyleFactory::create(styleOverride.toLower())) {
571                 QApplication::setStyle(style);
572             } else {
573                 qWarning("QApplication: invalid style override '%s' passed, ignoring it.\n"
574                     "\tAvailable styles: %s", qPrintable(styleOverride),
575                     qPrintable(QStyleFactory::keys().join(QLatin1String(", "))));
576             }
577         }
578 
579         // Trigger default style if none was set already
580         Q_UNUSED(QApplication::style());
581     }
582 #if QT_CONFIG(statemachine)
583     // trigger registering of QStateMachine's GUI types
584     qRegisterGuiStateMachine();
585 #endif
586 
587     if (qEnvironmentVariableIntValue("QT_USE_NATIVE_WINDOWS") > 0)
588         QCoreApplication::setAttribute(Qt::AA_NativeWindows);
589 
590     if (qt_is_gui_used)
591         initializeMultitouch();
592 
593     if (QGuiApplication::desktopSettingsAware())
594         if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
595             QApplicationPrivate::enabledAnimations = theme->themeHint(QPlatformTheme::UiEffects).toInt();
596         }
597 
598     is_app_running = true; // no longer starting up
599 }
600 
initializeWidgetFontHash()601 void QApplicationPrivate::initializeWidgetFontHash()
602 {
603     const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
604     if (!theme)
605         return;
606     FontHash *fontHash = app_fonts();
607     fontHash->clear();
608 
609     if (const QFont *font = theme->font(QPlatformTheme::MenuFont))
610         fontHash->insert(QByteArrayLiteral("QMenu"), *font);
611     if (const QFont *font = theme->font(QPlatformTheme::MenuBarFont))
612         fontHash->insert(QByteArrayLiteral("QMenuBar"), *font);
613     if (const QFont *font = theme->font(QPlatformTheme::MenuItemFont))
614         fontHash->insert(QByteArrayLiteral("QMenuItem"), *font);
615     if (const QFont *font = theme->font(QPlatformTheme::MessageBoxFont))
616         fontHash->insert(QByteArrayLiteral("QMessageBox"), *font);
617     if (const QFont *font = theme->font(QPlatformTheme::LabelFont))
618         fontHash->insert(QByteArrayLiteral("QLabel"), *font);
619     if (const QFont *font = theme->font(QPlatformTheme::TipLabelFont))
620         fontHash->insert(QByteArrayLiteral("QTipLabel"), *font);
621     if (const QFont *font = theme->font(QPlatformTheme::TitleBarFont))
622         fontHash->insert(QByteArrayLiteral("QTitleBar"), *font);
623     if (const QFont *font = theme->font(QPlatformTheme::StatusBarFont))
624         fontHash->insert(QByteArrayLiteral("QStatusBar"), *font);
625     if (const QFont *font = theme->font(QPlatformTheme::MdiSubWindowTitleFont))
626         fontHash->insert(QByteArrayLiteral("QMdiSubWindowTitleBar"), *font);
627     if (const QFont *font = theme->font(QPlatformTheme::DockWidgetTitleFont))
628         fontHash->insert(QByteArrayLiteral("QDockWidgetTitle"), *font);
629     if (const QFont *font = theme->font(QPlatformTheme::PushButtonFont))
630         fontHash->insert(QByteArrayLiteral("QPushButton"), *font);
631     if (const QFont *font = theme->font(QPlatformTheme::CheckBoxFont))
632         fontHash->insert(QByteArrayLiteral("QCheckBox"), *font);
633     if (const QFont *font = theme->font(QPlatformTheme::RadioButtonFont))
634         fontHash->insert(QByteArrayLiteral("QRadioButton"), *font);
635     if (const QFont *font = theme->font(QPlatformTheme::ToolButtonFont))
636         fontHash->insert(QByteArrayLiteral("QToolButton"), *font);
637     if (const QFont *font = theme->font(QPlatformTheme::ItemViewFont))
638         fontHash->insert(QByteArrayLiteral("QAbstractItemView"), *font);
639     if (const QFont *font = theme->font(QPlatformTheme::ListViewFont))
640         fontHash->insert(QByteArrayLiteral("QListView"), *font);
641     if (const QFont *font = theme->font(QPlatformTheme::HeaderViewFont))
642         fontHash->insert(QByteArrayLiteral("QHeaderView"), *font);
643     if (const QFont *font = theme->font(QPlatformTheme::ListBoxFont))
644         fontHash->insert(QByteArrayLiteral("QListBox"), *font);
645     if (const QFont *font = theme->font(QPlatformTheme::ComboMenuItemFont))
646         fontHash->insert(QByteArrayLiteral("QComboMenuItem"), *font);
647     if (const QFont *font = theme->font(QPlatformTheme::ComboLineEditFont))
648         fontHash->insert(QByteArrayLiteral("QComboLineEdit"), *font);
649     if (const QFont *font = theme->font(QPlatformTheme::SmallFont))
650         fontHash->insert(QByteArrayLiteral("QSmallFont"), *font);
651     if (const QFont *font = theme->font(QPlatformTheme::MiniFont))
652         fontHash->insert(QByteArrayLiteral("QMiniFont"), *font);
653 }
654 
655 /*****************************************************************************
656   Functions returning the active popup and modal widgets.
657  *****************************************************************************/
658 
659 /*!
660     Returns the active popup widget.
661 
662     A popup widget is a special top-level widget that sets the \c
663     Qt::WType_Popup widget flag, e.g. the QMenu widget. When the application
664     opens a popup widget, all events are sent to the popup. Normal widgets and
665     modal widgets cannot be accessed before the popup widget is closed.
666 
667     Only other popup widgets may be opened when a popup widget is shown. The
668     popup widgets are organized in a stack. This function returns the active
669     popup widget at the top of the stack.
670 
671     \sa activeModalWidget(), topLevelWidgets()
672 */
673 
activePopupWidget()674 QWidget *QApplication::activePopupWidget()
675 {
676     return QApplicationPrivate::popupWidgets && !QApplicationPrivate::popupWidgets->isEmpty() ?
677         QApplicationPrivate::popupWidgets->constLast() : nullptr;
678 }
679 
680 
681 /*!
682     Returns the active modal widget.
683 
684     A modal widget is a special top-level widget which is a subclass of QDialog
685     that specifies the modal parameter of the constructor as true. A modal
686     widget must be closed before the user can continue with other parts of the
687     program.
688 
689     Modal widgets are organized in a stack. This function returns the active
690     modal widget at the top of the stack.
691 
692     \sa activePopupWidget(), topLevelWidgets()
693 */
694 
activeModalWidget()695 QWidget *QApplication::activeModalWidget()
696 {
697     QWidgetWindow *widgetWindow = qobject_cast<QWidgetWindow *>(modalWindow());
698     return widgetWindow ? widgetWindow->widget() : nullptr;
699 }
700 
701 /*!
702     Cleans up any window system resources that were allocated by this
703     application. Sets the global variable \c qApp to \nullptr.
704 */
705 
~QApplication()706 QApplication::~QApplication()
707 {
708     Q_D(QApplication);
709 
710     //### this should probable be done even later
711     qt_call_post_routines();
712 
713     // kill timers before closing down the dispatcher
714     d->toolTipWakeUp.stop();
715     d->toolTipFallAsleep.stop();
716 
717     QApplicationPrivate::is_app_closing = true;
718     QApplicationPrivate::is_app_running = false;
719 
720     delete QWidgetPrivate::mapper;
721     QWidgetPrivate::mapper = nullptr;
722 
723     // delete all widgets
724     if (QWidgetPrivate::allWidgets) {
725         QWidgetSet *mySet = QWidgetPrivate::allWidgets;
726         QWidgetPrivate::allWidgets = nullptr;
727         for (QWidgetSet::ConstIterator it = mySet->constBegin(), cend = mySet->constEnd(); it != cend; ++it) {
728             QWidget *w = *it;
729             if (!w->parent())                        // window
730                 w->destroy(true, true);
731         }
732         delete mySet;
733     }
734 
735     delete qt_desktopWidget;
736     qt_desktopWidget = nullptr;
737 
738     QApplicationPrivate::widgetPalettes.clear();
739 
740     delete QApplicationPrivate::sys_font;
741     QApplicationPrivate::sys_font = nullptr;
742     delete QApplicationPrivate::set_font;
743     QApplicationPrivate::set_font = nullptr;
744     app_fonts()->clear();
745 
746     delete QApplicationPrivate::app_style;
747     QApplicationPrivate::app_style = nullptr;
748 
749 #if QT_CONFIG(draganddrop)
750     if (qt_is_gui_used)
751         delete QDragManager::self();
752 #endif
753 
754     d->cleanupMultitouch();
755 
756     qt_cleanup();
757 
758     if (QApplicationPrivate::widgetCount)
759         qDebug("Widgets left: %i    Max widgets: %i \n", QWidgetPrivate::instanceCounter, QWidgetPrivate::maxInstances);
760 
761     QApplicationPrivate::obey_desktop_settings = true;
762 
763     QApplicationPrivate::app_strut = QSize(0, 0);
764     QApplicationPrivate::enabledAnimations = QPlatformTheme::GeneralUiEffect;
765     QApplicationPrivate::widgetCount = false;
766 
767 #if QT_CONFIG(statemachine)
768     // trigger unregistering of QStateMachine's GUI types
769     qUnregisterGuiStateMachine();
770 #endif
771 }
772 
773 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
774 #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
775 // #fixme: Remove.
776 static HDC         displayDC        = 0;                // display device context
777 
qt_win_display_dc()778 Q_WIDGETS_EXPORT HDC qt_win_display_dc()                        // get display DC
779 {
780     Q_ASSERT(qApp && qApp->thread() == QThread::currentThread());
781     if (!displayDC)
782         displayDC = GetDC(0);
783     return displayDC;
784 }
785 #endif
786 #endif
787 
qt_cleanup()788 void qt_cleanup()
789 {
790     QPixmapCache::clear();
791     QColormap::cleanup();
792 
793     QApplicationPrivate::active_window = nullptr; //### this should not be necessary
794 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
795 #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
796     if (displayDC) {
797         ReleaseDC(0, displayDC);
798         displayDC = 0;
799     }
800 #endif
801 #endif
802 }
803 
804 /*!
805     \fn QWidget *QApplication::widgetAt(const QPoint &point)
806 
807     Returns the widget at global screen position \a point, or \nullptr
808     if there is no Qt widget there.
809 
810     This function can be slow.
811 
812     \sa QCursor::pos(), QWidget::grabMouse(), QWidget::grabKeyboard()
813 */
widgetAt(const QPoint & p)814 QWidget *QApplication::widgetAt(const QPoint &p)
815 {
816     QWidget *window = QApplication::topLevelAt(p);
817     if (!window)
818         return nullptr;
819 
820     QWidget *child = nullptr;
821 
822     if (!window->testAttribute(Qt::WA_TransparentForMouseEvents))
823         child = window->childAt(window->mapFromGlobal(p));
824 
825     if (child)
826         return child;
827 
828     if (window->testAttribute(Qt::WA_TransparentForMouseEvents)) {
829         //shoot a hole in the widget and try once again,
830         //suboptimal on Qt for Embedded Linux where we do
831         //know the stacking order of the toplevels.
832         int x = p.x();
833         int y = p.y();
834         QRegion oldmask = window->mask();
835         QPoint wpoint = window->mapFromGlobal(QPoint(x, y));
836         QRegion newmask = (oldmask.isEmpty() ? QRegion(window->rect()) : oldmask)
837                           - QRegion(wpoint.x(), wpoint.y(), 1, 1);
838         window->setMask(newmask);
839         QWidget *recurse = nullptr;
840         if (QApplication::topLevelAt(p) != window) // verify recursion will terminate
841             recurse = widgetAt(x, y);
842         if (oldmask.isEmpty())
843             window->clearMask();
844         else
845             window->setMask(oldmask);
846         return recurse;
847     }
848     return window;
849 }
850 
851 /*!
852     \fn QWidget *QApplication::widgetAt(int x, int y)
853 
854     \overload
855 
856     Returns the widget at global screen position (\a x, \a y), or
857     \nullptr if there is no Qt widget there.
858 */
859 
860 /*!
861     \internal
862 */
compressEvent(QEvent * event,QObject * receiver,QPostEventList * postedEvents)863 bool QApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventList *postedEvents)
864 {
865     if ((event->type() == QEvent::UpdateRequest
866           || event->type() == QEvent::LayoutRequest
867           || event->type() == QEvent::Resize
868           || event->type() == QEvent::Move
869           || event->type() == QEvent::LanguageChange)) {
870         for (QPostEventList::const_iterator it = postedEvents->constBegin(); it != postedEvents->constEnd(); ++it) {
871             const QPostEvent &cur = *it;
872             if (cur.receiver != receiver || cur.event == nullptr || cur.event->type() != event->type())
873                 continue;
874             if (cur.event->type() == QEvent::LayoutRequest
875                  || cur.event->type() == QEvent::UpdateRequest) {
876                 ;
877             } else if (cur.event->type() == QEvent::Resize) {
878                 ((QResizeEvent *)(cur.event))->s = ((QResizeEvent *)event)->s;
879             } else if (cur.event->type() == QEvent::Move) {
880                 ((QMoveEvent *)(cur.event))->p = ((QMoveEvent *)event)->p;
881             } else if (cur.event->type() == QEvent::LanguageChange) {
882                 ;
883             } else {
884                 continue;
885             }
886             delete event;
887             return true;
888         }
889         return false;
890     }
891     return QGuiApplication::compressEvent(event, receiver, postedEvents);
892 }
893 
894 /*!
895     \property QApplication::styleSheet
896     \brief the application style sheet
897     \since 4.2
898 
899     By default, this property returns an empty string unless the user specifies
900     the \c{-stylesheet} option on the command line when running the application.
901 
902     \sa QWidget::setStyle(), {Qt Style Sheets}
903 */
904 
905 /*!
906     \property QApplication::autoSipEnabled
907     \since 4.5
908     \brief toggles automatic SIP (software input panel) visibility
909 
910     Set this property to \c true to automatically display the SIP when entering
911     widgets that accept keyboard input. This property only affects widgets with
912     the WA_InputMethodEnabled attribute set, and is typically used to launch
913     a virtual keyboard on devices which have very few or no keys.
914 
915     \b{ The property only has an effect on platforms that use software input
916     panels.}
917 
918     The default is platform dependent.
919 */
setAutoSipEnabled(const bool enabled)920 void QApplication::setAutoSipEnabled(const bool enabled)
921 {
922     QApplicationPrivate::autoSipEnabled = enabled;
923 }
924 
autoSipEnabled() const925 bool QApplication::autoSipEnabled() const
926 {
927     return QApplicationPrivate::autoSipEnabled;
928 }
929 
930 #ifndef QT_NO_STYLE_STYLESHEET
931 
styleSheet() const932 QString QApplication::styleSheet() const
933 {
934     return QApplicationPrivate::styleSheet;
935 }
936 
setStyleSheet(const QString & styleSheet)937 void QApplication::setStyleSheet(const QString& styleSheet)
938 {
939     QApplicationPrivate::styleSheet = styleSheet;
940     QStyleSheetStyle *styleSheetStyle = qt_styleSheet(QApplicationPrivate::app_style);
941     if (styleSheet.isEmpty()) { // application style sheet removed
942         if (!styleSheetStyle)
943             return; // there was no stylesheet before
944         setStyle(styleSheetStyle->base);
945     } else if (styleSheetStyle) { // style sheet update, just repolish
946         styleSheetStyle->repolish(qApp);
947     } else { // stylesheet set the first time
948         QStyleSheetStyle *newStyleSheetStyle = new QStyleSheetStyle(QApplicationPrivate::app_style);
949         QApplicationPrivate::app_style->setParent(newStyleSheetStyle);
950         setStyle(newStyleSheetStyle);
951     }
952 }
953 
954 #endif // QT_NO_STYLE_STYLESHEET
955 
956 /*!
957     Returns the application's style object.
958 
959     \sa setStyle(), QStyle
960 */
style()961 QStyle *QApplication::style()
962 {
963     if (!QApplicationPrivate::app_style) {
964         // Create default style
965         if (!qobject_cast<QApplication *>(QCoreApplication::instance())) {
966             Q_ASSERT(!"No style available without QApplication!");
967             return nullptr;
968         }
969 
970         auto &defaultStyle = QApplicationPrivate::app_style;
971 
972         defaultStyle = QStyleFactory::create(QApplicationPrivate::desktopStyleKey());
973         if (!defaultStyle) {
974             const QStringList styles = QStyleFactory::keys();
975             for (const auto &style : styles) {
976                 if ((defaultStyle = QStyleFactory::create(style)))
977                     break;
978             }
979         }
980         if (!defaultStyle) {
981             Q_ASSERT(!"No styles available!");
982             return nullptr;
983         }
984 
985         // Take ownership of the style
986         defaultStyle->setParent(qApp);
987 
988         QGuiApplicationPrivate::updatePalette();
989 
990 #ifndef QT_NO_STYLE_STYLESHEET
991         if (!QApplicationPrivate::styleSheet.isEmpty()) {
992             qApp->setStyleSheet(QApplicationPrivate::styleSheet);
993         } else
994 #endif
995         {
996             defaultStyle->polish(qApp);
997         }
998     }
999 
1000     return QApplicationPrivate::app_style;
1001 }
1002 
1003 /*!
1004     Sets the application's GUI style to \a style. Ownership of the style object
1005     is transferred to QApplication, so QApplication will delete the style
1006     object on application exit or when a new style is set and the old style is
1007     still the parent of the application object.
1008 
1009     Example usage:
1010     \snippet code/src_gui_kernel_qapplication.cpp 1
1011 
1012     When switching application styles, the color palette is set back to the
1013     initial colors or the system defaults. This is necessary since certain
1014     styles have to adapt the color palette to be fully style-guide compliant.
1015 
1016     Setting the style before a palette has been set, i.e., before creating
1017     QApplication, will cause the application to use QStyle::standardPalette()
1018     for the palette.
1019 
1020     \warning Qt style sheets are currently not supported for custom QStyle
1021     subclasses. We plan to address this in some future release.
1022 
1023     \sa style(), QStyle, setPalette(), desktopSettingsAware()
1024 */
setStyle(QStyle * style)1025 void QApplication::setStyle(QStyle *style)
1026 {
1027     if (!style || style == QApplicationPrivate::app_style)
1028         return;
1029 
1030     QWidgetList all = allWidgets();
1031 
1032     // clean up the old style
1033     if (QApplicationPrivate::app_style) {
1034         if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) {
1035             for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
1036                 QWidget *w = *it;
1037                 if (!(w->windowType() == Qt::Desktop) &&        // except desktop
1038                      w->testAttribute(Qt::WA_WState_Polished)) { // has been polished
1039                     QApplicationPrivate::app_style->unpolish(w);
1040                 }
1041             }
1042         }
1043         QApplicationPrivate::app_style->unpolish(qApp);
1044     }
1045 
1046     QStyle *old = QApplicationPrivate::app_style; // save
1047 
1048 #ifndef QT_NO_STYLE_STYLESHEET
1049     if (!QApplicationPrivate::styleSheet.isEmpty() && !qt_styleSheet(style)) {
1050         // we have a stylesheet already and a new style is being set
1051         QStyleSheetStyle *newStyleSheetStyle = new QStyleSheetStyle(style);
1052         style->setParent(newStyleSheetStyle);
1053         QApplicationPrivate::app_style = newStyleSheetStyle;
1054     } else
1055 #endif // QT_NO_STYLE_STYLESHEET
1056         QApplicationPrivate::app_style = style;
1057     QApplicationPrivate::app_style->setParent(qApp); // take ownership
1058 
1059     // Take care of possible palette requirements of certain
1060     // styles. Do it before polishing the application since the
1061     // style might call QApplication::setPalette() itself.
1062     QGuiApplicationPrivate::updatePalette();
1063 
1064     // The default widget font hash is based on the platform theme,
1065     // not the style, but the widget fonts could in theory have been
1066     // affected by polish of the previous style, without a proper
1067     // cleanup in unpolish, so reset it now before polishing the
1068     // new style.
1069     QApplicationPrivate::initializeWidgetFontHash();
1070 
1071     // initialize the application with the new style
1072     QApplicationPrivate::app_style->polish(qApp);
1073 
1074     // re-polish existing widgets if necessary
1075     if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) {
1076         for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
1077             QWidget *w = *it;
1078             if (w->windowType() != Qt::Desktop && w->testAttribute(Qt::WA_WState_Polished)) {
1079                 if (w->style() == QApplicationPrivate::app_style)
1080                     QApplicationPrivate::app_style->polish(w);                // repolish
1081 #ifndef QT_NO_STYLE_STYLESHEET
1082                 else
1083                     w->setStyleSheet(w->styleSheet()); // touch
1084 #endif
1085             }
1086         }
1087 
1088         for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
1089             QWidget *w = *it;
1090             if (w->windowType() != Qt::Desktop && !w->testAttribute(Qt::WA_SetStyle)) {
1091                     QEvent e(QEvent::StyleChange);
1092                     QCoreApplication::sendEvent(w, &e);
1093                     w->update();
1094             }
1095         }
1096     }
1097 
1098 #ifndef QT_NO_STYLE_STYLESHEET
1099     if (QStyleSheetStyle *oldStyleSheetStyle = qt_styleSheet(old)) {
1100         oldStyleSheetStyle->deref();
1101     } else
1102 #endif
1103     if (old && old->parent() == qApp) {
1104         delete old;
1105     }
1106 
1107     if (QApplicationPrivate::focus_widget) {
1108         QFocusEvent in(QEvent::FocusIn, Qt::OtherFocusReason);
1109         QCoreApplication::sendEvent(QApplicationPrivate::focus_widget->style(), &in);
1110         QApplicationPrivate::focus_widget->update();
1111     }
1112 }
1113 
1114 /*!
1115     \overload
1116 
1117     Requests a QStyle object for \a style from the QStyleFactory.
1118 
1119     The string must be one of the QStyleFactory::keys(), typically one of
1120     "windows", "windowsvista", "fusion", or "macintosh". Style
1121     names are case insensitive.
1122 
1123     Returns \nullptr if an unknown \a style is passed, otherwise the QStyle object
1124     returned is set as the application's GUI style.
1125 
1126     \warning To ensure that the application's style is set correctly, it is
1127     best to call this function before the QApplication constructor, if
1128     possible.
1129 */
setStyle(const QString & style)1130 QStyle* QApplication::setStyle(const QString& style)
1131 {
1132     QStyle *s = QStyleFactory::create(style);
1133     if (!s)
1134         return nullptr;
1135 
1136     setStyle(s);
1137     return s;
1138 }
1139 
1140 #if QT_DEPRECATED_SINCE(5, 8)
1141 /*!
1142     Returns the color specification.
1143     \obsolete
1144 
1145     \sa QApplication::setColorSpec()
1146 */
1147 
colorSpec()1148 int QApplication::colorSpec()
1149 {
1150     return QApplication::NormalColor;
1151 }
1152 
1153 /*!
1154     Sets the color specification for the application to \a spec.
1155     \obsolete
1156 
1157     This call has no effect.
1158 
1159     The color specification controls how the application allocates colors when
1160     run on a display with a limited amount of colors, e.g. 8 bit / 256 color
1161     displays.
1162 
1163     The color specification must be set before you create the QApplication
1164     object.
1165 
1166     The options are:
1167     \list
1168         \li  QApplication::NormalColor. This is the default color allocation
1169             strategy. Use this option if your application uses buttons, menus,
1170             texts and pixmaps with few colors. With this option, the
1171             application uses system global colors. This works fine for most
1172             applications under X11, but on the Windows platform, it may cause
1173             dithering of non-standard colors.
1174         \li  QApplication::CustomColor. Use this option if your application
1175             needs a small number of custom colors. On X11, this option is the
1176             same as NormalColor. On Windows, Qt creates a Windows palette, and
1177             allocates colors to it on demand.
1178         \li  QApplication::ManyColor. Use this option if your application is
1179             very color hungry, e.g., it requires thousands of colors. \br
1180             Under X11 the effect is:
1181             \list
1182                 \li  For 256-color displays which have at best a 256 color true
1183                     color visual, the default visual is used, and colors are
1184                     allocated from a color cube. The color cube is the 6x6x6
1185                     (216 color) "Web palette" (the red, green, and blue
1186                     components always have one of the following values: 0x00,
1187                     0x33, 0x66, 0x99, 0xCC, or 0xFF), but the number of colors
1188                     can be changed by the \e -ncols option. The user can force
1189                     the application to use the true color visual with the
1190                     \l{QApplication::QApplication()}{-visual} option.
1191                 \li  For 256-color displays which have a true color visual with
1192                     more than 256 colors, use that visual. Silicon Graphics X
1193                     servers this feature, for example. They provide an 8 bit
1194                     visual by default but can deliver true color when asked.
1195             \endlist
1196             On Windows, Qt creates a Windows palette, and fills it with a color
1197             cube.
1198     \endlist
1199 
1200     Be aware that the CustomColor and ManyColor choices may lead to colormap
1201     flashing: The foreground application gets (most) of the available colors,
1202     while the background windows will look less attractive.
1203 
1204     Example:
1205 
1206     \snippet code/src_gui_kernel_qapplication.cpp 2
1207 
1208     \sa colorSpec()
1209 */
1210 
setColorSpec(int spec)1211 void QApplication::setColorSpec(int spec)
1212 {
1213     Q_UNUSED(spec)
1214 }
1215 #endif
1216 
1217 /*!
1218     \property QApplication::globalStrut
1219     \brief the minimum size that any GUI element that the user can interact
1220            with should have
1221     \deprecated
1222 
1223     For example, no button should be resized to be smaller than the global
1224     strut size. The strut size should be considered when reimplementing GUI
1225     controls that may be used on touch-screens or similar I/O devices.
1226 
1227     Example:
1228 
1229     \snippet code/src_gui_kernel_qapplication.cpp 3
1230 
1231     By default, this property contains a QSize object with zero width and height.
1232 */
globalStrut()1233 QSize QApplication::globalStrut()
1234 {
1235     return QApplicationPrivate::app_strut;
1236 }
1237 
setGlobalStrut(const QSize & strut)1238 void QApplication::setGlobalStrut(const QSize& strut)
1239 {
1240     QApplicationPrivate::app_strut = strut;
1241 }
1242 
1243 // Widget specific palettes
1244 QApplicationPrivate::PaletteHash QApplicationPrivate::widgetPalettes;
1245 
basePalette() const1246 QPalette QApplicationPrivate::basePalette() const
1247 {
1248     // Start out with a palette based on the style, in case there's no theme
1249     // available, or so that we can fill in missing roles in the theme.
1250     QPalette palette = app_style ? app_style->standardPalette() : Qt::gray;
1251 
1252     // Prefer theme palette if available, but fill in missing roles from style
1253     // for compatibility. Note that the style's standard palette is not prioritized
1254     // over the theme palette, as the documented way of applying the style's palette
1255     // is to set it explicitly using QApplication::setPalette().
1256     if (const QPalette *themePalette = platformTheme() ? platformTheme()->palette() : nullptr)
1257         palette = themePalette->resolve(palette);
1258 
1259     // Finish off by letting the application style polish the palette. This will
1260     // not result in the polished palette becoming a user-set palette, as the
1261     // resulting base palette is only used as a fallback, with the resolve mask
1262     // set to 0.
1263     if (app_style)
1264         app_style->polish(palette);
1265 
1266     return palette;
1267 }
1268 
1269 /*!
1270     \fn QPalette QApplication::palette(const QWidget* widget)
1271 
1272     If a \a widget is passed, the default palette for the widget's class is
1273     returned. This may or may not be the application palette. In most cases
1274     there is no special palette for certain types of widgets, but one notable
1275     exception is the popup menu under Windows, if the user has defined a
1276     special background color for menus in the display settings.
1277 
1278     \sa setPalette(), QWidget::palette()
1279 */
palette(const QWidget * w)1280 QPalette QApplication::palette(const QWidget* w)
1281 {
1282     auto &widgetPalettes = QApplicationPrivate::widgetPalettes;
1283     if (w && !widgetPalettes.isEmpty()) {
1284         auto it = widgetPalettes.constFind(w->metaObject()->className());
1285         const auto cend = widgetPalettes.constEnd();
1286         if (it != cend)
1287             return *it;
1288         for (it = widgetPalettes.constBegin(); it != cend; ++it) {
1289             if (w->inherits(it.key()))
1290                 return it.value();
1291         }
1292     }
1293     return palette();
1294 }
1295 
1296 /*!
1297     \overload
1298 
1299     Returns the palette for widgets of the given \a className.
1300 
1301     \sa setPalette(), QWidget::palette()
1302 */
palette(const char * className)1303 QPalette QApplication::palette(const char *className)
1304 {
1305     auto &widgetPalettes = QApplicationPrivate::widgetPalettes;
1306     if (className && !widgetPalettes.isEmpty()) {
1307         auto it = widgetPalettes.constFind(className);
1308         if (it != widgetPalettes.constEnd())
1309             return *it;
1310     }
1311 
1312     return QGuiApplication::palette();
1313 }
1314 
1315 /*!
1316     Changes the application palette to \a palette.
1317 
1318     If \a className is passed, the change applies only to widgets that inherit
1319     \a className (as reported by QObject::inherits()). If \a className is left
1320     0, the change affects all widgets, thus overriding any previously set class
1321     specific palettes.
1322 
1323     The palette may be changed according to the current GUI style in
1324     QStyle::polish().
1325 
1326     \warning Do not use this function in conjunction with \l{Qt Style Sheets}.
1327     When using style sheets, the palette of a widget can be customized using
1328     the "color", "background-color", "selection-color",
1329     "selection-background-color" and "alternate-background-color".
1330 
1331     \note Some styles do not use the palette for all drawing, for instance, if
1332     they make use of native theme engines. This is the case for the
1333     Windows Vista and \macos styles.
1334 
1335     \sa QWidget::setPalette(), palette(), QStyle::polish()
1336 */
setPalette(const QPalette & palette,const char * className)1337 void QApplication::setPalette(const QPalette &palette, const char* className)
1338 {
1339     if (className) {
1340         QPalette polishedPalette = palette;
1341         if (QApplicationPrivate::app_style) {
1342             auto originalResolveMask = palette.resolve();
1343             QApplicationPrivate::app_style->polish(polishedPalette);
1344             polishedPalette.resolve(originalResolveMask);
1345         }
1346 
1347         QApplicationPrivate::widgetPalettes.insert(className, polishedPalette);
1348         if (qApp)
1349             qApp->d_func()->handlePaletteChanged(className);
1350     } else {
1351         QGuiApplication::setPalette(palette);
1352     }
1353 }
1354 
handlePaletteChanged(const char * className)1355 void QApplicationPrivate::handlePaletteChanged(const char *className)
1356 {
1357     if (!is_app_running || is_app_closing)
1358         return;
1359 
1360     // Setting the global application palette is documented to
1361     // reset any previously set class specific widget palettes.
1362     bool sendPaletteChangeToAllWidgets = false;
1363     if (!className && !widgetPalettes.isEmpty()) {
1364         sendPaletteChangeToAllWidgets = true;
1365         widgetPalettes.clear();
1366     }
1367 
1368     QGuiApplicationPrivate::handlePaletteChanged(className);
1369 
1370     QEvent event(QEvent::ApplicationPaletteChange);
1371     const QWidgetList widgets = QApplication::allWidgets();
1372     for (auto widget : widgets) {
1373         if (sendPaletteChangeToAllWidgets || (!className && widget->isWindow()) || (className && widget->inherits(className)))
1374             QCoreApplication::sendEvent(widget, &event);
1375     }
1376 
1377 #if QT_CONFIG(graphicsview)
1378     for (auto scene : qAsConst(scene_list))
1379         QCoreApplication::sendEvent(scene, &event);
1380 #endif
1381 
1382     // Palette has been reset back to the default application palette,
1383     // so we need to reinitialize the widget palettes from the theme.
1384     if (!className && !testAttribute(Qt::AA_SetPalette))
1385         initializeWidgetPalettesFromTheme();
1386 }
1387 
initializeWidgetPalettesFromTheme()1388 void QApplicationPrivate::initializeWidgetPalettesFromTheme()
1389 {
1390     QPlatformTheme *platformTheme = QGuiApplicationPrivate::platformTheme();
1391     if (!platformTheme)
1392         return;
1393 
1394     widgetPalettes.clear();
1395 
1396     struct ThemedWidget { const char *className; QPlatformTheme::Palette palette; };
1397 
1398     static const ThemedWidget themedWidgets[] = {
1399         { "QToolButton", QPlatformTheme::ToolButtonPalette },
1400         { "QAbstractButton", QPlatformTheme::ButtonPalette },
1401         { "QCheckBox", QPlatformTheme::CheckBoxPalette },
1402         { "QRadioButton", QPlatformTheme::RadioButtonPalette },
1403         { "QHeaderView", QPlatformTheme::HeaderPalette },
1404         { "QAbstractItemView", QPlatformTheme::ItemViewPalette },
1405         { "QMessageBoxLabel", QPlatformTheme::MessageBoxLabelPalette },
1406         { "QTabBar", QPlatformTheme::TabBarPalette },
1407         { "QLabel", QPlatformTheme::LabelPalette },
1408         { "QGroupBox", QPlatformTheme::GroupBoxPalette },
1409         { "QMenu", QPlatformTheme::MenuPalette },
1410         { "QMenuBar", QPlatformTheme::MenuBarPalette },
1411         { "QTextEdit", QPlatformTheme::TextEditPalette },
1412         { "QTextControl", QPlatformTheme::TextEditPalette },
1413         { "QLineEdit", QPlatformTheme::TextLineEditPalette },
1414     };
1415 
1416     for (const auto themedWidget : themedWidgets) {
1417         if (auto *palette = platformTheme->palette(themedWidget.palette))
1418             QApplication::setPalette(*palette, themedWidget.className);
1419     }
1420 }
1421 
1422 /*!
1423     Returns the default application font.
1424 
1425     \sa fontMetrics(), QWidget::font()
1426 */
font()1427 QFont QApplication::font()
1428 {
1429     return QGuiApplication::font();
1430 }
1431 
1432 /*!
1433     \overload
1434 
1435     Returns the default font for the \a widget.
1436 
1437     \sa fontMetrics(), QWidget::setFont()
1438 */
1439 
font(const QWidget * widget)1440 QFont QApplication::font(const QWidget *widget)
1441 {
1442     typedef FontHash::const_iterator FontHashConstIt;
1443 
1444     FontHash *hash = app_fonts();
1445 
1446     if (widget && hash  && hash->size()) {
1447 #ifdef Q_OS_MAC
1448         // short circuit for small and mini controls
1449         if (widget->testAttribute(Qt::WA_MacSmallSize)) {
1450             return hash->value(QByteArrayLiteral("QSmallFont"));
1451         } else if (widget->testAttribute(Qt::WA_MacMiniSize)) {
1452             return hash->value(QByteArrayLiteral("QMiniFont"));
1453         }
1454 #endif
1455         FontHashConstIt it = hash->constFind(widget->metaObject()->className());
1456         const FontHashConstIt cend = hash->constEnd();
1457         if (it != cend)
1458             return it.value();
1459         for (it = hash->constBegin(); it != cend; ++it) {
1460             if (widget->inherits(it.key()))
1461                 return it.value();
1462         }
1463     }
1464     return font();
1465 }
1466 
1467 /*!
1468     \overload
1469 
1470     Returns the font for widgets of the given \a className.
1471 
1472     \sa setFont(), QWidget::font()
1473 */
font(const char * className)1474 QFont QApplication::font(const char *className)
1475 {
1476     FontHash *hash = app_fonts();
1477     if (className && hash && hash->size()) {
1478         QHash<QByteArray, QFont>::ConstIterator it = hash->constFind(className);
1479         if (it != hash->constEnd())
1480             return *it;
1481     }
1482     return font();
1483 }
1484 
1485 
1486 /*!
1487     Changes the default application font to \a font. If \a className is passed,
1488     the change applies only to classes that inherit \a className (as reported
1489     by QObject::inherits()).
1490 
1491     On application start-up, the default font depends on the window system. It
1492     can vary depending on both the window system version and the locale. This
1493     function lets you override the default font; but overriding may be a bad
1494     idea because, for example, some locales need extra large fonts to support
1495     their special characters.
1496 
1497     \warning Do not use this function in conjunction with \l{Qt Style Sheets}.
1498     The font of an application can be customized using the "font" style sheet
1499     property. To set a bold font for all QPushButtons, set the application
1500     styleSheet() as "QPushButton { font: bold }"
1501 
1502     \sa font(), fontMetrics(), QWidget::setFont()
1503 */
1504 
setFont(const QFont & font,const char * className)1505 void QApplication::setFont(const QFont &font, const char *className)
1506 {
1507     bool all = false;
1508     FontHash *hash = app_fonts();
1509     if (!className) {
1510         QGuiApplication::setFont(font);
1511         if (hash && hash->size()) {
1512             all = true;
1513             hash->clear();
1514         }
1515     } else if (hash) {
1516         hash->insert(className, font);
1517     }
1518     if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) {
1519         // Send ApplicationFontChange to qApp itself, and to the widgets.
1520         QEvent e(QEvent::ApplicationFontChange);
1521         QCoreApplication::sendEvent(QApplication::instance(), &e);
1522 
1523         QWidgetList wids = QApplication::allWidgets();
1524         for (QWidgetList::ConstIterator it = wids.constBegin(), cend = wids.constEnd(); it != cend; ++it) {
1525             QWidget *w = *it;
1526             if (all || (!className && w->isWindow()) || w->inherits(className)) // matching class
1527                 sendEvent(w, &e);
1528         }
1529 
1530 #if QT_CONFIG(graphicsview)
1531         // Send to all scenes as well.
1532         QList<QGraphicsScene *> &scenes = qApp->d_func()->scene_list;
1533         for (QList<QGraphicsScene *>::ConstIterator it = scenes.constBegin();
1534              it != scenes.constEnd(); ++it) {
1535             QCoreApplication::sendEvent(*it, &e);
1536         }
1537 #endif // QT_CONFIG(graphicsview)
1538     }
1539     if (!className && (!QApplicationPrivate::sys_font || !font.isCopyOf(*QApplicationPrivate::sys_font))) {
1540         if (!QApplicationPrivate::set_font)
1541             QApplicationPrivate::set_font = new QFont(font);
1542         else
1543             *QApplicationPrivate::set_font = font;
1544     }
1545 }
1546 
1547 /*! \internal
1548 */
setSystemFont(const QFont & font)1549 void QApplicationPrivate::setSystemFont(const QFont &font)
1550 {
1551      if (!sys_font)
1552         sys_font = new QFont(font);
1553     else
1554         *sys_font = font;
1555 
1556     if (!QApplicationPrivate::set_font)
1557         QApplication::setFont(*sys_font);
1558 }
1559 
1560 /*! \internal
1561 */
desktopStyleKey()1562 QString QApplicationPrivate::desktopStyleKey()
1563 {
1564 #if defined(QT_BUILD_INTERNAL)
1565     // Allow auto-tests to override the desktop style
1566     if (qEnvironmentVariableIsSet("QT_DESKTOP_STYLE_KEY"))
1567         return QString::fromLocal8Bit(qgetenv("QT_DESKTOP_STYLE_KEY"));
1568 #endif
1569 
1570     // The platform theme might return a style that is not available, find
1571     // first valid one.
1572     if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
1573         const QStringList availableKeys = QStyleFactory::keys();
1574         const auto styles = theme->themeHint(QPlatformTheme::StyleNames).toStringList();
1575         for (const QString &style : styles) {
1576             if (availableKeys.contains(style, Qt::CaseInsensitive))
1577                 return style;
1578         }
1579     }
1580     return QString();
1581 }
1582 
1583 #if QT_VERSION < 0x060000 // remove these forwarders in Qt 6
1584 /*!
1585     \property QApplication::windowIcon
1586     \brief the default window icon
1587 
1588     \sa QWidget::setWindowIcon(), {Setting the Application Icon}
1589 */
windowIcon()1590 QIcon QApplication::windowIcon()
1591 {
1592     return QGuiApplication::windowIcon();
1593 }
1594 
setWindowIcon(const QIcon & icon)1595 void QApplication::setWindowIcon(const QIcon &icon)
1596 {
1597     QGuiApplication::setWindowIcon(icon);
1598 }
1599 #endif
1600 
notifyWindowIconChanged()1601 void QApplicationPrivate::notifyWindowIconChanged()
1602 {
1603     QEvent ev(QEvent::ApplicationWindowIconChange);
1604     const QWidgetList list = QApplication::topLevelWidgets();
1605     QWindowList windowList = QGuiApplication::topLevelWindows();
1606 
1607     // send to all top-level QWidgets
1608     for (auto *w : list) {
1609         windowList.removeOne(w->windowHandle());
1610         QCoreApplication::sendEvent(w, &ev);
1611     }
1612 
1613     // in case there are any plain QWindows in this QApplication-using
1614     // application, also send the notification to them
1615     for (int i = 0; i < windowList.size(); ++i)
1616         QCoreApplication::sendEvent(windowList.at(i), &ev);
1617 }
1618 
1619 /*!
1620     Returns a list of the top-level widgets (windows) in the application.
1621 
1622     \note Some of the top-level widgets may be hidden, for example a tooltip if
1623     no tooltip is currently shown.
1624 
1625     Example:
1626 
1627     \snippet code/src_gui_kernel_qapplication.cpp 4
1628 
1629     \sa allWidgets(), QWidget::isWindow(), QWidget::isHidden()
1630 */
topLevelWidgets()1631 QWidgetList QApplication::topLevelWidgets()
1632 {
1633     QWidgetList list;
1634     if (QWidgetPrivate::allWidgets != nullptr) {
1635         const auto isTopLevelWidget = [] (const QWidget *w) {
1636             return w->isWindow() && w->windowType() != Qt::Desktop;
1637         };
1638         std::copy_if(QWidgetPrivate::allWidgets->cbegin(), QWidgetPrivate::allWidgets->cend(),
1639                      std::back_inserter(list), isTopLevelWidget);
1640     }
1641     return list;
1642 }
1643 
1644 /*!
1645     Returns a list of all the widgets in the application.
1646 
1647     The list is empty (QList::isEmpty()) if there are no widgets.
1648 
1649     \note Some of the widgets may be hidden.
1650 
1651     Example:
1652     \snippet code/src_gui_kernel_qapplication.cpp 5
1653 
1654     \sa topLevelWidgets(), QWidget::isVisible()
1655 */
1656 
allWidgets()1657 QWidgetList QApplication::allWidgets()
1658 {
1659     if (QWidgetPrivate::allWidgets)
1660         return QWidgetPrivate::allWidgets->values();
1661     return QWidgetList();
1662 }
1663 
1664 /*!
1665     Returns the application widget that has the keyboard input focus,
1666     or \nullptr if no widget in this application has the focus.
1667 
1668     \sa QWidget::setFocus(), QWidget::hasFocus(), activeWindow(), focusChanged()
1669 */
1670 
focusWidget()1671 QWidget *QApplication::focusWidget()
1672 {
1673     return QApplicationPrivate::focus_widget;
1674 }
1675 
setFocusWidget(QWidget * focus,Qt::FocusReason reason)1676 void QApplicationPrivate::setFocusWidget(QWidget *focus, Qt::FocusReason reason)
1677 {
1678 #if QT_CONFIG(graphicsview)
1679     if (focus && focus->window()->graphicsProxyWidget())
1680         return;
1681 #endif
1682 
1683     hidden_focus_widget = nullptr;
1684 
1685     if (focus != focus_widget) {
1686         if (focus && focus->isHidden()) {
1687             hidden_focus_widget = focus;
1688             return;
1689         }
1690 
1691         if (focus && (reason == Qt::BacktabFocusReason || reason == Qt::TabFocusReason)
1692             && qt_in_tab_key_event)
1693             focus->window()->setAttribute(Qt::WA_KeyboardFocusChange);
1694         else if (focus && reason == Qt::ShortcutFocusReason) {
1695             focus->window()->setAttribute(Qt::WA_KeyboardFocusChange);
1696         }
1697         QWidget *prev = focus_widget;
1698         focus_widget = focus;
1699 
1700         if(focus_widget)
1701             focus_widget->d_func()->setFocus_sys();
1702 
1703         if (reason != Qt::NoFocusReason) {
1704 
1705             //send events
1706             if (prev) {
1707 #ifdef QT_KEYPAD_NAVIGATION
1708                 if (QApplication::keypadNavigationEnabled()) {
1709                     if (prev->hasEditFocus() && reason != Qt::PopupFocusReason)
1710                         prev->setEditFocus(false);
1711                 }
1712 #endif
1713                 QFocusEvent out(QEvent::FocusOut, reason);
1714                 QPointer<QWidget> that = prev;
1715                 QCoreApplication::sendEvent(prev, &out);
1716                 if (that)
1717                     QCoreApplication::sendEvent(that->style(), &out);
1718             }
1719             if(focus && QApplicationPrivate::focus_widget == focus) {
1720                 QFocusEvent in(QEvent::FocusIn, reason);
1721                 QPointer<QWidget> that = focus;
1722                 QCoreApplication::sendEvent(focus, &in);
1723                 if (that)
1724                     QCoreApplication::sendEvent(that->style(), &in);
1725             }
1726             emit qApp->focusChanged(prev, focus_widget);
1727         }
1728     }
1729 }
1730 
1731 
1732 /*!
1733     Returns the application top-level window that has the keyboard input focus,
1734     or \nullptr if no application window has the focus. There might be an
1735     activeWindow() even if there is no focusWidget(), for example if no widget
1736     in that window accepts key events.
1737 
1738     \sa QWidget::setFocus(), QWidget::hasFocus(), focusWidget()
1739 */
1740 
activeWindow()1741 QWidget *QApplication::activeWindow()
1742 {
1743     return QApplicationPrivate::active_window;
1744 }
1745 
1746 /*!
1747     Returns display (screen) font metrics for the application font.
1748 
1749     \sa font(), setFont(), QWidget::fontMetrics(), QPainter::fontMetrics()
1750 */
1751 
fontMetrics()1752 QFontMetrics QApplication::fontMetrics()
1753 {
1754     return desktop()->fontMetrics();
1755 }
1756 
tryCloseAllWidgetWindows(QWindowList * processedWindows)1757 bool QApplicationPrivate::tryCloseAllWidgetWindows(QWindowList *processedWindows)
1758 {
1759     Q_ASSERT(processedWindows);
1760     while (QWidget *w = QApplication::activeModalWidget()) {
1761         if (!w->isVisible() || w->data->is_closing)
1762             break;
1763         QWindow *window = w->windowHandle();
1764         if (!window->close()) // Qt::WA_DeleteOnClose may cause deletion.
1765             return false;
1766         if (window)
1767             processedWindows->append(window);
1768     }
1769 
1770 retry:
1771     const QWidgetList list = QApplication::topLevelWidgets();
1772     for (auto *w : list) {
1773         if (w->isVisible() && w->windowType() != Qt::Desktop &&
1774                 !w->testAttribute(Qt::WA_DontShowOnScreen) && !w->data->is_closing) {
1775             QWindow *window = w->windowHandle();
1776             if (!window->close())  // Qt::WA_DeleteOnClose may cause deletion.
1777                 return false;
1778             if (window)
1779                 processedWindows->append(window);
1780             goto retry;
1781         }
1782     }
1783     return true;
1784 }
1785 
tryCloseAllWindows()1786 bool QApplicationPrivate::tryCloseAllWindows()
1787 {
1788     QWindowList processedWindows;
1789     return QApplicationPrivate::tryCloseAllWidgetWindows(&processedWindows)
1790         && QGuiApplicationPrivate::tryCloseRemainingWindows(processedWindows);
1791 }
1792 
1793 /*!
1794     Closes all top-level windows.
1795 
1796     This function is particularly useful for applications with many top-level
1797     windows. It could, for example, be connected to a \uicontrol{Exit} entry in the
1798     \uicontrol{File} menu:
1799 
1800     \snippet mainwindows/mdi/mainwindow.cpp 0
1801 
1802     The windows are closed in random order, until one window does not accept
1803     the close event. The application quits when the last window was
1804     successfully closed; this can be turned off by setting
1805     \l quitOnLastWindowClosed to false.
1806 
1807     \sa quitOnLastWindowClosed, lastWindowClosed(), QWidget::close(),
1808     QWidget::closeEvent(), lastWindowClosed(), QCoreApplication::quit(), topLevelWidgets(),
1809     QWidget::isWindow()
1810 */
closeAllWindows()1811 void QApplication::closeAllWindows()
1812 {
1813     QWindowList processedWindows;
1814     QApplicationPrivate::tryCloseAllWidgetWindows(&processedWindows);
1815 }
1816 
1817 /*!
1818     Displays a simple message box about Qt. The message includes the version
1819     number of Qt being used by the application.
1820 
1821     This is useful for inclusion in the \uicontrol Help menu of an application, as
1822     shown in the \l{mainwindows/menus}{Menus} example.
1823 
1824     This function is a convenience slot for QMessageBox::aboutQt().
1825 */
aboutQt()1826 void QApplication::aboutQt()
1827 {
1828 #if QT_CONFIG(messagebox)
1829     QMessageBox::aboutQt(activeWindow());
1830 #endif // QT_CONFIG(messagebox)
1831 }
1832 
1833 /*!
1834     \since 4.1
1835     \fn void QApplication::focusChanged(QWidget *old, QWidget *now)
1836 
1837     This signal is emitted when the widget that has keyboard focus changed from
1838     \a old to \a now, i.e., because the user pressed the tab-key, clicked into
1839     a widget or changed the active window. Both \a old and \a now can be \nullptr.
1840 
1841 
1842     The signal is emitted after both widget have been notified about the change
1843     through QFocusEvent.
1844 
1845     \sa QWidget::setFocus(), QWidget::clearFocus(), Qt::FocusReason
1846 */
1847 
1848 /*!\reimp
1849 
1850 */
event(QEvent * e)1851 bool QApplication::event(QEvent *e)
1852 {
1853     Q_D(QApplication);
1854     if (e->type() == QEvent::Quit) {
1855         closeAllWindows();
1856         for (auto *w : topLevelWidgets()) {
1857             if (w->isVisible() && !(w->windowType() == Qt::Desktop) && !(w->windowType() == Qt::Popup) &&
1858                  (!(w->windowType() == Qt::Dialog) || !w->parentWidget()) && !w->testAttribute(Qt::WA_DontShowOnScreen)) {
1859                 e->ignore();
1860                 return true;
1861             }
1862         }
1863         // Explicitly call QCoreApplication instead of QGuiApplication so that
1864         // we don't let QGuiApplication close any windows we skipped earlier in
1865         // closeAllWindows(). FIXME: Unify all this close magic through closeAllWindows.
1866         return QCoreApplication::event(e);
1867 #ifndef Q_OS_WIN
1868     } else if (e->type() == QEvent::LocaleChange) {
1869         // on Windows the event propagation is taken care by the
1870         // WM_SETTINGCHANGE event handler.
1871         const QWidgetList list = topLevelWidgets();
1872         for (auto *w : list) {
1873             if (!(w->windowType() == Qt::Desktop)) {
1874                 if (!w->testAttribute(Qt::WA_SetLocale))
1875                     w->d_func()->setLocale_helper(QLocale(), true);
1876             }
1877         }
1878 #endif
1879     } else if (e->type() == QEvent::Timer) {
1880         QTimerEvent *te = static_cast<QTimerEvent*>(e);
1881         Q_ASSERT(te != nullptr);
1882         if (te->timerId() == d->toolTipWakeUp.timerId()) {
1883             d->toolTipWakeUp.stop();
1884             if (d->toolTipWidget) {
1885                 QWidget *w = d->toolTipWidget->window();
1886                 // show tooltip if WA_AlwaysShowToolTips is set, or if
1887                 // any ancestor of d->toolTipWidget is the active
1888                 // window
1889                 bool showToolTip = w->testAttribute(Qt::WA_AlwaysShowToolTips);
1890                 while (w && !showToolTip) {
1891                     showToolTip = w->isActiveWindow();
1892                     w = w->parentWidget();
1893                     w = w ? w->window() : nullptr;
1894                 }
1895                 if (showToolTip) {
1896                     QHelpEvent e(QEvent::ToolTip, d->toolTipPos, d->toolTipGlobalPos);
1897                     QCoreApplication::sendEvent(d->toolTipWidget, &e);
1898                     if (e.isAccepted()) {
1899                         QStyle *s = d->toolTipWidget->style();
1900                         int sleepDelay = s->styleHint(QStyle::SH_ToolTip_FallAsleepDelay, nullptr, d->toolTipWidget, nullptr);
1901                         d->toolTipFallAsleep.start(sleepDelay, this);
1902                     }
1903                 }
1904             }
1905         } else if (te->timerId() == d->toolTipFallAsleep.timerId()) {
1906             d->toolTipFallAsleep.stop();
1907         }
1908 #if QT_CONFIG(whatsthis)
1909     } else if (e->type() == QEvent::EnterWhatsThisMode) {
1910         QWhatsThis::enterWhatsThisMode();
1911         return true;
1912 #endif
1913     }
1914 
1915     if(e->type() == QEvent::LanguageChange) {
1916         // QGuiApplication::event does not account for the cases where
1917         // there is a top level widget without a window handle. So they
1918         // need to have the event posted here
1919         const QWidgetList list = topLevelWidgets();
1920         for (auto *w : list) {
1921             if (!w->windowHandle() && (w->windowType() != Qt::Desktop))
1922                 postEvent(w, new QEvent(QEvent::LanguageChange));
1923         }
1924     }
1925 
1926     return QGuiApplication::event(e);
1927 }
1928 
1929 // ### FIXME: topLevelWindows does not contain QWidgets without a parent
1930 // until QWidgetPrivate::create is called. So we have to override the
1931 // QGuiApplication::notifyLayoutDirectionChange
1932 // to do the right thing.
notifyLayoutDirectionChange()1933 void QApplicationPrivate::notifyLayoutDirectionChange()
1934 {
1935     const QWidgetList list = QApplication::topLevelWidgets();
1936     QWindowList windowList = QGuiApplication::topLevelWindows();
1937 
1938     // send to all top-level QWidgets
1939     for (auto *w : list) {
1940         windowList.removeAll(w->windowHandle());
1941         QEvent ev(QEvent::ApplicationLayoutDirectionChange);
1942         QCoreApplication::sendEvent(w, &ev);
1943     }
1944 
1945     // in case there are any plain QWindows in this QApplication-using
1946     // application, also send the notification to them
1947     for (int i = 0; i < windowList.size(); ++i) {
1948         QEvent ev(QEvent::ApplicationLayoutDirectionChange);
1949         QCoreApplication::sendEvent(windowList.at(i), &ev);
1950     }
1951 }
1952 
1953 /*!
1954     \fn void QApplication::setActiveWindow(QWidget* active)
1955 
1956     Sets the active window to the \a active widget in response to a system
1957     event. The function is called from the platform specific event handlers.
1958 
1959     \warning This function does \e not set the keyboard focus to the active
1960     widget. Call QWidget::activateWindow() instead.
1961 
1962     It sets the activeWindow() and focusWidget() attributes and sends proper
1963     \l{QEvent::WindowActivate}{WindowActivate}/\l{QEvent::WindowDeactivate}
1964     {WindowDeactivate} and \l{QEvent::FocusIn}{FocusIn}/\l{QEvent::FocusOut}
1965     {FocusOut} events to all appropriate widgets. The window will then be
1966     painted in active state (e.g. cursors in line edits will blink), and it
1967     will have tool tips enabled.
1968 
1969     \sa activeWindow(), QWidget::activateWindow()
1970 */
setActiveWindow(QWidget * act)1971 void QApplication::setActiveWindow(QWidget* act)
1972 {
1973     QWidget* window = act?act->window():nullptr;
1974 
1975     if (QApplicationPrivate::active_window == window)
1976         return;
1977 
1978 #if QT_CONFIG(graphicsview)
1979     if (window && window->graphicsProxyWidget()) {
1980         // Activate the proxy's view->viewport() ?
1981         return;
1982     }
1983 #endif
1984 
1985     QWidgetList toBeActivated;
1986     QWidgetList toBeDeactivated;
1987 
1988     if (QApplicationPrivate::active_window) {
1989         if (style()->styleHint(QStyle::SH_Widget_ShareActivation, nullptr, QApplicationPrivate::active_window)) {
1990             const QWidgetList list = topLevelWidgets();
1991             for (auto *w : list) {
1992                 if (w->isVisible() && w->isActiveWindow())
1993                     toBeDeactivated.append(w);
1994             }
1995         } else {
1996             toBeDeactivated.append(QApplicationPrivate::active_window);
1997         }
1998     }
1999 
2000     if (QApplicationPrivate::focus_widget) {
2001         if (QApplicationPrivate::focus_widget->testAttribute(Qt::WA_InputMethodEnabled))
2002             QGuiApplication::inputMethod()->commit();
2003 
2004         QFocusEvent focusAboutToChange(QEvent::FocusAboutToChange, Qt::ActiveWindowFocusReason);
2005         QCoreApplication::sendEvent(QApplicationPrivate::focus_widget, &focusAboutToChange);
2006     }
2007 
2008     QApplicationPrivate::active_window = window;
2009 
2010     if (QApplicationPrivate::active_window) {
2011         if (style()->styleHint(QStyle::SH_Widget_ShareActivation, nullptr, QApplicationPrivate::active_window)) {
2012             const QWidgetList list = topLevelWidgets();
2013             for (auto *w : list) {
2014                 if (w->isVisible() && w->isActiveWindow())
2015                     toBeActivated.append(w);
2016             }
2017         } else {
2018             toBeActivated.append(QApplicationPrivate::active_window);
2019         }
2020 
2021     }
2022 
2023     // first the activation/deactivation events
2024     QEvent activationChange(QEvent::ActivationChange);
2025     QEvent windowActivate(QEvent::WindowActivate);
2026     QEvent windowDeactivate(QEvent::WindowDeactivate);
2027 
2028     for (int i = 0; i < toBeActivated.size(); ++i) {
2029         QWidget *w = toBeActivated.at(i);
2030         sendSpontaneousEvent(w, &windowActivate);
2031         sendSpontaneousEvent(w, &activationChange);
2032     }
2033 
2034     for(int i = 0; i < toBeDeactivated.size(); ++i) {
2035         QWidget *w = toBeDeactivated.at(i);
2036         sendSpontaneousEvent(w, &windowDeactivate);
2037         sendSpontaneousEvent(w, &activationChange);
2038     }
2039 
2040     if (QApplicationPrivate::popupWidgets == nullptr) { // !inPopupMode()
2041         // then focus events
2042         if (!QApplicationPrivate::active_window && QApplicationPrivate::focus_widget) {
2043             QApplicationPrivate::setFocusWidget(nullptr, Qt::ActiveWindowFocusReason);
2044         } else if (QApplicationPrivate::active_window) {
2045             QWidget *w = QApplicationPrivate::active_window->focusWidget();
2046             if (w && w->isVisible() /*&& w->focusPolicy() != QWidget::NoFocus*/)
2047                 w->setFocus(Qt::ActiveWindowFocusReason);
2048             else {
2049                 w = QApplicationPrivate::focusNextPrevChild_helper(QApplicationPrivate::active_window, true);
2050                 if (w) {
2051                     w->setFocus(Qt::ActiveWindowFocusReason);
2052                 } else {
2053                     // If the focus widget is not in the activate_window, clear the focus
2054                     w = QApplicationPrivate::focus_widget;
2055                     if (!w && QApplicationPrivate::active_window->focusPolicy() != Qt::NoFocus)
2056                         QApplicationPrivate::setFocusWidget(QApplicationPrivate::active_window, Qt::ActiveWindowFocusReason);
2057                     else if (!QApplicationPrivate::active_window->isAncestorOf(w))
2058                         QApplicationPrivate::setFocusWidget(nullptr, Qt::ActiveWindowFocusReason);
2059                 }
2060             }
2061         }
2062     }
2063 }
2064 
qt_tlw_for_window(QWindow * wnd)2065 QWidget *qt_tlw_for_window(QWindow *wnd)
2066 {
2067     // QTBUG-32177, wnd might be a QQuickView embedded via window container.
2068     while (wnd && !wnd->isTopLevel()) {
2069         QWindow *parent = wnd->parent();
2070         if (!parent)
2071             break;
2072 
2073         // Don't end up in windows not belonging to this application
2074         if (parent->handle() && parent->handle()->isForeignWindow())
2075             break;
2076 
2077         wnd = wnd->parent();
2078     }
2079     if (wnd) {
2080         const auto tlws = QApplication::topLevelWidgets();
2081         for (QWidget *tlw : tlws) {
2082             if (tlw->windowHandle() == wnd)
2083                 return tlw;
2084         }
2085     }
2086     return nullptr;
2087 }
2088 
notifyActiveWindowChange(QWindow * previous)2089 void QApplicationPrivate::notifyActiveWindowChange(QWindow *previous)
2090 {
2091     Q_UNUSED(previous);
2092     QWindow *wnd = QGuiApplicationPrivate::focus_window;
2093     if (inPopupMode()) // some delayed focus event to ignore
2094         return;
2095     QWidget *tlw = qt_tlw_for_window(wnd);
2096     QApplication::setActiveWindow(tlw);
2097     // QTBUG-37126, Active X controls may set the focus on native child widgets.
2098     if (wnd && tlw && wnd != tlw->windowHandle()) {
2099         if (QWidgetWindow *widgetWindow = qobject_cast<QWidgetWindow *>(wnd))
2100             if (QWidget *widget = widgetWindow->widget())
2101                 if (widget->inherits("QAxHostWidget"))
2102                     widget->setFocus(Qt::ActiveWindowFocusReason);
2103     }
2104 }
2105 
2106 /*!internal
2107  * Helper function that returns the new focus widget, but does not set the focus reason.
2108  * Returns \nullptr if a new focus widget could not be found.
2109  * Shared with QGraphicsProxyWidgetPrivate::findFocusChild()
2110 */
focusNextPrevChild_helper(QWidget * toplevel,bool next,bool * wrappingOccurred)2111 QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool next,
2112                                                         bool *wrappingOccurred)
2113 {
2114     uint focus_flag = qt_tab_all_widgets() ? Qt::TabFocus : Qt::StrongFocus;
2115 
2116     QWidget *f = toplevel->focusWidget();
2117     if (!f)
2118         f = toplevel;
2119 
2120     QWidget *w = f;
2121     QWidget *test = f->d_func()->focus_next;
2122     bool seenWindow = false;
2123     bool focusWidgetAfterWindow = false;
2124     while (test && test != f) {
2125         if (test->isWindow())
2126             seenWindow = true;
2127 
2128         // If the next focus widget has a focus proxy, we need to check to ensure
2129         // that the proxy is in the correct parent-child direction (according to
2130         // \a next). This is to ensure that we can tab in and out of compound widgets
2131         // without getting stuck in a tab-loop between parent and child.
2132         QWidget *focusProxy = test->d_func()->deepestFocusProxy();
2133         const bool canTakeFocus = ((focusProxy ? focusProxy->focusPolicy() : test->focusPolicy())
2134                                   & focus_flag) == focus_flag;
2135         const bool composites = focusProxy ? (next ? focusProxy->isAncestorOf(test)
2136                                                    : test->isAncestorOf(focusProxy))
2137                                            : false;
2138         if (canTakeFocus && !composites
2139             && test->isVisibleTo(toplevel) && test->isEnabled()
2140             && !(w->windowType() == Qt::SubWindow && !w->isAncestorOf(test))
2141             && (toplevel->windowType() != Qt::SubWindow || toplevel->isAncestorOf(test))
2142             && f != focusProxy) {
2143             w = test;
2144             if (seenWindow)
2145                 focusWidgetAfterWindow = true;
2146             if (next)
2147                 break;
2148         }
2149         test = test->d_func()->focus_next;
2150     }
2151 
2152     if (wrappingOccurred != nullptr)
2153         *wrappingOccurred = next ? focusWidgetAfterWindow : !focusWidgetAfterWindow;
2154 
2155     if (w == f) {
2156         if (qt_in_tab_key_event) {
2157             w->window()->setAttribute(Qt::WA_KeyboardFocusChange);
2158             w->update();
2159         }
2160         return nullptr;
2161     }
2162     return w;
2163 }
2164 
2165 /*!
2166     \fn void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave, const QPointF &globalPosF)
2167     \internal
2168 
2169     Creates the proper Enter/Leave event when widget \a enter is entered and
2170     widget \a leave is left.
2171  */
dispatchEnterLeave(QWidget * enter,QWidget * leave,const QPointF & globalPosF)2172 void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave, const QPointF &globalPosF)
2173 {
2174 #if 0
2175     if (leave) {
2176         QEvent e(QEvent::Leave);
2177         QCoreApplication::sendEvent(leave, & e);
2178     }
2179     if (enter) {
2180         const QPoint windowPos = enter->window()->mapFromGlobal(globalPos);
2181         QEnterEvent e(enter->mapFromGlobal(globalPos), windowPos, globalPos);
2182         QCoreApplication::sendEvent(enter, & e);
2183     }
2184     return;
2185 #endif
2186 
2187     if ((!enter && !leave) || (enter == leave))
2188         return;
2189 #ifdef ALIEN_DEBUG
2190     qDebug() << "QApplicationPrivate::dispatchEnterLeave, ENTER:" << enter << "LEAVE:" << leave;
2191 #endif
2192     QWidgetList leaveList;
2193     QWidgetList enterList;
2194 
2195     bool sameWindow = leave && enter && leave->window() == enter->window();
2196     if (leave && !sameWindow) {
2197         auto *w = leave;
2198         do {
2199             leaveList.append(w);
2200         } while (!w->isWindow() && (w = w->parentWidget()));
2201     }
2202     if (enter && !sameWindow) {
2203         auto *w = enter;
2204         do {
2205             enterList.append(w);
2206         } while (!w->isWindow() && (w = w->parentWidget()));
2207     }
2208     if (sameWindow) {
2209         int enterDepth = 0;
2210         int leaveDepth = 0;
2211         auto *e = enter;
2212         while (!e->isWindow() && (e = e->parentWidget()))
2213             enterDepth++;
2214         auto *l = leave;
2215         while (!l->isWindow() && (l = l->parentWidget()))
2216             leaveDepth++;
2217         QWidget* wenter = enter;
2218         QWidget* wleave = leave;
2219         while (enterDepth > leaveDepth) {
2220             wenter = wenter->parentWidget();
2221             enterDepth--;
2222         }
2223         while (leaveDepth > enterDepth) {
2224             wleave = wleave->parentWidget();
2225             leaveDepth--;
2226         }
2227         while (!wenter->isWindow() && wenter != wleave) {
2228             wenter = wenter->parentWidget();
2229             wleave = wleave->parentWidget();
2230         }
2231 
2232         for (auto *w = leave; w != wleave; w = w->parentWidget())
2233             leaveList.append(w);
2234 
2235         for (auto *w = enter; w != wenter; w = w->parentWidget())
2236             enterList.append(w);
2237     }
2238 
2239     QEvent leaveEvent(QEvent::Leave);
2240     for (int i = 0; i < leaveList.size(); ++i) {
2241         auto *w = leaveList.at(i);
2242         if (!QApplication::activeModalWidget() || QApplicationPrivate::tryModalHelper(w, nullptr)) {
2243             QCoreApplication::sendEvent(w, &leaveEvent);
2244             if (w->testAttribute(Qt::WA_Hover) &&
2245                 (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == w->window())) {
2246                 Q_ASSERT(instance());
2247                 QHoverEvent he(QEvent::HoverLeave, QPoint(-1, -1), w->mapFromGlobal(QApplicationPrivate::instance()->hoverGlobalPos),
2248                                QGuiApplication::keyboardModifiers());
2249                 qApp->d_func()->notify_helper(w, &he);
2250             }
2251         }
2252     }
2253     if (!enterList.isEmpty()) {
2254         // Guard against QGuiApplicationPrivate::lastCursorPosition initialized to qInf(), qInf().
2255         const QPoint globalPos = qIsInf(globalPosF.x())
2256             ? QPoint(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)
2257             : globalPosF.toPoint();
2258         const QPoint windowPos = qAsConst(enterList).back()->window()->mapFromGlobal(globalPos);
2259         for (auto it = enterList.crbegin(), end = enterList.crend(); it != end; ++it) {
2260             auto *w = *it;
2261             if (!QApplication::activeModalWidget() || QApplicationPrivate::tryModalHelper(w, nullptr)) {
2262                 const QPointF localPos = w->mapFromGlobal(globalPos);
2263                 QEnterEvent enterEvent(localPos, windowPos, globalPosF);
2264                 QCoreApplication::sendEvent(w, &enterEvent);
2265                 if (w->testAttribute(Qt::WA_Hover) &&
2266                         (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == w->window())) {
2267                     QHoverEvent he(QEvent::HoverEnter, localPos, QPoint(-1, -1),
2268                                    QGuiApplication::keyboardModifiers());
2269                     qApp->d_func()->notify_helper(w, &he);
2270                 }
2271             }
2272         }
2273     }
2274 
2275 #ifndef QT_NO_CURSOR
2276     // Update cursor for alien/graphics widgets.
2277 
2278     const bool enterOnAlien = (enter && (isAlien(enter) || enter->testAttribute(Qt::WA_DontShowOnScreen)));
2279     // Whenever we leave an alien widget on X11/QPA, we need to reset its nativeParentWidget()'s cursor.
2280     // This is not required on Windows as the cursor is reset on every single mouse move.
2281     QWidget *parentOfLeavingCursor = nullptr;
2282     for (int i = 0; i < leaveList.size(); ++i) {
2283         auto *w = leaveList.at(i);
2284         if (!isAlien(w))
2285             break;
2286         if (w->testAttribute(Qt::WA_SetCursor)) {
2287             QWidget *parent = w->parentWidget();
2288             while (parent && parent->d_func()->data.in_destructor)
2289                 parent = parent->parentWidget();
2290             parentOfLeavingCursor = parent;
2291             //continue looping, we need to find the downest alien widget with a cursor.
2292             // (downest on the screen)
2293         }
2294     }
2295     //check that we will not call qt_x11_enforce_cursor twice with the same native widget
2296     if (parentOfLeavingCursor && (!enterOnAlien
2297         || parentOfLeavingCursor->effectiveWinId() != enter->effectiveWinId())) {
2298 #if QT_CONFIG(graphicsview)
2299         if (!parentOfLeavingCursor->window()->graphicsProxyWidget())
2300 #endif
2301         {
2302             if (enter == QApplication::desktop()) {
2303                 qt_qpa_set_cursor(enter, true);
2304             } else {
2305                 qt_qpa_set_cursor(parentOfLeavingCursor, true);
2306             }
2307         }
2308     }
2309     if (enterOnAlien) {
2310         QWidget *cursorWidget = enter;
2311         while (!cursorWidget->isWindow() && !cursorWidget->isEnabled())
2312             cursorWidget = cursorWidget->parentWidget();
2313 
2314         if (!cursorWidget)
2315             return;
2316 
2317 #if QT_CONFIG(graphicsview)
2318         if (cursorWidget->window()->graphicsProxyWidget()) {
2319             QWidgetPrivate::nearestGraphicsProxyWidget(cursorWidget)->setCursor(cursorWidget->cursor());
2320         } else
2321 #endif
2322         {
2323             qt_qpa_set_cursor(cursorWidget, true);
2324         }
2325     }
2326 #endif
2327 }
2328 
2329 /* exported for the benefit of testing tools */
qt_tryModalHelper(QWidget * widget,QWidget ** rettop)2330 Q_WIDGETS_EXPORT bool qt_tryModalHelper(QWidget *widget, QWidget **rettop)
2331 {
2332     return QApplicationPrivate::tryModalHelper(widget, rettop);
2333 }
2334 
2335 /*! \internal
2336     Returns \c true if \a widget is blocked by a modal window.
2337  */
isBlockedByModal(QWidget * widget)2338 bool QApplicationPrivate::isBlockedByModal(QWidget *widget)
2339 {
2340     widget = widget->window();
2341     QWindow *window = widget->windowHandle();
2342     return window && self->isWindowBlocked(window);
2343 }
2344 
isWindowBlocked(QWindow * window,QWindow ** blockingWindow) const2345 bool QApplicationPrivate::isWindowBlocked(QWindow *window, QWindow **blockingWindow) const
2346 {
2347     QWindow *unused = nullptr;
2348     if (Q_UNLIKELY(!window)) {
2349         qWarning().nospace() << "window == 0 passed.";
2350         return false;
2351     }
2352     if (!blockingWindow)
2353         blockingWindow = &unused;
2354 
2355     if (modalWindowList.isEmpty()) {
2356         *blockingWindow = nullptr;
2357         return false;
2358     }
2359     QWidget *popupWidget = QApplication::activePopupWidget();
2360     QWindow *popupWindow = popupWidget ? popupWidget->windowHandle() : nullptr;
2361     if (popupWindow == window || (!popupWindow && QWindowPrivate::get(window)->isPopup())) {
2362         *blockingWindow = nullptr;
2363         return false;
2364     }
2365 
2366     for (int i = 0; i < modalWindowList.count(); ++i) {
2367         QWindow *modalWindow = modalWindowList.at(i);
2368 
2369         // A window is not blocked by another modal window if the two are
2370         // the same, or if the window is a child of the modal window.
2371         if (window == modalWindow || modalWindow->isAncestorOf(window, QWindow::IncludeTransients)) {
2372             *blockingWindow = nullptr;
2373             return false;
2374         }
2375 
2376         Qt::WindowModality windowModality = modalWindow->modality();
2377         QWidgetWindow *modalWidgetWindow = qobject_cast<QWidgetWindow *>(modalWindow);
2378         if (windowModality == Qt::NonModal) {
2379             // determine the modality type if it hasn't been set on the
2380             // modalWindow's widget, this normally happens when waiting for a
2381             // native dialog. use WindowModal if we are the child of a group
2382             // leader; otherwise use ApplicationModal.
2383             QWidget *m = modalWidgetWindow ? modalWidgetWindow->widget() : nullptr;
2384             while (m && !m->testAttribute(Qt::WA_GroupLeader)) {
2385                 m = m->parentWidget();
2386                 if (m)
2387                     m = m->window();
2388             }
2389             windowModality = (m && m->testAttribute(Qt::WA_GroupLeader))
2390                              ? Qt::WindowModal
2391                              : Qt::ApplicationModal;
2392         }
2393 
2394         switch (windowModality) {
2395         case Qt::ApplicationModal:
2396         {
2397             QWidgetWindow *widgetWindow = qobject_cast<QWidgetWindow *>(window);
2398             QWidget *groupLeaderForWidget = widgetWindow ? widgetWindow->widget() : nullptr;
2399             while (groupLeaderForWidget && !groupLeaderForWidget->testAttribute(Qt::WA_GroupLeader))
2400                 groupLeaderForWidget = groupLeaderForWidget->parentWidget();
2401 
2402             if (groupLeaderForWidget) {
2403                 // if \a widget has WA_GroupLeader, it can only be blocked by ApplicationModal children
2404                 QWidget *m = modalWidgetWindow ? modalWidgetWindow->widget() : nullptr;
2405                 while (m && m != groupLeaderForWidget && !m->testAttribute(Qt::WA_GroupLeader))
2406                     m = m->parentWidget();
2407                 if (m == groupLeaderForWidget) {
2408                     *blockingWindow = m->windowHandle();
2409                     return true;
2410                 }
2411             } else if (modalWindow != window) {
2412                 *blockingWindow = modalWindow;
2413                 return true;
2414             }
2415             break;
2416         }
2417         case Qt::WindowModal:
2418         {
2419             QWindow *w = window;
2420             do {
2421                 QWindow *m = modalWindow;
2422                 do {
2423                     if (m == w) {
2424                         *blockingWindow = m;
2425                         return true;
2426                     }
2427                     QWindow *p = m->parent();
2428                     if (!p)
2429                         p = m->transientParent();
2430                     m = p;
2431                 } while (m);
2432                 QWindow *p = w->parent();
2433                 if (!p)
2434                     p = w->transientParent();
2435                 w = p;
2436             } while (w);
2437             break;
2438         }
2439         default:
2440             Q_ASSERT_X(false, "QApplication", "internal error, a modal window cannot be modeless");
2441             break;
2442         }
2443     }
2444     *blockingWindow = nullptr;
2445     return false;
2446 }
2447 
2448 /*!\internal
2449 
2450   Called from qapplication_\e{platform}.cpp, returns \c true
2451   if the widget should accept the event.
2452  */
tryModalHelper(QWidget * widget,QWidget ** rettop)2453 bool QApplicationPrivate::tryModalHelper(QWidget *widget, QWidget **rettop)
2454 {
2455     QWidget *top = QApplication::activeModalWidget();
2456     if (rettop)
2457         *rettop = top;
2458 
2459     // the active popup widget always gets the input event
2460     if (QApplication::activePopupWidget())
2461         return true;
2462 
2463     return !isBlockedByModal(widget->window());
2464 }
2465 
qt_try_modal(QWidget * widget,QEvent::Type type)2466 bool qt_try_modal(QWidget *widget, QEvent::Type type)
2467 {
2468     QWidget * top = nullptr;
2469 
2470     if (QApplicationPrivate::tryModalHelper(widget, &top))
2471         return true;
2472 
2473     bool block_event  = false;
2474 
2475     switch (type) {
2476 #if 0
2477     case QEvent::Focus:
2478         if (!static_cast<QWSFocusEvent*>(event)->simpleData.get_focus)
2479             break;
2480         // drop through
2481 #endif
2482     case QEvent::MouseButtonPress:                        // disallow mouse/key events
2483     case QEvent::MouseButtonRelease:
2484     case QEvent::MouseMove:
2485     case QEvent::KeyPress:
2486     case QEvent::KeyRelease:
2487         block_event         = true;
2488         break;
2489     default:
2490         break;
2491     }
2492 
2493     if (block_event && top && top->parentWidget() == nullptr)
2494         top->raise();
2495 
2496     return !block_event;
2497 }
2498 
modalState()2499 bool QApplicationPrivate::modalState()
2500 {
2501     return !self->modalWindowList.isEmpty();
2502 }
2503 
2504 /*
2505    \internal
2506 */
pickMouseReceiver(QWidget * candidate,const QPoint & windowPos,QPoint * pos,QEvent::Type type,Qt::MouseButtons buttons,QWidget * buttonDown,QWidget * alienWidget)2507 QWidget *QApplicationPrivate::pickMouseReceiver(QWidget *candidate, const QPoint &windowPos,
2508                                                 QPoint *pos, QEvent::Type type,
2509                                                 Qt::MouseButtons buttons, QWidget *buttonDown,
2510                                                 QWidget *alienWidget)
2511 {
2512     Q_ASSERT(candidate);
2513 
2514     QWidget *mouseGrabber = QWidget::mouseGrabber();
2515     if (((type == QEvent::MouseMove && buttons) || (type == QEvent::MouseButtonRelease))
2516             && !buttonDown && !mouseGrabber) {
2517         return nullptr;
2518     }
2519 
2520     if (alienWidget && alienWidget->internalWinId())
2521         alienWidget = nullptr;
2522 
2523     QWidget *receiver = candidate;
2524 
2525     if (!mouseGrabber)
2526         mouseGrabber = (buttonDown && !isBlockedByModal(buttonDown)) ? buttonDown : alienWidget;
2527 
2528     if (mouseGrabber && mouseGrabber != candidate) {
2529         receiver = mouseGrabber;
2530         *pos = receiver->mapFromGlobal(candidate->mapToGlobal(windowPos));
2531 #ifdef ALIEN_DEBUG
2532         qDebug() << "  ** receiver adjusted to:" << receiver << "pos:" << pos;
2533 #endif
2534     }
2535 
2536     return receiver;
2537 
2538 }
2539 
2540 /*
2541    \internal
2542 */
sendMouseEvent(QWidget * receiver,QMouseEvent * event,QWidget * alienWidget,QWidget * nativeWidget,QWidget ** buttonDown,QPointer<QWidget> & lastMouseReceiver,bool spontaneous,bool onlyDispatchEnterLeave)2543 bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event,
2544                                          QWidget *alienWidget, QWidget *nativeWidget,
2545                                          QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver,
2546                                          bool spontaneous, bool onlyDispatchEnterLeave)
2547 {
2548     Q_ASSERT(receiver);
2549     Q_ASSERT(event);
2550     Q_ASSERT(nativeWidget);
2551     Q_ASSERT(buttonDown);
2552 
2553     if (alienWidget && !isAlien(alienWidget))
2554         alienWidget = nullptr;
2555 
2556     QPointer<QWidget> receiverGuard = receiver;
2557     QPointer<QWidget> nativeGuard = nativeWidget;
2558     QPointer<QWidget> alienGuard = alienWidget;
2559     QPointer<QWidget> activePopupWidget = QApplication::activePopupWidget();
2560 
2561     const bool graphicsWidget = nativeWidget->testAttribute(Qt::WA_DontShowOnScreen);
2562 
2563     bool widgetUnderMouse = QRectF(receiver->rect()).contains(event->localPos());
2564 
2565     // Clear the obsolete leaveAfterRelease value, if mouse button has been released but
2566     // leaveAfterRelease has not been updated.
2567     // This happens e.g. when modal dialog or popup is shown as a response to button click.
2568     if (leaveAfterRelease && !*buttonDown && !event->buttons())
2569         leaveAfterRelease = nullptr;
2570 
2571     if (*buttonDown) {
2572         if (!graphicsWidget) {
2573             // Register the widget that shall receive a leave event
2574             // after the last button is released.
2575             if ((alienWidget || !receiver->internalWinId()) && !leaveAfterRelease && !QWidget::mouseGrabber())
2576                 leaveAfterRelease = *buttonDown;
2577             if (event->type() == QEvent::MouseButtonRelease && !event->buttons())
2578                 *buttonDown = nullptr;
2579         }
2580     } else if (lastMouseReceiver && widgetUnderMouse) {
2581         // Dispatch enter/leave if we move:
2582         // 1) from an alien widget to another alien widget or
2583         //    from a native widget to an alien widget (first OR case)
2584         // 2) from an alien widget to a native widget (second OR case)
2585         if ((alienWidget && alienWidget != lastMouseReceiver)
2586             || (isAlien(lastMouseReceiver) && !alienWidget)) {
2587             if (activePopupWidget) {
2588                 if (!QWidget::mouseGrabber())
2589                     dispatchEnterLeave(alienWidget ? alienWidget : nativeWidget, lastMouseReceiver, event->screenPos());
2590             } else {
2591                 dispatchEnterLeave(receiver, lastMouseReceiver, event->screenPos());
2592             }
2593 
2594         }
2595     }
2596 
2597 #ifdef ALIEN_DEBUG
2598     qDebug() << "QApplicationPrivate::sendMouseEvent: receiver:" << receiver
2599              << "pos:" << event->pos() << "alien" << alienWidget << "button down"
2600              << *buttonDown << "last" << lastMouseReceiver << "leave after release"
2601              << leaveAfterRelease;
2602 #endif
2603 
2604     // We need this quard in case someone opens a modal dialog / popup. If that's the case
2605     // leaveAfterRelease is set to null, but we shall not update lastMouseReceiver.
2606     const bool wasLeaveAfterRelease = leaveAfterRelease != nullptr;
2607     bool result = true;
2608     // This code is used for sending the synthetic enter/leave events for cases where it is needed
2609     // due to other events causing the widget under the mouse to change. However in those cases
2610     // we do not want to send the mouse event associated with this call, so this enables us to
2611     // not send the unneeded mouse event
2612     if (!onlyDispatchEnterLeave) {
2613         if (spontaneous)
2614             result = QApplication::sendSpontaneousEvent(receiver, event);
2615         else
2616             result = QCoreApplication::sendEvent(receiver, event);
2617     }
2618 
2619     if (!graphicsWidget && leaveAfterRelease && event->type() == QEvent::MouseButtonRelease
2620         && !event->buttons() && QWidget::mouseGrabber() != leaveAfterRelease) {
2621         // Dispatch enter/leave if:
2622         // 1) the mouse grabber is an alien widget
2623         // 2) the button is released on an alien widget
2624         QWidget *enter = nullptr;
2625         if (nativeGuard)
2626             enter = alienGuard ? alienWidget : nativeWidget;
2627         else // The receiver is typically deleted on mouse release with drag'n'drop.
2628             enter = QApplication::widgetAt(event->globalPos());
2629         dispatchEnterLeave(enter, leaveAfterRelease, event->screenPos());
2630         leaveAfterRelease = nullptr;
2631         lastMouseReceiver = enter;
2632     } else if (!wasLeaveAfterRelease) {
2633         if (activePopupWidget) {
2634             if (!QWidget::mouseGrabber())
2635                 lastMouseReceiver = alienGuard ? alienWidget : (nativeGuard ? nativeWidget : nullptr);
2636         } else {
2637             lastMouseReceiver = receiverGuard ? receiver : QApplication::widgetAt(event->globalPos());
2638         }
2639     }
2640 
2641     return result;
2642 }
2643 
2644 /*
2645     This function should only be called when the widget changes visibility, i.e.
2646     when the \a widget is shown, hidden or deleted. This function does nothing
2647     if the widget is a top-level or native, i.e. not an alien widget. In that
2648     case enter/leave events are genereated by the underlying windowing system.
2649 */
2650 extern QPointer<QWidget> qt_last_mouse_receiver;
2651 extern Q_WIDGETS_EXPORT QWidget *qt_button_down;
sendSyntheticEnterLeave(QWidget * widget)2652 void QApplicationPrivate::sendSyntheticEnterLeave(QWidget *widget)
2653 {
2654 #ifndef QT_NO_CURSOR
2655     if (!widget || widget->isWindow())
2656         return;
2657     const bool widgetInShow = widget->isVisible() && !widget->data->in_destructor;
2658     if (!widgetInShow && widget != qt_last_mouse_receiver)
2659         return; // Widget was not under the cursor when it was hidden/deleted.
2660 
2661     if (widgetInShow && widget->parentWidget()->data->in_show)
2662         return; // Ingore recursive show.
2663 
2664     QWidget *mouseGrabber = QWidget::mouseGrabber();
2665     if (mouseGrabber && mouseGrabber != widget)
2666         return; // Someone else has the grab; enter/leave should not occur.
2667 
2668     QWidget *tlw = widget->window();
2669     if (tlw->data->in_destructor || tlw->data->is_closing)
2670         return; // Closing down the business.
2671 
2672     if (widgetInShow && (!qt_last_mouse_receiver || qt_last_mouse_receiver->window() != tlw))
2673         return; // Mouse cursor not inside the widget's top-level.
2674 
2675     const QPoint globalPos(QCursor::pos());
2676     QPoint windowPos = tlw->mapFromGlobal(globalPos);
2677 
2678     // Find the current widget under the mouse. If this function was called from
2679     // the widget's destructor, we have to make sure childAt() doesn't take into
2680     // account widgets that are about to be destructed.
2681     QWidget *widgetUnderCursor = tlw->d_func()->childAt_helper(windowPos, widget->data->in_destructor);
2682     if (!widgetUnderCursor)
2683         widgetUnderCursor = tlw;
2684     QPoint pos = widgetUnderCursor->mapFrom(tlw, windowPos);
2685 
2686     if (widgetInShow && widgetUnderCursor != widget && !widget->isAncestorOf(widgetUnderCursor))
2687         return; // Mouse cursor not inside the widget or any of its children.
2688 
2689     if (widget->data->in_destructor && qt_button_down == widget)
2690         qt_button_down = nullptr;
2691 
2692     // A mouse move is not actually sent, but we utilize the sendMouseEvent() call to send the
2693     // enter/leave events as appropriate
2694     QMouseEvent e(QEvent::MouseMove, pos, windowPos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier);
2695     sendMouseEvent(widgetUnderCursor, &e, widgetUnderCursor, tlw, &qt_button_down, qt_last_mouse_receiver, true, true);
2696 #else // !QT_NO_CURSOR
2697     Q_UNUSED(widget);
2698 #endif // QT_NO_CURSOR
2699 }
2700 
2701 /*!
2702     \obsolete
2703 
2704     Returns the desktop widget (also called the root window).
2705 
2706     The desktop may be composed of multiple screens, so it would be incorrect,
2707     for example, to attempt to \e center some widget in the desktop's geometry.
2708     QDesktopWidget has various functions for obtaining useful geometries upon
2709     the desktop, such as QDesktopWidget::screenGeometry() and
2710     QDesktopWidget::availableGeometry().
2711 */
desktop()2712 QDesktopWidget *QApplication::desktop()
2713 {
2714     CHECK_QAPP_INSTANCE(nullptr)
2715     if (!qt_desktopWidget || // not created yet
2716          !(qt_desktopWidget->windowType() == Qt::Desktop)) { // reparented away
2717         qt_desktopWidget = new QDesktopWidget();
2718     }
2719     return qt_desktopWidget;
2720 }
2721 
2722 /*
2723   Sets the time after which a drag should start to \a ms ms.
2724 
2725   \sa startDragTime()
2726 */
2727 
setStartDragTime(int ms)2728 void QApplication::setStartDragTime(int ms)
2729 {
2730     QGuiApplication::styleHints()->setStartDragTime(ms);
2731 }
2732 
2733 /*!
2734     \property QApplication::startDragTime
2735     \brief the time in milliseconds that a mouse button must be held down
2736     before a drag and drop operation will begin
2737 
2738     If you support drag and drop in your application, and want to start a drag
2739     and drop operation after the user has held down a mouse button for a
2740     certain amount of time, you should use this property's value as the delay.
2741 
2742     Qt also uses this delay internally, e.g. in QTextEdit and QLineEdit, for
2743     starting a drag.
2744 
2745     The default value is 500 ms.
2746 
2747     \sa startDragDistance(), {Drag and Drop}
2748 */
2749 
startDragTime()2750 int QApplication::startDragTime()
2751 {
2752     return QGuiApplication::styleHints()->startDragTime();
2753 }
2754 
2755 /*
2756     Sets the distance after which a drag should start to \a l pixels.
2757 
2758     \sa startDragDistance()
2759 */
2760 
setStartDragDistance(int l)2761 void QApplication::setStartDragDistance(int l)
2762 {
2763     QGuiApplication::styleHints()->setStartDragDistance(l);
2764 }
2765 
2766 /*!
2767     \property QApplication::startDragDistance
2768 
2769     If you support drag and drop in your application, and want to start a drag
2770     and drop operation after the user has moved the cursor a certain distance
2771     with a button held down, you should use this property's value as the
2772     minimum distance required.
2773 
2774     For example, if the mouse position of the click is stored in \c startPos
2775     and the current position (e.g. in the mouse move event) is \c currentPos,
2776     you can find out if a drag should be started with code like this:
2777 
2778     \snippet code/src_gui_kernel_qapplication.cpp 7
2779 
2780     Qt uses this value internally, e.g. in QFileDialog.
2781 
2782     The default value (if the platform doesn't provide a different default)
2783     is 10 pixels.
2784 
2785     \sa startDragTime(), QPoint::manhattanLength(), {Drag and Drop}
2786 */
2787 
startDragDistance()2788 int QApplication::startDragDistance()
2789 {
2790     return QGuiApplication::styleHints()->startDragDistance();
2791 }
2792 
2793 /*!
2794     Enters the main event loop and waits until exit() is called, then returns
2795     the value that was set to exit() (which is 0 if exit() is called via
2796     quit()).
2797 
2798     It is necessary to call this function to start event handling. The main
2799     event loop receives events from the window system and dispatches these to
2800     the application widgets.
2801 
2802     Generally, no user interaction can take place before calling exec(). As a
2803     special case, modal widgets like QMessageBox can be used before calling
2804     exec(), because modal widgets call exec() to start a local event loop.
2805 
2806     To make your application perform idle processing, i.e., executing a special
2807     function whenever there are no pending events, use a QTimer with 0 timeout.
2808     More advanced idle processing schemes can be achieved using processEvents().
2809 
2810     We recommend that you connect clean-up code to the
2811     \l{QCoreApplication::}{aboutToQuit()} signal, instead of putting it in your
2812     application's \c{main()} function. This is because, on some platforms the
2813     QApplication::exec() call may not return. For example, on the Windows
2814     platform, when the user logs off, the system terminates the process after Qt
2815     closes all top-level windows. Hence, there is \e{no guarantee} that the
2816     application will have time to exit its event loop and execute code at the
2817     end of the \c{main()} function, after the QApplication::exec() call.
2818 
2819     \sa quitOnLastWindowClosed, QCoreApplication::quit(), QCoreApplication::exit(),
2820         QCoreApplication::processEvents(), QCoreApplication::exec()
2821 */
exec()2822 int QApplication::exec()
2823 {
2824     return QGuiApplication::exec();
2825 }
2826 
shouldQuit()2827 bool QApplicationPrivate::shouldQuit()
2828 {
2829     /* if there is no non-withdrawn primary window left (except
2830         the ones without QuitOnClose), we emit the lastWindowClosed
2831         signal */
2832     QWidgetList list = QApplication::topLevelWidgets();
2833     QWindowList processedWindows;
2834     for (int i = 0; i < list.size(); ++i) {
2835         QWidget *w = list.at(i);
2836         if (QWindow *window = w->windowHandle()) { // Menus, popup widgets may not have a QWindow
2837             processedWindows.push_back(window);
2838             if (w->isVisible() && !w->parentWidget() && w->testAttribute(Qt::WA_QuitOnClose))
2839                 return false;
2840         }
2841     }
2842     return QGuiApplicationPrivate::shouldQuitInternal(processedWindows);
2843 }
2844 
closeAllPopups()2845 static inline void closeAllPopups()
2846 {
2847     // Close all popups: In case some popup refuses to close,
2848     // we give up after 1024 attempts (to avoid an infinite loop).
2849     int maxiter = 1024;
2850     QWidget *popup;
2851     while ((popup = QApplication::activePopupWidget()) && maxiter--)
2852         popup->close();
2853 }
2854 
2855 /*! \reimp
2856  */
notify(QObject * receiver,QEvent * e)2857 bool QApplication::notify(QObject *receiver, QEvent *e)
2858 {
2859     Q_D(QApplication);
2860     // no events are delivered after ~QCoreApplication() has started
2861     if (QApplicationPrivate::is_app_closing)
2862         return true;
2863 
2864     if (Q_UNLIKELY(!receiver)) {                        // serious error
2865         qWarning("QApplication::notify: Unexpected null receiver");
2866         return true;
2867     }
2868 
2869 #ifndef QT_NO_DEBUG
2870     QCoreApplicationPrivate::checkReceiverThread(receiver);
2871 #endif
2872 
2873     if (receiver->isWindowType()) {
2874         if (QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(static_cast<QWindow *>(receiver), e))
2875             return true; // Platform plugin ate the event
2876     }
2877 
2878     QGuiApplicationPrivate::captureGlobalModifierState(e);
2879 
2880 #ifndef QT_NO_GESTURES
2881     // walk through parents and check for gestures
2882     if (d->gestureManager) {
2883         switch (e->type()) {
2884         case QEvent::Paint:
2885         case QEvent::MetaCall:
2886         case QEvent::DeferredDelete:
2887         case QEvent::DragEnter: case QEvent::DragMove: case QEvent::DragLeave:
2888         case QEvent::Drop: case QEvent::DragResponse:
2889         case QEvent::ChildAdded: case QEvent::ChildPolished:
2890         case QEvent::ChildRemoved:
2891         case QEvent::UpdateRequest:
2892         case QEvent::UpdateLater:
2893         case QEvent::LocaleChange:
2894         case QEvent::Style:
2895         case QEvent::IconDrag:
2896         case QEvent::StyleChange:
2897         case QEvent::GraphicsSceneDragEnter:
2898         case QEvent::GraphicsSceneDragMove:
2899         case QEvent::GraphicsSceneDragLeave:
2900         case QEvent::GraphicsSceneDrop:
2901         case QEvent::DynamicPropertyChange:
2902         case QEvent::NetworkReplyUpdated:
2903             break;
2904         default:
2905             if (d->gestureManager->thread() == QThread::currentThread()) {
2906                 if (receiver->isWidgetType()) {
2907                     if (d->gestureManager->filterEvent(static_cast<QWidget *>(receiver), e))
2908                         return true;
2909                 } else {
2910                     // a special case for events that go to QGesture objects.
2911                     // We pass the object to the gesture manager and it'll figure
2912                     // out if it's QGesture or not.
2913                     if (d->gestureManager->filterEvent(receiver, e))
2914                         return true;
2915                 }
2916             }
2917             break;
2918         }
2919     }
2920 #endif // QT_NO_GESTURES
2921 
2922     switch (e->type()) {
2923     case QEvent::ApplicationDeactivate:
2924         // Close all popups (triggers when switching applications
2925         // by pressing ALT-TAB on Windows, which is not receive as key event.
2926         closeAllPopups();
2927         break;
2928     case QEvent::Wheel: // User input and window activation makes tooltips sleep
2929     case QEvent::ActivationChange:
2930     case QEvent::KeyPress:
2931     case QEvent::KeyRelease:
2932     case QEvent::FocusOut:
2933     case QEvent::FocusIn:
2934     case QEvent::MouseButtonPress:
2935     case QEvent::MouseButtonRelease:
2936     case QEvent::MouseButtonDblClick:
2937         d->toolTipFallAsleep.stop();
2938         Q_FALLTHROUGH();
2939     case QEvent::Leave:
2940         d->toolTipWakeUp.stop();
2941     default:
2942         break;
2943     }
2944 
2945     switch (e->type()) {
2946         case QEvent::KeyPress: {
2947             QKeyEvent* keyEvent = static_cast<QKeyEvent*>(e);
2948             const int key = keyEvent->key();
2949             // When a key press is received which is not spontaneous then it needs to
2950             // be manually sent as a shortcut override event to ensure that any
2951             // matching shortcut is triggered first. This enables emulation/playback
2952             // of recorded events to still have the same effect.
2953             if (!e->spontaneous() && receiver->isWidgetType()) {
2954                 if (qt_sendShortcutOverrideEvent(qobject_cast<QWidget *>(receiver), keyEvent->timestamp(),
2955                                                  key, keyEvent->modifiers(), keyEvent->text(),
2956                                                  keyEvent->isAutoRepeat(), keyEvent->count()))
2957                     return true;
2958             }
2959             qt_in_tab_key_event = (key == Qt::Key_Backtab
2960                         || key == Qt::Key_Tab
2961                         || key == Qt::Key_Left
2962                         || key == Qt::Key_Up
2963                         || key == Qt::Key_Right
2964                         || key == Qt::Key_Down);
2965         }
2966         default:
2967             break;
2968     }
2969 
2970     bool res = false;
2971     if (!receiver->isWidgetType()) {
2972         res = d->notify_helper(receiver, e);
2973     } else switch (e->type()) {
2974     case QEvent::ShortcutOverride:
2975     case QEvent::KeyPress:
2976     case QEvent::KeyRelease:
2977         {
2978             bool isWidget = receiver->isWidgetType();
2979 #if QT_CONFIG(graphicsview)
2980             const bool isGraphicsWidget = !isWidget && qobject_cast<QGraphicsWidget *>(receiver);
2981 #endif
2982             QKeyEvent* key = static_cast<QKeyEvent*>(e);
2983             bool def = key->isAccepted();
2984             QPointer<QObject> pr = receiver;
2985             while (receiver) {
2986                 if (def)
2987                     key->accept();
2988                 else
2989                     key->ignore();
2990                 QWidget *w = isWidget ? static_cast<QWidget *>(receiver) : nullptr;
2991 #if QT_CONFIG(graphicsview)
2992                 QGraphicsWidget *gw = isGraphicsWidget ? static_cast<QGraphicsWidget *>(receiver) : nullptr;
2993 #endif
2994                 res = d->notify_helper(receiver, e);
2995 
2996                 if ((res && key->isAccepted())
2997                     /*
2998                        QLineEdit will emit a signal on Key_Return, but
2999                        ignore the event, and sometimes the connected
3000                        slot deletes the QLineEdit (common in itemview
3001                        delegates), so we have to check if the widget
3002                        was destroyed even if the event was ignored (to
3003                        prevent a crash)
3004 
3005                        note that we don't have to reset pw while
3006                        propagating (because the original receiver will
3007                        be destroyed if one of its ancestors is)
3008                     */
3009                     || !pr
3010                     || (isWidget && (w->isWindow() || !w->parentWidget()))
3011 #if QT_CONFIG(graphicsview)
3012                     || (isGraphicsWidget && (gw->isWindow() || !gw->parentWidget()))
3013 #endif
3014                     ) {
3015                     break;
3016                 }
3017 
3018 #if QT_CONFIG(graphicsview)
3019                 receiver = w ? (QObject *)w->parentWidget() : (QObject *)gw->parentWidget();
3020 #else
3021                 receiver = w->parentWidget();
3022 #endif
3023             }
3024             qt_in_tab_key_event = false;
3025         }
3026         break;
3027     case QEvent::MouseButtonPress:
3028     case QEvent::MouseButtonRelease:
3029     case QEvent::MouseButtonDblClick:
3030     case QEvent::MouseMove:
3031         {
3032             QWidget* w = static_cast<QWidget *>(receiver);
3033 
3034             QMouseEvent* mouse = static_cast<QMouseEvent*>(e);
3035             QPoint relpos = mouse->pos();
3036 
3037             if (e->spontaneous()) {
3038                 if (e->type() != QEvent::MouseMove)
3039                     QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, e, relpos);
3040 
3041                 // ### Qt 5 These dynamic tool tips should be an OPT-IN feature. Some platforms
3042                 // like OS X (probably others too), can optimize their views by not
3043                 // dispatching mouse move events. We have attributes to control hover,
3044                 // and mouse tracking, but as long as we are deciding to implement this
3045                 // feature without choice of opting-in or out, you ALWAYS have to have
3046                 // tracking enabled. Therefore, the other properties give a false sense of
3047                 // performance enhancement.
3048                 if (e->type() == QEvent::MouseMove && mouse->buttons() == 0
3049                     && w->rect().contains(relpos)) { // Outside due to mouse grab?
3050                     d->toolTipWidget = w;
3051                     d->toolTipPos = relpos;
3052                     d->toolTipGlobalPos = mouse->globalPos();
3053                     QStyle *s = d->toolTipWidget->style();
3054                     int wakeDelay = s->styleHint(QStyle::SH_ToolTip_WakeUpDelay, nullptr, d->toolTipWidget, nullptr);
3055                     d->toolTipWakeUp.start(d->toolTipFallAsleep.isActive() ? 20 : wakeDelay, this);
3056                 }
3057             }
3058 
3059             bool eventAccepted = mouse->isAccepted();
3060 
3061             QPointer<QWidget> pw = w;
3062             while (w) {
3063                 QMouseEvent me(mouse->type(), relpos, mouse->windowPos(), mouse->globalPos(),
3064                                mouse->button(), mouse->buttons(), mouse->modifiers(), mouse->source());
3065                 me.spont = mouse->spontaneous();
3066                 me.setTimestamp(mouse->timestamp());
3067                 QGuiApplicationPrivate::setMouseEventFlags(&me, mouse->flags());
3068                 // throw away any mouse-tracking-only mouse events
3069                 if (!w->hasMouseTracking()
3070                     && mouse->type() == QEvent::MouseMove && mouse->buttons() == 0) {
3071                     // but still send them through all application event filters (normally done by notify_helper)
3072                     d->sendThroughApplicationEventFilters(w, w == receiver ? mouse : &me);
3073                     res = true;
3074                 } else {
3075                     w->setAttribute(Qt::WA_NoMouseReplay, false);
3076                     res = d->notify_helper(w, w == receiver ? mouse : &me);
3077                     e->spont = false;
3078                 }
3079                 eventAccepted = (w == receiver ? mouse : &me)->isAccepted();
3080                 if (res && eventAccepted)
3081                     break;
3082                 if (w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation))
3083                     break;
3084                 relpos += w->pos();
3085                 w = w->parentWidget();
3086             }
3087 
3088             mouse->setAccepted(eventAccepted);
3089 
3090             if (e->type() == QEvent::MouseMove) {
3091                 if (!pw)
3092                     break;
3093 
3094                 w = static_cast<QWidget *>(receiver);
3095                 relpos = mouse->pos();
3096                 QPoint diff = relpos - w->mapFromGlobal(d->hoverGlobalPos);
3097                 while (w) {
3098                     if (w->testAttribute(Qt::WA_Hover) &&
3099                         (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == w->window())) {
3100                         QHoverEvent he(QEvent::HoverMove, relpos, relpos - diff, mouse->modifiers());
3101                         d->notify_helper(w, &he);
3102                     }
3103                     if (w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation))
3104                         break;
3105                     relpos += w->pos();
3106                     w = w->parentWidget();
3107                 }
3108             }
3109 
3110             d->hoverGlobalPos = mouse->globalPos();
3111         }
3112         break;
3113 #if QT_CONFIG(wheelevent)
3114     case QEvent::Wheel:
3115         {
3116             QWidget* w = static_cast<QWidget *>(receiver);
3117 
3118             // QTBUG-40656, QTBUG-42731: ignore wheel events when a popup (QComboBox) is open.
3119             if (const QWidget *popup = QApplication::activePopupWidget()) {
3120                 if (w->window() != popup)
3121                     return true;
3122             }
3123 
3124             QWheelEvent* wheel = static_cast<QWheelEvent*>(e);
3125             const bool spontaneous = wheel->spontaneous();
3126             const Qt::ScrollPhase phase = wheel->phase();
3127 
3128             // Ideally, we should lock on a widget when it starts receiving wheel
3129             // events. This avoids other widgets to start receiving those events
3130             // as the mouse cursor hovers them. However, given the way common
3131             // wheeled mice work, there's no certain way of connecting different
3132             // wheel events as a stream. This results in the NoScrollPhase case,
3133             // where we just send the event from the original receiver and up its
3134             // hierarchy until the event gets accepted.
3135             //
3136             // In the case of more evolved input devices, like Apple's trackpad or
3137             // Magic Mouse, we receive the scroll phase information. This helps us
3138             // connect wheel events as a stream and therefore makes it easier to
3139             // lock on the widget onto which the scrolling was initiated.
3140             //
3141             // We assume that, when supported, the phase cycle follows the pattern:
3142             //
3143             //         ScrollBegin (ScrollUpdate* ScrollMomentum* ScrollEnd)+
3144             //
3145             // This means that we can have scrolling sequences (starting with ScrollBegin)
3146             // or partial sequences (after a ScrollEnd and starting with ScrollUpdate).
3147             // If wheel_widget is null because it was deleted, we also take the same
3148             // code path as an initial sequence.
3149             if (!spontaneous) {
3150                 // wheel_widget may forward the wheel event to a delegate widget,
3151                 // either directly or indirectly (e.g. QAbstractScrollArea will
3152                 // forward to its QScrollBars through viewportEvent()). In that
3153                 // case, the event will not be spontaneous but synthesized, so
3154                 // we can send it straight to the receiver.
3155                 wheel->ignore();
3156                 res = d->notify_helper(w, wheel);
3157             } else if (phase == Qt::NoScrollPhase || phase == Qt::ScrollBegin || !QApplicationPrivate::wheel_widget) {
3158                 // A system-generated ScrollBegin event starts a new user scrolling
3159                 // sequence, so we reset wheel_widget in case no one accepts the event
3160                 // or if we didn't get (or missed) a ScrollEnd previously.
3161                 if (phase == Qt::ScrollBegin)
3162                     QApplicationPrivate::wheel_widget = nullptr;
3163 
3164                 const QPoint relpos = wheel->position().toPoint();
3165 
3166                 if (phase == Qt::NoScrollPhase || phase == Qt::ScrollUpdate)
3167                     QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, e, relpos);
3168 
3169 #if QT_DEPRECATED_SINCE(5, 14)
3170 QT_WARNING_PUSH
3171 QT_WARNING_DISABLE_DEPRECATED
3172                 QWheelEvent we(relpos, wheel->globalPos(), wheel->pixelDelta(), wheel->angleDelta(), wheel->delta(), wheel->orientation(), wheel->buttons(),
3173                                wheel->modifiers(), phase, wheel->source(), wheel->inverted());
3174 QT_WARNING_POP
3175 #else
3176                 QWheelEvent we(relpos, wheel->globalPosition(), wheel->pixelDelta(), wheel->angleDelta(), wheel->buttons(),
3177                                wheel->modifiers(), phase, wheel->inverted(), wheel->source());
3178 #endif
3179                 we.setTimestamp(wheel->timestamp());
3180                 bool eventAccepted;
3181                 do {
3182                     we.spont = w == receiver;
3183                     we.ignore();
3184                     res = d->notify_helper(w, &we);
3185                     eventAccepted = we.isAccepted();
3186                     if (res && eventAccepted) {
3187                         // A new scrolling sequence or partial sequence starts and w has accepted
3188                         // the event. Therefore, we can set wheel_widget, but only if it's not
3189                         // the end of a sequence.
3190                         if (QApplicationPrivate::wheel_widget == nullptr && (phase == Qt::ScrollBegin || phase == Qt::ScrollUpdate))
3191                             QApplicationPrivate::wheel_widget = w;
3192                         break;
3193                     }
3194                     if (w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation))
3195                         break;
3196 
3197                     we.p += w->pos();
3198                     w = w->parentWidget();
3199                 } while (w);
3200                 wheel->setAccepted(eventAccepted);
3201             } else {
3202                 // The phase is either ScrollUpdate, ScrollMomentum, or ScrollEnd, and wheel_widget
3203                 // is set. Since it accepted the wheel event previously, we continue
3204                 // sending those events until we get a ScrollEnd, which signifies
3205                 // the end of the natural scrolling sequence.
3206                 const QPoint &relpos = QApplicationPrivate::wheel_widget->mapFromGlobal(wheel->globalPosition().toPoint());
3207 #if QT_DEPRECATED_SINCE(5, 0)
3208 QT_WARNING_PUSH
3209 QT_WARNING_DISABLE_DEPRECATED
3210                 QWheelEvent we(relpos, wheel->globalPos(), wheel->pixelDelta(), wheel->angleDelta(), wheel->delta(), wheel->orientation(), wheel->buttons(),
3211                                wheel->modifiers(), wheel->phase(), wheel->source());
3212 QT_WARNING_POP
3213 #else
3214                 QWheelEvent we(relpos, wheel->globalPosition(), wheel->pixelDelta(), wheel->angleDelta(), wheel->buttons(),
3215                                wheel->modifiers(), wheel->phase(), wheel->inverted(), wheel->source());
3216 #endif
3217                 we.setTimestamp(wheel->timestamp());
3218                 we.spont = true;
3219                 we.ignore();
3220                 d->notify_helper(QApplicationPrivate::wheel_widget, &we);
3221                 wheel->setAccepted(we.isAccepted());
3222                 if (phase == Qt::ScrollEnd)
3223                     QApplicationPrivate::wheel_widget = nullptr;
3224             }
3225         }
3226         break;
3227 #endif
3228 #ifndef QT_NO_CONTEXTMENU
3229     case QEvent::ContextMenu:
3230         {
3231             QWidget* w = static_cast<QWidget *>(receiver);
3232             QContextMenuEvent *context = static_cast<QContextMenuEvent*>(e);
3233             QPoint relpos = context->pos();
3234             bool eventAccepted = context->isAccepted();
3235             while (w) {
3236                 QContextMenuEvent ce(context->reason(), relpos, context->globalPos(), context->modifiers());
3237                 ce.spont = e->spontaneous();
3238                 res = d->notify_helper(w, w == receiver ? context : &ce);
3239                 eventAccepted = ((w == receiver) ? context : &ce)->isAccepted();
3240                 e->spont = false;
3241 
3242                 if ((res && eventAccepted)
3243                     || w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation))
3244                     break;
3245 
3246                 relpos += w->pos();
3247                 w = w->parentWidget();
3248             }
3249             context->setAccepted(eventAccepted);
3250         }
3251         break;
3252 #endif // QT_NO_CONTEXTMENU
3253 #if QT_CONFIG(tabletevent)
3254     case QEvent::TabletMove:
3255     case QEvent::TabletPress:
3256     case QEvent::TabletRelease:
3257         {
3258             QWidget *w = static_cast<QWidget *>(receiver);
3259             QTabletEvent *tablet = static_cast<QTabletEvent*>(e);
3260             QPointF relpos = tablet->posF();
3261             bool eventAccepted = tablet->isAccepted();
3262             while (w) {
3263                 QTabletEvent te(tablet->type(), relpos, tablet->globalPosF(),
3264                                 tablet->deviceType(), tablet->pointerType(),
3265                                 tablet->pressure(), tablet->xTilt(), tablet->yTilt(),
3266                                 tablet->tangentialPressure(), tablet->rotation(), tablet->z(),
3267                                 tablet->modifiers(), tablet->uniqueId(), tablet->button(), tablet->buttons());
3268                 te.spont = e->spontaneous();
3269                 te.setAccepted(false);
3270                 res = d->notify_helper(w, w == receiver ? tablet : &te);
3271                 eventAccepted = ((w == receiver) ? tablet : &te)->isAccepted();
3272                 e->spont = false;
3273                 if ((res && eventAccepted)
3274                      || w->isWindow()
3275                      || w->testAttribute(Qt::WA_NoMousePropagation))
3276                     break;
3277 
3278                 relpos += w->pos();
3279                 w = w->parentWidget();
3280             }
3281             tablet->setAccepted(eventAccepted);
3282         }
3283         break;
3284 #endif // QT_CONFIG(tabletevent)
3285 
3286 #if !defined(QT_NO_TOOLTIP) || QT_CONFIG(whatsthis)
3287     case QEvent::ToolTip:
3288     case QEvent::WhatsThis:
3289     case QEvent::QueryWhatsThis:
3290         {
3291             QWidget* w = static_cast<QWidget *>(receiver);
3292             QHelpEvent *help = static_cast<QHelpEvent*>(e);
3293             QPoint relpos = help->pos();
3294             bool eventAccepted = help->isAccepted();
3295             while (w) {
3296                 QHelpEvent he(help->type(), relpos, help->globalPos());
3297                 he.spont = e->spontaneous();
3298                 res = d->notify_helper(w, w == receiver ? help : &he);
3299                 e->spont = false;
3300                 eventAccepted = (w == receiver ? help : &he)->isAccepted();
3301                 if ((res && eventAccepted) || w->isWindow())
3302                     break;
3303 
3304                 relpos += w->pos();
3305                 w = w->parentWidget();
3306             }
3307             help->setAccepted(eventAccepted);
3308         }
3309         break;
3310 #endif
3311 #if QT_CONFIG(statustip) || QT_CONFIG(whatsthis)
3312     case QEvent::StatusTip:
3313     case QEvent::WhatsThisClicked:
3314         {
3315             QWidget *w = static_cast<QWidget *>(receiver);
3316             while (w) {
3317                 res = d->notify_helper(w, e);
3318                 if ((res && e->isAccepted()) || w->isWindow())
3319                     break;
3320                 w = w->parentWidget();
3321             }
3322         }
3323         break;
3324 #endif
3325 
3326 #if QT_CONFIG(draganddrop)
3327     case QEvent::DragEnter: {
3328             QWidget* w = static_cast<QWidget *>(receiver);
3329             QDragEnterEvent *dragEvent = static_cast<QDragEnterEvent *>(e);
3330 #if QT_CONFIG(graphicsview)
3331             // QGraphicsProxyWidget handles its own propagation,
3332             // and we must not change QDragManagers currentTarget.
3333             const auto &extra = w->window()->d_func()->extra;
3334             if (extra && extra->proxyWidget) {
3335                 res = d->notify_helper(w, dragEvent);
3336                 break;
3337             }
3338 #endif
3339             while (w) {
3340                 if (w->isEnabled() && w->acceptDrops()) {
3341                     res = d->notify_helper(w, dragEvent);
3342                     if (res && dragEvent->isAccepted()) {
3343                         QDragManager::self()->setCurrentTarget(w);
3344                         break;
3345                     }
3346                 }
3347                 if (w->isWindow())
3348                     break;
3349                 dragEvent->p = w->mapToParent(dragEvent->p.toPoint());
3350                 w = w->parentWidget();
3351             }
3352         }
3353         break;
3354     case QEvent::DragMove:
3355     case QEvent::Drop:
3356     case QEvent::DragLeave: {
3357             QWidget* w = static_cast<QWidget *>(receiver);
3358 #if QT_CONFIG(graphicsview)
3359             // QGraphicsProxyWidget handles its own propagation,
3360             // and we must not change QDragManagers currentTarget.
3361             const auto &extra = w->window()->d_func()->extra;
3362             bool isProxyWidget = extra && extra->proxyWidget;
3363             if (!isProxyWidget)
3364 #endif
3365                 w = qobject_cast<QWidget *>(QDragManager::self()->currentTarget());
3366 
3367             if (!w) {
3368                     break;
3369             }
3370             if (e->type() == QEvent::DragMove || e->type() == QEvent::Drop) {
3371                 QDropEvent *dragEvent = static_cast<QDropEvent *>(e);
3372                 QWidget *origReciver = static_cast<QWidget *>(receiver);
3373                 while (origReciver && w != origReciver) {
3374                     dragEvent->p = origReciver->mapToParent(dragEvent->p.toPoint());
3375                     origReciver = origReciver->parentWidget();
3376                 }
3377             }
3378             res = d->notify_helper(w, e);
3379             if (e->type() != QEvent::DragMove
3380 #if QT_CONFIG(graphicsview)
3381                 && !isProxyWidget
3382 #endif
3383                 )
3384                 QDragManager::self()->setCurrentTarget(nullptr, e->type() == QEvent::Drop);
3385         }
3386         break;
3387 #endif
3388     case QEvent::TouchBegin:
3389     // Note: TouchUpdate and TouchEnd events are never propagated
3390     {
3391         QWidget *widget = static_cast<QWidget *>(receiver);
3392         QTouchEvent *touchEvent = static_cast<QTouchEvent *>(e);
3393         bool eventAccepted = touchEvent->isAccepted();
3394         bool acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents);
3395 
3396         if (acceptTouchEvents && e->spontaneous()) {
3397             const QPoint localPos = touchEvent->touchPoints()[0].pos().toPoint();
3398             QApplicationPrivate::giveFocusAccordingToFocusPolicy(widget, e, localPos);
3399         }
3400 
3401 #ifndef QT_NO_GESTURES
3402         QPointer<QWidget> gesturePendingWidget;
3403 #endif
3404 
3405         while (widget) {
3406             // first, try to deliver the touch event
3407             acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents);
3408             touchEvent->setTarget(widget);
3409             touchEvent->setAccepted(acceptTouchEvents);
3410             QPointer<QWidget> p = widget;
3411             res = acceptTouchEvents && d->notify_helper(widget, touchEvent);
3412             eventAccepted = touchEvent->isAccepted();
3413             if (p.isNull()) {
3414                 // widget was deleted
3415                 widget = nullptr;
3416             } else {
3417                 widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, res && eventAccepted);
3418             }
3419             touchEvent->spont = false;
3420             if (res && eventAccepted) {
3421                 // the first widget to accept the TouchBegin gets an implicit grab.
3422                 d->activateImplicitTouchGrab(widget, touchEvent);
3423                 break;
3424             }
3425 #ifndef QT_NO_GESTURES
3426             if (gesturePendingWidget.isNull() && widget && QGestureManager::gesturePending(widget))
3427                 gesturePendingWidget = widget;
3428 #endif
3429             if (p.isNull() || widget->isWindow() || widget->testAttribute(Qt::WA_NoMousePropagation))
3430                 break;
3431 
3432             QPoint offset = widget->pos();
3433             widget = widget->parentWidget();
3434             touchEvent->setTarget(widget);
3435             for (int i = 0; i < touchEvent->_touchPoints.size(); ++i) {
3436                 QTouchEvent::TouchPoint &pt = touchEvent->_touchPoints[i];
3437                 pt.d->pos = pt.pos() + offset;
3438                 pt.d->startPos = pt.startPos() + offset;
3439                 pt.d->lastPos = pt.lastPos() + offset;
3440             }
3441         }
3442 
3443 #ifndef QT_NO_GESTURES
3444         if (!eventAccepted && !gesturePendingWidget.isNull()) {
3445             // the first widget subscribed to a gesture gets an implicit grab
3446             d->activateImplicitTouchGrab(gesturePendingWidget, touchEvent);
3447         }
3448 #endif
3449 
3450         touchEvent->setAccepted(eventAccepted);
3451         break;
3452     }
3453     case QEvent::TouchUpdate:
3454     case QEvent::TouchEnd:
3455     {
3456         QWidget *widget = static_cast<QWidget *>(receiver);
3457         // We may get here if the widget is subscribed to a gesture,
3458         // but has not accepted TouchBegin. Propagate touch events
3459         // only if TouchBegin has been accepted.
3460         if (widget->testAttribute(Qt::WA_WState_AcceptedTouchBeginEvent))
3461             res = d->notify_helper(widget, e);
3462         break;
3463     }
3464     case QEvent::RequestSoftwareInputPanel:
3465         inputMethod()->show();
3466         break;
3467     case QEvent::CloseSoftwareInputPanel:
3468         inputMethod()->hide();
3469         break;
3470 
3471 #ifndef QT_NO_GESTURES
3472     case QEvent::NativeGesture:
3473     {
3474         // only propagate the first gesture event (after the GID_BEGIN)
3475         QWidget *w = static_cast<QWidget *>(receiver);
3476         while (w) {
3477             e->ignore();
3478             res = d->notify_helper(w, e);
3479             if ((res && e->isAccepted()) || w->isWindow())
3480                 break;
3481             w = w->parentWidget();
3482         }
3483         break;
3484     }
3485     case QEvent::Gesture:
3486     case QEvent::GestureOverride:
3487     {
3488         if (receiver->isWidgetType()) {
3489             QWidget *w = static_cast<QWidget *>(receiver);
3490             QGestureEvent *gestureEvent = static_cast<QGestureEvent *>(e);
3491             QList<QGesture *> allGestures = gestureEvent->gestures();
3492 
3493             bool eventAccepted = gestureEvent->isAccepted();
3494             bool wasAccepted = eventAccepted;
3495             while (w) {
3496                 // send only gestures the widget expects
3497                 QList<QGesture *> gestures;
3498                 QWidgetPrivate *wd = w->d_func();
3499                 for (int i = 0; i < allGestures.size();) {
3500                     QGesture *g = allGestures.at(i);
3501                     Qt::GestureType type = g->gestureType();
3502                     QMap<Qt::GestureType, Qt::GestureFlags>::iterator contextit =
3503                             wd->gestureContext.find(type);
3504                     bool deliver = contextit != wd->gestureContext.end() &&
3505                         (g->state() == Qt::GestureStarted || w == receiver ||
3506                          (contextit.value() & Qt::ReceivePartialGestures));
3507                     if (deliver) {
3508                         allGestures.removeAt(i);
3509                         gestures.append(g);
3510                     } else {
3511                         ++i;
3512                     }
3513                 }
3514                 if (!gestures.isEmpty()) { // we have gestures for this w
3515                     QGestureEvent ge(gestures);
3516                     ge.t = gestureEvent->t;
3517                     ge.spont = gestureEvent->spont;
3518                     ge.m_accept = wasAccepted;
3519                     ge.m_accepted = gestureEvent->m_accepted;
3520                     res = d->notify_helper(w, &ge);
3521                     gestureEvent->spont = false;
3522                     eventAccepted = ge.isAccepted();
3523                     for (int i = 0; i < gestures.size(); ++i) {
3524                         QGesture *g = gestures.at(i);
3525                         // Ignore res [event return value] because handling of multiple gestures
3526                         // packed into a single QEvent depends on not consuming the event
3527                         if (eventAccepted || ge.isAccepted(g)) {
3528                             // if the gesture was accepted, mark the target widget for it
3529                             gestureEvent->m_targetWidgets[g->gestureType()] = w;
3530                             gestureEvent->setAccepted(g, true);
3531                         } else {
3532                             // if the gesture was explicitly ignored by the application,
3533                             // put it back so a parent can get it
3534                             allGestures.append(g);
3535                         }
3536                     }
3537                 }
3538                 if (allGestures.isEmpty()) // everything delivered
3539                     break;
3540                 if (w->isWindow())
3541                     break;
3542                 w = w->parentWidget();
3543             }
3544             for (QGesture *g : qAsConst(allGestures))
3545                 gestureEvent->setAccepted(g, false);
3546             gestureEvent->m_accept = false; // to make sure we check individual gestures
3547         } else {
3548             res = d->notify_helper(receiver, e);
3549         }
3550         break;
3551     }
3552 #endif // QT_NO_GESTURES
3553 #ifdef Q_OS_MAC
3554     // Enable touch events on enter, disable on leave.
3555     typedef void (*RegisterTouchWindowFn)(QWindow *,  bool);
3556     case QEvent::Enter:
3557         if (receiver->isWidgetType()) {
3558             QWidget *w = static_cast<QWidget *>(receiver);
3559             if (w->testAttribute(Qt::WA_AcceptTouchEvents)) {
3560                 RegisterTouchWindowFn registerTouchWindow = reinterpret_cast<RegisterTouchWindowFn>
3561                         (platformNativeInterface()->nativeResourceFunctionForIntegration("registertouchwindow"));
3562                 if (registerTouchWindow)
3563                     registerTouchWindow(w->window()->windowHandle(), true);
3564             }
3565         }
3566         res = d->notify_helper(receiver, e);
3567     break;
3568     case QEvent::Leave:
3569         if (receiver->isWidgetType()) {
3570             QWidget *w = static_cast<QWidget *>(receiver);
3571             if (w->testAttribute(Qt::WA_AcceptTouchEvents)) {
3572                 RegisterTouchWindowFn registerTouchWindow = reinterpret_cast<RegisterTouchWindowFn>
3573                         (platformNativeInterface()->nativeResourceFunctionForIntegration("registertouchwindow"));
3574                 if (registerTouchWindow)
3575                     registerTouchWindow(w->window()->windowHandle(), false);
3576             }
3577         }
3578         res = d->notify_helper(receiver, e);
3579     break;
3580 #endif
3581     default:
3582         res = d->notify_helper(receiver, e);
3583         break;
3584     }
3585 
3586     return res;
3587 }
3588 
notify_helper(QObject * receiver,QEvent * e)3589 bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e)
3590 {
3591     // These tracepoints (and the whole function, actually) are very similar
3592     // to the ones in QCoreApplicationPrivate::notify_helper; the reason for their
3593     // duplication is because tracepoint symbols are not exported by QtCore.
3594     // If you adjust the tracepoints here, consider adjusting QCoreApplicationPrivate too.
3595     Q_TRACE(QApplication_notify_entry, receiver, e, e->type());
3596     bool consumed = false;
3597     bool filtered = false;
3598     Q_TRACE_EXIT(QApplication_notify_exit, consumed, filtered);
3599 
3600     // send to all application event filters
3601     if (threadRequiresCoreApplication()
3602         && receiver->d_func()->threadData.loadRelaxed()->thread.loadAcquire() == mainThread()
3603         && sendThroughApplicationEventFilters(receiver, e)) {
3604         filtered = true;
3605         return filtered;
3606     }
3607 
3608     if (receiver->isWidgetType()) {
3609         QWidget *widget = static_cast<QWidget *>(receiver);
3610 
3611 #if !defined(QT_NO_CURSOR)
3612         // toggle HasMouse widget state on enter and leave
3613         if ((e->type() == QEvent::Enter || e->type() == QEvent::DragEnter) &&
3614             (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == widget->window()))
3615             widget->setAttribute(Qt::WA_UnderMouse, true);
3616         else if (e->type() == QEvent::Leave || e->type() == QEvent::DragLeave)
3617             widget->setAttribute(Qt::WA_UnderMouse, false);
3618 #endif
3619 
3620         if (QLayout *layout=widget->d_func()->layout) {
3621             layout->widgetEvent(e);
3622         }
3623     }
3624 
3625     // send to all receiver event filters
3626     if (sendThroughObjectEventFilters(receiver, e)) {
3627         filtered = true;
3628         return filtered;
3629     }
3630 
3631     // deliver the event
3632     consumed = receiver->event(e);
3633 
3634     QCoreApplicationPrivate::setEventSpontaneous(e, false);
3635     return consumed;
3636 }
3637 
inPopupMode()3638 bool QApplicationPrivate::inPopupMode()
3639 {
3640     return QApplicationPrivate::popupWidgets != nullptr;
3641 }
3642 
ungrabKeyboardForPopup(QWidget * popup)3643 static void ungrabKeyboardForPopup(QWidget *popup)
3644 {
3645     if (QWidget::keyboardGrabber())
3646         qt_widget_private(QWidget::keyboardGrabber())->stealKeyboardGrab(true);
3647     else
3648         qt_widget_private(popup)->stealKeyboardGrab(false);
3649 }
3650 
ungrabMouseForPopup(QWidget * popup)3651 static void ungrabMouseForPopup(QWidget *popup)
3652 {
3653     if (QWidget::mouseGrabber())
3654         qt_widget_private(QWidget::mouseGrabber())->stealMouseGrab(true);
3655     else
3656         qt_widget_private(popup)->stealMouseGrab(false);
3657 }
3658 
3659 static bool popupGrabOk;
3660 
grabForPopup(QWidget * popup)3661 static void grabForPopup(QWidget *popup)
3662 {
3663     Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
3664     popupGrabOk = qt_widget_private(popup)->stealKeyboardGrab(true);
3665     if (popupGrabOk) {
3666         popupGrabOk = qt_widget_private(popup)->stealMouseGrab(true);
3667         if (!popupGrabOk) {
3668             // transfer grab back to the keyboard grabber if any
3669             ungrabKeyboardForPopup(popup);
3670         }
3671     }
3672 }
3673 
3674 extern QWidget *qt_popup_down;
3675 extern bool qt_replay_popup_mouse_event;
3676 extern bool qt_popup_down_closed;
3677 
closePopup(QWidget * popup)3678 void QApplicationPrivate::closePopup(QWidget *popup)
3679 {
3680     if (!popupWidgets)
3681         return;
3682     popupWidgets->removeAll(popup);
3683 
3684      if (popup == qt_popup_down) {
3685          qt_button_down = nullptr;
3686          qt_popup_down_closed = true;
3687          qt_popup_down = nullptr;
3688      }
3689 
3690     if (QApplicationPrivate::popupWidgets->count() == 0) { // this was the last popup
3691         delete QApplicationPrivate::popupWidgets;
3692         QApplicationPrivate::popupWidgets = nullptr;
3693         qt_popup_down_closed = false;
3694 
3695         if (popupGrabOk) {
3696             popupGrabOk = false;
3697 
3698             if (popup->geometry().contains(QPoint(QGuiApplicationPrivate::mousePressX,
3699                                                   QGuiApplicationPrivate::mousePressY))
3700                 || popup->testAttribute(Qt::WA_NoMouseReplay)) {
3701                 // mouse release event or inside
3702                 qt_replay_popup_mouse_event = false;
3703             } else { // mouse press event
3704                 qt_replay_popup_mouse_event = true;
3705             }
3706 
3707             // transfer grab back to mouse grabber if any, otherwise release the grab
3708             ungrabMouseForPopup(popup);
3709 
3710             // transfer grab back to keyboard grabber if any, otherwise release the grab
3711             ungrabKeyboardForPopup(popup);
3712         }
3713 
3714         if (active_window) {
3715             if (QWidget *fw = active_window->focusWidget()) {
3716                 if (fw != QApplication::focusWidget()) {
3717                     fw->setFocus(Qt::PopupFocusReason);
3718                 } else {
3719                     QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason);
3720                     QCoreApplication::sendEvent(fw, &e);
3721                 }
3722             }
3723         }
3724 
3725     } else {
3726         // A popup was closed, so the previous popup gets the focus.
3727         QWidget* aw = QApplicationPrivate::popupWidgets->constLast();
3728         if (QWidget *fw = aw->focusWidget())
3729             fw->setFocus(Qt::PopupFocusReason);
3730 
3731         // can become nullptr due to setFocus() above
3732         if (QApplicationPrivate::popupWidgets &&
3733             QApplicationPrivate::popupWidgets->count() == 1) // grab mouse/keyboard
3734             grabForPopup(aw);
3735     }
3736 
3737 }
3738 
3739 int openPopupCount = 0;
3740 
openPopup(QWidget * popup)3741 void QApplicationPrivate::openPopup(QWidget *popup)
3742 {
3743     openPopupCount++;
3744     if (!popupWidgets) // create list
3745         popupWidgets = new QWidgetList;
3746     popupWidgets->append(popup); // add to end of list
3747 
3748     if (QApplicationPrivate::popupWidgets->count() == 1) // grab mouse/keyboard
3749         grabForPopup(popup);
3750 
3751     // popups are not focus-handled by the window system (the first
3752     // popup grabbed the keyboard), so we have to do that manually: A
3753     // new popup gets the focus
3754     if (popup->focusWidget()) {
3755         popup->focusWidget()->setFocus(Qt::PopupFocusReason);
3756     } else if (popupWidgets->count() == 1) { // this was the first popup
3757         if (QWidget *fw = QApplication::focusWidget()) {
3758             QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
3759             QCoreApplication::sendEvent(fw, &e);
3760         }
3761     }
3762 }
3763 
3764 #ifdef QT_KEYPAD_NAVIGATION
3765 /*!
3766     Sets the kind of focus navigation Qt should use to \a mode.
3767 
3768     This feature is available in Qt for Embedded Linux only.
3769 
3770     \since 4.6
3771 */
setNavigationMode(Qt::NavigationMode mode)3772 void QApplication::setNavigationMode(Qt::NavigationMode mode)
3773 {
3774     QApplicationPrivate::navigationMode = mode;
3775 }
3776 
3777 /*!
3778     Returns what kind of focus navigation Qt is using.
3779 
3780     This feature is available in Qt for Embedded Linux only.
3781 
3782     \since 4.6
3783 */
navigationMode()3784 Qt::NavigationMode QApplication::navigationMode()
3785 {
3786     return QApplicationPrivate::navigationMode;
3787 }
3788 
3789 # if QT_DEPRECATED_SINCE(5, 13)
3790 /*!
3791     Sets whether Qt should use focus navigation suitable for use with a
3792     minimal keypad.
3793 
3794     This feature is available in Qt for Embedded Linux, and Windows CE only.
3795 
3796     \note On Windows CE this feature is disabled by default for touch device
3797           mkspecs. To enable keypad navigation, build Qt with
3798           QT_KEYPAD_NAVIGATION defined.
3799 
3800     \deprecated
3801 
3802     \sa setNavigationMode()
3803 */
setKeypadNavigationEnabled(bool enable)3804 void QApplication::setKeypadNavigationEnabled(bool enable)
3805 {
3806     if (enable) {
3807         QApplication::setNavigationMode(Qt::NavigationModeKeypadTabOrder);
3808     } else {
3809         QApplication::setNavigationMode(Qt::NavigationModeNone);
3810     }
3811 }
3812 
3813 /*!
3814     Returns \c true if Qt is set to use keypad navigation; otherwise returns
3815     false.  The default value is false.
3816 
3817     This feature is available in Qt for Embedded Linux, and Windows CE only.
3818 
3819     \note On Windows CE this feature is disabled by default for touch device
3820           mkspecs. To enable keypad navigation, build Qt with
3821           QT_KEYPAD_NAVIGATION defined.
3822 
3823     \deprecated
3824 
3825     \sa navigationMode()
3826 */
keypadNavigationEnabled()3827 bool QApplication::keypadNavigationEnabled()
3828 {
3829     return QApplicationPrivate::navigationMode == Qt::NavigationModeKeypadTabOrder ||
3830         QApplicationPrivate::navigationMode == Qt::NavigationModeKeypadDirectional;
3831 }
3832 # endif
3833 #endif
3834 
3835 /*!
3836     \fn void QApplication::alert(QWidget *widget, int msec)
3837     \since 4.3
3838 
3839     Causes an alert to be shown for \a widget if the window is not the active
3840     window. The alert is shown for \a msec miliseconds. If \a msec is zero (the
3841     default), then the alert is shown indefinitely until the window becomes
3842     active again.
3843 
3844     Currently this function does nothing on Qt for Embedded Linux.
3845 
3846     On \macos, this works more at the application level and will cause the
3847     application icon to bounce in the dock.
3848 
3849     On Windows, this causes the window's taskbar entry to flash for a time. If
3850     \a msec is zero, the flashing will stop and the taskbar entry will turn a
3851     different color (currently orange).
3852 
3853     On X11, this will cause the window to be marked as "demands attention", the
3854     window must not be hidden (i.e. not have hide() called on it, but be
3855     visible in some sort of way) in order for this to work.
3856 */
alert(QWidget * widget,int duration)3857 void QApplication::alert(QWidget *widget, int duration)
3858 {
3859     if (widget) {
3860        if (widget->window()->isActiveWindow() && !(widget->window()->windowState() & Qt::WindowMinimized))
3861             return;
3862         if (QWindow *window= QApplicationPrivate::windowForWidget(widget))
3863             window->alert(duration);
3864     } else {
3865         const auto topLevels = topLevelWidgets();
3866         for (QWidget *topLevel : topLevels)
3867             QApplication::alert(topLevel, duration);
3868     }
3869 }
3870 
3871 /*!
3872     \property QApplication::cursorFlashTime
3873     \brief the text cursor's flash (blink) time in milliseconds
3874 
3875     The flash time is the time required to display, invert and restore the
3876     caret display. Usually the text cursor is displayed for half the cursor
3877     flash time, then hidden for the same amount of time, but this may vary.
3878 
3879     The default value on X11 is 1000 milliseconds. On Windows, the
3880     \uicontrol{Control Panel} value is used and setting this property sets the cursor
3881     flash time for all applications.
3882 
3883     We recommend that widgets do not cache this value as it may change at any
3884     time if the user changes the global desktop settings.
3885 
3886     \note This property may hold a negative value, for instance if cursor
3887     blinking is disabled.
3888 */
setCursorFlashTime(int msecs)3889 void QApplication::setCursorFlashTime(int msecs)
3890 {
3891     QGuiApplication::styleHints()->setCursorFlashTime(msecs);
3892 }
3893 
cursorFlashTime()3894 int QApplication::cursorFlashTime()
3895 {
3896     return QGuiApplication::styleHints()->cursorFlashTime();
3897 }
3898 
3899 /*!
3900     \property QApplication::doubleClickInterval
3901     \brief the time limit in milliseconds that distinguishes a double click
3902     from two consecutive mouse clicks
3903 
3904     The default value on X11 is 400 milliseconds. On Windows and Mac OS, the
3905     operating system's value is used.
3906 */
setDoubleClickInterval(int ms)3907 void QApplication::setDoubleClickInterval(int ms)
3908 {
3909     QGuiApplication::styleHints()->setMouseDoubleClickInterval(ms);
3910 }
3911 
doubleClickInterval()3912 int QApplication::doubleClickInterval()
3913 {
3914     return QGuiApplication::styleHints()->mouseDoubleClickInterval();
3915 }
3916 
3917 /*!
3918     \property QApplication::keyboardInputInterval
3919     \brief the time limit in milliseconds that distinguishes a key press
3920     from two consecutive key presses
3921     \since 4.2
3922 
3923     The default value on X11 is 400 milliseconds. On Windows and Mac OS, the
3924     operating system's value is used.
3925 */
setKeyboardInputInterval(int ms)3926 void QApplication::setKeyboardInputInterval(int ms)
3927 {
3928     QGuiApplication::styleHints()->setKeyboardInputInterval(ms);
3929 }
3930 
keyboardInputInterval()3931 int QApplication::keyboardInputInterval()
3932 {
3933     return QGuiApplication::styleHints()->keyboardInputInterval();
3934 }
3935 
3936 /*!
3937     \property QApplication::wheelScrollLines
3938     \brief the number of lines to scroll a widget, when the
3939     mouse wheel is rotated.
3940 
3941     If the value exceeds the widget's number of visible lines, the widget
3942     should interpret the scroll operation as a single \e{page up} or
3943     \e{page down}. If the widget is an \l{QAbstractItemView}{item view class},
3944     then the result of scrolling one \e line depends on the setting of the
3945     widget's \l{QAbstractItemView::verticalScrollMode()}{scroll mode}. Scroll
3946     one \e line can mean \l{QAbstractItemView::ScrollPerItem}{scroll one item}
3947     or \l{QAbstractItemView::ScrollPerPixel}{scroll one pixel}.
3948 
3949     By default, this property has a value of 3.
3950 
3951     \sa QStyleHints::wheelScrollLines()
3952 */
3953 #if QT_CONFIG(wheelevent)
wheelScrollLines()3954 int QApplication::wheelScrollLines()
3955 {
3956     return styleHints()->wheelScrollLines();
3957 }
3958 
setWheelScrollLines(int lines)3959 void QApplication::setWheelScrollLines(int lines)
3960 {
3961     styleHints()->setWheelScrollLines(lines);
3962 }
3963 #endif
3964 
uiEffectToFlag(Qt::UIEffect effect)3965 static inline int uiEffectToFlag(Qt::UIEffect effect)
3966 {
3967     switch (effect) {
3968     case Qt::UI_General:
3969         return QPlatformTheme::GeneralUiEffect;
3970     case Qt::UI_AnimateMenu:
3971         return QPlatformTheme::AnimateMenuUiEffect;
3972     case Qt::UI_FadeMenu:
3973         return QPlatformTheme::FadeMenuUiEffect;
3974     case Qt::UI_AnimateCombo:
3975         return QPlatformTheme::AnimateComboUiEffect;
3976     case Qt::UI_AnimateTooltip:
3977         return QPlatformTheme::AnimateTooltipUiEffect;
3978     case Qt::UI_FadeTooltip:
3979         return QPlatformTheme::FadeTooltipUiEffect;
3980     case Qt::UI_AnimateToolBox:
3981         return QPlatformTheme::AnimateToolBoxUiEffect;
3982     }
3983     return 0;
3984 }
3985 
3986 /*!
3987     \fn void QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable)
3988 
3989     Enables the UI effect \a effect if \a enable is true, otherwise the effect
3990     will not be used.
3991 
3992     \note All effects are disabled on screens running at less than 16-bit color
3993     depth.
3994 
3995     \sa isEffectEnabled(), Qt::UIEffect, setDesktopSettingsAware()
3996 */
setEffectEnabled(Qt::UIEffect effect,bool enable)3997 void QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable)
3998 {
3999     int effectFlags = uiEffectToFlag(effect);
4000     if (enable) {
4001         if (effectFlags & QPlatformTheme::FadeMenuUiEffect)
4002             effectFlags |= QPlatformTheme::AnimateMenuUiEffect;
4003         if (effectFlags & QPlatformTheme::FadeTooltipUiEffect)
4004             effectFlags |= QPlatformTheme::AnimateTooltipUiEffect;
4005         QApplicationPrivate::enabledAnimations |= effectFlags;
4006     } else {
4007         QApplicationPrivate::enabledAnimations &= ~effectFlags;
4008     }
4009 }
4010 
4011 /*!
4012     \fn bool QApplication::isEffectEnabled(Qt::UIEffect effect)
4013 
4014     Returns \c true if \a effect is enabled; otherwise returns \c false.
4015 
4016     By default, Qt will try to use the desktop settings. To prevent this, call
4017     setDesktopSettingsAware(false).
4018 
4019     \note All effects are disabled on screens running at less than 16-bit color
4020     depth.
4021 
4022     \sa setEffectEnabled(), Qt::UIEffect
4023 */
isEffectEnabled(Qt::UIEffect effect)4024 bool QApplication::isEffectEnabled(Qt::UIEffect effect)
4025 {
4026     CHECK_QAPP_INSTANCE(false)
4027     return QColormap::instance().depth() >= 16
4028            && (QApplicationPrivate::enabledAnimations & QPlatformTheme::GeneralUiEffect)
4029            && (QApplicationPrivate::enabledAnimations & uiEffectToFlag(effect));
4030 }
4031 
4032 /*!
4033     \fn void QApplication::beep()
4034 
4035     Sounds the bell, using the default volume and sound. The function is \e not
4036     available in Qt for Embedded Linux.
4037 */
beep()4038 void QApplication::beep()
4039 {
4040     QGuiApplicationPrivate::platformIntegration()->beep();
4041 }
4042 
4043 /*!
4044     \macro qApp
4045     \relates QApplication
4046 
4047     A global pointer referring to the unique application object. It is
4048     equivalent to QCoreApplication::instance(), but cast as a QApplication pointer,
4049     so only valid when the unique application object is a QApplication.
4050 
4051     \sa QCoreApplication::instance(), qGuiApp
4052 */
4053 
qt_sendSpontaneousEvent(QObject * receiver,QEvent * event)4054 bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event)
4055 {
4056     return QGuiApplication::sendSpontaneousEvent(receiver, event);
4057 }
4058 
giveFocusAccordingToFocusPolicy(QWidget * widget,QEvent * event,QPoint localPos)4059 void QApplicationPrivate::giveFocusAccordingToFocusPolicy(QWidget *widget, QEvent *event, QPoint localPos)
4060 {
4061     const bool setFocusOnRelease = QGuiApplication::styleHints()->setFocusOnTouchRelease();
4062     Qt::FocusPolicy focusPolicy = Qt::ClickFocus;
4063     static QPointer<QWidget> focusedWidgetOnTouchBegin = nullptr;
4064 
4065     switch (event->type()) {
4066         case QEvent::MouseButtonPress:
4067         case QEvent::MouseButtonDblClick:
4068         case QEvent::TouchBegin:
4069             focusedWidgetOnTouchBegin = QApplication::focusWidget();
4070             if (setFocusOnRelease)
4071                 return;
4072             break;
4073         case QEvent::MouseButtonRelease:
4074         case QEvent::TouchEnd:
4075             if (!setFocusOnRelease)
4076                 return;
4077             if (focusedWidgetOnTouchBegin != QApplication::focusWidget()) {
4078                 // Focus widget was changed while delivering press/move events.
4079                 // To not interfere with application logic, we leave focus as-is
4080                 return;
4081             }
4082             break;
4083         case QEvent::Wheel:
4084             focusPolicy = Qt::WheelFocus;
4085             break;
4086         default:
4087             return;
4088     }
4089 
4090     QWidget *focusWidget = widget;
4091     while (focusWidget) {
4092         if (focusWidget->isEnabled()
4093             && focusWidget->rect().contains(localPos)
4094             && QApplicationPrivate::shouldSetFocus(focusWidget, focusPolicy)) {
4095             focusWidget->setFocus(Qt::MouseFocusReason);
4096             break;
4097         }
4098         if (focusWidget->isWindow())
4099             break;
4100 
4101         // find out whether this widget (or its proxy) already has focus
4102         QWidget *f = focusWidget;
4103         if (focusWidget->d_func()->extra && focusWidget->d_func()->extra->focus_proxy)
4104             f = focusWidget->d_func()->extra->focus_proxy;
4105         // if it has, stop here.
4106         // otherwise a click on the focused widget would remove its focus if ClickFocus isn't set
4107         if (f->hasFocus())
4108             break;
4109 
4110         localPos += focusWidget->pos();
4111         focusWidget = focusWidget->parentWidget();
4112     }
4113 }
4114 
shouldSetFocus(QWidget * w,Qt::FocusPolicy policy)4115 bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy)
4116 {
4117     QWidget *f = w;
4118     while (f->d_func()->extra && f->d_func()->extra->focus_proxy)
4119         f = f->d_func()->extra->focus_proxy;
4120 
4121     if ((w->focusPolicy() & policy) != policy)
4122         return false;
4123     if (w != f && (f->focusPolicy() & policy) != policy)
4124         return false;
4125     return true;
4126 }
4127 
updateTouchPointsForWidget(QWidget * widget,QTouchEvent * touchEvent)4128 bool QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent)
4129 {
4130     bool containsPress = false;
4131     for (int i = 0; i < touchEvent->touchPoints().count(); ++i) {
4132         QTouchEvent::TouchPoint &touchPoint = touchEvent->_touchPoints[i];
4133 
4134         // preserve the sub-pixel resolution
4135         const QPointF screenPos = touchPoint.screenPos();
4136         const QPointF delta = screenPos - screenPos.toPoint();
4137 
4138         touchPoint.d->pos = widget->mapFromGlobal(screenPos.toPoint()) + delta;
4139         touchPoint.d->startPos = widget->mapFromGlobal(touchPoint.startScreenPos().toPoint()) + delta;
4140         touchPoint.d->lastPos = widget->mapFromGlobal(touchPoint.lastScreenPos().toPoint()) + delta;
4141 
4142         if (touchPoint.state() == Qt::TouchPointPressed)
4143             containsPress = true;
4144     }
4145     return containsPress;
4146 }
4147 
initializeMultitouch()4148 void QApplicationPrivate::initializeMultitouch()
4149 {
4150     initializeMultitouch_sys();
4151 }
4152 
initializeMultitouch_sys()4153 void QApplicationPrivate::initializeMultitouch_sys()
4154 {
4155 }
4156 
cleanupMultitouch()4157 void QApplicationPrivate::cleanupMultitouch()
4158 {
4159     cleanupMultitouch_sys();
4160 }
4161 
cleanupMultitouch_sys()4162 void QApplicationPrivate::cleanupMultitouch_sys()
4163 {
4164 }
4165 
findClosestTouchPointTarget(QTouchDevice * device,const QTouchEvent::TouchPoint & touchPoint)4166 QWidget *QApplicationPrivate::findClosestTouchPointTarget(QTouchDevice *device, const QTouchEvent::TouchPoint &touchPoint)
4167 {
4168     const QPointF screenPos = touchPoint.screenPos();
4169     int closestTouchPointId = -1;
4170     QObject *closestTarget = nullptr;
4171     qreal closestDistance = qreal(0.);
4172     QHash<ActiveTouchPointsKey, ActiveTouchPointsValue>::const_iterator it = activeTouchPoints.constBegin(),
4173             ite = activeTouchPoints.constEnd();
4174     while (it != ite) {
4175         if (it.key().device == device && it.key().touchPointId != touchPoint.id()) {
4176             const QTouchEvent::TouchPoint &touchPoint = it->touchPoint;
4177             qreal dx = screenPos.x() - touchPoint.screenPos().x();
4178             qreal dy = screenPos.y() - touchPoint.screenPos().y();
4179             qreal distance = dx * dx + dy * dy;
4180             if (closestTouchPointId == -1 || distance < closestDistance) {
4181                 closestTouchPointId = touchPoint.id();
4182                 closestDistance = distance;
4183                 closestTarget = it.value().target.data();
4184             }
4185         }
4186         ++it;
4187     }
4188     return static_cast<QWidget *>(closestTarget);
4189 }
4190 
activateImplicitTouchGrab(QWidget * widget,QTouchEvent * touchEvent)4191 void QApplicationPrivate::activateImplicitTouchGrab(QWidget *widget, QTouchEvent *touchEvent)
4192 {
4193     if (touchEvent->type() != QEvent::TouchBegin)
4194         return;
4195 
4196     for (int i = 0, tc = touchEvent->touchPoints().count(); i < tc; ++i) {
4197         const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i);
4198         activeTouchPoints[QGuiApplicationPrivate::ActiveTouchPointsKey(touchEvent->device(), touchPoint.id())].target = widget;
4199     }
4200 }
4201 
translateRawTouchEvent(QWidget * window,QTouchDevice * device,const QList<QTouchEvent::TouchPoint> & touchPoints,ulong timestamp)4202 bool QApplicationPrivate::translateRawTouchEvent(QWidget *window,
4203                                                  QTouchDevice *device,
4204                                                  const QList<QTouchEvent::TouchPoint> &touchPoints,
4205                                                  ulong timestamp)
4206 {
4207     QApplicationPrivate *d = self;
4208     typedef QPair<Qt::TouchPointStates, QList<QTouchEvent::TouchPoint> > StatesAndTouchPoints;
4209     QHash<QWidget *, StatesAndTouchPoints> widgetsNeedingEvents;
4210 
4211     for (int i = 0; i < touchPoints.count(); ++i) {
4212         QTouchEvent::TouchPoint touchPoint = touchPoints.at(i);
4213         // explicitly detach from the original touch point that we got, so even
4214         // if the touchpoint structs are reused, we will make a copy that we'll
4215         // deliver to the user (which might want to store the struct for later use).
4216         touchPoint.d = touchPoint.d->detach();
4217 
4218         // update state
4219         QPointer<QObject> target;
4220         ActiveTouchPointsKey touchInfoKey(device, touchPoint.id());
4221         ActiveTouchPointsValue &touchInfo = d->activeTouchPoints[touchInfoKey];
4222         if (touchPoint.state() == Qt::TouchPointPressed) {
4223             if (device->type() == QTouchDevice::TouchPad) {
4224                 // on touch-pads, send all touch points to the same widget
4225                 target = d->activeTouchPoints.isEmpty()
4226                         ? QPointer<QObject>()
4227                         : d->activeTouchPoints.constBegin().value().target;
4228             }
4229 
4230             if (!target) {
4231                 // determine which widget this event will go to
4232                 if (!window)
4233                     window = QApplication::topLevelAt(touchPoint.screenPos().toPoint());
4234                 if (!window)
4235                     continue;
4236                 target = window->childAt(window->mapFromGlobal(touchPoint.screenPos().toPoint()));
4237                 if (!target)
4238                     target = window;
4239             }
4240 
4241             if (device->type() == QTouchDevice::TouchScreen) {
4242                 QWidget *closestWidget = d->findClosestTouchPointTarget(device, touchPoint);
4243                 QWidget *widget = static_cast<QWidget *>(target.data());
4244                 if (closestWidget
4245                         && (widget->isAncestorOf(closestWidget) || closestWidget->isAncestorOf(widget))) {
4246                     target = closestWidget;
4247                 }
4248             }
4249 
4250             touchInfo.target = target;
4251         } else {
4252             target = touchInfo.target;
4253             if (!target)
4254                 continue;
4255         }
4256         Q_ASSERT(target.data() != nullptr);
4257 
4258         QWidget *targetWidget = static_cast<QWidget *>(target.data());
4259 
4260 #ifdef Q_OS_MACOS
4261         // Single-touch events are normally not sent unless WA_TouchPadAcceptSingleTouchEvents is set.
4262         // In Qt 4 this check was in OS X-only code. That behavior is preserved here by the #ifdef.
4263         if (touchPoints.count() == 1
4264             && device->type() == QTouchDevice::TouchPad
4265             && !targetWidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents))
4266             continue;
4267 #endif
4268 
4269         StatesAndTouchPoints &maskAndPoints = widgetsNeedingEvents[targetWidget];
4270         maskAndPoints.first |= touchPoint.state();
4271         maskAndPoints.second.append(touchPoint);
4272     }
4273 
4274     if (widgetsNeedingEvents.isEmpty())
4275         return false;
4276 
4277     bool accepted = false;
4278     QHash<QWidget *, StatesAndTouchPoints>::ConstIterator it = widgetsNeedingEvents.constBegin();
4279     const QHash<QWidget *, StatesAndTouchPoints>::ConstIterator end = widgetsNeedingEvents.constEnd();
4280     for (; it != end; ++it) {
4281         const QPointer<QWidget> widget = it.key();
4282         if (!QApplicationPrivate::tryModalHelper(widget, nullptr))
4283             continue;
4284 
4285         QEvent::Type eventType;
4286         switch (it.value().first) {
4287         case Qt::TouchPointPressed:
4288             eventType = QEvent::TouchBegin;
4289             break;
4290         case Qt::TouchPointReleased:
4291             eventType = QEvent::TouchEnd;
4292             break;
4293         case Qt::TouchPointStationary:
4294             // don't send the event if nothing changed
4295             continue;
4296         default:
4297             eventType = QEvent::TouchUpdate;
4298             break;
4299         }
4300 
4301         QTouchEvent touchEvent(eventType,
4302                                device,
4303                                QGuiApplication::keyboardModifiers(),
4304                                it.value().first,
4305                                it.value().second);
4306         bool containsPress = updateTouchPointsForWidget(widget, &touchEvent);
4307         touchEvent.setTimestamp(timestamp);
4308         touchEvent.setWindow(window->windowHandle());
4309         touchEvent.setTarget(widget);
4310 
4311         if (containsPress)
4312             widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent);
4313 
4314         switch (touchEvent.type()) {
4315         case QEvent::TouchBegin:
4316         {
4317             // if the TouchBegin handler recurses, we assume that means the event
4318             // has been implicitly accepted and continue to send touch events
4319             if (QApplication::sendSpontaneousEvent(widget, &touchEvent) && touchEvent.isAccepted()) {
4320                 accepted = true;
4321                 if (!widget.isNull())
4322                     widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent);
4323             }
4324             break;
4325         }
4326         default:
4327             if (widget->testAttribute(Qt::WA_WState_AcceptedTouchBeginEvent)
4328 #ifndef QT_NO_GESTURES
4329                 || QGestureManager::gesturePending(widget)
4330 #endif
4331                 ) {
4332                 if (QApplication::sendSpontaneousEvent(widget, &touchEvent) && touchEvent.isAccepted())
4333                     accepted = true;
4334                 // widget can be deleted on TouchEnd
4335                 if (touchEvent.type() == QEvent::TouchEnd && !widget.isNull())
4336                     widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, false);
4337             }
4338             break;
4339         }
4340     }
4341     return accepted;
4342 }
4343 
translateTouchCancel(QTouchDevice * device,ulong timestamp)4344 void QApplicationPrivate::translateTouchCancel(QTouchDevice *device, ulong timestamp)
4345 {
4346     QTouchEvent touchEvent(QEvent::TouchCancel, device, QGuiApplication::keyboardModifiers());
4347     touchEvent.setTimestamp(timestamp);
4348     QHash<ActiveTouchPointsKey, ActiveTouchPointsValue>::const_iterator it
4349             = self->activeTouchPoints.constBegin(), ite = self->activeTouchPoints.constEnd();
4350     QSet<QWidget *> widgetsNeedingCancel;
4351     while (it != ite) {
4352         QWidget *widget = static_cast<QWidget *>(it->target.data());
4353         if (widget)
4354             widgetsNeedingCancel.insert(widget);
4355         ++it;
4356     }
4357     for (QSet<QWidget *>::const_iterator widIt = widgetsNeedingCancel.constBegin(),
4358          widItEnd = widgetsNeedingCancel.constEnd(); widIt != widItEnd; ++widIt) {
4359         QWidget *widget = *widIt;
4360         touchEvent.setWindow(widget->windowHandle());
4361         touchEvent.setTarget(widget);
4362         QApplication::sendSpontaneousEvent(widget, &touchEvent);
4363     }
4364 }
4365 
notifyThemeChanged()4366 void QApplicationPrivate::notifyThemeChanged()
4367 {
4368     QGuiApplicationPrivate::notifyThemeChanged();
4369 
4370     qt_init_tooltip_palette();
4371 }
4372 
4373 #if QT_CONFIG(draganddrop)
notifyDragStarted(const QDrag * drag)4374 void QApplicationPrivate::notifyDragStarted(const QDrag *drag)
4375 {
4376     QGuiApplicationPrivate::notifyDragStarted(drag);
4377     // QTBUG-26145
4378     // Prevent pickMouseReceiver() from using the widget where the drag was started after a drag operation...
4379     // QTBUG-56713
4380     // ...only if qt_button_down is not a QQuickWidget
4381     if (qt_button_down && !qt_button_down->inherits("QQuickWidget"))
4382         qt_button_down = nullptr;
4383 }
4384 #endif // QT_CONFIG(draganddrop)
4385 
4386 #ifndef QT_NO_GESTURES
instance(InstanceCreation ic)4387 QGestureManager* QGestureManager::instance(InstanceCreation ic)
4388 {
4389     QApplicationPrivate *qAppPriv = QApplicationPrivate::instance();
4390     if (!qAppPriv)
4391         return nullptr;
4392     if (!qAppPriv->gestureManager && ic == ForceCreation)
4393         qAppPriv->gestureManager = new QGestureManager(qApp);
4394     return qAppPriv->gestureManager;
4395 }
4396 #endif // QT_NO_GESTURES
4397 
applyQIconStyleHelper(QIcon::Mode mode,const QPixmap & base) const4398 QPixmap QApplicationPrivate::applyQIconStyleHelper(QIcon::Mode mode, const QPixmap& base) const
4399 {
4400     QStyleOption opt(0);
4401     opt.palette = QGuiApplication::palette();
4402     return QApplication::style()->generatedIconPixmap(mode, base, &opt);
4403 }
4404 
4405 QT_END_NAMESPACE
4406 
4407 #include "moc_qapplication.cpp"
4408