Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FlatLaf 3.5.1] Repaint issue on Windows 11 #887

Open
IAmBaguette opened this issue Sep 22, 2024 · 21 comments
Open

[FlatLaf 3.5.1] Repaint issue on Windows 11 #887

IAmBaguette opened this issue Sep 22, 2024 · 21 comments

Comments

@IAmBaguette
Copy link

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.
flatlaf_demo.mp4

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.uiScale property to 2x appears to resolve the issue, but any smaller scale does not.
  • Using the -Dflatlaf.useNativeLibrary=false flag resolves the issue but removes the menu bar and title bar integration, which I would like to keep.
  • Dragging the JFrame window 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

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

Minimal reproduction project (MRP)

flatlaf-windows11.zip

@nevemlaci
Copy link

nevemlaci commented Sep 25, 2024

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
Copy link
Author

I'm seeing the same problem with a JComboBox in the FlatLaf demo app.

flatlaf_demo_jcombobox.mp4

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
Copy link

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
Copy link
Contributor

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

@norbert-gaulia
Copy link

Had the same issue on windows after some update

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

fixed this for me.

@IAmBaguette
Copy link
Author

@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
Copy link
Author

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
Copy link

@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
Copy link
Collaborator

@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
Copy link
Author

@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
Copy link
Collaborator

I think that following lines, which are invoked before setting rounded popup border, could cause the problem:

// make sure that the native window is created
if( !popupWindow.isDisplayable() )
popupWindow.addNotify();

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 added a commit that referenced this issue Oct 12, 2024
… create window ourself using `addNotify()`) to (hopefully) fix repaint issues on some Windows 11 systems after first showing a popup (issue #887, PR #643)
@DevCharly
Copy link
Collaborator

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

@IAmBaguette
Copy link
Author

No luck. Issue is still present.

image

@DevCharly
Copy link
Collaborator

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: kaikramer/keystore-explorer#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
Copy link
Author

There doesn't appear to be any redraw issue on Windows 11.

heavy-weight_popups.mp4

There are no redraw issue with FlatLaf either. Tested with versions 3.5.1 and 3.5.2-SNAPSHOT.

heavy-weight_popups_flatlaf.mp4

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.

heavy-weight_popups_flatlaf_redraw.mp4

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
Copy link
Collaborator

@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
Copy link
Author

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
Copy link
Collaborator

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
Copy link
Collaborator

@IAmBaguette you mentioned in this comment #887 (comment) 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
Copy link
Author

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

    ghosting_test_windows11_single_no_redraw.mp4
  • Here's an example using the same sequence of actions in reverse order.

    ghosting_test_windows11_reverse_single_no_redraw.mp4
  • Here's an example where the redraw issue appears with a single action of showing and hiding.

    ghosting_test_windows11_single_redraw.mp4
  • 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.

    ghosting_test_windows11_redraw.mp4
  • 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.

    ghosting_test_windows11_reverse_redraw.mp4

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 added a commit that referenced this issue Oct 17, 2024
@IAmBaguette
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants