Cleaning up closed TCanvas


A very basic question here, experienced in 6.24.06 but assume present in other versions too.

I’ve been finding that when a TCanvas’s window is closed, the TCanvas can be left in a bit of a messed up state. If the ‘Draw’ method of the canvas is called again, nothing gets drawn (no window is recreated), and what’s more we get fatal errors when ROOT closes:

root [0] TCanvas c
(TCanvas &) Name: c1 Title: c1
root [1] c.Draw()
root [2] .q
2022-01-07 16:26:56.697 root.exe[97301:7565983] Fatal error: requested non-existing drawable 49
2022-01-07 16:26:56.697 root.exe[97301:7565983] This window not found among allocated/deleted drawables

Also if one does gROOT->GetListOfCanvases()->Print() after closing the canvas, you get a crash.

I was wondering if there’s a good way to clean up these closed canvases when they get closed? Or any advice for keeping things clean for interactive sessions?


We’ll investigate (maybe @couet ). BTW, which OS are you working on?

Thanks. This is MacOS 10.15

Having had some more time to think about this issue, I’m thinking it would also be helpful to be able to reopen a closed canvas, is that possible? So far the only way I’ve been able to make the canvas reappear is to do a DrawClone which isn’t really making the original canvas appear. But I also understand that closing a canvas appears to clear it’s primitive list so perhaps the graphical content of the canvas is lost at this point?

I do not see such problem on my Mac:

% root
  | Welcome to ROOT 6.27/01               |
  | (c) 1995-2021, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for macosx64 on Jan 10 2022, 08:20:57                      |
  | From heads/master@v6-25-02-28-g22f777ee32                        |
  | With Apple clang version 12.0.5 (clang-1205.0.22.9)              |
  | Try '.help', '.demo', '.license', '.credits', '.quit'/'.q'       |

root [0] TCanvas c
(TCanvas &) Name: c1 Title: c1
root [1] c.Draw()
root [2] .q

Hi Olivier. Did you close the TCanvas window between constructing it and drawing it?:

TCanvas c;
// close the window now

oops no … sorry. I see the same when I close the canvas

Is it really a problem ? Drawing a deleted canvas seems a bit weird ?
Do you have a use case for a sequence ?

I dont have a concrete case to describe to you - this thread was really about understanding clearly what is the intended state of a canvas that has been closed. As you can see, a closed canvas seems to behave as an unpleasant object, causing errors (or crashes: see gROOT->GetListOfCanvases()->Print() after closing - a quick look at the code for TPad::Close implies the canvas should remove itself from the list but it doesnt??).

If you ask what I would have hoped for, it would be that if I close a TCanvas that the canvas remains a valid object (none of its primitives are deleted), and that calling Draw on the canvas another time would make the window reappear and redraw everything.

Instead I get the impression that a closed TCanvas should be seen like ‘Zombie’ object (it’s deleted all its primitives and got itself into an invalid state), but at the moment it’s a Zombie with teeth - biting me in places I wouldn’t expect it to, rather than just as some object that is waiting to die but otherwise is harmless.

Does that make any sense?

When the canvas is closed with the Close() command, the error shows up immediately at the Draw time which seems the correct behaviour. It looks like the “Close Button” is the problem, as when we use it the error shows up only at the .q time. I am not sure what this button is doing. May be @bellenot knows ?

root [0] TCanvas c
(TCanvas &) Name: c1 Title: c1
root [1] c.Close()
root [2] c.Draw()
2022-01-10 14:20:06.892 root.exe[84230:1787793] Fatal error: requested drawable 49 is not found among currently valid drawables.
2022-01-10 14:20:06.892 root.exe[84230:1787793] Fatal error: requested non-existing drawable 49
2022-01-10 14:20:06.892 root.exe[84230:1787793] This window not found among allocated/deleted drawables
root [3] .q

The same is true for the other issue …

root [0] TCanvas c
(TCanvas &) Name: c1 Title: c1
root [1] c.Close()
root [2]  gROOT->GetListOfCanvases()->Print()
Collection name='Canvases', class='TList', size=0
root [3] 

… does not crash
Whereas if one replace c.Close() by a clicking the “close” button then you get a crash (as you said). Again it seems the “close” button does not really do a Close().

Here is what’s happening when closing the Window (only the relevant part):

   Disconnect(fCanvas, "ProcessedEvent(Int_t, Int_t, Int_t, TObject*)",
              this, "EventInfo(Int_t, Int_t, Int_t, TObject*)");


Ok, it does not seem there is a fCanvas->Close() in that code.
Where is this code to test is adding a Close() would fix the problem ?

But be careful, this code is also called by TCanvas::Close()

Ok Thanks. May be TCanvas::Close() does more …

So what are we concluding here? I mean, it does feel sensible that closing the TCanvas window should call Close(), no?

I would suggest to open a Github issue for that case

@will_cern can you open the issue as @bellenot suggested ?

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.