Window decorations (Windows 10/11 only):
Some checks failed
CI / build (11) (push) Has been cancelled
Native Libraries / Natives (macos-latest) (push) Has been cancelled
Native Libraries / Natives (ubuntu-24.04-arm) (push) Has been cancelled
Native Libraries / Natives (ubuntu-latest) (push) Has been cancelled
Native Libraries / Natives (windows-latest) (push) Has been cancelled
CI / build-on (17, ) (push) Has been cancelled
CI / build-on (21, ) (push) Has been cancelled
CI / build-on (23, ) (push) Has been cancelled
CI / build-on (8, ) (push) Has been cancelled
CI / snapshot (push) Has been cancelled
CI / release (push) Has been cancelled

- improved diagonal window resizing on top-left and top-right window corners
- top window resize area now also covers iconify/maximize/close buttons
(issue #1015)
This commit is contained in:
Karl Tauber
2025-07-03 20:08:40 +02:00
parent 286ce15146
commit 34b19f00e4
3 changed files with 65 additions and 16 deletions

View File

@@ -4,6 +4,9 @@ FlatLaf Change Log
## 3.6.1-SNAPSHOT
- Extras: Support JSVG 2.0.0. Minimum JSVG version is now 1.6.0. (issue #997)
- FlatLaf window decorations (Windows 10/11 only): Improved diagonal window
resizing on top-left and top-right window corners. Top window resize area now
also covers iconify/maximize/close buttons. (issue #1015)
- ToggleButton: Styling `selectedForeground` did not work if `foreground` is
also styled. (issue #1017)
- JideSplitButton: Fixed updating popup when switching theme. (issue #1000)

View File

@@ -21,6 +21,7 @@ import java.awt.Dialog;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
@@ -39,6 +40,7 @@ import javax.swing.event.ChangeListener;
import javax.swing.event.EventListenerList;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
//
// Interesting resources:
@@ -282,6 +284,8 @@ class FlatWindowsNativeWindowBorder
HTMINBUTTON = 8,
HTMAXBUTTON = 9,
HTTOP = 12,
HTTOPLEFT = 13,
HTTOPRIGHT = 14,
HTCLOSE = 20;
private Window window;
@@ -341,6 +345,31 @@ class FlatWindowsNativeWindowBorder
// scale-down mouse x/y because Swing coordinates/values may be scaled on a HiDPI screen
Point pt = scaleDown( x, y );
// limit top resize border to 4px, which seems to be standard for modern WinUI apps
if( isOnResizeBorder && pt.y > UIScale.scale( 4 ) )
isOnResizeBorder = false;
if( isOnResizeBorder ) {
Insets insets = window.getInsets();
// return HTTOPLEFT if mouse is over top resize border on left side
// - hovering mouse shows top-left resize cursor
// - left-click-and-drag resizes window
if( pt.x <= insets.left + UIScale.scale( 12 ) )
return HTTOPLEFT;
// return HTTOPRIGHT if mouse is over top resize border on right side
// - hovering mouse shows top-right resize cursor
// - left-click-and-drag resizes window
if( pt.x >= window.getWidth() - insets.right - UIScale.scale( 12 ) )
return HTTOPRIGHT;
// return HTTOP if mouse is over top resize border
// - hovering mouse shows vertical resize cursor
// - left-click-and-drag vertically resizes window
return HTTOP;
}
// return HTSYSMENU if mouse is over application icon
// - left-click on HTSYSMENU area shows system menu
// - double-left-click sends WM_CLOSE
@@ -364,12 +393,6 @@ class FlatWindowsNativeWindowBorder
if( contains( closeButtonBounds, pt ) )
return HTCLOSE;
// return HTTOP if mouse is over top resize border
// - hovering mouse shows vertical resize cursor
// - left-click and drag vertically resizes window
if( isOnResizeBorder )
return HTTOP;
boolean isOnTitleBar = (pt.y < titleBarHeight);
if( isOnTitleBar ) {
// return HTCLIENT if mouse is over any Swing component in title bar

View File

@@ -24,6 +24,7 @@ import java.awt.Dialog;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
@@ -42,6 +43,7 @@ import javax.swing.event.ChangeListener;
import javax.swing.event.EventListenerList;
import com.formdev.flatlaf.ui.FlatNativeWindowBorder;
import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
@@ -326,6 +328,8 @@ public class FlatWindowsNativeWindowBorder
HTMINBUTTON = 8,
HTMAXBUTTON = 9,
HTTOP = 12,
HTTOPLEFT = 13,
HTTOPRIGHT = 14,
HTCLOSE = 20;
private static final int ABS_AUTOHIDE = 0x0000001;
@@ -674,6 +678,35 @@ public class FlatWindowsNativeWindowBorder
// scale-down mouse x/y because Swing coordinates/values may be scaled on a HiDPI screen
Point pt = scaleDown( x, y );
int resizeBorderHeight = getResizeHandleHeight();
boolean isOnResizeBorder = (y < resizeBorderHeight) &&
(User32.INSTANCE.GetWindowLong( hwnd, GWL_STYLE ) & WS_THICKFRAME) != 0;
// limit top resize border to 4px, which seems to be standard for modern WinUI apps
if( isOnResizeBorder && pt.y > UIScale.scale( 4 ) )
isOnResizeBorder = false;
if( isOnResizeBorder ) {
Insets insets = window.getInsets();
// return HTTOPLEFT if mouse is over top resize border on left side
// - hovering mouse shows top-left resize cursor
// - left-click-and-drag resizes window
if( pt.x <= insets.left + UIScale.scale( 12 ) )
return new LRESULT( HTTOPLEFT );
// return HTTOPRIGHT if mouse is over top resize border on right side
// - hovering mouse shows top-right resize cursor
// - left-click-and-drag resizes window
if( pt.x >= window.getWidth() - insets.right - UIScale.scale( 12 ) )
return new LRESULT( HTTOPRIGHT );
// return HTTOP if mouse is over top resize border
// - hovering mouse shows vertical resize cursor
// - left-click-and-drag vertically resizes window
return new LRESULT( HTTOP );
}
// return HTSYSMENU if mouse is over application icon
// - left-click on HTSYSMENU area shows system menu
// - double-left-click sends WM_CLOSE
@@ -697,16 +730,6 @@ public class FlatWindowsNativeWindowBorder
if( contains( closeButtonBounds, pt ) )
return new LRESULT( HTCLOSE );
int resizeBorderHeight = getResizeHandleHeight();
boolean isOnResizeBorder = (y < resizeBorderHeight) &&
(User32.INSTANCE.GetWindowLong( hwnd, GWL_STYLE ) & WS_THICKFRAME) != 0;
// return HTTOP if mouse is over top resize border
// - hovering mouse shows vertical resize cursor
// - left-click and drag vertically resizes window
if( isOnResizeBorder )
return new LRESULT( HTTOP );
boolean isOnTitleBar = (pt.y < titleBarHeight);
if( isOnTitleBar ) {
// return HTCLIENT if mouse is over any Swing component in title bar