diff options
Diffstat (limited to 'src/widgets/kernel')
-rw-r--r-- | src/widgets/kernel/qapplication.cpp | 80 | ||||
-rw-r--r-- | src/widgets/kernel/qapplication_p.h | 2 | ||||
-rw-r--r-- | src/widgets/kernel/qgesturemanager.cpp | 2 | ||||
-rw-r--r-- | src/widgets/kernel/qmacgesturerecognizer_p.h | 4 | ||||
-rw-r--r-- | src/widgets/kernel/qtooltip.cpp | 3 | ||||
-rw-r--r-- | src/widgets/kernel/qwhatsthis.cpp | 1 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget.cpp | 238 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetrepaintmanager.cpp | 79 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetrepaintmanager_p.h | 4 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetwindow.cpp | 76 |
10 files changed, 232 insertions, 257 deletions
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index a1392e10dc..5e1d792319 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -98,6 +98,8 @@ static void initResources() QT_BEGIN_NAMESPACE +Q_STATIC_LOGGING_CATEGORY(lcWidgetPopup, "qt.widgets.popup"); + using namespace Qt::StringLiterals; Q_TRACE_PREFIX(qtwidgets, @@ -352,8 +354,6 @@ Q_GLOBAL_STATIC(FontHash, app_fonts) // Exported accessor for use outside of this file FontHash *qt_app_fonts_hash() { return app_fonts(); } -QWidgetList *QApplicationPrivate::popupWidgets = nullptr; // has keyboard input focus - QWidget *qt_desktopWidget = nullptr; // root window widgets /*! @@ -627,8 +627,8 @@ void QApplicationPrivate::initializeWidgetFontHash() QWidget *QApplication::activePopupWidget() { - return QApplicationPrivate::popupWidgets && !QApplicationPrivate::popupWidgets->isEmpty() ? - QApplicationPrivate::popupWidgets->constLast() : nullptr; + auto *win = qobject_cast<QWidgetWindow *>(QGuiApplicationPrivate::activePopupWindow()); + return win ? win->widget() : nullptr; } @@ -1875,7 +1875,7 @@ void QApplicationPrivate::setActiveWindow(QWidget* act) QApplication::sendSpontaneousEvent(w, &activationChange); } - if (QApplicationPrivate::popupWidgets == nullptr) { // !inPopupMode() + if (!inPopupMode()) { // then focus events if (!QApplicationPrivate::active_window && QApplicationPrivate::focus_widget) { QApplicationPrivate::setFocusWidget(nullptr, Qt::ActiveWindowFocusReason); @@ -3299,11 +3299,12 @@ bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e) bool QApplicationPrivate::inPopupMode() { - return QApplicationPrivate::popupWidgets != nullptr; + return QGuiApplicationPrivate::activePopupWindow() != nullptr; } static void ungrabKeyboardForPopup(QWidget *popup) { + qCDebug(lcWidgetPopup) << "ungrab keyboard for" << popup; if (QWidget::keyboardGrabber()) qt_widget_private(QWidget::keyboardGrabber())->stealKeyboardGrab(true); else @@ -3312,6 +3313,7 @@ static void ungrabKeyboardForPopup(QWidget *popup) static void ungrabMouseForPopup(QWidget *popup) { + qCDebug(lcWidgetPopup) << "ungrab mouse for" << popup; if (QWidget::mouseGrabber()) qt_widget_private(QWidget::mouseGrabber())->stealMouseGrab(true); else @@ -3331,54 +3333,23 @@ static void grabForPopup(QWidget *popup) ungrabKeyboardForPopup(popup); } } -} - -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; + qCDebug(lcWidgetPopup) << "grabbed mouse and keyboard?" << popupGrabOk << "for popup" << popup; } void QApplicationPrivate::closePopup(QWidget *popup) { - if (!popupWidgets) + QWindow *win = popup->windowHandle(); + if (!win) + return; + if (!QGuiApplicationPrivate::closePopup(win)) return; - popupWidgets->removeAll(popup); - - if (popup == qt_popup_down) { - qt_button_down = nullptr; - qt_popup_down_closed = true; - qt_popup_down = nullptr; - } - if (QApplicationPrivate::popupWidgets->size() == 0) { // this was the last popup - delete QApplicationPrivate::popupWidgets; - QApplicationPrivate::popupWidgets = nullptr; - qt_popup_down_closed = false; + const QWindow *nextRemainingPopup = QGuiApplicationPrivate::activePopupWindow(); + if (!nextRemainingPopup) { // this was the last popup if (popupGrabOk) { popupGrabOk = false; - // TODO on multi-seat window systems, we have to know which mouse - auto devPriv = QPointingDevicePrivate::get(QPointingDevice::primaryPointingDevice()); - auto mousePressPos = devPriv->pointById(0)->eventPoint.globalPressPosition(); - if (popup->geometry().contains(mousePressPos.toPoint()) - || popup->testAttribute(Qt::WA_NoMouseReplay)) { - // mouse release event or inside - qt_replay_popup_mouse_event = false; - } else { // mouse press event - qt_replay_popup_mouse_event = true; - } - // transfer grab back to mouse grabber if any, otherwise release the grab ungrabMouseForPopup(popup); @@ -3397,30 +3368,23 @@ void QApplicationPrivate::closePopup(QWidget *popup) } } - } else { + } else if (const auto *popupWin = qobject_cast<const QWidgetWindow *>(nextRemainingPopup)) { // A popup was closed, so the previous popup gets the focus. - QWidget* aw = QApplicationPrivate::popupWidgets->constLast(); - if (QWidget *fw = aw->focusWidget()) + if (QWidget *fw = popupWin->widget()->focusWidget()) fw->setFocus(Qt::PopupFocusReason); // can become nullptr due to setFocus() above - if (QApplicationPrivate::popupWidgets && - QApplicationPrivate::popupWidgets->size() == 1) // grab mouse/keyboard - grabForPopup(aw); + if (QGuiApplicationPrivate::popupCount() == 1) // grab mouse/keyboard + grabForPopup(popupWin->widget()); } } -int openPopupCount = 0; - void QApplicationPrivate::openPopup(QWidget *popup) { - openPopupCount++; - if (!popupWidgets) // create list - popupWidgets = new QWidgetList; - popupWidgets->append(popup); // add to end of list + QGuiApplicationPrivate::activatePopup(popup->windowHandle()); - if (QApplicationPrivate::popupWidgets->size() == 1) // grab mouse/keyboard + if (QGuiApplicationPrivate::popupCount() == 1) // grab mouse/keyboard grabForPopup(popup); // popups are not focus-handled by the window system (the first @@ -3428,7 +3392,7 @@ void QApplicationPrivate::openPopup(QWidget *popup) // new popup gets the focus if (popup->focusWidget()) { popup->focusWidget()->setFocus(Qt::PopupFocusReason); - } else if (popupWidgets->size() == 1) { // this was the first popup + } else if (QGuiApplicationPrivate::popupCount() == 1) { // this was the first popup if (QWidget *fw = QApplication::focusWidget()) { QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason); QCoreApplication::sendEvent(fw, &e); diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h index 21b1605dfc..7de9f54b58 100644 --- a/src/widgets/kernel/qapplication_p.h +++ b/src/widgets/kernel/qapplication_p.h @@ -107,8 +107,6 @@ public: static void setActiveWindow(QWidget* act); static bool inPopupMode(); - bool popupActive() override { return inPopupMode(); } - bool closeAllPopups() override; void closePopup(QWidget *popup); void openPopup(QWidget *popup); static void setFocusWidget(QWidget *focus, Qt::FocusReason reason); diff --git a/src/widgets/kernel/qgesturemanager.cpp b/src/widgets/kernel/qgesturemanager.cpp index edb159bbbf..35f8a1b641 100644 --- a/src/widgets/kernel/qgesturemanager.cpp +++ b/src/widgets/kernel/qgesturemanager.cpp @@ -27,7 +27,7 @@ QT_BEGIN_NAMESPACE -Q_LOGGING_CATEGORY(lcGestureManager, "qt.widgets.gestures") +Q_STATIC_LOGGING_CATEGORY(lcGestureManager, "qt.widgets.gestures") #if !defined(Q_OS_MACOS) static inline int panTouchPoints() diff --git a/src/widgets/kernel/qmacgesturerecognizer_p.h b/src/widgets/kernel/qmacgesturerecognizer_p.h index 5c559c6cb9..9ce3ece051 100644 --- a/src/widgets/kernel/qmacgesturerecognizer_p.h +++ b/src/widgets/kernel/qmacgesturerecognizer_p.h @@ -16,9 +16,10 @@ // #include <QtWidgets/private/qtwidgetsglobal_p.h> -#include "qtimer.h" #include "qpoint.h" #include "qgesturerecognizer.h" +#include <QtCore/qbasictimer.h> +#include <QtCore/qobject.h> #include <QtCore/qpointer.h> #ifndef QT_NO_GESTURES @@ -47,6 +48,7 @@ public: class QMacPanGestureRecognizer : public QObject, public QGestureRecognizer { + Q_OBJECT public: QMacPanGestureRecognizer(); diff --git a/src/widgets/kernel/qtooltip.cpp b/src/widgets/kernel/qtooltip.cpp index 35eaa8042a..5485777eab 100644 --- a/src/widgets/kernel/qtooltip.cpp +++ b/src/widgets/kernel/qtooltip.cpp @@ -9,7 +9,6 @@ #include <qstyle.h> #include <qstyleoption.h> #include <qstylepainter.h> -#include <qtimer.h> #if QT_CONFIG(effects) #include <private/qeffects_p.h> #endif @@ -24,6 +23,8 @@ #include <QtGui/private/qhighdpiscaling_p.h> #include <qtooltip.h> +#include <QtCore/qbasictimer.h> + QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; diff --git a/src/widgets/kernel/qwhatsthis.cpp b/src/widgets/kernel/qwhatsthis.cpp index c80f37267f..4c988e4af3 100644 --- a/src/widgets/kernel/qwhatsthis.cpp +++ b/src/widgets/kernel/qwhatsthis.cpp @@ -10,7 +10,6 @@ #include "qpixmap.h" #include "qscreen.h" #include "qpainter.h" -#include "qtimer.h" #if QT_CONFIG(action) #include "qaction.h" #endif // QT_CONFIG(action) diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 6eff4abfb0..33fd9bfe4b 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -84,8 +84,8 @@ using namespace Qt::StringLiterals; Q_LOGGING_CATEGORY(lcWidgetPainting, "qt.widgets.painting", QtWarningMsg); Q_LOGGING_CATEGORY(lcWidgetShowHide, "qt.widgets.showhide", QtWarningMsg); -Q_LOGGING_CATEGORY(lcWidgetWindow, "qt.widgets.window", QtWarningMsg); -Q_LOGGING_CATEGORY(lcWidgetFocus, "qt.widgets.focus") +Q_STATIC_LOGGING_CATEGORY(lcWidgetWindow, "qt.widgets.window", QtWarningMsg); +Q_STATIC_LOGGING_CATEGORY(lcWidgetFocus, "qt.widgets.focus") #ifndef QT_NO_DEBUG_STREAM namespace { @@ -1029,10 +1029,13 @@ void QWidgetPrivate::createRecursively() QRhi *QWidgetPrivate::rhi() const { - if (QWidgetRepaintManager *repaintManager = maybeRepaintManager()) - return repaintManager->rhi(); - else + Q_Q(const QWidget); + if (auto *backingStore = q->backingStore()) { + auto *window = windowHandle(WindowHandleMode::Closest); + return backingStore->handle()->rhi(window); + } else { return nullptr; + } } /*! @@ -1112,8 +1115,15 @@ static bool q_evaluateRhiConfigRecursive(const QWidget *w, QPlatformBackingStore } for (const QObject *child : w->children()) { if (const QWidget *childWidget = qobject_cast<const QWidget *>(child)) { - if (q_evaluateRhiConfigRecursive(childWidget, outConfig, outType)) + if (q_evaluateRhiConfigRecursive(childWidget, outConfig, outType)) { + static bool optOut = qEnvironmentVariableIsSet("QT_WIDGETS_NO_CHILD_RHI"); + // Native child widgets should not trigger RHI for its parent + // hierarchy, but will still flush the native child using RHI. + if (!optOut && childWidget->testAttribute(Qt::WA_NativeWindow)) + continue; + return true; + } } } return false; @@ -1356,19 +1366,19 @@ void QWidgetPrivate::create() QBackingStore *store = q->backingStore(); usesRhiFlush = false; - if (!store) { - if (q->windowType() != Qt::Desktop) { - if (q->isWindow()) { - q->setBackingStore(new QBackingStore(win)); - QPlatformBackingStoreRhiConfig rhiConfig; - usesRhiFlush = q_evaluateRhiConfig(q, &rhiConfig, nullptr); - topData()->backingStore->handle()->setRhiConfig(rhiConfig); - } - } else { - q->setAttribute(Qt::WA_PaintOnScreen, true); + if (q->windowType() == Qt::Desktop) { + q->setAttribute(Qt::WA_PaintOnScreen, true); + } else { + if (!store && q->isWindow()) + q->setBackingStore(new QBackingStore(win)); + + QPlatformBackingStoreRhiConfig rhiConfig; + usesRhiFlush = q_evaluateRhiConfig(q, &rhiConfig, nullptr); + if (usesRhiFlush && q->backingStore()) { + // Trigger creation of support infrastructure up front, + // now that we have a specific RHI configuration. + q->backingStore()->handle()->createRhi(win, rhiConfig); } - } else if (win->handle()) { - usesRhiFlush = q_evaluateRhiConfig(q, nullptr, nullptr); } setWindowModified_helper(); @@ -1690,7 +1700,11 @@ void QWidgetPrivate::deleteSysExtra() void QWidgetPrivate::deleteTLSysExtra() { + Q_Q(QWidget); if (extra && extra->topextra) { + if (extra->hasWindowContainer) + QWindowContainer::toplevelAboutToBeDestroyed(q); + delete extra->topextra->window; extra->topextra->window = nullptr; } @@ -2715,8 +2729,10 @@ void QWidgetPrivate::inheritStyle() // to be running a proxy if (!qApp->styleSheet().isEmpty() || qt_styleSheet(parentStyle)) { QStyle *newStyle = parentStyle; - if (q->testAttribute(Qt::WA_SetStyle)) + if (q->testAttribute(Qt::WA_SetStyle) && qt_styleSheet(origStyle) == nullptr) newStyle = new QStyleSheetStyle(origStyle); + else if (auto *styleSheetStyle = qt_styleSheet(origStyle)) + newStyle = styleSheetStyle; else if (QStyleSheetStyle *newProxy = qt_styleSheet(parentStyle)) newProxy->ref(); @@ -6107,6 +6123,13 @@ void QWidget::setWindowTitle(const QString &title) if (QWidget::windowTitle() == title && !title.isEmpty() && !title.isNull()) return; +#if QT_CONFIG(accessibility) + QString oldAccessibleName; + const QAccessibleInterface *accessible = QAccessible::queryAccessibleInterface(this); + if (accessible) + oldAccessibleName = accessible->text(QAccessible::Name); +#endif + Q_D(QWidget); d->topData()->caption = title; d->setWindowTitle_helper(title); @@ -6115,6 +6138,13 @@ void QWidget::setWindowTitle(const QString &title) QCoreApplication::sendEvent(this, &e); emit windowTitleChanged(title); + +#if QT_CONFIG(accessibility) + if (accessible && accessible->text(QAccessible::Name) != oldAccessibleName) { + QAccessibleEvent event(this, QAccessible::NameChanged); + QAccessible::updateAccessibility(&event); + } +#endif } @@ -7079,7 +7109,6 @@ void QWidgetPrivate::reparentFocusWidgets(QWidget * oldtlw) if (focus_child) focus_child->clearFocus(); - insertIntoFocusChain(QWidgetPrivate::FocusDirection::Previous, q->window()); reparentFocusChildren(QWidgetPrivate::FocusDirection::Next); } @@ -7694,11 +7723,15 @@ QMargins QWidgetPrivate::safeAreaMargins() const return QMargins(); // Or, if one of our ancestors are in a layout that does not have WA_LayoutOnEntireRect - // set, then we know that the layout has already taken care of placing us inside the - // safe area, by taking the contents rect of its parent widget into account. + // set, and the widget respects the safe area, then we know that the layout has already + // taken care of placing us inside the safe area, by taking the contents rect of its + // parent widget into account. const QWidget *assumedSafeWidget = nullptr; for (const QWidget *w = q; w != nativeWidget; w = w->parentWidget()) { QWidget *parentWidget = w->parentWidget(); + if (!parentWidget->testAttribute(Qt::WA_ContentsMarginsRespectsSafeArea)) + continue; // Layout can't help us + if (parentWidget->testAttribute(Qt::WA_LayoutOnEntireRect)) continue; // Layout not going to help us @@ -8434,7 +8467,7 @@ void QWidgetPrivate::hideChildren(bool spontaneous) continue; qCDebug(lcWidgetShowHide) << "Considering" << widget << "with attributes" << WidgetAttributes{widget}; - if (widget->isWindow() || widget->testAttribute(Qt::WA_WState_Hidden)) + if (widget->isWindow() || !widget->isVisible()) continue; if (spontaneous) @@ -10656,6 +10689,7 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) const bool wasCreated = testAttribute(Qt::WA_WState_Created); QWidget *oldtlw = window(); Q_ASSERT(oldtlw); + QWidget *oldParentWithWindow = d->closestParentWidgetWithWindowHandle(); if (f & Qt::Window) // Frame geometry likely changes, refresh. d->data.fstrut_dirty = true; @@ -10698,7 +10732,8 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) // texture-based widgets need a pre-notification when their associated top-level window changes // This is not under the wasCreated/newParent conditions above in order to also play nice with QDockWidget. - if (oldtlw->d_func()->usesRhiFlush && ((!parent && parentWidget()) || (parent && parent->window() != oldtlw))) + const bool oldParentUsesRhiFlush = oldParentWithWindow ? oldParentWithWindow->d_func()->usesRhiFlush : false; + if (oldParentUsesRhiFlush && ((!parent && parentWidget()) || (parent && parent->window() != oldtlw))) qSendWindowChangeToTextureChildrenRecursively(this, QEvent::WindowAboutToChangeInternal); // If we get parented into another window, children will be folded @@ -10779,7 +10814,7 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) // texture-based widgets need another event when their top-level window // changes (more precisely, has already changed at this point) - if (oldtlw->d_func()->usesRhiFlush && oldtlw != window()) + if (oldParentUsesRhiFlush && oldtlw != window()) qSendWindowChangeToTextureChildrenRecursively(this, QEvent::WindowChangeInternal); if (!wasCreated) { @@ -10807,33 +10842,47 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) if (d->extra && d->extra->hasWindowContainer) QWindowContainer::parentWasChanged(this); - QWidget *newtlw = window(); - if (oldtlw != newtlw) { + QWidget *newParentWithWindow = d->closestParentWidgetWithWindowHandle(); + if (newParentWithWindow && newParentWithWindow != oldParentWithWindow) { + // Check if the native parent now needs to switch to RHI + qCDebug(lcWidgetPainting) << "Evaluating whether reparenting of" << this + << "into" << parent << "requires RHI enablement for" << newParentWithWindow; + + QPlatformBackingStoreRhiConfig rhiConfig; QSurface::SurfaceType surfaceType = QSurface::RasterSurface; - // Only evaluate the reparented subtree. While it might be tempting to - // do it on newtlw instead, the performance implications of that are + + // First evaluate whether the reparented widget uses RHI. + // We do this as a separate step because the performance + // implications of always checking the native parent are // problematic when it comes to large widget trees. - if (q_evaluateRhiConfig(this, nullptr, &surfaceType)) { - const bool wasUsingRhiFlush = newtlw->d_func()->usesRhiFlush; - newtlw->d_func()->usesRhiFlush = true; - bool recreate = false; - if (QWindow *w = newtlw->windowHandle()) { - if (w->surfaceType() != surfaceType || !wasUsingRhiFlush) - recreate = true; - } - // QTBUG-115652: Besides the toplevel the nativeParentWidget()'s QWindow must be checked as well. - if (QWindow *w = d->windowHandle(QWidgetPrivate::WindowHandleMode::Closest)) { - if (w->surfaceType() != surfaceType) - recreate = true; - } - if (recreate) { - const auto windowStateBeforeDestroy = newtlw->windowState(); - const auto visibilityBeforeDestroy = newtlw->isVisible(); - newtlw->destroy(); - newtlw->create(); - Q_ASSERT(newtlw->windowHandle()); - newtlw->windowHandle()->setWindowStates(windowStateBeforeDestroy); - QWidgetPrivate::get(newtlw)->setVisible(visibilityBeforeDestroy); + if (q_evaluateRhiConfig(this, &rhiConfig, &surfaceType)) { + // Then check whether the native parent requires RHI + // as a result. It may not, if this widget is a native + // window, and can handle its own RHI flushing. + if (q_evaluateRhiConfig(newParentWithWindow, nullptr, nullptr)) { + // Finally, check whether we need to recreate the + // native parent to enable RHI flushing. + auto *existingWindow = newParentWithWindow->windowHandle(); + auto existingSurfaceType = existingWindow->surfaceType(); + if (existingSurfaceType != surfaceType) { + qCDebug(lcWidgetPainting) + << "Recreating" << existingWindow + << "with current type" << existingSurfaceType + << "to support" << surfaceType; + const auto windowStateBeforeDestroy = newParentWithWindow->windowState(); + const auto visibilityBeforeDestroy = newParentWithWindow->isVisible(); + newParentWithWindow->destroy(); + newParentWithWindow->create(); + Q_ASSERT(newParentWithWindow->windowHandle()); + newParentWithWindow->windowHandle()->setWindowStates(windowStateBeforeDestroy); + QWidgetPrivate::get(newParentWithWindow)->setVisible(visibilityBeforeDestroy); + } else if (auto *backingStore = newParentWithWindow->backingStore()) { + // If we don't recreate we still need to make sure the native parent + // widget has a RHI config that the reparented widget can use. + backingStore->handle()->createRhi(existingWindow, rhiConfig); + // And that it knows it's now flushing with RHI + QWidgetPrivate::get(newParentWithWindow)->usesRhiFlush = true; + } } } } @@ -12291,8 +12340,10 @@ QBackingStore *QWidget::backingStore() const if (extra && extra->backingStore) return extra->backingStore; - QWidgetRepaintManager *repaintManager = d->maybeRepaintManager(); - return repaintManager ? repaintManager->backingStore() : nullptr; + if (!isWindow()) + return window()->backingStore(); + + return nullptr; } void QWidgetPrivate::getLayoutItemMargins(int *left, int *top, int *right, int *bottom) const @@ -12939,6 +12990,10 @@ int QWidget::metric(PaintDeviceMetric m) const return resolveDevicePixelRatio(); case PdmDevicePixelRatioScaled: return QPaintDevice::devicePixelRatioFScale() * resolveDevicePixelRatio(); + case PdmDevicePixelRatioF_EncodedA: + Q_FALLTHROUGH(); + case PdmDevicePixelRatioF_EncodedB: + return QPaintDevice::encodeMetricF(m, resolveDevicePixelRatio()); default: break; } @@ -13351,32 +13406,61 @@ void QWidgetPrivate::initFocusChain() void QWidgetPrivate::reparentFocusChildren(FocusDirection direction) { Q_Q(QWidget); - QWidgetList focusChildrenInsideChain; - QDuplicateTracker<QWidget *> seen; - QWidget *widget = q->nextInFocusChain(); - while (q->isAncestorOf(widget) - && !seen.hasSeen(widget) - && widget != q->window()) { - if (widget->focusPolicy() != Qt::NoFocus) - focusChildrenInsideChain << widget; - - widget = direction == FocusDirection::Next ? widget->nextInFocusChain() - : widget->previousInFocusChain(); - } - - const QWidgetList children = q->findChildren<QWidget *>(Qt::FindDirectChildrenOnly); - QWidgetList focusChildrenOutsideChain; - for (auto *child : children) { - if (!focusChildrenInsideChain.contains(child)) - focusChildrenOutsideChain << child; - } - if (focusChildrenOutsideChain.isEmpty()) - return; - QWidget *previous = q; - for (auto *child : focusChildrenOutsideChain) { - child->d_func()->insertIntoFocusChain(direction, previous); - previous = child; + // separate the focus chain into new (children of myself) and old (the rest) + QWidget *firstOld = nullptr; + QWidget *lastOld = nullptr; // last in the old list + QWidget *lastNew = q; // last in the new list + bool prevWasNew = true; + QWidget *widget = nextPrevElementInFocusChain(direction); + + // For efficiency, do not maintain the list invariant inside the loop. + // Append items to the relevant list, and we optimize by not changing pointers, + // when subsequent items are going into the same list. + while (widget != q) { + bool currentIsNew = q->isAncestorOf(widget); + if (currentIsNew) { + if (!prevWasNew) { + // previous was old => append to new list + FOCUS_NEXT(lastNew) = widget; + FOCUS_PREV(widget) = lastNew; + } + lastNew = widget; + } else { + if (prevWasNew) { + // prev was new => append to old list, if it exists + if (lastOld) { + FOCUS_NEXT(lastOld) = widget; + FOCUS_PREV(widget) = lastOld; + } else { + // start the old list + firstOld = widget; + } + } + lastOld = widget; + } + widget = widget->d_func()->nextPrevElementInFocusChain(direction); + prevWasNew = currentIsNew; + } + + // repair old list: + if (firstOld) { + FOCUS_NEXT(lastOld) = firstOld; + FOCUS_PREV(firstOld) = lastOld; + } + + if (!q->isWindow()) { + QWidget *topLevel = q->window(); + // insert new chain into toplevel's chain + QWidget *prev = FOCUS_PREV(topLevel); + FOCUS_PREV(topLevel) = lastNew; + FOCUS_NEXT(prev) = q; + FOCUS_PREV(q) = prev; + FOCUS_NEXT(lastNew) = topLevel; + } else { + // repair new list + FOCUS_NEXT(lastNew) = q; + FOCUS_PREV(q) = lastNew; } } diff --git a/src/widgets/kernel/qwidgetrepaintmanager.cpp b/src/widgets/kernel/qwidgetrepaintmanager.cpp index 607a767a20..0dee380a91 100644 --- a/src/widgets/kernel/qwidgetrepaintmanager.cpp +++ b/src/widgets/kernel/qwidgetrepaintmanager.cpp @@ -1016,11 +1016,13 @@ void QWidgetRepaintManager::flush(QWidget *widget, const QRegion ®ion, QPlatf if (tlw->testAttribute(Qt::WA_DontShowOnScreen) || widget->testAttribute(Qt::WA_DontShowOnScreen)) return; + QWindow *window = widget->windowHandle(); + // We should only be flushing to native widgets + Q_ASSERT(window); + // Foreign Windows do not have backing store content and must not be flushed - if (QWindow *widgetWindow = widget->windowHandle()) { - if (widgetWindow->type() == Qt::ForeignWindow) - return; - } + if (window->type() == Qt::ForeignWindow) + return; static bool fpsDebug = qEnvironmentVariableIntValue("QT_DEBUG_FPS"); if (fpsDebug) { @@ -1037,69 +1039,51 @@ void QWidgetRepaintManager::flush(QWidget *widget, const QRegion ®ion, QPlatf if (widget != tlw) offset += widget->mapTo(tlw, QPoint()); - // Use a condition that tries to keep both QTBUG-108344 and QTBUG-113557 - // happy, i.e. support both (A) "native rhi-based child in a rhi-based - // toplevel" and (B) "native raster child in a rhi-based toplevel". - // - // If the tlw and the backingstore are RHI-based, then there are two cases - // to consider: - // - // (1) widget is not a native child, i.e. the QWindow for widget and tlw are - // the same, - // - // (2) widget is a native child which we now attempt to flush with tlw's - // backingstore to widget's native window. This is the interesting one. - // - // Using the condition tlw->usesRhiFlush on its own is insufficient since - // it fails to capture the case of a raster-based native child widget - // within tlw. (which must hit the non-rhi flush path) - // - // Extending the condition with tlw->windowHandle() == widget->windowHandle() - // would be logical but wrong, when it comes to (A) since flushing a - // RHI-based native child with a given 3D API using a RHI-based - // tlw/backingstore with the same 3D API needs to be supported still. (this - // happens when e.g. someone calls winId() on a QOpenGLWidget) - // - // Different 3D APIs do not need to be supported since we do not allow to - // do things like having a QQuickWidget with Vulkan and a QOpenGLWidget in - // the same toplevel, regardless of the widgets being native children or - // not. Hence comparing the surfaceType() instead. This satisfies both (A) - // and (B) given that an RHI-based toplevel cannot be RasterSurface. - // - if (tlw->d_func()->usesRhiFlush && tlw->windowHandle()->surfaceType() == widget->windowHandle()->surfaceType()) { - QRhi *rhi = store->handle()->rhi(); - qCDebug(lcWidgetPainting) << "Flushing" << region << "of" << widget - << "with QRhi" << rhi - << "to window" << widget->windowHandle(); + // A widget uses RHI flush if itself, or one of its non-native children + // uses RHI for its drawing. If so, we composite the backing store raster + // data along with textures produced by the RHI widgets. + const bool flushWithRhi = widget->d_func()->usesRhiFlush; + + qCDebug(lcWidgetPainting) << "Flushing" << region << "of" << widget + << "to" << window << (flushWithRhi ? "using RHI" : ""); + + // A widget uses RHI flush if itself, or one of its non-native children + // uses RHI for its drawing. If so, we composite the backing store raster + // data along with textures produced by the RHI widgets. + if (flushWithRhi) { if (!widgetTextures) widgetTextures = qt_dummy_platformTextureList; - QWidgetPrivate *widgetWindowPrivate = widget->window()->d_func(); - widgetWindowPrivate->sendComposeStatus(widget->window(), false); + // We only need to let the widget sub-hierarchy that + // we are flushing know that we're compositing. + auto *widgetPrivate = QWidgetPrivate::get(widget); + widgetPrivate->sendComposeStatus(widget, false); + // A window may have alpha even when the app did not request // WA_TranslucentBackground. Therefore the compositor needs to know whether the app intends // to rely on translucency, in order to decide if it should clear to transparent or opaque. const bool translucentBackground = widget->testAttribute(Qt::WA_TranslucentBackground); QPlatformBackingStore::FlushResult flushResult; - flushResult = store->handle()->rhiFlush(widget->windowHandle(), + flushResult = store->handle()->rhiFlush(window, widget->devicePixelRatio(), region, offset, widgetTextures, translucentBackground); - widgetWindowPrivate->sendComposeStatus(widget->window(), true); + + widgetPrivate->sendComposeStatus(widget, true); + if (flushResult == QPlatformBackingStore::FlushFailedDueToLostDevice) { qSendWindowChangeToTextureChildrenRecursively(widget->window(), QEvent::WindowAboutToChangeInternal); - store->handle()->graphicsDeviceReportedLost(); + store->handle()->graphicsDeviceReportedLost(window); qSendWindowChangeToTextureChildrenRecursively(widget->window(), QEvent::WindowChangeInternal); widget->update(); } } else { - qCInfo(lcWidgetPainting) << "Flushing" << region << "of" << widget; - store->flush(region, widget->windowHandle(), offset); + store->flush(region, window, offset); } } @@ -1308,11 +1292,6 @@ void QWidgetPrivate::invalidateBackingStore_resizeHelper(const QPoint &oldPos, c } } -QRhi *QWidgetRepaintManager::rhi() const -{ - return store->handle()->rhi(); -} - QT_END_NAMESPACE #include "qwidgetrepaintmanager.moc" diff --git a/src/widgets/kernel/qwidgetrepaintmanager_p.h b/src/widgets/kernel/qwidgetrepaintmanager_p.h index 4378974610..13190a0bb0 100644 --- a/src/widgets/kernel/qwidgetrepaintmanager_p.h +++ b/src/widgets/kernel/qwidgetrepaintmanager_p.h @@ -26,8 +26,6 @@ QT_BEGIN_NAMESPACE class QPlatformTextureList; class QPlatformTextureListWatcher; class QWidgetRepaintManager; -class QRhi; -class QRhiSwapChain; class Q_WIDGETS_EXPORT QWidgetRepaintManager { @@ -72,8 +70,6 @@ public: bool bltRect(const QRect &rect, int dx, int dy, QWidget *widget); - QRhi *rhi() const; - private: void updateLists(QWidget *widget); diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index e7f0a84004..ce9bb44b45 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -27,9 +27,8 @@ Q_WIDGETS_EXPORT QWidget *qt_button_down = nullptr; // widget got last button-do // popup control QWidget *qt_popup_down = nullptr; // popup that contains the pressed widget -extern int openPopupCount; bool qt_popup_down_closed = false; // qt_popup_down has been closed -bool qt_replay_popup_mouse_event = false; + extern bool qt_try_modal(QWidget *widget, QEvent::Type type); class QWidgetWindowPrivate : public QWindowPrivate @@ -161,8 +160,8 @@ QWidgetWindow::QWidgetWindow(QWidget *widget) updateObjectName(); if (!QCoreApplication::testAttribute(Qt::AA_ForceRasterWidgets)) { QSurface::SurfaceType type = QSurface::RasterSurface; - q_evaluateRhiConfig(m_widget, nullptr, &type); - setSurfaceType(type); + if (q_evaluateRhiConfig(m_widget, nullptr, &type)) + setSurfaceType(type); } connect(widget, &QObject::objectNameChanged, this, &QWidgetWindow::updateObjectName); @@ -505,9 +504,6 @@ void QWidgetWindow::handleNonClientAreaMouseEvent(QMouseEvent *e) void QWidgetWindow::handleMouseEvent(QMouseEvent *event) { - static const QEvent::Type contextMenuTrigger = - QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::ContextMenuOnMouseRelease).toBool() ? - QEvent::MouseButtonRelease : QEvent::MouseButtonPress; if (QApplicationPrivate::inPopupMode()) { QPointer<QWidget> activePopupWidget = QApplication::activePopupWidget(); QPointF mapped = event->position(); @@ -535,11 +531,8 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) break; // nothing for mouse move } - int oldOpenPopupCount = openPopupCount; - if (activePopupWidget->isEnabled()) { // deliver event - qt_replay_popup_mouse_event = false; QPointer<QWidget> receiver = activePopupWidget; QPointF widgetPos = mapped; if (qt_button_down) @@ -591,57 +584,6 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) } } - if (QApplication::activePopupWidget() != activePopupWidget - && qt_replay_popup_mouse_event - && QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::ReplayMousePressOutsidePopup).toBool()) { - if (m_widget->windowType() != Qt::Popup) - qt_button_down = nullptr; - if (event->type() == QEvent::MouseButtonPress) { - // the popup disappeared, replay the mouse press event - QWidget *w = QApplication::widgetAt(event->globalPosition().toPoint()); - if (w && !QApplicationPrivate::isBlockedByModal(w)) { - // activate window of the widget under mouse pointer - if (!w->isActiveWindow()) { - w->activateWindow(); - w->window()->raise(); - } - - if (auto win = qt_widget_private(w)->windowHandle(QWidgetPrivate::WindowHandleMode::Closest)) { - const QRect globalGeometry = win->isTopLevel() - ? win->geometry() - : QRect(win->mapToGlobal(QPoint(0, 0)), win->size()); - if (globalGeometry.contains(event->globalPosition().toPoint())) { - // Use postEvent() to ensure the local QEventLoop terminates when called from QMenu::exec() - const QPoint localPos = win->mapFromGlobal(event->globalPosition().toPoint()); - QMouseEvent *e = new QMouseEvent(QEvent::MouseButtonPress, localPos, localPos, event->globalPosition().toPoint(), - event->button(), event->buttons(), event->modifiers(), event->source()); - QCoreApplicationPrivate::setEventSpontaneous(e, true); - e->setTimestamp(event->timestamp()); - QCoreApplication::postEvent(win, e); - } - } - } - } - qt_replay_popup_mouse_event = false; -#ifndef QT_NO_CONTEXTMENU - } else if (event->type() == contextMenuTrigger - && event->button() == Qt::RightButton - && (openPopupCount == oldOpenPopupCount)) { - QWidget *receiver = activePopupWidget; - if (qt_button_down) - receiver = qt_button_down; - else if (popupChild) - receiver = popupChild; - const QPoint localPos = receiver->mapFromGlobal(event->globalPosition().toPoint()); - QContextMenuEvent e(QContextMenuEvent::Mouse, localPos, event->globalPosition().toPoint(), event->modifiers()); - QApplication::forwardEvent(receiver, &e, event); - } -#else - Q_UNUSED(contextMenuTrigger); - Q_UNUSED(oldOpenPopupCount); - } -#endif - if (releaseAfter) { qt_button_down = nullptr; qt_popup_down_closed = false; @@ -671,6 +613,11 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) if (!receiver) return; + if (d_func()->isPopup() && receiver->window()->windowHandle() != this) { + receiver = widget; + mapped = event->position().toPoint(); + } + if ((event->type() != QEvent::MouseButtonPress) || !QMutableSinglePointEvent::from(event)->isDoubleClick()) { // The preceding statement excludes MouseButtonPress events which caused @@ -684,7 +631,8 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) event->setAccepted(translated.isAccepted()); } #ifndef QT_NO_CONTEXTMENU - if (event->type() == contextMenuTrigger && event->button() == Qt::RightButton + if (event->type() == QGuiApplicationPrivate::contextMenuEventType() + && event->button() == Qt::RightButton && m_widget->rect().contains(event->position().toPoint())) { QContextMenuEvent e(QContextMenuEvent::Mouse, mapped, event->globalPosition().toPoint(), event->modifiers()); QGuiApplication::forwardEvent(receiver, &e, event); @@ -862,6 +810,10 @@ void QWidgetWindow::handleResizeEvent(QResizeEvent *event) void QWidgetWindow::closeEvent(QCloseEvent *event) { Q_D(QWidgetWindow); + if (qt_popup_down == m_widget) { + qt_popup_down = nullptr; + qt_popup_down_closed = true; + } bool accepted = m_widget->d_func()->handleClose(d->inClose ? QWidgetPrivate::CloseWithEvent : QWidgetPrivate::CloseWithSpontaneousEvent); event->setAccepted(accepted); |