diff --git a/CHANGELOG.md b/CHANGELOG.md index 3703f269..0f0cf739 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ FlatLaf Change Log #### Fixed bugs +- Native window decorations: Fixed missing animations when minimizing, + maximizing or restoring a window using window title bar buttons. (issue #282) - Native window decorations: Fixed double window title bar when first disposing a window with `frame.dispose()` and then showing it again with `frame.setVisible(true)`. (issue #277) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowBorder.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowBorder.java index 87c252ca..d76ea198 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowBorder.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowBorder.java @@ -226,6 +226,13 @@ public class FlatNativeWindowBorder nativeProvider.setTitleBarAppIconBounds( window, appIconBounds ); } + static boolean showWindow( Window window, int cmd ) { + if( canUseJBRCustomDecorations || !isSupported() ) + return false; + + return nativeProvider.showWindow( window, cmd ); + } + private static void initialize() { if( supported != null ) return; @@ -276,6 +283,13 @@ public class FlatNativeWindowBorder void setTitleBarHitTestSpots( Window window, List hitTestSpots ); void setTitleBarAppIconBounds( Window window, Rectangle appIconBounds ); + // commands for showWindow(); values must match Win32 API + // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow + int SW_MAXIMIZE = 3; + int SW_MINIMIZE = 6; + int SW_RESTORE = 9; + boolean showWindow( Window window, int cmd ); + boolean isColorizationColorAffectsBorders(); Color getColorizationColor(); int getColorizationColorBalance(); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java index ca722822..fd948684 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java @@ -542,10 +542,12 @@ debug*/ * Iconifies the window. */ protected void iconify() { - if( window instanceof Frame ) { - Frame frame = (Frame) window; + if( !(window instanceof Frame) ) + return; + + Frame frame = (Frame) window; + if( !FlatNativeWindowBorder.showWindow( window, FlatNativeWindowBorder.Provider.SW_MINIMIZE ) ) frame.setExtendedState( frame.getExtendedState() | Frame.ICONIFIED ); - } } /** @@ -563,7 +565,8 @@ debug*/ rootPane.putClientProperty( "_flatlaf.maximizedBoundsUpToDate", true ); // maximize window - frame.setExtendedState( frame.getExtendedState() | Frame.MAXIMIZED_BOTH ); + if( !FlatNativeWindowBorder.showWindow( frame, FlatNativeWindowBorder.Provider.SW_MAXIMIZE ) ) + frame.setExtendedState( frame.getExtendedState() | Frame.MAXIMIZED_BOTH ); } protected void updateMaximizedBounds() { @@ -651,8 +654,11 @@ debug*/ * Restores the window size. */ protected void restore() { - if( window instanceof Frame ) { - Frame frame = (Frame) window; + if( !(window instanceof Frame) ) + return; + + Frame frame = (Frame) window; + if( !FlatNativeWindowBorder.showWindow( window, FlatNativeWindowBorder.Provider.SW_RESTORE ) ) { int state = frame.getExtendedState(); frame.setExtendedState( ((state & Frame.ICONIFIED) != 0) ? (state & ~Frame.ICONIFIED) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatWindowsNativeWindowBorder.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatWindowsNativeWindowBorder.java index 205c425e..bc1b4165 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatWindowsNativeWindowBorder.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatWindowsNativeWindowBorder.java @@ -197,6 +197,16 @@ class FlatWindowsNativeWindowBorder wndProc.appIconBounds = (appIconBounds != null) ? new Rectangle( appIconBounds ) : null; } + @Override + public boolean showWindow( Window window, int cmd ) { + WndProc wndProc = windowsMap.get( window ); + if( wndProc == null ) + return false; + + wndProc.showWindow( wndProc.hwnd, cmd ); + return true; + } + @Override public boolean isColorizationColorAffectsBorders() { updateColorization(); @@ -310,6 +320,7 @@ class FlatWindowsNativeWindowBorder private native long installImpl( Window window ); private native void uninstallImpl( long hwnd ); + private native void showWindow( long hwnd, int cmd ); // invoked from native code private int onNcHitTest( int x, int y, boolean isOnResizeBorder ) { diff --git a/flatlaf-natives/flatlaf-natives-jna/src/main/java/com/formdev/flatlaf/natives/jna/windows/FlatWindowsNativeWindowBorder.java b/flatlaf-natives/flatlaf-natives-jna/src/main/java/com/formdev/flatlaf/natives/jna/windows/FlatWindowsNativeWindowBorder.java index 5f48389c..9765750d 100644 --- a/flatlaf-natives/flatlaf-natives-jna/src/main/java/com/formdev/flatlaf/natives/jna/windows/FlatWindowsNativeWindowBorder.java +++ b/flatlaf-natives/flatlaf-natives-jna/src/main/java/com/formdev/flatlaf/natives/jna/windows/FlatWindowsNativeWindowBorder.java @@ -183,6 +183,16 @@ public class FlatWindowsNativeWindowBorder wndProc.appIconBounds = (appIconBounds != null) ? new Rectangle( appIconBounds ) : null; } + @Override + public boolean showWindow( Window window, int cmd ) { + WndProc wndProc = windowsMap.get( window ); + if( wndProc == null ) + return false; + + User32.INSTANCE.ShowWindow( wndProc.hwnd, cmd ); + return true; + } + @Override public boolean isColorizationColorAffectsBorders() { updateColorization(); diff --git a/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/FlatWndProc.cpp b/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/FlatWndProc.cpp index 4fdc6579..dfe4220c 100644 --- a/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/FlatWndProc.cpp +++ b/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/FlatWndProc.cpp @@ -45,6 +45,13 @@ JNIEXPORT void JNICALL Java_com_formdev_flatlaf_ui_FlatWindowsNativeWindowBorder FlatWndProc::uninstall( env, obj, reinterpret_cast( hwnd ) ); } +extern "C" +JNIEXPORT void JNICALL Java_com_formdev_flatlaf_ui_FlatWindowsNativeWindowBorder_00024WndProc_showWindow + ( JNIEnv *env, jobject obj, jlong hwnd, jint cmd ) +{ + ::ShowWindow( reinterpret_cast( hwnd ), cmd ); +} + //---- class FlatWndProc fields ----------------------------------------------- int FlatWndProc::initialized = 0; diff --git a/flatlaf-natives/flatlaf-natives-windows/src/main/headers/com_formdev_flatlaf_ui_FlatWindowsNativeWindowBorder_WndProc.h b/flatlaf-natives/flatlaf-natives-windows/src/main/headers/com_formdev_flatlaf_ui_FlatWindowsNativeWindowBorder_WndProc.h index a08cf74f..76a35d16 100644 --- a/flatlaf-natives/flatlaf-natives-windows/src/main/headers/com_formdev_flatlaf_ui_FlatWindowsNativeWindowBorder_WndProc.h +++ b/flatlaf-natives/flatlaf-natives-windows/src/main/headers/com_formdev_flatlaf_ui_FlatWindowsNativeWindowBorder_WndProc.h @@ -31,6 +31,14 @@ JNIEXPORT jlong JNICALL Java_com_formdev_flatlaf_ui_FlatWindowsNativeWindowBorde JNIEXPORT void JNICALL Java_com_formdev_flatlaf_ui_FlatWindowsNativeWindowBorder_00024WndProc_uninstallImpl (JNIEnv *, jobject, jlong); +/* + * Class: com_formdev_flatlaf_ui_FlatWindowsNativeWindowBorder_WndProc + * Method: showWindow + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_com_formdev_flatlaf_ui_FlatWindowsNativeWindowBorder_00024WndProc_showWindow + (JNIEnv *, jobject, jlong, jint); + #ifdef __cplusplus } #endif diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatNativeWindowBorderTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatNativeWindowBorderTest.java index d41adbc0..f9defb56 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatNativeWindowBorderTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatNativeWindowBorderTest.java @@ -153,6 +153,10 @@ public class FlatNativeWindowBorderTest } } ); + window.addWindowStateListener( e -> { + System.out.println( windowId + " windowStateChanged " + e.getOldState() + " --> " + e.getNewState() ); + } ); + registerSwitchToLookAndFeel( "F1", FlatLightLaf.class.getName() ); registerSwitchToLookAndFeel( "F2", FlatDarkLaf.class.getName() ); registerSwitchToLookAndFeel( "F3", FlatIntelliJLaf.class.getName() );