diff --git a/CHANGELOG.md b/CHANGELOG.md index d296b7f6..9c1ae2d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ FlatLaf Change Log ## 3.0-SNAPSHOT +#### New features and improvements + +- If value of system property `flatlaf.nativeLibraryPath` is `system`, then + `System.loadLibrary(String)` is used to load the native library. + #### Fixed bugs - ComboBox and Spinner: Fixed missing arrow buttons if preferred height is zero. diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatSystemProperties.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatSystemProperties.java index 2aa906d8..f7450216 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatSystemProperties.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatSystemProperties.java @@ -155,9 +155,19 @@ public interface FlatSystemProperties String UPDATE_UI_ON_SYSTEM_FONT_CHANGE = "flatlaf.updateUIOnSystemFontChange"; /** - * Specifies a directory in which the native FlatLaf library have been extracted. + * Specifies a directory in which the native FlatLaf libraries have been extracted. * The path can be absolute or relative to current application working directory. * This can be used to avoid extraction of the native libraries to the temporary directory at runtime. + *
+ * If the value is {@code "system"}, then {@link System#loadLibrary(String)} is + * used to load the native library. + * Searches for the native library in classloader of caller + * (using {@link ClassLoader#findLibrary(String)}) and in paths specified + * in system properties {@code sun.boot.library.path} and {@code java.library.path}. + * (supported since FlatLaf 3) + *
+ * If the native library can not loaded from the given path (or via {@link System#loadLibrary(String)}), + * then the embedded native library is extracted to the temporary directory and loaded from there. * * @since 2 */ diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLibrary.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLibrary.java index e486b7a8..14ccc07c 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLibrary.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLibrary.java @@ -84,11 +84,19 @@ class FlatNativeLibrary private static NativeLibrary createNativeLibrary( String libraryName ) { String libraryPath = System.getProperty( FlatSystemProperties.NATIVE_LIBRARY_PATH ); if( libraryPath != null ) { - File libraryFile = new File( libraryPath, System.mapLibraryName( libraryName ) ); - if( libraryFile.exists() ) - return new NativeLibrary( libraryFile, true ); - else + if( "system".equals( libraryPath ) ) { + NativeLibrary library = new NativeLibrary( libraryName, true ); + if( library.isLoaded() ) + return library; + + LoggingFacade.INSTANCE.logSevere( "Did not find library " + libraryName + " in java.library.path, using extracted library instead", null ); + } else { + File libraryFile = new File( libraryPath, System.mapLibraryName( libraryName ) ); + if( libraryFile.exists() ) + return new NativeLibrary( libraryFile, true ); + LoggingFacade.INSTANCE.logSevere( "Did not find external library " + libraryFile + ", using extracted library instead", null ); + } } return new NativeLibrary( "com/formdev/flatlaf/natives/" + libraryName, null, true ); @@ -101,9 +109,9 @@ class FlatNativeLibrary // log error only if native library jawt.dll not already loaded String message = ex.getMessage(); if( message == null || !message.contains( "already loaded in another classloader" ) ) - LoggingFacade.INSTANCE.logSevere( null, ex ); + LoggingFacade.INSTANCE.logSevere( message, ex ); } catch( Exception ex ) { - LoggingFacade.INSTANCE.logSevere( null, ex ); + LoggingFacade.INSTANCE.logSevere( ex.getMessage(), ex ); } } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/NativeLibrary.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/NativeLibrary.java index 7b57f06a..d81ae326 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/NativeLibrary.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/NativeLibrary.java @@ -73,6 +73,22 @@ public class NativeLibrary : false; } + /** + * Load native library using {@link System#loadLibrary(String)}. + * Searches for the library in classloader of caller + * (using {@link ClassLoader#findLibrary(String)}) and in paths specified + * in system properties {@code sun.boot.library.path} and {@code java.library.path}. + * + * @param libraryName name of the native library (without "lib" prefix and without extension) + * @param supported whether the native library is supported on the current platform + * @since 3 + */ + public NativeLibrary( String libraryName, boolean supported ) { + this.loaded = supported + ? loadLibraryFromSystem( libraryName ) + : false; + } + /** * Returns whether the native library is loaded. *
@@ -92,7 +108,7 @@ public class NativeLibrary ? classLoader.getResource( libraryName ) : NativeLibrary.class.getResource( "/" + libraryName ); if( libraryUrl == null ) { - log( "Library '" + libraryName + "' not found", null ); + LoggingFacade.INSTANCE.logSevere( "Library '" + libraryName + "' not found", null ); return false; } @@ -125,7 +141,7 @@ public class NativeLibrary return true; } catch( Throwable ex ) { - log( null, ex ); + LoggingFacade.INSTANCE.logSevere( ex.getMessage(), ex ); if( tempFile != null ) deleteOrMarkForDeletion( tempFile ); @@ -138,7 +154,24 @@ public class NativeLibrary System.load( libraryFile.getAbsolutePath() ); return true; } catch( Throwable ex ) { - log( ex.getMessage(), ex ); + LoggingFacade.INSTANCE.logSevere( ex.getMessage(), ex ); + return false; + } + } + + private boolean loadLibraryFromSystem( String libraryName ) { + try { + System.loadLibrary( libraryName ); + return true; + } catch( Throwable ex ) { + String message = ex.getMessage(); + + // do not log error if library was not found + // thrown in ClassLoader.loadLibrary(Class> fromClass, String name, boolean isAbsolute) + if( ex instanceof UnsatisfiedLinkError && message != null && message.contains( "java.library.path" ) ) + return false; + + LoggingFacade.INSTANCE.logSevere( message, ex ); return false; } } @@ -158,10 +191,6 @@ public class NativeLibrary : System.mapLibraryName( libraryName ); } - private static void log( String msg, Throwable thrown ) { - LoggingFacade.INSTANCE.logSevere( msg, thrown ); - } - private static Path createTempFile( String libraryName ) throws IOException { int sep = libraryName.lastIndexOf( '/' ); String name = (sep >= 0) ? libraryName.substring( sep + 1 ) : libraryName;