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