ADDITIONAL SYSTEM INFORMATION :
MacBook Pro (13-inch, 2018, Four Thunderbolt 3 Ports)
macOS Mojave 10.14.5 (18F132)
openjdk version "11.0.4" 2019-07-16
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.4+11)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.4+11, mixed mode)
A DESCRIPTION OF THE PROBLEM :
When changing displays an IllegalArgumentException may be thrown.
This occurs because java.awt.GraphicsConfiguration#getBounds may return a zero width and height Rectangle which causes javax.swing.RepaintManager#getDoubleBufferMaximumSize to return a Dimension with a zero width and height. This gets passed into java.awt.GraphicsConfiguration#createCompatibleVolatileImage(int, int, java.awt.ImageCapabilities, int) which will fail when it creates a new sun.awt.image.SunVolatileImage.
We are seeing a lot of bug reports from our users about this issue. Whatever they are doing they seem to be encountering this bug a lot. The only way that I have been able to reproduce it is by plugging in an external monitor into my laptop, closing the laptop lid, then unplugging the external monitor. Upon unplugging the external monitor is when java.awt.GraphicsConfiguration#getBounds returns a zero width and height Rectangle.
This bug also seems to be present on Java 12 however the NullPointerException from bug 9061686 is obscuring it.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Run the main class Main on a laptop
2. Plug in an external monitor
3. Close the lid of the laptop
4. Unplug the external monitor
5. Reopen the lid of the laptop
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
There should be no exceptions.
ACTUAL -
One or more of the following exceptions will be thrown:
java.lang.IllegalArgumentException: Width (0) and height (0) cannot be <= 0
at java.desktop/sun.awt.image.SunVolatileImage.<init>(SunVolatileImage.java:75)
at java.desktop/sun.awt.image.SunVolatileImage.<init>(SunVolatileImage.java:122)
at java.desktop/java.awt.GraphicsConfiguration.createCompatibleVolatileImage(GraphicsConfiguration.java:307)
at java.desktop/java.awt.GraphicsConfiguration.createCompatibleVolatileImage(GraphicsConfiguration.java:241)
at java.desktop/javax.swing.RepaintManager.getVolatileOffscreenBuffer(RepaintManager.java:1098)
at Main.reproduceExceptionLoop(Main.java:95)
at Main.main(Main.java:14)
java.lang.IllegalArgumentException: Width (0) and height (0) cannot be <= 0
at java.desktop/sun.awt.image.SunVolatileImage.<init>(SunVolatileImage.java:75)
at java.desktop/sun.awt.image.SunVolatileImage.<init>(SunVolatileImage.java:122)
at java.desktop/java.awt.GraphicsConfiguration.createCompatibleVolatileImage(GraphicsConfiguration.java:307)
at java.desktop/java.awt.GraphicsConfiguration.createCompatibleVolatileImage(GraphicsConfiguration.java:241)
at java.desktop/javax.swing.RepaintManager.getVolatileOffscreenBuffer(RepaintManager.java:1098)
at java.desktop/javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1543)
at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1323)
at java.desktop/javax.swing.JComponent._paintImmediately(JComponent.java:5203)
at java.desktop/javax.swing.JComponent.paintImmediately(JComponent.java:5013)
at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:865)
at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:848)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:848)
at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:823)
at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:772)
at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1890)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
---------- BEGIN SOURCE ----------
import javax.swing.*;
import java.awt.*;
import java.io.PrintWriter;
import java.io.Writer;
import java.time.LocalDateTime;
import java.util.ConcurrentModificationException;
public class Main {
private static volatile JTextArea ERRORS;
public static void main(String[] args) {
final JFrame gui = createAndShowGUI();
reproduceExceptionLoop(gui);
}
private static JFrame createAndShowGUI() {
final JFrame frame = new JFrame("Swing IllegalArgumentException");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setMinimumSize(new Dimension(500, 500));
final JTextArea instructions = new JTextArea("Steps to reproduce:\n"
+ "1) Run this application on a laptop\n"
+ "2) Plug in an external monitor\n"
+ "3) Shut the lid of the laptop\n"
+ "4) Unplug the external monitor\n"
+ "5) Reopen the lid of the laptop");
instructions.setMaximumSize(instructions.getPreferredSize());
instructions.setEditable(false);
final JLabel errorLabel = new JLabel("Uncaught exceptions:");
ERRORS = new JTextArea();
ERRORS.setEditable(false);
final JScrollPane errorsPane = new JScrollPane(ERRORS);
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
final LocalDateTime now = LocalDateTime.now();
SwingUtilities.invokeLater(() -> {
ERRORS.append(now.toString());
ERRORS.append("Thread: " + t.toString() + "\n");
ERRORS.append("Exception: ");
e.printStackTrace(new PrintWriter(new Writer() {
@Override
public void write(char[] cbuf, int off, int len) {
ERRORS.append(String.copyValueOf(cbuf, off, len));
}
@Override
public void flush() {
}
@Override
public void close() {
}
}));
ERRORS.append("\n\n");
});
System.err.println(now.toString());
e.printStackTrace();
});
final Container contentPane = frame.getContentPane();
contentPane.add(instructions);
contentPane.add(errorLabel);
contentPane.add(errorsPane);
final SpringLayout layout = new SpringLayout();
contentPane.setLayout(layout);
layout.putConstraint(SpringLayout.WEST, instructions, 5, SpringLayout.WEST, contentPane);
layout.putConstraint(SpringLayout.EAST, instructions, -5, SpringLayout.EAST, contentPane);
layout.putConstraint(SpringLayout.NORTH, instructions, 5, SpringLayout.NORTH, contentPane);
layout.putConstraint(SpringLayout.WEST, errorLabel, 5, SpringLayout.WEST, contentPane);
layout.putConstraint(SpringLayout.NORTH, errorLabel, 5, SpringLayout.SOUTH, instructions);
layout.putConstraint(SpringLayout.WEST, ERRORS, 0, SpringLayout.WEST, errorsPane);
layout.putConstraint(SpringLayout.NORTH, ERRORS, 0, SpringLayout.SOUTH, errorsPane);
layout.putConstraint(SpringLayout.EAST, ERRORS, -0, SpringLayout.EAST, errorsPane);
layout.putConstraint(SpringLayout.SOUTH, ERRORS, -0, SpringLayout.SOUTH, errorsPane);
layout.putConstraint(SpringLayout.WEST, errorsPane, 5, SpringLayout.WEST, contentPane);
layout.putConstraint(SpringLayout.NORTH, errorsPane, 5, SpringLayout.SOUTH, errorLabel);
layout.putConstraint(SpringLayout.EAST, contentPane, 5, SpringLayout.EAST, ERRORS);
layout.putConstraint(SpringLayout.SOUTH, contentPane, 5, SpringLayout.SOUTH, ERRORS);
frame.pack();
frame.setVisible(true);
return frame;
}
private static void reproduceExceptionLoop(Component component) {
while (true) {
final RepaintManager repaintManager = RepaintManager.currentManager(component);
setupPreconditions(repaintManager);
repaintManager.getVolatileOffscreenBuffer(component, component.getWidth(), component.getHeight());
}
}
private static void setupPreconditions(RepaintManager repaintManager) {
while (true) {
try {
repaintManager.setDoubleBufferMaximumSize(null);
return;
} catch (ConcurrentModificationException e) {
// Try again.
}
}
}
}
---------- END SOURCE ----------
FREQUENCY : occasionally