diff options
Diffstat (limited to 'src/widgets/kernel/qapplication.cpp')
-rw-r--r-- | src/widgets/kernel/qapplication.cpp | 1116 |
1 files changed, 507 insertions, 609 deletions
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index c230a71550..a1392e10dc 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -1,48 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWidgets module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qplatformdefs.h" #include "qabstracteventdispatcher.h" #include "qapplication.h" #include "qclipboard.h" #include "qcursor.h" -#include "qdesktopwidget_p.h" #include "qdir.h" #include "qevent.h" #include "qfile.h" @@ -85,14 +48,18 @@ #if QT_CONFIG(whatsthis) #include <QtWidgets/QWhatsThis> #endif +#if QT_CONFIG(accessibility) +#include <QtGui/qaccessible_base.h> +#include "private/qaccessiblewidgetfactory_p.h" +#endif #include "private/qkeymapper_p.h" -#include "private/qaccessiblewidgetfactory_p.h" #include <qthread.h> #include <private/qthread_p.h> #include <QtGui/private/qevent_p.h> +#include <QtGui/private/qeventpoint_p.h> #include <private/qfont_p.h> #if QT_CONFIG(action) #include <private/qaction_p.h> @@ -113,11 +80,13 @@ #include <qtwidgets_tracepoints_p.h> +#ifdef Q_OS_MACOS +#include <QtCore/private/qcore_mac_p.h> +#endif + #include <algorithm> #include <iterator> -//#define ALIEN_DEBUG - static void initResources() { Q_INIT_RESOURCE(qstyle); @@ -129,6 +98,15 @@ static void initResources() QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + +Q_TRACE_PREFIX(qtwidgets, + "#include <qcoreevent.h>" +); +Q_TRACE_METADATA(qtwidgets, "ENUM { AUTO, RANGE User ... MaxUser } QEvent::Type;"); +Q_TRACE_POINT(qtwidgets, QApplication_notify_entry, QObject *receiver, QEvent *event, QEvent::Type type); +Q_TRACE_POINT(qtwidgets, QApplication_notify_exit, bool consumed, bool filtered); + // Helper macro for static functions to check on the existence of the application class. #define CHECK_QAPP_INSTANCE(...) \ if (Q_LIKELY(QCoreApplication::instance())) { \ @@ -144,8 +122,8 @@ QApplicationPrivate *QApplicationPrivate::self = nullptr; bool QApplicationPrivate::autoSipEnabled = true; -QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, int flags) - : QApplicationPrivateBase(argc, argv, flags) +QApplicationPrivate::QApplicationPrivate(int &argc, char **argv) + : QGuiApplicationPrivate(argc, argv) { application_type = QApplicationPrivate::Gui; @@ -220,8 +198,7 @@ void QApplicationPrivate::createEventDispatcher() \li It provides localization of strings that are visible to the user via translate(). - \li It provides some magical objects like the desktop() and the - clipboard(). + \li It provides some magical objects like the clipboard(). \li It knows about the application's windows. You can ask which widget is at a certain position using widgetAt(), get a list of @@ -285,7 +262,6 @@ void QApplicationPrivate::createEventDispatcher() \li Widgets \li allWidgets(), topLevelWidgets(), - desktop(), activePopupWidget(), activeModalWidget(), clipboard(), @@ -334,7 +310,6 @@ QWidget *QApplication::topLevelAt(const QPoint &pos) */ void qt_init_tooltip_palette(); -void qt_cleanup(); QStyle *QApplicationPrivate::app_style = nullptr; // default application style #ifndef QT_NO_STYLE_STYLESHEET @@ -358,7 +333,7 @@ int QApplicationPrivate::enabledAnimations = QPlatformTheme::GeneralUiEffect; bool QApplicationPrivate::widgetCount = false; #ifdef QT_KEYPAD_NAVIGATION Qt::NavigationMode QApplicationPrivate::navigationMode = Qt::NavigationModeKeypadTabOrder; -QWidget *QApplicationPrivate::oldEditFocus = 0; +QWidget *QApplicationPrivate::oldEditFocus = nullptr; #endif inline bool QApplicationPrivate::isAlien(QWidget *widget) @@ -379,7 +354,7 @@ FontHash *qt_app_fonts_hash() { return app_fonts(); } QWidgetList *QApplicationPrivate::popupWidgets = nullptr; // has keyboard input focus -QDesktopWidget *qt_desktopWidget = nullptr; // root window widgets +QWidget *qt_desktopWidget = nullptr; // root window widgets /*! \internal @@ -390,7 +365,7 @@ void QApplicationPrivate::process_cmdline() styleOverride = QString::fromLocal8Bit(qgetenv("QT_STYLE_OVERRIDE")); // process platform-indep command line - if (!qt_is_gui_used || !argc) + if (qt_is_tty_app || !argc) return; int i, j; @@ -410,10 +385,10 @@ void QApplicationPrivate::process_cmdline() // obsolete argument #ifndef QT_NO_STYLE_STYLESHEET } else if (strcmp(arg, "-stylesheet") == 0 && i < argc -1) { - styleSheet = QLatin1String("file:///"); + styleSheet = "file:///"_L1; styleSheet.append(QString::fromLocal8Bit(argv[++i])); } else if (strncmp(arg, "-stylesheet=", 12) == 0) { - styleSheet = QLatin1String("file:///"); + styleSheet = "file:///"_L1; styleSheet.append(QString::fromLocal8Bit(arg + 12)); #endif } else if (qstrcmp(arg, "-widgetcount") == 0) { @@ -423,7 +398,7 @@ void QApplicationPrivate::process_cmdline() } } - if(j < argc) { + if (j < argc) { argv[j] = nullptr; argc = j; } @@ -477,9 +452,9 @@ void QApplicationPrivate::process_cmdline() #ifdef Q_QDOC QApplication::QApplication(int &argc, char **argv) #else -QApplication::QApplication(int &argc, char **argv, int _internal) +QApplication::QApplication(int &argc, char **argv, int) #endif - : QGuiApplication(*new QApplicationPrivate(argc, argv, _internal)) + : QGuiApplication(*new QApplicationPrivate(argc, argv)) { Q_D(QApplication); d->init(); @@ -498,7 +473,7 @@ void QApplicationPrivate::init() initResources(); - qt_is_gui_used = (application_type != QApplicationPrivate::Tty); + qt_is_tty_app = (application_type == QApplicationPrivate::Tty); process_cmdline(); // Must be called before initialize() @@ -510,7 +485,7 @@ void QApplicationPrivate::init() initialize(); eventDispatcher->startingUp(); -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) // factory for accessible interfaces for widgets shipped with Qt QAccessible::installFactory(&qAccessibleFactory); #endif @@ -520,16 +495,17 @@ void QApplicationPrivate::init() void qt_init_tooltip_palette() { #if QT_CONFIG(tooltip) - if (const QPalette *toolTipPalette = QGuiApplicationPrivate::platformTheme()->palette(QPlatformTheme::ToolTipPalette)) - QToolTip::setPalette(*toolTipPalette); + if (const QPalette *toolTipPalette = QGuiApplicationPrivate::platformTheme()->palette(QPlatformTheme::ToolTipPalette)) { + QPalette toolTipPal = *toolTipPalette; + toolTipPal.setResolveMask(0); + QToolTip::setPalette(toolTipPal); + } #endif } extern void qRegisterWidgetsVariant(); /*! - \fn void QApplicationPrivate::initialize() - Initializes the QApplication object, called from the constructors. */ void QApplicationPrivate::initialize() @@ -552,7 +528,9 @@ void QApplicationPrivate::initialize() } else { qWarning("QApplication: invalid style override '%s' passed, ignoring it.\n" "\tAvailable styles: %s", qPrintable(styleOverride), - qPrintable(QStyleFactory::keys().join(QLatin1String(", ")))); + qPrintable(QStyleFactory::keys().join(", "_L1))); + // Clear styleOverride so it is not picked by Qt Quick Controls (QTBUG-100563) + styleOverride.clear(); } } @@ -563,7 +541,7 @@ void QApplicationPrivate::initialize() if (qEnvironmentVariableIntValue("QT_USE_NATIVE_WINDOWS") > 0) QCoreApplication::setAttribute(Qt::AA_NativeWindows); - if (qt_is_gui_used) + if (!qt_is_tty_app) initializeMultitouch(); if (QGuiApplication::desktopSettingsAware()) @@ -723,13 +701,16 @@ QApplication::~QApplication() QApplicationPrivate::app_style = nullptr; #if QT_CONFIG(draganddrop) - if (qt_is_gui_used) + if (!qt_is_tty_app) delete QDragManager::self(); #endif d->cleanupMultitouch(); - qt_cleanup(); + QPixmapCache::clear(); + QColormap::cleanup(); + + QApplicationPrivate::active_window = nullptr; //### this should not be necessary if (QApplicationPrivate::widgetCount) qDebug("Widgets left: %i Max widgets: %i \n", QWidgetPrivate::instanceCounter, QWidgetPrivate::maxInstances); @@ -740,14 +721,6 @@ QApplication::~QApplication() QApplicationPrivate::widgetCount = false; } -void qt_cleanup() -{ - QPixmapCache::clear(); - QColormap::cleanup(); - - QApplicationPrivate::active_window = nullptr; //### this should not be necessary -} - /*! \fn QWidget *QApplication::widgetAt(const QPoint &point) @@ -809,35 +782,54 @@ QWidget *QApplication::widgetAt(const QPoint &p) */ bool QApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventList *postedEvents) { - if ((event->type() == QEvent::UpdateRequest - || event->type() == QEvent::LayoutRequest - || event->type() == QEvent::Resize - || event->type() == QEvent::Move - || event->type() == QEvent::LanguageChange)) { - for (QPostEventList::const_iterator it = postedEvents->constBegin(); it != postedEvents->constEnd(); ++it) { - const QPostEvent &cur = *it; - if (cur.receiver != receiver || cur.event == nullptr || cur.event->type() != event->type()) - continue; - if (cur.event->type() == QEvent::LayoutRequest - || cur.event->type() == QEvent::UpdateRequest) { - ; - } else if (cur.event->type() == QEvent::Resize) { - static_cast<QResizeEvent *>(cur.event)->m_size = - static_cast<const QResizeEvent *>(event)->size(); - } else if (cur.event->type() == QEvent::Move) { - static_cast<QMoveEvent *>(cur.event)->m_pos = - static_cast<const QMoveEvent *>(event)->pos(); - } else if (cur.event->type() == QEvent::LanguageChange) { - ; - } else { - continue; - } - delete event; - return true; + // Only compress the following events: + const QEvent::Type type = event->type(); + switch (type) { + case QEvent::UpdateRequest: + case QEvent::UpdateLater: + case QEvent::LayoutRequest: + case QEvent::Resize: + case QEvent::Move: + case QEvent::LanguageChange: + break; + default: + return QGuiApplication::compressEvent(event, receiver, postedEvents); + } + + for (const auto &postedEvent : std::as_const(*postedEvents)) { + + // Continue, unless a valid event of the same type exists for the same receiver + if (postedEvent.receiver != receiver + || !postedEvent.event + || postedEvent.event->type() != type) { + continue; } - return false; + + // Handle type specific compression + switch (type) { + case QEvent::Resize: + static_cast<QResizeEvent *>(postedEvent.event)->m_size = + static_cast<const QResizeEvent *>(event)->size(); + break; + case QEvent::Move: + static_cast<QMoveEvent *>(postedEvent.event)->m_pos = + static_cast<const QMoveEvent *>(event)->pos(); + break; + case QEvent::UpdateLater: + static_cast<QUpdateLaterEvent *>(postedEvent.event)->m_region += + static_cast<const QUpdateLaterEvent *>(event)->region(); + break; + case QEvent::UpdateRequest: + case QEvent::LanguageChange: + case QEvent::LayoutRequest: + break; + default: + continue; + } + delete event; + return true; } - return QGuiApplication::compressEvent(event, receiver, postedEvents); + return false; } /*! @@ -1102,6 +1094,12 @@ QPalette QApplicationPrivate::basePalette() const if (const QPalette *themePalette = platformTheme() ? platformTheme()->palette() : nullptr) palette = themePalette->resolve(palette); + // This palette now is Qt-generated, so reset the resolve mask. This allows + // QStyle::polish implementations to respect palettes that are user provided, + // by checking if the palette has a brush set for a color that the style might + // otherwise overwrite. + palette.setResolveMask(0); + // Finish off by letting the application style polish the palette. This will // not result in the polished palette becoming a user-set palette, as the // resulting base palette is only used as a fallback, with the resolve mask @@ -1218,7 +1216,7 @@ void QApplicationPrivate::handlePaletteChanged(const char *className) } #if QT_CONFIG(graphicsview) - for (auto scene : qAsConst(scene_list)) + for (auto scene : std::as_const(scene_list)) QCoreApplication::sendEvent(scene, &event); #endif @@ -1275,9 +1273,11 @@ QFont QApplication::font() /*! \overload - Returns the default font for the \a widget. + Returns the default font for the \a widget. If a default font was not + registered for the \a{widget}'s class, it returns the default font of + its nearest registered superclass. - \sa fontMetrics(), QWidget::setFont() + \sa fontMetrics(), setFont(), QWidget::setFont() */ QFont QApplication::font(const QWidget *widget) @@ -1295,14 +1295,16 @@ QFont QApplication::font(const QWidget *widget) return hash->value(QByteArrayLiteral("QMiniFont")); } #endif - FontHashConstIt it = hash->constFind(widget->metaObject()->className()); + // Return the font for the nearest registered superclass + const QMetaObject *metaObj = widget->metaObject(); + FontHashConstIt it = hash->constFind(metaObj->className()); const FontHashConstIt cend = hash->constEnd(); + while (it == cend && metaObj != &QWidget::staticMetaObject) { + metaObj = metaObj->superClass(); + it = hash->constFind(metaObj->className()); + } if (it != cend) return it.value(); - for (it = hash->constBegin(); it != cend; ++it) { - if (widget->inherits(it.key())) - return it.value(); - } } return font(); } @@ -1516,7 +1518,7 @@ void QApplicationPrivate::setFocusWidget(QWidget *focus, Qt::FocusReason reason) QWidget *prev = focus_widget; focus_widget = focus; - if(focus_widget) + if (focus_widget) focus_widget->d_func()->setFocus_sys(); if (reason != Qt::NoFocusReason) { @@ -1535,7 +1537,7 @@ void QApplicationPrivate::setFocusWidget(QWidget *focus, Qt::FocusReason reason) if (that) QCoreApplication::sendEvent(that->style(), &out); } - if(focus && QApplicationPrivate::focus_widget == focus) { + if (focus && QApplicationPrivate::focus_widget == focus) { QFocusEvent in(QEvent::FocusIn, reason); QPointer<QWidget> that = focus; QCoreApplication::sendEvent(focus, &in); @@ -1562,7 +1564,9 @@ QWidget *QApplication::activeWindow() return QApplicationPrivate::active_window; } +#if QT_DEPRECATED_SINCE(6,0) /*! + \deprecated Use the QFontMetricsF constructor instead. Returns display (screen) font metrics for the application font. \sa font(), setFont(), QWidget::fontMetrics(), QPainter::fontMetrics() @@ -1570,8 +1574,9 @@ QWidget *QApplication::activeWindow() QFontMetrics QApplication::fontMetrics() { - return desktop()->fontMetrics(); + return QApplicationPrivate::desktop()->fontMetrics(); } +#endif bool QApplicationPrivate::tryCloseAllWidgetWindows(QWindowList *processedWindows) { @@ -1661,9 +1666,16 @@ void QApplication::aboutQt() bool QApplication::event(QEvent *e) { Q_D(QApplication); - if (e->type() == QEvent::Quit) { + switch (e->type()) { + case QEvent::Quit: + // FIXME: This logic first tries to close all windows, and then + // checks whether it was successful, but the conditions used in + // closeAllWindows() differ from the verification logic below. + // We should build on the logic in tryCloseAllWidgetWindows(). closeAllWindows(); for (auto *w : topLevelWidgets()) { + if (w->data->is_closing) + continue; if (w->isVisible() && !(w->windowType() == Qt::Desktop) && !(w->windowType() == Qt::Popup) && (!(w->windowType() == Qt::Dialog) || !w->parentWidget()) && !w->testAttribute(Qt::WA_DontShowOnScreen)) { e->ignore(); @@ -1675,7 +1687,7 @@ bool QApplication::event(QEvent *e) // closeAllWindows(). FIXME: Unify all this close magic through closeAllWindows. return QCoreApplication::event(e); #ifndef Q_OS_WIN - } else if (e->type() == QEvent::LocaleChange) { + case QEvent::LocaleChange: { // on Windows the event propagation is taken care by the // WM_SETTINGCHANGE event handler. const QWidgetList list = topLevelWidgets(); @@ -1685,8 +1697,10 @@ bool QApplication::event(QEvent *e) w->d_func()->setLocale_helper(QLocale(), true); } } + break; + } #endif - } else if (e->type() == QEvent::Timer) { + case QEvent::Timer: { QTimerEvent *te = static_cast<QTimerEvent*>(e); Q_ASSERT(te != nullptr); if (te->timerId() == d->toolTipWakeUp.timerId()) { @@ -1715,15 +1729,16 @@ bool QApplication::event(QEvent *e) } else if (te->timerId() == d->toolTipFallAsleep.timerId()) { d->toolTipFallAsleep.stop(); } + break; + } #if QT_CONFIG(whatsthis) - } else if (e->type() == QEvent::EnterWhatsThisMode) { + case QEvent::EnterWhatsThisMode: QWhatsThis::enterWhatsThisMode(); return true; #endif - } - - if (e->type() == QEvent::LanguageChange || e->type() == QEvent::ApplicationFontChange || - e->type() == QEvent::ApplicationPaletteChange) { + case QEvent::LanguageChange: + case QEvent::ApplicationFontChange: + case QEvent::ApplicationPaletteChange: { // QGuiApplication::event does not account for the cases where // there is a top level widget without a window handle. So they // need to have the event posted here @@ -1732,6 +1747,10 @@ bool QApplication::event(QEvent *e) if (!w->windowHandle() && (w->windowType() != Qt::Desktop)) postEvent(w, new QEvent(e->type())); } + break; + } + default: + break; } return QGuiApplication::event(e); @@ -1763,6 +1782,7 @@ void QApplicationPrivate::notifyLayoutDirectionChange() /*! \fn void QApplication::setActiveWindow(QWidget* active) + \deprecated [6.5] Use QWidget::activateWindow() instead. Sets the active window to the \a active widget in response to a system event. The function is called from the platform specific event handlers. @@ -1779,8 +1799,15 @@ void QApplicationPrivate::notifyLayoutDirectionChange() \sa activeWindow(), QWidget::activateWindow() */ +#if QT_DEPRECATED_SINCE(6,5) void QApplication::setActiveWindow(QWidget* act) { + QApplicationPrivate::setActiveWindow(act); +} +#endif + +void QApplicationPrivate::setActiveWindow(QWidget* act) +{ QWidget* window = act?act->window():nullptr; if (QApplicationPrivate::active_window == window) @@ -1797,8 +1824,8 @@ void QApplication::setActiveWindow(QWidget* act) QWidgetList toBeDeactivated; if (QApplicationPrivate::active_window) { - if (style()->styleHint(QStyle::SH_Widget_ShareActivation, nullptr, QApplicationPrivate::active_window)) { - const QWidgetList list = topLevelWidgets(); + if (QApplication::style()->styleHint(QStyle::SH_Widget_ShareActivation, nullptr, QApplicationPrivate::active_window)) { + const QWidgetList list = QApplication::topLevelWidgets(); for (auto *w : list) { if (w->isVisible() && w->isActiveWindow()) toBeDeactivated.append(w); @@ -1819,8 +1846,8 @@ void QApplication::setActiveWindow(QWidget* act) QApplicationPrivate::active_window = window; if (QApplicationPrivate::active_window) { - if (style()->styleHint(QStyle::SH_Widget_ShareActivation, nullptr, QApplicationPrivate::active_window)) { - const QWidgetList list = topLevelWidgets(); + if (QApplication::style()->styleHint(QStyle::SH_Widget_ShareActivation, nullptr, QApplicationPrivate::active_window)) { + const QWidgetList list = QApplication::topLevelWidgets(); for (auto *w : list) { if (w->isVisible() && w->isActiveWindow()) toBeActivated.append(w); @@ -1838,14 +1865,14 @@ void QApplication::setActiveWindow(QWidget* act) for (int i = 0; i < toBeActivated.size(); ++i) { QWidget *w = toBeActivated.at(i); - sendSpontaneousEvent(w, &windowActivate); - sendSpontaneousEvent(w, &activationChange); + QApplication::sendSpontaneousEvent(w, &windowActivate); + QApplication::sendSpontaneousEvent(w, &activationChange); } for(int i = 0; i < toBeDeactivated.size(); ++i) { QWidget *w = toBeDeactivated.at(i); - sendSpontaneousEvent(w, &windowDeactivate); - sendSpontaneousEvent(w, &activationChange); + QApplication::sendSpontaneousEvent(w, &windowDeactivate); + QApplication::sendSpontaneousEvent(w, &activationChange); } if (QApplicationPrivate::popupWidgets == nullptr) { // !inPopupMode() @@ -1861,12 +1888,13 @@ void QApplication::setActiveWindow(QWidget* act) if (w) { w->setFocus(Qt::ActiveWindowFocusReason); } else { - // If the focus widget is not in the activate_window, clear the focus w = QApplicationPrivate::focus_widget; - if (!w && QApplicationPrivate::active_window->focusPolicy() != Qt::NoFocus) - QApplicationPrivate::setFocusWidget(QApplicationPrivate::active_window, Qt::ActiveWindowFocusReason); - else if (!QApplicationPrivate::active_window->isAncestorOf(w)) + if (!w && QApplicationPrivate::active_window->focusPolicy() != Qt::NoFocus) { + QApplicationPrivate::active_window->setFocus(Qt::ActiveWindowFocusReason); + } else if (!QApplicationPrivate::active_window->isAncestorOf(w)) { + // If the focus widget is not in the activate_window, clear the focus QApplicationPrivate::setFocusWidget(nullptr, Qt::ActiveWindowFocusReason); + } } } } @@ -1899,19 +1927,37 @@ QWidget *qt_tlw_for_window(QWindow *wnd) void QApplicationPrivate::notifyActiveWindowChange(QWindow *previous) { - Q_UNUSED(previous); - QWindow *wnd = QGuiApplicationPrivate::focus_window; - if (inPopupMode()) // some delayed focus event to ignore +#ifndef Q_OS_MACOS + // Some delayed focus event to ignore, unless we are on cocoa where + // popups can be opened via right-click on inactive applications + if (inPopupMode()) return; - QWidget *tlw = qt_tlw_for_window(wnd); - QApplication::setActiveWindow(tlw); +#endif + QWindow *focusWindow = QGuiApplicationPrivate::focus_window; + QWidget *focusWidget = qt_tlw_for_window(focusWindow); + QApplicationPrivate::setActiveWindow(focusWidget); // QTBUG-37126, Active X controls may set the focus on native child widgets. - if (wnd && tlw && wnd != tlw->windowHandle()) { - if (QWidgetWindow *widgetWindow = qobject_cast<QWidgetWindow *>(wnd)) + if (focusWindow && focusWidget && focusWindow != focusWidget->windowHandle()) { + if (QWidgetWindow *widgetWindow = qobject_cast<QWidgetWindow *>(focusWindow)) if (QWidget *widget = widgetWindow->widget()) if (widget->inherits("QAxHostWidget")) widget->setFocus(Qt::ActiveWindowFocusReason); } + + // QApplication::setActiveWindow() will deliver window activation events for + // QWidgetWindows. But for other subclasses of QWindow (like QQuickWindow), we + // need to send them explicitly, like we do from the base class implementation. + if (previous && !qobject_cast<QWidgetWindow *>(previous)) { + QEvent de(QEvent::WindowDeactivate); + QCoreApplication::sendEvent(previous, &de); + } + + if (focusWindow && !qobject_cast<QWidgetWindow *>(focusWindow)) { + QEvent ae(QEvent::WindowActivate); + QCoreApplication::sendEvent(focusWindow, &ae); + } + + // don't call base class to avoid double delivery of WindowActivate/Deactivate events } /*!internal @@ -1929,7 +1975,7 @@ QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool f = toplevel; QWidget *w = f; - QWidget *test = f->d_func()->focus_next; + QWidget *test = f->nextInFocusChain(); bool seenWindow = false; bool focusWidgetAfterWindow = false; while (test && test != f) { @@ -1941,7 +1987,10 @@ QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool // \a next). This is to ensure that we can tab in and out of compound widgets // without getting stuck in a tab-loop between parent and child. QWidget *focusProxy = test->d_func()->deepestFocusProxy(); - const bool canTakeFocus = ((focusProxy ? focusProxy->focusPolicy() : test->focusPolicy()) + auto effectiveFocusPolicy = [](QWidget *widget) { + return widget->isEnabled() ? widget->focusPolicy() : Qt::NoFocus; + }; + const bool canTakeFocus = (effectiveFocusPolicy(focusProxy ? focusProxy : test) & focus_flag) == focus_flag; const bool composites = focusProxy ? (next ? focusProxy->isAncestorOf(test) : test->isAncestorOf(focusProxy)) @@ -1957,7 +2006,7 @@ QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool if (next) break; } - test = test->d_func()->focus_next; + test = test->nextInFocusChain(); } if (wrappingOccurred != nullptr) @@ -1982,24 +2031,9 @@ QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool */ void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave, const QPointF &globalPosF) { -#if 0 - if (leave) { - QEvent e(QEvent::Leave); - QCoreApplication::sendEvent(leave, & e); - } - if (enter) { - const QPoint windowPos = enter->window()->mapFromGlobal(globalPos); - QEnterEvent e(enter->mapFromGlobal(globalPos), windowPos, globalPos); - QCoreApplication::sendEvent(enter, & e); - } - return; -#endif - if ((!enter && !leave) || (enter == leave)) return; -#ifdef ALIEN_DEBUG - qDebug() << "QApplicationPrivate::dispatchEnterLeave, ENTER:" << enter << "LEAVE:" << leave; -#endif + QWidgetList leaveList; QWidgetList enterList; @@ -2055,7 +2089,7 @@ void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave, con if (w->testAttribute(Qt::WA_Hover) && (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == w->window())) { Q_ASSERT(instance()); - QHoverEvent he(QEvent::HoverLeave, QPoint(-1, -1), w->mapFromGlobal(QApplicationPrivate::instance()->hoverGlobalPos), + QHoverEvent he(QEvent::HoverLeave, QPointF(-1, -1), globalPosF, w->mapFromGlobal(globalPosF), QGuiApplication::keyboardModifiers()); qApp->d_func()->notify_helper(w, &he); } @@ -2063,20 +2097,21 @@ void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave, con } if (!enterList.isEmpty()) { // Guard against QGuiApplicationPrivate::lastCursorPosition initialized to qInf(), qInf(). - const QPoint globalPos = qIsInf(globalPosF.x()) - ? QPoint(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX) - : globalPosF.toPoint(); - const QPoint windowPos = qAsConst(enterList).back()->window()->mapFromGlobal(globalPos); + const QPointF globalPos = qIsInf(globalPosF.x()) + ? QPointF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX) + : globalPosF; + const QPointF windowPos = std::as_const(enterList).back()->window()->mapFromGlobal(globalPos); for (auto it = enterList.crbegin(), end = enterList.crend(); it != end; ++it) { auto *w = *it; if (!QApplication::activeModalWidget() || QApplicationPrivate::tryModalHelper(w, nullptr)) { const QPointF localPos = w->mapFromGlobal(globalPos); - QEnterEvent enterEvent(localPos, windowPos, globalPosF); + QEnterEvent enterEvent(localPos, windowPos, globalPos); QCoreApplication::sendEvent(w, &enterEvent); if (w->testAttribute(Qt::WA_Hover) && (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == w->window())) { - QHoverEvent he(QEvent::HoverEnter, localPos, QPoint(-1, -1), + QHoverEvent he(QEvent::HoverEnter, windowPos, QPointF(-1, -1), globalPos, QGuiApplication::keyboardModifiers()); + QMutableEventPoint::setPosition(he.point(0), localPos); qApp->d_func()->notify_helper(w, &he); } } @@ -2110,7 +2145,7 @@ void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave, con if (!parentOfLeavingCursor->window()->graphicsProxyWidget()) #endif { - if (enter == QApplication::desktop()) { + if (enter == QApplicationPrivate::desktop()) { qt_qpa_set_cursor(enter, true); } else { qt_qpa_set_cursor(parentOfLeavingCursor, true); @@ -2153,107 +2188,16 @@ bool QApplicationPrivate::isBlockedByModal(QWidget *widget) return window && self->isWindowBlocked(window); } -bool QApplicationPrivate::isWindowBlocked(QWindow *window, QWindow **blockingWindow) const +Qt::WindowModality QApplicationPrivate::defaultModality() const { - QWindow *unused = nullptr; - if (Q_UNLIKELY(!window)) { - qWarning().nospace() << "window == 0 passed."; - return false; - } - if (!blockingWindow) - blockingWindow = &unused; + return Qt::ApplicationModal; +} - if (modalWindowList.isEmpty()) { - *blockingWindow = nullptr; - return false; - } +bool QApplicationPrivate::windowNeverBlocked(QWindow *window) const +{ QWidget *popupWidget = QApplication::activePopupWidget(); QWindow *popupWindow = popupWidget ? popupWidget->windowHandle() : nullptr; - if (popupWindow == window || (!popupWindow && QWindowPrivate::get(window)->isPopup())) { - *blockingWindow = nullptr; - return false; - } - - for (int i = 0; i < modalWindowList.count(); ++i) { - QWindow *modalWindow = modalWindowList.at(i); - - // A window is not blocked by another modal window if the two are - // the same, or if the window is a child of the modal window. - if (window == modalWindow || modalWindow->isAncestorOf(window, QWindow::IncludeTransients)) { - *blockingWindow = nullptr; - return false; - } - - Qt::WindowModality windowModality = modalWindow->modality(); - QWidgetWindow *modalWidgetWindow = qobject_cast<QWidgetWindow *>(modalWindow); - if (windowModality == Qt::NonModal) { - // determine the modality type if it hasn't been set on the - // modalWindow's widget, this normally happens when waiting for a - // native dialog. use WindowModal if we are the child of a group - // leader; otherwise use ApplicationModal. - QWidget *m = modalWidgetWindow ? modalWidgetWindow->widget() : nullptr; - while (m && !m->testAttribute(Qt::WA_GroupLeader)) { - m = m->parentWidget(); - if (m) - m = m->window(); - } - windowModality = (m && m->testAttribute(Qt::WA_GroupLeader)) - ? Qt::WindowModal - : Qt::ApplicationModal; - } - - switch (windowModality) { - case Qt::ApplicationModal: - { - QWidgetWindow *widgetWindow = qobject_cast<QWidgetWindow *>(window); - QWidget *groupLeaderForWidget = widgetWindow ? widgetWindow->widget() : nullptr; - while (groupLeaderForWidget && !groupLeaderForWidget->testAttribute(Qt::WA_GroupLeader)) - groupLeaderForWidget = groupLeaderForWidget->parentWidget(); - - if (groupLeaderForWidget) { - // if \a widget has WA_GroupLeader, it can only be blocked by ApplicationModal children - QWidget *m = modalWidgetWindow ? modalWidgetWindow->widget() : nullptr; - while (m && m != groupLeaderForWidget && !m->testAttribute(Qt::WA_GroupLeader)) - m = m->parentWidget(); - if (m == groupLeaderForWidget) { - *blockingWindow = m->windowHandle(); - return true; - } - } else if (modalWindow != window) { - *blockingWindow = modalWindow; - return true; - } - break; - } - case Qt::WindowModal: - { - QWindow *w = window; - do { - QWindow *m = modalWindow; - do { - if (m == w) { - *blockingWindow = m; - return true; - } - QWindow *p = m->parent(); - if (!p) - p = m->transientParent(); - m = p; - } while (m); - QWindow *p = w->parent(); - if (!p) - p = w->transientParent(); - w = p; - } while (w); - break; - } - default: - Q_ASSERT_X(false, "QApplication", "internal error, a modal window cannot be modeless"); - break; - } - } - *blockingWindow = nullptr; - return false; + return popupWindow == window || (!popupWindow && QWindowPrivate::get(window)->isPopup()); } /*!\internal @@ -2284,12 +2228,6 @@ bool qt_try_modal(QWidget *widget, QEvent::Type type) bool block_event = false; switch (type) { -#if 0 - case QEvent::Focus: - if (!static_cast<QWSFocusEvent*>(event)->simpleData.get_focus) - break; - // drop through -#endif case QEvent::MouseButtonPress: // disallow mouse/key events case QEvent::MouseButtonRelease: case QEvent::MouseMove: @@ -2339,9 +2277,6 @@ QWidget *QApplicationPrivate::pickMouseReceiver(QWidget *candidate, const QPoint if (mouseGrabber && mouseGrabber != candidate) { receiver = mouseGrabber; *pos = receiver->mapFromGlobal(candidate->mapToGlobal(windowPos)); -#ifdef ALIEN_DEBUG - qDebug() << " ** receiver adjusted to:" << receiver << "pos:" << pos; -#endif } return receiver; @@ -2405,13 +2340,6 @@ bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event, } } -#ifdef ALIEN_DEBUG - qDebug() << "QApplicationPrivate::sendMouseEvent: receiver:" << receiver - << "pos:" << event->position() << "alien" << alienWidget << "button down" - << *buttonDown << "last" << lastMouseReceiver << "leave after release" - << leaveAfterRelease; -#endif - // We need this quard in case someone opens a modal dialog / popup. If that's the case // leaveAfterRelease is set to null, but we shall not update lastMouseReceiver. const bool wasLeaveAfterRelease = leaveAfterRelease != nullptr; @@ -2456,7 +2384,7 @@ bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event, This function should only be called when the widget changes visibility, i.e. when the \a widget is shown, hidden or deleted. This function does nothing if the widget is a top-level or native, i.e. not an alien widget. In that - case enter/leave events are genereated by the underlying windowing system. + case enter/leave events are generated by the underlying windowing system. */ extern QPointer<QWidget> qt_last_mouse_receiver; extern Q_WIDGETS_EXPORT QWidget *qt_button_down; @@ -2470,7 +2398,7 @@ void QApplicationPrivate::sendSyntheticEnterLeave(QWidget *widget) return; // Widget was not under the cursor when it was hidden/deleted. if (widgetInShow && widget->parentWidget()->data->in_show) - return; // Ingore recursive show. + return; // Ignore recursive show. QWidget *mouseGrabber = QWidget::mouseGrabber(); if (mouseGrabber && mouseGrabber != widget) @@ -2512,29 +2440,19 @@ void QApplicationPrivate::sendSyntheticEnterLeave(QWidget *widget) /*! \internal - Returns the desktop widget (also called the root window) for \a screen. - - If \a screen is nullptr, then the widget that represents the entire virtual - desktop is returned, and its geometry will be the union of all screens. - - Use the desktop widget for a specific screen as the parent of a new toplevel - widget to position the widget on a specific screen. + Returns the desktop widget (also called the root window). - The desktop may be composed of multiple screens, so it would be incorrect, - for example, to attempt to \e center some widget in the desktop's geometry. - Use QScreen::geometry() and QScreen::availableGeometry() to get the dimensions - of a specific screen instead. + The widget represents the entire virtual desktop, and its geometry will + be the union of all screens. */ -QWidget *QApplication::desktop(QScreen *screen) +QWidget *QApplicationPrivate::desktop() { CHECK_QAPP_INSTANCE(nullptr) if (!qt_desktopWidget || // not created yet !(qt_desktopWidget->windowType() == Qt::Desktop)) { // reparented away - qt_desktopWidget = new QDesktopWidget(); + qt_desktopWidget = new QWidget(nullptr, Qt::Desktop); } - if (!screen) - return qt_desktopWidget; - return qt_desktopWidget->widgetForScreen(screen); + return qt_desktopWidget; } /* @@ -2562,7 +2480,7 @@ void QApplication::setStartDragTime(int ms) The default value is 500 ms. - \sa startDragDistance(), {Drag and Drop} + \sa startDragDistance(), {Drag and Drop in Qt}{Drag and Drop} */ int QApplication::startDragTime() @@ -2583,6 +2501,7 @@ void QApplication::setStartDragDistance(int l) /*! \property QApplication::startDragDistance + \brief the minimum distance required for a drag and drop operation to start. If you support drag and drop in your application, and want to start a drag and drop operation after the user has moved the cursor a certain distance @@ -2600,7 +2519,7 @@ void QApplication::setStartDragDistance(int l) The default value (if the platform doesn't provide a different default) is 10 pixels. - \sa startDragTime(), QPoint::manhattanLength(), {Drag and Drop} + \sa startDragTime(), QPoint::manhattanLength(), {Drag and Drop in Qt}{Drag and Drop} */ int QApplication::startDragDistance() @@ -2622,8 +2541,9 @@ int QApplication::startDragDistance() exec(), because modal widgets call exec() to start a local event loop. To make your application perform idle processing, i.e., executing a special - function whenever there are no pending events, use a QTimer with 0 timeout. - More advanced idle processing schemes can be achieved using processEvents(). + function whenever there are no pending events, use a QChronoTimer with 0ns + timeout. More advanced idle processing schemes can be achieved using + processEvents(). We recommend that you connect clean-up code to the \l{QCoreApplication::}{aboutToQuit()} signal, instead of putting it in your @@ -2642,34 +2562,6 @@ int QApplication::exec() return QGuiApplication::exec(); } -bool QApplicationPrivate::shouldQuit() -{ - /* if there is no non-withdrawn primary window left (except - the ones without QuitOnClose), we emit the lastWindowClosed - signal */ - QWidgetList list = QApplication::topLevelWidgets(); - QWindowList processedWindows; - for (int i = 0; i < list.size(); ++i) { - QWidget *w = list.at(i); - if (QWindow *window = w->windowHandle()) { // Menus, popup widgets may not have a QWindow - processedWindows.push_back(window); - if (w->isVisible() && !w->parentWidget() && w->testAttribute(Qt::WA_QuitOnClose)) - return false; - } - } - return QGuiApplicationPrivate::shouldQuitInternal(processedWindows); -} - -static inline void closeAllPopups() -{ - // Close all popups: In case some popup refuses to close, - // we give up after 1024 attempts (to avoid an infinite loop). - int maxiter = 1024; - QWidget *popup; - while ((popup = QApplication::activePopupWidget()) && maxiter--) - popup->close(); -} - /*! \reimp */ bool QApplication::notify(QObject *receiver, QEvent *e) @@ -2688,9 +2580,11 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QCoreApplicationPrivate::checkReceiverThread(receiver); #endif - if (receiver->isWindowType()) { - if (QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(static_cast<QWindow *>(receiver), e)) - return true; // Platform plugin ate the event + const bool isWindowType = receiver->isWindowType(); + const bool isWidgetType = receiver->isWidgetType(); + if (isWindowType + && QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(static_cast<QWindow *>(receiver), e)) { + return true; // Platform plugin ate the event } QGuiApplicationPrivate::captureGlobalModifierState(e); @@ -2721,7 +2615,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) break; default: if (d->gestureManager->thread() == QThread::currentThread()) { - if (receiver->isWidgetType()) { + if (isWidgetType) { if (d->gestureManager->filterEvent(static_cast<QWidget *>(receiver), e)) return true; } else { @@ -2739,9 +2633,11 @@ bool QApplication::notify(QObject *receiver, QEvent *e) switch (e->type()) { case QEvent::ApplicationDeactivate: + case QEvent::OrientationChange: // Close all popups (triggers when switching applications // by pressing ALT-TAB on Windows, which is not receive as key event. - closeAllPopups(); + // triggers when the screen rotates.) + d->closeAllPopups(); break; case QEvent::Wheel: // User input and window activation makes tooltips sleep case QEvent::ActivationChange: @@ -2756,99 +2652,80 @@ bool QApplication::notify(QObject *receiver, QEvent *e) Q_FALLTHROUGH(); case QEvent::Leave: d->toolTipWakeUp.stop(); + break; default: break; } switch (e->type()) { - case QEvent::KeyPress: { - QKeyEvent* keyEvent = static_cast<QKeyEvent*>(e); - const int key = keyEvent->key(); - // When a key press is received which is not spontaneous then it needs to - // be manually sent as a shortcut override event to ensure that any - // matching shortcut is triggered first. This enables emulation/playback - // of recorded events to still have the same effect. - if (!e->spontaneous() && receiver->isWidgetType()) { - if (qt_sendShortcutOverrideEvent(qobject_cast<QWidget *>(receiver), keyEvent->timestamp(), - key, keyEvent->modifiers(), keyEvent->text(), - keyEvent->isAutoRepeat(), keyEvent->count())) - return true; - } - qt_in_tab_key_event = (key == Qt::Key_Backtab - || key == Qt::Key_Tab - || key == Qt::Key_Left - || key == Qt::Key_Up - || key == Qt::Key_Right - || key == Qt::Key_Down); + case QEvent::KeyPress: { + QKeyEvent* keyEvent = static_cast<QKeyEvent*>(e); + const int key = keyEvent->key(); + // When a key press is received which is not spontaneous then it needs to + // be manually sent as a shortcut override event to ensure that any + // matching shortcut is triggered first. This enables emulation/playback + // of recorded events to still have the same effect. + if (!e->spontaneous() && isWidgetType + && qt_sendShortcutOverrideEvent(static_cast<QWidget *>(receiver), keyEvent->timestamp(), + key, keyEvent->modifiers(), keyEvent->text(), + keyEvent->isAutoRepeat(), keyEvent->count())) { + return true; } - default: - break; + qt_in_tab_key_event = (key == Qt::Key_Backtab + || key == Qt::Key_Tab + || key == Qt::Key_Left + || key == Qt::Key_Up + || key == Qt::Key_Right + || key == Qt::Key_Down); + break; + } + default: + break; } bool res = false; - if (!receiver->isWidgetType()) { - res = d->notify_helper(receiver, e); - } else switch (e->type()) { - case QEvent::ShortcutOverride: - case QEvent::KeyPress: - case QEvent::KeyRelease: - { - bool isWidget = receiver->isWidgetType(); -#if QT_CONFIG(graphicsview) - const bool isGraphicsWidget = !isWidget && qobject_cast<QGraphicsWidget *>(receiver); -#endif + if (isWidgetType) { + QWidget * w = static_cast<QWidget *>(receiver); + switch (e->type()) { + case QEvent::ShortcutOverride: + case QEvent::KeyPress: + case QEvent::KeyRelease: { QKeyEvent* key = static_cast<QKeyEvent*>(e); bool def = key->isAccepted(); + /* + QLineEdit will emit a signal on Key_Return, but + ignore the event, and sometimes the connected + slot deletes the QLineEdit (common in itemview + delegates), so we have to check if the widget + was destroyed even if the event was ignored (to + prevent a crash) + + Note that we don't have to reset pr while + propagating (because the original receiver will + be destroyed if one of its ancestors is) + */ QPointer<QObject> pr = receiver; - while (receiver) { + while (w) { if (def) key->accept(); else key->ignore(); - QWidget *w = isWidget ? static_cast<QWidget *>(receiver) : nullptr; -#if QT_CONFIG(graphicsview) - QGraphicsWidget *gw = isGraphicsWidget ? static_cast<QGraphicsWidget *>(receiver) : nullptr; -#endif - res = d->notify_helper(receiver, e); - - if ((res && key->isAccepted()) - /* - QLineEdit will emit a signal on Key_Return, but - ignore the event, and sometimes the connected - slot deletes the QLineEdit (common in itemview - delegates), so we have to check if the widget - was destroyed even if the event was ignored (to - prevent a crash) - - note that we don't have to reset pw while - propagating (because the original receiver will - be destroyed if one of its ancestors is) - */ - || !pr - || (isWidget && (w->isWindow() || !w->parentWidget())) -#if QT_CONFIG(graphicsview) - || (isGraphicsWidget && (gw->isWindow() || !gw->parentWidget())) -#endif - ) { + res = d->notify_helper(w, e); + + if (res && key->isAccepted()) + break; + if (!pr || w->isWindow()) break; - } -#if QT_CONFIG(graphicsview) - receiver = w ? (QObject *)w->parentWidget() : (QObject *)gw->parentWidget(); -#else - receiver = w->parentWidget(); -#endif + w = w->parentWidget(); } qt_in_tab_key_event = false; + break; } - break; - case QEvent::MouseButtonPress: - case QEvent::MouseButtonRelease: - case QEvent::MouseButtonDblClick: - case QEvent::MouseMove: - { - QWidget* w = static_cast<QWidget *>(receiver); - + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: { QMouseEvent* mouse = static_cast<QMouseEvent*>(e); QPoint relpos = mouse->position().toPoint(); @@ -2856,8 +2733,8 @@ bool QApplication::notify(QObject *receiver, QEvent *e) if (e->type() != QEvent::MouseMove) QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, e, relpos); - // ### Qt 5 These dynamic tool tips should be an OPT-IN feature. Some platforms - // like OS X (probably others too), can optimize their views by not + // ### Qt 7 These dynamic tool tips should be an OPT-IN feature. Some platforms + // like macOS (probably others too), can optimize their views by not // dispatching mouse move events. We have attributes to control hover, // and mouse tracking, but as long as we are deciding to implement this // feature without choice of opting-in or out, you ALWAYS have to have @@ -2879,8 +2756,9 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QPointer<QWidget> pw = w; while (w) { QMouseEvent me(mouse->type(), relpos, mouse->scenePosition(), mouse->globalPosition().toPoint(), - mouse->button(), mouse->buttons(), mouse->modifiers(), mouse->source()); - me.spont = mouse->spontaneous(); + mouse->button(), mouse->buttons(), mouse->modifiers(), mouse->source(), + mouse->pointingDevice()); + me.m_spont = mouse->spontaneous(); me.setTimestamp(mouse->timestamp()); QMutableSinglePointEvent::from(me).setDoubleClick(QMutableSinglePointEvent::from(mouse)->isDoubleClick()); // throw away any mouse-tracking-only mouse events @@ -2892,7 +2770,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) } else { w->setAttribute(Qt::WA_NoMouseReplay, false); res = d->notify_helper(w, w == receiver ? mouse : &me); - e->spont = false; + e->m_spont = false; } eventAccepted = (w == receiver ? mouse : &me)->isAccepted(); if (res && eventAccepted) @@ -2911,11 +2789,12 @@ bool QApplication::notify(QObject *receiver, QEvent *e) w = static_cast<QWidget *>(receiver); relpos = mouse->position().toPoint(); - QPoint diff = relpos - w->mapFromGlobal(d->hoverGlobalPos); + QPoint diff = relpos - w->mapFromGlobal(mouse->globalPosition().toPoint()); while (w) { if (w->testAttribute(Qt::WA_Hover) && (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == w->window())) { - QHoverEvent he(QEvent::HoverMove, relpos, relpos - diff, mouse->modifiers()); + QHoverEvent he(QEvent::HoverMove, mouse->scenePosition(), mouse->globalPosition(), relpos - diff, mouse->modifiers()); + QMutableEventPoint::setPosition(he.point(0), relpos); d->notify_helper(w, &he); } if (w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation)) @@ -2926,13 +2805,10 @@ bool QApplication::notify(QObject *receiver, QEvent *e) } d->hoverGlobalPos = mouse->globalPosition().toPoint(); + break; } - break; #if QT_CONFIG(wheelevent) - case QEvent::Wheel: - { - QWidget* w = static_cast<QWidget *>(receiver); - + case QEvent::Wheel: { // QTBUG-40656, QTBUG-42731: ignore wheel events when a popup (QComboBox) is open. if (const QWidget *popup = QApplication::activePopupWidget()) { if (w->window() != popup) @@ -2942,9 +2818,9 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QWheelEvent* wheel = static_cast<QWheelEvent*>(e); if (!wheel->spontaneous()) { /* - Synthesized events shouldn't propagate, e.g. QScrollArea passes events from the - viewport on to the scrollbars, which might ignore the event if there is no more - space to scroll. If we would propagate, the event would come back to the viewport. + Synthesized events shouldn't propagate, e.g. QScrollArea passes events from the + viewport on to the scrollbars, which might ignore the event if there is no more + space to scroll. If we would propagate, the event would come back to the viewport. */ res = d->notify_helper(w, wheel); break; @@ -3008,7 +2884,10 @@ bool QApplication::notify(QObject *receiver, QEvent *e) we.setTimestamp(wheel->timestamp()); bool eventAccepted; do { - we.spont = wheel->spontaneous() && w == receiver; + // events are delivered as accepted and ignored by the default event handler + // since we always send the same QWheelEvent object, we need to reset the accepted state + we.setAccepted(true); + we.m_spont = wheel->spontaneous() && w == receiver; res = d->notify_helper(w, &we); eventAccepted = we.isAccepted(); if (res && eventAccepted) @@ -3016,44 +2895,41 @@ bool QApplication::notify(QObject *receiver, QEvent *e) if (w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation)) break; - QMutableSinglePointEvent::from(we).mutablePoint().setPosition(we.position() + w->pos()); + QMutableEventPoint::setPosition(we.point(0), we.position() + w->pos()); w = w->parentWidget(); } while (w); wheel->setAccepted(eventAccepted); + break; } - break; #endif #ifndef QT_NO_CONTEXTMENU - case QEvent::ContextMenu: - { - QWidget* w = static_cast<QWidget *>(receiver); + case QEvent::ContextMenu: { QContextMenuEvent *context = static_cast<QContextMenuEvent*>(e); QPoint relpos = context->pos(); bool eventAccepted = context->isAccepted(); while (w) { QContextMenuEvent ce(context->reason(), relpos, context->globalPos(), context->modifiers()); - ce.spont = e->spontaneous(); + ce.m_spont = e->spontaneous(); res = d->notify_helper(w, w == receiver ? context : &ce); eventAccepted = ((w == receiver) ? context : &ce)->isAccepted(); - e->spont = false; + e->m_spont = false; - if ((res && eventAccepted) - || w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation)) + if (res && eventAccepted) + break; + if (w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation)) break; relpos += w->pos(); w = w->parentWidget(); } context->setAccepted(eventAccepted); + break; } - break; #endif // QT_NO_CONTEXTMENU #if QT_CONFIG(tabletevent) - case QEvent::TabletMove: - case QEvent::TabletPress: - case QEvent::TabletRelease: - { - QWidget *w = static_cast<QWidget *>(receiver); + case QEvent::TabletMove: + case QEvent::TabletPress: + case QEvent::TabletRelease: { QTabletEvent *tablet = static_cast<QTabletEvent*>(e); QPointF relpos = tablet->position(); bool eventAccepted = tablet->isAccepted(); @@ -3062,67 +2938,66 @@ bool QApplication::notify(QObject *receiver, QEvent *e) tablet->pressure(), tablet->xTilt(), tablet->yTilt(), tablet->tangentialPressure(), tablet->rotation(), tablet->z(), tablet->modifiers(), tablet->button(), tablet->buttons()); - te.spont = e->spontaneous(); + te.m_spont = e->spontaneous(); + te.setTimestamp(tablet->timestamp()); te.setAccepted(false); res = d->notify_helper(w, w == receiver ? tablet : &te); eventAccepted = ((w == receiver) ? tablet : &te)->isAccepted(); - e->spont = false; - if ((res && eventAccepted) - || w->isWindow() - || w->testAttribute(Qt::WA_NoMousePropagation)) + e->m_spont = false; + if (res && eventAccepted) + break; + if (w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation)) break; relpos += w->pos(); w = w->parentWidget(); } tablet->setAccepted(eventAccepted); + break; } - break; #endif // QT_CONFIG(tabletevent) #if QT_CONFIG(tooltip) || QT_CONFIG(whatsthis) - case QEvent::ToolTip: - case QEvent::WhatsThis: - case QEvent::QueryWhatsThis: - { - QWidget* w = static_cast<QWidget *>(receiver); + case QEvent::ToolTip: + case QEvent::WhatsThis: + case QEvent::QueryWhatsThis: { QHelpEvent *help = static_cast<QHelpEvent*>(e); QPoint relpos = help->pos(); bool eventAccepted = help->isAccepted(); while (w) { QHelpEvent he(help->type(), relpos, help->globalPos()); - he.spont = e->spontaneous(); + he.m_spont = e->spontaneous(); res = d->notify_helper(w, w == receiver ? help : &he); - e->spont = false; + e->m_spont = false; eventAccepted = (w == receiver ? help : &he)->isAccepted(); - if ((res && eventAccepted) || w->isWindow()) + if (res && eventAccepted) + break; + if (w->isWindow()) break; relpos += w->pos(); w = w->parentWidget(); } help->setAccepted(eventAccepted); + break; } - break; #endif #if QT_CONFIG(statustip) || QT_CONFIG(whatsthis) - case QEvent::StatusTip: - case QEvent::WhatsThisClicked: - { - QWidget *w = static_cast<QWidget *>(receiver); + case QEvent::StatusTip: + case QEvent::WhatsThisClicked: while (w) { res = d->notify_helper(w, e); - if ((res && e->isAccepted()) || w->isWindow()) + if (res && e->isAccepted()) + break; + if (w->isWindow()) break; w = w->parentWidget(); } - } - break; + break; #endif #if QT_CONFIG(draganddrop) - case QEvent::DragEnter: { - QWidget* w = static_cast<QWidget *>(receiver); + case QEvent::DragEnter: { QDragEnterEvent *dragEvent = static_cast<QDragEnterEvent *>(e); #if QT_CONFIG(graphicsview) // QGraphicsProxyWidget handles its own propagation, @@ -3146,12 +3021,11 @@ bool QApplication::notify(QObject *receiver, QEvent *e) dragEvent->m_pos = w->mapToParent(dragEvent->m_pos); w = w->parentWidget(); } + break; } - break; - case QEvent::DragMove: - case QEvent::Drop: - case QEvent::DragLeave: { - QWidget* w = static_cast<QWidget *>(receiver); + case QEvent::DragMove: + case QEvent::Drop: + case QEvent::DragLeave: { #if QT_CONFIG(graphicsview) // QGraphicsProxyWidget handles its own propagation, // and we must not change QDragManagers currentTarget. @@ -3162,14 +3036,21 @@ bool QApplication::notify(QObject *receiver, QEvent *e) w = qobject_cast<QWidget *>(QDragManager::self()->currentTarget()); if (!w) { + // The widget that received DragEnter didn't accept the event, so we have no + // current drag target in the QDragManager. But DragLeave still needs to be + // dispatched so that enter/leave events are in balance (and so that UnderMouse + // gets cleared). + if (e->type() == QEvent::DragLeave) + w = static_cast<QWidget *>(receiver); + else break; } if (e->type() == QEvent::DragMove || e->type() == QEvent::Drop) { QDropEvent *dragEvent = static_cast<QDropEvent *>(e); - QWidget *origReciver = static_cast<QWidget *>(receiver); - while (origReciver && w != origReciver) { - dragEvent->m_pos = origReciver->mapToParent(dragEvent->m_pos); - origReciver = origReciver->parentWidget(); + QWidget *origReceiver = static_cast<QWidget *>(receiver); + while (origReceiver && w != origReceiver) { + dragEvent->m_pos = origReceiver->mapToParent(dragEvent->m_pos); + origReceiver = origReceiver->parentWidget(); } } res = d->notify_helper(w, e); @@ -3179,109 +3060,101 @@ bool QApplication::notify(QObject *receiver, QEvent *e) #endif ) QDragManager::self()->setCurrentTarget(nullptr, e->type() == QEvent::Drop); + break; } - break; -#endif - case QEvent::TouchBegin: - // Note: TouchUpdate and TouchEnd events are never propagated - { - QWidget *widget = static_cast<QWidget *>(receiver); - QMutableTouchEvent *touchEvent = QMutableTouchEvent::from(static_cast<QTouchEvent *>(e)); - bool eventAccepted = touchEvent->isAccepted(); - bool acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents); - - if (acceptTouchEvents && e->spontaneous()) { - const QPoint localPos = touchEvent->points()[0].position().toPoint(); - QApplicationPrivate::giveFocusAccordingToFocusPolicy(widget, e, localPos); - } +#endif // QT_CONFIG(draganddrop) + case QEvent::TouchBegin: { + // Note: TouchUpdate and TouchEnd events are never propagated + QMutableTouchEvent *touchEvent = QMutableTouchEvent::from(static_cast<QTouchEvent *>(e)); + bool eventAccepted = touchEvent->isAccepted(); + bool acceptTouchEvents = w->testAttribute(Qt::WA_AcceptTouchEvents); + + if (acceptTouchEvents && e->spontaneous() + && touchEvent->device()->type() != QInputDevice::DeviceType::TouchPad) { + const QPoint localPos = touchEvent->points()[0].position().toPoint(); + QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, e, localPos); + } #ifndef QT_NO_GESTURES - QPointer<QWidget> gesturePendingWidget; + QPointer<QWidget> gesturePendingWidget; #endif - while (widget) { - // first, try to deliver the touch event - acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents); - touchEvent->setTarget(widget); - touchEvent->setAccepted(acceptTouchEvents); - QPointer<QWidget> p = widget; - res = acceptTouchEvents && d->notify_helper(widget, touchEvent); - eventAccepted = touchEvent->isAccepted(); - if (p.isNull()) { - // widget was deleted - widget = nullptr; - } else { - widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, res && eventAccepted); - } - touchEvent->spont = false; - if (res && eventAccepted) { - // the first widget to accept the TouchBegin gets an implicit grab. - d->activateImplicitTouchGrab(widget, touchEvent); - break; - } + while (w) { + // first, try to deliver the touch event + acceptTouchEvents = w->testAttribute(Qt::WA_AcceptTouchEvents); + touchEvent->setTarget(w); + touchEvent->setAccepted(acceptTouchEvents); + QPointer<QWidget> p = w; + res = acceptTouchEvents && d->notify_helper(w, touchEvent); + eventAccepted = touchEvent->isAccepted(); + if (p.isNull()) { + // widget was deleted + w = nullptr; + } else { + w->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, res && eventAccepted); + } + touchEvent->m_spont = false; + if (res && eventAccepted) { + // the first widget to accept the TouchBegin gets an implicit grab. + d->activateImplicitTouchGrab(w, touchEvent); + break; + } #ifndef QT_NO_GESTURES - if (gesturePendingWidget.isNull() && widget && QGestureManager::gesturePending(widget)) - gesturePendingWidget = widget; + if (gesturePendingWidget.isNull() && w && QGestureManager::gesturePending(w)) + gesturePendingWidget = w; #endif - if (p.isNull() || widget->isWindow() || widget->testAttribute(Qt::WA_NoMousePropagation)) - break; + if (!w || w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation)) + break; - QPoint offset = widget->pos(); - widget = widget->parentWidget(); - touchEvent->setTarget(widget); - for (int i = 0; i < touchEvent->pointCount(); ++i) { - auto &pt = QMutableEventPoint::from(touchEvent->point(i)); - pt.setPosition(pt.position() + offset); + const QPoint offset = w->pos(); + w = w->parentWidget(); + touchEvent->setTarget(w); + for (int i = 0; i < touchEvent->pointCount(); ++i) { + auto &pt = touchEvent->point(i); + QMutableEventPoint::setPosition(pt, pt.position() + offset); + } } - } #ifndef QT_NO_GESTURES - if (!eventAccepted && !gesturePendingWidget.isNull()) { - // the first widget subscribed to a gesture gets an implicit grab - d->activateImplicitTouchGrab(gesturePendingWidget, touchEvent); - } + if (!eventAccepted && !gesturePendingWidget.isNull()) { + // the first widget subscribed to a gesture gets an implicit grab for all + // points, also for events and event points that have not been accepted. + d->activateImplicitTouchGrab(gesturePendingWidget, touchEvent, QApplicationPrivate::GrabAllPoints); + } #endif - touchEvent->setAccepted(eventAccepted); - break; - } - case QEvent::TouchUpdate: - case QEvent::TouchEnd: - { - QWidget *widget = static_cast<QWidget *>(receiver); - // We may get here if the widget is subscribed to a gesture, - // but has not accepted TouchBegin. Propagate touch events - // only if TouchBegin has been accepted. - if (widget->testAttribute(Qt::WA_WState_AcceptedTouchBeginEvent)) - res = d->notify_helper(widget, e); - break; - } - case QEvent::RequestSoftwareInputPanel: - inputMethod()->show(); - break; - case QEvent::CloseSoftwareInputPanel: - inputMethod()->hide(); - break; + touchEvent->setAccepted(eventAccepted); + break; + } + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + // We may get here if the widget is subscribed to a gesture, + // but has not accepted TouchBegin. Propagate touch events + // only if TouchBegin has been accepted. + if (w->testAttribute(Qt::WA_WState_AcceptedTouchBeginEvent)) + res = d->notify_helper(w, e); + break; + case QEvent::RequestSoftwareInputPanel: + inputMethod()->show(); + break; + case QEvent::CloseSoftwareInputPanel: + inputMethod()->hide(); + break; #ifndef QT_NO_GESTURES - case QEvent::NativeGesture: - { - // only propagate the first gesture event (after the GID_BEGIN) - QWidget *w = static_cast<QWidget *>(receiver); - while (w) { - e->ignore(); - res = d->notify_helper(w, e); - if ((res && e->isAccepted()) || w->isWindow()) - break; - w = w->parentWidget(); - } - break; - } - case QEvent::Gesture: - case QEvent::GestureOverride: - { - if (receiver->isWidgetType()) { - QWidget *w = static_cast<QWidget *>(receiver); + case QEvent::NativeGesture: + while (w) { + e->ignore(); + res = d->notify_helper(w, e); + if (res && e->isAccepted()) + break; + if (w->isWindow()) + break; + w = w->parentWidget(); + } + break; + case QEvent::Gesture: + case QEvent::GestureOverride: { QGestureEvent *gestureEvent = static_cast<QGestureEvent *>(e); QList<QGesture *> allGestures = gestureEvent->gestures(); @@ -3298,7 +3171,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) wd->gestureContext.find(type); bool deliver = contextit != wd->gestureContext.end() && (g->state() == Qt::GestureStarted || w == receiver || - (contextit.value() & Qt::ReceivePartialGestures)); + (contextit.value() & Qt::ReceivePartialGestures)); if (deliver) { allGestures.removeAt(i); gestures.append(g); @@ -3309,11 +3182,11 @@ bool QApplication::notify(QObject *receiver, QEvent *e) if (!gestures.isEmpty()) { // we have gestures for this w QGestureEvent ge(gestures); ge.t = gestureEvent->t; - ge.spont = gestureEvent->spont; + ge.m_spont = gestureEvent->spontaneous(); ge.m_accept = wasAccepted; ge.m_accepted = gestureEvent->m_accepted; res = d->notify_helper(w, &ge); - gestureEvent->spont = false; + gestureEvent->m_spont = false; eventAccepted = ge.isAccepted(); for (int i = 0; i < gestures.size(); ++i) { QGesture *g = gestures.at(i); @@ -3336,46 +3209,40 @@ bool QApplication::notify(QObject *receiver, QEvent *e) break; w = w->parentWidget(); } - for (QGesture *g : qAsConst(allGestures)) + for (QGesture *g : std::as_const(allGestures)) gestureEvent->setAccepted(g, false); gestureEvent->m_accept = false; // to make sure we check individual gestures - } else { - res = d->notify_helper(receiver, e); + break; } - break; - } #endif // QT_NO_GESTURES #ifdef Q_OS_MAC - // Enable touch events on enter, disable on leave. - typedef void (*RegisterTouchWindowFn)(QWindow *, bool); - case QEvent::Enter: - if (receiver->isWidgetType()) { - QWidget *w = static_cast<QWidget *>(receiver); + // Enable touch events on enter, disable on leave. + typedef void (*RegisterTouchWindowFn)(QWindow *, bool); + case QEvent::Enter: if (w->testAttribute(Qt::WA_AcceptTouchEvents)) { RegisterTouchWindowFn registerTouchWindow = reinterpret_cast<RegisterTouchWindowFn> (platformNativeInterface()->nativeResourceFunctionForIntegration("registertouchwindow")); if (registerTouchWindow) registerTouchWindow(w->window()->windowHandle(), true); } - } - res = d->notify_helper(receiver, e); - break; - case QEvent::Leave: - if (receiver->isWidgetType()) { - QWidget *w = static_cast<QWidget *>(receiver); + res = d->notify_helper(receiver, e); + break; + case QEvent::Leave: if (w->testAttribute(Qt::WA_AcceptTouchEvents)) { RegisterTouchWindowFn registerTouchWindow = reinterpret_cast<RegisterTouchWindowFn> (platformNativeInterface()->nativeResourceFunctionForIntegration("registertouchwindow")); if (registerTouchWindow) registerTouchWindow(w->window()->windowHandle(), false); } - } - res = d->notify_helper(receiver, e); - break; + res = d->notify_helper(receiver, e); + break; #endif - default: + default: + res = d->notify_helper(receiver, e); + break; + } + } else { res = d->notify_helper(receiver, e); - break; } return res; @@ -3470,6 +3337,17 @@ extern QWidget *qt_popup_down; extern bool qt_replay_popup_mouse_event; extern bool qt_popup_down_closed; +bool QApplicationPrivate::closeAllPopups() +{ + // Close all popups: In case some popup refuses to close, + // we give up after 1024 attempts (to avoid an infinite loop). + int maxiter = 1024; + QWidget *popup; + while ((popup = QApplication::activePopupWidget()) && maxiter--) + popup->close(); // this will call QApplicationPrivate::closePopup + return true; +} + void QApplicationPrivate::closePopup(QWidget *popup) { if (!popupWidgets) @@ -3482,7 +3360,7 @@ void QApplicationPrivate::closePopup(QWidget *popup) qt_popup_down = nullptr; } - if (QApplicationPrivate::popupWidgets->count() == 0) { // this was the last popup + if (QApplicationPrivate::popupWidgets->size() == 0) { // this was the last popup delete QApplicationPrivate::popupWidgets; QApplicationPrivate::popupWidgets = nullptr; qt_popup_down_closed = false; @@ -3527,7 +3405,7 @@ void QApplicationPrivate::closePopup(QWidget *popup) // can become nullptr due to setFocus() above if (QApplicationPrivate::popupWidgets && - QApplicationPrivate::popupWidgets->count() == 1) // grab mouse/keyboard + QApplicationPrivate::popupWidgets->size() == 1) // grab mouse/keyboard grabForPopup(aw); } @@ -3542,7 +3420,7 @@ void QApplicationPrivate::openPopup(QWidget *popup) popupWidgets = new QWidgetList; popupWidgets->append(popup); // add to end of list - if (QApplicationPrivate::popupWidgets->count() == 1) // grab mouse/keyboard + if (QApplicationPrivate::popupWidgets->size() == 1) // grab mouse/keyboard grabForPopup(popup); // popups are not focus-handled by the window system (the first @@ -3550,7 +3428,7 @@ void QApplicationPrivate::openPopup(QWidget *popup) // new popup gets the focus if (popup->focusWidget()) { popup->focusWidget()->setFocus(Qt::PopupFocusReason); - } else if (popupWidgets->count() == 1) { // this was the first popup + } else if (popupWidgets->size() == 1) { // this was the first popup if (QWidget *fw = QApplication::focusWidget()) { QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason); QCoreApplication::sendEvent(fw, &e); @@ -3589,7 +3467,7 @@ Qt::NavigationMode QApplication::navigationMode() \since 4.3 Causes an alert to be shown for \a widget if the window is not the active - window. The alert is shown for \a msec miliseconds. If \a msec is zero (the + window. The alert is shown for \a msec milliseconds. If \a msec is zero (the default), then the alert is shown indefinitely until the window becomes active again. @@ -3882,8 +3760,8 @@ bool QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEven bool containsPress = false; for (int i = 0; i < touchEvent->pointCount(); ++i) { - auto &pt = QMutableEventPoint::from(touchEvent->point(i)); - pt.setPosition(widget->mapFromGlobal(pt.globalPosition())); + auto &pt = touchEvent->point(i); + QMutableEventPoint::setPosition(pt, widget->mapFromGlobal(pt.globalPosition())); if (pt.state() == QEventPoint::State::Pressed) containsPress = true; @@ -3916,8 +3794,8 @@ QWidget *QApplicationPrivate::findClosestTouchPointTarget(const QPointingDevice QObject *closestTarget = nullptr; qreal closestDistance = 0; const QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(device); - for (const auto &pair : devPriv->activePoints) { - const auto &pt = pair.second.eventPoint; + for (auto &epd : devPriv->activePoints.values()) { + const auto &pt = epd.eventPoint; if (pt.id() != touchPoint.id()) { qreal dx = globalPos.x() - pt.globalPosition().x(); qreal dy = globalPos.y() - pt.globalPosition().y(); @@ -3925,33 +3803,39 @@ QWidget *QApplicationPrivate::findClosestTouchPointTarget(const QPointingDevice if (closestTouchPointId == -1 || distance < closestDistance) { closestTouchPointId = pt.id(); closestDistance = distance; - closestTarget = static_cast<const QMutableEventPoint &>(pt).target(); + closestTarget = QMutableEventPoint::target(pt); } } } return static_cast<QWidget *>(closestTarget); } -void QApplicationPrivate::activateImplicitTouchGrab(QWidget *widget, QTouchEvent *touchEvent) +void QApplicationPrivate::activateImplicitTouchGrab(QWidget *widget, QTouchEvent *touchEvent, + ImplicitTouchGrabMode grabMode) { if (touchEvent->type() != QEvent::TouchBegin) return; - for (int i = 0; i < touchEvent->pointCount(); ++i) - QMutableEventPoint::from(touchEvent->point(i)).setTarget(widget); + // If the widget dispatched the event further (see QGraphicsProxyWidget), then + // there might already be an implicit grabber. Don't override that. A widget that + // has partially recognized a gesture needs to grab all points. + for (int i = 0; i < touchEvent->pointCount(); ++i) { + auto &ep = touchEvent->point(i); + if (!QMutableEventPoint::target(ep) && (ep.isAccepted() || grabMode == GrabAllPoints)) + QMutableEventPoint::setTarget(ep, widget); + } // TODO setExclusiveGrabber() to be consistent with Qt Quick? } -bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, - const QPointingDevice *device, - QList<QEventPoint> &touchPoints, - ulong timestamp) +bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, const QTouchEvent *te) { QApplicationPrivate *d = self; // TODO get rid of this QPair typedef QPair<QEventPoint::State, QList<QEventPoint> > StatesAndTouchPoints; QHash<QWidget *, StatesAndTouchPoints> widgetsNeedingEvents; + const auto *device = te->pointingDevice(); + auto touchPoints = te->points(); // touch points will be mutated for (auto &touchPoint : touchPoints) { // update state QPointer<QObject> target; @@ -3973,18 +3857,23 @@ bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, target = window; } + bool usingClosestWidget = false; if (device->type() == QInputDevice::DeviceType::TouchScreen) { QWidget *closestWidget = d->findClosestTouchPointTarget(device, touchPoint); QWidget *widget = static_cast<QWidget *>(target.data()); if (closestWidget && (widget->isAncestorOf(closestWidget) || closestWidget->isAncestorOf(widget))) { target = closestWidget; + usingClosestWidget = true; } } - QMutableEventPoint::from(touchPoint).setTarget(target); + // on touch pads, implicitly grab all touch points + // on touch screens, grab touch points that are redirected to the closest widget + if (device->type() == QInputDevice::DeviceType::TouchPad || usingClosestWidget) + QMutableEventPoint::setTarget(touchPoint, target); } else { - target = QMutableEventPoint::from(touchPoint).target(); + target = QMutableEventPoint::target(touchPoint); if (!target) continue; } @@ -4036,7 +3925,7 @@ bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, QMutableTouchEvent touchEvent(eventType, device, QGuiApplication::keyboardModifiers(), it.value().second); bool containsPress = updateTouchPointsForWidget(widget, &touchEvent); - touchEvent.setTimestamp(timestamp); + touchEvent.setTimestamp(te->timestamp()); touchEvent.setTarget(widget); if (containsPress) @@ -4047,7 +3936,9 @@ bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, { // if the TouchBegin handler recurses, we assume that means the event // has been implicitly accepted and continue to send touch events - if (QApplication::sendSpontaneousEvent(widget, &touchEvent) && touchEvent.isAccepted()) { + bool res = te->spontaneous() ? QApplication::sendSpontaneousEvent(widget, &touchEvent) + : QApplication::sendEvent(widget, &touchEvent); + if (res && touchEvent.isAccepted()) { accepted = true; if (!widget.isNull()) widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent); @@ -4060,7 +3951,9 @@ bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, || QGestureManager::gesturePending(widget) #endif ) { - if (QApplication::sendSpontaneousEvent(widget, &touchEvent) && touchEvent.isAccepted()) + bool res = te->spontaneous() ? QApplication::sendSpontaneousEvent(widget, &touchEvent) + : QApplication::sendEvent(widget, &touchEvent); + if (res && touchEvent.isAccepted()) accepted = true; // widget can be deleted on TouchEnd if (touchEvent.type() == QEvent::TouchEnd && !widget.isNull()) @@ -4079,9 +3972,9 @@ void QApplicationPrivate::translateTouchCancel(const QPointingDevice *device, ul QSet<QWidget *> widgetsNeedingCancel; const QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(device); - for (const auto &pair : devPriv->activePoints) { - const auto &pt = pair.second.eventPoint; - QObject *target = static_cast<const QMutableEventPoint &>(pt).target(); + for (auto &epd : devPriv->activePoints.values()) { + const auto &pt = epd.eventPoint; + QObject *target = QMutableEventPoint::target(pt); if (target && target->isWidgetType()) widgetsNeedingCancel.insert(static_cast<QWidget *>(target)); } @@ -4093,9 +3986,9 @@ void QApplicationPrivate::translateTouchCancel(const QPointingDevice *device, ul } } -void QApplicationPrivate::notifyThemeChanged() +void QApplicationPrivate::handleThemeChanged() { - QGuiApplicationPrivate::notifyThemeChanged(); + QGuiApplicationPrivate::handleThemeChanged(); qt_init_tooltip_palette(); } @@ -4132,6 +4025,11 @@ QPixmap QApplicationPrivate::applyQIconStyleHelper(QIcon::Mode mode, const QPixm return QApplication::style()->generatedIconPixmap(mode, base, &opt); } +void *QApplication::resolveInterface(const char *name, int revision) const +{ + return QGuiApplication::resolveInterface(name, revision); +} + QT_END_NAMESPACE #include "moc_qapplication.cpp" |