-
Notifications
You must be signed in to change notification settings - Fork 914
Improve Dialog Placement #5280
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
Improve Dialog Placement #5280
Conversation
if no focused component is found then use NbMainWindow. Change fallback for Utilities.findDialogParent to use NbMainWindow.
|
Doing the same steps, the problem (stemming from no focused component or window) is intermittent; I'm guessing timing. Happens more frequently when run under the debugger. The problem may be more likely to arise when using the jVi plugin. When the user does a vi colon command, a one line window, JDialog, is brought up for the command entry. Some jVi commands invoke actions which bring up a dialog. The one line window is disappearing while the NetBeans dialog is coming up. |
e33f093 to
9164e39
Compare
|
not sure if I will have time to take a deeper look at this before feature freeze. But I found a situation where the direct parent is not the optimal answer: the editor tab dropdown can close tabs. If the tab is unsaved a dialog will appear. This dialog's parent would be the popup which causes it open on the upper right area of the main window. This doesn't look horrible but its something to check. Simple yes/no dialogs should probably always open centered on the main window which might be the better default. |
| Window w = KeyboardFocusManager.getCurrentKeyboardFocusManager ().getActiveWindow (); | ||
| Frame f = w instanceof Frame ? (Frame) w : WindowManager.getDefault().getMainWindow(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a cosmetic change. It's both more clear and allows easier comparison to what's going on in the
if (descriptor instanceof DialogDescriptor) {
case
This is actually two tiny changes to handle corner cases where the "normal" situation doesn't apply. Adding some review comments to to clarify. |
| Frame[] f = Frame.getFrames(); | ||
| parent = f.length == 0 ? null : f[f.length - 1]; | ||
| // PR#5280 | ||
| parent = findMainWindow(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a change suggested by @matthiasblaesing in #4739 (comment). The change was deferred pending concrete examples. There is an example detailed in the opening comment for this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@errael I would possibly fall back to the original behaviour if the search for the main window returns null. Ideally it wouldn't use the name to find the right window, but that might be the easiest way to achieve. I have no idea how many people (if any!) use FileChoooserBuilder outside of the standard window system, but this will change the behaviour of those cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@errael I would possibly fall back to the original behaviour if the search for the main window returns null.
The original behavior is severely flawed. Take a look in the comment that opened this PR, under notes on Utilities.findDialogParent. And from the javadoc for Frame.getFrames()
Warning: this method may return system created frames, such as a shared, hidden frame which
is used by Swing. Applications should not assume the existence of these frames, nor should an
application assume anything about these frames such as component positions, LayoutManagers
or serialization.
Ideally it wouldn't use the name to find the right window, but that might be the easiest way to achieve.
Notice that this technique is already in use in this file. May have to do with dependencies. This PR encapsulates its use in a method so at least it's not buried.
I have no idea how many people (if any!) use
FileChoooserBuilderoutside of the standard window system, but this will change the behaviour of those cases.
If someone explicitly wants random dialog placement there are probably more interesting ways. I believe this case rarely comes up AFAIK, I've just been lucky.
A null owner is probably more consistent (better?).
If this is a strong concern for FileChooserBuilder, then suggest using a private version of findDialogParent() with the old code rather than propagate buggy behavior in a new-ish public API.
(Aside: I've wondered about use of non standard window system; are there any known examples in "production"? )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@errael yes, I read the doc. Let's stick with what you have and see if any complaints come out of the woodwork!
| Window w = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow(); | ||
| if( w == null ) { | ||
| // PR#5280 | ||
| LOG.fine( () -> "No focused window, find mainWindow" ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there is no focused window, then try the mainWindow before doing the backup which centers on the JDK's default screen.
Is this intermittent for you? I can't reproduce what you're seeing. I thought it might be because I use "focus follows mouse" but disabling that didn't change it. The Could be a OS/window manager issue. The close sequence starts with the following and notice the comment about focusing the top component before continuing. netbeans/platform/core.windows/src/org/netbeans/core/windows/actions/CloseWindowAction.java Lines 74 to 89 in cac7e65
The action does end up in |
@mbien, If you have a chance to check what is returned by at the first line of And it's something that doesn't make sense, something like Then I could try to address it. |
|
@matthiasblaesing Thanks for the info. Could you and @mbien provide OS/window manager info. I've been unable to reproduce this, see the last couple of messages I've posted. In particular, #5280 (comment) indicates some information I'd like to see (for example, collected with the debugger) that might provide some insight into what's going on. This behavior has been there for a long while (assuming it's the same thing Michael brought up) and doesn't have anything to do with this PR. |
matthiasblaesing
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My observation in the previous comment is reproducible, but it is also not caused by this change. The code in org.netbeans.core.windows.services.DialogDisplayerImpl is just not optimal, leading to the strange placement of the dialog. A quick test inserting:
presenter.setLocationRelativeTo(presenter.getOwner());before the setVisible(true) call, gives me sane centering over the main window. Not sure if that is desirable, but might be an option in the future to consider.
I checked what I got for the Window w / Frame f in line 255/256 and in both cases (editor pane in main window and editor pane in a separater window) I got the correect Window/JFrame objects I would have expected, not some popup.
@matthiasblaesing Wish I could reproduce it. Here's what the code does Note that the placement code in NbPresenter does not use the owner, DialogDisplayerImpl.AWTQuery.showDialog
XXX above could do what's being seen Here's what I tried, but can't reproduce Under the debugger
Observe |
| if( w == null ) { | ||
| // PR#5280 | ||
| LOG.fine( () -> "No focused window, find mainWindow" ); | ||
| for( Frame f01 : Frame.getFrames() ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: call findMainWindow ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
call
findMainWindow?
@sdedic I'd like to do that; can you give me some guidance? Need to find a non-API file in platform that's OK to access from both core.windows and openide.util.ui where it's appropriate to declare findMainWindow as a public method. Such a file must exist, any pointers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ;) my bad, I overlooked the module boundary. No suggestion that 'feels' right then. An option would be to add a API/SPI method on e.g. DialogDisplayer.
Related to existing 'nearby' code: this method uses KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow() while getCurrentGraphicsConfiguration() (in diff below) uses KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() then getWindowAncestor(). Deliberate difference or inconsistency ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've wondered about that myself; are the two equivalent?
I'm copying your comment to #4887 which are notes for a follow on PR addressing some stuff in Utilities. The opening comment of this PR mentions issues for the next PR.
|
In #5280 (comment) I said that the code in I'm taking a look at which seems to echo the noted behavior. In any event, knowing the arg in |
eirikbakke
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR looks fine to me, though I don't have deep knowledge of what's going on here. But it sounds like it's been extensively tested and discussed. Thanks for this PR!
|
There are two approvals, and someone wearing a release manager's hat said "Let's stick with what you have and see if any complaints come out of the woodwork!". I'll count that as 2+ approvals, no negatives. @mbien @sdedic (or @neilcsmith-net wearing a different hat) any further comments? Can this get merged? BTW, I think this PR will take care of several items I listed in #4887, I'll go through them all and see if they meet the criteria covered by this PR. The big revelation for me is that the layout decisions happen mostly in NbPresenter (with an occasional assist from openide.util.Utilities). I'll patch NB-17 release with this PR and keep my eyes open for follow on issues (I haven't been using NB lately). |
|
@matthiasblaesing @mbien I'm willing to consider the problem (not related to this PR) both of you can reproduce (and I can't). I think info gathered from There was some thought that it might be an issue with And #5280 (comment) might help in understanding what's going on. If you want/can open up a bug with some info (especially reproducability) I'd like to know about it. |
|
Lets get this in. |



When placing a dialog through NetBeans' API, if no focused component is found then use NbMainWindow. Change fallback for Utilities.findDialogParent to use NbMainWindow.
@matthiasblaesing , @neilcsmith-net , @mbien alerting since you made comments on previous PR.
This PR is a follow on to #4739. Wanted to open a bigger change earlier in the cycle, but... So this is a minimal change, hopefully more to come next cycle with detailed examination of cases from #4887.
There are situations where
And also related methods such as
getFocusOwner(),getActiveWindow()arenull.What happens is
NbPresenter.findFocusedWindow()returns null and the logic inNbPresenter.initBounds()ends up doingUtilities.findCenterBounds(size)which doesUtilities.getCurrentGraphicsConfiguration()and ends up on the default screen instead of a screen that NetBeans is on. The bigger change I've been thinking about addresses some issues withUtilities.getCurrentGraphicsConfiguration()and would put the dialog on the same screen as NetBeans is on, but even better is to have the dialog over the Window that NetBeans is in. This PR does that with a hack toNbPresenter.findFocusedWindow(); taken from Utilities.In
NbPresenter.initBounds(), can considerUtilities.findDialogParent()instead of the localfindFocusedWindow(), and then make sure that whatever's returned is a window. In any event, with this change the else clause is unlikely to ever be executed; just as well, notice the comment for the else clause:notes on Utilities.findDialogParent
There was some discussion in the dialog parent PR #4739 (comment) from last release about the
Utilities.findDialogParent()fallback. Investigation for this PR showed a situation where a fallback is needed, and the current fallback is not good.Frame.getFrames() comes from a Vector<WeakReference>; doing garbage collection shortens the array. Here's an example I saw, the fallback
selects the last item and is choosing something ripe for garbage collection. Notice in this case the 2nd entry is the main window.
These entries are like:
This PR makes the change to use the main window as fallback. This was previously proposed, but was deferred pending clarification on whether a fallback was needed at all.