diff --git a/.github/workflows/natives.yml b/.github/workflows/natives.yml index 676b17ba..dfe1ef56 100644 --- a/.github/workflows/natives.yml +++ b/.github/workflows/natives.yml @@ -40,6 +40,19 @@ jobs: if: matrix.os == 'ubuntu' run: sudo apt install libgtk-3-dev + - name: Download libgtk-3.so for arm64 + if: matrix.os == 'ubuntu' + working-directory: flatlaf-natives/flatlaf-natives-linux/lib/aarch64 + run: | + pwd + ls -l /usr/lib/x86_64-linux-gnu/libgtk* + wget --no-verbose https://ports.ubuntu.com/pool/main/g/gtk%2b3.0/libgtk-3-0_3.24.18-1ubuntu1_arm64.deb + ls -l + ar -x libgtk-3-0_3.24.18-1ubuntu1_arm64.deb data.tar.xz + tar -xvf data.tar.xz --wildcards --to-stdout "./usr/lib/aarch64-linux-gnu/libgtk-3.so.0.*" > libgtk-3.so + rm libgtk-3-0_3.24.18-1ubuntu1_arm64.deb data.tar.xz + ls -l + - name: install g++-aarch64-linux-gnu if: matrix.os == 'ubuntu' run: sudo apt install g++-aarch64-linux-gnu diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLinuxLibrary.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLinuxLibrary.java index 1cbefc97..51770be4 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLinuxLibrary.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLinuxLibrary.java @@ -49,6 +49,9 @@ public class FlatNativeLinuxLibrary return SystemInfo.isLinux && FlatNativeLibrary.isLoaded( API_VERSION_LINUX ); } + + //---- X Window System ---------------------------------------------------- + // direction for _NET_WM_MOVERESIZE message // see https://specifications.freedesktop.org/wm-spec/wm-spec-latest.html static final int MOVE = 8; @@ -118,6 +121,28 @@ public class FlatNativeLinuxLibrary } + //---- GTK ---------------------------------------------------------------- + + private static Boolean isGtk3Available; + + /** + * Checks whether GTK 3 is available. + * Use this before invoking any native method that uses GTK. + * Otherwise the app may terminate immediately if GTK is not installed. + *

+ * This works because Java uses {@code dlopen(RTLD_LAZY)} to load JNI libraries, + * which only resolves symbols as the code that references them is executed. + * + * @since 3.6 + */ + public static boolean isGtk3Available() { + if( isGtk3Available == null ) + isGtk3Available = isLibAvailable( "libgtk-3.so.0" ) || isLibAvailable( "libgtk-3.so" ); + return isGtk3Available; + } + + private native static boolean isLibAvailable( String libname ); + /** * https://docs.gtk.org/gtk3/iface.FileChooser.html#properties * 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 f3740102..cd25e182 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 @@ -49,8 +49,8 @@ import com.formdev.flatlaf.ui.FlatNativeWindowsLibrary; * If there are no compile errors, then there is a good chance that it works without further changes. * If there are compile errors, then you're using a feature that {@code SystemFileChooser} does not support. *

- * Supported platforms are Windows 10+, macOS 10.14+ and Linux GTK 3. - * {@code JFileChooser} is used on unsupported platforms. + * Supported platforms are Windows 10+, macOS 10.14+ and Linux with GTK 3. + * {@code JFileChooser} is used on unsupported platforms or if GTK 3 is not installed. *

* {@code SystemFileChooser} requires FlatLaf native libraries (usually contained in flatlaf.jar). * If not available or disabled (via {@link FlatSystemProperties#USE_NATIVE_LIBRARY} @@ -421,7 +421,7 @@ public class SystemFileChooser return new WindowsFileChooserProvider(); else if( SystemInfo.isMacOS && FlatNativeMacLibrary.isLoaded() ) return new MacFileChooserProvider(); - else if( SystemInfo.isLinux && FlatNativeLinuxLibrary.isLoaded() ) + else if( SystemInfo.isLinux && FlatNativeLinuxLibrary.isLoaded() && FlatNativeLinuxLibrary.isGtk3Available() ) return new LinuxFileChooserProvider(); else // unknown platform or FlatLaf native library not loaded return new SwingFileChooserProvider(); diff --git a/flatlaf-natives/flatlaf-natives-linux/README.md b/flatlaf-natives/flatlaf-natives-linux/README.md index 0fcc9877..3d4c2051 100644 --- a/flatlaf-natives/flatlaf-natives-linux/README.md +++ b/flatlaf-natives/flatlaf-natives-linux/README.md @@ -43,6 +43,16 @@ Only on x86_64 Linux for cross-compiling for arm64 architecture: sudo apt install g++-aarch64-linux-gnu ~~~ +Download `libgtk-3.so` for arm64 architecture: + +~~~ +cd flatlaf-natives/flatlaf-natives-linux/lib/aarch64 +wget --no-verbose https://ports.ubuntu.com/pool/main/g/gtk%2b3.0/libgtk-3-0_3.24.18-1ubuntu1_arm64.deb +ar -x libgtk-3-0_3.24.18-1ubuntu1_arm64.deb data.tar.xz +tar -xvf data.tar.xz --wildcards --to-stdout "./usr/lib/aarch64-linux-gnu/libgtk-3.so.0.*" > libgtk-3.so +rm libgtk-3-0_3.24.18-1ubuntu1_arm64.deb data.tar.xz +~~~ + ### Fedora diff --git a/flatlaf-natives/flatlaf-natives-linux/build.gradle.kts b/flatlaf-natives/flatlaf-natives-linux/build.gradle.kts index 9ddee01b..6b286266 100644 --- a/flatlaf-natives/flatlaf-natives-linux/build.gradle.kts +++ b/flatlaf-natives/flatlaf-natives-linux/build.gradle.kts @@ -149,7 +149,20 @@ tasks { "-I", "${javaHome}/include/linux", "-I", "$include", + // for GTK + "-I", "/usr/include/gtk-3.0", + "-I", "/usr/include/glib-2.0", + "-I", "/usr/lib/x86_64-linux-gnu/glib-2.0/include", + "-I", "/usr/include/gdk-pixbuf-2.0", + "-I", "/usr/include/atk-1.0", + "-I", "/usr/include/cairo", + "-I", "/usr/include/pango-1.0", + "-I", "/usr/include/harfbuzz", + "$src/ApiVersion.cpp", + "$src/GtkFileChooser.cpp", + "$src/GtkMessageDialog.cpp", + "$src/JNIUtils.cpp", "$src/X11WmUtils.cpp", ) } @@ -173,10 +186,14 @@ tasks { "-o", "$outDir/$libraryName", "$objDir/ApiVersion.o", + "$objDir/GtkFileChooser.o", + "$objDir/GtkMessageDialog.o", + "$objDir/JNIUtils.o", "$objDir/X11WmUtils.o", "-L${layout.projectDirectory}/lib/aarch64", "-ljawt", + "-lgtk-3", ) doLast { diff --git a/flatlaf-natives/flatlaf-natives-linux/src/main/cpp/JNIUtils.cpp b/flatlaf-natives/flatlaf-natives-linux/src/main/cpp/JNIUtils.cpp index bd587070..4edea7e4 100644 --- a/flatlaf-natives/flatlaf-natives-linux/src/main/cpp/JNIUtils.cpp +++ b/flatlaf-natives/flatlaf-natives-linux/src/main/cpp/JNIUtils.cpp @@ -17,6 +17,7 @@ // avoid inlining of printf() #define _NO_CRT_STDIO_INLINE +#include #include "JNIUtils.h" /** @@ -35,3 +36,19 @@ AutoReleaseStringUTF8::~AutoReleaseStringUTF8() { if( chars != NULL ) env->ReleaseStringUTFChars( javaString, chars ); } + +//---- JNI methods ------------------------------------------------------------ + +extern "C" +JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLinuxLibrary_isLibAvailable + ( JNIEnv* env, jclass cls, jstring libname ) +{ + AutoReleaseStringUTF8 clibname( env, libname ); + + void* lib = dlopen( clibname, RTLD_LAZY ); + if( lib == NULL ) + return false; + + dlclose( lib ); + return true; +} diff --git a/flatlaf-natives/flatlaf-natives-linux/src/main/headers/com_formdev_flatlaf_ui_FlatNativeLinuxLibrary.h b/flatlaf-natives/flatlaf-natives-linux/src/main/headers/com_formdev_flatlaf_ui_FlatNativeLinuxLibrary.h index 5e9573b4..0c581640 100644 --- a/flatlaf-natives/flatlaf-natives-linux/src/main/headers/com_formdev_flatlaf_ui_FlatNativeLinuxLibrary.h +++ b/flatlaf-natives/flatlaf-natives-linux/src/main/headers/com_formdev_flatlaf_ui_FlatNativeLinuxLibrary.h @@ -37,6 +37,14 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLinuxLibrary_xM JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLinuxLibrary_xShowWindowMenu (JNIEnv *, jclass, jobject, jint, jint); +/* + * Class: com_formdev_flatlaf_ui_FlatNativeLinuxLibrary + * Method: isLibAvailable + * Signature: (Ljava/lang/String;)Z + */ +JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLinuxLibrary_isLibAvailable + (JNIEnv *, jclass, jstring); + /* * Class: com_formdev_flatlaf_ui_FlatNativeLinuxLibrary * Method: showFileChooser diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserLinuxTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserLinuxTest.java index 0c4f59f6..df89e063 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserLinuxTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserLinuxTest.java @@ -49,7 +49,7 @@ public class FlatSystemFileChooserLinuxTest } FlatTestFrame frame = FlatTestFrame.create( args, "FlatSystemFileChooserLinuxTest" ); - addListeners( frame ); +// addListeners( frame ); frame.showFrame( FlatSystemFileChooserLinuxTest::new ); } ); } @@ -134,6 +134,8 @@ public class FlatSystemFileChooserLinuxTest return true; }; + System.out.println( FlatNativeLinuxLibrary.isGtk3Available() ); + if( direct ) { String[] files = FlatNativeLinuxLibrary.showFileChooser( owner, open, title, okButtonLabel, currentName, currentFolder,