Skip to content

Commit

Permalink
WebEngine-specific: look for QQuickWidget child of QWebEngineView
Browse files Browse the repository at this point in the history
When the user hovers the mouse pointer over the collapse-article icon
while the article is expanded or over the article name while it is
collapsed, a "(Collapse|Expand) article" tooltip is displayed. This
tooltip creates a temporary QTipLabel child of ArticleWebView. QTipLabel
is a private Qt class derived from QLabel. This transitory widget child
of ArticleWebView replaces the RenderWidgetHostViewQtDelegateWidget
child in the childWidget pointer. Afterwards ArticleWebView's cursor
member functions do not update RenderWidgetHostViewQtDelegateWidget's
cursor and thus the cursor no longer changes shape to a wait cursor when
an article starts loading.

Don't look for RenderWidgetHostViewQtDelegateWidget directly, because
5d1ef38f9f6815807596d0606cf7ed06b7930aac replaced this class with
WebEngineQuickWidget in Qt WebEngine 6.4. Both the old class and its
replacement inherit QQuickWidget. Since GoldenDict does not use Qt Quick
directly, I don't expect any more wrong childWidget values with this
implementation.

quickwidgets Qt module dependency has to be added to the Qt WebEngine
version of GoldenDict to use qobject_cast< QQuickWidget * >. This should
not cause any issues to end users, because webenginewidgets module
itself privately depends on quickwidgets.
  • Loading branch information
vedgy committed Nov 29, 2022
1 parent df3dae3 commit a64d1bb
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 9 deletions.
40 changes: 33 additions & 7 deletions articlewebview.cc
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,15 @@ bool ArticleWebView::isOnScrollBar( QMouseEvent const & event ) const
#include "gddebug.hh"

#include <QChildEvent>
#include <QQuickWidget>

namespace {
QWidget * toChildWidget( QObject * object )
{
// We are interested only in the QQuickWidget child of QWebEngineView.
return qobject_cast< QQuickWidget * >( object );
}
}

void ArticleWebView::setEventFilter( QObject * filterObject )
{
Expand All @@ -194,7 +203,7 @@ void ArticleWebView::setEventFilter( QObject * filterObject )

bool ArticleWebView::isWatched( QObject * object ) const
{
return object->parent() == this && object->isWidgetType();
return object->parent() == this && object->isWidgetType() && toChildWidget( object );
}

QCursor ArticleWebView::cursor() const
Expand All @@ -219,21 +228,38 @@ void ArticleWebView::childEvent( QChildEvent * event )
auto * const child = event->child();
if( child->isWidgetType() )
{
// Empirical observation: in Qt 5.15 QWebEngineView has a single widget child, which is added
// Empirical observation: in Qt 5.15 QWebEngineView has a single QQuickWidget child, which is added
// soon after construction and is never removed. Remove the event filter from a removed child
// anyway in case this occurs under some circumstances or in a future Qt version.
switch( event->type() )
{
case QEvent::ChildAdded:
// Handle ChildPolished event, which occurs soon after ChildAdded event we are really interested in. Cannot handle
// the ChildAdded event directly, because child is not fully constructed and is only a QWidget then. ChildPolished
// event occurs before a lambda invocation queued in ChildAdded event, and thus is preferable to that alternative.
case QEvent::ChildPolished:
{
if( child == childWidget )
return; // repeated polishing => nothing to do
auto * const childAsWidget = toChildWidget( child );
if( !childAsWidget )
return; // this must be a non-quick widget child we are not interested in

// Theoretically eventFilterObject can be installed multiple times on the same quick widget child
// in case of multiple ChildPolished events and a childWidget replacement. This is not a problem,
// because QObject::installEventFilter() removes the event filter if present before installing it
// (guards against a single event filter object installed twice).
child->installEventFilter( eventFilterObject );

if( childWidget )
gdWarning( "A second widget child is added to an article web view. Replacing the first one." );
childWidget = qobject_cast< QWidget * >( child );
gdWarning( "A second quick widget child is added to an article web view. Replacing the first one." );
childWidget = childAsWidget;
break;

}
case QEvent::ChildRemoved:
child->removeEventFilter( eventFilterObject );
// If child is being destroyed and is no longer a QQuickWidget, removing the event filter is unnecessary,
// because when an object is destroyed, all event filters installed on it are automatically removed.
if( toChildWidget( child ) )
child->removeEventFilter( eventFilterObject );

if( childWidget == child )
childWidget = nullptr;
Expand Down
2 changes: 1 addition & 1 deletion articlewebview.hh
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ private:
#include <QWebEngineView>

/// A thin wrapper around QWebEngineView that works around QTBUG-43602 by installing
/// an event filter on the widget child of QWebEngineView, which swallows mouse events.
/// an event filter on the QQuickWidget child of QWebEngineView, which swallows mouse events.
/// In the Qt WebEngine version, ArticleView implements most features ArticleWebView provides in the Qt WebKit version.
class ArticleWebView: public QWebEngineView
{
Expand Down
3 changes: 2 additions & 1 deletion goldendict.pro
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ greaterThan(QT_MAJOR_VERSION, 4) {
"The Qt WebEngine version of GoldenDict requires Qt $${REQUIRED_QT_VERSION} or newer." )
}

QT += webchannel \
QT += quickwidgets \
webchannel \
webenginewidgets
CONFIG += c++14
} else {
Expand Down

0 comments on commit a64d1bb

Please sign in to comment.