From 58e073a05b7d548b0135727da8418ef6f156481e Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Mon, 1 Dec 2025 13:41:54 +0100 Subject: [PATCH] System File Chooser: on Linux when JavaFX is used in application, then always use Swing file chooser because system file dialog does work (PR #988) with Java 8, some GLib related messages are logged to console and system file dialog is not shown e.g.: `GLib-GObject-WARNING **: cannot register existing type 'GdkDisplayManager'` with Java 17, the system file dialog is shown, but then JavaFX no longer works with Java 21, the application quits/crashes immediately when trying to show system file dialog also fixed Error Prone warning in `getFiltersForDialog()` --- .../flatlaf/util/SystemFileChooser.java | 49 ++++++++++++++++++- .../testing/FlatSystemFileChooserTest.java | 6 +-- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/SystemFileChooser.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/SystemFileChooser.java index cf2dc857..105e9c5f 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/SystemFileChooser.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/SystemFileChooser.java @@ -22,9 +22,10 @@ import java.awt.SecondaryLoop; import java.awt.Toolkit; import java.awt.Window; import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -590,7 +591,7 @@ public class SystemFileChooser if( filters.size() == 1 && filters.get( 0 ) == getAcceptAllFileFilter() && (fileFilter == getAcceptAllFileFilter() || fileFilter == null) ) - return Collections.emptyList(); + return new ArrayList<>(); // check whether current filter is already in list if( (fileFilter != null && filters.contains( fileFilter )) || fileFilter == null ) @@ -1073,6 +1074,15 @@ public class SystemFileChooser private static class LinuxFileChooserProvider extends SystemFileChooserProvider { + @Override + public File[] showDialog( Window owner, SystemFileChooser fc ) { + // fallback to Swing file chooser if JavaFX is initialized + if( isFXinitialized() ) + return new SwingFileChooserProvider().showDialog( owner, fc ); + + return super.showDialog( owner, fc ); + } + @Override String[] showSystemDialog( Window owner, SystemFileChooser fc ) { boolean open = (fc.getDialogType() == OPEN_DIALOG); @@ -1175,6 +1185,41 @@ public class SystemFileChooser return buf.toString(); } + + private static Boolean fxinitialized; + + boolean isFXinitialized() { + if( fxinitialized != null ) + return fxinitialized; + + // check whether JavaFX is available + try { + Class.forName( "javafx.application.Platform", false, getClass().getClassLoader() ); + } catch( ClassNotFoundException ex ) { + // JavaFX is not available + fxinitialized = false; + return fxinitialized; + } + + // check whether JavaFX is initialized + try { + Class cls = Class.forName( "javafx.application.Platform" ); + Method m = cls.getMethod( "runLater", Runnable.class ); + m.invoke( null, (Runnable) () -> {} ); + fxinitialized = true; + return fxinitialized; + } catch( InvocationTargetException ex ) { + if( ex.getCause() instanceof IllegalStateException ) + return false; // JavaFX is available, but not (yet) initialized + } catch( Throwable ex ) { + // ignore + } + + // other error --> assume that JavaFX is not initialized + fxinitialized = false; + return fxinitialized; + } + //---- class LinuxApproveContext ---- private static class LinuxApproveContext diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserTest.java index adfd8ef2..2fc682a3 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserTest.java @@ -77,7 +77,7 @@ public class FlatSystemFileChooserTest FlatSystemFileChooserTest() { initComponents(); - if( !NativeJFileChooser.FX_AVAILABLE ) { + if( SystemInfo.isLinux || !NativeJFileChooser.FX_AVAILABLE ) { javafxOpenButton.setEnabled( false ); javafxSaveButton.setEnabled( false ); } @@ -231,7 +231,7 @@ public class FlatSystemFileChooserTest int fileTypeIndex = fileTypeIndexSlider.getValue(); if( !useAcceptAllFileFilterCheckBox.isSelected() ) fc.setAcceptAllFileFilterUsed( false ); - for( int i = 0; i < fileTypes.length; i += 2 ) { + for( int i = 0; i < fileTypes.length; i += 2 ) { fc.addChoosableFileFilter( "*".equals( fileTypes[i+1] ) ? fc.getAcceptAllFileFilter() : new SystemFileChooser.FileNameExtensionFilter( fileTypes[i], fileTypes[i+1].split( ";" ) ) ); @@ -282,7 +282,7 @@ public class FlatSystemFileChooserTest int fileTypeIndex = fileTypeIndexSlider.getValue(); if( !useAcceptAllFileFilterCheckBox.isSelected() ) fc.setAcceptAllFileFilterUsed( false ); - for( int i = 0; i < fileTypes.length; i += 2 ) { + for( int i = 0; i < fileTypes.length; i += 2 ) { fc.addChoosableFileFilter( "*".equals( fileTypes[i+1] ) ? fc.getAcceptAllFileFilter() : new FileNameExtensionFilter( fileTypes[i], fileTypes[i+1].split( ";" ) ) );