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