wxWidgets / Phoenix

wxPython's Project Phoenix. A new implementation of wxPython, better, stronger, faster than he was before.
http://wxpython.org/
2.33k stars 515 forks source link

AuiManager creates bogus top level windows #1662

Open carandraug opened 4 years ago

carandraug commented 4 years ago

Operating system: GNU/Linux Debian 10.4 wxPython version & source: PyPI 4.1.0 gtk3 (phoenix) wxWidgets 3.1.4 Python version & source: Python 3.7.3 as distributed by Debian

When using AuiManager, a hidden top level frame is created. Here's the minimal code to replicate the issue (to keep the example minimal I omit the whole handling of UnInit the AuiManager which is why errors will also appear at exit):

import wx
import wx.aui
app = wx.App()
frame = wx.Frame(None)
auimanager = wx.aui.AuiManager(frame)
frame.Show()
print(wx.GetTopLevelWindows())
app.MainLoop()

which prints (note there are two frames):

WindowList: [<wx._core.Frame object at 0x7fde6f5015e8>, <wx._core.Frame object at 0x7fde6cf1fc18>]
swt2c commented 4 years ago

I do see that too. Is it a problem, though? Same thing happens in Classic so it is probably something happening in wxWidgets itself.

carandraug commented 4 years ago

I do see that too. Is it a problem, though?

Yes. I want to get a list of all available windows to create menu to hide/show them.

Same thing happens in Classic so it is probably something happening in wxWidgets itself.

I can confirm this. I just built wxWidgets from source and found the problem there too. I have reported an issue to them https://trac.wxwidgets.org/ticket/18784 Should it be closed here, then?

swt2c commented 4 years ago

You can leave it open so that if there's a fix needed in wxWidgets that Robin can update the subproject commit and bring the fix here.

infinity77 commented 4 years ago

I am not sure it is an issue at all. This is the way the wxWidgets version of AUI works, by creating a hidden frame to provide a “docking hint” while you’re about to dock a floating pane. If this is not satisfactory, then you may try to use the pure-Python version of AUI which shouldn’t have that issue if you pass it the right flags.

Alternatively, an argument might be made that the hidden frame providing the docking hint should not be created straight away and kept around hidden, but rather it should be created, shown and then destroyed. I am unclear if the wxWidgets guys will accept something like that but I believe they will be more keen if you provide a ready-to-apply patch to wxAUI.

That said, it seems to me it’s a lot of work for very little gain: since you are the developer of your app, you can always loop through all your toplevel windows and check if any of them is an instance of wx.aui.AuiHintDockWindow (or whatever is its name) and skip doing stuff to it.

carandraug commented 4 years ago

That said, it seems to me it’s a lot of work for very little gain: since you are the developer of your app, you can always loop through all your toplevel windows and check if any of them is an instance of wx.aui.AuiHintDockWindow (or whatever is its name) and skip doing stuff to it.

The hint window is just an instance of wx.Frame (at least on the wxWidgets implementation, not sure of the pure-python implementation) so that won't work.

Anyway, I understand now that the AuiManager makes use of a top level window to work but if that's the case, how does one get the "real" list of top level windows? Shouldn't functions like wx.GetTopLevelWindows handle that then?

infinity77 commented 4 years ago

Ah, yes, I naively thought they would create a separate class for it, but I was mistaken. Then I guess the best bets you have is to keep your own list of toplevel windows or find a way to differentiate your frames from the ones in AUI or try the Python version or provide a patch to the C++ guys implementing the idea I highlighted above - or something along those lines. wx.GetTopLevelWindows is highly unlikely to get modified in my opinion...

carandraug commented 4 years ago

What I am doing now is to simply skip windows with an empty title:

real_tlws = [w for w in wx.GetTopLevelWindows() if w.Title]

It's a bit of an hack but seems to work so far.

wxWidgets recognizes there's something wrong the the current behaviour although it's difficult to specify exactly where.

Metallicow commented 4 years ago

@carandraug I've been doing "Bogus" window switcherooo stuff for years, but as Andrea says, being the developer of the app gives you a choice. It would be more proper to have a dedicated class for dummy windows, but sometimes what happens within those windows matter. I'm not sure to say either way.... On the python side you will deal with a lot of hackery, performace issues, or just bugs. Most of what is built-in python can be tested with their modules. https://github.com/Metallicow/timeit-tests

But yea, I have a few functions myself that checks for the right window, and yes it is odd, so until it is fixed properly, you might see such little things as a PITA. ...as long as you don't have problems sending a empty string, then you should be good......

RobinD42 commented 4 years ago

A safer test would be to check if the frames in the WindowList are instances of your frame classes.

Or another idea would be to use the little used name attribute of your frames.