Skip to content

Commit

Permalink
8303950: avoid letting Window.paint(..) call g.fillRect(..)
Browse files Browse the repository at this point in the history
When Window.paint(..) calls g.fillRect(..): sometimes this results in flickering.

The problem appears to be that the monitor refreshes shortly after the call to fillRect(..) but *before* the RepaintManager has a chance to paint its replacement image with AlphaComposite.SRC.

This proposal uses a new RenderingHint to tell Window.paint(..) to skip its paint method. This feels hacky, but I don't see a simpler solution at this point. (I can think of at least two hackier approaches though, if we want to brainstorm alternatives.) If there is a simple way to safeguard the monitor from refreshing prematurely that might be a much better solution, but I'm not familiar that logic.

Skipping g.fillRect(..) should be safe in RepaintManager's case, because the RepaintManager is already calling:
```
g2d.setBackground(c.getBackground());
g2d.clearRect(x,y,bw,bh);
```

So in this bug's test case: c will be a `JRootPane`. And JRootPane's `getBackground()` method will default to the Window's background color. So we're already flood filling RepaintManager's buffer with the correct background color (which is the window's background color).

And (sigh) in the event the JRootPane and Window have *different* background colors: the JRootPane "wins", and the Window's background color is ignored. This is weird (and maybe bad), but this is the preexisting behavior. If you set up a window with a background of `new Color(255,0,0,200)` and a JRootPane with a background of `new Color(0,255,0,200)`, then (when there is no flickering): the JRootPane's background color always wins and there is no sign of the red. IMO this is a very low-priority bug of its own, where the expected behavior is the JRootPane's background renders on top of the Window's background.
  • Loading branch information
mickleness committed Mar 12, 2023
1 parent 55caec2 commit 1991fda
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 5 deletions.
11 changes: 7 additions & 4 deletions src/java.desktop/share/classes/java/awt/Window.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import sun.awt.AppContext;
import sun.awt.DebugSettings;
import sun.awt.SunToolkit;
import sun.awt.SunHints;
import sun.awt.util.IdentityArrayList;
import sun.java2d.pipe.Region;
import sun.security.action.GetPropertyAction;
Expand Down Expand Up @@ -3947,10 +3948,12 @@ public void paint(Graphics g) {
if (!isOpaque()) {
Graphics gg = g.create();
try {
if (gg instanceof Graphics2D) {
gg.setColor(getBackground());
((Graphics2D)gg).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC));
gg.fillRect(0, 0, getWidth(), getHeight());
if (gg instanceof Graphics2D gg2d) {
if (!SunHints.VALUE_PAINT_WINDOW_BACKGROUND_OFF.equals(gg2d.getRenderingHint(SunHints.KEY_PAINT_WINDOW_BACKGROUND_COLOR))) {
gg2d.setColor(getBackground());
gg2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC));
gg2d.fillRect(0, 0, getWidth(), getHeight());
}
}
} finally {
gg.dispose();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import sun.awt.AppContext;
import sun.awt.DisplayChangedListener;
import sun.awt.SunToolkit;
import sun.awt.SunHints;
import sun.java2d.SunGraphicsEnvironment;
import sun.security.action.GetPropertyAction;

Expand Down Expand Up @@ -885,6 +886,12 @@ else if (dirtyComponent.isShowing()) {
// the window, don't do anything.
if (g != null) {
g.setClip(rect.x, rect.y, rect.width, rect.height);

if (g instanceof Graphics2D g2d) {
// If Window#paint(Graphics) fills its background color we may see flickering
g2d.setRenderingHint(SunHints.KEY_PAINT_WINDOW_BACKGROUND_COLOR, SunHints.VALUE_PAINT_WINDOW_BACKGROUND_OFF);
}

try {
dirtyComponent.paint(g);
} finally {
Expand Down
24 changes: 23 additions & 1 deletion src/java.desktop/share/classes/sun/awt/SunHints.java
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public final boolean equals(Object o) {
}
}

private static final int NUM_KEYS = 10;
private static final int NUM_KEYS = 11;
private static final int VALS_PER_KEY = 8;

/**
Expand Down Expand Up @@ -261,6 +261,13 @@ public final boolean equals(Object o) {
@Native public static final int INTVAL_RESOLUTION_VARIANT_SIZE_FIT = 2;
@Native public static final int INTVAL_RESOLUTION_VARIANT_DPI_FIT = 3;

/**
* Paint window background color hint key and values
*/
@Native public static final int INTKEY_PAINT_WINDOW_BACKGROUND_COLOR = 10;
@Native public static final int INTVAL_PAINT_WINDOW_BACKGROUND_COLOR_ON = 0;
@Native public static final int INTVAL_PAINT_WINDOW_BACKGROUND_COLOR_OFF = 1;

/**
* LCD text contrast control hint key.
* Value is "100" to make discontiguous with the others which
Expand Down Expand Up @@ -513,4 +520,19 @@ public final boolean isCompatibleValue(Object val) {
KEY_TEXT_ANTIALIAS_LCD_CONTRAST =
new LCDContrastKey(SunHints.INTKEY_AATEXT_LCD_CONTRAST,
"Text-specific LCD contrast key");

/**
* Paint window background color key and value objects
*/
public static final Key KEY_PAINT_WINDOW_BACKGROUND_COLOR =
new SunHints.Key(SunHints.INTKEY_PAINT_WINDOW_BACKGROUND_COLOR,
"Paint window background color");
public static final Object VALUE_PAINT_WINDOW_BACKGROUND_ON =
new SunHints.Value(KEY_PAINT_WINDOW_BACKGROUND_COLOR,
SunHints.INTVAL_PAINT_WINDOW_BACKGROUND_COLOR_ON,
"Paint window background color");
public static final Object VALUE_PAINT_WINDOW_BACKGROUND_OFF =
new SunHints.Value(KEY_PAINT_WINDOW_BACKGROUND_COLOR,
SunHints.INTVAL_PAINT_WINDOW_BACKGROUND_COLOR_OFF,
"Do not paint window background color");
}

0 comments on commit 1991fda

Please sign in to comment.