Jogamp
Merge branch 'master' of github.com:sgothel/jogl
[jogl.git] / src / jogl / classes / javax / media / opengl / awt / GLCanvas.java
1 /*
2  * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
3  * 
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  * 
8  * - Redistribution of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * 
11  * - Redistribution in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in the
13  *   documentation and/or other materials provided with the distribution.
14  * 
15  * Neither the name of Sun Microsystems, Inc. or the names of
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  * 
19  * This software is provided "AS IS," without a warranty of any kind. ALL
20  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
23  * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
24  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
25  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
26  * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
27  * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
28  * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
29  * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
30  * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  * 
32  * You acknowledge that this software is not designed or intended for use
33  * in the design, construction, operation or maintenance of any nuclear
34  * facility.
35  * 
36  * Sun gratefully acknowledges that this software was originally authored
37  * and developed by Kenneth Bradley Russell and Christopher John Kline.
38  */
39
40 package javax.media.opengl.awt;
41
42 import javax.media.opengl.*;
43 import javax.media.nativewindow.*;
44 import javax.media.nativewindow.awt.*;
45
46 import com.jogamp.opengl.impl.*;
47
48 import java.awt.Canvas;
49 import java.awt.Color;
50 import java.awt.Component;
51 import java.awt.FontMetrics;
52 import java.awt.Graphics;
53 import java.awt.GraphicsConfiguration;
54 import java.awt.GraphicsDevice;
55 import java.awt.Container;
56 import java.awt.Window;
57 import java.awt.event.WindowEvent;
58 import java.awt.event.WindowAdapter;
59 import java.awt.geom.*;
60 import java.beans.*;
61 import java.lang.reflect.*;
62 import java.security.*;
63
64 // FIXME: Subclasses need to call resetGLFunctionAvailability() on their
65 // context whenever the displayChanged() function is called on our
66 // GLEventListeners
67
68 /** A heavyweight AWT component which provides OpenGL rendering
69     support. This is the primary implementation of {@link GLDrawable};
70     {@link GLJPanel} is provided for compatibility with Swing user
71     interfaces when adding a heavyweight doesn't work either because
72     of Z-ordering or LayoutManager problems. */
73
74 public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
75
76   private static final boolean DEBUG = Debug.debug("GLCanvas");
77
78   static private GLProfile defaultGLProfile = GLProfile.getDefault();
79   private GLProfile glProfile;
80   private GLDrawableHelper drawableHelper = new GLDrawableHelper();
81   private GraphicsConfiguration chosen;
82   private AWTGraphicsConfiguration awtConfig;
83   private GLDrawable drawable;
84   private GLContextImpl context;
85   private boolean autoSwapBufferMode = true;
86   private boolean sendReshape = false;
87   
88   // copy of the cstr args ..
89   private GLCapabilities capabilities;
90   private GLCapabilitiesChooser chooser;
91   private GLContext shareWith;
92   private GraphicsDevice device;
93
94   /** Creates a new GLCanvas component with a default set of OpenGL
95       capabilities, using the default OpenGL capabilities selection
96       mechanism, on the default screen device. */
97   public GLCanvas() {
98     this(null);
99   }
100
101   /** Creates a new GLCanvas component with the requested set of
102       OpenGL capabilities, using the default OpenGL capabilities
103       selection mechanism, on the default screen device. */
104   public GLCanvas(GLCapabilities capabilities) {
105     this(capabilities, null, null, null);
106   }
107
108   /** Creates a new GLCanvas component. The passed GLCapabilities
109       specifies the OpenGL capabilities for the component; if null, a
110       default set of capabilities is used. The GLCapabilitiesChooser
111       specifies the algorithm for selecting one of the available
112       GLCapabilities for the component; a DefaultGLCapabilitesChooser
113       is used if null is passed for this argument. The passed
114       GLContext specifies an OpenGL context with which to share
115       textures, display lists and other OpenGL state, and may be null
116       if sharing is not desired. See the note in the overview
117       documentation on <a
118       href="../../../overview-summary.html#SHARING">context
119       sharing</a>. The passed GraphicsDevice indicates the screen on
120       which to create the GLCanvas; the GLDrawableFactory uses the
121       default screen device of the local GraphicsEnvironment if null
122       is passed for this argument. */
123   public GLCanvas(GLCapabilities capabilities,
124                   GLCapabilitiesChooser chooser,
125                   GLContext shareWith,
126                   GraphicsDevice device) {
127     /*
128      * Workaround for Xinerama, always pass null so we can detect whether
129      * super.getGraphicsConfiguration() is returning the Canvas' GC (null),
130      * or an ancestor component's GC (non-null) in the overridden version
131      * below.
132      */
133     super();
134
135     if(null==capabilities) {
136         capabilities = new GLCapabilities(defaultGLProfile);
137     }
138     glProfile = capabilities.getGLProfile();
139
140     this.capabilities = capabilities;
141     this.chooser = chooser;
142     this.shareWith=shareWith;
143     this.device = device;
144   }
145
146   protected interface DestroyMethod {
147     public void destroyMethod();
148   }
149
150   protected final static Object  addClosingListener(Component c, final DestroyMethod d) {
151     WindowAdapter cl = null;
152     Window w = getWindow(c);
153     if(null!=w) {
154         cl = new WindowAdapter() {
155                 public void windowClosing(WindowEvent e) {
156                   // we have to issue this call rigth away,
157                   // otherwise the window gets destroyed
158                   d.destroyMethod();
159                 }
160             };
161         w.addWindowListener(cl);
162     }
163     return cl;
164   }
165
166   protected final static Window getWindow(Component c) {
167     while ( c!=null && ! ( c instanceof Window ) ) {
168         c = c.getParent();
169     }
170     return (Window)c;
171   }
172
173   /**
174    * Overridden to choose a GraphicsConfiguration on a parent container's
175    * GraphicsDevice because both devices
176    */
177   public GraphicsConfiguration getGraphicsConfiguration() {
178     /*
179      * Workaround for problems with Xinerama and java.awt.Component.checkGD
180      * when adding to a container on a different graphics device than the
181      * one that this Canvas is associated with.
182      * 
183      * GC will be null unless:
184      *   - A native peer has assigned it. This means we have a native
185      *     peer, and are already comitted to a graphics configuration.
186      *   - This canvas has been added to a component hierarchy and has
187      *     an ancestor with a non-null GC, but the native peer has not
188      *     yet been created. This means we can still choose the GC on
189      *     all platforms since the peer hasn't been created.
190      */
191     final GraphicsConfiguration gc = super.getGraphicsConfiguration();
192     /*
193      * chosen is only non-null on platforms where the GLDrawableFactory
194      * returns a non-null GraphicsConfiguration (in the GLCanvas
195      * constructor).
196      * 
197      * if gc is from this Canvas' native peer then it should equal chosen,
198      * otherwise it is from an ancestor component that this Canvas is being
199      * added to, and we go into this block.
200      */
201     if (gc != null && chosen != null && !chosen.equals(gc)) {
202       /*
203        * Check for compatibility with gc. If they differ by only the
204        * device then return a new GCconfig with the super-class' GDevice
205        * (and presumably the same visual ID in Xinerama).
206        * 
207        */
208       if (!chosen.getDevice().getIDstring().equals(gc.getDevice().getIDstring())) {
209         /*
210          * Here we select a GraphicsConfiguration on the alternate
211          * device that is presumably identical to the chosen
212          * configuration, but on the other device.
213          * 
214          * Should really check to ensure that we select a configuration
215          * with the same X visual ID for Xinerama screens, otherwise the
216          * GLDrawable may have the wrong visual ID (I don't think this
217          * ever gets updated). May need to add a method to
218          * X11GLDrawableFactory to do this in a platform specific
219          * manner.
220          * 
221          * However, on platforms where we can actually get into this
222          * block, both devices should have the same visual list, and the
223          * same configuration should be selected here.
224          */
225         AWTGraphicsConfiguration config = chooseGraphicsConfiguration((GLCapabilities)awtConfig.getRequestedCapabilities(), chooser, gc.getDevice());
226         final GraphicsConfiguration compatible = (null!=config)?config.getGraphicsConfiguration():null;
227         boolean equalCaps = config.getChosenCapabilities().equals(awtConfig.getChosenCapabilities());
228         if(DEBUG) {
229             Exception e = new Exception("Call Stack: "+Thread.currentThread().getName());
230             e.printStackTrace();
231             System.err.println("!!! Created Config (n): HAVE    GC "+chosen);
232             System.err.println("!!! Created Config (n): THIS    GC "+gc);
233             System.err.println("!!! Created Config (n): Choosen GC "+compatible);
234             System.err.println("!!! Created Config (n): HAVE    CF "+awtConfig);
235             System.err.println("!!! Created Config (n): Choosen CF "+config);
236             System.err.println("!!! Created Config (n): EQUALS CAPS "+equalCaps);
237         }
238
239         if (compatible != null) {
240           /*
241            * Save the new GC for equals test above, and to return to
242            * any outside callers of this method.
243            */
244           chosen = compatible;
245
246           awtConfig = config;
247
248           if( !equalCaps && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED ) {
249               dispose(true);
250           }
251         }
252       }
253
254       /*
255        * If a compatible GC was not found in the block above, this will
256        * return the GC that was selected in the constructor (and might
257        * cause an exception in Component.checkGD when adding to a
258        * container, but in this case that would be the desired behavior).
259        * 
260        */
261       return chosen;
262     } else if (gc == null) {
263       /*
264        * The GC is null, which means we have no native peer, and are not
265        * part of a (realized) component hierarchy. So we return the
266        * desired visual that was selected in the constructor (possibly
267        * null).
268        */
269       return chosen;
270     }
271
272     /*
273      * Otherwise we have not explicitly selected a GC in the constructor, so
274      * just return what Canvas would have.
275      */
276     return gc;
277   }
278   
279   public GLContext createContext(GLContext shareWith) {
280     return drawable.createContext(shareWith);
281   }
282
283   public void setRealized(boolean realized) {
284   }
285
286   private Object closingListener = null;
287   private Object closingListenerLock = new Object();
288
289   public void display() {
290     maybeDoSingleThreadedWorkaround(displayOnEventDispatchThreadAction,
291                                     displayAction);
292     if(null==closingListener) {
293       synchronized(closingListenerLock) {
294         if(null==closingListener) {
295             closingListener=addClosingListener(this, new DestroyMethod() { 
296                         public void destroyMethod() { destroy(); } });
297         }
298       }
299     }
300   }
301
302   protected void dispose(boolean regenerate) {
303     if(DEBUG) {
304         Exception ex1 = new Exception("dispose("+regenerate+") - start");
305         ex1.printStackTrace();
306     }
307     disposeRegenerate=regenerate;
308
309     if (Threading.isSingleThreaded() &&
310         !Threading.isOpenGLThread()) {
311       // Workaround for termination issues with applets --
312       // sun.applet.AppletPanel should probably be performing the
313       // remove() call on the EDT rather than on its own thread
314       if (ThreadingImpl.isAWTMode() &&
315           Thread.holdsLock(getTreeLock())) {
316         // The user really should not be invoking remove() from this
317         // thread -- but since he/she is, we can not go over to the
318         // EDT at this point. Try to destroy the context from here.
319         drawableHelper.invokeGL(drawable, context, disposeAction, null);
320       } else {
321         Threading.invokeOnOpenGLThread(disposeOnEventDispatchThreadAction);
322       }
323     } else {
324       drawableHelper.invokeGL(drawable, context, disposeAction, null);
325     }
326
327     if(DEBUG) {
328         System.err.println("dispose("+regenerate+") - stop");
329     }
330   }
331
332   /**
333    * Just an alias for removeNotify
334    */
335   public void destroy() {
336     removeNotify();
337   }
338
339   /** Overridden to cause OpenGL rendering to be performed during
340       repaint cycles. Subclasses which override this method must call
341       super.paint() in their paint() method in order to function
342       properly. <P>
343
344       <B>Overrides:</B>
345       <DL><DD><CODE>paint</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
346   public void paint(Graphics g) {
347     if (Beans.isDesignTime()) {
348       // Make GLCanvas behave better in NetBeans GUI builder
349       g.setColor(Color.BLACK);
350       g.fillRect(0, 0, getWidth(), getHeight());
351       FontMetrics fm = g.getFontMetrics();
352       String name = getName();
353       if (name == null) {
354         name = getClass().getName();
355         int idx = name.lastIndexOf('.');
356         if (idx >= 0) {
357           name = name.substring(idx + 1);
358         }
359       }
360       Rectangle2D bounds = fm.getStringBounds(name, g);
361       g.setColor(Color.WHITE);
362       g.drawString(name,
363                    (int) ((getWidth()  - bounds.getWidth())  / 2),
364                    (int) ((getHeight() + bounds.getHeight()) / 2));
365       return;
366     }
367
368     display();
369   }
370
371   /** Overridden to track when this component is added to a container.
372       Subclasses which override this method must call
373       super.addNotify() in their addNotify() method in order to
374       function properly. <P>
375
376       <B>Overrides:</B>
377       <DL><DD><CODE>addNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
378   public void addNotify() {
379     super.addNotify();
380     if (!Beans.isDesignTime()) {
381         disableBackgroundErase();
382
383         if(null==device) {
384             GraphicsConfiguration gc = super.getGraphicsConfiguration();
385             if(null!=gc) {
386                 device = gc.getDevice();
387             }
388         }
389
390         /*
391          * Save the chosen capabilities for use in getGraphicsConfiguration().
392          */
393         awtConfig = chooseGraphicsConfiguration(capabilities, chooser, device);
394         if(DEBUG) {
395             Exception e = new Exception("Created Config: "+awtConfig);
396             e.printStackTrace();
397         }
398         if(null!=awtConfig) {
399           // update ..
400           chosen = awtConfig.getGraphicsConfiguration();
401
402         }
403         if(null==awtConfig) {
404           throw new GLException("Error: AWTGraphicsConfiguration is null");
405         }
406         drawable = GLDrawableFactory.getFactory(glProfile).createGLDrawable(NativeWindowFactory.getNativeWindow(this, awtConfig));
407         context = (GLContextImpl) drawable.createContext(shareWith);
408         context.setSynchronized(true);
409
410         if(DEBUG) {
411             System.err.println("Created Drawable: "+drawable);
412         }
413         drawable.setRealized(true);
414     }
415   }
416
417   /** Overridden to track when this component is removed from a
418       container. Subclasses which override this method must call
419       super.removeNotify() in their removeNotify() method in order to
420       function properly. <P>
421
422       <B>Overrides:</B>
423       <DL><DD><CODE>removeNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
424   public void removeNotify() {
425     if(DEBUG) {
426         Exception ex1 = new Exception("removeNotify - start");
427         ex1.printStackTrace();
428     }
429
430     if (Beans.isDesignTime()) {
431       super.removeNotify();
432     } else {
433       try {
434         dispose(false);
435       } finally {
436         drawable=null;
437         super.removeNotify();
438       }
439     }
440     if(DEBUG) {
441         System.out.println("removeNotify - end");
442     }
443   }
444
445   /** Overridden to cause {@link GLDrawableHelper#reshape} to be
446       called on all registered {@link GLEventListener}s. Subclasses
447       which override this method must call super.reshape() in
448       their reshape() method in order to function properly. <P>
449
450       <B>Overrides:</B>
451       <DL><DD><CODE>reshape</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
452   public void reshape(int x, int y, int width, int height) {
453     super.reshape(x, y, width, height);
454     sendReshape = true;
455   }
456
457   /** <B>Overrides:</B>
458       <DL><DD><CODE>update</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
459   // Overridden from Canvas to prevent the AWT's clearing of the
460   // canvas from interfering with the OpenGL rendering.
461   public void update(Graphics g) {
462     paint(g);
463   }
464   
465   public void addGLEventListener(GLEventListener listener) {
466     drawableHelper.addGLEventListener(listener);
467   }
468
469   public void removeGLEventListener(GLEventListener listener) {
470     drawableHelper.removeGLEventListener(listener);
471   }
472
473   public void setContext(GLContext ctx) {
474     context=(GLContextImpl)ctx;
475   }
476
477   public GLContext getContext() {
478     return context;
479   }
480
481   public GL getGL() {
482     if (Beans.isDesignTime()) {
483       return null;
484     }
485     GLContext context = getContext();
486     return (context == null) ? null : context.getGL();
487   }
488
489   public GL setGL(GL gl) {
490     GLContext context = getContext();
491     if (context != null) {
492       context.setGL(gl);
493       return gl;
494     }
495     return null;
496   }
497
498
499   public void setAutoSwapBufferMode(boolean onOrOff) {
500     drawableHelper.setAutoSwapBufferMode(onOrOff);
501   }
502
503   public boolean getAutoSwapBufferMode() {
504     return drawableHelper.getAutoSwapBufferMode();
505   }
506
507   public void swapBuffers() {
508     maybeDoSingleThreadedWorkaround(swapBuffersOnEventDispatchThreadAction, swapBuffersAction);
509   }
510
511   public GLProfile getGLProfile() {
512     return glProfile;
513   }
514
515   public GLCapabilities getChosenGLCapabilities() {
516     if (awtConfig == null) {
517         throw new GLException("No AWTGraphicsConfiguration: "+this);
518     }
519
520     return (GLCapabilities)awtConfig.getChosenCapabilities();
521   }
522
523   public GLCapabilities getRequestedGLCapabilities() {
524     if (awtConfig == null) {
525         throw new GLException("No AWTGraphicsConfiguration: "+this);
526     }
527
528     return (GLCapabilities)awtConfig.getRequestedCapabilities();
529   }
530
531   public NativeWindow getNativeWindow() {
532     return drawable.getNativeWindow();
533   }
534
535   public GLDrawableFactory getFactory() {
536     return drawable.getFactory();
537   }
538
539   public String toString() {
540     return "AWT-GLCanvas[ "+awtConfig+", "+((null!=drawable)?drawable.getClass().getName():"null-drawable")+", "+drawableHelper+"]";
541   }
542
543   //----------------------------------------------------------------------
544   // Internals only below this point
545   //
546
547   private void maybeDoSingleThreadedWorkaround(Runnable eventDispatchThreadAction,
548                                                Runnable invokeGLAction) {
549     if (Threading.isSingleThreaded() &&
550         !Threading.isOpenGLThread()) {
551       Threading.invokeOnOpenGLThread(eventDispatchThreadAction);
552     } else {
553       drawableHelper.invokeGL(drawable, context, invokeGLAction, initAction);
554     }
555   }
556
557   private boolean disposeRegenerate;
558   private DisposeAction disposeAction = new DisposeAction(this);
559
560   class DisposeAction implements Runnable {
561     private GLCanvas canvas;
562     public DisposeAction(GLCanvas canvas) {
563         this.canvas = canvas;
564     }
565     public void run() {
566       drawableHelper.dispose(GLCanvas.this);
567
568       if(null!=context) {
569         context.makeCurrent(); // implicit wait for lock ..
570         context.destroy();
571         context=null;
572       }
573
574       if(null!=drawable) {
575           drawable.setRealized(false);
576       }
577
578       if(disposeRegenerate) {
579           // recreate GLDrawable to reflect it's new graphics configuration
580           drawable = GLDrawableFactory.getFactory(glProfile).createGLDrawable(NativeWindowFactory.getNativeWindow(canvas, awtConfig));
581           if(DEBUG) {
582             System.err.println("GLCanvas.dispose(true): new drawable: "+drawable);
583           }
584           drawable.setRealized(true);
585           context = (GLContextImpl) drawable.createContext(shareWith);
586           context.setSynchronized(true);
587           sendReshape=true; // ensure a reshape is being send ..
588       }
589     }
590   }
591
592   private DisposeOnEventDispatchThreadAction disposeOnEventDispatchThreadAction =
593     new DisposeOnEventDispatchThreadAction();
594
595   class DisposeOnEventDispatchThreadAction implements Runnable {
596     public void run() {
597       drawableHelper.invokeGL(drawable, context, disposeAction, null);
598     }
599   }
600
601   class InitAction implements Runnable {
602     public void run() {
603       drawableHelper.init(GLCanvas.this);
604     }
605   }
606   private InitAction initAction = new InitAction();
607   
608   class DisplayAction implements Runnable {
609     public void run() {
610       if (sendReshape) {
611         // Note: we ignore the given x and y within the parent component
612         // since we are drawing directly into this heavyweight component.
613         int width = getWidth();
614         int height = getHeight();
615         getGL().glViewport(0, 0, width, height);
616         drawableHelper.reshape(GLCanvas.this, 0, 0, width, height);
617         sendReshape = false;
618       }
619
620       drawableHelper.display(GLCanvas.this);
621     }
622   }
623   private DisplayAction displayAction = new DisplayAction();
624
625   class SwapBuffersAction implements Runnable {
626     public void run() {
627       drawable.swapBuffers();
628     }
629   }
630   private SwapBuffersAction swapBuffersAction = new SwapBuffersAction();
631
632   // Workaround for ATI driver bugs related to multithreading issues
633   // like simultaneous rendering via Animators to canvases that are
634   // being resized on the AWT event dispatch thread
635   class DisplayOnEventDispatchThreadAction implements Runnable {
636     public void run() {
637       drawableHelper.invokeGL(drawable, context, displayAction, initAction);
638     }
639   }
640   private DisplayOnEventDispatchThreadAction displayOnEventDispatchThreadAction =
641     new DisplayOnEventDispatchThreadAction();
642   class SwapBuffersOnEventDispatchThreadAction implements Runnable {
643     public void run() {
644       drawableHelper.invokeGL(drawable, context, swapBuffersAction, initAction);
645     }
646   }
647   private SwapBuffersOnEventDispatchThreadAction swapBuffersOnEventDispatchThreadAction =
648     new SwapBuffersOnEventDispatchThreadAction();
649
650   // Disables the AWT's erasing of this Canvas's background on Windows
651   // in Java SE 6. This internal API is not available in previous
652   // releases, but the system property
653   // -Dsun.awt.noerasebackground=true can be specified to get similar
654   // results globally in previous releases.
655   private static boolean disableBackgroundEraseInitialized;
656   private static Method  disableBackgroundEraseMethod;
657   private void disableBackgroundErase() {
658     if (!disableBackgroundEraseInitialized) {
659       try {
660         AccessController.doPrivileged(new PrivilegedAction() {
661             public Object run() {
662               try {
663                 Class clazz = getToolkit().getClass();
664                 while (clazz != null && disableBackgroundEraseMethod == null) {
665                   try {
666                     disableBackgroundEraseMethod =
667                       clazz.getDeclaredMethod("disableBackgroundErase",
668                                               new Class[] { Canvas.class });
669                     disableBackgroundEraseMethod.setAccessible(true);
670                   } catch (Exception e) {
671                     clazz = clazz.getSuperclass();
672                   }
673                 }
674               } catch (Exception e) {
675               }
676               return null;
677             }
678           });
679       } catch (Exception e) {
680       }
681       disableBackgroundEraseInitialized = true;
682     }
683     if (disableBackgroundEraseMethod != null) {
684       try {
685         disableBackgroundEraseMethod.invoke(getToolkit(), new Object[] { this });
686       } catch (Exception e) {
687         // FIXME: workaround for 6504460 (incorrect backport of 6333613 in 5.0u10)
688         // throw new GLException(e);
689       }
690     }
691   }
692
693   private static AWTGraphicsConfiguration chooseGraphicsConfiguration(GLCapabilities capabilities,
694                                                                       GLCapabilitiesChooser chooser,
695                                                                       GraphicsDevice device) {
696     // Make GLCanvas behave better in NetBeans GUI builder
697     if (Beans.isDesignTime()) {
698       return null;
699     }
700
701     AbstractGraphicsScreen aScreen = AWTGraphicsScreen.createScreenDevice(device);
702     AWTGraphicsConfiguration config = (AWTGraphicsConfiguration)
703       GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class).chooseGraphicsConfiguration(capabilities,
704                                                                                                    chooser,
705                                                                                                    aScreen);
706     if (config == null) {
707       throw new GLException("Error: Couldn't fetch AWTGraphicsConfiguration");
708     }
709
710     return config;
711   }
712 }
http://JogAmp.org git info: FAQ, tutorial and man pages.