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
119static void initResources()
120{
121 Q_INIT_RESOURCE(qstyle);
122
123#if QT_CONFIG(messagebox)
124 Q_INIT_RESOURCE(qmessagebox);
125#endif
126}
127
128QT_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
138Q_CORE_EXPORT void qt_call_post_routines();
139Q_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
141QApplicationPrivate *QApplicationPrivate::self = 0;
142
143static void initSystemPalette()
144{
145 if (!QApplicationPrivate::sys_pal) {
146 QPalette defaultPlatte;
147 if (QApplicationPrivate::app_style)
148 defaultPlatte = QApplicationPrivate::app_style->standardPalette();
149 if (const QPalette *themePalette = QGuiApplicationPrivate::platformTheme()->palette()) {
150 QApplicationPrivate::setSystemPalette(themePalette->resolve(defaultPlatte));
151 QApplicationPrivate::initializeWidgetPaletteHash();
152 } else {
153 QApplicationPrivate::setSystemPalette(defaultPlatte);
154 }
155 }
156}
157
158static void clearSystemPalette()
159{
160 delete QApplicationPrivate::sys_pal;
161 QApplicationPrivate::sys_pal = 0;
162}
163
164bool QApplicationPrivate::autoSipEnabled = true;
165
166QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, int flags)
167 : QApplicationPrivateBase(argc, argv, flags)
168{
169 application_type = QApplicationPrivate::Gui;
170
171#ifndef QT_NO_GESTURES
172 gestureManager = 0;
173 gestureWidget = 0;
174#endif // QT_NO_GESTURES
175
176 if (!self)
177 self = this;
178}
179
180QApplicationPrivate::~QApplicationPrivate()
181{
182 if (self == this)
183 self = 0;
184}
185
186void QApplicationPrivate::createEventDispatcher()
187{
188 QGuiApplicationPrivate::createEventDispatcher();
189}
190
191/*!
192 \class QApplication
193 \brief The QApplication class manages the GUI application's control
194 flow and main settings.
195
196 \inmodule QtWidgets
197
198 QApplication specializes QGuiApplication with some functionality needed
199 for QWidget-based applications. It handles widget specific initialization,
200 finalization.
201
202 For any GUI application using Qt, there is precisely \b one QApplication
203 object, no matter whether the application has 0, 1, 2 or more windows at
204 any given time. For non-QWidget based Qt applications, use QGuiApplication instead,
205 as it does not depend on the \l QtWidgets library.
206
207 Some GUI applications provide a special batch mode ie. provide command line
208 arguments for executing tasks without manual intervention. In such non-GUI
209 mode, it is often sufficient to instantiate a plain QCoreApplication to
210 avoid unnecessarily initializing resources needed for a graphical user
211 interface. The following example shows how to dynamically create an
212 appropriate type of application instance:
213
214 \snippet code/src_gui_kernel_qapplication.cpp 0
215
216 The QApplication object is accessible through the instance() function that
217 returns a pointer equivalent to the global qApp pointer.
218
219 QApplication's main areas of responsibility are:
220 \list
221 \li It initializes the application with the user's desktop settings
222 such as palette(), font() and doubleClickInterval(). It keeps
223 track of these properties in case the user changes the desktop
224 globally, for example through some kind of control panel.
225
226 \li It performs event handling, meaning that it receives events
227 from the underlying window system and dispatches them to the
228 relevant widgets. By using sendEvent() and postEvent() you can
229 send your own events to widgets.
230
231 \li It parses common command line arguments and sets its internal
232 state accordingly. See the \l{QApplication::QApplication()}
233 {constructor documentation} below for more details.
234
235 \li It defines the application's look and feel, which is
236 encapsulated in a QStyle object. This can be changed at runtime
237 with setStyle().
238
239 \li It specifies how the application is to allocate colors. See
240 setColorSpec() for details.
241
242 \li It provides localization of strings that are visible to the
243 user via translate().
244
245 \li It provides some magical objects like the desktop() and the
246 clipboard().
247
248 \li It knows about the application's windows. You can ask which
249 widget is at a certain position using widgetAt(), get a list of
250 topLevelWidgets() and closeAllWindows(), etc.
251
252 \li It manages the application's mouse cursor handling, see
253 setOverrideCursor()
254 \endlist
255
256 Since the QApplication object does so much initialization, it \e{must} be
257 created before any other objects related to the user interface are created.
258 QApplication also deals with common command line arguments. Hence, it is
259 usually a good idea to create it \e before any interpretation or
260 modification of \c argv is done in the application itself.
261
262 \table
263 \header
264 \li{2,1} Groups of functions
265
266 \row
267 \li System settings
268 \li desktopSettingsAware(),
269 setDesktopSettingsAware(),
270 cursorFlashTime(),
271 setCursorFlashTime(),
272 doubleClickInterval(),
273 setDoubleClickInterval(),
274 setKeyboardInputInterval(),
275 wheelScrollLines(),
276 setWheelScrollLines(),
277 palette(),
278 setPalette(),
279 font(),
280 setFont(),
281 fontMetrics().
282
283 \row
284 \li Event handling
285 \li exec(),
286 processEvents(),
287 exit(),
288 quit().
289 sendEvent(),
290 postEvent(),
291 sendPostedEvents(),
292 removePostedEvents(),
293 hasPendingEvents(),
294 notify().
295
296 \row
297 \li GUI Styles
298 \li style(),
299 setStyle().
300
301 \row
302 \li Color usage
303 \li colorSpec(),
304 setColorSpec().
305
306 \row
307 \li Text handling
308 \li installTranslator(),
309 removeTranslator()
310 translate().
311
312 \row
313 \li Widgets
314 \li allWidgets(),
315 topLevelWidgets(),
316 desktop(),
317 activePopupWidget(),
318 activeModalWidget(),
319 clipboard(),
320 focusWidget(),
321 activeWindow(),
322 widgetAt().
323
324 \row
325 \li Advanced cursor handling
326 \li overrideCursor(),
327 setOverrideCursor(),
328 restoreOverrideCursor().
329
330 \row
331 \li Miscellaneous
332 \li closeAllWindows(),
333 startingUp(),
334 closingDown().
335 \endtable
336
337 \sa QCoreApplication, QAbstractEventDispatcher, QEventLoop, QSettings
338*/
339
340// ### fixme: Qt 6: Remove ColorSpec and accessors.
341/*!
342 \enum QApplication::ColorSpec
343 \obsolete
344
345 \value NormalColor the default color allocation policy
346 \value CustomColor the same as NormalColor for X11; allocates colors
347 to a palette on demand under Windows
348 \value ManyColor the right choice for applications that use thousands of
349 colors
350
351 See setColorSpec() for full details.
352*/
353
354/*!
355 \fn QApplication::setGraphicsSystem(const QString &)
356 \obsolete
357
358 This call has no effect.
359
360 Use the QPA framework instead.
361*/
362
363/*!
364 \fn QWidget *QApplication::topLevelAt(const QPoint &point)
365
366 Returns the top-level widget at the given \a point; returns \nullptr if
367 there is no such widget.
368*/
369QWidget *QApplication::topLevelAt(const QPoint &pos)
370{
371 if (const QWindow *window = QGuiApplication::topLevelAt(pos)) {
372 if (const QWidgetWindow *widgetWindow = qobject_cast<const QWidgetWindow *>(window))
373 return widgetWindow->widget();
374 }
375 return 0;
376}
377
378/*!
379 \fn QWidget *QApplication::topLevelAt(int x, int y)
380
381 \overload
382
383 Returns the top-level widget at the point (\a{x}, \a{y}); returns
384 0 if there is no such widget.
385*/
386
387void qt_init_tooltip_palette();
388void qt_cleanup();
389
390QStyle *QApplicationPrivate::app_style = 0; // default application style
391#ifndef QT_NO_STYLE_STYLESHEET
392QString QApplicationPrivate::styleSheet; // default application stylesheet
393#endif
394QPointer<QWidget> QApplicationPrivate::leaveAfterRelease = 0;
395
396QPalette *QApplicationPrivate::sys_pal = 0; // default system palette
397QPalette *QApplicationPrivate::set_pal = 0; // default palette set by programmer
398
399QFont *QApplicationPrivate::sys_font = 0; // default system font
400QFont *QApplicationPrivate::set_font = 0; // default font set by programmer
401
402QWidget *QApplicationPrivate::main_widget = 0; // main application widget
403QWidget *QApplicationPrivate::focus_widget = 0; // has keyboard input focus
404QWidget *QApplicationPrivate::hidden_focus_widget = 0; // will get keyboard input focus after show()
405QWidget *QApplicationPrivate::active_window = 0; // toplevel with keyboard focus
406#if QT_CONFIG(wheelevent)
407QPointer<QWidget> QApplicationPrivate::wheel_widget;
408#endif
409bool qt_in_tab_key_event = false;
410int qt_antialiasing_threshold = -1;
411QSize QApplicationPrivate::app_strut = QSize(0,0); // no default application strut
412int QApplicationPrivate::enabledAnimations = QPlatformTheme::GeneralUiEffect;
413bool QApplicationPrivate::widgetCount = false;
414#ifdef QT_KEYPAD_NAVIGATION
415Qt::NavigationMode QApplicationPrivate::navigationMode = Qt::NavigationModeKeypadTabOrder;
416QWidget *QApplicationPrivate::oldEditFocus = 0;
417#endif
418
419inline bool QApplicationPrivate::isAlien(QWidget *widget)
420{
421 return widget && !widget->isWindow();
422}
423
424bool Q_WIDGETS_EXPORT qt_tab_all_widgets()
425{
426 return QGuiApplication::styleHints()->tabFocusBehavior() == Qt::TabFocusAllControls;
427}
428
429// ######## move to QApplicationPrivate
430// Default application palettes and fonts (per widget type)
431Q_GLOBAL_STATIC(PaletteHash, app_palettes)
432Q_GLOBAL_STATIC(FontHash, app_fonts)
433// Exported accessors for use outside of this file
434PaletteHash *qt_app_palettes_hash() { return app_palettes(); }
435FontHash *qt_app_fonts_hash() { return app_fonts(); }
436
437QWidgetList *QApplicationPrivate::popupWidgets = 0; // has keyboard input focus
438
439QDesktopWidget *qt_desktopWidget = 0; // root window widgets
440
441/*!
442 \internal
443*/
444void QApplicationPrivate::process_cmdline()
445{
446 if (styleOverride.isEmpty() && qEnvironmentVariableIsSet("QT_STYLE_OVERRIDE"))
447 styleOverride = QString::fromLocal8Bit(qgetenv("QT_STYLE_OVERRIDE"));
448
449 if (!styleOverride.isEmpty()) {
450 if (app_style) {
451 delete app_style;
452 app_style = 0;
453 }
454 }
455
456 // process platform-indep command line
457 if (!qt_is_gui_used || !argc)
458 return;
459
460 int i, j;
461
462 j = 1;
463 for (i=1; i<argc; i++) { // if you add anything here, modify QCoreApplication::arguments()
464 if (!argv[i])
465 continue;
466 if (*argv[i] != '-') {
467 argv[j++] = argv[i];
468 continue;
469 }
470 const char *arg = argv[i];
471 if (arg[1] == '-') // startsWith("--")
472 ++arg;
473 if (strcmp(arg, "-qdevel") == 0 || strcmp(arg, "-qdebug") == 0) {
474 // obsolete argument
475#ifndef QT_NO_STYLE_STYLESHEET
476 } else if (strcmp(arg, "-stylesheet") == 0 && i < argc -1) {
477 styleSheet = QLatin1String("file:///");
478 styleSheet.append(QString::fromLocal8Bit(argv[++i]));
479 } else if (strncmp(arg, "-stylesheet=", 12) == 0) {
480 styleSheet = QLatin1String("file:///");
481 styleSheet.append(QString::fromLocal8Bit(arg + 12));
482#endif
483 } else if (qstrcmp(arg, "-widgetcount") == 0) {
484 widgetCount = true;
485 } else {
486 argv[j++] = argv[i];
487 }
488 }
489
490 if(j < argc) {
491 argv[j] = 0;
492 argc = j;
493 }
494}
495
496/*!
497 Initializes the window system and constructs an application object with
498 \a argc command line arguments in \a argv.
499
500 \warning The data referred to by \a argc and \a argv must stay valid for
501 the entire lifetime of the QApplication object. In addition, \a argc must
502 be greater than zero and \a argv must contain at least one valid character
503 string.
504
505 The global \c qApp pointer refers to this application object. Only one
506 application object should be created.
507
508 This application object must be constructed before any \l{QPaintDevice}
509 {paint devices} (including widgets, pixmaps, bitmaps etc.).
510
511 \note \a argc and \a argv might be changed as Qt removes command line
512 arguments that it recognizes.
513
514 All Qt programs automatically support the following command line options:
515 \list
516 \li -style= \e style, sets the application GUI style. Possible values
517 depend on your system configuration. If you compiled Qt with
518 additional styles or have additional styles as plugins these will
519 be available to the \c -style command line option. You can also
520 set the style for all Qt applications by setting the
521 \c QT_STYLE_OVERRIDE environment variable.
522 \li -style \e style, is the same as listed above.
523 \li -stylesheet= \e stylesheet, sets the application \l styleSheet. The
524 value must be a path to a file that contains the Style Sheet.
525 \note Relative URLs in the Style Sheet file are relative to the
526 Style Sheet file's path.
527 \li -stylesheet \e stylesheet, is the same as listed above.
528 \li -widgetcount, prints debug message at the end about number of
529 widgets left undestroyed and maximum number of widgets existed at
530 the same time
531 \li -reverse, sets the application's layout direction to
532 Qt::RightToLeft
533 \li -qmljsdebugger=, activates the QML/JS debugger with a specified port.
534 The value must be of format port:1234[,block], where block is optional
535 and will make the application wait until a debugger connects to it.
536 \endlist
537
538 \sa QCoreApplication::arguments()
539*/
540
541#ifdef Q_QDOC
542QApplication::QApplication(int &argc, char **argv)
543#else
544QApplication::QApplication(int &argc, char **argv, int _internal)
545#endif
546 : QGuiApplication(*new QApplicationPrivate(argc, argv, _internal))
547{
548 Q_D(QApplication);
549 d->init();
550}
551
552/*!
553 \internal
554*/
555void QApplicationPrivate::init()
556{
557#if defined(Q_OS_MACOS)
558 QMacAutoReleasePool pool;
559#endif
560
561 QGuiApplicationPrivate::init();
562
563 initResources();
564
565 qt_is_gui_used = (application_type != QApplicationPrivate::Tty);
566 process_cmdline();
567
568 // Must be called before initialize()
569 QColormap::initialize();
570 qt_init_tooltip_palette();
571 QApplicationPrivate::initializeWidgetFontHash();
572
573 initialize();
574 eventDispatcher->startingUp();
575
576#ifndef QT_NO_ACCESSIBILITY
577 // factory for accessible interfaces for widgets shipped with Qt
578 QAccessible::installFactory(&qAccessibleFactory);
579#endif
580
581}
582
583void qt_init_tooltip_palette()
584{
585#ifndef QT_NO_TOOLTIP
586 if (const QPalette *toolTipPalette = QGuiApplicationPrivate::platformTheme()->palette(QPlatformTheme::ToolTipPalette))
587 QToolTip::setPalette(*toolTipPalette);
588#endif
589}
590
591#if QT_CONFIG(statemachine)
592void qRegisterGuiStateMachine();
593void qUnregisterGuiStateMachine();
594#endif
595extern void qRegisterWidgetsVariant();
596
597/*!
598 \fn void QApplicationPrivate::initialize()
599
600 Initializes the QApplication object, called from the constructors.
601*/
602void QApplicationPrivate::initialize()
603{
604 is_app_running = false; // Starting up.
605
606 QWidgetPrivate::mapper = new QWidgetMapper;
607 QWidgetPrivate::allWidgets = new QWidgetSet;
608
609 // needed for a static build.
610 qRegisterWidgetsVariant();
611
612 // needed for widgets in QML
613 QAbstractDeclarativeData::setWidgetParent = QWidgetPrivate::setWidgetParentHelper;
614
615 if (application_type != QApplicationPrivate::Tty)
616 (void) QApplication::style(); // trigger creation of application style
617#if QT_CONFIG(statemachine)
618 // trigger registering of QStateMachine's GUI types
619 qRegisterGuiStateMachine();
620#endif
621
622 if (qEnvironmentVariableIntValue("QT_USE_NATIVE_WINDOWS") > 0)
623 QCoreApplication::setAttribute(Qt::AA_NativeWindows);
624
625 if (qt_is_gui_used)
626 initializeMultitouch();
627
628 if (QGuiApplication::desktopSettingsAware())
629 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
630 QApplicationPrivate::enabledAnimations = theme->themeHint(QPlatformTheme::UiEffects).toInt();
631 }
632
633 is_app_running = true; // no longer starting up
634}
635
636static void setPossiblePalette(const QPalette *palette, const char *className)
637{
638 if (palette == 0)
639 return;
640 QApplicationPrivate::setPalette_helper(*palette, className, false);
641}
642
643void QApplicationPrivate::initializeWidgetPaletteHash()
644{
645 QPlatformTheme *platformTheme = QGuiApplicationPrivate::platformTheme();
646 if (!platformTheme)
647 return;
648 app_palettes()->clear();
649
650 setPossiblePalette(platformTheme->palette(QPlatformTheme::ToolButtonPalette), "QToolButton");
651 setPossiblePalette(platformTheme->palette(QPlatformTheme::ButtonPalette), "QAbstractButton");
652 setPossiblePalette(platformTheme->palette(QPlatformTheme::CheckBoxPalette), "QCheckBox");
653 setPossiblePalette(platformTheme->palette(QPlatformTheme::RadioButtonPalette), "QRadioButton");
654 setPossiblePalette(platformTheme->palette(QPlatformTheme::HeaderPalette), "QHeaderView");
655 setPossiblePalette(platformTheme->palette(QPlatformTheme::ItemViewPalette), "QAbstractItemView");
656 setPossiblePalette(platformTheme->palette(QPlatformTheme::MessageBoxLabelPalette), "QMessageBoxLabel");
657 setPossiblePalette(platformTheme->palette(QPlatformTheme::TabBarPalette), "QTabBar");
658 setPossiblePalette(platformTheme->palette(QPlatformTheme::LabelPalette), "QLabel");
659 setPossiblePalette(platformTheme->palette(QPlatformTheme::GroupBoxPalette), "QGroupBox");
660 setPossiblePalette(platformTheme->palette(QPlatformTheme::MenuPalette), "QMenu");
661 setPossiblePalette(platformTheme->palette(QPlatformTheme::MenuBarPalette), "QMenuBar");
662 setPossiblePalette(platformTheme->palette(QPlatformTheme::TextEditPalette), "QTextEdit");
663 setPossiblePalette(platformTheme->palette(QPlatformTheme::TextEditPalette), "QTextControl");
664 setPossiblePalette(platformTheme->palette(QPlatformTheme::TextLineEditPalette), "QLineEdit");
665}
666
667void QApplicationPrivate::initializeWidgetFontHash()
668{
669 const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
670 if (!theme)
671 return;
672 FontHash *fontHash = app_fonts();
673 fontHash->clear();
674
675 if (const QFont *font = theme->font(QPlatformTheme::MenuFont))
676 fontHash->insert(QByteArrayLiteral("QMenu"), *font);
677 if (const QFont *font = theme->font(QPlatformTheme::MenuBarFont))
678 fontHash->insert(QByteArrayLiteral("QMenuBar"), *font);
679 if (const QFont *font = theme->font(QPlatformTheme::MenuItemFont))
680 fontHash->insert(QByteArrayLiteral("QMenuItem"), *font);
681 if (const QFont *font = theme->font(QPlatformTheme::MessageBoxFont))
682 fontHash->insert(QByteArrayLiteral("QMessageBox"), *font);
683 if (const QFont *font = theme->font(QPlatformTheme::LabelFont))
684 fontHash->insert(QByteArrayLiteral("QLabel"), *font);
685 if (const QFont *font = theme->font(QPlatformTheme::TipLabelFont))
686 fontHash->insert(QByteArrayLiteral("QTipLabel"), *font);
687 if (const QFont *font = theme->font(QPlatformTheme::TitleBarFont))
688 fontHash->insert(QByteArrayLiteral("QTitleBar"), *font);
689 if (const QFont *font = theme->font(QPlatformTheme::StatusBarFont))
690 fontHash->insert(QByteArrayLiteral("QStatusBar"), *font);
691 if (const QFont *font = theme->font(QPlatformTheme::MdiSubWindowTitleFont))
692 fontHash->insert(QByteArrayLiteral("QMdiSubWindowTitleBar"), *font);
693 if (const QFont *font = theme->font(QPlatformTheme::DockWidgetTitleFont))
694 fontHash->insert(QByteArrayLiteral("QDockWidgetTitle"), *font);
695 if (const QFont *font = theme->font(QPlatformTheme::PushButtonFont))
696 fontHash->insert(QByteArrayLiteral("QPushButton"), *font);
697 if (const QFont *font = theme->font(QPlatformTheme::CheckBoxFont))
698 fontHash->insert(QByteArrayLiteral("QCheckBox"), *font);
699 if (const QFont *font = theme->font(QPlatformTheme::RadioButtonFont))
700 fontHash->insert(QByteArrayLiteral("QRadioButton"), *font);
701 if (const QFont *font = theme->font(QPlatformTheme::ToolButtonFont))
702 fontHash->insert(QByteArrayLiteral("QToolButton"), *font);
703 if (const QFont *font = theme->font(QPlatformTheme::ItemViewFont))
704 fontHash->insert(QByteArrayLiteral("QAbstractItemView"), *font);
705 if (const QFont *font = theme->font(QPlatformTheme::ListViewFont))
706 fontHash->insert(QByteArrayLiteral("QListView"), *font);
707 if (const QFont *font = theme->font(QPlatformTheme::HeaderViewFont))
708 fontHash->insert(QByteArrayLiteral("QHeaderView"), *font);
709 if (const QFont *font = theme->font(QPlatformTheme::ListBoxFont))
710 fontHash->insert(QByteArrayLiteral("QListBox"), *font);
711 if (const QFont *font = theme->font(QPlatformTheme::ComboMenuItemFont))
712 fontHash->insert(QByteArrayLiteral("QComboMenuItem"), *font);
713 if (const QFont *font = theme->font(QPlatformTheme::ComboLineEditFont))
714 fontHash->insert(QByteArrayLiteral("QComboLineEdit"), *font);
715 if (const QFont *font = theme->font(QPlatformTheme::SmallFont))
716 fontHash->insert(QByteArrayLiteral("QSmallFont"), *font);
717 if (const QFont *font = theme->font(QPlatformTheme::MiniFont))
718 fontHash->insert(QByteArrayLiteral("QMiniFont"), *font);
719}
720
721/*****************************************************************************
722 Functions returning the active popup and modal widgets.
723 *****************************************************************************/
724
725/*!
726 Returns the active popup widget.
727
728 A popup widget is a special top-level widget that sets the \c
729 Qt::WType_Popup widget flag, e.g. the QMenu widget. When the application
730 opens a popup widget, all events are sent to the popup. Normal widgets and
731 modal widgets cannot be accessed before the popup widget is closed.
732
733 Only other popup widgets may be opened when a popup widget is shown. The
734 popup widgets are organized in a stack. This function returns the active
735 popup widget at the top of the stack.
736
737 \sa activeModalWidget(), topLevelWidgets()
738*/
739
740QWidget *QApplication::activePopupWidget()
741{
742 return QApplicationPrivate::popupWidgets && !QApplicationPrivate::popupWidgets->isEmpty() ?
743 QApplicationPrivate::popupWidgets->constLast() : nullptr;
744}
745
746
747/*!
748 Returns the active modal widget.
749
750 A modal widget is a special top-level widget which is a subclass of QDialog
751 that specifies the modal parameter of the constructor as true. A modal
752 widget must be closed before the user can continue with other parts of the
753 program.
754
755 Modal widgets are organized in a stack. This function returns the active
756 modal widget at the top of the stack.
757
758 \sa activePopupWidget(), topLevelWidgets()
759*/
760
761QWidget *QApplication::activeModalWidget()
762{
763 QWidgetWindow *widgetWindow = qobject_cast<QWidgetWindow *>(modalWindow());
764 return widgetWindow ? widgetWindow->widget() : 0;
765}
766
767/*!
768 Cleans up any window system resources that were allocated by this
769 application. Sets the global variable \c qApp to \nullptr.
770*/
771
772QApplication::~QApplication()
773{
774 Q_D(QApplication);
775
776 //### this should probable be done even later
777 qt_call_post_routines();
778
779 // kill timers before closing down the dispatcher
780 d->toolTipWakeUp.stop();
781 d->toolTipFallAsleep.stop();
782
783 QApplicationPrivate::is_app_closing = true;
784 QApplicationPrivate::is_app_running = false;
785
786 delete QWidgetPrivate::mapper;
787 QWidgetPrivate::mapper = 0;
788
789 // delete all widgets
790 if (QWidgetPrivate::allWidgets) {
791 QWidgetSet *mySet = QWidgetPrivate::allWidgets;
792 QWidgetPrivate::allWidgets = 0;
793 for (QWidgetSet::ConstIterator it = mySet->constBegin(), cend = mySet->constEnd(); it != cend; ++it) {
794 QWidget *w = *it;
795 if (!w->parent()) // window
796 w->destroy(true, true);
797 }
798 delete mySet;
799 }
800
801 delete qt_desktopWidget;
802 qt_desktopWidget = 0;
803
804 delete QApplicationPrivate::app_pal;
805 QApplicationPrivate::app_pal = 0;
806 clearSystemPalette();
807 delete QApplicationPrivate::set_pal;
808 QApplicationPrivate::set_pal = 0;
809 app_palettes()->clear();
810
811 delete QApplicationPrivate::sys_font;
812 QApplicationPrivate::sys_font = 0;
813 delete QApplicationPrivate::set_font;
814 QApplicationPrivate::set_font = 0;
815 app_fonts()->clear();
816
817 delete QApplicationPrivate::app_style;
818 QApplicationPrivate::app_style = 0;
819
820#if QT_CONFIG(draganddrop)
821 if (qt_is_gui_used)
822 delete QDragManager::self();
823#endif
824
825 d->cleanupMultitouch();
826
827 qt_cleanup();
828
829 if (QApplicationPrivate::widgetCount)
830 qDebug("Widgets left: %i Max widgets: %i \n", QWidgetPrivate::instanceCounter, QWidgetPrivate::maxInstances);
831
832 QApplicationPrivate::obey_desktop_settings = true;
833
834 QApplicationPrivate::app_strut = QSize(0, 0);
835 QApplicationPrivate::enabledAnimations = QPlatformTheme::GeneralUiEffect;
836 QApplicationPrivate::widgetCount = false;
837
838#if QT_CONFIG(statemachine)
839 // trigger unregistering of QStateMachine's GUI types
840 qUnregisterGuiStateMachine();
841#endif
842}
843
844#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
845#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
846// #fixme: Remove.
847static HDC displayDC = 0; // display device context
848
849Q_WIDGETS_EXPORT HDC qt_win_display_dc() // get display DC
850{
851 Q_ASSERT(qApp && qApp->thread() == QThread::currentThread());
852 if (!displayDC)
853 displayDC = GetDC(0);
854 return displayDC;
855}
856#endif
857#endif
858
859void qt_cleanup()
860{
861 QPixmapCache::clear();
862 QColormap::cleanup();
863
864 QApplicationPrivate::active_window = 0; //### this should not be necessary
865#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
866#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
867 if (displayDC) {
868 ReleaseDC(0, displayDC);
869 displayDC = 0;
870 }
871#endif
872#endif
873}
874
875/*!
876 \fn QWidget *QApplication::widgetAt(const QPoint &point)
877
878 Returns the widget at global screen position \a point, or \nullptr
879 if there is no Qt widget there.
880
881 This function can be slow.
882
883 \sa QCursor::pos(), QWidget::grabMouse(), QWidget::grabKeyboard()
884*/
885QWidget *QApplication::widgetAt(const QPoint &p)
886{
887 QWidget *window = QApplication::topLevelAt(p);
888 if (!window)
889 return nullptr;
890
891 QWidget *child = nullptr;
892
893 if (!window->testAttribute(Qt::WA_TransparentForMouseEvents))
894 child = window->childAt(window->mapFromGlobal(p));
895
896 if (child)
897 return child;
898
899 if (window->testAttribute(Qt::WA_TransparentForMouseEvents)) {
900 //shoot a hole in the widget and try once again,
901 //suboptimal on Qt for Embedded Linux where we do
902 //know the stacking order of the toplevels.
903 int x = p.x();
904 int y = p.y();
905 QRegion oldmask = window->mask();
906 QPoint wpoint = window->mapFromGlobal(QPoint(x, y));
907 QRegion newmask = (oldmask.isEmpty() ? QRegion(window->rect()) : oldmask)
908 - QRegion(wpoint.x(), wpoint.y(), 1, 1);
909 window->setMask(newmask);
910 QWidget *recurse = 0;
911 if (QApplication::topLevelAt(p) != window) // verify recursion will terminate
912 recurse = widgetAt(x, y);
913 if (oldmask.isEmpty())
914 window->clearMask();
915 else
916 window->setMask(oldmask);
917 return recurse;
918 }
919 return window;
920}
921
922/*!
923 \fn QWidget *QApplication::widgetAt(int x, int y)
924
925 \overload
926
927 Returns the widget at global screen position (\a x, \a y), or
928 \nullptr if there is no Qt widget there.
929*/
930
931/*!
932 \internal
933*/
934bool QApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventList *postedEvents)
935{
936 if ((event->type() == QEvent::UpdateRequest
937 || event->type() == QEvent::LayoutRequest
938 || event->type() == QEvent::Resize
939 || event->type() == QEvent::Move
940 || event->type() == QEvent::LanguageChange)) {
941 for (QPostEventList::const_iterator it = postedEvents->constBegin(); it != postedEvents->constEnd(); ++it) {
942 const QPostEvent &cur = *it;
943 if (cur.receiver != receiver || cur.event == 0 || cur.event->type() != event->type())
944 continue;
945 if (cur.event->type() == QEvent::LayoutRequest
946 || cur.event->type() == QEvent::UpdateRequest) {
947 ;
948 } else if (cur.event->type() == QEvent::Resize) {
949 ((QResizeEvent *)(cur.event))->s = ((QResizeEvent *)event)->s;
950 } else if (cur.event->type() == QEvent::Move) {
951 ((QMoveEvent *)(cur.event))->p = ((QMoveEvent *)event)->p;
952 } else if (cur.event->type() == QEvent::LanguageChange) {
953 ;
954 } else {
955 continue;
956 }
957 delete event;
958 return true;
959 }
960 return false;
961 }
962 return QGuiApplication::compressEvent(event, receiver, postedEvents);
963}
964
965/*!
966 \property QApplication::styleSheet
967 \brief the application style sheet
968 \since 4.2
969
970 By default, this property returns an empty string unless the user specifies
971 the \c{-stylesheet} option on the command line when running the application.
972
973 \sa QWidget::setStyle(), {Qt Style Sheets}
974*/
975
976/*!
977 \property QApplication::autoSipEnabled
978 \since 4.5
979 \brief toggles automatic SIP (software input panel) visibility
980
981 Set this property to \c true to automatically display the SIP when entering
982 widgets that accept keyboard input. This property only affects widgets with
983 the WA_InputMethodEnabled attribute set, and is typically used to launch
984 a virtual keyboard on devices which have very few or no keys.
985
986 \b{ The property only has an effect on platforms that use software input
987 panels.}
988
989 The default is platform dependent.
990*/
991void QApplication::setAutoSipEnabled(const bool enabled)
992{
993 QApplicationPrivate::autoSipEnabled = enabled;
994}
995
996bool QApplication::autoSipEnabled() const
997{
998 return QApplicationPrivate::autoSipEnabled;
999}
1000
1001#ifndef QT_NO_STYLE_STYLESHEET
1002
1003QString QApplication::styleSheet() const
1004{
1005 return QApplicationPrivate::styleSheet;
1006}
1007
1008void QApplication::setStyleSheet(const QString& styleSheet)
1009{
1010 QApplicationPrivate::styleSheet = styleSheet;
1011 QStyleSheetStyle *styleSheetStyle = qt_styleSheet(QApplicationPrivate::app_style);
1012 if (styleSheet.isEmpty()) { // application style sheet removed
1013 if (!styleSheetStyle)
1014 return; // there was no stylesheet before
1015 setStyle(styleSheetStyle->base);
1016 } else if (styleSheetStyle) { // style sheet update, just repolish
1017 styleSheetStyle->repolish(qApp);
1018 } else { // stylesheet set the first time
1019 QStyleSheetStyle *newStyleSheetStyle = new QStyleSheetStyle(QApplicationPrivate::app_style);
1020 QApplicationPrivate::app_style->setParent(newStyleSheetStyle);
1021 setStyle(newStyleSheetStyle);
1022 }
1023}
1024
1025#endif // QT_NO_STYLE_STYLESHEET
1026
1027/*!
1028 Returns the application's style object.
1029
1030 \sa setStyle(), QStyle
1031*/
1032QStyle *QApplication::style()
1033{
1034 if (QApplicationPrivate::app_style)
1035 return QApplicationPrivate::app_style;
1036 if (!qobject_cast<QApplication *>(QCoreApplication::instance())) {
1037 Q_ASSERT(!"No style available without QApplication!");
1038 return 0;
1039 }
1040
1041 if (!QApplicationPrivate::app_style) {
1042 // Compile-time search for default style
1043 //
1044 QStyle *&app_style = QApplicationPrivate::app_style;
1045
1046 if (!QApplicationPrivate::styleOverride.isEmpty()) {
1047 const QString style = QApplicationPrivate::styleOverride.toLower();
1048 app_style = QStyleFactory::create(style);
1049 if (Q_UNLIKELY(!app_style)) {
1050 qWarning("QApplication: invalid style override passed, ignoring it.\n"
1051 " Available styles: %s", qPrintable(QStyleFactory::keys().join(QLatin1String(", "))));
1052 }
1053 }
1054 if (!app_style)
1055 app_style = QStyleFactory::create(QApplicationPrivate::desktopStyleKey());
1056
1057 if (!app_style) {
1058 const QStringList styles = QStyleFactory::keys();
1059 for (const auto &style : styles) {
1060 if ((app_style = QStyleFactory::create(style)))
1061 break;
1062 }
1063 }
1064 if (!app_style) {
1065 Q_ASSERT(!"No styles available!");
1066 return 0;
1067 }
1068 }
1069 // take ownership of the style
1070 QApplicationPrivate::app_style->setParent(qApp);
1071
1072 initSystemPalette();
1073
1074 if (QApplicationPrivate::set_pal) // repolish set palette with the new style
1075 QApplication::setPalette(*QApplicationPrivate::set_pal);
1076
1077#ifndef QT_NO_STYLE_STYLESHEET
1078 if (!QApplicationPrivate::styleSheet.isEmpty()) {
1079 qApp->setStyleSheet(QApplicationPrivate::styleSheet);
1080 } else
1081#endif
1082 QApplicationPrivate::app_style->polish(qApp);
1083
1084 return QApplicationPrivate::app_style;
1085}
1086
1087/*!
1088 Sets the application's GUI style to \a style. Ownership of the style object
1089 is transferred to QApplication, so QApplication will delete the style
1090 object on application exit or when a new style is set and the old style is
1091 still the parent of the application object.
1092
1093 Example usage:
1094 \snippet code/src_gui_kernel_qapplication.cpp 1
1095
1096 When switching application styles, the color palette is set back to the
1097 initial colors or the system defaults. This is necessary since certain
1098 styles have to adapt the color palette to be fully style-guide compliant.
1099
1100 Setting the style before a palette has been set, i.e., before creating
1101 QApplication, will cause the application to use QStyle::standardPalette()
1102 for the palette.
1103
1104 \warning Qt style sheets are currently not supported for custom QStyle
1105 subclasses. We plan to address this in some future release.
1106
1107 \sa style(), QStyle, setPalette(), desktopSettingsAware()
1108*/
1109void QApplication::setStyle(QStyle *style)
1110{
1111 if (!style || style == QApplicationPrivate::app_style)
1112 return;
1113
1114 QWidgetList all = allWidgets();
1115
1116 // clean up the old style
1117 if (QApplicationPrivate::app_style) {
1118 if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) {
1119 for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
1120 QWidget *w = *it;
1121 if (!(w->windowType() == Qt::Desktop) && // except desktop
1122 w->testAttribute(Qt::WA_WState_Polished)) { // has been polished
1123 QApplicationPrivate::app_style->unpolish(w);
1124 }
1125 }
1126 }
1127 QApplicationPrivate::app_style->unpolish(qApp);
1128 }
1129
1130 QStyle *old = QApplicationPrivate::app_style; // save
1131
1132#ifndef QT_NO_STYLE_STYLESHEET
1133 if (!QApplicationPrivate::styleSheet.isEmpty() && !qt_styleSheet(style)) {
1134 // we have a stylesheet already and a new style is being set
1135 QStyleSheetStyle *newStyleSheetStyle = new QStyleSheetStyle(style);
1136 style->setParent(newStyleSheetStyle);
1137 QApplicationPrivate::app_style = newStyleSheetStyle;
1138 } else
1139#endif // QT_NO_STYLE_STYLESHEET
1140 QApplicationPrivate::app_style = style;
1141 QApplicationPrivate::app_style->setParent(qApp); // take ownership
1142
1143 // take care of possible palette requirements of certain gui
1144 // styles. Do it before polishing the application since the style
1145 // might call QApplication::setPalette() itself
1146 if (QApplicationPrivate::set_pal) {
1147 QApplication::setPalette(*QApplicationPrivate::set_pal);
1148 } else if (QApplicationPrivate::sys_pal) {
1149 clearSystemPalette();
1150 initSystemPalette();
1151 QApplicationPrivate::initializeWidgetFontHash();
1152 } else if (!QApplicationPrivate::sys_pal) {
1153 // Initialize the sys_pal if it hasn't happened yet...
1154 QApplicationPrivate::setSystemPalette(QApplicationPrivate::app_style->standardPalette());
1155 }
1156
1157 // initialize the application with the new style
1158 QApplicationPrivate::app_style->polish(qApp);
1159
1160 // re-polish existing widgets if necessary
1161 if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) {
1162 for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
1163 QWidget *w = *it;
1164 if (w->windowType() != Qt::Desktop && w->testAttribute(Qt::WA_WState_Polished)) {
1165 if (w->style() == QApplicationPrivate::app_style)
1166 QApplicationPrivate::app_style->polish(w); // repolish
1167#ifndef QT_NO_STYLE_STYLESHEET
1168 else
1169 w->setStyleSheet(w->styleSheet()); // touch
1170#endif
1171 }
1172 }
1173
1174 for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
1175 QWidget *w = *it;
1176 if (w->windowType() != Qt::Desktop && !w->testAttribute(Qt::WA_SetStyle)) {
1177 QEvent e(QEvent::StyleChange);
1178 QCoreApplication::sendEvent(w, &e);
1179 w->update();
1180 }
1181 }
1182 }
1183
1184#ifndef QT_NO_STYLE_STYLESHEET
1185 if (QStyleSheetStyle *oldStyleSheetStyle = qt_styleSheet(old)) {
1186 oldStyleSheetStyle->deref();
1187 } else
1188#endif
1189 if (old && old->parent() == qApp) {
1190 delete old;
1191 }
1192
1193 if (QApplicationPrivate::focus_widget) {
1194 QFocusEvent in(QEvent::FocusIn, Qt::OtherFocusReason);
1195 QCoreApplication::sendEvent(QApplicationPrivate::focus_widget->style(), &in);
1196 QApplicationPrivate::focus_widget->update();
1197 }
1198}
1199
1200/*!
1201 \overload
1202
1203 Requests a QStyle object for \a style from the QStyleFactory.
1204
1205 The string must be one of the QStyleFactory::keys(), typically one of
1206 "windows", "windowsvista", "fusion", or "macintosh". Style
1207 names are case insensitive.
1208
1209 Returns \nullptr if an unknown \a style is passed, otherwise the QStyle object
1210 returned is set as the application's GUI style.
1211
1212 \warning To ensure that the application's style is set correctly, it is
1213 best to call this function before the QApplication constructor, if
1214 possible.
1215*/
1216QStyle* QApplication::setStyle(const QString& style)
1217{
1218 QStyle *s = QStyleFactory::create(style);
1219 if (!s)
1220 return 0;
1221
1222 setStyle(s);
1223 return s;
1224}
1225
1226#if QT_DEPRECATED_SINCE(5, 8)
1227/*!
1228 Returns the color specification.
1229 \obsolete
1230
1231 \sa QApplication::setColorSpec()
1232*/
1233
1234int QApplication::colorSpec()
1235{
1236 return QApplication::NormalColor;
1237}
1238
1239/*!
1240 Sets the color specification for the application to \a spec.
1241 \obsolete
1242
1243 This call has no effect.
1244
1245 The color specification controls how the application allocates colors when
1246 run on a display with a limited amount of colors, e.g. 8 bit / 256 color
1247 displays.
1248
1249 The color specification must be set before you create the QApplication
1250 object.
1251
1252 The options are:
1253 \list
1254 \li QApplication::NormalColor. This is the default color allocation
1255 strategy. Use this option if your application uses buttons, menus,
1256 texts and pixmaps with few colors. With this option, the
1257 application uses system global colors. This works fine for most
1258 applications under X11, but on the Windows platform, it may cause
1259 dithering of non-standard colors.
1260 \li QApplication::CustomColor. Use this option if your application
1261 needs a small number of custom colors. On X11, this option is the
1262 same as NormalColor. On Windows, Qt creates a Windows palette, and
1263 allocates colors to it on demand.
1264 \li QApplication::ManyColor. Use this option if your application is
1265 very color hungry, e.g., it requires thousands of colors. \br
1266 Under X11 the effect is:
1267 \list
1268 \li For 256-color displays which have at best a 256 color true
1269 color visual, the default visual is used, and colors are
1270 allocated from a color cube. The color cube is the 6x6x6
1271 (216 color) "Web palette" (the red, green, and blue
1272 components always have one of the following values: 0x00,
1273 0x33, 0x66, 0x99, 0xCC, or 0xFF), but the number of colors
1274 can be changed by the \e -ncols option. The user can force
1275 the application to use the true color visual with the
1276 \l{QApplication::QApplication()}{-visual} option.
1277 \li For 256-color displays which have a true color visual with
1278 more than 256 colors, use that visual. Silicon Graphics X
1279 servers this feature, for example. They provide an 8 bit
1280 visual by default but can deliver true color when asked.
1281 \endlist
1282 On Windows, Qt creates a Windows palette, and fills it with a color
1283 cube.
1284 \endlist
1285
1286 Be aware that the CustomColor and ManyColor choices may lead to colormap
1287 flashing: The foreground application gets (most) of the available colors,
1288 while the background windows will look less attractive.
1289
1290 Example:
1291
1292 \snippet code/src_gui_kernel_qapplication.cpp 2
1293
1294 \sa colorSpec()
1295*/
1296
1297void QApplication::setColorSpec(int spec)
1298{
1299 Q_UNUSED(spec)
1300}
1301#endif
1302
1303/*!
1304 \property QApplication::globalStrut
1305 \brief the minimum size that any GUI element that the user can interact
1306 with should have
1307
1308 For example, no button should be resized to be smaller than the global
1309 strut size. The strut size should be considered when reimplementing GUI
1310 controls that may be used on touch-screens or similar I/O devices.
1311
1312 Example:
1313
1314 \snippet code/src_gui_kernel_qapplication.cpp 3
1315
1316 By default, this property contains a QSize object with zero width and height.
1317*/
1318QSize QApplication::globalStrut()
1319{
1320 return QApplicationPrivate::app_strut;
1321}
1322
1323void QApplication::setGlobalStrut(const QSize& strut)
1324{
1325 QApplicationPrivate::app_strut = strut;
1326}
1327
1328
1329/*!
1330 \fn QPalette QApplication::palette(const QWidget* widget)
1331
1332 If a \a widget is passed, the default palette for the widget's class is
1333 returned. This may or may not be the application palette. In most cases
1334 there is no special palette for certain types of widgets, but one notable
1335 exception is the popup menu under Windows, if the user has defined a
1336 special background color for menus in the display settings.
1337
1338 \sa setPalette(), QWidget::palette()
1339*/
1340QPalette QApplication::palette(const QWidget* w)
1341{
1342 typedef PaletteHash::const_iterator PaletteHashConstIt;
1343
1344 PaletteHash *hash = app_palettes();
1345 if (w && hash && hash->size()) {
1346 PaletteHashConstIt it = hash->constFind(w->metaObject()->className());
1347 const PaletteHashConstIt cend = hash->constEnd();
1348 if (it != cend)
1349 return *it;
1350 for (it = hash->constBegin(); it != cend; ++it) {
1351 if (w->inherits(it.key()))
1352 return it.value();
1353 }
1354 }
1355 return palette();
1356}
1357
1358/*!
1359 \overload
1360
1361 Returns the palette for widgets of the given \a className.
1362
1363 \sa setPalette(), QWidget::palette()
1364*/
1365QPalette QApplication::palette(const char *className)
1366{
1367 if (!QApplicationPrivate::app_pal)
1368 palette();
1369 PaletteHash *hash = app_palettes();
1370 if (className && hash && hash->size()) {
1371 QHash<QByteArray, QPalette>::ConstIterator it = hash->constFind(className);
1372 if (it != hash->constEnd())
1373 return *it;
1374 }
1375 return *QApplicationPrivate::app_pal;
1376}
1377
1378void QApplicationPrivate::setPalette_helper(const QPalette &palette, const char* className, bool clearWidgetPaletteHash)
1379{
1380 QPalette pal = palette;
1381
1382 if (QApplicationPrivate::app_style)
1383 QApplicationPrivate::app_style->polish(pal); // NB: non-const reference
1384
1385 bool all = false;
1386 PaletteHash *hash = app_palettes();
1387 if (!className) {
1388 if (QApplicationPrivate::app_pal && pal.isCopyOf(*QApplicationPrivate::app_pal))
1389 return;
1390 if (!QApplicationPrivate::app_pal)
1391 QApplicationPrivate::app_pal = new QPalette(pal);
1392 else
1393 *QApplicationPrivate::app_pal = pal;
1394 if (hash && hash->size()) {
1395 all = true;
1396 if (clearWidgetPaletteHash)
1397 hash->clear();
1398 }
1399 } else if (hash) {
1400 hash->insert(className, pal);
1401 }
1402
1403 if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) {
1404 // Send ApplicationPaletteChange to qApp itself, and to the widgets.
1405 qApp->d_func()->sendApplicationPaletteChange(all, className);
1406 }
1407 if (!className && (!QApplicationPrivate::sys_pal || !palette.isCopyOf(*QApplicationPrivate::sys_pal))) {
1408 if (!QApplicationPrivate::set_pal)
1409 QApplicationPrivate::set_pal = new QPalette(palette);
1410 else
1411 *QApplicationPrivate::set_pal = palette;
1412 QCoreApplication::setAttribute(Qt::AA_SetPalette);
1413 emit qGuiApp->paletteChanged(*QGuiApplicationPrivate::app_pal);
1414 }
1415}
1416
1417/*!
1418 Changes the default application palette to \a palette.
1419
1420 If \a className is passed, the change applies only to widgets that inherit
1421 \a className (as reported by QObject::inherits()). If \a className is left
1422 0, the change affects all widgets, thus overriding any previously set class
1423 specific palettes.
1424
1425 The palette may be changed according to the current GUI style in
1426 QStyle::polish().
1427
1428 \warning Do not use this function in conjunction with \l{Qt Style Sheets}.
1429 When using style sheets, the palette of a widget can be customized using
1430 the "color", "background-color", "selection-color",
1431 "selection-background-color" and "alternate-background-color".
1432
1433 \note Some styles do not use the palette for all drawing, for instance, if
1434 they make use of native theme engines. This is the case for the
1435 Windows Vista and \macos styles.
1436
1437 \sa QWidget::setPalette(), palette(), QStyle::polish()
1438*/
1439
1440void QApplication::setPalette(const QPalette &palette, const char* className)
1441{
1442 QApplicationPrivate::setPalette_helper(palette, className, /*clearWidgetPaletteHash=*/ true);
1443}
1444
1445
1446
1447void QApplicationPrivate::setSystemPalette(const QPalette &pal)
1448{
1449 if (!sys_pal)
1450 sys_pal = new QPalette(pal);
1451 else
1452 *sys_pal = pal;
1453
1454 if (!QApplicationPrivate::set_pal)
1455 QApplication::setPalette(*sys_pal);
1456}
1457
1458/*!
1459 Returns the default application font.
1460
1461 \sa fontMetrics(), QWidget::font()
1462*/
1463QFont QApplication::font()
1464{
1465 return QGuiApplication::font();
1466}
1467
1468/*!
1469 \overload
1470
1471 Returns the default font for the \a widget.
1472
1473 \sa fontMetrics(), QWidget::setFont()
1474*/
1475
1476QFont QApplication::font(const QWidget *widget)
1477{
1478 typedef FontHash::const_iterator FontHashConstIt;
1479
1480 FontHash *hash = app_fonts();
1481
1482 if (widget && hash && hash->size()) {
1483#ifdef Q_OS_MAC
1484 // short circuit for small and mini controls
1485 if (widget->testAttribute(Qt::WA_MacSmallSize)) {
1486 return hash->value(QByteArrayLiteral("QSmallFont"));
1487 } else if (widget->testAttribute(Qt::WA_MacMiniSize)) {
1488 return hash->value(QByteArrayLiteral("QMiniFont"));
1489 }
1490#endif
1491 FontHashConstIt it = hash->constFind(widget->metaObject()->className());
1492 const FontHashConstIt cend = hash->constEnd();
1493 if (it != cend)
1494 return it.value();
1495 for (it = hash->constBegin(); it != cend; ++it) {
1496 if (widget->inherits(it.key()))
1497 return it.value();
1498 }
1499 }
1500 return font();
1501}
1502
1503/*!
1504 \overload
1505
1506 Returns the font for widgets of the given \a className.
1507
1508 \sa setFont(), QWidget::font()
1509*/
1510QFont QApplication::font(const char *className)
1511{
1512 FontHash *hash = app_fonts();
1513 if (className && hash && hash->size()) {
1514 QHash<QByteArray, QFont>::ConstIterator it = hash->constFind(className);
1515 if (it != hash->constEnd())
1516 return *it;
1517 }
1518 return font();
1519}
1520
1521
1522/*!
1523 Changes the default application font to \a font. If \a className is passed,
1524 the change applies only to classes that inherit \a className (as reported
1525 by QObject::inherits()).
1526
1527 On application start-up, the default font depends on the window system. It
1528 can vary depending on both the window system version and the locale. This
1529 function lets you override the default font; but overriding may be a bad
1530 idea because, for example, some locales need extra large fonts to support
1531 their special characters.
1532
1533 \warning Do not use this function in conjunction with \l{Qt Style Sheets}.
1534 The font of an application can be customized using the "font" style sheet
1535 property. To set a bold font for all QPushButtons, set the application
1536 styleSheet() as "QPushButton { font: bold }"
1537
1538 \sa font(), fontMetrics(), QWidget::setFont()
1539*/
1540
1541void QApplication::setFont(const QFont &font, const char *className)
1542{
1543 bool all = false;
1544 FontHash *hash = app_fonts();
1545 if (!className) {
1546 QGuiApplication::setFont(font);
1547 if (hash && hash->size()) {
1548 all = true;
1549 hash->clear();
1550 }
1551 } else if (hash) {
1552 hash->insert(className, font);
1553 }
1554 if (QApplicationPrivate::is_app_running && !QApplicationPrivate::is_app_closing) {
1555 // Send ApplicationFontChange to qApp itself, and to the widgets.
1556 QEvent e(QEvent::ApplicationFontChange);
1557 QCoreApplication::sendEvent(QApplication::instance(), &e);
1558
1559 QWidgetList wids = QApplication::allWidgets();
1560 for (QWidgetList::ConstIterator it = wids.constBegin(), cend = wids.constEnd(); it != cend; ++it) {
1561 QWidget *w = *it;
1562 if (all || (!className && w->isWindow()) || w->inherits(className)) // matching class
1563 sendEvent(w, &e);
1564 }
1565
1566#if QT_CONFIG(graphicsview)
1567 // Send to all scenes as well.
1568 QList<QGraphicsScene *> &scenes = qApp->d_func()->scene_list;
1569 for (QList<QGraphicsScene *>::ConstIterator it = scenes.constBegin();
1570 it != scenes.constEnd(); ++it) {
1571 QCoreApplication::sendEvent(*it, &e);
1572 }
1573#endif // QT_CONFIG(graphicsview)
1574 }
1575 if (!className && (!QApplicationPrivate::sys_font || !font.isCopyOf(*QApplicationPrivate::sys_font))) {
1576 if (!QApplicationPrivate::set_font)
1577 QApplicationPrivate::set_font = new QFont(font);
1578 else
1579 *QApplicationPrivate::set_font = font;
1580 }
1581}
1582
1583/*! \internal
1584*/
1585void QApplicationPrivate::setSystemFont(const QFont &font)
1586{
1587 if (!sys_font)
1588 sys_font = new QFont(font);
1589 else
1590 *sys_font = font;
1591
1592 if (!QApplicationPrivate::set_font)
1593 QApplication::setFont(*sys_font);
1594}
1595
1596/*! \internal
1597*/
1598QString QApplicationPrivate::desktopStyleKey()
1599{
1600 // The platform theme might return a style that is not available, find
1601 // first valid one.
1602 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
1603 const QStringList availableKeys = QStyleFactory::keys();
1604 const auto styles = theme->themeHint(QPlatformTheme::StyleNames).toStringList();
1605 for (const QString &style : styles) {
1606 if (availableKeys.contains(style, Qt::CaseInsensitive))
1607 return style;
1608 }
1609 }
1610 return QString();
1611}
1612
1613#if QT_VERSION < 0x060000 // remove these forwarders in Qt 6
1614/*!
1615 \property QApplication::windowIcon
1616 \brief the default window icon
1617
1618 \sa QWidget::setWindowIcon(), {Setting the Application Icon}
1619*/
1620QIcon QApplication::windowIcon()
1621{
1622 return QGuiApplication::windowIcon();
1623}
1624
1625void QApplication::setWindowIcon(const QIcon &icon)
1626{
1627 QGuiApplication::setWindowIcon(icon);
1628}
1629#endif
1630
1631void QApplicationPrivate::notifyWindowIconChanged()
1632{
1633 QEvent ev(QEvent::ApplicationWindowIconChange);
1634 const QWidgetList list = QApplication::topLevelWidgets();
1635 QWindowList windowList = QGuiApplication::topLevelWindows();
1636
1637 // send to all top-level QWidgets
1638 for (auto *w : list) {
1639 windowList.removeOne(w->windowHandle());
1640 QCoreApplication::sendEvent(w, &ev);
1641 }
1642
1643 // in case there are any plain QWindows in this QApplication-using
1644 // application, also send the notification to them
1645 for (int i = 0; i < windowList.size(); ++i)
1646 QCoreApplication::sendEvent(windowList.at(i), &ev);
1647}
1648
1649/*!
1650 Returns a list of the top-level widgets (windows) in the application.
1651
1652 \note Some of the top-level widgets may be hidden, for example a tooltip if
1653 no tooltip is currently shown.
1654
1655 Example:
1656
1657 \snippet code/src_gui_kernel_qapplication.cpp 4
1658
1659 \sa allWidgets(), QWidget::isWindow(), QWidget::isHidden()
1660*/
1661QWidgetList QApplication::topLevelWidgets()
1662{
1663 QWidgetList list;
1664 if (QWidgetPrivate::allWidgets != nullptr) {
1665 const auto isTopLevelWidget = [] (const QWidget *w) {
1666 return w->isWindow() && w->windowType() != Qt::Desktop;
1667 };
1668 std::copy_if(QWidgetPrivate::allWidgets->cbegin(), QWidgetPrivate::allWidgets->cend(),
1669 std::back_inserter(list), isTopLevelWidget);
1670 }
1671 return list;
1672}
1673
1674/*!
1675 Returns a list of all the widgets in the application.
1676
1677 The list is empty (QList::isEmpty()) if there are no widgets.
1678
1679 \note Some of the widgets may be hidden.
1680
1681 Example:
1682 \snippet code/src_gui_kernel_qapplication.cpp 5
1683
1684 \sa topLevelWidgets(), QWidget::isVisible()
1685*/
1686
1687QWidgetList QApplication::allWidgets()
1688{
1689 if (QWidgetPrivate::allWidgets)
1690 return QWidgetPrivate::allWidgets->values();
1691 return QWidgetList();
1692}
1693
1694/*!
1695 Returns the application widget that has the keyboard input focus,
1696 or \nullptr if no widget in this application has the focus.
1697
1698 \sa QWidget::setFocus(), QWidget::hasFocus(), activeWindow(), focusChanged()
1699*/
1700
1701QWidget *QApplication::focusWidget()
1702{
1703 return QApplicationPrivate::focus_widget;
1704}
1705
1706void QApplicationPrivate::setFocusWidget(QWidget *focus, Qt::FocusReason reason)
1707{
1708#if QT_CONFIG(graphicsview)
1709 if (focus && focus->window()->graphicsProxyWidget())
1710 return;
1711#endif
1712
1713 hidden_focus_widget = 0;
1714
1715 if (focus != focus_widget) {
1716 if (focus && focus->isHidden()) {
1717 hidden_focus_widget = focus;
1718 return;
1719 }
1720
1721 if (focus && (reason == Qt::BacktabFocusReason || reason == Qt::TabFocusReason)
1722 && qt_in_tab_key_event)
1723 focus->window()->setAttribute(Qt::WA_KeyboardFocusChange);
1724 else if (focus && reason == Qt::ShortcutFocusReason) {
1725 focus->window()->setAttribute(Qt::WA_KeyboardFocusChange);
1726 }
1727 QWidget *prev = focus_widget;
1728 focus_widget = focus;
1729
1730 if(focus_widget)
1731 focus_widget->d_func()->setFocus_sys();
1732
1733 if (reason != Qt::NoFocusReason) {
1734
1735 //send events
1736 if (prev) {
1737#ifdef QT_KEYPAD_NAVIGATION
1738 if (QApplication::keypadNavigationEnabled()) {
1739 if (prev->hasEditFocus() && reason != Qt::PopupFocusReason)
1740 prev->setEditFocus(false);
1741 }
1742#endif
1743 QFocusEvent out(QEvent::FocusOut, reason);
1744 QPointer<QWidget> that = prev;
1745 QCoreApplication::sendEvent(prev, &out);
1746 if (that)
1747 QCoreApplication::sendEvent(that->style(), &out);
1748 }
1749 if(focus && QApplicationPrivate::focus_widget == focus) {
1750 QFocusEvent in(QEvent::FocusIn, reason);
1751 QPointer<QWidget> that = focus;
1752 QCoreApplication::sendEvent(focus, &in);
1753 if (that)
1754 QCoreApplication::sendEvent(that->style(), &in);
1755 }
1756 emit qApp->focusChanged(prev, focus_widget);
1757 }
1758 }
1759}
1760
1761
1762/*!
1763 Returns the application top-level window that has the keyboard input focus,
1764 or \nullptr if no application window has the focus. There might be an
1765 activeWindow() even if there is no focusWidget(), for example if no widget
1766 in that window accepts key events.
1767
1768 \sa QWidget::setFocus(), QWidget::hasFocus(), focusWidget()
1769*/
1770
1771QWidget *QApplication::activeWindow()
1772{
1773 return QApplicationPrivate::active_window;
1774}
1775
1776/*!
1777 Returns display (screen) font metrics for the application font.
1778
1779 \sa font(), setFont(), QWidget::fontMetrics(), QPainter::fontMetrics()
1780*/
1781
1782QFontMetrics QApplication::fontMetrics()
1783{
1784 return desktop()->fontMetrics();
1785}
1786
1787bool QApplicationPrivate::tryCloseAllWidgetWindows(QWindowList *processedWindows)
1788{
1789 Q_ASSERT(processedWindows);
1790 while (QWidget *w = QApplication::activeModalWidget()) {
1791 if (!w->isVisible() || w->data->is_closing)
1792 break;
1793 QWindow *window = w->windowHandle();
1794 if (!window->close()) // Qt::WA_DeleteOnClose may cause deletion.
1795 return false;
1796 if (window)
1797 processedWindows->append(window);
1798 }
1799
1800retry:
1801 const QWidgetList list = QApplication::topLevelWidgets();
1802 for (auto *w : list) {
1803 if (w->isVisible() && w->windowType() != Qt::Desktop &&
1804 !w->testAttribute(Qt::WA_DontShowOnScreen) && !w->data->is_closing) {
1805 QWindow *window = w->windowHandle();
1806 if (!window->close()) // Qt::WA_DeleteOnClose may cause deletion.
1807 return false;
1808 if (window)
1809 processedWindows->append(window);
1810 goto retry;
1811 }
1812 }
1813 return true;
1814}
1815
1816bool QApplicationPrivate::tryCloseAllWindows()
1817{
1818 QWindowList processedWindows;
1819 return QApplicationPrivate::tryCloseAllWidgetWindows(&processedWindows)
1820 && QGuiApplicationPrivate::tryCloseRemainingWindows(processedWindows);
1821}
1822
1823/*!
1824 Closes all top-level windows.
1825
1826 This function is particularly useful for applications with many top-level
1827 windows. It could, for example, be connected to a \uicontrol{Exit} entry in the
1828 \uicontrol{File} menu:
1829
1830 \snippet mainwindows/mdi/mainwindow.cpp 0
1831
1832 The windows are closed in random order, until one window does not accept
1833 the close event. The application quits when the last window was
1834 successfully closed; this can be turned off by setting
1835 \l quitOnLastWindowClosed to false.
1836
1837 \sa quitOnLastWindowClosed, lastWindowClosed(), QWidget::close(),
1838 QWidget::closeEvent(), lastWindowClosed(), QCoreApplication::quit(), topLevelWidgets(),
1839 QWidget::isWindow()
1840*/
1841void QApplication::closeAllWindows()
1842{
1843 QWindowList processedWindows;
1844 QApplicationPrivate::tryCloseAllWidgetWindows(&processedWindows);
1845}
1846
1847/*!
1848 Displays a simple message box about Qt. The message includes the version
1849 number of Qt being used by the application.
1850
1851 This is useful for inclusion in the \uicontrol Help menu of an application, as
1852 shown in the \l{mainwindows/menus}{Menus} example.
1853
1854 This function is a convenience slot for QMessageBox::aboutQt().
1855*/
1856void QApplication::aboutQt()
1857{
1858#if QT_CONFIG(messagebox)
1859 QMessageBox::aboutQt(activeWindow());
1860#endif // QT_CONFIG(messagebox)
1861}
1862
1863/*!
1864 \since 4.1
1865 \fn void QApplication::focusChanged(QWidget *old, QWidget *now)
1866
1867 This signal is emitted when the widget that has keyboard focus changed from
1868 \a old to \a now, i.e., because the user pressed the tab-key, clicked into
1869 a widget or changed the active window. Both \a old and \a now can be \nullptr.
1870
1871
1872 The signal is emitted after both widget have been notified about the change
1873 through QFocusEvent.
1874
1875 \sa QWidget::setFocus(), QWidget::clearFocus(), Qt::FocusReason
1876*/
1877
1878/*!\reimp
1879
1880*/
1881bool QApplication::event(QEvent *e)
1882{
1883 Q_D(QApplication);
1884 if(e->type() == QEvent::Close) {
1885 QCloseEvent *ce = static_cast<QCloseEvent*>(e);
1886 ce->accept();
1887 closeAllWindows();
1888
1889 const QWidgetList list = topLevelWidgets();
1890 for (auto *w : list) {
1891 if (w->isVisible() && !(w->windowType() == Qt::Desktop) && !(w->windowType() == Qt::Popup) &&
1892 (!(w->windowType() == Qt::Dialog) || !w->parentWidget())) {
1893 ce->ignore();
1894 break;
1895 }
1896 }
1897 if (ce->isAccepted()) {
1898 return true;
1899 }
1900#ifndef Q_OS_WIN
1901 } else if (e->type() == QEvent::LocaleChange) {
1902 // on Windows the event propagation is taken care by the
1903 // WM_SETTINGCHANGE event handler.
1904 const QWidgetList list = topLevelWidgets();
1905 for (auto *w : list) {
1906 if (!(w->windowType() == Qt::Desktop)) {
1907 if (!w->testAttribute(Qt::WA_SetLocale))
1908 w->d_func()->setLocale_helper(QLocale(), true);
1909 }
1910 }
1911#endif
1912 } else if (e->type() == QEvent::Timer) {
1913 QTimerEvent *te = static_cast<QTimerEvent*>(e);
1914 Q_ASSERT(te != 0);
1915 if (te->timerId() == d->toolTipWakeUp.timerId()) {
1916 d->toolTipWakeUp.stop();
1917 if (d->toolTipWidget) {
1918 QWidget *w = d->toolTipWidget->window();
1919 // show tooltip if WA_AlwaysShowToolTips is set, or if
1920 // any ancestor of d->toolTipWidget is the active
1921 // window
1922 bool showToolTip = w->testAttribute(Qt::WA_AlwaysShowToolTips);
1923 while (w && !showToolTip) {
1924 showToolTip = w->isActiveWindow();
1925 w = w->parentWidget();
1926 w = w ? w->window() : 0;
1927 }
1928 if (showToolTip) {
1929 QHelpEvent e(QEvent::ToolTip, d->toolTipPos, d->toolTipGlobalPos);
1930 QCoreApplication::sendEvent(d->toolTipWidget, &e);
1931 if (e.isAccepted()) {
1932 QStyle *s = d->toolTipWidget->style();
1933 int sleepDelay = s->styleHint(QStyle::SH_ToolTip_FallAsleepDelay, 0, d->toolTipWidget, 0);
1934 d->toolTipFallAsleep.start(sleepDelay, this);
1935 }
1936 }
1937 }
1938 } else if (te->timerId() == d->toolTipFallAsleep.timerId()) {
1939 d->toolTipFallAsleep.stop();
1940 }
1941#if QT_CONFIG(whatsthis)
1942 } else if (e->type() == QEvent::EnterWhatsThisMode) {
1943 QWhatsThis::enterWhatsThisMode();
1944 return true;
1945#endif
1946 }
1947
1948 if(e->type() == QEvent::LanguageChange) {
1949 const QWidgetList list = topLevelWidgets();
1950 for (auto *w : list) {
1951 if (!(w->windowType() == Qt::Desktop))
1952 postEvent(w, new QEvent(QEvent::LanguageChange));
1953 }
1954 }
1955
1956 return QGuiApplication::event(e);
1957}
1958
1959/*!
1960 \fn void QApplication::syncX()
1961 Was used to synchronize with the X server in 4.x, here for source compatibility.
1962 \internal
1963 \obsolete
1964*/
1965
1966// ### FIXME: topLevelWindows does not contain QWidgets without a parent
1967// until QWidgetPrivate::create is called. So we have to override the
1968// QGuiApplication::notifyLayoutDirectionChange
1969// to do the right thing.
1970void QApplicationPrivate::notifyLayoutDirectionChange()
1971{
1972 const QWidgetList list = QApplication::topLevelWidgets();
1973 QWindowList windowList = QGuiApplication::topLevelWindows();
1974
1975 // send to all top-level QWidgets
1976 for (auto *w : list) {
1977 windowList.removeAll(w->windowHandle());
1978 QEvent ev(QEvent::ApplicationLayoutDirectionChange);
1979 QCoreApplication::sendEvent(w, &ev);
1980 }
1981
1982 // in case there are any plain QWindows in this QApplication-using
1983 // application, also send the notification to them
1984 for (int i = 0; i < windowList.size(); ++i) {
1985 QEvent ev(QEvent::ApplicationLayoutDirectionChange);
1986 QCoreApplication::sendEvent(windowList.at(i), &ev);
1987 }
1988}
1989
1990/*!
1991 \fn void QApplication::setActiveWindow(QWidget* active)
1992
1993 Sets the active window to the \a active widget in response to a system
1994 event. The function is called from the platform specific event handlers.
1995
1996 \warning This function does \e not set the keyboard focus to the active
1997 widget. Call QWidget::activateWindow() instead.
1998
1999 It sets the activeWindow() and focusWidget() attributes and sends proper
2000 \l{QEvent::WindowActivate}{WindowActivate}/\l{QEvent::WindowDeactivate}
2001 {WindowDeactivate} and \l{QEvent::FocusIn}{FocusIn}/\l{QEvent::FocusOut}
2002 {FocusOut} events to all appropriate widgets. The window will then be
2003 painted in active state (e.g. cursors in line edits will blink), and it
2004 will have tool tips enabled.
2005
2006 \sa activeWindow(), QWidget::activateWindow()
2007*/
2008void QApplication::setActiveWindow(QWidget* act)
2009{
2010 QWidget* window = act?act->window():0;
2011
2012 if (QApplicationPrivate::active_window == window)
2013 return;
2014
2015#if QT_CONFIG(graphicsview)
2016 if (window && window->graphicsProxyWidget()) {
2017 // Activate the proxy's view->viewport() ?
2018 return;
2019 }
2020#endif
2021
2022 QWidgetList toBeActivated;
2023 QWidgetList toBeDeactivated;
2024
2025 if (QApplicationPrivate::active_window) {
2026 if (style()->styleHint(QStyle::SH_Widget_ShareActivation, 0, QApplicationPrivate::active_window)) {
2027 const QWidgetList list = topLevelWidgets();
2028 for (auto *w : list) {
2029 if (w->isVisible() && w->isActiveWindow())
2030 toBeDeactivated.append(w);
2031 }
2032 } else {
2033 toBeDeactivated.append(QApplicationPrivate::active_window);
2034 }
2035 }
2036
2037 if (QApplicationPrivate::focus_widget) {
2038 if (QApplicationPrivate::focus_widget->testAttribute(Qt::WA_InputMethodEnabled))
2039 QGuiApplication::inputMethod()->commit();
2040
2041 QFocusEvent focusAboutToChange(QEvent::FocusAboutToChange, Qt::ActiveWindowFocusReason);
2042 QCoreApplication::sendEvent(QApplicationPrivate::focus_widget, &focusAboutToChange);
2043 }
2044
2045 QApplicationPrivate::active_window = window;
2046
2047 if (QApplicationPrivate::active_window) {
2048 if (style()->styleHint(QStyle::SH_Widget_ShareActivation, 0, QApplicationPrivate::active_window)) {
2049 const QWidgetList list = topLevelWidgets();
2050 for (auto *w : list) {
2051 if (w->isVisible() && w->isActiveWindow())
2052 toBeActivated.append(w);
2053 }
2054 } else {
2055 toBeActivated.append(QApplicationPrivate::active_window);
2056 }
2057
2058 }
2059
2060 // first the activation/deactivation events
2061 QEvent activationChange(QEvent::ActivationChange);
2062 QEvent windowActivate(QEvent::WindowActivate);
2063 QEvent windowDeactivate(QEvent::WindowDeactivate);
2064
2065 for (int i = 0; i < toBeActivated.size(); ++i) {
2066 QWidget *w = toBeActivated.at(i);
2067 sendSpontaneousEvent(w, &windowActivate);
2068 sendSpontaneousEvent(w, &activationChange);
2069 }
2070
2071 for(int i = 0; i < toBeDeactivated.size(); ++i) {
2072 QWidget *w = toBeDeactivated.at(i);
2073 sendSpontaneousEvent(w, &windowDeactivate);
2074 sendSpontaneousEvent(w, &activationChange);
2075 }
2076
2077 if (QApplicationPrivate::popupWidgets == 0) { // !inPopupMode()
2078 // then focus events
2079 if (!QApplicationPrivate::active_window && QApplicationPrivate::focus_widget) {
2080 QApplicationPrivate::setFocusWidget(0, Qt::ActiveWindowFocusReason);
2081 } else if (QApplicationPrivate::active_window) {
2082 QWidget *w = QApplicationPrivate::active_window->focusWidget();
2083 if (w && w->isVisible() /*&& w->focusPolicy() != QWidget::NoFocus*/)
2084 w->setFocus(Qt::ActiveWindowFocusReason);
2085 else {
2086 w = QApplicationPrivate::focusNextPrevChild_helper(QApplicationPrivate::active_window, true);
2087 if (w) {
2088 w->setFocus(Qt::ActiveWindowFocusReason);
2089 } else {
2090 // If the focus widget is not in the activate_window, clear the focus
2091 w = QApplicationPrivate::focus_widget;
2092 if (!w && QApplicationPrivate::active_window->focusPolicy() != Qt::NoFocus)
2093 QApplicationPrivate::setFocusWidget(QApplicationPrivate::active_window, Qt::ActiveWindowFocusReason);
2094 else if (!QApplicationPrivate::active_window->isAncestorOf(w))
2095 QApplicationPrivate::setFocusWidget(0, Qt::ActiveWindowFocusReason);
2096 }
2097 }
2098 }
2099 }
2100}
2101
2102QWidget *qt_tlw_for_window(QWindow *wnd)
2103{
2104 // QTBUG-32177, wnd might be a QQuickView embedded via window container.
2105 while (wnd && !wnd->isTopLevel()) {
2106 QWindow *parent = wnd->parent();
2107 if (!parent)
2108 break;
2109
2110 // Don't end up in windows not belonging to this application
2111 if (parent->handle() && parent->handle()->isForeignWindow())
2112 break;
2113
2114 wnd = wnd->parent();
2115 }
2116 if (wnd) {
2117 const auto tlws = QApplication::topLevelWidgets();
2118 for (QWidget *tlw : tlws) {
2119 if (tlw->windowHandle() == wnd)
2120 return tlw;
2121 }
2122 }
2123 return 0;
2124}
2125
2126void QApplicationPrivate::notifyActiveWindowChange(QWindow *previous)
2127{
2128 Q_UNUSED(previous);
2129 QWindow *wnd = QGuiApplicationPrivate::focus_window;
2130 if (inPopupMode()) // some delayed focus event to ignore
2131 return;
2132 QWidget *tlw = qt_tlw_for_window(wnd);
2133 QApplication::setActiveWindow(tlw);
2134 // QTBUG-37126, Active X controls may set the focus on native child widgets.
2135 if (wnd && tlw && wnd != tlw->windowHandle()) {
2136 if (QWidgetWindow *widgetWindow = qobject_cast<QWidgetWindow *>(wnd))
2137 if (QWidget *widget = widgetWindow->widget())
2138 if (widget->inherits("QAxHostWidget"))
2139 widget->setFocus(Qt::ActiveWindowFocusReason);
2140 }
2141}
2142
2143/*!internal
2144 * Helper function that returns the new focus widget, but does not set the focus reason.
2145 * Returns \nullptr if a new focus widget could not be found.
2146 * Shared with QGraphicsProxyWidgetPrivate::findFocusChild()
2147*/
2148QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool next,
2149 bool *wrappingOccurred)
2150{
2151 uint focus_flag = qt_tab_all_widgets() ? Qt::TabFocus : Qt::StrongFocus;
2152
2153 QWidget *f = toplevel->focusWidget();
2154 if (!f)
2155 f = toplevel;
2156
2157 QWidget *w = f;
2158 QWidget *test = f->d_func()->focus_next;
2159 bool seenWindow = false;
2160 bool focusWidgetAfterWindow = false;
2161 while (test && test != f) {
2162 if (test->isWindow())
2163 seenWindow = true;
2164
2165 // If the next focus widget has a focus proxy, we need to check to ensure
2166 // that the proxy is in the correct parent-child direction (according to
2167 // \a next). This is to ensure that we can tab in and out of compound widgets
2168 // without getting stuck in a tab-loop between parent and child.
2169 QWidget *focusProxy = test->d_func()->deepestFocusProxy();
2170
2171 if ((test->focusPolicy() & focus_flag) == focus_flag
2172 && !(next && focusProxy && focusProxy->isAncestorOf(test))
2173 && !(!next && focusProxy && test->isAncestorOf(focusProxy))
2174 && test->isVisibleTo(toplevel) && test->isEnabled()
2175 && !(w->windowType() == Qt::SubWindow && !w->isAncestorOf(test))
2176 && (toplevel->windowType() != Qt::SubWindow || toplevel->isAncestorOf(test))) {
2177 w = test;
2178 if (seenWindow)
2179 focusWidgetAfterWindow = true;
2180 if (next)
2181 break;
2182 }
2183 test = test->d_func()->focus_next;
2184 }
2185
2186 if (wrappingOccurred != 0)
2187 *wrappingOccurred = next ? focusWidgetAfterWindow : !focusWidgetAfterWindow;
2188
2189 if (w == f) {
2190 if (qt_in_tab_key_event) {
2191 w->window()->setAttribute(Qt::WA_KeyboardFocusChange);
2192 w->update();
2193 }
2194 return 0;
2195 }
2196 return w;
2197}
2198
2199/*!
2200 \fn void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave, const QPointF &globalPosF)
2201 \internal
2202
2203 Creates the proper Enter/Leave event when widget \a enter is entered and
2204 widget \a leave is left.
2205 */
2206void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave, const QPointF &globalPosF)
2207{
2208#if 0
2209 if (leave) {
2210 QEvent e(QEvent::Leave);
2211 QCoreApplication::sendEvent(leave, & e);
2212 }
2213 if (enter) {
2214 const QPoint windowPos = enter->window()->mapFromGlobal(globalPos);
2215 QEnterEvent e(enter->mapFromGlobal(globalPos), windowPos, globalPos);
2216 QCoreApplication::sendEvent(enter, & e);
2217 }
2218 return;
2219#endif
2220
2221 if ((!enter && !leave) || (enter == leave))
2222 return;
2223#ifdef ALIEN_DEBUG
2224 qDebug() << "QApplicationPrivate::dispatchEnterLeave, ENTER:" << enter << "LEAVE:" << leave;
2225#endif
2226 QWidgetList leaveList;
2227 QWidgetList enterList;
2228
2229 bool sameWindow = leave && enter && leave->window() == enter->window();
2230 if (leave && !sameWindow) {
2231 auto *w = leave;
2232 do {
2233 leaveList.append(w);
2234 } while (!w->isWindow() && (w = w->parentWidget()));
2235 }
2236 if (enter && !sameWindow) {
2237 auto *w = enter;
2238 do {
2239 enterList.append(w);
2240 } while (!w->isWindow() && (w = w->parentWidget()));
2241 }
2242 if (sameWindow) {
2243 int enterDepth = 0;
2244 int leaveDepth = 0;
2245 auto *e = enter;
2246 while (!e->isWindow() && (e = e->parentWidget()))
2247 enterDepth++;
2248 auto *l = leave;
2249 while (!l->isWindow() && (l = l->parentWidget()))
2250 leaveDepth++;
2251 QWidget* wenter = enter;
2252 QWidget* wleave = leave;
2253 while (enterDepth > leaveDepth) {
2254 wenter = wenter->parentWidget();
2255 enterDepth--;
2256 }
2257 while (leaveDepth > enterDepth) {
2258 wleave = wleave->parentWidget();
2259 leaveDepth--;
2260 }
2261 while (!wenter->isWindow() && wenter != wleave) {
2262 wenter = wenter->parentWidget();
2263 wleave = wleave->parentWidget();
2264 }
2265
2266 for (auto *w = leave; w != wleave; w = w->parentWidget())
2267 leaveList.append(w);
2268
2269 for (auto *w = enter; w != wenter; w = w->parentWidget())
2270 enterList.append(w);
2271 }
2272
2273 QEvent leaveEvent(QEvent::Leave);
2274 for (int i = 0; i < leaveList.size(); ++i) {
2275 auto *w = leaveList.at(i);
2276 if (!QApplication::activeModalWidget() || QApplicationPrivate::tryModalHelper(w, 0)) {
2277 QCoreApplication::sendEvent(w, &leaveEvent);
2278 if (w->testAttribute(Qt::WA_Hover) &&
2279 (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == w->window())) {
2280 Q_ASSERT(instance());
2281 QHoverEvent he(QEvent::HoverLeave, QPoint(-1, -1), w->mapFromGlobal(QApplicationPrivate::instance()->hoverGlobalPos),
2282 QGuiApplication::keyboardModifiers());
2283 qApp->d_func()->notify_helper(w, &he);
2284 }
2285 }
2286 }
2287 if (!enterList.isEmpty()) {
2288 // Guard against QGuiApplicationPrivate::lastCursorPosition initialized to qInf(), qInf().
2289 const QPoint globalPos = qIsInf(globalPosF.x())
2290 ? QPoint(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)
2291 : globalPosF.toPoint();
2292 const QPoint windowPos = qAsConst(enterList).back()->window()->mapFromGlobal(globalPos);
2293 for (auto it = enterList.crbegin(), end = enterList.crend(); it != end; ++it) {
2294 auto *w = *it;
2295 if (!QApplication::activeModalWidget() || QApplicationPrivate::tryModalHelper(w, 0)) {
2296 const QPointF localPos = w->mapFromGlobal(globalPos);
2297 QEnterEvent enterEvent(localPos, windowPos, globalPosF);
2298 QCoreApplication::sendEvent(w, &enterEvent);
2299 if (w->testAttribute(Qt::WA_Hover) &&
2300 (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == w->window())) {
2301 QHoverEvent he(QEvent::HoverEnter, localPos, QPoint(-1, -1),
2302 QGuiApplication::keyboardModifiers());
2303 qApp->d_func()->notify_helper(w, &he);
2304 }
2305 }
2306 }
2307 }
2308
2309#ifndef QT_NO_CURSOR
2310 // Update cursor for alien/graphics widgets.
2311
2312 const bool enterOnAlien = (enter && (isAlien(enter) || enter->testAttribute(Qt::WA_DontShowOnScreen)));
2313 // Whenever we leave an alien widget on X11/QPA, we need to reset its nativeParentWidget()'s cursor.
2314 // This is not required on Windows as the cursor is reset on every single mouse move.
2315 QWidget *parentOfLeavingCursor = 0;
2316 for (int i = 0; i < leaveList.size(); ++i) {
2317 auto *w = leaveList.at(i);
2318 if (!isAlien(w))
2319 break;
2320 if (w->testAttribute(Qt::WA_SetCursor)) {
2321 QWidget *parent = w->parentWidget();
2322 while (parent && parent->d_func()->data.in_destructor)
2323 parent = parent->parentWidget();
2324 parentOfLeavingCursor = parent;
2325 //continue looping, we need to find the downest alien widget with a cursor.
2326 // (downest on the screen)
2327 }
2328 }
2329 //check that we will not call qt_x11_enforce_cursor twice with the same native widget
2330 if (parentOfLeavingCursor && (!enterOnAlien
2331 || parentOfLeavingCursor->effectiveWinId() != enter->effectiveWinId())) {
2332#if QT_CONFIG(graphicsview)
2333 if (!parentOfLeavingCursor->window()->graphicsProxyWidget())
2334#endif
2335 {
2336 if (enter == QApplication::desktop()) {
2337 qt_qpa_set_cursor(enter, true);
2338 } else {
2339 qt_qpa_set_cursor(parentOfLeavingCursor, true);
2340 }
2341 }
2342 }
2343 if (enterOnAlien) {
2344 QWidget *cursorWidget = enter;
2345 while (!cursorWidget->isWindow() && !cursorWidget->isEnabled())
2346 cursorWidget = cursorWidget->parentWidget();
2347
2348 if (!cursorWidget)
2349 return;
2350
2351#if QT_CONFIG(graphicsview)
2352 if (cursorWidget->window()->graphicsProxyWidget()) {
2353 QWidgetPrivate::nearestGraphicsProxyWidget(cursorWidget)->setCursor(cursorWidget->cursor());
2354 } else
2355#endif
2356 {
2357 qt_qpa_set_cursor(cursorWidget, true);
2358 }
2359 }
2360#endif
2361}
2362
2363/* exported for the benefit of testing tools */
2364Q_WIDGETS_EXPORT bool qt_tryModalHelper(QWidget *widget, QWidget **rettop)
2365{
2366 return QApplicationPrivate::tryModalHelper(widget, rettop);
2367}
2368
2369/*! \internal
2370 Returns \c true if \a widget is blocked by a modal window.
2371 */
2372bool QApplicationPrivate::isBlockedByModal(QWidget *widget)
2373{
2374 widget = widget->window();
2375 QWindow *window = widget->windowHandle();
2376 return window && self->isWindowBlocked(window);
2377}
2378
2379bool QApplicationPrivate::isWindowBlocked(QWindow *window, QWindow **blockingWindow) const
2380{
2381 QWindow *unused = 0;
2382 if (Q_UNLIKELY(!window)) {
2383 qWarning().nospace() << "window == 0 passed.";
2384 return false;
2385 }
2386 if (!blockingWindow)
2387 blockingWindow = &unused;
2388
2389 if (modalWindowList.isEmpty()) {
2390 *blockingWindow = 0;
2391 return false;
2392 }
2393 QWidget *popupWidget = QApplication::activePopupWidget();
2394 QWindow *popupWindow = popupWidget ? popupWidget->windowHandle() : 0;
2395 if (popupWindow == window || (!popupWindow && QWindowPrivate::get(window)->isPopup())) {
2396 *blockingWindow = 0;
2397 return false;
2398 }
2399
2400 for (int i = 0; i < modalWindowList.count(); ++i) {
2401 QWindow *modalWindow = modalWindowList.at(i);
2402
2403 // A window is not blocked by another modal window if the two are
2404 // the same, or if the window is a child of the modal window.
2405 if (window == modalWindow || modalWindow->isAncestorOf(window, QWindow::IncludeTransients)) {
2406 *blockingWindow = 0;
2407 return false;
2408 }
2409
2410 Qt::WindowModality windowModality = modalWindow->modality();
2411 QWidgetWindow *modalWidgetWindow = qobject_cast<QWidgetWindow *>(modalWindow);
2412 if (windowModality == Qt::NonModal) {
2413 // determine the modality type if it hasn't been set on the
2414 // modalWindow's widget, this normally happens when waiting for a
2415 // native dialog. use WindowModal if we are the child of a group
2416 // leader; otherwise use ApplicationModal.
2417 QWidget *m = modalWidgetWindow ? modalWidgetWindow->widget() : 0;
2418 while (m && !m->testAttribute(Qt::WA_GroupLeader)) {
2419 m = m->parentWidget();
2420 if (m)
2421 m = m->window();
2422 }
2423 windowModality = (m && m->testAttribute(Qt::WA_GroupLeader))
2424 ? Qt::WindowModal
2425 : Qt::ApplicationModal;
2426 }
2427
2428 switch (windowModality) {
2429 case Qt::ApplicationModal:
2430 {
2431 QWidgetWindow *widgetWindow = qobject_cast<QWidgetWindow *>(window);
2432 QWidget *groupLeaderForWidget = widgetWindow ? widgetWindow->widget() : 0;
2433 while (groupLeaderForWidget && !groupLeaderForWidget->testAttribute(Qt::WA_GroupLeader))
2434 groupLeaderForWidget = groupLeaderForWidget->parentWidget();
2435
2436 if (groupLeaderForWidget) {
2437 // if \a widget has WA_GroupLeader, it can only be blocked by ApplicationModal children
2438 QWidget *m = modalWidgetWindow ? modalWidgetWindow->widget() : 0;
2439 while (m && m != groupLeaderForWidget && !m->testAttribute(Qt::WA_GroupLeader))
2440 m = m->parentWidget();
2441 if (m == groupLeaderForWidget) {
2442 *blockingWindow = m->windowHandle();
2443 return true;
2444 }
2445 } else if (modalWindow != window) {
2446 *blockingWindow = modalWindow;
2447 return true;
2448 }
2449 break;
2450 }
2451 case Qt::WindowModal:
2452 {
2453 QWindow *w = window;
2454 do {
2455 QWindow *m = modalWindow;
2456 do {
2457 if (m == w) {
2458 *blockingWindow = m;
2459 return true;
2460 }
2461 QWindow *p = m->parent();
2462 if (!p)
2463 p = m->transientParent();
2464 m = p;
2465 } while (m);
2466 QWindow *p = w->parent();
2467 if (!p)
2468 p = w->transientParent();
2469 w = p;
2470 } while (w);
2471 break;
2472 }
2473 default:
2474 Q_ASSERT_X(false, "QApplication", "internal error, a modal window cannot be modeless");
2475 break;
2476 }
2477 }
2478 *blockingWindow = 0;
2479 return false;
2480}
2481
2482/*!\internal
2483
2484 Called from qapplication_\e{platform}.cpp, returns \c true
2485 if the widget should accept the event.
2486 */
2487bool QApplicationPrivate::tryModalHelper(QWidget *widget, QWidget **rettop)
2488{
2489 QWidget *top = QApplication::activeModalWidget();
2490 if (rettop)
2491 *rettop = top;
2492
2493 // the active popup widget always gets the input event
2494 if (QApplication::activePopupWidget())
2495 return true;
2496
2497 return !isBlockedByModal(widget->window());
2498}
2499
2500bool qt_try_modal(QWidget *widget, QEvent::Type type)
2501{
2502 QWidget * top = 0;
2503
2504 if (QApplicationPrivate::tryModalHelper(widget, &top))
2505 return true;
2506
2507 bool block_event = false;
2508
2509 switch (type) {
2510#if 0
2511 case QEvent::Focus:
2512 if (!static_cast<QWSFocusEvent*>(event)->simpleData.get_focus)
2513 break;
2514 // drop through
2515#endif
2516 case QEvent::MouseButtonPress: // disallow mouse/key events
2517 case QEvent::MouseButtonRelease:
2518 case QEvent::MouseMove:
2519 case QEvent::KeyPress:
2520 case QEvent::KeyRelease:
2521 block_event = true;
2522 break;
2523 default:
2524 break;
2525 }
2526
2527 if (block_event && top && top->parentWidget() == 0)
2528 top->raise();
2529
2530 return !block_event;
2531}
2532
2533bool QApplicationPrivate::modalState()
2534{
2535 return !self->modalWindowList.isEmpty();
2536}
2537
2538/*
2539 \internal
2540*/
2541QWidget *QApplicationPrivate::pickMouseReceiver(QWidget *candidate, const QPoint &windowPos,
2542 QPoint *pos, QEvent::Type type,
2543 Qt::MouseButtons buttons, QWidget *buttonDown,
2544 QWidget *alienWidget)
2545{
2546 Q_ASSERT(candidate);
2547
2548 QWidget *mouseGrabber = QWidget::mouseGrabber();
2549 if (((type == QEvent::MouseMove && buttons) || (type == QEvent::MouseButtonRelease))
2550 && !buttonDown && !mouseGrabber) {
2551 return 0;
2552 }
2553
2554 if (alienWidget && alienWidget->internalWinId())
2555 alienWidget = 0;
2556
2557 QWidget *receiver = candidate;
2558
2559 if (!mouseGrabber)
2560 mouseGrabber = (buttonDown && !isBlockedByModal(buttonDown)) ? buttonDown : alienWidget;
2561
2562 if (mouseGrabber && mouseGrabber != candidate) {
2563 receiver = mouseGrabber;
2564 *pos = receiver->mapFromGlobal(candidate->mapToGlobal(windowPos));
2565#ifdef ALIEN_DEBUG
2566 qDebug() << " ** receiver adjusted to:" << receiver << "pos:" << pos;
2567#endif
2568 }
2569
2570 return receiver;
2571
2572}
2573
2574/*
2575 \internal
2576*/
2577bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event,
2578 QWidget *alienWidget, QWidget *nativeWidget,
2579 QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver,
2580 bool spontaneous, bool onlyDispatchEnterLeave)
2581{
2582 Q_ASSERT(receiver);
2583 Q_ASSERT(event);
2584 Q_ASSERT(nativeWidget);
2585 Q_ASSERT(buttonDown);
2586
2587 if (alienWidget && !isAlien(alienWidget))
2588 alienWidget = 0;
2589
2590 QPointer<QWidget> receiverGuard = receiver;
2591 QPointer<QWidget> nativeGuard = nativeWidget;
2592 QPointer<QWidget> alienGuard = alienWidget;
2593 QPointer<QWidget> activePopupWidget = QApplication::activePopupWidget();
2594
2595 const bool graphicsWidget = nativeWidget->testAttribute(Qt::WA_DontShowOnScreen);
2596
2597 bool widgetUnderMouse = QRectF(receiver->rect()).contains(event->localPos());
2598
2599 // Clear the obsolete leaveAfterRelease value, if mouse button has been released but
2600 // leaveAfterRelease has not been updated.
2601 // This happens e.g. when modal dialog or popup is shown as a response to button click.
2602 if (leaveAfterRelease && !*buttonDown && !event->buttons())
2603 leaveAfterRelease = 0;
2604
2605 if (*buttonDown) {
2606 if (!graphicsWidget) {
2607 // Register the widget that shall receive a leave event
2608 // after the last button is released.
2609 if ((alienWidget || !receiver->internalWinId()) && !leaveAfterRelease && !QWidget::mouseGrabber())
2610 leaveAfterRelease = *buttonDown;
2611 if (event->type() == QEvent::MouseButtonRelease && !event->buttons())
2612 *buttonDown = 0;
2613 }
2614 } else if (lastMouseReceiver && widgetUnderMouse) {
2615 // Dispatch enter/leave if we move:
2616 // 1) from an alien widget to another alien widget or
2617 // from a native widget to an alien widget (first OR case)
2618 // 2) from an alien widget to a native widget (second OR case)
2619 if ((alienWidget && alienWidget != lastMouseReceiver)
2620 || (isAlien(lastMouseReceiver) && !alienWidget)) {
2621 if (activePopupWidget) {
2622 if (!QWidget::mouseGrabber())
2623 dispatchEnterLeave(alienWidget ? alienWidget : nativeWidget, lastMouseReceiver, event->screenPos());
2624 } else {
2625 dispatchEnterLeave(receiver, lastMouseReceiver, event->screenPos());
2626 }
2627
2628 }
2629 }
2630
2631#ifdef ALIEN_DEBUG
2632 qDebug() << "QApplicationPrivate::sendMouseEvent: receiver:" << receiver
2633 << "pos:" << event->pos() << "alien" << alienWidget << "button down"
2634 << *buttonDown << "last" << lastMouseReceiver << "leave after release"
2635 << leaveAfterRelease;
2636#endif
2637
2638 // We need this quard in case someone opens a modal dialog / popup. If that's the case
2639 // leaveAfterRelease is set to null, but we shall not update lastMouseReceiver.
2640 const bool wasLeaveAfterRelease = leaveAfterRelease != 0;
2641 bool result = true;
2642 // This code is used for sending the synthetic enter/leave events for cases where it is needed
2643 // due to other events causing the widget under the mouse to change. However in those cases
2644 // we do not want to send the mouse event associated with this call, so this enables us to
2645 // not send the unneeded mouse event
2646 if (!onlyDispatchEnterLeave) {
2647 if (spontaneous)
2648 result = QApplication::sendSpontaneousEvent(receiver, event);
2649 else
2650 result = QCoreApplication::sendEvent(receiver, event);
2651 }
2652
2653 if (!graphicsWidget && leaveAfterRelease && event->type() == QEvent::MouseButtonRelease
2654 && !event->buttons() && QWidget::mouseGrabber() != leaveAfterRelease) {
2655 // Dispatch enter/leave if:
2656 // 1) the mouse grabber is an alien widget
2657 // 2) the button is released on an alien widget
2658 QWidget *enter = 0;
2659 if (nativeGuard)
2660 enter = alienGuard ? alienWidget : nativeWidget;
2661 else // The receiver is typically deleted on mouse release with drag'n'drop.
2662 enter = QApplication::widgetAt(event->globalPos());
2663 dispatchEnterLeave(enter, leaveAfterRelease, event->screenPos());
2664 leaveAfterRelease = 0;
2665 lastMouseReceiver = enter;
2666 } else if (!wasLeaveAfterRelease) {
2667 if (activePopupWidget) {
2668 if (!QWidget::mouseGrabber())
2669 lastMouseReceiver = alienGuard ? alienWidget : (nativeGuard ? nativeWidget : 0);
2670 } else {
2671 lastMouseReceiver = receiverGuard ? receiver : QApplication::widgetAt(event->globalPos());
2672 }
2673 }
2674
2675 return result;
2676}
2677
2678/*
2679 This function should only be called when the widget changes visibility, i.e.
2680 when the \a widget is shown, hidden or deleted. This function does nothing
2681 if the widget is a top-level or native, i.e. not an alien widget. In that
2682 case enter/leave events are genereated by the underlying windowing system.
2683*/
2684extern QPointer<QWidget> qt_last_mouse_receiver;
2685extern Q_WIDGETS_EXPORT QWidget *qt_button_down;
2686void QApplicationPrivate::sendSyntheticEnterLeave(QWidget *widget)
2687{
2688#ifndef QT_NO_CURSOR
2689 if (!widget || widget->isWindow())
2690 return;
2691 const bool widgetInShow = widget->isVisible() && !widget->data->in_destructor;
2692 if (!widgetInShow && widget != qt_last_mouse_receiver)
2693 return; // Widget was not under the cursor when it was hidden/deleted.
2694
2695 if (widgetInShow && widget->parentWidget()->data->in_show)
2696 return; // Ingore recursive show.
2697
2698 QWidget *mouseGrabber = QWidget::mouseGrabber();
2699 if (mouseGrabber && mouseGrabber != widget)
2700 return; // Someone else has the grab; enter/leave should not occur.
2701
2702 QWidget *tlw = widget->window();
2703 if (tlw->data->in_destructor || tlw->data->is_closing)
2704 return; // Closing down the business.
2705
2706 if (widgetInShow && (!qt_last_mouse_receiver || qt_last_mouse_receiver->window() != tlw))
2707 return; // Mouse cursor not inside the widget's top-level.
2708
2709 const QPoint globalPos(QCursor::pos());
2710 QPoint windowPos = tlw->mapFromGlobal(globalPos);
2711
2712 // Find the current widget under the mouse. If this function was called from
2713 // the widget's destructor, we have to make sure childAt() doesn't take into
2714 // account widgets that are about to be destructed.
2715 QWidget *widgetUnderCursor = tlw->d_func()->childAt_helper(windowPos, widget->data->in_destructor);
2716 if (!widgetUnderCursor)
2717 widgetUnderCursor = tlw;
2718 QPoint pos = widgetUnderCursor->mapFrom(tlw, windowPos);
2719
2720 if (widgetInShow && widgetUnderCursor != widget && !widget->isAncestorOf(widgetUnderCursor))
2721 return; // Mouse cursor not inside the widget or any of its children.
2722
2723 if (widget->data->in_destructor && qt_button_down == widget)
2724 qt_button_down = 0;
2725
2726 // A mouse move is not actually sent, but we utilize the sendMouseEvent() call to send the
2727 // enter/leave events as appropriate
2728 QMouseEvent e(QEvent::MouseMove, pos, windowPos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier);
2729 sendMouseEvent(widgetUnderCursor, &e, widgetUnderCursor, tlw, &qt_button_down, qt_last_mouse_receiver, true, true);
2730#else // !QT_NO_CURSOR
2731 Q_UNUSED(widget);
2732#endif // QT_NO_CURSOR
2733}
2734
2735/*!
2736 Returns the desktop widget (also called the root window).
2737
2738 The desktop may be composed of multiple screens, so it would be incorrect,
2739 for example, to attempt to \e center some widget in the desktop's geometry.
2740 QDesktopWidget has various functions for obtaining useful geometries upon
2741 the desktop, such as QDesktopWidget::screenGeometry() and
2742 QDesktopWidget::availableGeometry().
2743
2744 On X11, it is also possible to draw on the desktop.
2745*/
2746QDesktopWidget *QApplication::desktop()
2747{
2748 CHECK_QAPP_INSTANCE(nullptr)
2749 if (!qt_desktopWidget || // not created yet
2750 !(qt_desktopWidget->windowType() == Qt::Desktop)) { // reparented away
2751 qt_desktopWidget = new QDesktopWidget();
2752 }
2753 return qt_desktopWidget;
2754}
2755
2756/*
2757 Sets the time after which a drag should start to \a ms ms.
2758
2759 \sa startDragTime()
2760*/
2761
2762void QApplication::setStartDragTime(int ms)
2763{
2764 QGuiApplication::styleHints()->setStartDragTime(ms);
2765}
2766
2767/*!
2768 \property QApplication::startDragTime
2769 \brief the time in milliseconds that a mouse button must be held down
2770 before a drag and drop operation will begin
2771
2772 If you support drag and drop in your application, and want to start a drag
2773 and drop operation after the user has held down a mouse button for a
2774 certain amount of time, you should use this property's value as the delay.
2775
2776 Qt also uses this delay internally, e.g. in QTextEdit and QLineEdit, for
2777 starting a drag.
2778
2779 The default value is 500 ms.
2780
2781 \sa startDragDistance(), {Drag and Drop}
2782*/
2783
2784int QApplication::startDragTime()
2785{
2786 return QGuiApplication::styleHints()->startDragTime();
2787}
2788
2789/*
2790 Sets the distance after which a drag should start to \a l pixels.
2791
2792 \sa startDragDistance()
2793*/
2794
2795void QApplication::setStartDragDistance(int l)
2796{
2797 QGuiApplication::styleHints()->setStartDragDistance(l);
2798}
2799
2800/*!
2801 \property QApplication::startDragDistance
2802
2803 If you support drag and drop in your application, and want to start a drag
2804 and drop operation after the user has moved the cursor a certain distance
2805 with a button held down, you should use this property's value as the
2806 minimum distance required.
2807
2808 For example, if the mouse position of the click is stored in \c startPos
2809 and the current position (e.g. in the mouse move event) is \c currentPos,
2810 you can find out if a drag should be started with code like this:
2811
2812 \snippet code/src_gui_kernel_qapplication.cpp 7
2813
2814 Qt uses this value internally, e.g. in QFileDialog.
2815
2816 The default value (if the platform doesn't provide a different default)
2817 is 10 pixels.
2818
2819 \sa startDragTime(), QPoint::manhattanLength(), {Drag and Drop}
2820*/
2821
2822int QApplication::startDragDistance()
2823{
2824 return QGuiApplication::styleHints()->startDragDistance();
2825}
2826
2827/*!
2828 Enters the main event loop and waits until exit() is called, then returns
2829 the value that was set to exit() (which is 0 if exit() is called via
2830 quit()).
2831
2832 It is necessary to call this function to start event handling. The main
2833 event loop receives events from the window system and dispatches these to
2834 the application widgets.
2835
2836 Generally, no user interaction can take place before calling exec(). As a
2837 special case, modal widgets like QMessageBox can be used before calling
2838 exec(), because modal widgets call exec() to start a local event loop.
2839
2840 To make your application perform idle processing, i.e., executing a special
2841 function whenever there are no pending events, use a QTimer with 0 timeout.
2842 More advanced idle processing schemes can be achieved using processEvents().
2843
2844 We recommend that you connect clean-up code to the
2845 \l{QCoreApplication::}{aboutToQuit()} signal, instead of putting it in your
2846 application's \c{main()} function. This is because, on some platforms the
2847 QApplication::exec() call may not return. For example, on the Windows
2848 platform, when the user logs off, the system terminates the process after Qt
2849 closes all top-level windows. Hence, there is \e{no guarantee} that the
2850 application will have time to exit its event loop and execute code at the
2851 end of the \c{main()} function, after the QApplication::exec() call.
2852
2853 \sa quitOnLastWindowClosed, QCoreApplication::quit(), QCoreApplication::exit(),
2854 QCoreApplication::processEvents(), QCoreApplication::exec()
2855*/
2856int QApplication::exec()
2857{
2858 return QGuiApplication::exec();
2859}
2860
2861bool QApplicationPrivate::shouldQuit()
2862{
2863 /* if there is no non-withdrawn primary window left (except
2864 the ones without QuitOnClose), we emit the lastWindowClosed
2865 signal */
2866 QWidgetList list = QApplication::topLevelWidgets();
2867 QWindowList processedWindows;
2868 for (int i = 0; i < list.size(); ++i) {
2869 QWidget *w = list.at(i);
2870 if (QWindow *window = w->windowHandle()) { // Menus, popup widgets may not have a QWindow
2871 processedWindows.push_back(window);
2872 if (w->isVisible() && !w->parentWidget() && w->testAttribute(Qt::WA_QuitOnClose))
2873 return false;
2874 }
2875 }
2876 return QGuiApplicationPrivate::shouldQuitInternal(processedWindows);
2877}
2878
2879static inline void closeAllPopups()
2880{
2881 // Close all popups: In case some popup refuses to close,
2882 // we give up after 1024 attempts (to avoid an infinite loop).
2883 int maxiter = 1024;
2884 QWidget *popup;
2885 while ((popup = QApplication::activePopupWidget()) && maxiter--)
2886 popup->close();
2887}
2888
2889/*! \reimp
2890 */
2891bool QApplication::notify(QObject *receiver, QEvent *e)
2892{
2893 Q_D(QApplication);
2894 // no events are delivered after ~QCoreApplication() has started
2895 if (QApplicationPrivate::is_app_closing)
2896 return true;
2897
2898 if (Q_UNLIKELY(!receiver)) { // serious error
2899 qWarning("QApplication::notify: Unexpected null receiver");
2900 return true;
2901 }
2902
2903#ifndef QT_NO_DEBUG
2904 QCoreApplicationPrivate::checkReceiverThread(receiver);
2905#endif
2906
2907 if (receiver->isWindowType()) {
2908 if (QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(static_cast<QWindow *>(receiver), e))
2909 return true; // Platform plugin ate the event
2910 }
2911
2912 if(e->spontaneous()) {
2913 // Capture the current mouse and keyboard states. Doing so here is
2914 // required in order to support Qt Test synthesized events. Real mouse
2915 // and keyboard state updates from the platform plugin are managed by
2916 // QGuiApplicationPrivate::process(Mouse|Wheel|Key|Touch|Tablet)Event();
2917 // ### FIXME: Qt Test should not call qapp->notify(), but rather route
2918 // the events through the proper QPA interface. This is required to
2919 // properly generate all other events such as enter/leave etc.
2920 switch (e->type()) {
2921 case QEvent::MouseButtonPress:
2922 {
2923 QMouseEvent *me = static_cast<QMouseEvent*>(e);
2924 QApplicationPrivate::modifier_buttons = me->modifiers();
2925 QApplicationPrivate::mouse_buttons |= me->button();
2926 break;
2927 }
2928 case QEvent::MouseButtonDblClick:
2929 {
2930 QMouseEvent *me = static_cast<QMouseEvent*>(e);
2931 QApplicationPrivate::modifier_buttons = me->modifiers();
2932 QApplicationPrivate::mouse_buttons |= me->button();
2933 break;
2934 }
2935 case QEvent::MouseButtonRelease:
2936 {
2937 QMouseEvent *me = static_cast<QMouseEvent*>(e);
2938 QApplicationPrivate::modifier_buttons = me->modifiers();
2939 QApplicationPrivate::mouse_buttons &= ~me->button();
2940 break;
2941 }
2942 case QEvent::KeyPress:
2943 case QEvent::KeyRelease:
2944 case QEvent::MouseMove:
2945#if QT_CONFIG(wheelevent)
2946 case QEvent::Wheel:
2947#endif
2948 case QEvent::TouchBegin:
2949 case QEvent::TouchUpdate:
2950 case QEvent::TouchEnd:
2951#if QT_CONFIG(tabletevent)
2952 case QEvent::TabletMove:
2953 case QEvent::TabletPress:
2954 case QEvent::TabletRelease:
2955#endif
2956 {
2957 QInputEvent *ie = static_cast<QInputEvent*>(e);
2958 QApplicationPrivate::modifier_buttons = ie->modifiers();
2959 break;
2960 }
2961 default:
2962 break;
2963 }
2964 }
2965
2966#ifndef QT_NO_GESTURES
2967 // walk through parents and check for gestures
2968 if (d->gestureManager) {
2969 switch (e->type()) {
2970 case QEvent::Paint:
2971 case QEvent::MetaCall:
2972 case QEvent::DeferredDelete:
2973 case QEvent::DragEnter: case QEvent::DragMove: case QEvent::DragLeave:
2974 case QEvent::Drop: case QEvent::DragResponse:
2975 case QEvent::ChildAdded: case QEvent::ChildPolished:
2976 case QEvent::ChildRemoved:
2977 case QEvent::UpdateRequest:
2978 case QEvent::UpdateLater:
2979 case QEvent::LocaleChange:
2980 case QEvent::Style:
2981 case QEvent::IconDrag:
2982 case QEvent::StyleChange:
2983 case QEvent::GraphicsSceneDragEnter:
2984 case QEvent::GraphicsSceneDragMove:
2985 case QEvent::GraphicsSceneDragLeave:
2986 case QEvent::GraphicsSceneDrop:
2987 case QEvent::DynamicPropertyChange:
2988 case QEvent::NetworkReplyUpdated:
2989 break;
2990 default:
2991 if (d->gestureManager->thread() == QThread::currentThread()) {
2992 if (receiver->isWidgetType()) {
2993 if (d->gestureManager->filterEvent(static_cast<QWidget *>(receiver), e))
2994 return true;
2995 } else {
2996 // a special case for events that go to QGesture objects.
2997 // We pass the object to the gesture manager and it'll figure
2998 // out if it's QGesture or not.
2999 if (d->gestureManager->filterEvent(receiver, e))
3000 return true;
3001 }
3002 }
3003 break;
3004 }
3005 }
3006#endif // QT_NO_GESTURES
3007
3008 switch (e->type()) {
3009 case QEvent::ApplicationDeactivate:
3010 // Close all popups (triggers when switching applications
3011 // by pressing ALT-TAB on Windows, which is not receive as key event.
3012 closeAllPopups();
3013 break;
3014 case QEvent::Wheel: // User input and window activation makes tooltips sleep
3015 case QEvent::ActivationChange:
3016 case QEvent::KeyPress:
3017 case QEvent::KeyRelease:
3018 case QEvent::FocusOut:
3019 case QEvent::FocusIn:
3020 case QEvent::MouseButtonPress:
3021 case QEvent::MouseButtonRelease:
3022 case QEvent::MouseButtonDblClick:
3023 d->toolTipFallAsleep.stop();
3024 Q_FALLTHROUGH();
3025 case QEvent::Leave:
3026 d->toolTipWakeUp.stop();
3027 default:
3028 break;
3029 }
3030
3031 switch (e->type()) {
3032 case QEvent::KeyPress: {
3033 QKeyEvent* keyEvent = static_cast<QKeyEvent*>(e);
3034 const int key = keyEvent->key();
3035 // When a key press is received which is not spontaneous then it needs to
3036 // be manually sent as a shortcut override event to ensure that any
3037 // matching shortcut is triggered first. This enables emulation/playback
3038 // of recorded events to still have the same effect.
3039 if (!e->spontaneous() && receiver->isWidgetType()) {
3040 if (qt_sendShortcutOverrideEvent(qobject_cast<QWidget *>(receiver), keyEvent->timestamp(),
3041 key, keyEvent->modifiers(), keyEvent->text(),
3042 keyEvent->isAutoRepeat(), keyEvent->count()))
3043 return true;
3044 }
3045 qt_in_tab_key_event = (key == Qt::Key_Backtab
3046 || key == Qt::Key_Tab
3047 || key == Qt::Key_Left
3048 || key == Qt::Key_Up
3049 || key == Qt::Key_Right
3050 || key == Qt::Key_Down);
3051 }
3052 default:
3053 break;
3054 }
3055
3056 bool res = false;
3057 if (!receiver->isWidgetType()) {
3058 res = d->notify_helper(receiver, e);
3059 } else switch (e->type()) {
3060 case QEvent::ShortcutOverride:
3061 case QEvent::KeyPress:
3062 case QEvent::KeyRelease:
3063 {
3064 bool isWidget = receiver->isWidgetType();
3065#if QT_CONFIG(graphicsview)
3066 const bool isGraphicsWidget = !isWidget && qobject_cast<QGraphicsWidget *>(receiver);
3067#endif
3068 QKeyEvent* key = static_cast<QKeyEvent*>(e);
3069 bool def = key->isAccepted();
3070 QPointer<QObject> pr = receiver;
3071 while (receiver) {
3072 if (def)
3073 key->accept();
3074 else
3075 key->ignore();
3076 QWidget *w = isWidget ? static_cast<QWidget *>(receiver) : 0;
3077#if QT_CONFIG(graphicsview)
3078 QGraphicsWidget *gw = isGraphicsWidget ? static_cast<QGraphicsWidget *>(receiver) : 0;
3079#endif
3080 res = d->notify_helper(receiver, e);
3081
3082 if ((res && key->isAccepted())
3083 /*
3084 QLineEdit will emit a signal on Key_Return, but
3085 ignore the event, and sometimes the connected
3086 slot deletes the QLineEdit (common in itemview
3087 delegates), so we have to check if the widget
3088 was destroyed even if the event was ignored (to
3089 prevent a crash)
3090
3091 note that we don't have to reset pw while
3092 propagating (because the original receiver will
3093 be destroyed if one of its ancestors is)
3094 */
3095 || !pr
3096 || (isWidget && (w->isWindow() || !w->parentWidget()))
3097#if QT_CONFIG(graphicsview)
3098 || (isGraphicsWidget && (gw->isWindow() || !gw->parentWidget()))
3099#endif
3100 ) {
3101 break;
3102 }
3103
3104#if QT_CONFIG(graphicsview)
3105 receiver = w ? (QObject *)w->parentWidget() : (QObject *)gw->parentWidget();
3106#else
3107 receiver = w->parentWidget();
3108#endif
3109 }
3110 qt_in_tab_key_event = false;
3111 }
3112 break;
3113 case QEvent::MouseButtonPress:
3114 case QEvent::MouseButtonRelease:
3115 case QEvent::MouseButtonDblClick:
3116 case QEvent::MouseMove:
3117 {
3118 QWidget* w = static_cast<QWidget *>(receiver);
3119
3120 QMouseEvent* mouse = static_cast<QMouseEvent*>(e);
3121 QPoint relpos = mouse->pos();
3122
3123 if (e->spontaneous()) {
3124 if (e->type() != QEvent::MouseMove)
3125 QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, e, relpos);
3126
3127 // ### Qt 5 These dynamic tool tips should be an OPT-IN feature. Some platforms
3128 // like OS X (probably others too), can optimize their views by not
3129 // dispatching mouse move events. We have attributes to control hover,
3130 // and mouse tracking, but as long as we are deciding to implement this
3131 // feature without choice of opting-in or out, you ALWAYS have to have
3132 // tracking enabled. Therefore, the other properties give a false sense of
3133 // performance enhancement.
3134 if (e->type() == QEvent::MouseMove && mouse->buttons() == 0
3135 && w->rect().contains(relpos)) { // Outside due to mouse grab?
3136 d->toolTipWidget = w;
3137 d->toolTipPos = relpos;
3138 d->toolTipGlobalPos = mouse->globalPos();
3139 QStyle *s = d->toolTipWidget->style();
3140 int wakeDelay = s->styleHint(QStyle::SH_ToolTip_WakeUpDelay, 0, d->toolTipWidget, 0);
3141 d->toolTipWakeUp.start(d->toolTipFallAsleep.isActive() ? 20 : wakeDelay, this);
3142 }
3143 }
3144
3145 bool eventAccepted = mouse->isAccepted();
3146
3147 QPointer<QWidget> pw = w;
3148 while (w) {
3149 QMouseEvent me(mouse->type(), relpos, mouse->windowPos(), mouse->globalPos(),
3150 mouse->button(), mouse->buttons(), mouse->modifiers(), mouse->source());
3151 me.spont = mouse->spontaneous();
3152 me.setTimestamp(mouse->timestamp());
3153 QGuiApplicationPrivate::setMouseEventFlags(&me, mouse->flags());
3154 // throw away any mouse-tracking-only mouse events
3155 if (!w->hasMouseTracking()
3156 && mouse->type() == QEvent::MouseMove && mouse->buttons() == 0) {
3157 // but still send them through all application event filters (normally done by notify_helper)
3158 d->sendThroughApplicationEventFilters(w, w == receiver ? mouse : &me);
3159 res = true;
3160 } else {
3161 w->setAttribute(Qt::WA_NoMouseReplay, false);
3162 res = d->notify_helper(w, w == receiver ? mouse : &me);
3163 e->spont = false;
3164 }
3165 eventAccepted = (w == receiver ? mouse : &me)->isAccepted();
3166 if (res && eventAccepted)
3167 break;
3168 if (w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation))
3169 break;
3170 relpos += w->pos();
3171 w = w->parentWidget();
3172 }
3173
3174 mouse->setAccepted(eventAccepted);
3175
3176 if (e->type() == QEvent::MouseMove) {
3177 if (!pw)
3178 break;
3179
3180 w = static_cast<QWidget *>(receiver);
3181 relpos = mouse->pos();
3182 QPoint diff = relpos - w->mapFromGlobal(d->hoverGlobalPos);
3183 while (w) {
3184 if (w->testAttribute(Qt::WA_Hover) &&
3185 (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == w->window())) {
3186 QHoverEvent he(QEvent::HoverMove, relpos, relpos - diff, mouse->modifiers());
3187 d->notify_helper(w, &he);
3188 }
3189 if (w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation))
3190 break;
3191 relpos += w->pos();
3192 w = w->parentWidget();
3193 }
3194 }
3195
3196 d->hoverGlobalPos = mouse->globalPos();
3197 }
3198 break;
3199#if QT_CONFIG(wheelevent)
3200 case QEvent::Wheel:
3201 {
3202 QWidget* w = static_cast<QWidget *>(receiver);
3203
3204 // QTBUG-40656, QTBUG-42731: ignore wheel events when a popup (QComboBox) is open.
3205 if (const QWidget *popup = QApplication::activePopupWidget()) {
3206 if (w->window() != popup)
3207 return true;
3208 }
3209
3210 QWheelEvent* wheel = static_cast<QWheelEvent*>(e);
3211 const bool spontaneous = wheel->spontaneous();
3212 const Qt::ScrollPhase phase = wheel->phase();
3213
3214 // Ideally, we should lock on a widget when it starts receiving wheel
3215 // events. This avoids other widgets to start receiving those events
3216 // as the mouse cursor hovers them. However, given the way common
3217 // wheeled mice work, there's no certain way of connecting different
3218 // wheel events as a stream. This results in the NoScrollPhase case,
3219 // where we just send the event from the original receiver and up its
3220 // hierarchy until the event gets accepted.
3221 //
3222 // In the case of more evolved input devices, like Apple's trackpad or
3223 // Magic Mouse, we receive the scroll phase information. This helps us
3224 // connect wheel events as a stream and therefore makes it easier to
3225 // lock on the widget onto which the scrolling was initiated.
3226 //
3227 // We assume that, when supported, the phase cycle follows the pattern:
3228 //
3229 // ScrollBegin (ScrollUpdate* ScrollEnd)+
3230 //
3231 // This means that we can have scrolling sequences (starting with ScrollBegin)
3232 // or partial sequences (after a ScrollEnd and starting with ScrollUpdate).
3233 // If wheel_widget is null because it was deleted, we also take the same
3234 // code path as an initial sequence.
3235 if (phase == Qt::NoScrollPhase || phase == Qt::ScrollBegin || !QApplicationPrivate::wheel_widget) {
3236
3237 // A system-generated ScrollBegin event starts a new user scrolling
3238 // sequence, so we reset wheel_widget in case no one accepts the event
3239 // or if we didn't get (or missed) a ScrollEnd previously.
3240 if (spontaneous && phase == Qt::ScrollBegin)
3241 QApplicationPrivate::wheel_widget = nullptr;
3242
3243 QPoint relpos = wheel->position().toPoint();
3244
3245 if (spontaneous && (phase == Qt::NoScrollPhase || phase == Qt::ScrollUpdate))
3246 QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, e, relpos);
3247
3248#if QT_DEPRECATED_SINCE(5, 14)
3249 QWheelEvent we(relpos, wheel->globalPos(), wheel->pixelDelta(), wheel->angleDelta(), wheel->delta(), wheel->orientation(), wheel->buttons(),
3250 wheel->modifiers(), phase, wheel->source(), wheel->inverted());
3251#else
3252 QWheelEvent we(relpos, wheel->globalPosition(), wheel->pixelDelta(), wheel->angleDelta(), wheel->buttons(),
3253 wheel->modifiers(), phase, wheel->inverted(), wheel->source());
3254#endif
3255 we.setTimestamp(wheel->timestamp());
3256 bool eventAccepted;
3257 do {
3258 we.spont = spontaneous && w == receiver;
3259 we.ignore();
3260 res = d->notify_helper(w, &we);
3261 eventAccepted = we.isAccepted();
3262 if (res && eventAccepted) {
3263 // A new scrolling sequence or partial sequence starts and w has accepted
3264 // the event. Therefore, we can set wheel_widget, but only if it's not
3265 // the end of a sequence.
3266 if (spontaneous && (phase == Qt::ScrollBegin || phase == Qt::ScrollUpdate))
3267 QApplicationPrivate::wheel_widget = w;
3268 break;
3269 }
3270 if (w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation))
3271 break;
3272
3273 we.p += w->pos();
3274 w = w->parentWidget();
3275 } while (w);
3276 wheel->setAccepted(eventAccepted);
3277 } else if (!spontaneous) {
3278 // wheel_widget may forward the wheel event to a delegate widget,
3279 // either directly or indirectly (e.g. QAbstractScrollArea will
3280 // forward to its QScrollBars through viewportEvent()). In that
3281 // case, the event will not be spontaneous but synthesized, so
3282 // we can send it straight to the receiver.
3283 d->notify_helper(w, wheel);
3284 } else {
3285 // The phase is either ScrollUpdate or ScrollEnd, and wheel_widget
3286 // is set. Since it accepted the wheel event previously, we continue
3287 // sending those events until we get a ScrollEnd, which signifies
3288 // the end of the natural scrolling sequence.
3289 const QPoint &relpos = QApplicationPrivate::wheel_widget->mapFromGlobal(wheel->globalPosition().toPoint());
3290#if QT_DEPRECATED_SINCE(5, 0)
3291 QWheelEvent we(relpos, wheel->globalPos(), wheel->pixelDelta(), wheel->angleDelta(), wheel->delta(), wheel->orientation(), wheel->buttons(),
3292 wheel->modifiers(), wheel->phase(), wheel->source());
3293#else
3294 QWheelEvent we(relpos, wheel->globalPosition(), wheel->pixelDelta(), wheel->angleDelta(), wheel->buttons(),
3295 wheel->modifiers(), wheel->phase(), wheel->inverted(), wheel->source());
3296#endif
3297 we.setTimestamp(wheel->timestamp());
3298 we.spont = true;
3299 we.ignore();
3300 d->notify_helper(QApplicationPrivate::wheel_widget, &we);
3301 wheel->setAccepted(we.isAccepted());
3302 if (phase == Qt::ScrollEnd)
3303 QApplicationPrivate::wheel_widget = nullptr;
3304 }
3305 }
3306 break;
3307#endif
3308#ifndef QT_NO_CONTEXTMENU
3309 case QEvent::ContextMenu:
3310 {
3311 QWidget* w = static_cast<QWidget *>(receiver);
3312 QContextMenuEvent *context = static_cast<QContextMenuEvent*>(e);
3313 QPoint relpos =