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

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