diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java index 2a1b24c3..3799bfd9 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java @@ -23,6 +23,20 @@ import java.awt.Window; *

* Note: This is private API. Do not use! * + *

Methods that use windows as parameter

+ * + * For all methods that accept a {@link java.awt.Window} as parameter, + * the underlying macOS window must be already created, + * otherwise the method fails. You can use following to ensure this: + *
{@code
+ * if( !window.isDisplayable() )
+ *     window.addNotify();
+ * }
+ * or invoke the method after packing the window. E.g. + *
{@code
+ * window.pack();
+ * }
+ * * @author Karl Tauber * @since 3.3 */ @@ -38,22 +52,5 @@ public class FlatNativeMacLibrary return FlatNativeLibrary.isLoaded(); } - /** - * Gets the macOS window pointer (NSWindow) for the given Swing window. - *

- * Note that the underlying macOS window must be already created, - * otherwise this method returns zero. Use following to ensure this: - *

{@code
-	 * if( !window.isDisplayable() )
-	 *     window.addNotify();
-	 * }
- * or invoke this method after packing the window. E.g. - *
{@code
-	 * window.pack();
-	 * long windowPtr = getWindowPtr( window );
-	 * }
- */ - public native static long getWindowPtr( Window window ); - - public native static void setWindowRoundedBorder( long windowPtr, float radius, float borderWidth, int borderColor ); + public native static boolean setWindowRoundedBorder( Window window, float radius, float borderWidth, int borderColor ); } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java index 8aa636f0..9039c28d 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java @@ -324,13 +324,6 @@ public class FlatPopupFactory if( !popupWindow.isDisplayable() ) popupWindow.addNotify(); - // get native window handle/pointer - long hwnd = SystemInfo.isWindows - ? FlatNativeWindowsLibrary.getHWND( popupWindow ) - : FlatNativeMacLibrary.getWindowPtr( popupWindow ); - if( hwnd == 0 ) - return; - int borderCornerRadius = getBorderCornerRadius( owner, contents ); float borderWidth = getRoundedBorderWidth( owner, contents ); @@ -353,6 +346,9 @@ public class FlatPopupFactory } if( SystemInfo.isWindows ) { + // get native window handle + long hwnd = FlatNativeWindowsLibrary.getHWND( popupWindow ); + // set corner preference int cornerPreference = (borderCornerRadius <= 4) ? FlatNativeWindowsLibrary.DWMWCP_ROUNDSMALL // 4px @@ -366,7 +362,7 @@ public class FlatPopupFactory borderWidth = 0; // set corner radius, border width and color - FlatNativeMacLibrary.setWindowRoundedBorder( hwnd, borderCornerRadius, + FlatNativeMacLibrary.setWindowRoundedBorder( popupWindow, borderCornerRadius, borderWidth, (borderColor != null) ? borderColor.getRGB() : 0 ); } } diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-macos-arm64.dylib b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-macos-arm64.dylib old mode 100644 new mode 100755 index 6094c831..e29df3b1 Binary files a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-macos-arm64.dylib and b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-macos-arm64.dylib differ diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-macos-x86_64.dylib b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-macos-x86_64.dylib old mode 100644 new mode 100755 index a15d4876..bb1c221c Binary files a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-macos-x86_64.dylib and b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-macos-x86_64.dylib differ diff --git a/flatlaf-natives/flatlaf-natives-macos/build.gradle.kts b/flatlaf-natives/flatlaf-natives-macos/build.gradle.kts index b6b24745..322b1998 100644 --- a/flatlaf-natives/flatlaf-natives-macos/build.gradle.kts +++ b/flatlaf-natives/flatlaf-natives-macos/build.gradle.kts @@ -81,7 +81,7 @@ tasks { val nativesDir = project( ":flatlaf-core" ).projectDir.resolve( "src/main/resources/com/formdev/flatlaf/natives" ) val isARM64 = name.contains( "Arm64" ) val minOs = if( isARM64 ) minOsARM64 else minOsX86_64 - val libraryName = if( isARM64 ) "flatlaf-macos-arm64.dylib" else "flatlaf-macos-x86_64.dylib" + val libraryName = if( isARM64 ) "libflatlaf-macos-arm64.dylib" else "libflatlaf-macos-x86_64.dylib" linkerArgs.addAll( toolChain.map { when( it ) { @@ -91,14 +91,17 @@ tasks { } ) doLast { + // sign shared library +// exec { commandLine( "codesign", "-s", "FormDev Software GmbH", "--timestamp", "${linkedFile.asFile.get()}" ) } + // copy shared library to flatlaf-core resources copy { from( linkedFile ) into( nativesDir ) - rename( "flatlaf-natives-macos.dylib", libraryName ) + rename( "libflatlaf-natives-macos.dylib", libraryName ) } -///*dump +/*dump val dylib = linkedFile.asFile.get() val dylibDir = dylib.parent exec { commandLine( "size", dylib ) } @@ -123,7 +126,7 @@ tasks { } exec { commandLine( "objdump", "--disassemble-all", dylib ); standardOutput = FileOutputStream( "$dylibDir/disassemble.txt" ) } exec { commandLine( "objdump", "--full-contents", dylib ); standardOutput = FileOutputStream( "$dylibDir/full-contents.txt" ) } -//dump*/ +dump*/ } } } diff --git a/flatlaf-natives/flatlaf-natives-macos/src/main/headers/JNIUtils.h b/flatlaf-natives/flatlaf-natives-macos/src/main/headers/JNIUtils.h index 8e5be892..2de80956 100644 --- a/flatlaf-natives/flatlaf-natives-macos/src/main/headers/JNIUtils.h +++ b/flatlaf-natives/flatlaf-natives-macos/src/main/headers/JNIUtils.h @@ -23,9 +23,9 @@ */ -// from JNFJNI.h +// from jlong_md.h #ifndef jlong_to_ptr -#define jlong_to_ptr(a) ((void *)(uintptr_t)(a)) + #define jlong_to_ptr(a) ((void*)(a)) #endif @@ -39,3 +39,6 @@ [ex name], [ex reason], [ex userInfo], [ex callStackSymbols] ); \ } \ } + + +jfieldID getFieldID( JNIEnv *env, const char* className, const char* fieldName, const char* fieldSignature ); diff --git a/flatlaf-natives/flatlaf-natives-macos/src/main/headers/com_formdev_flatlaf_ui_FlatNativeMacLibrary.h b/flatlaf-natives/flatlaf-natives-macos/src/main/headers/com_formdev_flatlaf_ui_FlatNativeMacLibrary.h index f4d55eed..f5bcd35b 100644 --- a/flatlaf-natives/flatlaf-natives-macos/src/main/headers/com_formdev_flatlaf_ui_FlatNativeMacLibrary.h +++ b/flatlaf-natives/flatlaf-natives-macos/src/main/headers/com_formdev_flatlaf_ui_FlatNativeMacLibrary.h @@ -7,21 +7,13 @@ #ifdef __cplusplus extern "C" { #endif -/* - * Class: com_formdev_flatlaf_ui_FlatNativeMacLibrary - * Method: getWindowPtr - * Signature: (Ljava/awt/Window;)J - */ -JNIEXPORT jlong JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_getWindowPtr - (JNIEnv *, jclass, jobject); - /* * Class: com_formdev_flatlaf_ui_FlatNativeMacLibrary * Method: setWindowRoundedBorder - * Signature: (JFFI)V + * Signature: (Ljava/awt/Window;FFI)Z */ -JNIEXPORT void JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setWindowRoundedBorder - (JNIEnv *, jclass, jlong, jfloat, jfloat, jint); +JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setWindowRoundedBorder + (JNIEnv *, jclass, jobject, jfloat, jfloat, jint); #ifdef __cplusplus } diff --git a/flatlaf-natives/flatlaf-natives-macos/src/main/objcpp/JNIUtils.mm b/flatlaf-natives/flatlaf-natives-macos/src/main/objcpp/JNIUtils.mm new file mode 100644 index 00000000..7c4e798d --- /dev/null +++ b/flatlaf-natives/flatlaf-natives-macos/src/main/objcpp/JNIUtils.mm @@ -0,0 +1,44 @@ +/* + * Copyright 2023 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. + */ + +#import +#import "JNIUtils.h" + +/** + * @author Karl Tauber + */ + +jfieldID getFieldID( JNIEnv *env, const char* className, const char* fieldName, const char* fieldSignature ) { +// NSLog( @"getFieldID %s %s %s", className, fieldName, fieldSignature ); + + jclass cls = env->FindClass( className ); + if( cls == NULL ) { + NSLog( @"FlatLaf: failed to lookup class '%s'", className ); + env->ExceptionDescribe(); // print stack trace + env->ExceptionClear(); + return NULL; + } + + jfieldID fieldID = env->GetFieldID( cls, fieldName, fieldSignature ); + if( fieldID == NULL ) { + NSLog( @"FlatLaf: failed to lookup field '%s' of type '%s' in class '%s'", fieldName, fieldSignature, className ); + env->ExceptionDescribe(); // print stack trace + env->ExceptionClear(); + return NULL; + } + + return fieldID; +} diff --git a/flatlaf-natives/flatlaf-natives-macos/src/main/objcpp/MacWindow.mm b/flatlaf-natives/flatlaf-natives-macos/src/main/objcpp/MacWindow.mm index de0e8876..5d81a51c 100644 --- a/flatlaf-natives/flatlaf-natives-macos/src/main/objcpp/MacWindow.mm +++ b/flatlaf-natives/flatlaf-natives-macos/src/main/objcpp/MacWindow.mm @@ -24,67 +24,66 @@ * @author Karl Tauber */ -extern "C" -JNIEXPORT jlong JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_getWindowPtr - ( JNIEnv* env, jclass cls, jobject window ) -{ +NSWindow* getNSWindow( JNIEnv* env, jclass cls, jobject window ) { if( window == NULL ) return NULL; - - JNI_COCOA_ENTER() + + // initialize field IDs (done only once because fields are static) + static jfieldID peerID = getFieldID( env, "java/awt/Component", "peer", "Ljava/awt/peer/ComponentPeer;" ); + static jfieldID platformWindowID = getFieldID( env, "sun/lwawt/LWWindowPeer", "platformWindow", "Lsun/lwawt/PlatformWindow;" ); + static jfieldID ptrID = getFieldID( env, "sun/lwawt/macosx/CFRetainedResource", "ptr", "J" ); + if( peerID == NULL || platformWindowID == NULL || ptrID == NULL ) + return NULL; // get field java.awt.Component.peer - jfieldID peerID = env->GetFieldID( env->GetObjectClass( window ), "peer", "Ljava/awt/peer/ComponentPeer;" ); - jobject peer = (peerID != NULL) ? env->GetObjectField( window, peerID ) : NULL; + jobject peer = env->GetObjectField( window, peerID ); if( peer == NULL ) return NULL; // get field sun.lwawt.LWWindowPeer.platformWindow - jfieldID platformWindowID = env->GetFieldID( env->GetObjectClass( peer ), "platformWindow", "Lsun/lwawt/PlatformWindow;" ); - jobject platformWindow = (platformWindowID != NULL) ? env->GetObjectField( peer, platformWindowID ) : NULL; + jobject platformWindow = env->GetObjectField( peer, platformWindowID ); if( platformWindow == NULL ) return NULL; // get field sun.lwawt.macosx.CFRetainedResource.ptr - jfieldID ptrID = env->GetFieldID( env->GetObjectClass( platformWindow ), "ptr", "J" ); - return (ptrID != NULL) ? env->GetLongField( platformWindow, ptrID ) : NULL; - - JNI_COCOA_EXIT() + return (NSWindow *) jlong_to_ptr( env->GetLongField( platformWindow, ptrID ) ); } extern "C" -JNIEXPORT void JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setWindowRoundedBorder - ( JNIEnv* env, jclass cls, jlong windowPtr, jfloat radius, jfloat borderWidth, jint borderColor ) +JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setWindowRoundedBorder + ( JNIEnv* env, jclass cls, jobject window, jfloat radius, jfloat borderWidth, jint borderColor ) { - if( windowPtr == 0 ) - return; - JNI_COCOA_ENTER() + NSWindow* nsWindow = getNSWindow( env, cls, window ); + if( nsWindow == NULL ) + return FALSE; + [FlatJNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - NSWindow* window = (NSWindow *) jlong_to_ptr( windowPtr ); + nsWindow.hasShadow = YES; + nsWindow.contentView.wantsLayer = YES; + nsWindow.contentView.layer.cornerRadius = radius; + nsWindow.contentView.layer.masksToBounds = YES; - window.hasShadow = YES; - window.contentView.wantsLayer = YES; - window.contentView.layer.cornerRadius = radius; - window.contentView.layer.masksToBounds = YES; - - window.contentView.layer.borderWidth = borderWidth; + nsWindow.contentView.layer.borderWidth = borderWidth; if( borderWidth > 0 ) { CGFloat red = ((borderColor >> 16) & 0xff) / 255.; CGFloat green = ((borderColor >> 8) & 0xff) / 255.; CGFloat blue = (borderColor & 0xff) / 255.; CGFloat alpha = ((borderColor >> 24) & 0xff) / 255.; - window.contentView.layer.borderColor = [[NSColor colorWithDeviceRed:red green:green blue:blue alpha:alpha] CGColor]; + nsWindow.contentView.layer.borderColor = [[NSColor colorWithDeviceRed:red green:green blue:blue alpha:alpha] CGColor]; } - window.backgroundColor = NSColor.clearColor; - window.opaque = NO; + nsWindow.backgroundColor = NSColor.clearColor; + nsWindow.opaque = NO; - [window.contentView.layer removeAllAnimations]; - [window invalidateShadow]; + [nsWindow.contentView.layer removeAllAnimations]; + [nsWindow invalidateShadow]; }]; + return TRUE; + JNI_COCOA_EXIT() + return FALSE; }