Jogamp
fef30f385f02a70494066301149c297c00e8217f
[jogl.git] / src / newt / classes / com / jogamp / javafx / newt / awt / AWTCanvas.java
1 /*
2  * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
3  * 
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  * 
8  * - Redistribution of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * 
11  * - Redistribution in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in the
13  *   documentation and/or other materials provided with the distribution.
14  * 
15  * Neither the name of Sun Microsystems, Inc. or the names of
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  * 
19  * This software is provided "AS IS," without a warranty of any kind. ALL
20  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
23  * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
24  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
25  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
26  * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
27  * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
28  * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
29  * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
30  * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  * 
32  */
33
34 package com.jogamp.javafx.newt.awt;
35
36 import com.jogamp.javafx.newt.Window;
37
38 import java.awt.Canvas;
39 import java.awt.GraphicsDevice;
40 import java.awt.GraphicsEnvironment;
41 import java.awt.GraphicsConfiguration;
42
43 import javax.media.nativewindow.*;
44 import javax.media.nativewindow.awt.*;
45 import com.jogamp.javafx.newt.impl.Debug;
46 import java.lang.reflect.Method;
47 import java.security.AccessController;
48 import java.security.PrivilegedAction;
49
50 public class AWTCanvas extends Canvas {
51   private GraphicsDevice device;
52   private GraphicsConfiguration chosen;
53   private AWTGraphicsConfiguration awtConfig;
54
55   private Capabilities capabilities;
56
57   private boolean displayConfigChanged=false;
58
59   public AWTCanvas(Capabilities capabilities) {
60     super();
61
62     if(null==capabilities) {
63         throw new NativeWindowException("Capabilities null");
64     }
65     this.capabilities=capabilities;
66   }
67
68   public AWTGraphicsConfiguration getAWTGraphicsConfiguration() {
69     return awtConfig;
70   }
71
72   public boolean hasDeviceChanged() {
73     boolean res = displayConfigChanged;
74     displayConfigChanged=false;
75     return res;
76   }
77
78   public void addNotify() {
79     super.addNotify();
80
81     disableBackgroundErase();
82
83     GraphicsConfiguration gc = super.getGraphicsConfiguration();
84     if(null!=gc) {
85         device = gc.getDevice();
86     }
87
88     /*
89      * Save the chosen capabilities for use in getGraphicsConfiguration().
90      */
91     awtConfig = chooseGraphicsConfiguration(capabilities, device);
92     if(Window.DEBUG_IMPLEMENTATION) {
93         Exception e = new Exception("Created Config: "+awtConfig);
94         e.printStackTrace();
95     }
96     if(null!=awtConfig) {
97       // update ..
98       chosen = awtConfig.getGraphicsConfiguration();
99     }
100     if(null==awtConfig) {
101           throw new NativeWindowException("Error: AWTGraphicsConfiguration is null");
102     }
103   }
104
105   /**
106    * Overridden to choose a GraphicsConfiguration on a parent container's
107    * GraphicsDevice because both devices
108    */
109   public GraphicsConfiguration getGraphicsConfiguration() {
110     /*
111      * Workaround for problems with Xinerama and java.awt.Component.checkGD
112      * when adding to a container on a different graphics device than the
113      * one that this Canvas is associated with.
114      * 
115      * GC will be null unless:
116      *   - A native peer has assigned it. This means we have a native
117      *     peer, and are already comitted to a graphics configuration.
118      *   - This canvas has been added to a component hierarchy and has
119      *     an ancestor with a non-null GC, but the native peer has not
120      *     yet been created. This means we can still choose the GC on
121      *     all platforms since the peer hasn't been created.
122      */
123     final GraphicsConfiguration gc = super.getGraphicsConfiguration();
124     /*
125      * chosen is only non-null on platforms where the GLDrawableFactory
126      * returns a non-null GraphicsConfiguration (in the GLCanvas
127      * constructor).
128      * 
129      * if gc is from this Canvas' native peer then it should equal chosen,
130      * otherwise it is from an ancestor component that this Canvas is being
131      * added to, and we go into this block.
132      */
133     if (gc != null && chosen != null && !chosen.equals(gc)) {
134       /*
135        * Check for compatibility with gc. If they differ by only the
136        * device then return a new GCconfig with the super-class' GDevice
137        * (and presumably the same visual ID in Xinerama).
138        * 
139        */
140       if (!chosen.getDevice().getIDstring().equals(gc.getDevice().getIDstring())) {
141         /*
142          * Here we select a GraphicsConfiguration on the alternate
143          * device that is presumably identical to the chosen
144          * configuration, but on the other device.
145          * 
146          * Should really check to ensure that we select a configuration
147          * with the same X visual ID for Xinerama screens, otherwise the
148          * GLDrawable may have the wrong visual ID (I don't think this
149          * ever gets updated). May need to add a method to
150          * X11GLDrawableFactory to do this in a platform specific
151          * manner.
152          * 
153          * However, on platforms where we can actually get into this
154          * block, both devices should have the same visual list, and the
155          * same configuration should be selected here.
156          */
157         AWTGraphicsConfiguration config = chooseGraphicsConfiguration((Capabilities)awtConfig.getRequestedCapabilities(), gc.getDevice());
158         final GraphicsConfiguration compatible = (null!=config)?config.getGraphicsConfiguration():null;
159         if(Window.DEBUG_IMPLEMENTATION) {
160             Exception e = new Exception("Call Stack: "+Thread.currentThread().getName());
161             e.printStackTrace();
162             System.err.println("!!! Created Config (n): HAVE    GC "+chosen);
163             System.err.println("!!! Created Config (n): THIS    GC "+gc);
164             System.err.println("!!! Created Config (n): Choosen GC "+compatible);
165             System.err.println("!!! Created Config (n): HAVE    CF "+awtConfig);
166             System.err.println("!!! Created Config (n): Choosen CF "+config);
167             System.err.println("!!! Created Config (n): EQUALS CAPS "+config.getChosenCapabilities().equals(awtConfig.getChosenCapabilities()));
168         }
169
170         if (compatible != null) {
171           /*
172            * Save the new GC for equals test above, and to return to
173            * any outside callers of this method.
174            */
175           chosen = compatible;
176           if( !config.getChosenCapabilities().equals(awtConfig.getChosenCapabilities())) {
177               displayConfigChanged=true;
178           } 
179           awtConfig = config;
180         }
181       }
182
183       /*
184        * If a compatible GC was not found in the block above, this will
185        * return the GC that was selected in the constructor (and might
186        * cause an exception in Component.checkGD when adding to a
187        * container, but in this case that would be the desired behavior).
188        * 
189        */
190       return chosen;
191     } else if (gc == null) {
192       /*
193        * The GC is null, which means we have no native peer, and are not
194        * part of a (realized) component hierarchy. So we return the
195        * desired visual that was selected in the constructor (possibly
196        * null).
197        */
198       return chosen;
199     }
200
201     /*
202      * Otherwise we have not explicitly selected a GC in the constructor, so
203      * just return what Canvas would have.
204      */
205     return gc;
206   }
207
208   private static AWTGraphicsConfiguration chooseGraphicsConfiguration(Capabilities capabilities,
209                                                                       GraphicsDevice device) {
210     AbstractGraphicsScreen aScreen = AWTGraphicsScreen.createScreenDevice(device);
211     AWTGraphicsConfiguration config = (AWTGraphicsConfiguration)
212       GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class).chooseGraphicsConfiguration(capabilities,
213                                                                                                    null,
214                                                                                                    aScreen);
215     if (config == null) {
216       throw new NativeWindowException("Error: Couldn't fetch AWTGraphicsConfiguration");
217     }
218
219     return config;
220   }
221
222   // Disables the AWT's erasing of this Canvas's background on Windows
223   // in Java SE 6. This internal API is not available in previous
224   // releases, but the system property
225   // -Dsun.awt.noerasebackground=true can be specified to get similar
226   // results globally in previous releases.
227   private static boolean disableBackgroundEraseInitialized;
228   private static Method  disableBackgroundEraseMethod;
229   private void disableBackgroundErase() {
230     if (!disableBackgroundEraseInitialized) {
231       try {
232         AccessController.doPrivileged(new PrivilegedAction() {
233             public Object run() {
234               try {
235                 Class clazz = getToolkit().getClass();
236                 while (clazz != null && disableBackgroundEraseMethod == null) {
237                   try {
238                     disableBackgroundEraseMethod =
239                       clazz.getDeclaredMethod("disableBackgroundErase",
240                                               new Class[] { Canvas.class });
241                     disableBackgroundEraseMethod.setAccessible(true);
242                   } catch (Exception e) {
243                     clazz = clazz.getSuperclass();
244                   }
245                 }
246               } catch (Exception e) {
247               }
248               return null;
249             }
250           });
251       } catch (Exception e) {
252       }
253       disableBackgroundEraseInitialized = true;
254     }
255     if (disableBackgroundEraseMethod != null) {
256       try {
257         disableBackgroundEraseMethod.invoke(getToolkit(), new Object[] { this });
258       } catch (Exception e) {
259         // FIXME: workaround for 6504460 (incorrect backport of 6333613 in 5.0u10)
260         // throw new GLException(e);
261       }
262     }
263   }
264 }
http://JogAmp.org git info: FAQ, tutorial and man pages.