Popup: fixed background flashing effect when drop shadows are disabled (issue #94)

This commit is contained in:
Karl Tauber
2020-05-14 14:48:12 +02:00
parent a4d7f278cf
commit 3bbc9517af

View File

@@ -35,8 +35,8 @@ import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
/** /**
* A popup factory that adds drop shadows to popups on Windows and Linux. * A popup factory that adds drop shadows to popups on Windows.
* On macOS, heavy weight popups (without drop shadow) are produced and the * On macOS and Linux, heavy weight popups (without drop shadow) are produced and the
* operating system automatically adds drop shadows. * operating system automatically adds drop shadows.
* *
* @author Karl Tauber * @author Karl Tauber
@@ -52,23 +52,18 @@ public class FlatPopupFactory
throws IllegalArgumentException throws IllegalArgumentException
{ {
if( !isDropShadowPainted( owner, contents ) ) if( !isDropShadowPainted( owner, contents ) )
return super.getPopup( owner, contents, x, y ); return new NonFlashingPopup( super.getPopup( owner, contents, x, y ), contents );
// macOS and Linux adds drop shadow to heavy weight popups // macOS and Linux adds drop shadow to heavy weight popups
if( SystemInfo.IS_MAC || SystemInfo.IS_LINUX ) { if( SystemInfo.IS_MAC || SystemInfo.IS_LINUX ) {
Popup popup = getHeavyWeightPopup( owner, contents, x, y ); Popup popup = getHeavyWeightPopup( owner, contents, x, y );
if ( popup != null ) { if( popup == null )
// fix background flashing popup = super.getPopup( owner, contents, x, y );
SwingUtilities.windowForComponent( contents ).setBackground( contents.getBackground() ); return new NonFlashingPopup( popup, contents );
}
return (popup != null) ? popup : super.getPopup( owner, contents, x, y );
} }
// create popup
Popup popup = super.getPopup( owner, contents, x, y );
// create drop shadow popup // create drop shadow popup
return new DropShadowPopup( popup, owner, contents ); return new DropShadowPopup( super.getPopup( owner, contents, x, y ), owner, contents );
} }
private boolean isDropShadowPainted( Component owner, Component contents ) { private boolean isDropShadowPainted( Component owner, Component contents ) {
@@ -124,26 +119,69 @@ public class FlatPopupFactory
} }
} }
//---- class DropShadowPopup ---------------------------------------------- //---- class NonFlashingPopup ---------------------------------------------
private class DropShadowPopup private class NonFlashingPopup
extends Popup extends Popup
{ {
private Popup delegate; private Popup delegate;
// heavy weight
protected Window popupWindow;
private Color oldPopupWindowBackground;
NonFlashingPopup( Popup delegate, Component contents ) {
this.delegate = delegate;
popupWindow = SwingUtilities.windowForComponent( contents );
if( popupWindow != null ) {
// heavy weight popup
// fix background flashing which may occur on some platforms
// (e.g. macOS and Linux) when using dark theme
oldPopupWindowBackground = popupWindow.getBackground();
popupWindow.setBackground( contents.getBackground() );
}
}
@Override
public void show() {
delegate.show();
}
@Override
public void hide() {
if( delegate != null ) {
delegate.hide();
delegate = null;
}
if( popupWindow != null ) {
// restore background so that it can not affect other LaFs (when switching)
// because popup windows are cached and reused
popupWindow.setBackground( oldPopupWindowBackground );
popupWindow = null;
}
}
}
//---- class DropShadowPopup ----------------------------------------------
private class DropShadowPopup
extends NonFlashingPopup
{
// light weight // light weight
private JComponent lightComp; private JComponent lightComp;
private Border oldBorder; private Border oldBorder;
private boolean oldOpaque; private boolean oldOpaque;
// heavy weight // heavy weight
private Window popupWindow;
private Popup dropShadowDelegate; private Popup dropShadowDelegate;
private Window dropShadowWindow; private Window dropShadowWindow;
private Color oldBackground; private Color oldDropShadowWindowBackground;
DropShadowPopup( Popup delegate, Component owner, Component contents ) { DropShadowPopup( Popup delegate, Component owner, Component contents ) {
this.delegate = delegate; super( delegate, contents );
// drop shadows on medium weight popups are not supported // drop shadows on medium weight popups are not supported
if( delegate.getClass().getName().endsWith( "MediumWeightPopup" ) ) if( delegate.getClass().getName().endsWith( "MediumWeightPopup" ) )
@@ -153,7 +191,6 @@ public class FlatPopupFactory
if( size.width <= 0 || size.height <= 0 ) if( size.width <= 0 || size.height <= 0 )
return; return;
popupWindow = SwingUtilities.windowForComponent( contents );
if( popupWindow != null ) { if( popupWindow != null ) {
// heavy weight popup // heavy weight popup
@@ -175,15 +212,15 @@ public class FlatPopupFactory
prefSize.width + insets.left + insets.right, prefSize.width + insets.left + insets.right,
prefSize.height + insets.top + insets.bottom ) ); prefSize.height + insets.top + insets.bottom ) );
// create popup for drop shadow // create heavy weight popup for drop shadow
int x = popupWindow.getX() - insets.left; int x = popupWindow.getX() - insets.left;
int y = popupWindow.getY() - insets.top; int y = popupWindow.getY() - insets.top;
dropShadowDelegate = getHeavyWeightPopup( owner, dropShadowPanel, x, y ); dropShadowDelegate = getHeavyWeightPopup( owner, dropShadowPanel, x, y );
// make drop shadow popup translucent // make drop shadow popup window translucent
dropShadowWindow = SwingUtilities.windowForComponent( dropShadowPanel ); dropShadowWindow = SwingUtilities.windowForComponent( dropShadowPanel );
if( dropShadowWindow != null ) { if( dropShadowWindow != null ) {
oldBackground = dropShadowWindow.getBackground(); oldDropShadowWindowBackground = dropShadowWindow.getBackground();
dropShadowWindow.setBackground( new Color( 0, true ) ); dropShadowWindow.setBackground( new Color( 0, true ) );
} }
} else { } else {
@@ -213,7 +250,7 @@ public class FlatPopupFactory
if( dropShadowDelegate != null ) if( dropShadowDelegate != null )
dropShadowDelegate.show(); dropShadowDelegate.show();
delegate.show(); super.show();
// fix location of light weight popup in case it has left or top drop shadow // fix location of light weight popup in case it has left or top drop shadow
if( lightComp != null ) { if( lightComp != null ) {
@@ -230,13 +267,10 @@ public class FlatPopupFactory
dropShadowDelegate = null; dropShadowDelegate = null;
} }
if( delegate != null ) { super.hide();
delegate.hide();
delegate = null;
}
if( dropShadowWindow != null ) { if( dropShadowWindow != null ) {
dropShadowWindow.setBackground( oldBackground ); dropShadowWindow.setBackground( oldDropShadowWindowBackground );
dropShadowWindow = null; dropShadowWindow = null;
} }