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