Jogamp
JOGL: Reenable Applet/Webstart/RCP support for JOGL + AWT + X11
[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
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.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;
77   private static final GLProfile defaultGLProfile;
78
79   static {
80       DEBUG = Debug.debug("GLCanvas");
81       defaultGLProfile = GLProfile.getDefault();
82   }
83
84   private GLProfile glProfile;
85   private GLDrawableHelper drawableHelper = new GLDrawableHelper();
86   private GraphicsConfiguration chosen;
87   private AWTGraphicsConfiguration awtConfig;
88   private GLDrawable drawable;
89   private GLContextImpl context;
90   private boolean autoSwapBufferMode = true;
91   private boolean sendReshape = false;
92   
93   // copy of the cstr args ..
94   private GLCapabilities capabilities;
95   private GLCapabilitiesChooser chooser;
96   private GLContext shareWith;
97   private GraphicsDevice device;
98
99   /** Creates a new GLCanvas component with a default set of OpenGL
100       capabilities, using the default OpenGL capabilities selection
101       mechanism, on the default screen device. */
102   public GLCanvas() {
103     this(null);
104   }
105
106   /** Creates a new GLCanvas component with the requested set of
107       OpenGL capabilities, using the default OpenGL capabilities
108       selection mechanism, on the default screen device. */
109   public GLCanvas(GLCapabilities capabilities) {
110     this(capabilities, null, null, null);
111   }
112
113   /** Creates a new GLCanvas component. The passed GLCapabilities
114       specifies the OpenGL capabilities for the component; if null, a
115       default set of capabilities is used. The GLCapabilitiesChooser
116       specifies the algorithm for selecting one of the available
117       GLCapabilities for the component; a DefaultGLCapabilitesChooser
118       is used if null is passed for this argument. The passed
119       GLContext specifies an OpenGL context with which to share
120       textures, display lists and other OpenGL state, and may be null
121       if sharing is not desired. See the note in the overview
122       documentation on <a
123       href="../../../overview-summary.html#SHARING">context
124       sharing</a>. The passed GraphicsDevice indicates the screen on
125       which to create the GLCanvas; the GLDrawableFactory uses the
126       default screen device of the local GraphicsEnvironment if null
127       is passed for this argument. */
128   public GLCanvas(GLCapabilities capabilities,
129                   GLCapabilitiesChooser chooser,
130                   GLContext shareWith,
131                   GraphicsDevice device) {
132     /*
133      * Workaround for Xinerama, always pass null so we can detect whether
134      * super.getGraphicsConfiguration() is returning the Canvas' GC (null),
135      * or an ancestor component's GC (non-null) in the overridden version
136      * below.
137      */
138     super();
139
140     if(null==capabilities) {
141         capabilities = new GLCapabilities(defaultGLProfile);
142     }
143     glProfile = capabilities.getGLProfile();
144
145     this.capabilities = capabilities;
146     this.chooser = chooser;
147     this.shareWith=shareWith;
148     this.device = device;
149   }
150
151   protected interface DestroyMethod {
152     public void destroyMethod();
153   }
154
155   protected final static Object  addClosingListener(Component c, final DestroyMethod d) {
156     WindowAdapter cl = null;
157     Window w = getWindow(c);
158     if(null!=w) {
159         cl = new WindowAdapter() {
160                 public void windowClosing(WindowEvent e) {
161                   // we have to issue this call rigth away,
162                   // otherwise the window gets destroyed
163                   d.destroyMethod();
164                 }
165             };
166         w.addWindowListener(cl);
167     }
168     return cl;
169   }
170
171   protected final static Window getWindow(Component c) {
172     while ( c!=null && ! ( c instanceof Window ) ) {
173         c = c.getParent();
174     }
175     return (Window)c;
176   }
177
178   /**
179    * Overridden to choose a GraphicsConfiguration on a parent container's
180    * GraphicsDevice because both devices
181    */
182   public GraphicsConfiguration getGraphicsConfiguration() {
183     /*
184      * Workaround for problems with Xinerama and java.awt.Component.checkGD
185      * when adding to a container on a different graphics device than the
186      * one that this Canvas is associated with.
187      * 
188      * GC will be null unless:
189      *   - A native peer has assigned it. This means we have a native
190      *     peer, and are already comitted to a graphics configuration.
191      *   - This canvas has been added to a component hierarchy and has
192      *     an ancestor with a non-null GC, but the native peer has not
193      *     yet been created. This means we can still choose the GC on
194      *     all platforms since the peer hasn't been created.
195      */
196     final GraphicsConfiguration gc = super.getGraphicsConfiguration();
197     /*
198      * chosen is only non-null on platforms where the GLDrawableFactory
199      * returns a non-null GraphicsConfiguration (in the GLCanvas
200      * constructor).
201      * 
202      * if gc is from this Canvas' native peer then it should equal chosen,
203      * otherwise it is from an ancestor component that this Canvas is being
204      * added to, and we go into this block.
205      */
206     if (gc != null && chosen != null && !chosen.equals(gc)) {
207       /*
208        * Check for compatibility with gc. If they differ by only the
209        * device then return a new GCconfig with the super-class' GDevice
210        * (and presumably the same visual ID in Xinerama).
211        * 
212        */
213       if (!chosen.getDevice().getIDstring().equals(gc.getDevice().getIDstring())) {
214         /*
215          * Here we select a GraphicsConfiguration on the alternate
216          * device that is presumably identical to the chosen
217          * configuration, but on the other device.
218          * 
219          * Should really check to ensure that we select a configuration
220          * with the same X visual ID for Xinerama screens, otherwise the
221          * GLDrawable may have the wrong visual ID (I don't think this
222          * ever gets updated). May need to add a method to
223          * X11GLDrawableFactory to do this in a platform specific
224          * manner.
225          * 
226          * However, on platforms where we can actually get into this
227          * block, both devices should have the same visual list, and the
228          * same configuration should be selected here.
229          */
230         AWTGraphicsConfiguration config = chooseGraphicsConfiguration((GLCapabilities)awtConfig.getRequestedCapabilities(), chooser, gc.getDevice());
231         final GraphicsConfiguration compatible = (null!=config)?config.getGraphicsConfiguration():null;
232         boolean equalCaps = config.getChosenCapabilities().equals(awtConfig.getChosenCapabilities());
233         if(DEBUG) {
234             Exception e = new Exception("Info: Call Stack: "+Thread.currentThread().getName());
235             e.printStackTrace();
236             System.err.println("!!! Created Config (n): HAVE    GC "+chosen);
237             System.err.println("!!! Created Config (n): THIS    GC "+gc);
238             System.err.println("!!! Created Config (n): Choosen GC "+compatible);
239             System.err.println("!!! Created Config (n): HAVE    CF "+awtConfig);
240             System.err.println("!!! Created Config (n): Choosen CF "+config);
241             System.err.println("!!! Created Config (n): EQUALS CAPS "+equalCaps);
242         }
243
244         if (compatible != null) {
245           /*
246            * Save the new GC for equals test above, and to return to
247            * any outside callers of this method.
248            */
249           chosen = compatible;
250
251           awtConfig = config;
252
253           if( !equalCaps && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED ) {
254               dispose(true);
255           }
256         }
257       }
258
259       /*
260        * If a compatible GC was not found in the block above, this will
261        * return the GC that was selected in the constructor (and might
262        * cause an exception in Component.checkGD when adding to a
263        * container, but in this case that would be the desired behavior).
264        * 
265        */
266       return chosen;
267     } else if (gc == null) {
268       /*
269        * The GC is null, which means we have no native peer, and are not
270        * part of a (realized) component hierarchy. So we return the
271        * desired visual that was selected in the constructor (possibly
272        * null).
273        */
274       return chosen;
275     }
276
277     /*
278      * Otherwise we have not explicitly selected a GC in the constructor, so
279      * just return what Canvas would have.
280      */
281     return gc;
282   }
283   
284   public GLContext createContext(GLContext shareWith) {
285     return drawable.createContext(shareWith);
286   }
287
288   public void setRealized(boolean realized) {
289   }
290
291   public boolean isRealized() {
292     return ( null != drawable ) ? drawable.isRealized() : false;
293   }
294
295   private Object closingListener = null;
296   private Object closingListenerLock = new Object();
297
298   public void display() {
299     maybeDoSingleThreadedWorkaround(displayOnEventDispatchThreadAction,
300                                     displayAction);
301     if(null==closingListener) {
302       synchronized(closingListenerLock) {
303         if(null==closingListener) {
304             closingListener=addClosingListener(this, new DestroyMethod() { 
305                         public void destroyMethod() { destroy(); } });
306         }
307       }
308     }
309   }
310
311   protected void dispose(boolean regenerate) {
312     if(DEBUG) {
313         Exception ex1 = new Exception("Info: dispose("+regenerate+") - start");
314         ex1.printStackTrace();
315     }
316
317     if(null!=context) {
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
341     if(DEBUG) {
342         System.err.println("dispose("+regenerate+") - stop");
343     }
344   }
345
346   /**
347    * Just an alias for removeNotify
348    */
349   public void destroy() {
350     removeNotify();
351   }
352
353   /** Overridden to cause OpenGL rendering to be performed during
354       repaint cycles. Subclasses which override this method must call
355       super.paint() in their paint() method in order to function
356       properly. <P>
357
358       <B>Overrides:</B>
359       <DL><DD><CODE>paint</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
360   public void paint(Graphics g) {
361     if (Beans.isDesignTime()) {
362       // Make GLCanvas behave better in NetBeans GUI builder
363       g.setColor(Color.BLACK);
364       g.fillRect(0, 0, getWidth(), getHeight());
365       FontMetrics fm = g.getFontMetrics();
366       String name = getName();
367       if (name == null) {
368         name = getClass().getName();
369         int idx = name.lastIndexOf('.');
370         if (idx >= 0) {
371           name = name.substring(idx + 1);
372         }
373       }
374       Rectangle2D bounds = fm.getStringBounds(name, g);
375       g.setColor(Color.WHITE);
376       g.drawString(name,
377                    (int) ((getWidth()  - bounds.getWidth())  / 2),
378                    (int) ((getHeight() + bounds.getHeight()) / 2));
379       return;
380     }
381     if( ! this.drawableHelper.isExternalAnimatorAnimating() ) {
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         NativeWindowFactory.getDefaultToolkitLock().lock();
409         try {
410             awtConfig = chooseGraphicsConfiguration(capabilities, chooser, device);
411             if(DEBUG) {
412                 Exception e = new Exception("Info: 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             NativeWindowFactory.getDefaultToolkitLock().unlock();
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("Info: 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.err.println("Info: 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(GLAnimatorControl animatorControl) {
498     drawableHelper.setAnimator(animatorControl);
499   }
500
501   public GLAnimatorControl 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 NativeSurface getNativeSurface() {
568     return drawable.getNativeSurface();
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")+"]";
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.