United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: 4417798 Need to track add/remove of monitors on display changes
4417798 : Need to track add/remove of monitors on display changes

Details
Type:
Bug
Submit Date:
2001-02-22
Status:
Closed
Updated Date:
2011-04-05
Project Name:
JDK
Resolved Date:
2011-04-05
Component:
client-libs
OS:
linux,windows_xp,windows_2000
Sub-Component:
2d
CPU:
x86
Priority:
P2
Resolution:
Fixed
Affected Versions:
1.4.0,1.4.1_03,1.4.2_03,5.0,6
Fixed Versions:
7

Related Reports
Backport:
Duplicate:
Duplicate:
Duplicate:
Duplicate:
Duplicate:
Duplicate:
Duplicate:
Relates:
Relates:
Relates:
Relates:

Sub Tasks

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();
    }
}
                                     
2007-08-03
SUGGESTED FIX

http://javaweb.sfbay/jcg/1.7.0-dolphin/2D/4417798/
                                     
2006-12-13
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).
                                     
2006-11-22
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.
                                     
2006-11-22
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).
                                     
2006-11-10
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.
                                     
2006-10-31
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.
                                     
2006-10-26
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.
                                     
2006-10-25
SUGGESTED FIX

deleted
                                     
2004-09-11
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
                                     
2003-10-01
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
                                     
2002-02-14



Hardware and Software, Engineered to Work Together