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 ## 3.6.1-SNAPSHOT
- Extras: Support JSVG 2.0.0. Minimum JSVG version is now 1.6.0. (issue #997) - 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 - ToggleButton: Styling `selectedForeground` did not work if `foreground` is
also styled. (issue #1017) also styled. (issue #1017)
- JideSplitButton: Fixed updating popup when switching theme. (issue #1000) - 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.EventQueue;
import java.awt.Frame; import java.awt.Frame;
import java.awt.GraphicsConfiguration; import java.awt.GraphicsConfiguration;
import java.awt.Insets;
import java.awt.Point; import java.awt.Point;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.Window; import java.awt.Window;
@@ -39,6 +40,7 @@ import javax.swing.event.ChangeListener;
import javax.swing.event.EventListenerList; import javax.swing.event.EventListenerList;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
// //
// Interesting resources: // Interesting resources:
@@ -282,6 +284,8 @@ class FlatWindowsNativeWindowBorder
HTMINBUTTON = 8, HTMINBUTTON = 8,
HTMAXBUTTON = 9, HTMAXBUTTON = 9,
HTTOP = 12, HTTOP = 12,
HTTOPLEFT = 13,
HTTOPRIGHT = 14,
HTCLOSE = 20; HTCLOSE = 20;
private Window window; 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 // scale-down mouse x/y because Swing coordinates/values may be scaled on a HiDPI screen
Point pt = scaleDown( x, y ); 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 // return HTSYSMENU if mouse is over application icon
// - left-click on HTSYSMENU area shows system menu // - left-click on HTSYSMENU area shows system menu
// - double-left-click sends WM_CLOSE // - double-left-click sends WM_CLOSE
@@ -364,12 +393,6 @@ class FlatWindowsNativeWindowBorder
if( contains( closeButtonBounds, pt ) ) if( contains( closeButtonBounds, pt ) )
return HTCLOSE; 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); boolean isOnTitleBar = (pt.y < titleBarHeight);
if( isOnTitleBar ) { if( isOnTitleBar ) {
// return HTCLIENT if mouse is over any Swing component in title bar // 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.EventQueue;
import java.awt.Frame; import java.awt.Frame;
import java.awt.GraphicsConfiguration; import java.awt.GraphicsConfiguration;
import java.awt.Insets;
import java.awt.Point; import java.awt.Point;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.Window; import java.awt.Window;
@@ -42,6 +43,7 @@ import javax.swing.event.ChangeListener;
import javax.swing.event.EventListenerList; import javax.swing.event.EventListenerList;
import com.formdev.flatlaf.ui.FlatNativeWindowBorder; import com.formdev.flatlaf.ui.FlatNativeWindowBorder;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
import com.sun.jna.Native; import com.sun.jna.Native;
import com.sun.jna.Pointer; import com.sun.jna.Pointer;
import com.sun.jna.Structure; import com.sun.jna.Structure;
@@ -326,6 +328,8 @@ public class FlatWindowsNativeWindowBorder
HTMINBUTTON = 8, HTMINBUTTON = 8,
HTMAXBUTTON = 9, HTMAXBUTTON = 9,
HTTOP = 12, HTTOP = 12,
HTTOPLEFT = 13,
HTTOPRIGHT = 14,
HTCLOSE = 20; HTCLOSE = 20;
private static final int ABS_AUTOHIDE = 0x0000001; 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 // scale-down mouse x/y because Swing coordinates/values may be scaled on a HiDPI screen
Point pt = scaleDown( x, y ); 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 // return HTSYSMENU if mouse is over application icon
// - left-click on HTSYSMENU area shows system menu // - left-click on HTSYSMENU area shows system menu
// - double-left-click sends WM_CLOSE // - double-left-click sends WM_CLOSE
@@ -697,16 +730,6 @@ public class FlatWindowsNativeWindowBorder
if( contains( closeButtonBounds, pt ) ) if( contains( closeButtonBounds, pt ) )
return new LRESULT( HTCLOSE ); 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); boolean isOnTitleBar = (pt.y < titleBarHeight);
if( isOnTitleBar ) { if( isOnTitleBar ) {
// return HTCLIENT if mouse is over any Swing component in title bar // return HTCLIENT if mouse is over any Swing component in title bar