diff --git a/CHANGELOG.md b/CHANGELOG.md index 92cff378..c9f7a1a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,12 +3,15 @@ FlatLaf Change Log ## 1.6.5-SNAPSHOT +#### Fixed bugs + - Linux: Fixed font problems when running on Oracle Java 8 (OpenJDK 8 is not affected): - oversized text if system font is "Inter" (issue #427) - missing text if system font is "Cantarell" (on Fedora) - MenuItem: Changed accelerator delimiter from `-` to `+`. (Windows and Linux). - +- ComboBox: Fixed occasional `StackOverflowError` when modifying combo box not + on AWT thread. (issue #432) ## 1.6.4 diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java index d991ee3a..8794c3d8 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java @@ -805,7 +805,9 @@ public class FlatComboBoxUI this.padding = padding; } - void install( Component c ) { + // using synchronized to avoid problems with code that modifies combo box + // (model, selection, etc) not on AWT thread (which should be not done) + synchronized void install( Component c ) { if( !(c instanceof JComponent) ) return; @@ -837,7 +839,7 @@ public class FlatComboBoxUI * there is no single place to uninstall it. * This is the reason why this method is called from various places. */ - void uninstall() { + synchronized void uninstall() { if( rendererComponent == null ) return; @@ -848,9 +850,9 @@ public class FlatComboBoxUI } @Override - public Insets getBorderInsets( Component c, Insets insets ) { + synchronized public Insets getBorderInsets( Component c, Insets insets ) { Insets padding = scale( this.padding ); - if( rendererBorder != null ) { + if( rendererBorder != null && !(rendererBorder instanceof CellPaddingBorder) ) { Insets insideInsets = rendererBorder.getBorderInsets( c ); insets.top = Math.max( padding.top, insideInsets.top ); insets.left = Math.max( padding.left, insideInsets.left ); diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatStressTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatStressTest.java new file mode 100644 index 00000000..58b39a48 --- /dev/null +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatStressTest.java @@ -0,0 +1,83 @@ +/* + * Copyright 2021 FormDev Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.formdev.flatlaf.testing; + +import java.awt.Container; +import java.awt.FlowLayout; +import java.util.Random; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; +import com.formdev.flatlaf.FlatClientProperties; +import com.formdev.flatlaf.FlatLightLaf; + +/** + * @author Karl Tauber + */ +public class FlatStressTest +{ + public static void main( String[] args ) { + SwingUtilities.invokeLater( () -> { + FlatLightLaf.setup(); + new FlatStressTest(); + } ); + } + + protected FlatStressTest() { + JFrame frame = new JFrame( "FlatStressTest" ); + frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); + + Container contentPane = frame.getContentPane(); + contentPane.setLayout( new FlowLayout() ); + + contentPane.add( createStressTest() ); + + frame.setSize( 800, 600 ); + frame.setLocationRelativeTo( null ); + frame.setVisible( true ); + } + + private JComponent createStressTest() { + return createComboBoxStressTest(); + } + + // for https://github.com/JFormDesigner/FlatLaf/issues/432 + // simulates StackOverflowError in FlatComboBoxUI when doing stuff in various threads + // + // requires adding `Thread.sleep( 1 );` to `FlatComboBoxUI.CellPaddingBorder.install()` + // after invocation of `uninstall()` + private JComponent createComboBoxStressTest() { + Random random = new Random(); + + JComboBox comboBox = new JComboBox<>(); + comboBox.putClientProperty( FlatClientProperties.MINIMUM_WIDTH, 0 ); + for( int i = 0; i < 100; i++ ) + comboBox.addItem( Integer.toString( random.nextInt() ) ); + + Thread thread = new Thread( () -> { + for(;;) { + comboBox.setSelectedIndex( random.nextInt( comboBox.getItemCount() ) ); + comboBox.putClientProperty( FlatClientProperties.MINIMUM_WIDTH, random.nextInt( 500 ) ); + } + }); + thread.setDaemon( true ); + thread.start(); + + return comboBox; + } +}