QtRoot 5.34 and X11 errors

Hi,

We are having problems with one of out Qt applications (running native Qt event loop) which
also displays ROOT histograms in ROOT canvas. In some cases it generates loads of messages
with X11 errors, like:

X Error: BadDrawable (invalid Pixmap or Window parameter) 9
  Major opcode: 55 (X_CreateGC)
  Resource id:  0x0
X Error: BadDrawable (invalid Pixmap or Window parameter) 9
  Major opcode: 55 (X_CreateGC)
  Resource id:  0x0
X Error: BadGC (invalid GC parameter) 13
  Major opcode: 60 (X_FreeGC)
  Resource id:  0x0
X Error: BadGC (invalid GC parameter) 13
  Major opcode: 60 (X_FreeGC)
  Resource id:  0x0
X Error: BadDrawable (invalid Pixmap or Window parameter) 9
  Major opcode: 55 (X_CreateGC)
  Resource id:  0x0
X Error: BadDrawable (invalid Pixmap or Window parameter) 9
  Major opcode: 55 (X_CreateGC)
  Resource id:  0x0
X Error: BadGC (invalid GC parameter) 13
  Major opcode: 56 (X_ChangeGC)
  Resource id:  0x0
... and so on

This usually happens when opening ROOT context menu and selecting one of the entries there, e.g. Inspect
or SetLineAttributes. I tried to debug it but could not see any obvious issues in our code. Looking at the
backtrace in debugger I think what happens is that QtRoot tries to draw on Qt widgets that have not been
mapped to X11 display (hence “Resource id: 0x0” in the messages). This could be related to how events
are processed in QtRoot, I have a suspicion that order of the events may be different from pure-ROOT
event loop.

This is observed with CERN-installed ROOT v5.36.13. I made simple test application which reproduces this
error in a few lines of code:

#include <QtGui/QApplication>
#include <TROOT.h>
#include <TQtWidget.h>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    TQtWidget::InitRint(false, "test_qtroot", &argc, argv);

    gROOT->Inspect();

    return app.exec();
}

and a Makefile:

QTDIR = /afs/cern.ch/sw/lcg/external/qt/4.8.4/x86_64-slc6-gcc47-opt
ROOTSYS = /afs/cern.ch/sw/lcg/app/releases/ROOT/5.34.13/x86_64-slc6-gcc47-dbg/root

CXXFLAGS = -I$(QTDIR)/include $(shell $(ROOTSYS)/bin/root-config --cflags)
LDLIBS = $(shell $(ROOTSYS)/bin/root-config --libs) -lQtRoot -L$(QTDIR)/lib -lQtCore -lQtGui

test_qtroot: test_qtroot.cc

Make sure that you set ROOTSYS, QTDIR and LD_LIBRARY_PATH in your shell before you run executable.

Could someone help us to find workaround for this issue?

Another less urgent thing is that QtRoot prints some weird messages to a terminal:

** $Id$ this=0x1d80360
Symbol font family found:  "Standard Symbols L" 
 Font metric w =  148  h =  14 points= 0 pixels= 12 QFont( "Arial,0,12,0,80,0,0,0,0,0" ) 
TGQt::ClearArea: ***   wrong client are size:  0  :  0 

Would be nice to get rid of those, they end up in the logs and confuse people.

Thanks,
Andy

we will try to reproduce this.

Is there any update on this?

Andy

No… sorry … Qt is not a priority.
Could it be that your Qt version has problems ?
Does it work before with older ROOt versions ? With which Qt version ?
I will tell the author of the Qt code … he may have ideas…

We did not see this problem during Run1 and at that time we used ROOT 5.30.05 with Qt 4.6.3 (on SLC5).
I do not observe any issues with pure Qt applications, it’s ROOT+Qt combination which shows errors.
I’ll try to test my code with different ROOT/Qt versions to maybe find version where it started to happen.

Hi, Olivier has asked me to comment this issue. For years I have been maintaining one thing: to run smoothly under QtRoot it is essential to get the Qt API based implementation for the Root context menu. This implementation is available from sourceforge.net/p/qtroot/wiki/Home/. HTH

Hi Valeri,

if this is so essential, would it make sense to move it into QtRoot itself? I’d be happy to have it built for myself but it’s too much trouble to have it installed and supported for major experiment.

Andy

I was actually incorrect above about not seeing these errors in ROT 5.30. During Run1 we had different implementation of the application which now generates these errors. I have built my simple test with ROOT 5.30 and now I see the same stream of errors, so it looks like earlier versions of ROOT are also affected. I also tested it with ROOT 6.00.02 and I still see the same errors (later ROOT6 versions on AFS do not have QtRoot built).
I spent some time in debugger trying to figure out what happens, my impression is that there is some race condition between ROOT and Qt even loops which causes drawing operations to be done on X11 windows that have not been mapped yet. This only happens when main even loop is controlled by Qt (QApplication::exec() like in my example above). If I switch to TApplication::Run() for the main event loop these messages go away. For our application I prefer to run Qt event loop, this is purely (or mainly) Qt application which only occasionally needs to show ROOT histograms, so I’d like to avoid polluting it with too many ROOT dependencies.
I’d appreciate any further help with resolving this.

Hi Andy,

And what about simply embedding a TCanvas in your Qt application, as described here ?
Since you only need a TCanvas. It would be much simpler…

Cheers, Bertrand.

[quote=“andy.s”]
if this is so essential, would it make sense to move it into QtRoot itself? . . .Andy[/quote]I might misunderstood. My answer is ‘Yes’ (always was “Yes”).

If understood the Bertrand’s comment correctly he said the QtRoot is so simple that everybody (each experiment) can create his own TQtWidget correctly follow the receipt provided.

Frankly, I do not see that one approach contradicts another one. ROOT repository may provide some “default” correct implementation and, yes, everybody is smart enough and free to learn the examples and implement things themselves.

[quote=“fine”][quote=“andy.s”]
if this is so essential, would it make sense to move it into QtRoot itself? . . .Andy[/quote]I might misunderstood. My answer is ‘Yes’ (always was “Yes”). [/quote]

Well, I meant that it should be in the regular ROOT builds that we have on AFS and we would not need to build your qtroot version separately?

[quote=“fine”]
If understood the Bertrand’s comment correctly he said the QtRoot is so simple that everybody (each experiment) can create his own TQtWidget correctly follow the receipt provided. [/quote]

I think point of that example is that ROOT is so simple that you can integrate it with any other X11 toolkit. I do wish it was indeed true but I simply cannot believe it, sorry. Integrating two different event loops will never be simple because they very likely need some synchronization (e.g. to avoid TCanvas drawing on X11 window that has not been mapped yet) and timer-based “synchronization” is not enough here.

I tried to adapt the example from the above link (it is not really an example for Qt, but for some other toolkit) and got a result which is not really usable. One thing is that it produces error messages similar to what I saw already with QtRoot:

Error in <RootX11ErrorHandler>: BadWindow (invalid Window parameter) (XID: 33554651, XREQ: 2)
Error in <RootX11ErrorHandler>: BadWindow (invalid Window parameter) (XID: 33554651, XREQ: 61)
Error in <RootX11ErrorHandler>: BadDrawable (invalid Pixmap or Window parameter) (XID: 33554651, XREQ: 14)
Error in <RootX11ErrorHandler>: BadWindow (invalid Window parameter) (XID: 33554651, XREQ: 40)
Error in <RootX11ErrorHandler>: BadDrawable (invalid Pixmap or Window parameter) (XID: 33554651, XREQ: 62)
Error in <RootX11ErrorHandler>: BadWindow (invalid Window parameter) (XID: 33554651, XREQ: 2)
Error in <RootX11ErrorHandler>: BadDrawable (invalid Pixmap or Window parameter) (XID: 33554651, XREQ: 62)
Error in <RootX11ErrorHandler>: BadWindow (invalid Window parameter) (XID: 33554651, XREQ: 2)

These happen in constructor of TCanvas, I believe that TCanvas needs its X11 window to be mapped already and this is something that I don’t really know how to control with Qt. Besides these messages the canvas is not very usable because it does not correctly redraw itself when pop-up menus disappear leaving ugly blank areas.

Another issue is that example is just broken, I had to spend a lot of time to just figure out how to make it work without hanging or interacting correctly with mouse (with very poor result). I guess all this is supposed to be handled by QtRoot which I’d prefer to use if it was working. There is actually another very serious issue with QtRoot filed while ago (sft.its.cern.ch/jira/browse/ROOT-4032) which we need to be fixed, it also makes QtRoot applications unusable and unresponsive.

Hi Andy,

Here is a very simple Qt example, just to show it is not that complicated… (simply cd simple_canvas, type qmake, then make). simple_canvas.tar.gz (2.4 KB)Hope this will help…

Cheers, Bertrand.

Hi Bertrand,

thanks a lot for example, it helped me to debug things and understand better what happens.

My code was actually very close to what your example does but your example does not show X11 errors. This apparently happens due to different X11 error handlers being installed and this depends on the order of initialization of ROOT and Qt. In my code Qt app was created first and ROOT app later, with ROOT X11 error handler being used as a result. ROOT handler prints all X11 errors that it sees, and you can see them in my post above. In your example the order is opposite, ROOT app is created first and Qt app later, this makes Qt X11 error handler being installed. Qt handler is apparently “smarter” and it masks some X11 error. This is why you do not see them, but still those errors are happening and they are caused by TCanvas code doing some operations on non-mapped X11 windows. You can test it with your example by reversing order of QApplication and TApplication.

Thre are other interesting issues that I observed with your example, one is that canvas areas are not always being redrawn after being hidden behind other windows (just put some other window on top of canvas and then bring canvas on top again). There is a picture of the effect in attachment:



I think I managed to get around this issue by adding setAttribute(Qt::WA_OpaquePaintEvent, true); to the canvas widget. I’m not sure that this cures the problem completely, I believe I saw something like that even after adding the flag (hard to reproduce now).

Another issue that I could not fix is canvas resizing behavior after maximizing and restoring canvas window, see another attachment:



This happens after I maximize window with my window manager (canvas is correctly resized to fill whole area) and then restore it to original size, at which point canvas show a part of the large canvas. Eventually it gets resized to normal size if you do something that causes canvas redraw (e.g. minimize/restore).

SO this embedding is still not perfect, I do not know if this is because of fundamental issues of two event loops running without synchronization or maybe just an artifact of some issues inside TCanvas (we know that does some things that cause x11 errors).

I’m still interested to get QtRoot working as it should, would appreciate any help with that (especially with fixing JIRA ticket).

Cheers,
Andy

[quote=“andy.s”]
if this is so essential, would it make sense to move it into QtRoot itself? . . .Andy[/quote]Sorry, I may be misunderstood. Did you mean the QtRoot from CERN distribution ? Did you ask me? The answer is ‘Yes’ (always was “Yes”).

If understood the Bertrand’s comment correctly he said the QtRoot is so simple that everybody (each experiment) can create his own TQtWidget correctly follow the receipt provided.

Frankly, I do not see that one approach contradicts another one. ROOT repository may provide some “default” implementation and yes everybody are smart enough and free to learn the examples and implement things themselves.

[quote=“andy.s”] . . .
SO this embedding is still not perfect, I do not know if this is because of fundamental issues of two event loops running without synchronization or maybe just an artifact of some issues inside TCanvas (we know that does some things that cause x11 errors). . .
[/quote] This is because there is a big difference between the “events” Qt and ROOT event loop process.
Qt event loop processes the QtEvent, ROOT does the X11 events. (from your application stand point. You may forget at this point that Qt does process X11 too). All main troubles come from this fundamental difference.

One example:

“Right mouse button click” + what is that? For ROOT event loop it is “Right mouse button click” event to process. The Qt event loop is to be feed with the “ContextMenuRequest”. The Context Menu request is to invoke some Qt “default Context Menu handler”. To make it right within Qt/ROOT GUI mashup this “default behavior” has to be suppressed and the original “right mouse button click” event has to be RESTORED and re-injected into event loop to be processed again. etc.? I hope ROOT team can restore the links to my >1000 forum posts on this issue.
HTP. Valeri Fine

Sorry for confusion, and yes, I meant whatever is distributed as a part of ROOT. CERN distribution is built from released ROOT sources, and this is what most people at CERN and outside are using. Would be nice if QtRoot that comes with released ROOT source had everything needed to make it work reliably.

Well, nothing is quite simple, I had to spend a lot of time to make it kind of work and still there are issues with it that I’m not sure that anyone can solve.

My point is that the default implementation should be usable, currently it’s not. Whatever comes as a default with ROOT is not really working for us. One problem that started this ticket is X11 errors, another is sft.its.cern.ch/jira/browse/ROOT-4032 (and it did not see much attention).

[quote=“fine”]This is because there is a big difference between the “events” Qt and ROOT event loop process.
Qt event loop processes the QtEvent, ROOT does the X11 events. (from your application stand point. You may forget at this point that Qt does process X11 too). All main troubles come from this fundamental difference.[/quote]
I’m not sure that this is the reason in this particular case. I verified that when I maximize and then restore canvas window its widget correctly receives resize events and in those event handlers we call canvas’ Resize() followed by Update(). The thing that looks suspicious is that Resize() does not require any dimensions passed to it so my guess is it takes dimensions from X11 window. But Qt does not say anything about state of the corresponding X11 window when it calls event handlers for Qt widgets. It could happen that X11 window still has old dimensions when Qt calls handler (or may be even in unusable state), if that is true then there is a mismatch between what TCanvas class expects and what Qt can provide.

Cheers,
Andy

Hi Andy,

To solve the maximize/restore issue, simply add this method (e.g. for the example code I sent):

//______________________________________________________________________________ void QMainCanvas::changeEvent(QEvent * e) { if (e->type() == QEvent ::WindowStateChange) { if (canvas->getCanvas()) { canvas->getCanvas()->Resize(); canvas->getCanvas()->Update(); } } }
Cheers, Bertrand.

[quote=“bellenot”]Hi Andy,

To solve the maximize/restore issue, simply add this method (e.g. for the example code I sent):

//______________________________________________________________________________ void QMainCanvas::changeEvent(QEvent * e) { if (e->type() == QEvent ::WindowStateChange) { if (canvas->getCanvas()) { canvas->getCanvas()->Resize(); canvas->getCanvas()->Update(); } } }
Cheers, Bertrand.[/quote]Did you try that on Windows :unamused: ?

[quote=“andy.s”] if that is true then there is a mismatch between what TCanvas class expects and what Qt can provide.[/quote]That is true. I did arrive at the same conclusion 10 years ago #-o Bertrand’s approach works well for the “passive” widget, for example to stream the video into the video player GUI. One watches the video and interact with the surrounding video player GUI. Video player can resize the video frame and refresh it.