mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-11 06:27:13 -06:00
Native window decorations: delete temporary DLLs on next startup (same approach as used in JNA)
This commit is contained in:
@@ -17,10 +17,12 @@
|
|||||||
package com.formdev.flatlaf.util;
|
package com.formdev.flatlaf.util;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@@ -35,6 +37,9 @@ import com.formdev.flatlaf.FlatLaf;
|
|||||||
*/
|
*/
|
||||||
public class NativeLibrary
|
public class NativeLibrary
|
||||||
{
|
{
|
||||||
|
private static final String DELETE_SUFFIX = ".delete";
|
||||||
|
private static boolean deletedTemporary;
|
||||||
|
|
||||||
private final boolean loaded;
|
private final boolean loaded;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -71,6 +76,7 @@ public class NativeLibrary
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File tempFile = null;
|
||||||
try {
|
try {
|
||||||
// for development environment
|
// for development environment
|
||||||
if( "file".equals( libraryUrl.getProtocol() ) ) {
|
if( "file".equals( libraryUrl.getProtocol() ) ) {
|
||||||
@@ -83,11 +89,8 @@ public class NativeLibrary
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create temporary file
|
// create temporary file
|
||||||
Path tempPath = Files.createTempFile( "jni", basename( libraryName ) );
|
Path tempPath = createTempFile( libraryName );
|
||||||
File tempFile = tempPath.toFile();
|
tempFile = tempPath.toFile();
|
||||||
|
|
||||||
//TODO this does not work on Windows
|
|
||||||
tempFile.deleteOnExit();
|
|
||||||
|
|
||||||
// copy library to temporary file
|
// copy library to temporary file
|
||||||
try( InputStream in = libraryUrl.openStream() ) {
|
try( InputStream in = libraryUrl.openStream() ) {
|
||||||
@@ -97,9 +100,15 @@ public class NativeLibrary
|
|||||||
// load library
|
// load library
|
||||||
System.load( tempFile.getCanonicalPath() );
|
System.load( tempFile.getCanonicalPath() );
|
||||||
|
|
||||||
|
// delete library
|
||||||
|
deleteOrMarkForDeletion( tempFile );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch( Throwable ex ) {
|
} catch( Throwable ex ) {
|
||||||
log( null, ex );
|
log( null, ex );
|
||||||
|
|
||||||
|
if( tempFile != null )
|
||||||
|
deleteOrMarkForDeletion( tempFile );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,12 +125,69 @@ public class NativeLibrary
|
|||||||
: "lib" + libraryName + suffix;
|
: "lib" + libraryName + suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String basename( String libName ) {
|
|
||||||
int sep = libName.lastIndexOf( '/' );
|
|
||||||
return (sep >= 0) ? libName.substring( sep + 1 ) : libName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void log( String msg, Throwable thrown ) {
|
private static void log( String msg, Throwable thrown ) {
|
||||||
Logger.getLogger( FlatLaf.class.getName() ).log( Level.SEVERE, msg, thrown );
|
Logger.getLogger( FlatLaf.class.getName() ).log( Level.SEVERE, msg, thrown );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Path createTempFile( String libraryName ) throws IOException {
|
||||||
|
int sep = libraryName.lastIndexOf( '/' );
|
||||||
|
String name = (sep >= 0) ? libraryName.substring( sep + 1 ) : libraryName;
|
||||||
|
|
||||||
|
int dot = name.lastIndexOf( '.' );
|
||||||
|
String prefix = ((dot >= 0) ? name.substring( 0, dot ) : name) + '-';
|
||||||
|
String suffix = (dot >= 0) ? name.substring( dot ) : "";
|
||||||
|
|
||||||
|
Path tempDir = getTempDir();
|
||||||
|
if( tempDir != null ) {
|
||||||
|
deleteTemporaryFiles( tempDir );
|
||||||
|
|
||||||
|
return Files.createTempFile( tempDir, prefix, suffix );
|
||||||
|
} else
|
||||||
|
return Files.createTempFile( prefix, suffix );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Path getTempDir() throws IOException {
|
||||||
|
if( SystemInfo.isWindows ) {
|
||||||
|
// On Windows, where File.delete() and File.deleteOnExit() does not work
|
||||||
|
// for loaded native libraries, they will be deleted on next application startup.
|
||||||
|
// The default temporary directory may contain hundreds or thousands of files.
|
||||||
|
// To make searching for "marked for deletion" files as fast as possible,
|
||||||
|
// use a sub directory that contains only our temporary native libraries.
|
||||||
|
Path tempDir = Paths.get( System.getProperty( "java.io.tmpdir" ) + "/flatlaf.temp" );
|
||||||
|
Files.createDirectories( tempDir );
|
||||||
|
return tempDir;
|
||||||
|
} else
|
||||||
|
return null; // use standard temporary directory
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void deleteTemporaryFiles( Path tempDir ) {
|
||||||
|
if( deletedTemporary )
|
||||||
|
return;
|
||||||
|
deletedTemporary = true;
|
||||||
|
|
||||||
|
File[] markerFiles = tempDir.toFile().listFiles( (dir, name) -> name.endsWith( DELETE_SUFFIX ) );
|
||||||
|
if( markerFiles == null )
|
||||||
|
return;
|
||||||
|
|
||||||
|
for( File markerFile : markerFiles ) {
|
||||||
|
File toDeleteFile = new File( markerFile.getParent(), StringUtils.removeTrailing( markerFile.getName(), DELETE_SUFFIX ) );
|
||||||
|
if( !toDeleteFile.exists() || toDeleteFile.delete() )
|
||||||
|
markerFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void deleteOrMarkForDeletion( File file ) {
|
||||||
|
// try to delete the native library
|
||||||
|
if( file.delete() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// not possible to delete on Windows because native library file is locked
|
||||||
|
// --> create "to delete" marker file (used at next startup)
|
||||||
|
try {
|
||||||
|
File markFile = new File( file.getParent(), file.getName() + DELETE_SUFFIX );
|
||||||
|
markFile.createNewFile();
|
||||||
|
} catch( IOException ex2 ) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user