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