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

source code of qtbase/src/widgets/kernel/qapplication.cpp