<AWT Dev> Focus regression in Java8 caused by JDK-7160604
Clemens Eisserer
linuxhippy at gmail.com
Sun Nov 2 13:52:23 UTC 2014
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