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