From 9a727f68ce29335dfa16edeadcd8feed05133f81 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sun, 17 Mar 2024 18:01:03 +0100 Subject: [PATCH] Window decorations: fixed missing window top border on Windows 10 in "full window content" mode (issue #809) --- CHANGELOG.md | 2 ++ .../formdev/flatlaf/ui/FlatRootPaneUI.java | 18 +++++++++++ .../com/formdev/flatlaf/ui/FlatTitlePane.java | 31 ++++++++++++++++--- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8488781..844a6d15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ FlatLaf Change Log - TabbedPane: Fixed swapped back and forward scroll buttons when using `TabbedPane.scrollButtonsPlacement = trailing` (regression in FlatLaf 3.3). - Extras: `FlatSVGIcon` color filters now support linear gradients. (PR #817) +- Fixed missing window top border on Windows 10 in "full window content" mode. + (issue 809) ## 3.4 diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRootPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRootPaneUI.java index a2dfab1c..5dafefce 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRootPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRootPaneUI.java @@ -270,6 +270,7 @@ public class FlatRootPaneUI // layer title pane under frame content layer to allow placing menu bar over title pane protected final static Integer TITLE_PANE_LAYER = JLayeredPane.FRAME_CONTENT_LAYER - 1; private final static Integer TITLE_PANE_MOUSE_LAYER = JLayeredPane.FRAME_CONTENT_LAYER - 2; + private final static Integer WINDOW_TOP_BORDER_LAYER = Integer.MAX_VALUE; // for fullWindowContent mode, layer title pane over frame content layer to allow placing title bar buttons over content /** @since 3.4 */ @@ -285,11 +286,15 @@ public class FlatRootPaneUI if( titlePane != null ) { layeredPane.remove( titlePane ); layeredPane.remove( titlePane.mouseLayer ); + if( titlePane.windowTopBorderLayer != null ) + layeredPane.remove( titlePane.windowTopBorderLayer ); } if( newTitlePane != null ) { layeredPane.add( newTitlePane, getLayerForTitlePane() ); layeredPane.add( newTitlePane.mouseLayer, TITLE_PANE_MOUSE_LAYER ); + if( newTitlePane.windowTopBorderLayer != null && newTitlePane.isWindowTopBorderNeeded() && isFullWindowContent( rootPane ) ) + layeredPane.add( newTitlePane.windowTopBorderLayer, WINDOW_TOP_BORDER_LAYER ); } titlePane = newTitlePane; @@ -446,6 +451,13 @@ public class FlatRootPaneUI case FlatClientProperties.FULL_WINDOW_CONTENT: if( titlePane != null ) { rootPane.getLayeredPane().setLayer( titlePane, getLayerForTitlePane() ); + if( titlePane.windowTopBorderLayer != null ) { + JLayeredPane layeredPane = rootPane.getLayeredPane(); + if( titlePane.isWindowTopBorderNeeded() && isFullWindowContent( rootPane ) ) + layeredPane.add( titlePane.windowTopBorderLayer, WINDOW_TOP_BORDER_LAYER ); + else + layeredPane.remove( titlePane.windowTopBorderLayer ); + } titlePane.updateIcon(); titlePane.updateVisibility(); titlePane.updateFullWindowContentButtonsBoundsProperty(); @@ -591,6 +603,12 @@ public class FlatRootPaneUI titlePane.setBounds( 0, 0, width, prefHeight ); titlePane.mouseLayer.setBounds( 0, 0, width, prefHeight ); + if( titlePane.windowTopBorderLayer != null ) { + boolean show = isFullWindowContent && !titlePane.isWindowMaximized() && !isFullScreen; + if( show ) + titlePane.windowTopBorderLayer.setBounds( 0, 0, width, 1 ); + titlePane.windowTopBorderLayer.setVisible( show ); + } if( !isFullWindowContent ) nextY += prefHeight; 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 82f5a22b..7afcb8f7 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 @@ -110,6 +110,7 @@ public class FlatTitlePane extends JComponent { static final String KEY_DEBUG_SHOW_RECTANGLES = "FlatLaf.debug.titlebar.showRectangles"; + private static final boolean isWindows_10 = SystemInfo.isWindows_10_orLater && !SystemInfo.isWindows_11_orLater; /** @since 2.5 */ protected final Font titleFont; protected final Color activeBackground; @@ -166,6 +167,16 @@ public class FlatTitlePane */ final JPanel mouseLayer; + /** + * This panel paint a border at the top of the window in fullWindowContent mode, + * if FlatLaf window decorations are enabled. + * Only used on Windows 10. + *

+ * This panel is not a child of the title pane. + * Instead it is added by FlatRootPaneUI to the layered pane at a layer over all other layers. + */ + final JPanel windowTopBorderLayer; + public FlatTitlePane( JRootPane rootPane ) { this.rootPane = rootPane; @@ -207,6 +218,14 @@ public class FlatTitlePane mouseLayer.addMouseListener( handler ); mouseLayer.addMouseMotionListener( handler ); + if( isWindows_10 && FlatNativeWindowBorder.isSupported() ) { + windowTopBorderLayer = new JPanel(); + windowTopBorderLayer.setVisible( false ); + windowTopBorderLayer.setOpaque( false ); + windowTopBorderLayer.setBorder( FlatUIUtils.nonUIResource( FlatNativeWindowBorder.WindowTopBorder.getInstance() ) ); + } else + windowTopBorderLayer = null; + applyComponentOrientation( rootPane.getComponentOrientation() ); } @@ -919,6 +938,10 @@ public class FlatTitlePane return window != null && FlatNativeWindowBorder.hasCustomDecoration( window ); } + boolean isWindowTopBorderNeeded() { + return isWindows_10 && hasNativeCustomDecoration(); + } + // used to invoke updateNativeTitleBarHeightAndHitTestSpots() only once from latest invokeLater() private int laterCounter; @@ -1146,7 +1169,7 @@ public class FlatTitlePane } else if( borderColor != null && (rootPane.getJMenuBar() == null || !rootPane.getJMenuBar().isVisible()) ) insets.bottom += UIScale.scale( 1 ); - if( !SystemInfo.isWindows_11_orLater && hasNativeCustomDecoration() && !isWindowMaximized() ) + if( isWindowTopBorderNeeded() && !isWindowMaximized() ) insets = FlatUIUtils.addInsets( insets, WindowTopBorder.getInstance().getBorderInsets() ); return insets; @@ -1165,7 +1188,7 @@ public class FlatTitlePane FlatUIUtils.paintFilledRectangle( g, borderColor, x, y + height - lineHeight, width, lineHeight ); } - if( !SystemInfo.isWindows_11_orLater && hasNativeCustomDecoration() && !isWindowMaximized() ) + if( isWindowTopBorderNeeded() && !isWindowMaximized() && !isFullWindowContent() ) WindowTopBorder.getInstance().paintBorder( c, g, x, y, width, height ); } @@ -1329,7 +1352,7 @@ public class FlatTitlePane activeChanged( true ); updateNativeTitleBarHeightAndHitTestSpots(); - if( !SystemInfo.isWindows_11_orLater && hasNativeCustomDecoration() ) + if( isWindowTopBorderNeeded() ) WindowTopBorder.getInstance().repaintBorder( FlatTitlePane.this ); repaintWindowBorder(); @@ -1340,7 +1363,7 @@ public class FlatTitlePane activeChanged( false ); updateNativeTitleBarHeightAndHitTestSpots(); - if( !SystemInfo.isWindows_11_orLater && hasNativeCustomDecoration() ) + if( isWindowTopBorderNeeded() ) WindowTopBorder.getInstance().repaintBorder( FlatTitlePane.this ); repaintWindowBorder();