JDK-4417798 : Need to track add/remove of monitors on display changes
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 1.4.0,1.4.1_03,1.4.2_03,5.0,6
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: linux,windows_2000,windows_xp
  • CPU: x86
  • Submitted: 2001-02-22
  • Updated: 2011-04-05
  • Resolved: 2011-04-05
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 JDK 7
6u2Fixed 7 b08Fixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
Run the attached test on a multi-mon machine machine configured so that only one monitor is active.  Adding a secondary display will crash with the following results:

An unexpected exception has been detected in native code outside the VM.
Unexpected Signal : EXCEPTION_ACCESS_VIOLATION occurred at PC=0x50075421
Function=Java_sun_print_Win32PrintJob_printRawData+0x4C7
Library=J:\java\jdk1.4\win\jre\bin\awt.dll

Current Java thread:
        at sun.java2d.loops.Blit.Blit(Native Method)
        at sun.java2d.SunGraphics2D.blitSurfaceData(SunGraphics2D.java:2778)
        at sun.java2d.SunGraphics2D.renderSurfaceData(SunGraphics2D.java:2704)
        at sun.java2d.SunGraphics2D.clipAndRenderSurfaceData(SunGraphics2D.java:2761)
        at sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:3105)
        at sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:3189)
        at sun.awt.image.ImageRepresentation.drawToBufImage(ImageRepresentation.java:748)
        at sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:3151)
        at MultiDitherTest$DitherCanvas.paint(MultiDitherTest.java:375)
        at MultiDitherTest$DitherCanvas.update(MultiDitherTest.java:380)
        at sun.awt.RepaintArea.paintRect(RepaintArea.java:331)
        at sun.awt.RepaintArea.paint(RepaintArea.java:321)
        at sun.awt.windows.WComponentPeer.handleEvent(WComponentPeer.java:254)
        at java.awt.Component.dispatchEventImpl(Component.java:3533)
        at java.awt.Component.dispatchEvent(Component.java:3327)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:437)
        at java.awt.EventDispatchThread.pumpOneEvent(EventDispatchThread.java:140)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:126)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:121)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:99)

Dynamic libraries:
0x00400000 - 0x00405000         j:\java\jdk1.4\win\bin\java.exe
0x77F80000 - 0x77FF9000         E:\WINNT\System32\ntdll.dll
0x77DB0000 - 0x77E0A000         E:\WINNT\system32\ADVAPI32.dll
0x77E80000 - 0x77F36000         E:\WINNT\system32\KERNEL32.DLL
0x77D40000 - 0x77DAF000         E:\WINNT\system32\RPCRT4.DLL
0x78000000 - 0x78046000         E:\WINNT\system32\MSVCRT.dll
0x50410000 - 0x50509000         j:\java\jdk1.4\win\jre\bin\hotspot\jvm.dll
0x77E10000 - 0x77E75000         E:\WINNT\system32\USER32.dll
0x77F40000 - 0x77F7C000         E:\WINNT\system32\GDI32.DLL
0x77570000 - 0x775A0000         E:\WINNT\System32\WINMM.dll
0x50210000 - 0x50217000         j:\java\jdk1.4\win\jre\bin\hpi.dll
0x503E0000 - 0x503ED000         j:\java\jdk1.4\win\jre\bin\verify.dll
0x50250000 - 0x50265000         j:\java\jdk1.4\win\jre\bin\java.dll
0x50400000 - 0x5040D000         j:\java\jdk1.4\win\jre\bin\zip.dll
0x50020000 - 0x50109000         J:\java\jdk1.4\win\jre\bin\awt.dll
0x77800000 - 0x7781D000         E:\WINNT\System32\WINSPOOL.DRV
0x75E60000 - 0x75E7A000         E:\WINNT\System32\IMM32.dll
0x77A50000 - 0x77B45000         E:\WINNT\system32\ole32.dll
0x501C0000 - 0x5020F000         J:\java\jdk1.4\win\jre\bin\fontmanager.dll
0x72800000 - 0x72846000         E:\WINNT\System32\ddraw.dll
0x728A0000 - 0x728A6000         E:\WINNT\System32\DCIMAN32.dll
0x76B20000 - 0x76B25000         E:\WINNT\System32\RICHED32.DLL
0x772B0000 - 0x7731C000         E:\WINNT\System32\RICHED20.dll
0x61220000 - 0x6122E000         E:\Program Files\Microsoft Hardware\Mouse\MSH_ZWF.dll
0x77920000 - 0x77942000         E:\WINNT\system32\imagehlp.dll
0x72A00000 - 0x72A2D000         E:\WINNT\system32\DBGHELP.dll
0x690A0000 - 0x690AB000         E:\WINNT\System32\PSAPI.DLL

Local Time = Thu Feb 22 00:11:59 2001
Elapsed Time = 29
#
# The exception above was detected in native code outside the VM
#
# Java VM: Java HotSpot(TM) Client VM (B53 mixed mode)
#
# An error report file has been saved as hs_err_pid476.log.
# Please refer to the file for further information.
#

Comments
WORK AROUND Workaround submitted by customer: ================================= In order to make this work around work you will need the following 4 classes. You will also need to make all JFrames and JDialogs into IFrame or IDialog (all subclasses AND instantiations) and you will also need to register the BugHandler as the default exception handler. try { System.setProperty("sun.awt.exception.handler", "BugHandler"); } catch (java.security.AccessControlException e) {} ======================================================= import SafeGraphicsEnvironment; public class BugHandler { public void handle(Throwable throwable) { if (e instanceof ArrayIndexOutOfBoundsException) { StackTraceElement[] trace = e.getStackTrace(); if (trace.length > 1 && trace[0].getClassName().equals("sun.awt.Win32GraphicsEnvironment") && trace[0].getMethodName().equals("getDefaultScreenDevice")) { SafeGraphicsEnvironment.handleDisplayChangeError(); } } } } ================================================== import java.awt.*; import java.awt.image.BufferedImage; import java.lang.reflect.*; import java.util.Locale; import javax.swing.JFrame; import javax.swing.JOptionPane; public class SafeGraphicsEnvironment extends GraphicsEnvironment { private GraphicsEnvironment m_originalEnvironment; private SafeGraphicsEnvironment() { m_originalEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment(); } public Graphics2D createGraphics(BufferedImage arg0) { return m_originalEnvironment.createGraphics(arg0); } public Font[] getAllFonts() { return m_originalEnvironment.getAllFonts(); } public String[] getAvailableFontFamilyNames() { return m_originalEnvironment.getAvailableFontFamilyNames(); } public String[] getAvailableFontFamilyNames(Locale arg0) { return m_originalEnvironment.getAvailableFontFamilyNames(arg0); } public GraphicsDevice getDefaultScreenDevice() throws HeadlessException { try { return m_originalEnvironment.getDefaultScreenDevice(); } catch (ArrayIndexOutOfBoundsException ex) { System.err.println("Screen display changed and caused error."); } // try and reset the original environment try { Class ge = GraphicsEnvironment.class; Field localEnv = ge.getDeclaredField("localEnv"); localEnv.setAccessible(true); // because it is static we use null as the object to change // and null for the value as that is what we want to change it to localEnv.set(null, null); // try this seperately in case the class is not initialised under other // platforms try { Class fm = Class.forName("sun.font.FontManager"); Class compFontClass = Class.forName("sun.font.CompositeFont"); Field fontArray = fm.getDeclaredField("compFonts"); fontArray.setAccessible(true); fontArray.set(null, Array.newInstance(compFontClass, 20)); Field fontCount = fm.getDeclaredField("maxCompFont"); fontCount.setAccessible(true); fontCount.setInt(null, 0); } catch (Exception ignore) {} m_originalEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment(); } catch (Exception ignore) { //System.err.println("Failed to change private field"); } try { return m_originalEnvironment.getDefaultScreenDevice(); } catch (ArrayIndexOutOfBoundsException ex) { /* ignore and deal with next */ System.err.println("Changing the private field didn't work"); } GraphicsDevice[] devices = getScreenDevices(); if (devices.length == 0) throw new RuntimeException("No valid graphics devices"); // just return the first graphics device if the default is no longer available. return devices[0]; } public GraphicsDevice[] getScreenDevices() throws HeadlessException { return m_originalEnvironment.getScreenDevices(); } public Point getCenterPoint() throws HeadlessException { return m_originalEnvironment.getCenterPoint(); } public Rectangle getMaximumWindowBounds() throws HeadlessException { return m_originalEnvironment.getMaximumWindowBounds(); } public boolean isHeadlessInstance() { return m_originalEnvironment.isHeadlessInstance(); } public void preferLocaleFonts() { m_originalEnvironment.preferLocaleFonts(); } public void preferProportionalFonts() { m_originalEnvironment.preferProportionalFonts(); } private static SafeGraphicsEnvironment SINGLETON; public static SafeGraphicsEnvironment getSafeLocalGraphicsEnvironment() { if (SINGLETON == null) { SINGLETON = new SafeGraphicsEnvironment(); } return SINGLETON; } /** * WToolkit's displayChanged calls the getDefaultScreenDevice which causes the * error to happen internally. To catch this you need to have an error handler * which calls this method. This is in BugHandler. */ public static void handleDisplayChangeError() { try { // force the SafeGraphicsEnvironment to update the GraphicsEnvironment getSafeLocalGraphicsEnvironment().getDefaultScreenDevice(); // re-call the displayChanged event which caused the error Class windowsToolkit = Class.forName("sun.awt.windows.WToolkit"); Method displayChanged = windowsToolkit.getDeclaredMethod("displayChanged", null); displayChanged.invoke(null, null); // finally to cause a full refresh toggle the extended state - this // can't really be seen by the user and is the only way I seem to be // able to force it to fully repaint. Frame parent = JOptionPane.getRootFrame(); if (parent.isShowing() && parent instanceof JFrame) { boolean isMaximized = parent.getExtendedState() == Frame.MAXIMIZED_BOTH; if (!isMaximized) parent.setExtendedState(Frame.MAXIMIZED_BOTH); parent.setExtendedState(Frame.NORMAL); if (isMaximized) parent.setExtendedState(Frame.MAXIMIZED_BOTH); } return; } catch (Exception ignore) {} // do nothing - if it doesn't work then we are // no worse off than before. } } ====================================================== import java.awt.*; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import javax.swing.JDialog; import SafeGraphicsEnvironment; /** * Fix for problems with GraphicsEnvironment on multiple display configurations */ public class IDialog extends JDialog { public IDialog() {this((Frame)null, false);} public IDialog(Frame owner) {this(owner, false);} public IDialog(Frame owner, boolean modal) {this(owner, null, modal);} public IDialog(Frame owner, String title) {this(owner, title, false);} public IDialog(Frame owner, String title, boolean modal) {this(owner, title, modal, null);} public IDialog(Frame owner, String title, boolean modal, GraphicsConfiguration gc) { super(getRootFrame(owner), title, modal, getGraphicsConfiguration(gc)); } public IDialog(Dialog owner) {this(owner, false);} public IDialog(Dialog owner, boolean modal) {this(owner, null, modal);} public IDialog(Dialog owner, String title) {this(owner, title, false);} public IDialog(Dialog owner, String title, boolean modal) {this(owner, title, modal, null);} public IDialog(Dialog owner, String title, boolean modal, GraphicsConfiguration gc) { super(owner, title, modal, getGraphicsConfiguration(gc)); } //public IDialog(Window owner) {this(owner, Dialog.ModalityType.MODELESS);} //public IDialog(Window owner, ModalityType modalityType) {this(owner, null, modalityType);} //public IDialog(Window owner, String title) {this(owner, title, Dialog.ModalityType.MODELESS);} //public IDialog(Window owner, String title, ModalityType modalityType) {this(owner, title, modalityType, null);} //public IDialog(Window owner, String title, ModalityType modalityType, GraphicsConfiguration gc) { // super(owner, title, modalityType, getGraphicsConfiguration(gc)); //} private static Frame s_sharedOwnerFrame; public static Frame getRootFrame() throws HeadlessException { return getRootFrame(null); } public static Frame getRootFrame(Frame owner) throws HeadlessException { if (owner != null) return owner; if (s_sharedOwnerFrame == null) { s_sharedOwnerFrame = new SharedOwnerFrame(); } return s_sharedOwnerFrame; } private static GraphicsConfiguration getGraphicsConfiguration(GraphicsConfiguration gc) { if (gc != null) return gc; return SafeGraphicsEnvironment.getSafeLocalGraphicsEnvironment() .getDefaultScreenDevice().getDefaultConfiguration(); } static class SharedOwnerFrame extends IFrame implements WindowListener { public void addNotify() { super.addNotify(); installListeners(); } /** * Install window listeners on owned windows to watch for displayability changes */ void installListeners() { Window[] windows = getOwnedWindows(); for (int ind = 0; ind < windows.length; ind++){ Window window = windows[ind]; if (window != null) { window.removeWindowListener(this); window.addWindowListener(this); } } } /** * Watches for displayability changes and disposes shared instance if there are no * displayable children left. */ public void windowClosed(WindowEvent e) { synchronized(getTreeLock()) { Window[] windows = getOwnedWindows(); for (int ind = 0; ind < windows.length; ind++) { Window window = windows[ind]; if (window != null) { if (window.isDisplayable()) { return; } window.removeWindowListener(this); } } dispose(); } } public void windowOpened(WindowEvent e) {} public void windowClosing(WindowEvent e) {} public void windowIconified(WindowEvent e) {} public void windowDeiconified(WindowEvent e) {} public void windowActivated(WindowEvent e) {} public void windowDeactivated(WindowEvent e) {} public void show() { // This frame can never be shown } public void dispose() { try { getToolkit().getSystemEventQueue(); super.dispose(); } catch (Exception e) { // untrusted code not allowed to dispose } } } } ======================================================= import java.awt.*; import javax.swing.JFrame; import SafeGraphicsEnvironment; public class IFrame extends JFrame { public IFrame() throws HeadlessException {this("");} public IFrame(String title) throws HeadlessException {this(title, null);} public IFrame(GraphicsConfiguration gc) {super(getGraphicsConfiguration(gc));} public IFrame(String title, GraphicsConfiguration gc) {super(title, getGraphicsConfiguration(gc));} private static GraphicsConfiguration getGraphicsConfiguration(GraphicsConfiguration gc) { if (gc != null) return gc; return SafeGraphicsEnvironment.getSafeLocalGraphicsEnvironment() .getDefaultScreenDevice().getDefaultConfiguration(); } }
03-08-2007

SUGGESTED FIX http://javaweb.sfbay/jcg/1.7.0-dolphin/2D/4417798/
13-12-2006

EVALUATION With all these changes, it's important to understand how this affects the "normal" display change events, which don't change the number of attached devices (like a resolution change, or depth). Basically, it will just work: no Java-level GraphicsDevices will be invalidated, we'll reuse those we have. The native array will be recreated just as it has been before this fix. It appears that mhnd's (HMONITOR) of the monitors don't change in a normal display change event, which is why the DirectDraw hw acceleration works - even the obsolete wsdo->device contain correct mhnd, so we can successfully find the corrent DirectDraw instance which correspondinds to the particular display (using GetDDInstanceForDevice(HMONITOR)). So the following chain: wsdo->device => get device's HMONITOR => GetDDInstanceForDevice => ddInstance works as expected. Also, the new native devices's DxCaps field gets correctly initialized after the display change event during the InitDirectX call (see CheckRegistry() in dxInit). The same happens when devices are added/removed.
22-11-2006

EVALUATION Another source of issues was the implementation of the MTSafeArray: unfortunately it didn't prevent from dereferencing a disposed array. For example: T1 about to use the global "devices" reference, but before taking a lock T2 removes the last reference to the "devices" array, and it self-destructs T1 resumes and uses a disposed reference, crash ensues So we need a way to guarantee that user will get a reference to a live array, and it won't be released until the user is done with it. So MTSafeArray class has been reimplemented (and renamed to Devices). Now it encapsulates a single static instance of the Devices class, representing the current array of devices, which the user can only get via static Devices::GetDevicesReference(), which increases the reference counter of the array instance prior to handling it over to the user (while holding a lock). Once user is done with the array, she makes a call array's Release() method to decrement the reference count. With this change a bunch of global static variables in awt_Win32GraphicsEnv.c had been eliminated (awt_numScreens, monHds, devices). The new Devices class also provides facilities to obtain a reference to the particular devices in the array (while atomically increasing the ref number of the array). Also, since the device index is typically used to access particular device, and such index can be obsolete (like if it's handled down from the java level at the time when the device removal happens), the new class also adds some fool-proofing - if the index is out of range, the first device is returned (whether to do this adjustment or not is controlled via parameter in GetDevice and GetDeviceReference methods).
22-11-2006

EVALUATION Just fixing up MTSafeArray won't help, unfortunately, as many of the devices' functions are based off the screen number, and it will be hard to prevent from using incorrect screen number as index because of multithreading: say, while we're responding to WM_DISPLAYCHANGE event on the toolkit thread by replacing the old native devices with the new, another thread may use the old GraphicsDevice's getAvailableAcceleratedMemory() method, which would use the old screen number (1) as index, but if the screen 1 was removed, then we'll get access violation. So a possibly better solution is to invalidate the removed devices before the native devices array is replaced (with possibly shorter one). That way there will be (almost) no window during other threads may use incorrect screen id to index into native devices array. I'm saying "Almost" because there's still a possibility that another thread may grab the screen id and be on its way to the native code then the swap happens - most methods in Win32GD are not sycnronized. This can be mostly alleviated by fool-proofing the native Win32GD functions. So, in native graphcis environment's initScreens() method (called in response to display change event), we invalidate those devices which were removed. Unfortunately there is no way to find which device were removed (at least, I couldn't find one, especially one which would work in both DirectDraw and no-ddraw modes). So, we would have to just invalidate those devices which are out of the new devices array. Say, if there were 3 devices, and 2 were removed, we'll invalidate devices 1,2, leaving device 0 as valid. Of course, this doesn't cover all cases, as the number of devices might not change (say, removed one and added one). But in this case this device's screen number won't change, so it will not be accessing invalid data, so that's ok. We do replace the color model and such, so it shouldn't be a problem. The trick is what to do with those "invalidated" devices. The user may have a reference to it and continue to use it. We don't have any way of indicating that this device is no longer valid short of introducing new API. But I'm hoping to back port this fix to previous releases, so this won't work. So I came up with the following: we just change invalidated devices' screen ids to the default screen. That way if the user still uses it, it will continue to work - it will just be using the default screen's data. These devices will still be removed from the list of java devices and put onto "old devices" list (accessed via weak references) - as we still need to update them when dispay changes occur, or if, say, the default device changes (gets removed). This should take care of most of the issues. It's by no means perfect, though. Another problem is the DirectDraw re-initialization. Our current init code is just not written with possibility of re-initialization in mind, and it will take a lot of effort to change that. It's not worth it as it will most likely be removed in jdk7 anyway as part of the new Direct3D9 pipeline. Currently even the devices which weren't removed will lose hw acceleration on a device removal event. This is because the new native device structures will not be correctly re-initialized (the DxCapabilities, which is a member of Win32GraphicsDevice native object).
10-11-2006

EVALUATION I've tracked the cause of the second crash. Basically, after a screen device has been removed, it is still possible to see attempts to create surfaces on this device. In Win32[OffScreen]SurfaceData_initSurface methods we get the device from the awt devices array using devices->GetElementReference(screen). Unfortunately this method doesn't protect from incorrect screen number - it just returns safeArray[index] instead of NULL, for example. So when later during surfaceData disposal we try to release the device, we crash when attempting to reference wsdo->device. So another piece of the fix would be to fix MTSafeArray::GetElementReference() to return NULL for out of range indexes, and react appropriately in initSurface to the case when device is NULL - invalidate the surface and throw InvalidPipeException.
31-10-2006

EVALUATION More details on one of the crash scenarios: - ddraw enabled - app moved to secondary screen - the screen is then removed We crash in CheckDDCreationCaps: [V] GetDDInstanceForDevice [I] InitDirectX [I] CheckRegistry [V] CheckRegistry: Found Display Device 0: SAPPHIRE RADEON 9000 ATLANTIS PRO [V] DDCanReplaceSurfaces: hwnd=0x0 [V] ddInstance[0]->hwndFullScreen=0x0 [V] ddInstance[1]->hwndFullScreen=0x0 [I] DDInvalidateDDInstance [I] DDCreateSurface [V] GetDDInstanceForDevice [I] DDCreatePrimary [V] GetDDInstanceForDevice [I] DDSetupDevice [I] CheckDDCreationCaps The reason for this crash is the obsolete device data in the native wsdo structure: it keeps a pointer to AwtWin32GraphicsDevice structure, which represents the old removed device. More specific: when trying to create a new primary surface instead of the invalidated one (it gets invalidated when a WM_DISPLAYCHANGE event is received - see awt_Toolkit.cpp), we get the hMon from the surface data to retrieve associated DDrawObjectStruct structure. Note that wsdo->device is still pointing to the old device (AWT creates the new one instead of the old, and the old device list is disposed when there are no more references to it). So, in DDCreatePrimary we attempt to setup the device by calling DDSetupDevice and passing the dxCaps structure retrieved from the corresponding awt device: dxCaps = AwtWin32GraphicsDevice::GetDxCapsForDevice(hMon); where hMon is the monitor handle retrieved from the old awt device. GetDxCapsForDevice can't find the device associated with this monitor in the current devices list, and returns NULL, which we pass to DDSetupDevice. It then gets passed to CheckDDCreationCaps where we happily dereference it and die. Even if for some reason the hMon somehow would be found, the dxCaps for this device would still be null since it would not have been initialized - we do it only once during startup for the initial list of devices. We could address this particular crash by checking for NULL in CheckDDCreationCaps - and return failure if dxCaps is null, which will result in basically disabling ddraw for the old device, which is what we want. But as for reinitializing the ddraw data so that we could use ddraw on the new device - that's another, more complicated story. Another manifestation of this bug is the ArrayIndexOutOfBounds exception. I think this could be basically addressed (in JDK6-7 codebase) by resetting the array of devices on display change. We already have all mechanisms in place for reinitializing the GraphicsConfig data of the components, and they work fine. It does fix the exception, and another problem, where if the monitor is added, and the app is moved to it, the menus appear on the primary screen. These changes will not be sufficient for the noddraw mode, unfortunately, as I've ran into another crash in noddraw mode, which needs further investigation.
26-10-2006

EVALUATION A lot of people are running into this (especially now with notebooks which add/remove a screen when another monitor is plugged). We need to consider fixing this for jdk6 update and possibly 5.0 update as well. Depending on the severity of the fix we may only be able to fix the noddraw mode.
25-10-2006

SUGGESTED FIX deleted
11-09-2004

EVALUATION Targetted for hopper. ###@###.### 2002-01-17 The bug is reproducible with Merlin b92. It dies in CreateDDPrimarySurface. Need to investigate more to find out why. Looks like we don't recreate the native win32 graphics device structures on new screen addition. When ddraw is disabled the application doesn't crash but still returns the wrong number of screens. This is probably because Win32GraphicsEnvironment.resetDisplays doesn't actually reset the displays list. ###@###.### 2002-02-14 This bug is no longer reproducible with 1.4.2 build 13, that is, the application doesn't crash when a screen is added or removed, presumably fixed by the fullscreen fixes (4731131, 4641396, 4713003) and 4738111, which eliminated the use of ogl pixel format functions during the display change, which caused problems for some drivers. There are still problems when the application keeps a hold on an obsolete graphics configuration: for example, if the display has been removed, we do not recreate the list of graphics devices/configurations. This may result in a crash when the app attempts to create a new window using the old GraphicsConfiguration object. We should probably invalidate them somehow and throw an exception. ###@###.### 2003-01-16 Another manifestation of this bug is 4923108. If the JDK is started up in single-screen mode, and then a display is added, you can get the following exception: l:/jdk1.5/windows-i586/bin/java -cp Stylepad.jar;. Stylepad java.lang.ArrayIndexOutOfBoundsException: 1 at sun.awt.windows.WWindowPeer.displayChanged(WWindowPeer.java:173) at sun.awt.windows.WWindowPeer$1.run(WWindowPeer.java:137) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:188) at java.awt.EventQueue.dispatchEvent(EventQueue.java:459) at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:214) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:163) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:157) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:149) at java.awt.EventDispatchThread.run(EventDispatchThread.java:110) ###@###.### 2003-09-17 The array out of index is due to the change of code in sun.awt.Win32GraphicsEnvironment.resetDisplays(Win32GraphicsEnvironment.java:114) with version 1.19 and 1.20 for the file. Earlier the array was always recreated when a resetDisplays call was made. ###@###.### 2003-10-01
01-10-2003

WORK AROUND Run the application with -Dsun.java2d.noddraw=true This will prevent the app from crashing, but the number of devices will still be incorrect. ###@###.### 2002-02-14
14-02-2002