summaryrefslogtreecommitdiffstats
path: root/src/widgets/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/kernel')
-rw-r--r--src/widgets/kernel/qapplication.cpp80
-rw-r--r--src/widgets/kernel/qapplication_p.h2
-rw-r--r--src/widgets/kernel/qgesturemanager.cpp2
-rw-r--r--src/widgets/kernel/qmacgesturerecognizer_p.h4
-rw-r--r--src/widgets/kernel/qtooltip.cpp3
-rw-r--r--src/widgets/kernel/qwhatsthis.cpp1
-rw-r--r--src/widgets/kernel/qwidget.cpp238
-rw-r--r--src/widgets/kernel/qwidgetrepaintmanager.cpp79
-rw-r--r--src/widgets/kernel/qwidgetrepaintmanager_p.h4
-rw-r--r--src/widgets/kernel/qwidgetwindow.cpp76
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 &region, 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 &region, 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);