Jogamp
Bug 741 HiDPI: Add ScalableSurface interface to get/set pixelScale w/ full OSX impl.
[jogl.git] / src / jogl / classes / javax / media / opengl / awt / GLCanvas.java
CommitLineData
a959c53b
KR
1/*
2 * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
34fffab0 3 * Copyright (c) 2010 JogAmp Community. All rights reserved.
bd92af2b 4 *
a959c53b
KR
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
bd92af2b 8 *
a959c53b
KR
9 * - Redistribution of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
bd92af2b 11 *
a959c53b
KR
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.
bd92af2b 15 *
a959c53b
KR
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.
bd92af2b 19 *
a959c53b
KR
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.
bd92af2b 32 *
a959c53b
KR
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.
bd92af2b 36 *
a959c53b
KR
37 * Sun gratefully acknowledges that this software was originally authored
38 * and developed by Kenneth Bradley Russell and Christopher John Kline.
39 */
40
41package javax.media.opengl.awt;
42
2cbab63b
SG
43import java.beans.Beans;
44import java.lang.reflect.Method;
45import java.security.AccessController;
46import java.security.PrivilegedAction;
a959c53b
KR
47import java.awt.Canvas;
48import java.awt.Color;
a959c53b 49import java.awt.FontMetrics;
597d10f5 50import java.awt.Frame;
a959c53b 51import java.awt.Graphics;
9450900c 52import java.awt.Graphics2D;
a959c53b
KR
53import java.awt.GraphicsConfiguration;
54import java.awt.GraphicsDevice;
071bdd6c
SG
55import java.awt.event.HierarchyEvent;
56import java.awt.event.HierarchyListener;
8a4a64e1 57import java.awt.geom.NoninvertibleTransformException;
2cbab63b 58import java.awt.geom.Rectangle2D;
8adc0478
SG
59import java.awt.EventQueue;
60import java.lang.reflect.InvocationTargetException;
61import java.util.ArrayList;
8c78f80f 62import java.util.List;
2cbab63b 63
098398c2 64import javax.media.nativewindow.AbstractGraphicsConfiguration;
8e0f3ad5 65import javax.media.nativewindow.OffscreenLayerOption;
2571ed0b 66import javax.media.nativewindow.ScalableSurface;
00bef950 67import javax.media.nativewindow.VisualIDHolder;
2cbab63b 68import javax.media.nativewindow.WindowClosingProtocol;
2cbab63b
SG
69import javax.media.nativewindow.AbstractGraphicsDevice;
70import javax.media.nativewindow.AbstractGraphicsScreen;
71import javax.media.nativewindow.GraphicsConfigurationFactory;
72import javax.media.nativewindow.NativeSurface;
73import javax.media.nativewindow.NativeWindowFactory;
2cbab63b
SG
74import javax.media.opengl.GL;
75import javax.media.opengl.GLAnimatorControl;
76import javax.media.opengl.GLAutoDrawable;
77import javax.media.opengl.GLCapabilities;
78import javax.media.opengl.GLCapabilitiesChooser;
79import javax.media.opengl.GLCapabilitiesImmutable;
80import javax.media.opengl.GLContext;
81import javax.media.opengl.GLDrawable;
82import javax.media.opengl.GLDrawableFactory;
83import javax.media.opengl.GLEventListener;
84import javax.media.opengl.GLException;
85import javax.media.opengl.GLProfile;
86import javax.media.opengl.GLRunnable;
7f7a23dd 87import javax.media.opengl.GLSharedContextSetter;
2cbab63b 88import javax.media.opengl.Threading;
8adc0478 89
8adc0478
SG
90import com.jogamp.common.GlueGenVersion;
91import com.jogamp.common.util.VersionUtil;
33eb58fc 92import com.jogamp.common.util.awt.AWTEDTExecutor;
4b5a0f65
SG
93import com.jogamp.common.util.locks.LockFactory;
94import com.jogamp.common.util.locks.RecursiveLock;
efa70cd3
SG
95import com.jogamp.nativewindow.awt.AWTGraphicsConfiguration;
96import com.jogamp.nativewindow.awt.AWTGraphicsDevice;
97import com.jogamp.nativewindow.awt.AWTGraphicsScreen;
c2ce31e1 98import com.jogamp.nativewindow.awt.AWTPrintLifecycle;
efa70cd3
SG
99import com.jogamp.nativewindow.awt.AWTWindowClosingProtocol;
100import com.jogamp.nativewindow.awt.JAWTWindow;
2cbab63b 101import com.jogamp.opengl.JoglVersion;
6ef3c22a 102import com.jogamp.opengl.util.GLDrawableUtil;
6ef3c22a 103import com.jogamp.opengl.util.TileRenderer;
8adc0478 104
2571ed0b 105import jogamp.nativewindow.SurfaceScaleUtils;
360b6716
SG
106import jogamp.opengl.Debug;
107import jogamp.opengl.GLContextImpl;
108import jogamp.opengl.GLDrawableHelper;
4dd44b98 109import jogamp.opengl.GLDrawableImpl;
4b5e7796 110import jogamp.opengl.awt.AWTTilePainter;
a959c53b
KR
111
112// FIXME: Subclasses need to call resetGLFunctionAvailability() on their
113// context whenever the displayChanged() function is called on our
114// GLEventListeners
115
116/** A heavyweight AWT component which provides OpenGL rendering
86c16495 117 support. This is the primary implementation of an AWT {@link GLDrawable};
a959c53b
KR
118 {@link GLJPanel} is provided for compatibility with Swing user
119 interfaces when adding a heavyweight doesn't work either because
86c16495
SG
120 of Z-ordering or LayoutManager problems.
121 *
7f7a23dd 122 * <h5><a name="offscreenlayer">Offscreen Layer Remarks</a></h5>
5e9c02bc 123 *
4dd44b98 124 * {@link OffscreenLayerOption#setShallUseOffscreenLayer(boolean) setShallUseOffscreenLayer(true)}
5e9c02bc 125 * maybe called to use an offscreen drawable (FBO or PBuffer) allowing
4dd44b98
SG
126 * the underlying JAWT mechanism to composite the image, if supported.
127 * <p>
128 * {@link OffscreenLayerOption#setShallUseOffscreenLayer(boolean) setShallUseOffscreenLayer(true)}
129 * is being called if {@link GLCapabilitiesImmutable#isOnscreen()} is <code>false</code>.
130 * </p>
5e9c02bc 131 *
7f7a23dd 132 * <h5><a name="java2dgl">Java2D OpenGL Remarks</a></h5>
86c16495
SG
133 *
134 * To avoid any conflicts with a potential Java2D OpenGL context,<br>
135 * you shall consider setting the following JVM properties:<br>
136 * <ul>
137 * <li><pre>sun.java2d.opengl=false</pre></li>
138 * <li><pre>sun.java2d.noddraw=true</pre></li>
139 * </ul>
140 * This is especially true in case you want to utilize a GLProfile other than
141 * {@link GLProfile#GL2}, eg. using {@link GLProfile#getMaxFixedFunc()}.<br>
142 * On the other hand, if you like to experiment with GLJPanel's utilization
143 * of Java2D's OpenGL pipeline, you have to set them to
144 * <ul>
145 * <li><pre>sun.java2d.opengl=true</pre></li>
146 * <li><pre>sun.java2d.noddraw=true</pre></li>
147 * </ul>
148 *
7f7a23dd 149 * <h5><a name="backgrounderase">Disable Background Erase</a></h5>
86c16495
SG
150 *
151 * GLCanvas tries to disable background erase for the AWT Canvas
152 * before native peer creation (X11) and after it (Windows), <br>
153 * utilizing the optional {@link java.awt.Toolkit} method <code>disableBeackgroundErase(java.awt.Canvas)</code>.<br>
154 * However if this does not give you the desired results, you may want to disable AWT background erase in general:
155 * <ul>
156 * <li><pre>sun.awt.noerasebackground=true</pre></li>
157 * </ul>
158 */
a959c53b 159
df85f0df 160@SuppressWarnings("serial")
2571ed0b
SG
161public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosingProtocol, OffscreenLayerOption,
162 AWTPrintLifecycle, GLSharedContextSetter, ScalableSurface {
a959c53b 163
b7c5a58f 164 private static final boolean DEBUG = Debug.debug("GLCanvas");
a959c53b 165
4b5a0f65 166 private final RecursiveLock lock = LockFactory.createRecursiveLock();
9b35c574 167 private final GLDrawableHelper helper = new GLDrawableHelper();
a959c53b 168 private AWTGraphicsConfiguration awtConfig;
4dd44b98 169 private volatile GLDrawableImpl drawable; // volatile: avoid locking for read-only access
5a5c2bc7 170 private volatile JAWTWindow jawtWindow; // the JAWTWindow presentation of this AWT Canvas, bound to the 'drawable' lifecycle
0943389a 171 private volatile GLContextImpl context; // volatile: avoid locking for read-only access
4b5a0f65 172 private volatile boolean sendReshape = false; // volatile: maybe written by EDT w/o locking
2571ed0b
SG
173 private volatile int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
174 final int[] reqPixelScale = new int[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
bd92af2b 175
16bb6386 176 // copy of the cstr args, mainly for recreation
7f7a23dd
SG
177 private final GLCapabilitiesImmutable capsReqUser;
178 private final GLCapabilitiesChooser chooser;
bd92af2b 179 private int additionalCtxCreationFlags = 0;
7f7a23dd 180 private final GraphicsDevice device;
8e0f3ad5 181 private boolean shallUseOffscreenLayer = false;
a959c53b 182
071bdd6c
SG
183 private volatile boolean isShowing;
184 private final HierarchyListener hierarchyListener = new HierarchyListener() {
185 @Override
186 public void hierarchyChanged(HierarchyEvent e) {
187 isShowing = GLCanvas.this.isShowing();
188 }
189 };
190
7f7a23dd 191 private final AWTWindowClosingProtocol awtWindowClosingProtocol =
2cbab63b 192 new AWTWindowClosingProtocol(this, new Runnable() {
bd92af2b 193 @Override
2cbab63b 194 public void run() {
3567e7e8 195 GLCanvas.this.destroyImpl( true );
2cbab63b 196 }
808a9a27 197 }, null);
2cbab63b 198
a959c53b
KR
199 /** Creates a new GLCanvas component with a default set of OpenGL
200 capabilities, using the default OpenGL capabilities selection
bd92af2b 201 mechanism, on the default screen device.
29cc5fa0
SG
202 * @throws GLException if no default profile is available for the default desktop device.
203 */
204 public GLCanvas() throws GLException {
a959c53b
KR
205 this(null);
206 }
207
208 /** Creates a new GLCanvas component with the requested set of
209 OpenGL capabilities, using the default OpenGL capabilities
bd92af2b 210 selection mechanism, on the default screen device.
29cc5fa0 211 * @throws GLException if no GLCapabilities are given and no default profile is available for the default desktop device.
de2a3010
SG
212 * @see GLCanvas#GLCanvas(javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesChooser, javax.media.opengl.GLContext, java.awt.GraphicsDevice)
213 */
29cc5fa0 214 public GLCanvas(GLCapabilitiesImmutable capsReqUser) throws GLException {
29e3b223 215 this(capsReqUser, null, null, null);
a959c53b
KR
216 }
217
de2a3010
SG
218 /** Creates a new GLCanvas component with the requested set of
219 OpenGL capabilities, using the default OpenGL capabilities
220 selection mechanism, on the default screen device.
221 * This constructor variant also supports using a shared GLContext.
222 *
29cc5fa0 223 * @throws GLException if no GLCapabilities are given and no default profile is available for the default desktop device.
de2a3010 224 * @see GLCanvas#GLCanvas(javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesChooser, javax.media.opengl.GLContext, java.awt.GraphicsDevice)
7f7a23dd
SG
225 * @deprecated Use {@link #GLCanvas(GLCapabilitiesImmutable)}
226 * and set shared GLContext via {@link #setSharedContext(GLContext)} or {@link #setSharedAutoDrawable(GLAutoDrawable)}.
de2a3010 227 */
bd92af2b
SG
228 public GLCanvas(GLCapabilitiesImmutable capsReqUser, GLContext shareWith)
229 throws GLException
29cc5fa0 230 {
de2a3010
SG
231 this(capsReqUser, null, shareWith, null);
232 }
233
a959c53b
KR
234 /** Creates a new GLCanvas component. The passed GLCapabilities
235 specifies the OpenGL capabilities for the component; if null, a
236 default set of capabilities is used. The GLCapabilitiesChooser
237 specifies the algorithm for selecting one of the available
238 GLCapabilities for the component; a DefaultGLCapabilitesChooser
7f7a23dd
SG
239 is used if null is passed for this argument.
240 The passed GraphicsDevice indicates the screen on
241 which to create the GLCanvas; the GLDrawableFactory uses the
242 default screen device of the local GraphicsEnvironment if null
243 is passed for this argument.
244 * @throws GLException if no GLCapabilities are given and no default profile is available for the default desktop device.
245 */
246 public GLCanvas(GLCapabilitiesImmutable capsReqUser,
247 GLCapabilitiesChooser chooser,
248 GraphicsDevice device)
249 throws GLException
250 {
251 this(capsReqUser, chooser, null, device);
252 }
253
254 /** Creates a new GLCanvas component. The passed GLCapabilities
255 specifies the OpenGL capabilities for the component; if null, a
256 default set of capabilities is used. The GLCapabilitiesChooser
257 specifies the algorithm for selecting one of the available
258 GLCapabilities for the component; a DefaultGLCapabilitesChooser
a959c53b
KR
259 is used if null is passed for this argument. The passed
260 GLContext specifies an OpenGL context with which to share
261 textures, display lists and other OpenGL state, and may be null
262 if sharing is not desired. See the note in the overview
263 documentation on <a
bcfaa149 264 href="../../../spec-overview.html#SHARING">context
a959c53b
KR
265 sharing</a>. The passed GraphicsDevice indicates the screen on
266 which to create the GLCanvas; the GLDrawableFactory uses the
267 default screen device of the local GraphicsEnvironment if null
bd92af2b 268 is passed for this argument.
29cc5fa0 269 * @throws GLException if no GLCapabilities are given and no default profile is available for the default desktop device.
7f7a23dd
SG
270 * @deprecated Use {@link #GLCanvas(GLCapabilitiesImmutable, GLCapabilitiesChooser, GraphicsDevice)}
271 * and set shared GLContext via {@link #setSharedContext(GLContext)} or {@link #setSharedAutoDrawable(GLAutoDrawable)}.
29cc5fa0 272 */
29e3b223 273 public GLCanvas(GLCapabilitiesImmutable capsReqUser,
a959c53b
KR
274 GLCapabilitiesChooser chooser,
275 GLContext shareWith,
bd92af2b
SG
276 GraphicsDevice device)
277 throws GLException
29cc5fa0 278 {
a959c53b 279 /*
96af6c9b
SG
280 * Determination of the native window is made in 'super.addNotify()',
281 * which creates the native peer using AWT's GraphicsConfiguration.
282 * GraphicsConfiguration is returned by this class overwritten
283 * 'getGraphicsConfiguration()', which returns our OpenGL compatible
284 * 'chosen' GraphicsConfiguration.
a959c53b
KR
285 */
286 super();
287
29e3b223 288 if(null==capsReqUser) {
4011e70e 289 capsReqUser = new GLCapabilities(GLProfile.getDefault(GLProfile.getDefaultDevice()));
29e3b223
SG
290 } else {
291 // don't allow the user to change data
96af6c9b 292 capsReqUser = (GLCapabilitiesImmutable) capsReqUser.cloneMutable();
a959c53b 293 }
4dd44b98
SG
294 if(!capsReqUser.isOnscreen()) {
295 setShallUseOffscreenLayer(true); // trigger offscreen layer - if supported
296 }
a959c53b 297
96af6c9b
SG
298 if(null==device) {
299 GraphicsConfiguration gc = super.getGraphicsConfiguration();
300 if(null!=gc) {
301 device = gc.getDevice();
302 }
303 }
304
16bb6386
SG
305 // instantiation will be issued in addNotify()
306 this.capsReqUser = capsReqUser;
a959c53b 307 this.chooser = chooser;
aa7cbaea
SG
308 if( null != shareWith ) {
309 helper.setSharedContext(null, shareWith);
310 }
16bb6386 311 this.device = device;
071bdd6c
SG
312
313 this.addHierarchyListener(hierarchyListener);
314 this.isShowing = isShowing();
a959c53b
KR
315 }
316
bd92af2b 317 @Override
7f7a23dd
SG
318 public final void setSharedContext(GLContext sharedContext) throws IllegalStateException {
319 helper.setSharedContext(this.context, sharedContext);
320 }
321
322 @Override
323 public final void setSharedAutoDrawable(GLAutoDrawable sharedAutoDrawable) throws IllegalStateException {
324 helper.setSharedAutoDrawable(this, sharedAutoDrawable);
325 }
326
327 @Override
20bf031d
SG
328 public final Object getUpstreamWidget() {
329 return this;
330 }
5e9c02bc 331
20bf031d 332 @Override
8e0f3ad5
SG
333 public void setShallUseOffscreenLayer(boolean v) {
334 shallUseOffscreenLayer = v;
335 }
336
bd92af2b 337 @Override
8e0f3ad5 338 public final boolean getShallUseOffscreenLayer() {
bd92af2b 339 return shallUseOffscreenLayer;
8e0f3ad5
SG
340 }
341
bd92af2b 342 @Override
8e0f3ad5 343 public final boolean isOffscreenLayerSurfaceEnabled() {
5a5c2bc7
SG
344 final JAWTWindow _jawtWindow = jawtWindow;
345 if(null != _jawtWindow) {
346 return _jawtWindow.isOffscreenLayerSurfaceEnabled();
8e0f3ad5
SG
347 }
348 return false;
349 }
350
bd92af2b 351
a959c53b
KR
352 /**
353 * Overridden to choose a GraphicsConfiguration on a parent container's
354 * GraphicsDevice because both devices
355 */
bd92af2b 356 @Override
a959c53b
KR
357 public GraphicsConfiguration getGraphicsConfiguration() {
358 /*
359 * Workaround for problems with Xinerama and java.awt.Component.checkGD
360 * when adding to a container on a different graphics device than the
361 * one that this Canvas is associated with.
bd92af2b 362 *
a959c53b
KR
363 * GC will be null unless:
364 * - A native peer has assigned it. This means we have a native
365 * peer, and are already comitted to a graphics configuration.
366 * - This canvas has been added to a component hierarchy and has
367 * an ancestor with a non-null GC, but the native peer has not
368 * yet been created. This means we can still choose the GC on
369 * all platforms since the peer hasn't been created.
370 */
371 final GraphicsConfiguration gc = super.getGraphicsConfiguration();
5e9c02bc 372
3567e7e8
SG
373 if( Beans.isDesignTime() ) {
374 return gc;
375 }
5e9c02bc 376
a959c53b
KR
377 /*
378 * chosen is only non-null on platforms where the GLDrawableFactory
379 * returns a non-null GraphicsConfiguration (in the GLCanvas
380 * constructor).
bd92af2b 381 *
a959c53b
KR
382 * if gc is from this Canvas' native peer then it should equal chosen,
383 * otherwise it is from an ancestor component that this Canvas is being
384 * added to, and we go into this block.
385 */
f9a00b91 386 GraphicsConfiguration chosen = null != awtConfig ? awtConfig.getAWTGraphicsConfiguration() : null;
16bb6386 387
a959c53b
KR
388 if (gc != null && chosen != null && !chosen.equals(gc)) {
389 /*
390 * Check for compatibility with gc. If they differ by only the
391 * device then return a new GCconfig with the super-class' GDevice
392 * (and presumably the same visual ID in Xinerama).
bd92af2b 393 *
a959c53b
KR
394 */
395 if (!chosen.getDevice().getIDstring().equals(gc.getDevice().getIDstring())) {
396 /*
397 * Here we select a GraphicsConfiguration on the alternate
398 * device that is presumably identical to the chosen
399 * configuration, but on the other device.
bd92af2b 400 *
a959c53b
KR
401 * Should really check to ensure that we select a configuration
402 * with the same X visual ID for Xinerama screens, otherwise the
403 * GLDrawable may have the wrong visual ID (I don't think this
404 * ever gets updated). May need to add a method to
405 * X11GLDrawableFactory to do this in a platform specific
406 * manner.
bd92af2b 407 *
a959c53b
KR
408 * However, on platforms where we can actually get into this
409 * block, both devices should have the same visual list, and the
410 * same configuration should be selected here.
411 */
29e3b223
SG
412 AWTGraphicsConfiguration config = chooseGraphicsConfiguration( (GLCapabilitiesImmutable)awtConfig.getChosenCapabilities(),
413 (GLCapabilitiesImmutable)awtConfig.getRequestedCapabilities(),
414 chooser, gc.getDevice());
bafd9b99 415 final GraphicsConfiguration compatible = (null!=config)?config.getAWTGraphicsConfiguration():null;
a959c53b
KR
416 boolean equalCaps = config.getChosenCapabilities().equals(awtConfig.getChosenCapabilities());
417 if(DEBUG) {
b7c5a58f 418 System.err.println(getThreadName()+": Info:");
33249b6e
SG
419 System.err.println("Created Config (n): HAVE GC "+chosen);
420 System.err.println("Created Config (n): THIS GC "+gc);
421 System.err.println("Created Config (n): Choosen GC "+compatible);
422 System.err.println("Created Config (n): HAVE CF "+awtConfig);
423 System.err.println("Created Config (n): Choosen CF "+config);
424 System.err.println("Created Config (n): EQUALS CAPS "+equalCaps);
9b5cee85 425 // Thread.dumpStack();
a959c53b
KR
426 }
427
428 if (compatible != null) {
429 /*
430 * Save the new GC for equals test above, and to return to
431 * any outside callers of this method.
432 */
433 chosen = compatible;
434
a959c53b 435 if( !equalCaps && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED ) {
3567e7e8
SG
436 // complete destruction!
437 destroyImpl( true );
438 // recreation!
439 awtConfig = config;
7f7a23dd 440 createJAWTDrawableAndContext();
3567e7e8
SG
441 validateGLDrawable();
442 } else {
443 awtConfig = config;
a959c53b
KR
444 }
445 }
446 }
447
448 /*
449 * If a compatible GC was not found in the block above, this will
450 * return the GC that was selected in the constructor (and might
451 * cause an exception in Component.checkGD when adding to a
452 * container, but in this case that would be the desired behavior).
bd92af2b 453 *
a959c53b
KR
454 */
455 return chosen;
456 } else if (gc == null) {
457 /*
458 * The GC is null, which means we have no native peer, and are not
459 * part of a (realized) component hierarchy. So we return the
460 * desired visual that was selected in the constructor (possibly
461 * null).
462 */
463 return chosen;
464 }
465
466 /*
467 * Otherwise we have not explicitly selected a GC in the constructor, so
468 * just return what Canvas would have.
469 */
470 return gc;
471 }
bd92af2b
SG
472
473 @Override
eed8508a 474 public GLContext createContext(final GLContext shareWith) {
4b5a0f65
SG
475 final RecursiveLock _lock = lock;
476 _lock.lock();
477 try {
478 if(drawable != null) {
479 final GLContext _ctx = drawable.createContext(shareWith);
480 _ctx.setContextCreationFlags(additionalCtxCreationFlags);
481 return _ctx;
482 }
483 return null;
484 } finally {
485 _lock.unlock();
eed8508a 486 }
a959c53b 487 }
5e9c02bc 488
c225285e
SG
489 private final void setRealizedImpl(boolean realized) {
490 final RecursiveLock _lock = lock;
491 _lock.lock();
5e9c02bc 492 try {
c225285e 493 final GLDrawable _drawable = drawable;
dd705f1e 494 if( null == _drawable || realized == _drawable.isRealized() ||
f9a00b91 495 realized && ( 0 >= _drawable.getSurfaceWidth() || 0 >= _drawable.getSurfaceHeight() ) ) {
dd705f1e 496 return;
c225285e
SG
497 }
498 _drawable.setRealized(realized);
499 if( realized && _drawable.isRealized() ) {
500 sendReshape=true; // ensure a reshape is being send ..
501 }
502 } finally {
503 _lock.unlock();
504 }
5e9c02bc 505 }
f1ae8ddb
HH
506 private final Runnable realizeOnEDTAction = new Runnable() {
507 @Override
508 public void run() { setRealizedImpl(true); }
509 };
510 private final Runnable unrealizeOnEDTAction = new Runnable() {
511 @Override
512 public void run() { setRealizedImpl(false); }
513 };
5e9c02bc 514
bd92af2b 515 @Override
c225285e
SG
516 public final void setRealized(boolean realized) {
517 // Make sure drawable realization happens on AWT-EDT and only there. Consider the AWTTree lock!
518 AWTEDTExecutor.singleton.invoke(getTreeLock(), false /* allowOnNonEDT */, true /* wait */, realized ? realizeOnEDTAction : unrealizeOnEDTAction);
a959c53b
KR
519 }
520
bd92af2b 521 @Override
811bd23e 522 public boolean isRealized() {
4b5a0f65
SG
523 final GLDrawable _drawable = drawable;
524 return ( null != _drawable ) ? _drawable.isRealized() : false;
811bd23e
SG
525 }
526
bd92af2b 527 @Override
935523a8 528 public WindowClosingMode getDefaultCloseOperation() {
2cbab63b
SG
529 return awtWindowClosingProtocol.getDefaultCloseOperation();
530 }
531
bd92af2b 532 @Override
935523a8 533 public WindowClosingMode setDefaultCloseOperation(WindowClosingMode op) {
2cbab63b
SG
534 return awtWindowClosingProtocol.setDefaultCloseOperation(op);
535 }
a959c53b 536
bd92af2b 537 @Override
a959c53b 538 public void display() {
a3cb6bb1
SG
539 if( !validateGLDrawable() ) {
540 if(DEBUG) {
541 System.err.println(getThreadName()+": Info: GLCanvas display - skipped GL render, drawable not valid yet");
542 }
543 return; // not yet available ..
544 }
071bdd6c 545 if( isShowing && !printActive ) {
1cee0f1a
SG
546 Threading.invoke(true, displayOnEDTAction, getTreeLock());
547 }
a959c53b
KR
548 }
549
a959c53b 550 /**
bd92af2b
SG
551 * {@inheritDoc}
552 *
553 * <p>
3567e7e8
SG
554 * This impl. only destroys all GL related resources.
555 * </p>
556 * <p>
557 * This impl. does not remove the GLCanvas from it's parent AWT container
558 * so this class's {@link #removeNotify()} AWT override won't get called.
559 * To do so, remove this component from it's parent AWT container.
bd92af2b 560 * </p>
a959c53b 561 */
bd92af2b 562 @Override
a959c53b 563 public void destroy() {
3567e7e8
SG
564 destroyImpl( false );
565 }
5e9c02bc 566
3567e7e8
SG
567 protected void destroyImpl(boolean destroyJAWTWindowAndAWTDevice) {
568 Threading.invoke(true, destroyOnEDTAction, getTreeLock());
569 if( destroyJAWTWindowAndAWTDevice ) {
570 AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, disposeJAWTWindowAndAWTDeviceOnEDT);
571 }
a959c53b
KR
572 }
573
574 /** Overridden to cause OpenGL rendering to be performed during
575 repaint cycles. Subclasses which override this method must call
576 super.paint() in their paint() method in order to function
4dd44b98
SG
577 properly.
578 */
579 @Override
a959c53b 580 public void paint(Graphics g) {
3567e7e8 581 if( Beans.isDesignTime() ) {
a959c53b
KR
582 // Make GLCanvas behave better in NetBeans GUI builder
583 g.setColor(Color.BLACK);
584 g.fillRect(0, 0, getWidth(), getHeight());
585 FontMetrics fm = g.getFontMetrics();
586 String name = getName();
587 if (name == null) {
588 name = getClass().getName();
589 int idx = name.lastIndexOf('.');
590 if (idx >= 0) {
591 name = name.substring(idx + 1);
592 }
593 }
594 Rectangle2D bounds = fm.getStringBounds(name, g);
595 g.setColor(Color.WHITE);
596 g.drawString(name,
597 (int) ((getWidth() - bounds.getWidth()) / 2),
598 (int) ((getHeight() + bounds.getHeight()) / 2));
3567e7e8 599 } else if( !this.helper.isAnimatorAnimatingOnOtherThread() ) {
969e4276
SG
600 display();
601 }
a959c53b
KR
602 }
603
604 /** Overridden to track when this component is added to a container.
605 Subclasses which override this method must call
606 super.addNotify() in their addNotify() method in order to
607 function properly. <P>
608
609 <B>Overrides:</B>
610 <DL><DD><CODE>addNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
df85f0df 611 @SuppressWarnings("deprecation")
10c696f7 612 @Override
a959c53b 613 public void addNotify() {
4b5a0f65
SG
614 final RecursiveLock _lock = lock;
615 _lock.lock();
5e9c02bc 616 try {
3567e7e8 617 final boolean isBeansDesignTime = Beans.isDesignTime();
5e9c02bc 618
4b5a0f65 619 if(DEBUG) {
3567e7e8 620 System.err.println(getThreadName()+": Info: addNotify - start, bounds: "+this.getBounds()+", isBeansDesignTime "+isBeansDesignTime);
9b5cee85 621 // Thread.dumpStack();
4b5a0f65 622 }
5e9c02bc 623
3567e7e8
SG
624 if( isBeansDesignTime ) {
625 super.addNotify();
626 } else {
627 /**
628 * 'super.addNotify()' determines the GraphicsConfiguration,
629 * while calling this class's overriden 'getGraphicsConfiguration()' method
630 * after which it creates the native peer.
631 * Hence we have to set the 'awtConfig' before since it's GraphicsConfiguration
632 * is being used in getGraphicsConfiguration().
633 * This code order also allows recreation, ie re-adding the GLCanvas.
634 */
635 awtConfig = chooseGraphicsConfiguration(capsReqUser, capsReqUser, chooser, device);
636 if(null==awtConfig) {
637 throw new GLException("Error: NULL AWTGraphicsConfiguration");
638 }
5e9c02bc 639
3567e7e8
SG
640 // before native peer is valid: X11
641 disableBackgroundErase();
5e9c02bc 642
3567e7e8
SG
643 // issues getGraphicsConfiguration() and creates the native peer
644 super.addNotify();
5e9c02bc 645
3567e7e8
SG
646 // after native peer is valid: Windows
647 disableBackgroundErase();
5e9c02bc 648
7f7a23dd 649 createJAWTDrawableAndContext();
5e9c02bc 650
3567e7e8
SG
651 // init drawable by paint/display makes the init sequence more equal
652 // for all launch flavors (applet/javaws/..)
5e9c02bc 653 // validateGLDrawable();
4b5a0f65 654 }
808a9a27
SG
655 awtWindowClosingProtocol.addClosingListener();
656
4b5a0f65
SG
657 if(DEBUG) {
658 System.err.println(getThreadName()+": Info: addNotify - end: peer: "+getPeer());
659 }
660 } finally {
661 _lock.unlock();
7e606ef3 662 }
a959c53b
KR
663 }
664
2571ed0b
SG
665 @Override
666 public final void setSurfaceScale(final int[] pixelScale) {
667 SurfaceScaleUtils.validateReqPixelScale(reqPixelScale, pixelScale, DEBUG ? getClass().getSimpleName() : null);
668 if( isRealized() ) {
669 final ScalableSurface ns = jawtWindow;
670 if( null != ns ) {
671 ns.setSurfaceScale(reqPixelScale);
672 final int hadPixelScaleX = hasPixelScale[0];
673 final int hadPixelScaleY = hasPixelScale[1];
674 ns.getSurfaceScale(hasPixelScale);
675 if( hadPixelScaleX != hasPixelScale[0] || hadPixelScaleY != hasPixelScale[1] ) {
676 reshapeImpl(getWidth(), getHeight());
677 display();
678 }
679 }
680 }
681 }
682
683 @Override
684 public final int[] getSurfaceScale(final int[] result) {
685 final ScalableSurface ns = jawtWindow;
686 if( null != ns ) {
687 return ns.getSurfaceScale(result);
688 } else {
689 System.arraycopy(reqPixelScale, 0, result, 0, 2);
690 return result;
691 }
692 }
693
7f7a23dd 694 private void createJAWTDrawableAndContext() {
3567e7e8 695 if ( !Beans.isDesignTime() ) {
7f7a23dd
SG
696 jawtWindow = (JAWTWindow) NativeWindowFactory.getNativeWindow(this, awtConfig);
697 jawtWindow.setShallUseOffscreenLayer(shallUseOffscreenLayer);
2571ed0b 698 jawtWindow.setSurfaceScale(reqPixelScale);
3567e7e8
SG
699 jawtWindow.lockSurface();
700 try {
701 drawable = (GLDrawableImpl) GLDrawableFactory.getFactory(capsReqUser.getGLProfile()).createGLDrawable(jawtWindow);
7f7a23dd 702 createContextImpl(drawable);
2571ed0b 703 jawtWindow.getSurfaceScale(hasPixelScale);
3567e7e8
SG
704 } finally {
705 jawtWindow.unlockSurface();
706 }
8e0f3ad5 707 }
5e9c02bc 708 }
7f7a23dd
SG
709 private boolean createContextImpl(final GLDrawable drawable) {
710 final GLContext[] shareWith = { null };
711 if( !helper.isSharedGLContextPending(shareWith) ) {
712 context = (GLContextImpl) drawable.createContext(shareWith[0]);
713 context.setContextCreationFlags(additionalCtxCreationFlags);
714 if(DEBUG) {
715 System.err.println(getThreadName()+": Context created: has shared "+(null != shareWith[0]));
716 }
717 return true;
718 } else {
719 if(DEBUG) {
720 System.err.println(getThreadName()+": Context !created: pending share");
721 }
722 return false;
723 }
724 }
bd92af2b 725
86c16495 726 private boolean validateGLDrawable() {
de538efc 727 if( Beans.isDesignTime() || !isDisplayable() ) {
c225285e
SG
728 return false; // early out!
729 }
730 final GLDrawable _drawable = drawable;
731 if ( null != _drawable ) {
7f7a23dd
SG
732 boolean res = _drawable.isRealized();
733 if( !res ) {
734 // re-try drawable creation
f9a00b91 735 if( 0 >= _drawable.getSurfaceWidth() || 0 >= _drawable.getSurfaceHeight() ) {
7f7a23dd
SG
736 return false; // early out!
737 }
738 setRealized(true);
739 res = _drawable.isRealized();
740 if(DEBUG) {
741 System.err.println(getThreadName()+": Realized Drawable: isRealized "+res+", "+_drawable.toString());
742 // Thread.dumpStack();
743 }
c225285e 744 }
7f7a23dd
SG
745 if( res && null == context ) {
746 // re-try context creation
747 res = createContextImpl(_drawable); // pending creation.
c225285e
SG
748 }
749 return res;
750 }
751 return false;
752 }
5e9c02bc 753
7e606ef3 754 /** <p>Overridden to track when this component is removed from a
a959c53b
KR
755 container. Subclasses which override this method must call
756 super.removeNotify() in their removeNotify() method in order to
7e606ef3
SG
757 function properly. </p>
758 <p>User shall not call this method outside of EDT, read the AWT/Swing specs
759 about this.</p>
a959c53b
KR
760 <B>Overrides:</B>
761 <DL><DD><CODE>removeNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
df85f0df 762 @SuppressWarnings("deprecation")
10c696f7 763 @Override
a959c53b
KR
764 public void removeNotify() {
765 if(DEBUG) {
b7c5a58f 766 System.err.println(getThreadName()+": Info: removeNotify - start");
9b5cee85 767 // Thread.dumpStack();
a959c53b
KR
768 }
769
2cbab63b
SG
770 awtWindowClosingProtocol.removeClosingListener();
771
3567e7e8 772 if( Beans.isDesignTime() ) {
a959c53b
KR
773 super.removeNotify();
774 } else {
775 try {
3567e7e8 776 destroyImpl( true );
a959c53b 777 } finally {
a959c53b
KR
778 super.removeNotify();
779 }
780 }
781 if(DEBUG) {
b7c5a58f 782 System.err.println(getThreadName()+": Info: removeNotify - end, peer: "+getPeer());
a959c53b
KR
783 }
784 }
785
786 /** Overridden to cause {@link GLDrawableHelper#reshape} to be
787 called on all registered {@link GLEventListener}s. Subclasses
788 which override this method must call super.reshape() in
789 their reshape() method in order to function properly. <P>
790
791 <B>Overrides:</B>
792 <DL><DD><CODE>reshape</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
df85f0df 793 @SuppressWarnings("deprecation")
10c696f7 794 @Override
a959c53b 795 public void reshape(int x, int y, int width, int height) {
4dd44b98
SG
796 synchronized (getTreeLock()) { // super.reshape(..) claims tree lock, so we do extend it's lock over reshape
797 super.reshape(x, y, width, height);
2571ed0b
SG
798 reshapeImpl(width, height);
799 }
800 }
5e9c02bc 801
2571ed0b
SG
802 private void reshapeImpl(final int width, final int height) {
803 final int scaledWidth = width * hasPixelScale[0];
804 final int scaledHeight = height * hasPixelScale[1];
f9a00b91 805
2571ed0b
SG
806 if(DEBUG) {
807 final NativeSurface ns = getNativeSurface();
808 final long nsH = null != ns ? ns.getSurfaceHandle() : 0;
809 System.err.println(getThreadName()+": GLCanvas.reshape.0 "+this.getName()+" resize"+(printActive?"WithinPrint":"")+
810 " [ this "+getWidth()+"x"+getHeight()+", pixelScale "+getPixelScaleStr()+
811 "] -> "+(printActive?"[skipped] ":"") + width+"x"+height+" * "+getPixelScaleStr()+" -> "+scaledWidth+"x"+scaledHeight+
812 " - surfaceHandle 0x"+Long.toHexString(nsH));
813 // Thread.dumpStack();
814 }
815 if( validateGLDrawable() && !printActive ) {
816 final GLDrawableImpl _drawable = drawable;
817 if( ! _drawable.getChosenGLCapabilities().isOnscreen() ) {
818 final RecursiveLock _lock = lock;
819 _lock.lock();
820 try {
821 final GLDrawableImpl _drawableNew = GLDrawableHelper.resizeOffscreenDrawable(_drawable, context, scaledWidth, scaledHeight);
822 if(_drawable != _drawableNew) {
823 // write back
824 drawable = _drawableNew;
4dd44b98 825 }
2571ed0b
SG
826 } finally {
827 _lock.unlock();
4dd44b98 828 }
4dd44b98 829 }
2571ed0b 830 sendReshape = true; // async if display() doesn't get called below, but avoiding deadlock
8e0f3ad5 831 }
a959c53b
KR
832 }
833
bd92af2b 834 /**
10c696f7
SG
835 * Overridden from Canvas to prevent the AWT's clearing of the
836 * canvas from interfering with the OpenGL rendering.
837 */
4dd44b98 838 @Override
a959c53b
KR
839 public void update(Graphics g) {
840 paint(g);
841 }
bd92af2b 842
6ef3c22a 843 private volatile boolean printActive = false;
5e9c02bc 844 private GLAnimatorControl printAnimator = null;
76048cd7 845 private GLAutoDrawable printGLAD = null;
4b5e7796 846 private AWTTilePainter printAWTTiles = null;
5e9c02bc 847
95d49687 848 @Override
a05b87a3 849 public void setupPrint(double scaleMatX, double scaleMatY, int numSamples, int tileWidth, int tileHeight) {
5e9c02bc 850 printActive = true;
76048cd7
SG
851 final int componentCount = isOpaque() ? 3 : 4;
852 final TileRenderer printRenderer = new TileRenderer();
a05b87a3 853 printAWTTiles = new AWTTilePainter(printRenderer, componentCount, scaleMatX, scaleMatY, numSamples, tileWidth, tileHeight, DEBUG);
de538efc
SG
854 AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, setupPrintOnEDT);
855 }
856 private final Runnable setupPrintOnEDT = new Runnable() {
857 @Override
858 public void run() {
988da6f3
SG
859 if( !validateGLDrawable() ) {
860 if(DEBUG) {
861 System.err.println(getThreadName()+": Info: GLCanvas setupPrint - skipped GL render, drawable not valid yet");
862 }
5e9c02bc 863 printActive = false;
988da6f3
SG
864 return; // not yet available ..
865 }
083e430a 866 if( !isVisible() ) {
988da6f3 867 if(DEBUG) {
083e430a 868 System.err.println(getThreadName()+": Info: GLCanvas setupPrint - skipped GL render, canvas not visible");
988da6f3 869 }
5e9c02bc 870 printActive = false;
988da6f3
SG
871 return; // not yet available ..
872 }
de538efc
SG
873 sendReshape = false; // clear reshape flag
874 printAnimator = helper.getAnimator();
875 if( null != printAnimator ) {
876 printAnimator.remove(GLCanvas.this);
9450900c 877 }
5e9c02bc 878 printGLAD = GLCanvas.this; // _not_ default, shall be replaced by offscreen GLAD
de538efc 879 final GLCapabilities caps = (GLCapabilities)getChosenGLCapabilities().cloneMutable();
a05b87a3
SG
880 final int printNumSamples = printAWTTiles.getNumSamples(caps);
881 GLDrawable printDrawable = printGLAD.getDelegatedDrawable();
882 final boolean reqNewGLADSamples = printNumSamples != caps.getNumSamples();
f9a00b91
SG
883 final boolean reqNewGLADSize = printAWTTiles.customTileWidth != -1 && printAWTTiles.customTileWidth != printDrawable.getSurfaceWidth() ||
884 printAWTTiles.customTileHeight != -1 && printAWTTiles.customTileHeight != printDrawable.getSurfaceHeight();
77b0adbd
SG
885 final boolean reqNewGLADOnscrn = caps.isOnscreen();
886 // It is desired to use a new offscreen GLAD, however Bug 830 forbids this for AA onscreen context.
887 // Bug 830: swapGLContextAndAllGLEventListener and onscreen MSAA w/ NV/GLX
888 final boolean reqNewGLAD = !caps.getSampleBuffers() && ( reqNewGLADOnscrn || reqNewGLADSamples || reqNewGLADSize );
988da6f3 889 if( DEBUG ) {
77b0adbd 890 System.err.println("AWT print.setup: reqNewGLAD "+reqNewGLAD+"[ onscreen "+reqNewGLADOnscrn+", samples "+reqNewGLADSamples+", size "+reqNewGLADSize+"], "+
f9a00b91 891 ", drawableSize "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+
a05b87a3
SG
892 ", customTileSize "+printAWTTiles.customTileWidth+"x"+printAWTTiles.customTileHeight+
893 ", scaleMat "+printAWTTiles.scaleMatX+" x "+printAWTTiles.scaleMatY+
894 ", numSamples "+printAWTTiles.customNumSamples+" -> "+printNumSamples+", printAnimator "+printAnimator);
988da6f3 895 }
77b0adbd 896 if( reqNewGLAD ) {
76048cd7
SG
897 caps.setDoubleBuffered(false);
898 caps.setOnscreen(false);
c2ce31e1
SG
899 if( printNumSamples != caps.getNumSamples() ) {
900 caps.setSampleBuffers(0 < printNumSamples);
901 caps.setNumSamples(printNumSamples);
9b5cee85 902 }
76048cd7 903 final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile());
5e9c02bc
HH
904 printGLAD = factory.createOffscreenAutoDrawable(null, caps, null,
905 printAWTTiles.customTileWidth != -1 ? printAWTTiles.customTileWidth : DEFAULT_PRINT_TILE_SIZE,
7f7a23dd 906 printAWTTiles.customTileHeight != -1 ? printAWTTiles.customTileHeight : DEFAULT_PRINT_TILE_SIZE);
76048cd7 907 GLDrawableUtil.swapGLContextAndAllGLEventListener(GLCanvas.this, printGLAD);
a05b87a3 908 printDrawable = printGLAD.getDelegatedDrawable();
9b5cee85 909 }
f8c2a901 910 printAWTTiles.setGLOrientation(printGLAD.isGLOriented(), printGLAD.isGLOriented());
f9a00b91 911 printAWTTiles.renderer.setTileSize(printDrawable.getSurfaceWidth(), printDrawable.getSurfaceHeight(), 0);
4ef53cf2 912 printAWTTiles.renderer.attachAutoDrawable(printGLAD);
4b5e7796
SG
913 if( DEBUG ) {
914 System.err.println("AWT print.setup "+printAWTTiles);
c2ce31e1 915 System.err.println("AWT print.setup AA "+printNumSamples+", "+caps);
f9a00b91
SG
916 System.err.println("AWT print.setup printGLAD: "+printGLAD.getSurfaceWidth()+"x"+printGLAD.getSurfaceHeight()+", "+printGLAD);
917 System.err.println("AWT print.setup printDraw: "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+", "+printDrawable);
4b5e7796 918 }
de538efc
SG
919 }
920 };
5e9c02bc 921
95d49687 922 @Override
604434f8 923 public void releasePrint() {
6ef3c22a
SG
924 if( !printActive || null == printGLAD ) {
925 throw new IllegalStateException("setupPrint() not called");
926 }
b780eff4 927 sendReshape = false; // clear reshape flag
de538efc 928 AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, releasePrintOnEDT);
604434f8 929 }
de538efc
SG
930 private final Runnable releasePrintOnEDT = new Runnable() {
931 @Override
932 public void run() {
4b5e7796
SG
933 if( DEBUG ) {
934 System.err.println("AWT print.release "+printAWTTiles);
935 }
936 printAWTTiles.dispose();
937 printAWTTiles= null;
76048cd7
SG
938 if( printGLAD != GLCanvas.this ) {
939 GLDrawableUtil.swapGLContextAndAllGLEventListener(printGLAD, GLCanvas.this);
940 printGLAD.destroy();
941 }
4b5e7796 942 printGLAD = null;
de538efc
SG
943 if( null != printAnimator ) {
944 printAnimator.add(GLCanvas.this);
4b5e7796 945 printAnimator = null;
de538efc 946 }
fe284b51 947 sendReshape = true; // trigger reshape, i.e. gl-viewport and -listener - this component might got resized!
de538efc 948 printActive = false;
fe284b51 949 display();
de538efc
SG
950 }
951 };
5e9c02bc 952
604434f8
SG
953 @Override
954 public void print(Graphics graphics) {
6ef3c22a
SG
955 if( !printActive || null == printGLAD ) {
956 throw new IllegalStateException("setupPrint() not called");
957 }
b780eff4
SG
958 if(DEBUG && !EventQueue.isDispatchThread()) {
959 System.err.println(getThreadName()+": Warning: GLCanvas print - not called from AWT-EDT");
960 // we cannot dispatch print on AWT-EDT due to printing internal locking ..
961 }
6ef3c22a 962 sendReshape = false; // clear reshape flag
5e9c02bc 963
76048cd7 964 final Graphics2D g2d = (Graphics2D)graphics;
76048cd7 965 try {
8a4a64e1 966 printAWTTiles.setupGraphics2DAndClipBounds(g2d, getWidth(), getHeight());
2634ce35
SG
967 final TileRenderer tileRenderer = printAWTTiles.renderer;
968 if( DEBUG ) {
969 System.err.println("AWT print.0: "+tileRenderer);
970 }
971 if( !tileRenderer.eot() ) {
972 try {
973 do {
974 if( printGLAD != GLCanvas.this ) {
975 tileRenderer.display();
976 } else {
977 Threading.invoke(true, displayOnEDTAction, getTreeLock());
978 }
979 } while ( !tileRenderer.eot() );
980 if( DEBUG ) {
981 System.err.println("AWT print.1: "+printAWTTiles);
8a4a64e1 982 }
2634ce35
SG
983 } finally {
984 tileRenderer.reset();
985 printAWTTiles.resetGraphics2D();
986 }
8a4a64e1
SG
987 }
988 } catch (NoninvertibleTransformException nte) {
989 System.err.println("Catched: Inversion failed of: "+g2d.getTransform());
990 nte.printStackTrace();
6ef3c22a 991 }
4b5e7796 992 if( DEBUG ) {
76048cd7 993 System.err.println("AWT print.X: "+printAWTTiles);
4b5e7796 994 }
b780eff4 995 }
5e9c02bc 996
bd92af2b 997 @Override
a959c53b 998 public void addGLEventListener(GLEventListener listener) {
9b35c574 999 helper.addGLEventListener(listener);
a959c53b
KR
1000 }
1001
bd92af2b 1002 @Override
9b35c574
SG
1003 public void addGLEventListener(int index, GLEventListener listener) throws IndexOutOfBoundsException {
1004 helper.addGLEventListener(index, listener);
0d24458c
SG
1005 }
1006
bd92af2b 1007 @Override
c002e04f
SG
1008 public int getGLEventListenerCount() {
1009 return helper.getGLEventListenerCount();
a959c53b
KR
1010 }
1011
bd92af2b 1012 @Override
c002e04f
SG
1013 public GLEventListener getGLEventListener(int index) throws IndexOutOfBoundsException {
1014 return helper.getGLEventListener(index);
1015 }
1016
1017 @Override
97f4ef27
SG
1018 public boolean areAllGLEventListenerInitialized() {
1019 return helper.areAllGLEventListenerInitialized();
1020 }
1021
1022 @Override
c002e04f
SG
1023 public boolean getGLEventListenerInitState(GLEventListener listener) {
1024 return helper.getGLEventListenerInitState(listener);
1025 }
1026
1027 @Override
1028 public void setGLEventListenerInitState(GLEventListener listener, boolean initialized) {
1029 helper.setGLEventListenerInitState(listener, initialized);
9b35c574 1030 }
5e9c02bc 1031
9b35c574 1032 @Override
c002e04f
SG
1033 public GLEventListener disposeGLEventListener(GLEventListener listener, boolean remove) {
1034 final DisposeGLEventListenerAction r = new DisposeGLEventListenerAction(listener, remove);
1035 Threading.invoke(true, r, getTreeLock());
1036 return r.listener;
1037 }
5e9c02bc 1038
c002e04f
SG
1039 @Override
1040 public GLEventListener removeGLEventListener(GLEventListener listener) {
1041 return helper.removeGLEventListener(listener);
1042 }
1043
1044 @Override
34fffab0 1045 public void setAnimator(GLAnimatorControl animatorControl) {
9b35c574 1046 helper.setAnimator(animatorControl);
969e4276
SG
1047 }
1048
bd92af2b 1049 @Override
34fffab0 1050 public GLAnimatorControl getAnimator() {
9b35c574 1051 return helper.getAnimator();
969e4276
SG
1052 }
1053
bd92af2b 1054 @Override
224fab1b
SG
1055 public final Thread setExclusiveContextThread(Thread t) throws GLException {
1056 return helper.setExclusiveContextThread(t, context);
1057 }
1058
1059 @Override
1060 public final Thread getExclusiveContextThread() {
1061 return helper.getExclusiveContextThread();
1062 }
1063
1064 @Override
9b35c574
SG
1065 public boolean invoke(boolean wait, GLRunnable glRunnable) {
1066 return helper.invoke(this, wait, glRunnable);
0d24458c
SG
1067 }
1068
bd92af2b 1069 @Override
8c78f80f
SG
1070 public boolean invoke(final boolean wait, final List<GLRunnable> glRunnables) {
1071 return helper.invoke(this, wait, glRunnables);
c002e04f 1072 }
5e9c02bc 1073
c002e04f 1074 @Override
c225285e 1075 public GLContext setContext(GLContext newCtx, boolean destroyPrevCtx) {
4b5a0f65
SG
1076 final RecursiveLock _lock = lock;
1077 _lock.lock();
1078 try {
1079 final GLContext oldCtx = context;
c225285e 1080 GLDrawableHelper.switchContext(drawable, oldCtx, destroyPrevCtx, newCtx, additionalCtxCreationFlags);
4b5a0f65 1081 context=(GLContextImpl)newCtx;
4b5a0f65
SG
1082 return oldCtx;
1083 } finally {
1084 _lock.unlock();
eed8508a 1085 }
a959c53b
KR
1086 }
1087
bd92af2b 1088 @Override
4dd44b98
SG
1089 public final GLDrawable getDelegatedDrawable() {
1090 return drawable;
1091 }
5e9c02bc 1092
4dd44b98 1093 @Override
a959c53b
KR
1094 public GLContext getContext() {
1095 return context;
1096 }
1097
bd92af2b 1098 @Override
a959c53b 1099 public GL getGL() {
3567e7e8 1100 if( Beans.isDesignTime() ) {
a959c53b
KR
1101 return null;
1102 }
4b5a0f65
SG
1103 final GLContext _context = context;
1104 return (_context == null) ? null : _context.getGL();
a959c53b
KR
1105 }
1106
bd92af2b 1107 @Override
4e0a5af0 1108 public GL setGL(GL gl) {
4b5a0f65
SG
1109 final GLContext _context = context;
1110 if (_context != null) {
1111 _context.setGL(gl);
4e0a5af0 1112 return gl;
a959c53b 1113 }
4e0a5af0 1114 return null;
a959c53b
KR
1115 }
1116
1117
bd92af2b 1118 @Override
a959c53b 1119 public void setAutoSwapBufferMode(boolean onOrOff) {
9b35c574 1120 helper.setAutoSwapBufferMode(onOrOff);
a959c53b
KR
1121 }
1122
bd92af2b 1123 @Override
a959c53b 1124 public boolean getAutoSwapBufferMode() {
9b35c574 1125 return helper.getAutoSwapBufferMode();
a959c53b
KR
1126 }
1127
bd92af2b 1128 @Override
a959c53b 1129 public void swapBuffers() {
bd92af2b 1130 Threading.invoke(true, swapBuffersOnEDTAction, getTreeLock());
a959c53b
KR
1131 }
1132
bd92af2b 1133 @Override
6c0ad949
SG
1134 public void setContextCreationFlags(int flags) {
1135 additionalCtxCreationFlags = flags;
4b5a0f65
SG
1136 final GLContext _context = context;
1137 if(null != _context) {
1138 _context.setContextCreationFlags(additionalCtxCreationFlags);
eed8508a 1139 }
6c0ad949 1140 }
bd92af2b
SG
1141
1142 @Override
6c0ad949 1143 public int getContextCreationFlags() {
bd92af2b 1144 return additionalCtxCreationFlags;
6c0ad949 1145 }
bd92af2b
SG
1146
1147 @Override
a959c53b 1148 public GLProfile getGLProfile() {
16bb6386 1149 return capsReqUser.getGLProfile();
a959c53b
KR
1150 }
1151
bd92af2b 1152 @Override
29e3b223 1153 public GLCapabilitiesImmutable getChosenGLCapabilities() {
3567e7e8
SG
1154 if( Beans.isDesignTime() ) {
1155 return capsReqUser;
1156 } else if( null == awtConfig ) {
a959c53b
KR
1157 throw new GLException("No AWTGraphicsConfiguration: "+this);
1158 }
29e3b223 1159 return (GLCapabilitiesImmutable)awtConfig.getChosenCapabilities();
a959c53b
KR
1160 }
1161
29e3b223 1162 public GLCapabilitiesImmutable getRequestedGLCapabilities() {
3567e7e8 1163 if( null == awtConfig ) {
b9aa38f3 1164 return capsReqUser;
a959c53b 1165 }
29e3b223 1166 return (GLCapabilitiesImmutable)awtConfig.getRequestedCapabilities();
a959c53b
KR
1167 }
1168
bd92af2b 1169 @Override
f9a00b91 1170 public int getSurfaceWidth() {
2571ed0b 1171 return getWidth() * hasPixelScale[0];
f9a00b91
SG
1172 }
1173
1174 @Override
1175 public int getSurfaceHeight() {
2571ed0b 1176 return getHeight() * hasPixelScale[1];
f9a00b91
SG
1177 }
1178
1179 @Override
fd418a69
SG
1180 public boolean isGLOriented() {
1181 final GLDrawable _drawable = drawable;
1182 return null != _drawable ? _drawable.isGLOriented() : true;
1183 }
5e9c02bc 1184
fd418a69 1185 @Override
018c7e86 1186 public NativeSurface getNativeSurface() {
4b5a0f65
SG
1187 final GLDrawable _drawable = drawable;
1188 return (null != _drawable) ? _drawable.getNativeSurface() : null;
a959c53b
KR
1189 }
1190
bd92af2b 1191 @Override
1d333a77 1192 public long getHandle() {
4b5a0f65
SG
1193 final GLDrawable _drawable = drawable;
1194 return (null != _drawable) ? _drawable.getHandle() : 0;
1d333a77
SG
1195 }
1196
bd92af2b 1197 @Override
a959c53b 1198 public GLDrawableFactory getFactory() {
4b5a0f65
SG
1199 final GLDrawable _drawable = drawable;
1200 return (null != _drawable) ? _drawable.getFactory() : null;
a959c53b
KR
1201 }
1202
e5f0ee1e 1203 @Override
a959c53b 1204 public String toString() {
4b5a0f65 1205 final GLDrawable _drawable = drawable;
f9a00b91
SG
1206 final int dw = (null!=_drawable) ? _drawable.getSurfaceWidth() : -1;
1207 final int dh = (null!=_drawable) ? _drawable.getSurfaceHeight() : -1;
bd92af2b 1208
e5f0ee1e 1209 return "AWT-GLCanvas[Realized "+isRealized()+
4b5a0f65 1210 ",\n\t"+((null!=_drawable)?_drawable.getClass().getName():"null-drawable")+
e5f0ee1e
SG
1211 ",\n\tFactory "+getFactory()+
1212 ",\n\thandle 0x"+Long.toHexString(getHandle())+
f9a00b91
SG
1213 ",\n\tDrawable size "+dw+"x"+dh+" surface["+getSurfaceWidth()+"x"+getSurfaceHeight()+"]"+
1214 ",\n\tAWT[pos "+getX()+"/"+getY()+", size "+getWidth()+"x"+getHeight()+
071bdd6c 1215 ",\n\tvisible "+isVisible()+", displayable "+isDisplayable()+", showing "+isShowing+
f9a00b91 1216 ",\n\t"+awtConfig+"]]";
a959c53b 1217 }
bd92af2b 1218
a959c53b
KR
1219 //----------------------------------------------------------------------
1220 // Internals only below this point
1221 //
1222
2571ed0b 1223 private final String getPixelScaleStr() { return hasPixelScale[0]+"x"+hasPixelScale[1]; }
f9a00b91 1224
3567e7e8 1225 private final Runnable destroyOnEDTAction = new Runnable() {
bd92af2b 1226 @Override
a959c53b 1227 public void run() {
4b5a0f65
SG
1228 final RecursiveLock _lock = lock;
1229 _lock.lock();
5e9c02bc 1230 try {
4b5a0f65
SG
1231 final GLAnimatorControl animator = getAnimator();
1232
1233 if(DEBUG) {
3567e7e8 1234 System.err.println(getThreadName()+": Info: destroyOnEDTAction() - START, hasContext " +
4b5a0f65 1235 (null!=context) + ", hasDrawable " + (null!=drawable)+", "+animator);
9b5cee85 1236 // Thread.dumpStack();
4b5a0f65 1237 }
5e9c02bc 1238
d0f91a8e
SG
1239 final boolean animatorPaused;
1240 if(null!=animator) {
1241 // can't remove us from animator for recreational addNotify()
1242 animatorPaused = animator.pause();
1243 } else {
1244 animatorPaused = false;
1245 }
5e9c02bc 1246
28c64723 1247 // OLS will be detached by disposeGL's context destruction below
d0f91a8e
SG
1248 if( null != context ) {
1249 if( context.isCreated() ) {
1250 // Catch dispose GLExceptions by GLEventListener, just 'print' them
1251 // so we can continue with the destruction.
1252 try {
e92823cd 1253 helper.disposeGL(GLCanvas.this, context, true);
3567e7e8
SG
1254 if(DEBUG) {
1255 System.err.println(getThreadName()+": destroyOnEDTAction() - post ctx: "+context);
1256 }
d0f91a8e
SG
1257 } catch (GLException gle) {
1258 gle.printStackTrace();
1259 }
3567e7e8
SG
1260 }
1261 context = null;
d0f91a8e
SG
1262 }
1263 if( null != drawable ) {
1264 drawable.setRealized(false);
1265 if(DEBUG) {
3567e7e8 1266 System.err.println(getThreadName()+": destroyOnEDTAction() - post drawable: "+drawable);
4b5a0f65 1267 }
3567e7e8 1268 drawable = null;
4b5a0f65 1269 }
d0f91a8e 1270
d0f91a8e
SG
1271 if(animatorPaused) {
1272 animator.resume();
1273 }
5e9c02bc 1274
4b5a0f65 1275 if(DEBUG) {
3567e7e8 1276 System.err.println(getThreadName()+": dispose() - END, animator "+animator);
4b5a0f65 1277 }
5e9c02bc 1278
4b5a0f65
SG
1279 } finally {
1280 _lock.unlock();
1281 }
a959c53b 1282 }
3ed49121 1283 };
a959c53b 1284
4dd44b98 1285 /**
3567e7e8 1286 * Disposes the JAWTWindow and AbstractGraphicsDevice within EDT,
4dd44b98 1287 * since resources created (X11: Display), must be destroyed in the same thread, where they have been created.
3567e7e8
SG
1288 * <p>
1289 * The drawable and context handle are null'ed as well, assuming {@link #destroy()} has been called already.
1290 * </p>
4dd44b98
SG
1291 *
1292 * @see #chooseGraphicsConfiguration(javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesChooser, java.awt.GraphicsDevice)
1293 */
3567e7e8 1294 private final Runnable disposeJAWTWindowAndAWTDeviceOnEDT = new Runnable() {
bd92af2b 1295 @Override
7e606ef3 1296 public void run() {
3567e7e8
SG
1297 context=null;
1298 drawable=null;
1299
1300 if( null != jawtWindow ) {
1301 jawtWindow.destroy();
1302 if(DEBUG) {
1303 System.err.println(getThreadName()+": GLCanvas.disposeJAWTWindowAndAWTDeviceOnEDT(): post JAWTWindow: "+jawtWindow);
1304 }
1305 jawtWindow=null;
1306 }
2571ed0b
SG
1307 hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
1308 hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
5e9c02bc 1309
3567e7e8
SG
1310 if(null != awtConfig) {
1311 final AbstractGraphicsConfiguration aconfig = awtConfig.getNativeGraphicsConfiguration();
1312 final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice();
1313 final String adeviceMsg;
1314 if(DEBUG) {
1315 adeviceMsg = adevice.toString();
1316 } else {
1317 adeviceMsg = null;
1318 }
1319 boolean closed = adevice.close();
1320 if(DEBUG) {
1321 System.err.println(getThreadName()+": GLCanvas.disposeJAWTWindowAndAWTDeviceOnEDT(): post GraphicsDevice: "+adeviceMsg+", result: "+closed);
1322 }
1323 }
1324 awtConfig=null;
7e606ef3 1325 }
3ed49121 1326 };
5e9c02bc 1327
3ed49121 1328 private final Runnable initAction = new Runnable() {
bd92af2b 1329 @Override
a959c53b 1330 public void run() {
4f8432b0 1331 helper.init(GLCanvas.this, !sendReshape);
a959c53b 1332 }
3ed49121 1333 };
bd92af2b 1334
3ed49121 1335 private final Runnable displayAction = new Runnable() {
bd92af2b 1336 @Override
a959c53b
KR
1337 public void run() {
1338 if (sendReshape) {
16bb6386 1339 if(DEBUG) {
f9a00b91 1340 System.err.println(getThreadName()+": Reshape: "+getSurfaceWidth()+"x"+getSurfaceHeight());
16bb6386 1341 }
a959c53b
KR
1342 // Note: we ignore the given x and y within the parent component
1343 // since we are drawing directly into this heavyweight component.
f9a00b91 1344 helper.reshape(GLCanvas.this, 0, 0, getSurfaceWidth(), getSurfaceHeight());
a959c53b
KR
1345 sendReshape = false;
1346 }
1347
9b35c574 1348 helper.display(GLCanvas.this);
a959c53b 1349 }
3ed49121 1350 };
a959c53b 1351
bd92af2b
SG
1352 private final Runnable displayOnEDTAction = new Runnable() {
1353 @Override
a959c53b 1354 public void run() {
4b5a0f65
SG
1355 final RecursiveLock _lock = lock;
1356 _lock.lock();
c002e04f 1357 try {
97b81768 1358 if( null != drawable && drawable.isRealized() ) {
1ae0737f
SG
1359 helper.invokeGL(drawable, context, displayAction, initAction);
1360 }
4b5a0f65
SG
1361 } finally {
1362 _lock.unlock();
1363 }
a959c53b 1364 }
3ed49121 1365 };
bd92af2b
SG
1366
1367 private final Runnable swapBuffersOnEDTAction = new Runnable() {
1368 @Override
a959c53b 1369 public void run() {
4b5a0f65
SG
1370 final RecursiveLock _lock = lock;
1371 _lock.lock();
455fed40 1372 try {
97b81768 1373 if( null != drawable && drawable.isRealized() ) {
d4114a61
SG
1374 drawable.swapBuffers();
1375 }
4b5a0f65
SG
1376 } finally {
1377 _lock.unlock();
1378 }
bd92af2b 1379 }
3ed49121 1380 };
a959c53b 1381
c002e04f
SG
1382 private class DisposeGLEventListenerAction implements Runnable {
1383 GLEventListener listener;
7f7a23dd 1384 private final boolean remove;
c002e04f
SG
1385 private DisposeGLEventListenerAction(GLEventListener listener, boolean remove) {
1386 this.listener = listener;
1387 this.remove = remove;
1388 }
5e9c02bc 1389
c002e04f
SG
1390 @Override
1391 public void run() {
1392 final RecursiveLock _lock = lock;
1393 _lock.lock();
1394 try {
1395 listener = helper.disposeGLEventListener(GLCanvas.this, drawable, context, listener, remove);
1396 } finally {
1397 _lock.unlock();
1398 }
1399 }
1400 };
5e9c02bc 1401
a959c53b
KR
1402 // Disables the AWT's erasing of this Canvas's background on Windows
1403 // in Java SE 6. This internal API is not available in previous
1404 // releases, but the system property
1405 // -Dsun.awt.noerasebackground=true can be specified to get similar
1406 // results globally in previous releases.
1407 private static boolean disableBackgroundEraseInitialized;
1408 private static Method disableBackgroundEraseMethod;
1409 private void disableBackgroundErase() {
1410 if (!disableBackgroundEraseInitialized) {
1411 try {
df85f0df 1412 AccessController.doPrivileged(new PrivilegedAction<Object>() {
bd92af2b 1413 @Override
a959c53b
KR
1414 public Object run() {
1415 try {
df85f0df 1416 Class<?> clazz = getToolkit().getClass();
a959c53b
KR
1417 while (clazz != null && disableBackgroundEraseMethod == null) {
1418 try {
1419 disableBackgroundEraseMethod =
1420 clazz.getDeclaredMethod("disableBackgroundErase",
1421 new Class[] { Canvas.class });
1422 disableBackgroundEraseMethod.setAccessible(true);
1423 } catch (Exception e) {
1424 clazz = clazz.getSuperclass();
1425 }
1426 }
1427 } catch (Exception e) {
1428 }
1429 return null;
1430 }
1431 });
1432 } catch (Exception e) {
1433 }
1434 disableBackgroundEraseInitialized = true;
86c16495 1435 if(DEBUG) {
b7c5a58f 1436 System.err.println(getThreadName()+": GLCanvas: TK disableBackgroundErase method found: "+
86c16495
SG
1437 (null!=disableBackgroundEraseMethod));
1438 }
a959c53b
KR
1439 }
1440 if (disableBackgroundEraseMethod != null) {
86c16495 1441 Throwable t=null;
a959c53b
KR
1442 try {
1443 disableBackgroundEraseMethod.invoke(getToolkit(), new Object[] { this });
1444 } catch (Exception e) {
86c16495
SG
1445 t = e;
1446 }
1447 if(DEBUG) {
b7c5a58f 1448 System.err.println(getThreadName()+": GLCanvas: TK disableBackgroundErase error: "+t);
a959c53b
KR
1449 }
1450 }
1451 }
1452
e8b25a1d
SG
1453 /**
1454 * Issues the GraphicsConfigurationFactory's choosing facility within EDT,
1455 * since resources created (X11: Display), must be destroyed in the same thread, where they have been created.
1456 *
1457 * @param capsChosen
1458 * @param capsRequested
1459 * @param chooser
1460 * @param device
1461 * @return the chosen AWTGraphicsConfiguration
1462 *
3567e7e8 1463 * @see #disposeJAWTWindowAndAWTDeviceOnEDT
e8b25a1d
SG
1464 */
1465 private AWTGraphicsConfiguration chooseGraphicsConfiguration(final GLCapabilitiesImmutable capsChosen,
1466 final GLCapabilitiesImmutable capsRequested,
1467 final GLCapabilitiesChooser chooser,
1468 final GraphicsDevice device) {
a959c53b 1469 // Make GLCanvas behave better in NetBeans GUI builder
3567e7e8 1470 if( Beans.isDesignTime() ) {
a959c53b
KR
1471 return null;
1472 }
1473
bd92af2b 1474 final AbstractGraphicsScreen aScreen = null != device ?
a94c1a29
SG
1475 AWTGraphicsScreen.createScreenDevice(device, AbstractGraphicsDevice.DEFAULT_UNIT):
1476 AWTGraphicsScreen.createDefault();
e8b25a1d
SG
1477 AWTGraphicsConfiguration config = null;
1478
1479 if( EventQueue.isDispatchThread() || Thread.holdsLock(getTreeLock()) ) {
1480 config = (AWTGraphicsConfiguration)
00bef950 1481 GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class, GLCapabilitiesImmutable.class).chooseGraphicsConfiguration(capsChosen,
e8b25a1d 1482 capsRequested,
00bef950 1483 chooser, aScreen, VisualIDHolder.VID_UNDEFINED);
e8b25a1d
SG
1484 } else {
1485 try {
df85f0df 1486 final ArrayList<AWTGraphicsConfiguration> bucket = new ArrayList<AWTGraphicsConfiguration>(1);
e8b25a1d 1487 EventQueue.invokeAndWait(new Runnable() {
bd92af2b 1488 @Override
e8b25a1d
SG
1489 public void run() {
1490 AWTGraphicsConfiguration c = (AWTGraphicsConfiguration)
00bef950 1491 GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class, GLCapabilitiesImmutable.class).chooseGraphicsConfiguration(capsChosen,
e8b25a1d 1492 capsRequested,
00bef950 1493 chooser, aScreen, VisualIDHolder.VID_UNDEFINED);
e8b25a1d
SG
1494 bucket.add(c);
1495 }
1496 });
df85f0df 1497 config = ( bucket.size() > 0 ) ? bucket.get(0) : null ;
e8b25a1d
SG
1498 } catch (InvocationTargetException e) {
1499 throw new GLException(e.getTargetException());
1500 } catch (InterruptedException e) {
1501 throw new GLException(e);
1502 }
1503 }
1504
a959c53b
KR
1505 if (config == null) {
1506 throw new GLException("Error: Couldn't fetch AWTGraphicsConfiguration");
1507 }
1508
1509 return config;
1510 }
bd92af2b 1511
eff09c35 1512 protected static String getThreadName() { return Thread.currentThread().getName(); }
bd92af2b 1513
597d10f5
SG
1514 /**
1515 * A most simple JOGL AWT test entry
1516 */
1517 public static void main(String args[]) {
8c9f3bb3 1518 System.err.println(VersionUtil.getPlatformInfo());
83d3a3f2 1519 System.err.println(GlueGenVersion.getInstance());
62df9dd1 1520 // System.err.println(NativeWindowVersion.getInstance());
2aa90676 1521 System.err.println(JoglVersion.getInstance());
dac35658 1522
20bf031d 1523 System.err.println(JoglVersion.getDefaultOpenGLInfo(null, null, true).toString());
8adc0478 1524
4011e70e 1525 final GLCapabilitiesImmutable caps = new GLCapabilities( GLProfile.getDefault(GLProfile.getDefaultDevice()) );
098398c2 1526 final Frame frame = new Frame("JOGL AWT Test");
597d10f5 1527
098398c2 1528 final GLCanvas glCanvas = new GLCanvas(caps);
597d10f5
SG
1529 frame.add(glCanvas);
1530 frame.setSize(128, 128);
1531
1532 glCanvas.addGLEventListener(new GLEventListener() {
bd92af2b 1533 @Override
597d10f5
SG
1534 public void init(GLAutoDrawable drawable) {
1535 GL gl = drawable.getGL();
10c696f7 1536 System.err.println(JoglVersion.getGLInfo(gl, null));
597d10f5 1537 }
bd92af2b 1538 @Override
098398c2 1539 public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { }
bd92af2b 1540 @Override
098398c2 1541 public void display(GLAutoDrawable drawable) { }
bd92af2b 1542 @Override
098398c2 1543 public void dispose(GLAutoDrawable drawable) { }
597d10f5
SG
1544 });
1545
597d10f5
SG
1546 try {
1547 javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
bd92af2b 1548 @Override
597d10f5 1549 public void run() {
098398c2 1550 frame.setVisible(true);
597d10f5
SG
1551 }});
1552 } catch (Throwable t) {
1553 t.printStackTrace();
1554 }
1555 glCanvas.display();
1556 try {
1557 javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
bd92af2b 1558 @Override
597d10f5 1559 public void run() {
098398c2 1560 frame.dispose();
597d10f5
SG
1561 }});
1562 } catch (Throwable t) {
1563 t.printStackTrace();
1564 }
1565 }
1566
a959c53b 1567}
http://JogAmp.org git info: FAQ, tutorial and man pages.