diff options
Diffstat (limited to 'src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp')
-rw-r--r-- | src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp | 81 |
1 files changed, 42 insertions, 39 deletions
diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp index c32e89f0c..7bbd85091 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -49,7 +49,7 @@ #include <QSGAbstractRenderer> #include <QSGNode> #include <QWindow> -#include <private/qquickwindow_p.h> +#include <QtQuick/private/qquickwindow_p.h> namespace QtWebEngineCore { @@ -165,15 +165,28 @@ RenderWidgetHostViewQtDelegateWidget::RenderWidgetHostViewQtDelegateWidget(Rende setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_AlwaysShowToolTips); - if (parent) { - // Unset the popup parent if the parent is being destroyed, thus making sure a double - // delete does not happen. - // Also in case the delegate is destroyed before its parent (when a popup is simply - // dismissed), this connection will automatically be removed by ~QObject(), preventing - // a use-after-free. + setContent(QUrl(), nullptr, m_rootItem.data()); + + connectRemoveParentBeforeParentDelete(); +} + +RenderWidgetHostViewQtDelegateWidget::~RenderWidgetHostViewQtDelegateWidget() +{ + QWebEnginePagePrivate::bindPageAndWidget(nullptr, this); +} + +void RenderWidgetHostViewQtDelegateWidget::connectRemoveParentBeforeParentDelete() +{ + if (QWidget *parent = parentWidget()) connect(parent, &QObject::destroyed, this, &RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete); - } +} + +void RenderWidgetHostViewQtDelegateWidget::disconnectRemoveParentBeforeParentDelete() +{ + if (QWidget *parent = parentWidget()) + disconnect(parent, &QObject::destroyed, + this, &RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete); } void RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete() @@ -188,29 +201,9 @@ void RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete() close(); } -void RenderWidgetHostViewQtDelegateWidget::initAsChild(WebContentsAdapterClient* container) -{ - setContent(QUrl(), nullptr, m_rootItem.data()); - - QWebEnginePagePrivate *pagePrivate = static_cast<QWebEnginePagePrivate *>(container); - if (pagePrivate->view) { - if (parentWidget()) - disconnect(parentWidget(), &QObject::destroyed, - this, &RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete); - pagePrivate->view->layout()->addWidget(this); - if (QWidget *focusProxy = pagePrivate->view->focusProxy()) - if (focusProxy != this) - pagePrivate->view->layout()->removeWidget(focusProxy); - pagePrivate->view->setFocusProxy(this); - show(); - } else - setParent(0); -} - void RenderWidgetHostViewQtDelegateWidget::initAsPopup(const QRect& screenRect) { m_isPopup = true; - setContent(QUrl(), nullptr, m_rootItem.data()); // The keyboard events are supposed to go to the parent RenderHostView // so the WebUI popups should never have focus. Besides, if the parent view @@ -249,20 +242,18 @@ QRectF RenderWidgetHostViewQtDelegateWidget::contentsRect() const void RenderWidgetHostViewQtDelegateWidget::setKeyboardFocus() { - // If the corresponding window is inactive (for example, because of a popup), - // the active focus cannot be set. Sync up with the Window System to try to - // reactivate the window in time if the other window (possibly popup) which took - // the focus is already closed. - if (window() && !window()->isActive()) - QGuiApplication::sync(); + // The root item always has focus within the root focus scope: + Q_ASSERT(m_rootItem->hasFocus()); - m_rootItem->forceActiveFocus(); setFocus(); } bool RenderWidgetHostViewQtDelegateWidget::hasKeyboardFocus() { - return m_rootItem->hasActiveFocus(); + // The root item always has focus within the root focus scope: + Q_ASSERT(m_rootItem->hasFocus()); + + return hasFocus(); } void RenderWidgetHostViewQtDelegateWidget::lockMouse() @@ -312,13 +303,13 @@ QSGLayer *RenderWidgetHostViewQtDelegateWidget::createLayer() return renderContext->sceneGraphContext()->createLayer(renderContext); } -QSGInternalImageNode *RenderWidgetHostViewQtDelegateWidget::createImageNode() +QSGInternalImageNode *RenderWidgetHostViewQtDelegateWidget::createInternalImageNode() { QSGRenderContext *renderContext = QQuickWindowPrivate::get(quickWindow())->context; return renderContext->sceneGraphContext()->createInternalImageNode(); } -QSGTextureNode *RenderWidgetHostViewQtDelegateWidget::createTextureNode() +QSGImageNode *RenderWidgetHostViewQtDelegateWidget::createImageNode() { return quickWindow()->createImageNode(); } @@ -403,7 +394,7 @@ void RenderWidgetHostViewQtDelegateWidget::showEvent(QShowEvent *event) // We don't have a way to catch a top-level window change with QWidget // but a widget will most likely be shown again if it changes, so do // the reconnection at this point. - foreach (const QMetaObject::Connection &c, m_windowConnections) + for (const QMetaObject::Connection &c : qAsConst(m_windowConnections)) disconnect(c); m_windowConnections.clear(); if (QWindow *w = window()) { @@ -424,6 +415,18 @@ bool RenderWidgetHostViewQtDelegateWidget::event(QEvent *event) { bool handled = false; + // Track parent to make sure we don't get deleted. + switch (event->type()) { + case QEvent::ParentAboutToChange: + disconnectRemoveParentBeforeParentDelete(); + break; + case QEvent::ParentChange: + connectRemoveParentBeforeParentDelete(); + break; + default: + break; + } + // Mimic QWidget::event() by ignoring mouse, keyboard, touch and tablet events if the widget is // disabled. if (!isEnabled()) { |