mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-11 06:27:13 -06:00
removed support for JetBrains custom decorations
This commit is contained in:
@@ -42,6 +42,14 @@ FlatLaf Change Log
|
|||||||
- Fixed broken rendering after resizing window to minimum size and then
|
- Fixed broken rendering after resizing window to minimum size and then
|
||||||
increasing size again. (issue #767)
|
increasing size again. (issue #767)
|
||||||
|
|
||||||
|
#### Incompatibilities
|
||||||
|
|
||||||
|
- Removed support for JetBrains custom decorations, which required
|
||||||
|
[JetBrains Runtime](https://github.com/JetBrains/JetBrainsRuntime/wiki) (JBR)
|
||||||
|
8 or 11. It did not work for JBR 17. System property
|
||||||
|
`flatlaf.useJetBrainsCustomDecorations` is now ignored. **Note**: FlatLaf
|
||||||
|
window decorations continue to work with JBR.
|
||||||
|
|
||||||
|
|
||||||
## 3.2.5
|
## 3.2.5
|
||||||
|
|
||||||
|
|||||||
@@ -183,17 +183,11 @@ public abstract class FlatLaf
|
|||||||
* This depends on the operating system and on the used Java runtime.
|
* This depends on the operating system and on the used Java runtime.
|
||||||
* <p>
|
* <p>
|
||||||
* This method returns {@code true} on Windows 10/11 (see exception below)
|
* This method returns {@code true} on Windows 10/11 (see exception below)
|
||||||
* and on Linux, {@code false} otherwise.
|
* and on Linux, otherwise returns {@code false}.
|
||||||
|
* <p>
|
||||||
|
* Returns also {@code false} on Windows 10/11 if
|
||||||
|
* FlatLaf native window border support is available (requires Windows 10/11).
|
||||||
* <p>
|
* <p>
|
||||||
* Returns also {@code false} on Windows 10/11 if:
|
|
||||||
* <ul>
|
|
||||||
* <li>FlatLaf native window border support is available (requires Windows 10/11)</li>
|
|
||||||
* <li>running in
|
|
||||||
* <a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">JetBrains Runtime 11 (or later)</a>
|
|
||||||
* (<a href="https://github.com/JetBrains/JetBrainsRuntime">source code on github</a>)
|
|
||||||
* and JBR supports custom window decorations
|
|
||||||
* </li>
|
|
||||||
* </ul>
|
|
||||||
* In these cases, custom decorations are enabled by the root pane.
|
* In these cases, custom decorations are enabled by the root pane.
|
||||||
* Usage of {@link JFrame#setDefaultLookAndFeelDecorated(boolean)} or
|
* Usage of {@link JFrame#setDefaultLookAndFeelDecorated(boolean)} or
|
||||||
* {@link JDialog#setDefaultLookAndFeelDecorated(boolean)} is not necessary.
|
* {@link JDialog#setDefaultLookAndFeelDecorated(boolean)} is not necessary.
|
||||||
|
|||||||
@@ -103,7 +103,10 @@ public interface FlatSystemProperties
|
|||||||
* <p>
|
* <p>
|
||||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||||
* <strong>Default</strong> {@code false} (since v2; was {@code true} in v1)
|
* <strong>Default</strong> {@code false} (since v2; was {@code true} in v1)
|
||||||
|
*
|
||||||
|
* @deprecated No longer used since FlatLaf 3.3. Retained for API compatibility.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations";
|
String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -17,20 +17,26 @@
|
|||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Component;
|
||||||
import java.awt.Container;
|
import java.awt.Container;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.Toolkit;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
import javax.swing.JRootPane;
|
import javax.swing.JRootPane;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.event.ChangeListener;
|
import javax.swing.event.ChangeListener;
|
||||||
|
import javax.swing.plaf.BorderUIResource;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.FlatLaf;
|
import com.formdev.flatlaf.FlatLaf;
|
||||||
import com.formdev.flatlaf.FlatSystemProperties;
|
import com.formdev.flatlaf.FlatSystemProperties;
|
||||||
import com.formdev.flatlaf.ui.JBRCustomDecorations.JBRWindowTopBorder;
|
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,27 +60,15 @@ public class FlatNativeWindowBorder
|
|||||||
!SystemInfo.isWinPE &&
|
!SystemInfo.isWinPE &&
|
||||||
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_WINDOW_DECORATIONS, true );
|
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_WINDOW_DECORATIONS, true );
|
||||||
|
|
||||||
// check this field before using class JBRCustomDecorations to avoid unnecessary loading of that class
|
|
||||||
private static final boolean canUseJBRCustomDecorations =
|
|
||||||
canUseWindowDecorations &&
|
|
||||||
SystemInfo.isJetBrainsJVM_11_orLater &&
|
|
||||||
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_JETBRAINS_CUSTOM_DECORATIONS, false );
|
|
||||||
|
|
||||||
private static Boolean supported;
|
private static Boolean supported;
|
||||||
private static Provider nativeProvider;
|
private static Provider nativeProvider;
|
||||||
|
|
||||||
public static boolean isSupported() {
|
public static boolean isSupported() {
|
||||||
if( canUseJBRCustomDecorations )
|
|
||||||
return JBRCustomDecorations.isSupported();
|
|
||||||
|
|
||||||
initialize();
|
initialize();
|
||||||
return supported;
|
return supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Object install( JRootPane rootPane ) {
|
static Object install( JRootPane rootPane ) {
|
||||||
if( canUseJBRCustomDecorations )
|
|
||||||
return JBRCustomDecorations.install( rootPane );
|
|
||||||
|
|
||||||
if( !isSupported() )
|
if( !isSupported() )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -163,11 +157,6 @@ public class FlatNativeWindowBorder
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void uninstall( JRootPane rootPane, Object data ) {
|
static void uninstall( JRootPane rootPane, Object data ) {
|
||||||
if( canUseJBRCustomDecorations ) {
|
|
||||||
JBRCustomDecorations.uninstall( rootPane, data );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !isSupported() )
|
if( !isSupported() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -215,9 +204,6 @@ public class FlatNativeWindowBorder
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasCustomDecoration( Window window ) {
|
public static boolean hasCustomDecoration( Window window ) {
|
||||||
if( canUseJBRCustomDecorations )
|
|
||||||
return JBRCustomDecorations.hasCustomDecoration( window );
|
|
||||||
|
|
||||||
if( !isSupported() )
|
if( !isSupported() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -225,11 +211,6 @@ public class FlatNativeWindowBorder
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void setHasCustomDecoration( Window window, boolean hasCustomDecoration ) {
|
public static void setHasCustomDecoration( Window window, boolean hasCustomDecoration ) {
|
||||||
if( canUseJBRCustomDecorations ) {
|
|
||||||
JBRCustomDecorations.setHasCustomDecoration( window, hasCustomDecoration );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !isSupported() )
|
if( !isSupported() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -240,11 +221,6 @@ public class FlatNativeWindowBorder
|
|||||||
List<Rectangle> hitTestSpots, Rectangle appIconBounds, Rectangle minimizeButtonBounds,
|
List<Rectangle> hitTestSpots, Rectangle appIconBounds, Rectangle minimizeButtonBounds,
|
||||||
Rectangle maximizeButtonBounds, Rectangle closeButtonBounds )
|
Rectangle maximizeButtonBounds, Rectangle closeButtonBounds )
|
||||||
{
|
{
|
||||||
if( canUseJBRCustomDecorations ) {
|
|
||||||
JBRCustomDecorations.setTitleBarHeightAndHitTestSpots( window, titleBarHeight, hitTestSpots );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !isSupported() )
|
if( !isSupported() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -253,7 +229,7 @@ public class FlatNativeWindowBorder
|
|||||||
}
|
}
|
||||||
|
|
||||||
static boolean showWindow( Window window, int cmd ) {
|
static boolean showWindow( Window window, int cmd ) {
|
||||||
if( canUseJBRCustomDecorations || !isSupported() )
|
if( !isSupported() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return nativeProvider.showWindow( window, cmd );
|
return nativeProvider.showWindow( window, cmd );
|
||||||
@@ -320,20 +296,36 @@ public class FlatNativeWindowBorder
|
|||||||
* No longer needed since Windows 11.
|
* No longer needed since Windows 11.
|
||||||
*/
|
*/
|
||||||
static class WindowTopBorder
|
static class WindowTopBorder
|
||||||
extends JBRCustomDecorations.JBRWindowTopBorder
|
extends BorderUIResource.EmptyBorderUIResource
|
||||||
{
|
{
|
||||||
private static WindowTopBorder instance;
|
private static WindowTopBorder instance;
|
||||||
|
|
||||||
static JBRWindowTopBorder getInstance() {
|
private final Color activeLightColor = new Color( 0x707070 );
|
||||||
if( canUseJBRCustomDecorations )
|
private final Color activeDarkColor = new Color( 0x2D2E2F );
|
||||||
return JBRWindowTopBorder.getInstance();
|
private final Color inactiveLightColor = new Color( 0xaaaaaa );
|
||||||
|
private final Color inactiveDarkColor = new Color( 0x494A4B );
|
||||||
|
|
||||||
|
private boolean colorizationAffectsBorders;
|
||||||
|
private Color activeColor;
|
||||||
|
|
||||||
|
static WindowTopBorder getInstance() {
|
||||||
if( instance == null )
|
if( instance == null )
|
||||||
instance = new WindowTopBorder();
|
instance = new WindowTopBorder();
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
WindowTopBorder() {
|
||||||
|
super( 1, 0, 0, 0 );
|
||||||
|
|
||||||
|
update();
|
||||||
|
installListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void update() {
|
||||||
|
colorizationAffectsBorders = isColorizationColorAffectsBorders();
|
||||||
|
activeColor = calculateActiveBorderColor();
|
||||||
|
}
|
||||||
|
|
||||||
void installListeners() {
|
void installListeners() {
|
||||||
nativeProvider.addChangeListener( e -> {
|
nativeProvider.addChangeListener( e -> {
|
||||||
update();
|
update();
|
||||||
@@ -346,19 +338,69 @@ public class FlatNativeWindowBorder
|
|||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean isColorizationColorAffectsBorders() {
|
boolean isColorizationColorAffectsBorders() {
|
||||||
return nativeProvider.isColorizationColorAffectsBorders();
|
return nativeProvider.isColorizationColorAffectsBorders();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
Color getColorizationColor() {
|
Color getColorizationColor() {
|
||||||
return nativeProvider.getColorizationColor();
|
return nativeProvider.getColorizationColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
int getColorizationColorBalance() {
|
int getColorizationColorBalance() {
|
||||||
return nativeProvider.getColorizationColorBalance();
|
return nativeProvider.getColorizationColorBalance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Color calculateActiveBorderColor() {
|
||||||
|
if( !colorizationAffectsBorders )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Color colorizationColor = getColorizationColor();
|
||||||
|
if( colorizationColor != null ) {
|
||||||
|
int colorizationColorBalance = getColorizationColorBalance();
|
||||||
|
if( colorizationColorBalance < 0 || colorizationColorBalance > 100 )
|
||||||
|
colorizationColorBalance = 100;
|
||||||
|
|
||||||
|
if( colorizationColorBalance == 0 )
|
||||||
|
return new Color( 0xD9D9D9 );
|
||||||
|
if( colorizationColorBalance == 100 )
|
||||||
|
return colorizationColor;
|
||||||
|
|
||||||
|
float alpha = colorizationColorBalance / 100.0f;
|
||||||
|
float remainder = 1 - alpha;
|
||||||
|
int r = Math.round( colorizationColor.getRed() * alpha + 0xD9 * remainder );
|
||||||
|
int g = Math.round( colorizationColor.getGreen() * alpha + 0xD9 * remainder );
|
||||||
|
int b = Math.round( colorizationColor.getBlue() * alpha + 0xD9 * remainder );
|
||||||
|
|
||||||
|
// avoid potential IllegalArgumentException in Color constructor
|
||||||
|
r = Math.min( Math.max( r, 0 ), 255 );
|
||||||
|
g = Math.min( Math.max( g, 0 ), 255 );
|
||||||
|
b = Math.min( Math.max( b, 0 ), 255 );
|
||||||
|
|
||||||
|
return new Color( r, g, b );
|
||||||
|
}
|
||||||
|
|
||||||
|
Color activeBorderColor = (Color) Toolkit.getDefaultToolkit().getDesktopProperty( "win.frame.activeBorderColor" );
|
||||||
|
return (activeBorderColor != null) ? activeBorderColor : UIManager.getColor( "MenuBar.borderColor" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||||
|
Window window = SwingUtilities.windowForComponent( c );
|
||||||
|
boolean active = window != null && window.isActive();
|
||||||
|
boolean dark = FlatLaf.isLafDark();
|
||||||
|
|
||||||
|
g.setColor( active
|
||||||
|
? (activeColor != null ? activeColor : (dark ? activeDarkColor : activeLightColor))
|
||||||
|
: (dark ? inactiveDarkColor : inactiveLightColor) );
|
||||||
|
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, this::paintImpl );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||||
|
g.fillRect( x, y, width, 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void repaintBorder( Component c ) {
|
||||||
|
c.repaint( 0, 0, c.getWidth(), 1 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ import javax.swing.plaf.RootPaneUI;
|
|||||||
import javax.swing.plaf.UIResource;
|
import javax.swing.plaf.UIResource;
|
||||||
import javax.swing.plaf.basic.BasicRootPaneUI;
|
import javax.swing.plaf.basic.BasicRootPaneUI;
|
||||||
import com.formdev.flatlaf.FlatClientProperties;
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
import com.formdev.flatlaf.FlatLaf;
|
|
||||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
@@ -156,10 +155,6 @@ public class FlatRootPaneUI
|
|||||||
if( background == null || background instanceof UIResource )
|
if( background == null || background instanceof UIResource )
|
||||||
parent.setBackground( UIManager.getColor( "control" ) );
|
parent.setBackground( UIManager.getColor( "control" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable dark window appearance on macOS when running in JetBrains Runtime
|
|
||||||
if( SystemInfo.isJetBrainsJVM && SystemInfo.isMacOS_10_14_Mojave_orLater )
|
|
||||||
c.putClientProperty( "jetbrains.awt.windowDarkAppearance", FlatLaf.isLafDark() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -839,10 +839,6 @@ public class FlatTitlePane
|
|||||||
window.dispatchEvent( new WindowEvent( window, WindowEvent.WINDOW_CLOSING ) );
|
window.dispatchEvent( new WindowEvent( window, WindowEvent.WINDOW_CLOSING ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasJBRCustomDecoration() {
|
|
||||||
return window != null && JBRCustomDecorations.hasCustomDecoration( window );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether windows uses native window border and has custom decorations enabled.
|
* Returns whether windows uses native window border and has custom decorations enabled.
|
||||||
*/
|
*/
|
||||||
@@ -900,9 +896,6 @@ public class FlatTitlePane
|
|||||||
iconBounds.width += iconInsets.right;
|
iconBounds.width += iconInsets.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( hasJBRCustomDecoration() )
|
|
||||||
hitTestSpots.add( iconBounds );
|
|
||||||
else
|
|
||||||
appIconBounds = iconBounds;
|
appIconBounds = iconBounds;
|
||||||
} else if( showIconBesideTitle && titleLabel.getIcon() != null && titleLabel.getUI() instanceof FlatTitleLabelUI ) {
|
} else if( showIconBesideTitle && titleLabel.getIcon() != null && titleLabel.getUI() instanceof FlatTitleLabelUI ) {
|
||||||
FlatTitleLabelUI ui = (FlatTitleLabelUI) titleLabel.getUI();
|
FlatTitleLabelUI ui = (FlatTitleLabelUI) titleLabel.getUI();
|
||||||
@@ -931,9 +924,6 @@ public class FlatTitlePane
|
|||||||
iconR.width += 2;
|
iconR.width += 2;
|
||||||
iconR.height += 2;
|
iconR.height += 2;
|
||||||
|
|
||||||
if( hasJBRCustomDecoration() )
|
|
||||||
hitTestSpots.add( iconR );
|
|
||||||
else
|
|
||||||
appIconBounds = iconR;
|
appIconBounds = iconR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,306 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 FormDev Software GmbH
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.formdev.flatlaf.ui;
|
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Component;
|
|
||||||
import java.awt.Container;
|
|
||||||
import java.awt.EventQueue;
|
|
||||||
import java.awt.Graphics;
|
|
||||||
import java.awt.Graphics2D;
|
|
||||||
import java.awt.Rectangle;
|
|
||||||
import java.awt.Toolkit;
|
|
||||||
import java.awt.Window;
|
|
||||||
import java.awt.event.HierarchyEvent;
|
|
||||||
import java.awt.event.HierarchyListener;
|
|
||||||
import java.beans.PropertyChangeListener;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import javax.swing.JRootPane;
|
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
import javax.swing.UIManager;
|
|
||||||
import javax.swing.plaf.BorderUIResource;
|
|
||||||
import com.formdev.flatlaf.FlatLaf;
|
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
|
||||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Support for custom window decorations provided by JetBrains Runtime (based on OpenJDK).
|
|
||||||
* Requires that the application runs on Windows 10 in a JetBrains Runtime 11 or later.
|
|
||||||
* <ul>
|
|
||||||
* <li><a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime</a></li>
|
|
||||||
* <li><a href="https://github.com/JetBrains/JetBrainsRuntime">https://github.com/JetBrains/JetBrainsRuntime</a></li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @author Karl Tauber
|
|
||||||
*/
|
|
||||||
public class JBRCustomDecorations
|
|
||||||
{
|
|
||||||
private static Boolean supported;
|
|
||||||
private static Method Window_hasCustomDecoration;
|
|
||||||
private static Method Window_setHasCustomDecoration;
|
|
||||||
private static Method WWindowPeer_setCustomDecorationTitleBarHeight;
|
|
||||||
private static Method WWindowPeer_setCustomDecorationHitTestSpots;
|
|
||||||
private static Method AWTAccessor_getComponentAccessor;
|
|
||||||
private static Method AWTAccessor_ComponentAccessor_getPeer;
|
|
||||||
|
|
||||||
public static boolean isSupported() {
|
|
||||||
initialize();
|
|
||||||
return supported;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Object install( JRootPane rootPane ) {
|
|
||||||
if( !isSupported() )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// check whether root pane already has a parent, which is the case when switching LaF
|
|
||||||
Container parent = rootPane.getParent();
|
|
||||||
if( parent != null ) {
|
|
||||||
if( parent instanceof Window )
|
|
||||||
FlatNativeWindowBorder.install( (Window) parent );
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use hierarchy listener to wait until the root pane is added to a window.
|
|
||||||
// Enabling JBR decorations must be done very early, probably before
|
|
||||||
// window becomes displayable (window.isDisplayable()). Tried also using
|
|
||||||
// "ancestor" property change event on root pane, but this is invoked too late.
|
|
||||||
HierarchyListener addListener = new HierarchyListener() {
|
|
||||||
@Override
|
|
||||||
public void hierarchyChanged( HierarchyEvent e ) {
|
|
||||||
if( e.getChanged() != rootPane || (e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) == 0 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
Container parent = e.getChangedParent();
|
|
||||||
if( parent instanceof Window )
|
|
||||||
FlatNativeWindowBorder.install( (Window) parent );
|
|
||||||
|
|
||||||
// remove listener since it is actually not possible to uninstall JBR decorations
|
|
||||||
// use invokeLater to remove listener to avoid that listener
|
|
||||||
// is removed while listener queue is processed
|
|
||||||
EventQueue.invokeLater( () -> {
|
|
||||||
rootPane.removeHierarchyListener( this );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
rootPane.addHierarchyListener( addListener );
|
|
||||||
return addListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void uninstall( JRootPane rootPane, Object data ) {
|
|
||||||
// remove listener (if not yet done)
|
|
||||||
if( data instanceof HierarchyListener )
|
|
||||||
rootPane.removeHierarchyListener( (HierarchyListener) data );
|
|
||||||
|
|
||||||
// since it is actually not possible to uninstall JBR decorations,
|
|
||||||
// simply reduce titleBarHeight so that it is still possible to resize window
|
|
||||||
// and remove hitTestSpots
|
|
||||||
Container parent = rootPane.getParent();
|
|
||||||
if( parent instanceof Window )
|
|
||||||
setHasCustomDecoration( (Window) parent, false );
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean hasCustomDecoration( Window window ) {
|
|
||||||
if( !isSupported() )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
return (Boolean) Window_hasCustomDecoration.invoke( window );
|
|
||||||
} catch( Exception ex ) {
|
|
||||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setHasCustomDecoration( Window window, boolean hasCustomDecoration ) {
|
|
||||||
if( !isSupported() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
if( hasCustomDecoration )
|
|
||||||
Window_setHasCustomDecoration.invoke( window );
|
|
||||||
else
|
|
||||||
setTitleBarHeightAndHitTestSpots( window, 4, Collections.emptyList() );
|
|
||||||
} catch( Exception ex ) {
|
|
||||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setTitleBarHeightAndHitTestSpots( Window window, int titleBarHeight, List<Rectangle> hitTestSpots ) {
|
|
||||||
if( !isSupported() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Object compAccessor = AWTAccessor_getComponentAccessor.invoke( null );
|
|
||||||
Object peer = AWTAccessor_ComponentAccessor_getPeer.invoke( compAccessor, window );
|
|
||||||
WWindowPeer_setCustomDecorationTitleBarHeight.invoke( peer, titleBarHeight );
|
|
||||||
WWindowPeer_setCustomDecorationHitTestSpots.invoke( peer, hitTestSpots );
|
|
||||||
} catch( Exception ex ) {
|
|
||||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void initialize() {
|
|
||||||
if( supported != null )
|
|
||||||
return;
|
|
||||||
supported = false;
|
|
||||||
|
|
||||||
// requires JetBrains Runtime 11 and Windows 10
|
|
||||||
if( !SystemInfo.isJetBrainsJVM_11_orLater || !SystemInfo.isWindows_10_orLater )
|
|
||||||
return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Class<?> awtAcessorClass = Class.forName( "sun.awt.AWTAccessor" );
|
|
||||||
Class<?> compAccessorClass = Class.forName( "sun.awt.AWTAccessor$ComponentAccessor" );
|
|
||||||
AWTAccessor_getComponentAccessor = awtAcessorClass.getDeclaredMethod( "getComponentAccessor" );
|
|
||||||
AWTAccessor_ComponentAccessor_getPeer = compAccessorClass.getDeclaredMethod( "getPeer", Component.class );
|
|
||||||
|
|
||||||
Class<?> peerClass = Class.forName( "sun.awt.windows.WWindowPeer" );
|
|
||||||
WWindowPeer_setCustomDecorationTitleBarHeight = peerClass.getDeclaredMethod( "setCustomDecorationTitleBarHeight", int.class );
|
|
||||||
WWindowPeer_setCustomDecorationHitTestSpots = peerClass.getDeclaredMethod( "setCustomDecorationHitTestSpots", List.class );
|
|
||||||
WWindowPeer_setCustomDecorationTitleBarHeight.setAccessible( true );
|
|
||||||
WWindowPeer_setCustomDecorationHitTestSpots.setAccessible( true );
|
|
||||||
|
|
||||||
Window_hasCustomDecoration = Window.class.getDeclaredMethod( "hasCustomDecoration" );
|
|
||||||
Window_setHasCustomDecoration = Window.class.getDeclaredMethod( "setHasCustomDecoration" );
|
|
||||||
Window_hasCustomDecoration.setAccessible( true );
|
|
||||||
Window_setHasCustomDecoration.setAccessible( true );
|
|
||||||
|
|
||||||
supported = true;
|
|
||||||
} catch( Exception ex ) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---- class JBRWindowTopBorder -------------------------------------------
|
|
||||||
|
|
||||||
static class JBRWindowTopBorder
|
|
||||||
extends BorderUIResource.EmptyBorderUIResource
|
|
||||||
{
|
|
||||||
private static JBRWindowTopBorder instance;
|
|
||||||
|
|
||||||
private final Color activeLightColor = new Color( 0x707070 );
|
|
||||||
private final Color activeDarkColor = new Color( 0x2D2E2F );
|
|
||||||
private final Color inactiveLightColor = new Color( 0xaaaaaa );
|
|
||||||
private final Color inactiveDarkColor = new Color( 0x494A4B );
|
|
||||||
|
|
||||||
private boolean colorizationAffectsBorders;
|
|
||||||
private Color activeColor;
|
|
||||||
|
|
||||||
static JBRWindowTopBorder getInstance() {
|
|
||||||
if( instance == null )
|
|
||||||
instance = new JBRWindowTopBorder();
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
JBRWindowTopBorder() {
|
|
||||||
super( 1, 0, 0, 0 );
|
|
||||||
|
|
||||||
update();
|
|
||||||
installListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
void update() {
|
|
||||||
colorizationAffectsBorders = isColorizationColorAffectsBorders();
|
|
||||||
activeColor = calculateActiveBorderColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
void installListeners() {
|
|
||||||
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
|
||||||
toolkit.addPropertyChangeListener( "win.dwm.colorizationColor.affects.borders", e -> {
|
|
||||||
colorizationAffectsBorders = isColorizationColorAffectsBorders();
|
|
||||||
activeColor = calculateActiveBorderColor();
|
|
||||||
} );
|
|
||||||
|
|
||||||
PropertyChangeListener l = e -> {
|
|
||||||
activeColor = calculateActiveBorderColor();
|
|
||||||
};
|
|
||||||
toolkit.addPropertyChangeListener( "win.dwm.colorizationColor", l );
|
|
||||||
toolkit.addPropertyChangeListener( "win.dwm.colorizationColorBalance", l );
|
|
||||||
toolkit.addPropertyChangeListener( "win.frame.activeBorderColor", l );
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isColorizationColorAffectsBorders() {
|
|
||||||
Object value = Toolkit.getDefaultToolkit().getDesktopProperty( "win.dwm.colorizationColor.affects.borders" );
|
|
||||||
return (value instanceof Boolean) ? (Boolean) value : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Color getColorizationColor() {
|
|
||||||
return (Color) Toolkit.getDefaultToolkit().getDesktopProperty( "win.dwm.colorizationColor" );
|
|
||||||
}
|
|
||||||
|
|
||||||
int getColorizationColorBalance() {
|
|
||||||
Object value = Toolkit.getDefaultToolkit().getDesktopProperty( "win.dwm.colorizationColorBalance" );
|
|
||||||
return (value instanceof Integer) ? (Integer) value : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color calculateActiveBorderColor() {
|
|
||||||
if( !colorizationAffectsBorders )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
Color colorizationColor = getColorizationColor();
|
|
||||||
if( colorizationColor != null ) {
|
|
||||||
int colorizationColorBalance = getColorizationColorBalance();
|
|
||||||
if( colorizationColorBalance < 0 || colorizationColorBalance > 100 )
|
|
||||||
colorizationColorBalance = 100;
|
|
||||||
|
|
||||||
if( colorizationColorBalance == 0 )
|
|
||||||
return new Color( 0xD9D9D9 );
|
|
||||||
if( colorizationColorBalance == 100 )
|
|
||||||
return colorizationColor;
|
|
||||||
|
|
||||||
float alpha = colorizationColorBalance / 100.0f;
|
|
||||||
float remainder = 1 - alpha;
|
|
||||||
int r = Math.round( colorizationColor.getRed() * alpha + 0xD9 * remainder );
|
|
||||||
int g = Math.round( colorizationColor.getGreen() * alpha + 0xD9 * remainder );
|
|
||||||
int b = Math.round( colorizationColor.getBlue() * alpha + 0xD9 * remainder );
|
|
||||||
|
|
||||||
// avoid potential IllegalArgumentException in Color constructor
|
|
||||||
r = Math.min( Math.max( r, 0 ), 255 );
|
|
||||||
g = Math.min( Math.max( g, 0 ), 255 );
|
|
||||||
b = Math.min( Math.max( b, 0 ), 255 );
|
|
||||||
|
|
||||||
return new Color( r, g, b );
|
|
||||||
}
|
|
||||||
|
|
||||||
Color activeBorderColor = (Color) Toolkit.getDefaultToolkit().getDesktopProperty( "win.frame.activeBorderColor" );
|
|
||||||
return (activeBorderColor != null) ? activeBorderColor : UIManager.getColor( "MenuBar.borderColor" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
|
||||||
Window window = SwingUtilities.windowForComponent( c );
|
|
||||||
boolean active = window != null && window.isActive();
|
|
||||||
boolean dark = FlatLaf.isLafDark();
|
|
||||||
|
|
||||||
g.setColor( active
|
|
||||||
? (activeColor != null ? activeColor : (dark ? activeDarkColor : activeLightColor))
|
|
||||||
: (dark ? inactiveDarkColor : inactiveLightColor) );
|
|
||||||
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, this::paintImpl );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
|
||||||
g.fillRect( x, y, width, 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
void repaintBorder( Component c ) {
|
|
||||||
c.repaint( 0, 0, c.getWidth(), 1 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -46,7 +46,6 @@ import com.formdev.flatlaf.icons.FlatAbstractIcon;
|
|||||||
import com.formdev.flatlaf.themes.FlatMacDarkLaf;
|
import com.formdev.flatlaf.themes.FlatMacDarkLaf;
|
||||||
import com.formdev.flatlaf.themes.FlatMacLightLaf;
|
import com.formdev.flatlaf.themes.FlatMacLightLaf;
|
||||||
import com.formdev.flatlaf.extras.FlatSVGUtils;
|
import com.formdev.flatlaf.extras.FlatSVGUtils;
|
||||||
import com.formdev.flatlaf.ui.JBRCustomDecorations;
|
|
||||||
import com.formdev.flatlaf.util.ColorFunctions;
|
import com.formdev.flatlaf.util.ColorFunctions;
|
||||||
import com.formdev.flatlaf.util.FontUtils;
|
import com.formdev.flatlaf.util.FontUtils;
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
@@ -931,12 +930,6 @@ class DemoFrame
|
|||||||
menuBarEmbeddedCheckBoxMenuItem.setSelected( UIManager.getBoolean( "TitlePane.menuBarEmbedded" ) );
|
menuBarEmbeddedCheckBoxMenuItem.setSelected( UIManager.getBoolean( "TitlePane.menuBarEmbedded" ) );
|
||||||
unifiedTitleBarMenuItem.setSelected( UIManager.getBoolean( "TitlePane.unifiedBackground" ) );
|
unifiedTitleBarMenuItem.setSelected( UIManager.getBoolean( "TitlePane.unifiedBackground" ) );
|
||||||
showTitleBarIconMenuItem.setSelected( UIManager.getBoolean( "TitlePane.showIcon" ) );
|
showTitleBarIconMenuItem.setSelected( UIManager.getBoolean( "TitlePane.showIcon" ) );
|
||||||
|
|
||||||
if( JBRCustomDecorations.isSupported() ) {
|
|
||||||
// If the JetBrains Runtime is used, it forces the use of it's own custom
|
|
||||||
// window decoration, which can not disabled.
|
|
||||||
windowDecorationsCheckBoxMenuItem.setEnabled( false );
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
unsupported( windowDecorationsCheckBoxMenuItem );
|
unsupported( windowDecorationsCheckBoxMenuItem );
|
||||||
unsupported( menuBarEmbeddedCheckBoxMenuItem );
|
unsupported( menuBarEmbeddedCheckBoxMenuItem );
|
||||||
|
|||||||
Reference in New Issue
Block a user