<AWT Dev> Focus regression in Java8 caused by JDK-7160604

Anton V. Tarasov anton.tarasov at oracle.com
Wed Nov 5 13:32:38 UTC 2014


Hi Clemens,

I can't say exactly how the fix for JDK-7160604 could change the behavior like you described (this 
requires some more time to investigate).
However, an obvious question comes to my mind - why don't you make your popup non-focusable? I 
suppose you manage navigation through the content of your "auto-completion list" somehow by 
intercepting the up/down keys on the textfiled, right? In that case, you don't need your popup be a 
focusable component. Does it work for you?

Also, just a side note. As a straightforward workaround to the focus issue, you could invoke your 
requestFocus later, either via calling invokeLater() or by invoking it at the time the popup is 
shown (I'm not sure you can listen for the componentShown(), but at least, you can listen for 
focusGained() on its content). This would make the things happen in a fixed order: popup_show then 
request_focus. (Currently, it seems the order is broken somehow.) But still, making the popup simply 
non-focusable looks better.

Regards,
Anton.

On 02.11.2014 17:52, Clemens Eisserer wrote:
> HI,
>
> Starting with the rollout of Java8 via the auto-updater we received
> several reports that one of our applications has servere focus issues.
> The application registers a KeyListener on a JTextField showing an
> auto-completion JPopupMenu every time a character is typed.
>
> Every time a key is typed, the following sequence is run:
> - Hide existing JPopupMenu in case there is one
> - Create new JPopupMenu and populate with contents (in this case a JTable)
> - JPopupMenu.show() below the JTextField which caused the keyTyped-event
> - JTextField.requestFocus(), so the user can continue typing.
>
> I've created a self-contained testcase available here:
> http://pastebin.com/GEQ1ZW28
>
> This worked fine with Java6 & Java7, however since JDK8-b119 it failes
> when the popup is heavyweight - for lightweight popups it still
> succeeds (unfourtunately, we need heavyweight ones).
>
> I tried to analyze what happend and registered a global focus listener:
>
> This is the focus-history without the fix for JDK-7160604 - once the
> JTextField got it's focus no changes can be observed, despite new
> JPopups are being opened:
> javax.swing.JTextField[,241,115,197x19,...
> javax.swing.JRootPane[,5,27,955x384,.....
> javax.swing.JTextField[,241,115,197x19,... (focus stays here, despite
> new JPopups are beeing opened and old ones closed)
>
> With the fix, the focus history looks like this:
> javax.swing.JTextField[,241,115,197x19,....
> javax.swing.JTextField[,241,115,197x19,....
> javax.swing.JRootPane[,5,27,938x588,...(focus stays here, no further
> keyEvents are received by the JTextField)
>
>
> Beside some refactorings, the only functional change I can spot is
> that the order of the assignment of the "popup"-member and
> popup.show() have changed in JPopupMenu.showPopup():
>
>
>          Popup newPopup = getUI().getPopup(this, desiredLocationX,
>                                            desiredLocationY);
>
>          popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP);
>          popup = newPopup;
>          newPopup.show();
>
> If I change the order of newPopup.show() and popup=newPopup, the old
> behaviour is restored.
> At least it looks somehow suspicious the original author introduced a
> variable "newPopup" (and the patch still uses it without a good
> reason, "popup" could be assigned directly), so at first sight it
> looks intentional to assign popup only after show() was called.
>
> During the call to newPopup.show() the method JPopupMenu.isVisible()
> is called several times.
> Before the fix for JDK-7160604 it would return false, now it returns
> true - the focus issue mentioned is triggered by returning "true" at
> the following call-stack (full one available at
> http://pastebin.com/4qG8h7Td).
>
>          at javax.swing.JPopupMenu.isVisible(JPopupMenu.java:854)
>          at javax.swing.SortingFocusTraversalPolicy.enumerateCycle(SortingFocusTraversalPolicy.java:141)
>          at javax.swing.SortingFocusTraversalPolicy.enumerateCycle(SortingFocusTraversalPolicy.java:156)
>          at javax.swing.SortingFocusTraversalPolicy.enumerateCycle(SortingFocusTraversalPolicy.java:156)
>          at javax.swing.SortingFocusTraversalPolicy.enumerateCycle(SortingFocusTraversalPolicy.java:156)
>          at javax.swing.SortingFocusTraversalPolicy.enumerateCycle(SortingFocusTraversalPolicy.java:156)
>          at javax.swing.SortingFocusTraversalPolicy.enumerateAndSortCycle(SortingFocusTraversalPolicy.java:135)
>          at javax.swing.SortingFocusTraversalPolicy.getFocusTraversalCycle(SortingFocusTraversalPolicy.java:110)
>          at javax.swing.SortingFocusTraversalPolicy.getFirstComponent(SortingFocusTraversalPolicy.java:445)
>          at javax.swing.LayoutFocusTraversalPolicy.getFirstComponent(LayoutFocusTraversalPolicy.java:166)
>          at javax.swing.SortingFocusTraversalPolicy.getDefaultComponent(SortingFocusTraversalPolicy.java:535)
>          at java.awt.Window.isFocusableWindow(Window.java:2496)
>
> If I introspect the call-stack and return "false" only when
> "enumerateCycle" is contained in the stack, everything works again.
> So from what I understand the JPopupMenu would never receive focus
> before the fix, because during show() it wasn't believed to be
> visible.
>
> What I wonder, is the code in the testcase even supposed to work - or
> did it just because of an accident?
> Also a mystery remains why the JPopupMenu has to contain a JTable to
> trigger the issue - with a JLabel everything works like it ever did.
>
> Thank you in advance, Clemens



More information about the awt-dev mailing list