Discussion:
QWindow::setTransientParent()
(too old to reply)
John Weeks
2014-11-07 01:05:29 UTC
Permalink
Can anyone tell me about QWindow::setTransientParent()? When building with Qt 5 I keep seeing warnings:

void QWindow::setTransientParent(QWindow *) QWidgetWindow(0x118c39a10, name = "QWidgetClassWindow") must be a top level window.

One situation where I see it is on Macintosh:

Our application can make a 3D graph window that uses OpenGL calls to draw. The OpenGL context is implemented via a QGLWidget. The QGLWidget is contained in a QWidget that is itself contained in a QWidget that is (usually) a top-level window.

I see the warning when calling new QMenu(QGLWidget *). Here's a (truncated) stack trace (GizmoWD is our class, of course):

0 QWindow::setTransientParent(QWindow*) qwindow.cpp 1131 0x10969ac1a
1 QWidgetPrivate::setParent_sys(QWidget*, QFlags<Qt::WindowType>) qwidget.cpp 10516 0x10898b528
2 QWidget::setParent(QWidget*, QFlags<Qt::WindowType>) qwidget.cpp 10375 0x108971b07
3 QWidgetPrivate::init(QWidget*, QFlags<Qt::WindowType>) qwidget.cpp 1179 0x10896fe3c
4 QWidget qwidget.cpp 1026 0x1089701a9
5 QMenu qmenu.cpp 1333 0x108b3468f
6 QMenu qmenu.cpp 1336 0x108b3460d
7 GizmoWD::init(char const*, int) GizmoWD.cpp 90 0x100cb58f9
8 doNewGizmo(GizmoWD**, char const*, char*, wDataClass*, wdChildInfo::hostRectType, WMRect*, int, int, int) GizmoBuiltInOps.cpp 279 0x100c81f7a

In tracing into this, I see that QGLWidget requires a WinID. The QWindow * being passed to setTransientParent() is the QGLWidget. The QWindow whose setTransientParent() method was called is the QMenu.

I haven't seen any obvious problems that I can trace to this, but maybe I'm missing something.


I also see it on Windows in some other situations.


My apologies for a somewhat vague and abstruse question. I'm trying to understand the warning, but I don't have an obvious place to start. Thanks for any light you can shed!

-John
Rutledge Shawn
2014-11-07 08:13:23 UTC
Permalink
On 7 Nov 2014, at 02:05, John Weeks <***@wavemetrics.com> wrote:

> Can anyone tell me about QWindow::setTransientParent()? When building with Qt 5 I keep seeing warnings:
>
> void QWindow::setTransientParent(QWindow *) QWidgetWindow(0x118c39a10, name = "QWidgetClassWindow") must be a top level window.
>
> One situation where I see it is on Macintosh:
>
> Our application can make a 3D graph window that uses OpenGL calls to draw. The OpenGL context is implemented via a QGLWidget. The QGLWidget is contained in a QWidget that is itself contained in a QWidget that is (usually) a top-level window.
>
> I see the warning when calling new QMenu(QGLWidget *). Here's a (truncated) stack trace (GizmoWD is our class, of course):
>
> 0 QWindow::setTransientParent(QWindow*) qwindow.cpp 1131 0x10969ac1a
> 1 QWidgetPrivate::setParent_sys(QWidget*, QFlags<Qt::WindowType>) qwidget.cpp 10516 0x10898b528
> 2 QWidget::setParent(QWidget*, QFlags<Qt::WindowType>) qwidget.cpp 10375 0x108971b07
> 3 QWidgetPrivate::init(QWidget*, QFlags<Qt::WindowType>) qwidget.cpp 1179 0x10896fe3c
> 4 QWidget qwidget.cpp 1026 0x1089701a9
> 5 QMenu qmenu.cpp 1333 0x108b3468f
> 6 QMenu qmenu.cpp 1336 0x108b3460d
> 7 GizmoWD::init(char const*, int) GizmoWD.cpp 90 0x100cb58f9
> 8 doNewGizmo(GizmoWD**, char const*, char*, wDataClass*, wdChildInfo::hostRectType, WMRect*, int, int, int) GizmoBuiltInOps.cpp 279 0x100c81f7a
>
> In tracing into this, I see that QGLWidget requires a WinID. The QWindow * being passed to setTransientParent() is the QGLWidget. The QWindow whose setTransientParent() method was called is the QMenu.
>
> I haven't seen any obvious problems that I can trace to this, but maybe I'm missing something.
>
>
> I also see it on Windows in some other situations.
>
>
> My apologies for a somewhat vague and abstruse question. I'm trying to understand the warning, but I don't have an obvious place to start. Thanks for any light you can shed!

I can reproduce it with qtbase/examples/opengl/legacy/hellogl like this:

void GLWidget::mousePressEvent(QMouseEvent *event)
{
lastPos = event->pos();
if (event->button() == Qt::RightButton) {
QMenu m(this);
m.addAction("test item");
m.exec(event->globalPos());
}
}

and the warning is in

void QWindow::setTransientParent(QWindow *parent)
{
Q_D(QWindow);
if (parent && !parent->isTopLevel()) {
qWarning() << Q_FUNC_INFO << parent << "must be a top level window.";
return;
}

which is harmless, right? Have you actually seen any behavior problems? But we shouldn’t emit needless warnings either. So I wrote up https://bugreports.qt-project.org/browse/QTBUG-42464

QGLWidget is obsolete, because it has the disadvantage of requiring its own platform window for the GL content to render into, which has caused various problems over the years. QOpenGLWidget (new in Qt 5.4) simplifies some things: Qt uses FBO tricks to composite the OpenGL content and the other widgets into a single window. So you should probably try to switch from QGLWidget to QOpenGLWidget.

setTransientParent just provides a hint that one window is a dependent of another, so that e.g. a dialog is to be shown centered over the main window. For a context menu’s popup window, maybe that should not be necessary at all, actually, because it has to set its position to be right next to the cursor: we can’t depend on the window manager to position it.
John Weeks
2014-11-07 17:02:09 UTC
Permalink
Thanks, Sean.

I have not seen any behavior problems associated with the warning. We actually see the warning on Windows more than on Macintosh. On Windows we run in an MDI window. In certain cases we need a winID in order to wrap native GUI elements (we allow customers to create plugins with windows). And we wrap lots of things in QMdiSubWindow to make them live inside the MDI window. That includes modeless dialogs, so we're wrapping QDialog in a QMdiSubWindow, and that is apt to trigger the warning. I also see the warning on Windows when the tooltip for the window title buttons appears.

As for QGLWidget being obsolete, we are using it because our port to Qt started five years ago(!). The OpenGL window is complex and we would like to avoid making intrusive changes at this late stage in the process. But if it is more or less a drop-in replacement, I guess we should look into it.

Again, thanks for the bug report. I didn't know enough about the situation to file one myself.

-John Weeks

On Nov 7, 2014, at 12:13 AM, Rutledge Shawn <***@theqtcompany.com> wrote:

>
> On 7 Nov 2014, at 02:05, John Weeks <***@wavemetrics.com> wrote:
>
>> Can anyone tell me about QWindow::setTransientParent()? When building with Qt 5 I keep seeing warnings:
>>
>> void QWindow::setTransientParent(QWindow *) QWidgetWindow(0x118c39a10, name = "QWidgetClassWindow") must be a top level window.
>>
>> One situation where I see it is on Macintosh:
>>
>> Our application can make a 3D graph window that uses OpenGL calls to draw. The OpenGL context is implemented via a QGLWidget. The QGLWidget is contained in a QWidget that is itself contained in a QWidget that is (usually) a top-level window.
>>
>> I see the warning when calling new QMenu(QGLWidget *). Here's a (truncated) stack trace (GizmoWD is our class, of course):
>>
>> 0 QWindow::setTransientParent(QWindow*) qwindow.cpp 1131 0x10969ac1a
>> 1 QWidgetPrivate::setParent_sys(QWidget*, QFlags<Qt::WindowType>) qwidget.cpp 10516 0x10898b528
>> 2 QWidget::setParent(QWidget*, QFlags<Qt::WindowType>) qwidget.cpp 10375 0x108971b07
>> 3 QWidgetPrivate::init(QWidget*, QFlags<Qt::WindowType>) qwidget.cpp 1179 0x10896fe3c
>> 4 QWidget qwidget.cpp 1026 0x1089701a9
>> 5 QMenu qmenu.cpp 1333 0x108b3468f
>> 6 QMenu qmenu.cpp 1336 0x108b3460d
>> 7 GizmoWD::init(char const*, int) GizmoWD.cpp 90 0x100cb58f9
>> 8 doNewGizmo(GizmoWD**, char const*, char*, wDataClass*, wdChildInfo::hostRectType, WMRect*, int, int, int) GizmoBuiltInOps.cpp 279 0x100c81f7a
>>
>> In tracing into this, I see that QGLWidget requires a WinID. The QWindow * being passed to setTransientParent() is the QGLWidget. The QWindow whose setTransientParent() method was called is the QMenu.
>>
>> I haven't seen any obvious problems that I can trace to this, but maybe I'm missing something.
>>
>>
>> I also see it on Windows in some other situations.
>>
>>
>> My apologies for a somewhat vague and abstruse question. I'm trying to understand the warning, but I don't have an obvious place to start. Thanks for any light you can shed!
>
> I can reproduce it with qtbase/examples/opengl/legacy/hellogl like this:
>
> void GLWidget::mousePressEvent(QMouseEvent *event)
> {
> lastPos = event->pos();
> if (event->button() == Qt::RightButton) {
> QMenu m(this);
> m.addAction("test item");
> m.exec(event->globalPos());
> }
> }
>
> and the warning is in
>
> void QWindow::setTransientParent(QWindow *parent)
> {
> Q_D(QWindow);
> if (parent && !parent->isTopLevel()) {
> qWarning() << Q_FUNC_INFO << parent << "must be a top level window.";
> return;
> }
>
> which is harmless, right? Have you actually seen any behavior problems? But we shouldn’t emit needless warnings either. So I wrote up https://bugreports.qt-project.org/browse/QTBUG-42464
>
> QGLWidget is obsolete, because it has the disadvantage of requiring its own platform window for the GL content to render into, which has caused various problems over the years. QOpenGLWidget (new in Qt 5.4) simplifies some things: Qt uses FBO tricks to composite the OpenGL content and the other widgets into a single window. So you should probably try to switch from QGLWidget to QOpenGLWidget.
>
> setTransientParent just provides a hint that one window is a dependent of another, so that e.g. a dialog is to be shown centered over the main window. For a context menu’s popup window, maybe that should not be necessary at all, actually, because it has to set its position to be right next to the cursor: we can’t depend on the window manager to position it.

-John
John Weeks
2014-11-21 22:12:59 UTC
Permalink
Shawn-

> QGLWidget is obsolete, because it has the disadvantage of requiring its own platform window for the GL content to render into, which has caused various problems over the years. QOpenGLWidget (new in Qt 5.4) simplifies some things: Qt uses FBO tricks to composite the OpenGL content and the other widgets into a single window. So you should probably try to switch from QGLWidget to QOpenGLWidget.

We have now done this, and it has solved a nagging problem we were having. Thank you!

There are a couple of things missing from QOpenGLWidget compared to QGLWidget: renderText() and renderPixmap().

We were using renderPixmap() to export graphics at resolution higher than what is displayed on-screen. And renderText() was being used for plotting data with text as the data point markers.

Are there alternatives to these for QOpenGLWidget?

-John Weeks
Agocs Laszlo
2014-11-24 08:55:29 UTC
Permalink
renderPixmap() can be replaced with a call to grabFramebuffer(). They both perform (potentially expensive) readbacks.

There is no direct replacement for renderText(). Then again renderText is pretty broken anyway when it comes to depth handling so it is best to avoid it even when using QGLWidget. One workaround would be to render the labels into a QImage and then use those as textures and draw quads at the correct position in the scene.

Best regards,
Laszlo

________________________________________
From: interest-bounces+laszlo.agocs=***@qt-project.org <interest-bounces+laszlo.agocs=***@qt-project.org> on behalf of John Weeks <***@wavemetrics.com>
Sent: Friday, November 21, 2014 11:12 PM
To: ***@qt-project.org
Subject: Re: [Interest] QWindow::setTransientParent()

Shawn-

> QGLWidget is obsolete, because it has the disadvantage of requiring its own platform window for the GL content to render into, which has caused various problems over the years. QOpenGLWidget (new in Qt 5.4) simplifies some things: Qt uses FBO tricks to composite the OpenGL content and the other widgets into a single window. So you should probably try to switch from QGLWidget to QOpenGLWidget.

We have now done this, and it has solved a nagging problem we were having. Thank you!

There are a couple of things missing from QOpenGLWidget compared to QGLWidget: renderText() and renderPixmap().

We were using renderPixmap() to export graphics at resolution higher than what is displayed on-screen. And renderText() was being used for plotting data with text as the data point markers.

Are there alternatives to these for QOpenGLWidget?

-John Weeks
John Weeks
2014-11-24 17:12:02 UTC
Permalink
> renderPixmap() can be replaced with a call to grabFramebuffer(). They both perform (potentially expensive) readbacks.

Thanks Laszlo.

The expense is probably OK, since this is for exporting graphics as a file or on the clipboard. But grabFramebuffer() gives you the same resolution as on screen, and we need hi-res export.

I ran across some code in a JIRA bug using QGLFramebufferObject; I see there is also QOpenGLFramebufferObject so I guess we can use the same technique.

-John Weeks
Agocs Laszlo
2014-11-25 09:00:21 UTC
Permalink
Hi John,

Right. grabFramebuffer() won't suffice since you need to specify a custom size. So use your own QOpenGLFramebufferObject with the desired size and then call toImage(), similarly to this:

w.makeCurrent(); // w is a QOpenGLWidget
QOpenGLFramebufferObject fbo(size, QOpenGLFramebufferObject::CombinedDepthStencil);
fbo.bind();
... // draw
fbo.release();
img = fbo.toImage();

Cheers,
Laszlo

________________________________________
From: interest-bounces+laszlo.agocs=***@qt-project.org <interest-bounces+laszlo.agocs=***@qt-project.org> on behalf of John Weeks <***@wavemetrics.com>
Sent: Monday, November 24, 2014 6:12 PM
To: interest
Subject: Re: [Interest] QWindow::setTransientParent()

> renderPixmap() can be replaced with a call to grabFramebuffer(). They both perform (potentially expensive) readbacks.

Thanks Laszlo.

The expense is probably OK, since this is for exporting graphics as a file or on the clipboard. But grabFramebuffer() gives you the same resolution as on screen, and we need hi-res export.

I ran across some code in a JIRA bug using QGLFramebufferObject; I see there is also QOpenGLFramebufferObject so I guess we can use the same technique.

-John Weeks
Loading...