-
Notifications
You must be signed in to change notification settings - Fork 35
Description
Discovered some issues with MenuTracker while working on MenuBarTests.cs.
I was trying to add some pre-conditions to the TestMenuOperations test, to be sure it had a clean slate to start from, but it fails that check unless it is run in isolation, because the other tests change things.
Upon investigation, I found the root(s) of the problem:
If Register is called on MenuTracker, the MenuBar is subscribed to three events.
However, there is nothing that can un-register them from those events, nor is there anything that can remove them from the bars
HashSet in MenuTracker.
Why are these issues problematic?
Well, for a couple reasons, unfortunately.
For one, it means that, if a menubar is deleted in the UI, it still exists with a path back to root, via the MenuTracker, and won't be collected by the GC.
That also means it is still alive and, if the events are raised, they are being called on the objects that should be gone.
Also, now that View is IDisposable, in v2, it exposes a potential runtime ObjectDisposedException or other potential issues, if anything happens once a MenuBar has been disposed, through any means.
The .Contains call in Register also checks if the menubar being registered is in the collection, but that's purely a reference equality, since no equality operator currently exists on MenuBar or any of its ancestor types. That has the potential to cause other weird problems in conjunction with the above problems, and would continue to compound and get weirder and weirder, as code is re-generated and re-compiled.
Proposed solution:
A few things, to address each part of the problem...
- Terminal.Gui really should expose a Disposing event on View, so that dependent objects can properly handle themselves when a View is disposed.
- This should likely be done before working on the rest of the fixes for this.
- We should provide an explicit UnRegister method to do the inverse of the Register method, at minimum.
- We should be sure to call that method when deleting a MenuBar.
- This may be un-fun, depending on how Redo and Undo are handled, which I haven't yet explored in the context of MenuBars.
- We should probably define a more formal means of determining equality between MenuBar items, at least in the
bars
collection, which can either be done in Terminal.Gui or, the probably better and less-impacting way, by having an appropriate IComparer in TGD to handle the HashSet. - Some other thoughts, but I need to let it simmer a bit to determine if they're relevant, especially once the above are handled.