-
Notifications
You must be signed in to change notification settings - Fork 700
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ContextMenu
accesses disposed MenuBar
#3678
Comments
It's already static:
and it's disposing here: Terminal.Gui/Terminal.Gui/Views/Menu/ContextMenu.cs Lines 106 to 121 in e95f821
My suggestion is calling |
I have a lot of questions and concerns regarding that static menubar reference. 🫤 I'll need to pull down the branch in its latest state to get a good look at it all, though, in case I'm missing key context. |
At a high level, the concern is based on the following rules of thumb regarding holding a reference to another object. Unless an object holding a reference to another object in any member field or property:
That is, unless (1 || 2 || 3) && 4 is true, then that reference should almost definitely not be static, especially in a library where that object and related types are in the visible API surface, via one or more code paths. |
The reason for the |
Hm. Thanks for the added context. That sounds like there's a more fundamental problem that we might not be managing the lifetime of the object(s?) properly. Making it static just addresses a symptom without fixing the underlying issue, though, while bringing in caveats that can be more difficult to address than tracking down and addressing the root problem, anyway. But again, I haven't pulled it yet since I'm in the middle of a few other things, at the moment, but I'll take a peek at whatever you have later, when I get to it. Turning a static member back into an instance member isn't usually that hard, so the risk of wasted effort is pretty low even if tweaks are needed. It may even end up not warranting a change at all, so certainly not worth waiting up for me if you're working on it right now. |
Some follow-up thoughts (if these have already been addressed, don't mind me): Do we really need to create and dispose the thing all the time, then? Can't we create one instance and just show it and hide it, instead, or similar. Seems perfectly reasonable to me that the context menu could be added to the view the application was started with, so that it fits into the current expected flow for views, no? Or it could be added to the view that had focus at the time. Something. And there's also the option key on most keyboards, or other programmatic methods by which someone may want to be able to open a context menu - not just the mouse. Those really should all share the same root code path, which would suggest to me that unconditionally operating on the state of the mouse is at least not ideal. |
ContextMenu is a hack. It works but it's a hack. In order to not have to have a hack like this, we need to get rid of So lets not worry about ContextMenu for now. Plus, the whole reason I invested in creating See I think the first step here is to actually do But it won't be possible until this is complete: |
Ahhh ok that makes things fall into place much better. Thank you. I was just about to get busy with tracing through it line by line, after shooting over a quick initial cleanup first (@BDisp - I sent you this PR for your convenience). I'll just mainly focus on the disposal, then, which should end up being a pretty small change overall, and of course any other of the usual little opportunistic cleanup bits that don't dirty up the PR too much, if the urge strikes in the process. 😅 |
And, side note, looks like y'all have fixed whatever had broken the tests from this, by the point I branched from, so 🥳 |
Actually... Know what? I'm getting tired and less effective, so should probably cease with code work for the night. Besides, the change to the disposal pattern, while technically "breaking" because it changes the type of one or more thrown exceptions, isn't a blocker that needs to hold up this PR being finished for merge. It can be dealt with in later cleanup and formalizing passes, as far as I'm concerned, now that my main worry about the way the rest of it operates is largely allayed. @BDisp, what I was trying to get across is that the application isn't the one who should be throwing that ODE. The view that has been disposed is the thing that is supposed to throw the exception, upon an attempt to call a method on it that won't have the expected effect due to the object being disposed. In the application class code, you would then follow the numbered steps in my earlier comment describing the ODE handling procedure. Ideally, that means hooking the application up to receive the Disposed event so it can just null the view out and then avoid the exception altogether with a simple null check. But you'd also want to make access to it thread-safe (need to anyway, but that's an additional reason why). |
Short version: IDisposables throw ODE about themselves. |
I know that not the only place that should be throwing the ODE. That why @tig is checking in some crucial places (properties and methods) if an object that was already disposed is being accessed. In |
To repo, change
Application.UngrabMouse()
:Run unit tests.
My suggestion is to refactor it to create
_menuBar
as astatic
and use_menuBar.Visible
and/or_menuBar.Enabled
to manage.The text was updated successfully, but these errors were encountered: