JFormDesigner / FlatLaf

FlatLaf - Swing Look and Feel (with Darcula/IntelliJ themes support)
https://www.formdev.com/flatlaf/
Apache License 2.0
3.45k stars 274 forks source link

[FlatLaf 3.5.1] Repaint issue on Windows 11 #887

Open IAmBaguette opened 2 months ago

IAmBaguette commented 2 months ago

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:

https://github.com/user-attachments/assets/9c2bcdc7-94ac-4856-bcb1-090b2b971867

Observations:

Steps to reproduce

  1. Run the application.
  2. Use the menu bar.

https://github.com/user-attachments/assets/b0ed217e-24fb-4a79-82fd-48a042c5da4a

Minimal reproduction project (MRP)

flatlaf-windows11.zip

nevemlaci commented 2 months ago

This is also a problem with JComboBoxes withing JTables, not just MenuBars. image

2 monitors, 144hz both, RTX 3050 GPU, Windows 11 Education 23H2

IAmBaguette commented 2 months ago

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?

nevemlaci commented 2 months ago

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.

KlemenDEV commented 2 months ago

Some of the users of our software which uses FlatLAF 3.5.1 are also reporting this issue

norbert-gaulia commented 1 month ago

Had the same issue on windows after some update

System.setProperty("sun.java2d.noddraw", "true");

fixed this for me.

IAmBaguette commented 1 month ago

@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.

IAmBaguette commented 1 month ago

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 commented 1 month ago

@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.

DevCharly commented 1 month ago

@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 );
IAmBaguette commented 1 month ago

@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.

DevCharly commented 1 month ago

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.

DevCharly commented 1 month ago

Could you please try latest 3.5.2-SNAPSHOT: https://github.com/JFormDesigner/FlatLaf#snapshots Hope this change fixes the problem...

IAmBaguette commented 1 month ago

No luck. Issue is still present.

image

DevCharly commented 1 month ago

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 );
    }
}
IAmBaguette commented 1 month ago

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.

DevCharly commented 1 month ago

@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

IAmBaguette commented 1 month ago

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!

DevCharly commented 1 month ago

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.

DevCharly commented 1 month ago

@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;
    }
}
IAmBaguette commented 1 month ago

@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.

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.

IAmBaguette commented 1 month ago

@DevCharly Would you like me to close issue now that the issue is resolved?