diff options
Diffstat (limited to 'src/widgets/kernel/qapplication.cpp')
-rw-r--r-- | src/widgets/kernel/qapplication.cpp | 463 |
1 files changed, 208 insertions, 255 deletions
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 6ad6004030..de7d93ce20 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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" @@ -84,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> @@ -112,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); @@ -128,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())) { \ @@ -143,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; @@ -331,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 @@ -387,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; @@ -407,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) { @@ -474,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(); @@ -495,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() @@ -507,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 @@ -517,8 +495,11 @@ 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 } @@ -547,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(); } } @@ -558,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()) @@ -718,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); @@ -735,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) @@ -804,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; } /*! @@ -1213,7 +1210,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 @@ -1663,7 +1660,8 @@ 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. @@ -1683,7 +1681,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(); @@ -1693,8 +1691,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()) { @@ -1723,15 +1723,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 @@ -1740,6 +1741,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); @@ -1771,6 +1776,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. @@ -1787,8 +1793,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) @@ -1805,8 +1818,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); @@ -1827,8 +1840,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); @@ -1846,14 +1859,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() @@ -1908,7 +1921,6 @@ QWidget *qt_tlw_for_window(QWindow *wnd) void QApplicationPrivate::notifyActiveWindowChange(QWindow *previous) { - Q_UNUSED(previous); #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 @@ -1917,7 +1929,7 @@ void QApplicationPrivate::notifyActiveWindowChange(QWindow *previous) #endif QWindow *focusWindow = QGuiApplicationPrivate::focus_window; QWidget *focusWidget = qt_tlw_for_window(focusWindow); - QApplication::setActiveWindow(focusWidget); + QApplicationPrivate::setActiveWindow(focusWidget); // QTBUG-37126, Active X controls may set the focus on native child widgets. if (focusWindow && focusWidget && focusWindow != focusWidget->windowHandle()) { if (QWidgetWindow *widgetWindow = qobject_cast<QWidgetWindow *>(focusWindow)) @@ -1925,6 +1937,20 @@ void QApplicationPrivate::notifyActiveWindowChange(QWindow *previous) 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 } @@ -1943,7 +1969,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) { @@ -1955,7 +1981,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)) @@ -1971,7 +2000,7 @@ QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool if (next) break; } - test = test->d_func()->focus_next; + test = test->nextInFocusChain(); } if (wrappingOccurred != nullptr) @@ -1996,24 +2025,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; @@ -2069,7 +2083,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); } @@ -2077,20 +2091,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); } } @@ -2167,80 +2182,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(); - if (windowModality == Qt::NonModal) { - // If modality type hasn't been set on the modalWindow's widget, as - // when waiting for a native dialog, use ApplicationModal. - windowModality = Qt::ApplicationModal; - } - - switch (windowModality) { - case Qt::ApplicationModal: - 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 @@ -2320,9 +2271,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; @@ -2386,13 +2334,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; @@ -2533,7 +2474,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() @@ -2572,7 +2513,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() @@ -2594,8 +2535,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 @@ -2704,6 +2646,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) Q_FALLTHROUGH(); case QEvent::Leave: d->toolTipWakeUp.stop(); + break; default: break; } @@ -2728,6 +2671,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) || key == Qt::Key_Up || key == Qt::Key_Right || key == Qt::Key_Down); + break; } default: break; @@ -2839,11 +2783,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)) @@ -2944,7 +2889,7 @@ 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); @@ -2988,6 +2933,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) tablet->tangentialPressure(), tablet->rotation(), tablet->z(), tablet->modifiers(), tablet->button(), tablet->buttons()); 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(); @@ -3083,8 +3029,16 @@ bool QApplication::notify(QObject *receiver, QEvent *e) #endif w = qobject_cast<QWidget *>(QDragManager::self()->currentTarget()); - if (!w) - break; + 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 *origReceiver = static_cast<QWidget *>(receiver); @@ -3101,15 +3055,16 @@ bool QApplication::notify(QObject *receiver, QEvent *e) ) QDragManager::self()->setCurrentTarget(nullptr, e->type() == QEvent::Drop); break; -#endif } +#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()) { + if (acceptTouchEvents && e->spontaneous() + && touchEvent->device()->type() != QInputDevice::DeviceType::TouchPad) { const QPoint localPos = touchEvent->points()[0].position().toPoint(); QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, e, localPos); } @@ -3149,15 +3104,16 @@ bool QApplication::notify(QObject *receiver, QEvent *e) w = w->parentWidget(); touchEvent->setTarget(w); for (int i = 0; i < touchEvent->pointCount(); ++i) { - auto &pt = QMutableEventPoint::from(touchEvent->point(i)); - pt.setPosition(pt.position() + offset); + 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); + // 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 @@ -3247,7 +3203,7 @@ 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 break; @@ -3279,11 +3235,6 @@ bool QApplication::notify(QObject *receiver, QEvent *e) res = d->notify_helper(receiver, e); break; } - } else if (receiver->isWindowType()) { - res = d->notify_helper(receiver, e); - // We don't call QGuiApplication::notify here, so we need to duplicate the logic - if (res && e->type() == QEvent::Close) - d->maybeLastWindowClosed(static_cast<QWindow *>(receiver)); } else { res = d->notify_helper(receiver, e); } @@ -3403,7 +3354,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; @@ -3448,7 +3399,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); } @@ -3463,7 +3414,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 @@ -3471,7 +3422,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); @@ -3803,8 +3754,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; @@ -3846,24 +3797,26 @@ 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; // If the widget dispatched the event further (see QGraphicsProxyWidget), then - // there might already be an implicit grabber. Don't override that. + // 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 &mep = QMutableEventPoint::from(touchEvent->point(i)); - if (!mep.target() && mep.isAccepted()) - mep.setTarget(widget); + 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? } @@ -3912,9 +3865,9 @@ bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, const QTouchEv // 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::from(touchPoint).setTarget(target); + QMutableEventPoint::setTarget(touchPoint, target); } else { - target = QMutableEventPoint::from(touchPoint).target(); + target = QMutableEventPoint::target(touchPoint); if (!target) continue; } @@ -4015,7 +3968,7 @@ void QApplicationPrivate::translateTouchCancel(const QPointingDevice *device, ul const QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(device); for (auto &epd : devPriv->activePoints.values()) { const auto &pt = epd.eventPoint; - QObject *target = static_cast<const QMutableEventPoint &>(pt).target(); + QObject *target = QMutableEventPoint::target(pt); if (target && target->isWidgetType()) widgetsNeedingCancel.insert(static_cast<QWidget *>(target)); } @@ -4027,9 +3980,9 @@ void QApplicationPrivate::translateTouchCancel(const QPointingDevice *device, ul } } -void QApplicationPrivate::notifyThemeChanged() +void QApplicationPrivate::handleThemeChanged() { - QGuiApplicationPrivate::notifyThemeChanged(); + QGuiApplicationPrivate::handleThemeChanged(); qt_init_tooltip_palette(); } |