Skip to content

Commit 34b19f0

Browse files
committed
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)
1 parent 286ce15 commit 34b19f0

3 files changed

Lines changed: 65 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ FlatLaf Change Log
44
## 3.6.1-SNAPSHOT
55

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

flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatWindowsNativeWindowBorder.java

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.awt.EventQueue;
2222
import java.awt.Frame;
2323
import java.awt.GraphicsConfiguration;
24+
import java.awt.Insets;
2425
import java.awt.Point;
2526
import java.awt.Rectangle;
2627
import java.awt.Window;
@@ -39,6 +40,7 @@
3940
import javax.swing.event.EventListenerList;
4041
import com.formdev.flatlaf.util.LoggingFacade;
4142
import com.formdev.flatlaf.util.SystemInfo;
43+
import com.formdev.flatlaf.util.UIScale;
4244

4345
//
4446
// Interesting resources:
@@ -282,6 +284,8 @@ private class WndProc
282284
HTMINBUTTON = 8,
283285
HTMAXBUTTON = 9,
284286
HTTOP = 12,
287+
HTTOPLEFT = 13,
288+
HTTOPRIGHT = 14,
285289
HTCLOSE = 20;
286290

287291
private Window window;
@@ -341,6 +345,31 @@ private int onNcHitTest( int x, int y, boolean isOnResizeBorder ) {
341345
// scale-down mouse x/y because Swing coordinates/values may be scaled on a HiDPI screen
342346
Point pt = scaleDown( x, y );
343347

348+
// limit top resize border to 4px, which seems to be standard for modern WinUI apps
349+
if( isOnResizeBorder && pt.y > UIScale.scale( 4 ) )
350+
isOnResizeBorder = false;
351+
352+
if( isOnResizeBorder ) {
353+
Insets insets = window.getInsets();
354+
355+
// return HTTOPLEFT if mouse is over top resize border on left side
356+
// - hovering mouse shows top-left resize cursor
357+
// - left-click-and-drag resizes window
358+
if( pt.x <= insets.left + UIScale.scale( 12 ) )
359+
return HTTOPLEFT;
360+
361+
// return HTTOPRIGHT if mouse is over top resize border on right side
362+
// - hovering mouse shows top-right resize cursor
363+
// - left-click-and-drag resizes window
364+
if( pt.x >= window.getWidth() - insets.right - UIScale.scale( 12 ) )
365+
return HTTOPRIGHT;
366+
367+
// return HTTOP if mouse is over top resize border
368+
// - hovering mouse shows vertical resize cursor
369+
// - left-click-and-drag vertically resizes window
370+
return HTTOP;
371+
}
372+
344373
// return HTSYSMENU if mouse is over application icon
345374
// - left-click on HTSYSMENU area shows system menu
346375
// - double-left-click sends WM_CLOSE
@@ -364,12 +393,6 @@ private int onNcHitTest( int x, int y, boolean isOnResizeBorder ) {
364393
if( contains( closeButtonBounds, pt ) )
365394
return HTCLOSE;
366395

367-
// return HTTOP if mouse is over top resize border
368-
// - hovering mouse shows vertical resize cursor
369-
// - left-click and drag vertically resizes window
370-
if( isOnResizeBorder )
371-
return HTTOP;
372-
373396
boolean isOnTitleBar = (pt.y < titleBarHeight);
374397
if( isOnTitleBar ) {
375398
// return HTCLIENT if mouse is over any Swing component in title bar

flatlaf-natives/flatlaf-natives-jna/src/main/java/com/formdev/flatlaf/natives/jna/windows/FlatWindowsNativeWindowBorder.java

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.awt.EventQueue;
2525
import java.awt.Frame;
2626
import java.awt.GraphicsConfiguration;
27+
import java.awt.Insets;
2728
import java.awt.Point;
2829
import java.awt.Rectangle;
2930
import java.awt.Window;
@@ -42,6 +43,7 @@
4243
import javax.swing.event.EventListenerList;
4344
import com.formdev.flatlaf.ui.FlatNativeWindowBorder;
4445
import com.formdev.flatlaf.util.SystemInfo;
46+
import com.formdev.flatlaf.util.UIScale;
4547
import com.sun.jna.Native;
4648
import com.sun.jna.Pointer;
4749
import com.sun.jna.Structure;
@@ -326,6 +328,8 @@ private class WndProc
326328
HTMINBUTTON = 8,
327329
HTMAXBUTTON = 9,
328330
HTTOP = 12,
331+
HTTOPLEFT = 13,
332+
HTTOPRIGHT = 14,
329333
HTCLOSE = 20;
330334

331335
private static final int ABS_AUTOHIDE = 0x0000001;
@@ -674,6 +678,35 @@ private LRESULT WmNcHitTest( HWND hwnd, int uMsg, WPARAM wParam, LPARAM lParam )
674678
// scale-down mouse x/y because Swing coordinates/values may be scaled on a HiDPI screen
675679
Point pt = scaleDown( x, y );
676680

681+
int resizeBorderHeight = getResizeHandleHeight();
682+
boolean isOnResizeBorder = (y < resizeBorderHeight) &&
683+
(User32.INSTANCE.GetWindowLong( hwnd, GWL_STYLE ) & WS_THICKFRAME) != 0;
684+
685+
// limit top resize border to 4px, which seems to be standard for modern WinUI apps
686+
if( isOnResizeBorder && pt.y > UIScale.scale( 4 ) )
687+
isOnResizeBorder = false;
688+
689+
if( isOnResizeBorder ) {
690+
Insets insets = window.getInsets();
691+
692+
// return HTTOPLEFT if mouse is over top resize border on left side
693+
// - hovering mouse shows top-left resize cursor
694+
// - left-click-and-drag resizes window
695+
if( pt.x <= insets.left + UIScale.scale( 12 ) )
696+
return new LRESULT( HTTOPLEFT );
697+
698+
// return HTTOPRIGHT if mouse is over top resize border on right side
699+
// - hovering mouse shows top-right resize cursor
700+
// - left-click-and-drag resizes window
701+
if( pt.x >= window.getWidth() - insets.right - UIScale.scale( 12 ) )
702+
return new LRESULT( HTTOPRIGHT );
703+
704+
// return HTTOP if mouse is over top resize border
705+
// - hovering mouse shows vertical resize cursor
706+
// - left-click-and-drag vertically resizes window
707+
return new LRESULT( HTTOP );
708+
}
709+
677710
// return HTSYSMENU if mouse is over application icon
678711
// - left-click on HTSYSMENU area shows system menu
679712
// - double-left-click sends WM_CLOSE
@@ -697,16 +730,6 @@ private LRESULT WmNcHitTest( HWND hwnd, int uMsg, WPARAM wParam, LPARAM lParam )
697730
if( contains( closeButtonBounds, pt ) )
698731
return new LRESULT( HTCLOSE );
699732

700-
int resizeBorderHeight = getResizeHandleHeight();
701-
boolean isOnResizeBorder = (y < resizeBorderHeight) &&
702-
(User32.INSTANCE.GetWindowLong( hwnd, GWL_STYLE ) & WS_THICKFRAME) != 0;
703-
704-
// return HTTOP if mouse is over top resize border
705-
// - hovering mouse shows vertical resize cursor
706-
// - left-click and drag vertically resizes window
707-
if( isOnResizeBorder )
708-
return new LRESULT( HTTOP );
709-
710733
boolean isOnTitleBar = (pt.y < titleBarHeight);
711734
if( isOnTitleBar ) {
712735
// return HTCLIENT if mouse is over any Swing component in title bar

0 commit comments

Comments
 (0)