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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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