mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-08 15:00:54 +03:00
macOS: setting window background (of undecorated window) to translucent color (alpha < 255) did not show the window translucent (issue #705)
This commit is contained in:
@@ -16,6 +16,8 @@ FlatLaf Change Log
|
|||||||
|
|
||||||
#### Fixed bugs
|
#### Fixed bugs
|
||||||
|
|
||||||
|
- macOS: Setting window background (of undecorated window) to translucent color
|
||||||
|
(alpha < 255) did not show the window translucent. (issue #705)
|
||||||
- JIDE CommandMenuBar: Fixed `ClassCastException` when JIDE command bar displays
|
- JIDE CommandMenuBar: Fixed `ClassCastException` when JIDE command bar displays
|
||||||
`JideMenu` in popup. (PR #794)
|
`JideMenu` in popup. (PR #794)
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import java.awt.LayoutManager2;
|
|||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.awt.event.ComponentListener;
|
import java.awt.event.ComponentListener;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
@@ -85,6 +86,7 @@ public class FlatRootPaneUI
|
|||||||
private Object nativeWindowBorderData;
|
private Object nativeWindowBorderData;
|
||||||
private LayoutManager oldLayout;
|
private LayoutManager oldLayout;
|
||||||
private ComponentListener macFullWindowContentListener;
|
private ComponentListener macFullWindowContentListener;
|
||||||
|
private PropertyChangeListener macWindowBackgroundListener;
|
||||||
|
|
||||||
public static ComponentUI createUI( JComponent c ) {
|
public static ComponentUI createUI( JComponent c ) {
|
||||||
return new FlatRootPaneUI();
|
return new FlatRootPaneUI();
|
||||||
@@ -153,6 +155,8 @@ 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" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macClearBackgroundForTranslucentWindow( c );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -174,6 +178,7 @@ public class FlatRootPaneUI
|
|||||||
|
|
||||||
if( SystemInfo.isMacFullWindowContentSupported )
|
if( SystemInfo.isMacFullWindowContentSupported )
|
||||||
macFullWindowContentListener = FullWindowContentSupport.macInstallListeners( root );
|
macFullWindowContentListener = FullWindowContentSupport.macInstallListeners( root );
|
||||||
|
macInstallWindowBackgroundListener( root );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -184,6 +189,7 @@ public class FlatRootPaneUI
|
|||||||
FullWindowContentSupport.macUninstallListeners( root, macFullWindowContentListener );
|
FullWindowContentSupport.macUninstallListeners( root, macFullWindowContentListener );
|
||||||
macFullWindowContentListener = null;
|
macFullWindowContentListener = null;
|
||||||
}
|
}
|
||||||
|
macUninstallWindowBackgroundListener( root );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 1.1.2 */
|
/** @since 1.1.2 */
|
||||||
@@ -296,7 +302,7 @@ public class FlatRootPaneUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlatNativeMacLibrary.setWindowButtonsSpacing( getParentWindow(), buttonsSpacing );
|
FlatNativeMacLibrary.setWindowButtonsSpacing( getParentWindow( rootPane ), buttonsSpacing );
|
||||||
}
|
}
|
||||||
|
|
||||||
// update buttons bounds client property
|
// update buttons bounds client property
|
||||||
@@ -313,7 +319,7 @@ public class FlatRootPaneUI
|
|||||||
|
|
||||||
// reset window buttons spacing
|
// reset window buttons spacing
|
||||||
if( isMacButtonsSpacingSupported() )
|
if( isMacButtonsSpacingSupported() )
|
||||||
FlatNativeMacLibrary.setWindowButtonsSpacing( getParentWindow(), FlatNativeMacLibrary.BUTTONS_SPACING_DEFAULT );
|
FlatNativeMacLibrary.setWindowButtonsSpacing( getParentWindow( rootPane ), FlatNativeMacLibrary.BUTTONS_SPACING_DEFAULT );
|
||||||
|
|
||||||
// remove buttons bounds client property
|
// remove buttons bounds client property
|
||||||
FullWindowContentSupport.macUninstallFullWindowContentButtonsBoundsProperty( rootPane );
|
FullWindowContentSupport.macUninstallFullWindowContentButtonsBoundsProperty( rootPane );
|
||||||
@@ -323,11 +329,60 @@ public class FlatRootPaneUI
|
|||||||
return SystemInfo.isMacOS && SystemInfo.isJava_17_orLater && FlatNativeMacLibrary.isLoaded();
|
return SystemInfo.isMacOS && SystemInfo.isJava_17_orLater && FlatNativeMacLibrary.isLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Window getParentWindow() {
|
private void macInstallWindowBackgroundListener( JRootPane c ) {
|
||||||
|
if( !SystemInfo.isMacOS )
|
||||||
|
return;
|
||||||
|
|
||||||
|
Window window = getParentWindow( c );
|
||||||
|
if( window != null && macWindowBackgroundListener == null ) {
|
||||||
|
macWindowBackgroundListener = e -> macClearBackgroundForTranslucentWindow( c );
|
||||||
|
window.addPropertyChangeListener( "background", macWindowBackgroundListener );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void macUninstallWindowBackgroundListener( JRootPane c ) {
|
||||||
|
if( !SystemInfo.isMacOS )
|
||||||
|
return;
|
||||||
|
|
||||||
|
Window window = getParentWindow( c );
|
||||||
|
if( window != null && macWindowBackgroundListener != null ) {
|
||||||
|
window.removePropertyChangeListener( "background", macWindowBackgroundListener );
|
||||||
|
macWindowBackgroundListener = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When setting window background to translucent color (alpha < 255),
|
||||||
|
* Swing paints that window translucent on Windows and Linux, but not on macOS.
|
||||||
|
* The reason for this is that FlatLaf sets the background color of the root pane,
|
||||||
|
* and Swing behaves a bit differently on macOS than on other platforms in that case.
|
||||||
|
* Other L&Fs do not set root pane background, which is {@code null} by default.
|
||||||
|
* <p>
|
||||||
|
* To fix this problem, set the root pane background to {@code null}
|
||||||
|
* if windows uses a translucent background.
|
||||||
|
*/
|
||||||
|
private void macClearBackgroundForTranslucentWindow( JRootPane c ) {
|
||||||
|
if( !SystemInfo.isMacOS )
|
||||||
|
return;
|
||||||
|
|
||||||
|
Window window = getParentWindow( c );
|
||||||
|
if( window != null ) {
|
||||||
|
Color windowBackground = window.getBackground();
|
||||||
|
if( windowBackground != null &&
|
||||||
|
windowBackground.getAlpha() < 255 &&
|
||||||
|
c.getBackground() instanceof UIResource )
|
||||||
|
{
|
||||||
|
// clear root pane background
|
||||||
|
c.setBackground( null );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Window getParentWindow( JRootPane c ) {
|
||||||
// not using SwingUtilities.windowForComponent() or SwingUtilities.getWindowAncestor()
|
// not using SwingUtilities.windowForComponent() or SwingUtilities.getWindowAncestor()
|
||||||
// here because root panes may be nested and used anywhere (e.g. in JInternalFrame)
|
// here because root panes may be nested and used anywhere (e.g. in JInternalFrame)
|
||||||
// but we're only interested in the "root" root pane, which is a direct child of the window
|
// but we're only interested in the "root" root pane, which is a direct child of the window
|
||||||
Container parent = rootPane.getParent();
|
Container parent = c.getParent();
|
||||||
return (parent instanceof Window) ? (Window) parent : null;
|
return (parent instanceof Window) ? (Window) parent : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,6 +444,12 @@ public class FlatRootPaneUI
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "ancestor":
|
case "ancestor":
|
||||||
|
if( e.getNewValue() instanceof Window )
|
||||||
|
macClearBackgroundForTranslucentWindow( rootPane );
|
||||||
|
|
||||||
|
macUninstallWindowBackgroundListener( rootPane );
|
||||||
|
macInstallWindowBackgroundListener( rootPane );
|
||||||
|
|
||||||
// FlatNativeMacLibrary.setWindowButtonsSpacing() and
|
// FlatNativeMacLibrary.setWindowButtonsSpacing() and
|
||||||
// FullWindowContentSupport.macUpdateFullWindowContentButtonsBoundsProperty()
|
// FullWindowContentSupport.macUpdateFullWindowContentButtonsBoundsProperty()
|
||||||
// require a native window, but setting the client properties
|
// require a native window, but setting the client properties
|
||||||
|
|||||||
@@ -32,8 +32,10 @@ public class FlatTestPanel
|
|||||||
int width = getWidth();
|
int width = getWidth();
|
||||||
int height = getHeight();
|
int height = getHeight();
|
||||||
|
|
||||||
g.setColor( super.getBackground() );
|
if( isOpaque() ) {
|
||||||
g.fillRect( 0, 0, width, height );
|
g.setColor( super.getBackground() );
|
||||||
|
g.fillRect( 0, 0, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
if( isPaintBackgroundPattern() ) {
|
if( isPaintBackgroundPattern() ) {
|
||||||
g.setColor( Color.magenta );
|
g.setColor( Color.magenta );
|
||||||
|
|||||||
@@ -76,6 +76,14 @@ public class FlatWindowDecorationsTest
|
|||||||
initComponents();
|
initComponents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateUI() {
|
||||||
|
super.updateUI();
|
||||||
|
|
||||||
|
if( translucentWindowBackgroundCheckBox != null )
|
||||||
|
translucentWindowBackgroundChanged();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addNotify() {
|
public void addNotify() {
|
||||||
super.addNotify();
|
super.addNotify();
|
||||||
@@ -237,6 +245,27 @@ public class FlatWindowDecorationsTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void translucentWindowBackgroundChanged() {
|
||||||
|
boolean selected = translucentWindowBackgroundCheckBox.isSelected();
|
||||||
|
if( selected && !undecoratedCheckBox.isSelected() ) {
|
||||||
|
undecoratedCheckBox.setSelected( true );
|
||||||
|
undecoratedChanged();
|
||||||
|
}
|
||||||
|
undecoratedCheckBox.setEnabled( !selected );
|
||||||
|
|
||||||
|
Color background = selected
|
||||||
|
? new Color( 100, 0, 0, 100 )
|
||||||
|
: UIManager.getColor( "control" );
|
||||||
|
|
||||||
|
Window window = SwingUtilities.windowForComponent( this );
|
||||||
|
window.setBackground( background );
|
||||||
|
|
||||||
|
for( Component c = this; c != null; c = c.getParent() ) {
|
||||||
|
if( c instanceof JComponent )
|
||||||
|
LookAndFeel.installProperty( (JComponent) c, "opaque", !selected );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void addMenu() {
|
private void addMenu() {
|
||||||
JMenu menu = new JMenu( "Hello" );
|
JMenu menu = new JMenu( "Hello" );
|
||||||
menu.add( new JMenuItem( "world" ) );
|
menu.add( new JMenuItem( "world" ) );
|
||||||
@@ -543,6 +572,7 @@ debug*/
|
|||||||
colorizeTitleBarCheckBox = new JCheckBox();
|
colorizeTitleBarCheckBox = new JCheckBox();
|
||||||
colorizeMenuBarCheckBox = new JCheckBox();
|
colorizeMenuBarCheckBox = new JCheckBox();
|
||||||
colorizeMenusCheckBox = new JCheckBox();
|
colorizeMenusCheckBox = new JCheckBox();
|
||||||
|
translucentWindowBackgroundCheckBox = new JCheckBox();
|
||||||
JButton openDialogButton = new JButton();
|
JButton openDialogButton = new JButton();
|
||||||
JButton openFrameButton = new JButton();
|
JButton openFrameButton = new JButton();
|
||||||
typeNormalRadioButton = new JRadioButton();
|
typeNormalRadioButton = new JRadioButton();
|
||||||
@@ -885,6 +915,7 @@ debug*/
|
|||||||
"[]" +
|
"[]" +
|
||||||
"[]" +
|
"[]" +
|
||||||
"[]" +
|
"[]" +
|
||||||
|
"[]para" +
|
||||||
"[]"));
|
"[]"));
|
||||||
|
|
||||||
//---- unifiedBackgroundCheckBox ----
|
//---- unifiedBackgroundCheckBox ----
|
||||||
@@ -906,6 +937,11 @@ debug*/
|
|||||||
colorizeMenusCheckBox.setText("colorize menus");
|
colorizeMenusCheckBox.setText("colorize menus");
|
||||||
colorizeMenusCheckBox.addActionListener(e -> colorizeMenus());
|
colorizeMenusCheckBox.addActionListener(e -> colorizeMenus());
|
||||||
panel5.add(colorizeMenusCheckBox, "cell 0 3");
|
panel5.add(colorizeMenusCheckBox, "cell 0 3");
|
||||||
|
|
||||||
|
//---- translucentWindowBackgroundCheckBox ----
|
||||||
|
translucentWindowBackgroundCheckBox.setText("translucent window background");
|
||||||
|
translucentWindowBackgroundCheckBox.addActionListener(e -> translucentWindowBackgroundChanged());
|
||||||
|
panel5.add(translucentWindowBackgroundCheckBox, "cell 0 4");
|
||||||
}
|
}
|
||||||
add(panel5, "cell 2 1");
|
add(panel5, "cell 2 1");
|
||||||
|
|
||||||
@@ -1169,6 +1205,7 @@ debug*/
|
|||||||
private JCheckBox colorizeTitleBarCheckBox;
|
private JCheckBox colorizeTitleBarCheckBox;
|
||||||
private JCheckBox colorizeMenuBarCheckBox;
|
private JCheckBox colorizeMenuBarCheckBox;
|
||||||
private JCheckBox colorizeMenusCheckBox;
|
private JCheckBox colorizeMenusCheckBox;
|
||||||
|
private JCheckBox translucentWindowBackgroundCheckBox;
|
||||||
private JRadioButton typeNormalRadioButton;
|
private JRadioButton typeNormalRadioButton;
|
||||||
private JRadioButton typeUtilityRadioButton;
|
private JRadioButton typeUtilityRadioButton;
|
||||||
private JRadioButton typeSmallRadioButton;
|
private JRadioButton typeSmallRadioButton;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
JFDML JFormDesigner: "8.1.0.0.283" Java: "19.0.2" encoding: "UTF-8"
|
JFDML JFormDesigner: "8.2.1.0.348" Java: "21.0.1" encoding: "UTF-8"
|
||||||
|
|
||||||
new FormModel {
|
new FormModel {
|
||||||
contentType: "form/swing"
|
contentType: "form/swing"
|
||||||
@@ -449,7 +449,7 @@ new FormModel {
|
|||||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
"$layoutConstraints": "ltr,hidemode 3,gap 0 0"
|
"$layoutConstraints": "ltr,hidemode 3,gap 0 0"
|
||||||
"$columnConstraints": "[left]"
|
"$columnConstraints": "[left]"
|
||||||
"$rowConstraints": "[][][][]"
|
"$rowConstraints": "[][][][]para[]"
|
||||||
} ) {
|
} ) {
|
||||||
name: "panel5"
|
name: "panel5"
|
||||||
"border": new javax.swing.border.TitledBorder( "Color" )
|
"border": new javax.swing.border.TitledBorder( "Color" )
|
||||||
@@ -493,6 +493,16 @@ new FormModel {
|
|||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 0 3"
|
"value": "cell 0 3"
|
||||||
} )
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||||
|
name: "translucentWindowBackgroundCheckBox"
|
||||||
|
"text": "translucent window background"
|
||||||
|
auxiliary() {
|
||||||
|
"JavaCodeGenerator.variableLocal": false
|
||||||
|
}
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "translucentWindowBackgroundChanged", false ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 4"
|
||||||
|
} )
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 2 1"
|
"value": "cell 2 1"
|
||||||
} )
|
} )
|
||||||
|
|||||||
Reference in New Issue
Block a user