[FlatLaf 3.5.1] Repaint issue on Windows 11
Issue Description
I'm experiencing a repaint issue with FlatLaf 3.5.1 on Windows 11. My setup includes an AMD graphics card (RX 6700 XT) with three monitors (1920 x 1080, 120Hz). The issue occurs when using a JFrame with a JMenuBar. Notably, the same project does not exhibit the issue on Windows 10 with an Intel integrated graphics card.
Details:
- The issue persists across Java versions 11, 17, and 21 on Windows 11.
- The FlatLaf demo app also shows the same repaint issue on Windows 11.
https://github.com/user-attachments/assets/9c2bcdc7-94ac-4856-bcb1-090b2b971867
Observations:
- The issue only occurs with FlatLaf versions greater than 3.1. FlatLaf 3.0 works without any problems on Windows 11.
- Setting the
flatlaf.uiScaleproperty to2xappears to resolve the issue, but any smaller scale does not. - Using the
-Dflatlaf.useNativeLibrary=falseflag resolves the issue but removes the menu bar and title bar integration, which I would like to keep. - Dragging the
JFramewindow to another monitor forces a full repaint. - Resizing the window forces a full repaint.
- A button click does not force a full repaint.
Steps to reproduce
- Run the application.
- Use the menu bar.
https://github.com/user-attachments/assets/b0ed217e-24fb-4a79-82fd-48a042c5da4a
Minimal reproduction project (MRP)
This is also a problem with JComboBoxes withing JTables, not just MenuBars.
2 monitors, 144hz both, RTX 3050 GPU, Windows 11 Education 23H2
I'm seeing the same problem with a JComboBox in the FlatLaf demo app.
https://github.com/user-attachments/assets/85841646-1b54-45ce-ae21-915554a6ffe1
However, I am unable to replicate the issue with JComboBoxes within a JTable when using the demo app. @nevemlaci Are you able to reproduce the same issue using the demo app for the JComboBoxes within a JTable?
I'd love to but the demo app is impossible to navigate for me due to the repaint issues, 2 clicks and the whole thing just breaks down. I'm not sure where to look for a JTable + JComboBox in the demo app either, I've never used it.
Some of the users of our software which uses FlatLAF 3.5.1 are also reporting this issue
Had the same issue on windows after some update
System.setProperty("sun.java2d.noddraw", "true");
fixed this for me.
@nevemlaci
I'd love to but the demo app is impossible to navigate for me due to the repaint issues, 2 clicks and the whole thing just breaks down. I'm not sure where to look for a JTable + JComboBox in the demo app either, I've never used it.
The JTable is located under the Data components tab in the demo app.
Had the same issue on windows after some update
System.setProperty("sun.java2d.noddraw", "true");fixed this for me.
I'm no longer seeing the issue with the demo app or the minimal reproduction project. It also addressed my problem of the menu not being integrated into the title bar using my initial solution. Thank you @norbert-gaulia!
Note, turning off DirectDraw disables hardware acceleration, which will reduce performance, especially in graphics-intensive applications. While this isn’t a problem for me at the moment, I suspect this may not be a solution for everyone.
@nevemlaci
I'd love to but the demo app is impossible to navigate for me due to the repaint issues, 2 clicks and the whole thing just breaks down. I'm not sure where to look for a JTable + JComboBox in the demo app either, I've never used it.
The JTable is located under the Data components tab in the demo app.
I'll take a look today.
@IAmBaguette thanks for the detailed report and the screencasts. Very useful 👍
Unfortunately I can not reproduce the issue on my systems...
What happens if you use the flag -Dflatlaf.useWindowDecorations=false? (with DirectDraw enabled)
This flag disables the FlatLaf window decorations, but keeps the rounded popup border enabled.
Since you wrote that it first occurs with FlatLaf 3.1, I assume that it has something to do with the (native) rounded popup borders, which are the only change in native code in this version.
Does it work if you disable rounded popup borders with:
UIManager.put( "PopupMenu.borderCornerRadius", 0 );
UIManager.put( "ComboBox.borderCornerRadius", 0 );
UIManager.put( "ToolTip.borderCornerRadius", 0 );
UIManager.put( "Popup.borderCornerRadius", 0 );
@DevCharly Disabling the FlatLaf window decorations while DirectDraw is enabled results to the same issue with the Minimal reproduction project (MRP).
-Dflatlaf.useWindowDecorations=false -Dsun.java2d.noddraw=false
Disabling the rounded popup borders using the UIManager did resolve the issue. Do you have any idea why the native rounded popup borders would cause this painting issue?
I also attempted to turn off hardware acceleration from my Windows display graphics settings to see if it would make a difference, but the option does not seem to be available with my AMD graphics card.
If there's anything else you'd like me to try, let me know.
I think that following lines, which are invoked before setting rounded popup border, could cause the problem:
https://github.com/JFormDesigner/FlatLaf/blob/09f2d65d5eb64f9c7c11fc547bcb36d0d7bad2c6/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java#L367-L369
addNotify() creates the native window and also invokes some DirectDraw code.
I'll rework the code to avoid invocation of addNotify().
Hope this will solve the issue.
Could you please try latest 3.5.2-SNAPSHOT: https://github.com/JFormDesigner/FlatLaf#snapshots
Hope this change fixes the problem...
No luck. Issue is still present.
It could be a general Swing issue with "heavy-weight" popup windows, which are used if the popup does not fit into the owner window. If the popup fits into the owner window, FlatLaf 3.0 (and most other L&Fs) use "light-weight" popups (simple Swing component). But FlatLaf 3.1 always uses "heavy-weight" popups on Windows 11 to show Windows rounded borders and drop shadows.
Here is an issue that reports same redraw issue for Windows L&F: https://github.com/kaikramer/keystore-explorer/issues/497
Here is a test case that uses Windows L&F and large menus. Could you try this out and report whether is shows same redraw issue?
import javax.swing.*;
public class HeavyWeightPopupsTest {
public static void main( String[] args ) {
try {
UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
} catch( Exception ex ) {
ex.printStackTrace();
}
JFrame frame = new JFrame( "HeavyWeightPopupsTest" );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
JMenu fileMenu = new JMenu( "File" );
JMenu editMenu = new JMenu( "Edit" );
for( int i = 1; i <= 20; i++ )
fileMenu.add( "Item " + 1 );
for( int i = 1; i <= 20; i++ )
editMenu.add( "Item " + 1 );
JMenuBar menuBar = new JMenuBar();
menuBar.add( fileMenu );
menuBar.add( editMenu );
frame.setJMenuBar( menuBar );
JTable table = new JTable( 100, 5 );
frame.getContentPane().add( new JScrollPane( table ) );
frame.setSize( 400, 300 );
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
}
There doesn't appear to be any redraw issue on Windows 11.
https://github.com/user-attachments/assets/49bfef07-9c58-4c16-81c8-277a3657945d
There are no redraw issue with FlatLaf either. Tested with versions 3.5.1 and 3.5.2-SNAPSHOT.
https://github.com/user-attachments/assets/9bdee9cc-8185-40df-966a-fe7824ecfff5
However, the issue reappears with FlatLaf when the JMenu contains 6 or fewer menu items. Tested with versions 3.5.1 and 3.5.2-SNAPSHOT. The system LAF remained unaffected.
https://github.com/user-attachments/assets/8d44a06f-fc17-4da2-82cf-d08469248aa5
I was able to reproduce the redraw issue using the system LAF with two JComboBox components. The issue appears to heavily depend on the layout and constraints. I noticed that in some cases, if the layout was near the bottom of the window (causing the popup to open outside the window), the redraw issue would appear. However, this was not the case when using a GridLayout, the redraw issue did not appear for either the system LAF or FlatLaf. When I tested the same layout with FlatLaf, the redraw issue did not appear, but it reappeared if the number of items within the combo box was 7 or fewer (with the exception of GridLayout).
If you need more details about when the redraw issue appears with specific layouts, I will need to conduct a more thorough investigation to compile a comprehensive list.
Let me know what you would like me to do.
@IAmBaguette thanks for testing and confirming that this is can also happen in other L&Fs. So it is actually not a FlatLaf bug.
Not sure whether it makes sense to try layouts...
Found an undocumented Java system property that disables parts of DirectX.
Please try option -Dsun.java2d.d3d.onscreen=false
I was unable to reproduce the redraw issue with -Dsun.java2d.d3d.onscreen=false in any of the apps: FlatLaf demo, MRP, or heavy-weight popups.
It does appear the issue originates from Java rather than FlatLaf. Both -Dsun.java2d.noddraw=false and -Dsun.java2d.d3d.onscreen=false appear to be viable solutions for users who are encountering the same redraw issue with Swing.
I’m not sure if you plan to continue pursuing this. The question is whether it’s worth the effort now that there are workarounds for this Java-related issue.
@DevCharly Thank you for your help, I really appreciate it!
Great that sun.java2d.d3d.onscreen=false fixes the issue.
Compared to sun.java2d.d3d=false (same as sun.java2d.noddraw=true), sun.java2d.d3d.onscreen=false has the advantage that only a part of Java's Direct3D usage is disabled. Component rendering (via class Graphics) still uses Direct3D. So hope that performance does not change much...
BTW IntelliJ IDEA has disabled Direct3D (since 13 years). See <idea-install>/bin/idea.properties. Also NetBeans has it disabled...
Too avoid/fix the redraw issue, I'm going to set sun.java2d.d3d.onscreen=false in FlatLaf 3.5.2.
@IAmBaguette you mentioned in this comment https://github.com/JFormDesigner/FlatLaf/issues/887#issuecomment-2409099659 that the redraw issue appears only if the menu contains 6 or fewer menu items. There is some code in method sun.java2d.d3d.D3DScreenUpdateManager.canUseD3DOnScreen() that checks whether (popup) window is smaller that 150x150 pixels and then uses different screen surfaces. GDI surface if smaller then 150x150, otherwise D3D surface. In your video the size of the popup is 83x140. So maybe the redraw problem is related to that 150x150 size check.
Could you please try following test case? (without using any -D... flags!)
It has 3 menus that show (empty) popups of size 152x152, 151x151 and 150x150.
First click the 152x152 menu to show the popup, click it again to hide it.
Then try the same with the 151x151 and 150x150 menus.
If my theory is correct, then the redraw problem should start after the 150x150 popup is shown.
In this case it would be great if you could post a screencast.
I'd like to report the problem to Oracle and having a test case would be great.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class GhostingTest
{
public static void main( String[] args ) {
JFrame frame = new JFrame( "GhostingTest" );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
UIManager.put( "PopupMenu.border", BorderFactory.createEmptyBorder() );
// force heavy-weight popups
JPopupMenu.setDefaultLightWeightPopupEnabled( false );
JMenuBar menuBar = new JMenuBar();
frame.setJMenuBar( menuBar );
// showing this popups should not start ghosting
menuBar.add( createMenuOfSize( 152 ) );
menuBar.add( createMenuOfSize( 151 ) );
// showing this popup should start ghosting
menuBar.add( createMenuOfSize( 150 ) );
JTable table = new JTable( 100, 5 );
frame.getContentPane().add( new JScrollPane( table ) );
frame.setSize( 400, 300 );
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
private static JMenu createMenuOfSize( int size ) {
JPanel p = new JPanel();
p.setPreferredSize( new Dimension( size, size ) );
p.setBorder( new LineBorder( Color.red ) );
JMenu menu = new JMenu( size + " x " + size );
menu.add( p );
return menu;
}
}
@DevCharly I was able to reproduce the redraw issue inconsistently when following your exact instructions. To consistently trigger the redraw issue, I needed to repeat the action of showing and hiding the 150x150 menu exactly twice.
-
Here's an example where the redraw issue does not appear with a single action of showing and hiding.
https://github.com/user-attachments/assets/85ecc180-62e7-4f6f-a297-c458703b4457
-
Here's an example using the same sequence of actions in reverse order.
https://github.com/user-attachments/assets/fb28229d-272e-4f24-8e23-9d26f2ffda5c
-
Here's an example where the redraw issue appears with a single action of showing and hiding.
https://github.com/user-attachments/assets/2786e07b-05d7-4b03-926d-8969a8324622
-
Here’s an example where the redraw issue appears after repeating the action of showing and hiding exactly twice. Note that the outcome is the same regardless of whether the other menus were shown/hidden once or twice before the 150x150 menu. I decided to keep the actions consistent for all menus.
https://github.com/user-attachments/assets/fedf8d3b-503d-4f06-bade-eaac01ebdf62
-
Here's an example using is the same sequence of actions in reverse order. Note that after performing the action of showing and hiding exactly twice for the 152x152 menu, it “erases” the content pane. This behavior is inconsistent. In some tests, this occurred with both the 152x152 and 151x151 menus, while in others, it did not occur at all.
https://github.com/user-attachments/assets/17329984-203c-4f69-9c58-ac4b403e79e2
I've provided more screencasts than you asked to provide a more complete view of what's happening. I prefer to give you more information so that you can decide whether it is necessary for your report to Oracle.
@DevCharly Would you like me to close issue now that the issue is resolved?
Compared to
sun.java2d.d3d=false(same assun.java2d.noddraw=true),sun.java2d.d3d.onscreen=falsehas the advantage that only a part of Java's Direct3D usage is disabled. Component rendering (via classGraphics) still uses Direct3D. So hope that performance does not change much...BTW IntelliJ IDEA has disabled Direct3D (since 13 years). See
<idea-install>/bin/idea.properties. Also NetBeans has it disabled...
Just to chip in to say: I learned early on that sun.java2d.d3d=false only ever seems to improve Swing performance. Some 20 years on and probably 6 laptop/desktop Windows devices tested, and this has never changed. (In an IDE-like application with various charts.) If there are specific things that the D3D pipeline might enhance performance over the 2D pipeline, I've never found them.
Most visibly to the end-user, it dramatically improves repainting while the Window is being resized. (Avoiding it essentially "freezing up".) I've not toyed with the other options.
fixed in FlatLaf 3.5.2 by setting Java system property sun.java2d.d3d.onscreen to false
@lukeu thanks for your insights. That's very interesting. Actually did not notice before that disabling d3d improves window resizing...
Comments here and elsewhere have potential for confusion (and maybe I am also adding to it right now):
-
sun.java2d.nodrawis (according to the docs) outdated, formulated negatively and false by default. - Setting
sun.java2d.nodraw=trueshould be (unnecessary and) the same assun.java2d.d3d=falseand means disable Direct3D hardware acceleration. - but then many also combine this with
sun.java2d.opengl=true, thereby enabling another hardware accelerated rendering pipeline: OpenGL. I believe this invites the same set of rendering issues, just caused by the OpenGL driver instead of the Direct3D driver. At least on my Windows/Nvidia machine I observe the same resizing problems for Direct3D and OpenGL. - The Java 17/21 docs for these flags exist but some information seems to be lost
- note that we can stop guessing which pipeline is active by setting
-Dsun.java2d.trace=log: quite interesting to see how the pipeline switches when you move a frame from one screen to another, especially if one screen is attached to the mainboard and the other to the graphics card. - Because OpenGL is or has been turned on by default in some Java versions for Linux and macOS, the only configuration to enforce software based rendering on all platforms (if so desired) would be (as it has always been):
-sun.java2d.d3d=false
-sun.java2d.nodraw=true
-sun.java2d.opengl=false
And based on the Java 21 docs for macOS, metal is the new (I believe hardware accelerated) default pipeline for macOS since Java 19, so to enforce software rendering it might have to be disabled as well (I haven't tested that scenario yet):
-sun.java2d.metal=false