githubuser0xFFFF/Qt-Advanced-Docking-System

White flash when switching qwebengine tab when using dark theme

char101 opened this issue · 11 comments

Hi,

When two qwebengine widgets are arranged in a tab, switching from one to the other causes white flashes (most visible when using dark theme). This does not happen when the widgets are put in a qstackedlayout (white flash only happens when the widgets are first added to the layout). Also switching the tab in the qstackedlayout does not trigger ResizeEvent, while switching in the docking tab triggers ResizeEvent.

I'm guessing this is because the qwebengine widget is removed and added to the boxlayout causing the embedded chromium to reset its layout.

Hi,

For performance reasons in ADS only visble dock widgets, that means only the widget in a visible tab, has a parent widget. That means the qwebengine widget is reparented when it becomes visible. If it gets hidden, it will get a nullptr parent and if it gets visible, it will be parented to its dock area. So this is nothing I can fix. You can try to derive a widget from qwebengine to fix this somehow - sorry.

Thanks. For reference to other users with the same problem, I can switch DockAreaLayout to QStackedLayout using this changes. So far it works ok, I didn't get any white flash and I haven't notice any other problem.

The first widget in the QBoxLayout is the tabs, so QStackedWidget should be added as a child layout. DockAreaLayout is not a layout instead it replace the widget at position 1 of the QBoxLayout.

diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp
index aa6d16d..f4ab81d 100644
--- a/src/DockAreaWidget.cpp
+++ b/src/DockAreaWidget.cpp
@@ -256,7 +256,7 @@ struct DockAreaWidgetPrivate
 {
        CDockAreaWidget*        _this                   = nullptr;
        QBoxLayout*                     Layout                  = nullptr;
-       DockAreaLayout*         ContentsLayout  = nullptr;
+       QStackedLayout*         ContentsLayout  = nullptr;
        CDockAreaTitleBar*      TitleBar                = nullptr;
        CDockManager*           DockManager             = nullptr;
        CAutoHideDockContainer* AutoHideDockContainer = nullptr;
@@ -441,7 +441,8 @@ CDockAreaWidget::CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget
        setLayout(d->Layout);

        d->createTitleBar();
-       d->ContentsLayout = new DockAreaLayout(d->Layout);
+       d->ContentsLayout = new QStackedLayout();
+       d->Layout->addLayout(d->ContentsLayout);
        if (d->DockManager)
        {
                Q_EMIT d->DockManager->dockAreaCreated(this);

Thank you very much for further testing. Initially, when I implemented ADS I used QStackedLayout. But I noticed that switching or loading perspectives took a very long time (sometimes several seconds for complex layout). The reson is, that loading a perspective causes reparenting, resizing and repositioning of widgets wich in turn causes relayouting or layout update of each widget. That means, if you have several widgets with a complex layout, than each widget will be updated because all widgets in the QStackedLayout will be relayouted. I could solve this issue, by setting the parent of all invisible widgets to nullptr. Now, If a perspective is loaded, only the visible widgets are updated. That means, if you have 4 visible widgets and 23 hidden widgets this will speed up perspective switching significantly.

Maybe I have to test, if this issue is still there in latest Qt versions such as Qt 6.5.2.

My perspective only has 11 widgets and each widget only has a simple boxlayout. I tried switching it back and forth with another perspective and I didn't notice any lag (Qt 6.7.0).

The only problem I notice is that moving the widgets or switching perspective causes the white flash to come back. To eliminate the white flash I have to restart the application.

But this would indicate that also QStackedLayout does not solve your problem?

It does, as long as I don't change the layout.

So you forbid your users to change their perspective?

It is a personal application. I am the only user and developer.

Ok, so then your fix works for your specific use case but does not fix the problem for other users because switching perspectives is an integral part of ADS. So maybe this is an Qt issue because reparenting a widget with a QWebEngine should not cause such issues.

My current hypothesis of this problem is that

  1. QWebEngineView uses QQuickWidget which uses OpenGL, OpenGL context is associated with the top level window the widget reside in
  2. Thus setting parent to null causes problem with the GL texture creation, this can be fixed by using QStackedLayout that does not reset the parent
  3. But dragging the widget changes the top level window to the floating window. I notice that whenever a widget is dropped to one of the dock overlay, Qt emits "Compositor returned null texture" message. After this message, dragging the widget back to the previous QStackedLayout still results in white flashes.

At the end what works for me is setting [1]

QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL);

before creating QApplication. This eliminates flickering when using DockAreaLayout (but I still prefer QStackedLayout since it prevents resize event when switching tabs) and when moving widgets to different dock area. Since I'm using Windows, the default graphics API seems to be Direct3D.

[1] https://forum.qt.io/topic/148089/qopenglwidget-doesn-t-work-with-qquickwidget/3