JOGL v2.6.0-rc-20250712
JOGL, High-Performance Graphics Binding for Java™ (public API).
JAWTWindow.java
Go to the documentation of this file.
1/*
2 * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
3 * Copyright (c) 2010-2023 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
38package com.jogamp.nativewindow.awt;
39
40import com.jogamp.common.ExceptionUtils;
41import com.jogamp.common.os.Platform;
42import com.jogamp.common.util.awt.AWTEDTExecutor;
43import com.jogamp.common.util.locks.LockFactory;
44import com.jogamp.common.util.locks.RecursiveLock;
45import com.jogamp.nativewindow.MutableGraphicsConfiguration;
46
47import java.awt.Component;
48import java.awt.Container;
49import java.awt.Cursor;
50import java.awt.EventQueue;
51import java.awt.GraphicsConfiguration;
52import java.awt.event.ComponentEvent;
53import java.awt.event.ComponentListener;
54import java.awt.event.HierarchyEvent;
55import java.awt.event.HierarchyListener;
56
57import com.jogamp.nativewindow.AbstractGraphicsConfiguration;
58import com.jogamp.nativewindow.AbstractGraphicsDevice;
59import com.jogamp.nativewindow.CapabilitiesImmutable;
60import com.jogamp.nativewindow.NativeSurface;
61import com.jogamp.nativewindow.NativeWindow;
62import com.jogamp.nativewindow.NativeWindowException;
63import com.jogamp.nativewindow.OffscreenLayerOption;
64import com.jogamp.nativewindow.OffscreenLayerSurface;
65import com.jogamp.nativewindow.ScalableSurface;
66import com.jogamp.nativewindow.SurfaceUpdatedListener;
67import com.jogamp.nativewindow.util.Insets;
68import com.jogamp.nativewindow.util.InsetsImmutable;
69import com.jogamp.nativewindow.util.PixelRectangle;
70import com.jogamp.nativewindow.util.Point;
71import com.jogamp.nativewindow.util.PointImmutable;
72import com.jogamp.nativewindow.util.Rectangle;
73import com.jogamp.nativewindow.util.RectangleImmutable;
74
75import jogamp.common.os.PlatformPropsImpl;
76import jogamp.nativewindow.SurfaceScaleUtils;
77import jogamp.nativewindow.SurfaceUpdatedHelper;
78import jogamp.nativewindow.awt.AWTMisc;
79import jogamp.nativewindow.jawt.JAWT;
80import jogamp.nativewindow.jawt.JAWTUtil;
81import jogamp.nativewindow.jawt.JAWT_Rectangle;
82
84 protected static final boolean DEBUG = JAWTUtil.DEBUG;
85
86 // user properties
87 protected boolean shallUseOffscreenLayer = false;
88
89 // lifetime: forever
90 protected final Component component;
91 private final AppContextInfo appContextInfo; // only used for offscreen layer, i.e. MacOS only
92 private final SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper();
93 private final RecursiveLock surfaceLock = LockFactory.createRecursiveLock();
94 private final JAWTComponentListener jawtComponentListener;
95 private volatile AWTGraphicsConfiguration awtConfig; // control access through delegation
96
97 // lifetime: valid after lock but may change with each 1st lock, purges after invalidate
98 private JAWT jawt;
99 private boolean isOffscreenLayerSurface;
100 protected long drawable;
102 protected Insets insets;
103 private volatile long offscreenSurfaceLayer;
104
105 private final float[] hasPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
106 private volatile boolean hasPixelScaleChanged = false;
107 private long drawable_old;
108
109 /**
110 * Constructed by {@link jogamp.nativewindow.NativeWindowFactoryImpl#getNativeWindow(Object, AbstractGraphicsConfiguration)}
111 * via this platform's specialization (X11, OSX, Windows, ..).
112 *
113 * @param comp
114 * @param config
115 */
116 protected JAWTWindow(final Object comp, final AbstractGraphicsConfiguration config) {
117 if (config == null) {
118 throw new IllegalArgumentException("Error: AbstractGraphicsConfiguration is null");
119 }
120 if(! ( config instanceof AWTGraphicsConfiguration ) ) {
121 throw new NativeWindowException("Error: AbstractGraphicsConfiguration is not an AWTGraphicsConfiguration: "+config);
122 }
123 if( JAWTUtil.isOffscreenLayerSupported() ) {
124 appContextInfo = new AppContextInfo("<init>");
125 } else {
126 appContextInfo = null;
127 }
128 this.component = (Component)comp;
129 this.jawtComponentListener = new JAWTComponentListener();
130 this.offscreenSurfaceLayer = 0;
131 invalidate();
132 this.awtConfig = (AWTGraphicsConfiguration) config;
133 if(DEBUG) {
134 System.err.println(jawtStr2("ctor"));
135 }
136 }
137 private static String id(final Object obj) { return ( null!=obj ? toHexString(obj.hashCode()) : "nil" ); }
138 private String jawtStr1() { return "JAWTWindow["+id(JAWTWindow.this)+"]"; }
139 private String jawtStr2(final String sub) { return jawtStr1()+"."+sub+" @ Thread "+getThreadName(); }
140
141 private class JAWTComponentListener implements ComponentListener, HierarchyListener {
142 private volatile boolean isShowing;
143
144 private String str(final Object obj) {
145 if( null == obj ) {
146 return "0xnil: null";
147 } else if( obj instanceof Component ) {
148 final Component c = (Component)obj;
149 return id(obj)+": "+c.getClass().getSimpleName()+"[visible "+c.isVisible()+", showing "+c.isShowing()+", valid "+c.isValid()+
150 ", displayable "+c.isDisplayable()+", "+c.getX()+"/"+c.getY()+" "+c.getWidth()+"x"+c.getHeight()+"]";
151 } else {
152 return id(obj)+": "+obj.getClass().getSimpleName()+"[..]";
153 }
154 }
155 private String s(final ComponentEvent e) {
156 return "visible[isShowing "+isShowing+"],"+Platform.getNewline()+
157 " ** COMP "+str(e.getComponent())+Platform.getNewline()+
158 " ** SOURCE "+str(e.getSource())+Platform.getNewline()+
159 " ** THIS "+str(component)+Platform.getNewline()+
160 " ** THREAD "+getThreadName();
161 }
162 private String s(final HierarchyEvent e) {
163 return "visible[isShowing "+isShowing+"], changeBits 0x"+Long.toHexString(e.getChangeFlags())+Platform.getNewline()+
164 " ** COMP "+str(e.getComponent())+Platform.getNewline()+
165 " ** SOURCE "+str(e.getSource())+Platform.getNewline()+
166 " ** CHANGED "+str(e.getChanged())+Platform.getNewline()+
167 " ** CHANGEDPARENT "+str(e.getChangedParent())+Platform.getNewline()+
168 " ** THIS "+str(component)+Platform.getNewline()+
169 " ** THREAD "+getThreadName();
170 }
171 @Override
172 public final String toString() {
173 return "visible[isShowing "+isShowing+"],"+Platform.getNewline()+
174 " ** THIS "+str(component)+Platform.getNewline()+
175 " ** THREAD "+getThreadName();
176 }
177
178 private JAWTComponentListener() {
179 isShowing = component.isShowing();
180 AWTEDTExecutor.singleton.invoke(false, new Runnable() { // Bug 952: Avoid deadlock via AWTTreeLock acquisition ..
181 @Override
182 public void run() {
183 isShowing = component.isShowing(); // Bug 1161: Runnable might be deferred, hence need to update
184 if(DEBUG) {
185 System.err.println(jawtStr2("attach")+": "+JAWTComponentListener.this.toString());
186 }
187 component.addComponentListener(JAWTComponentListener.this);
188 component.addHierarchyListener(JAWTComponentListener.this);
189 } } );
190 }
191
192 private final void detach() {
193 AWTEDTExecutor.singleton.invoke(false, new Runnable() { // Bug 952: Avoid deadlock via AWTTreeLock acquisition ..
194 @Override
195 public void run() {
196 if(DEBUG) {
197 System.err.println(jawtStr2("detach")+": "+JAWTComponentListener.this.toString());
198 }
199 component.removeComponentListener(JAWTComponentListener.this);
200 component.removeHierarchyListener(JAWTComponentListener.this);
201 } } );
202 }
203
204 @Override
205 public final void componentResized(final ComponentEvent e) {
206 if(DEBUG) {
207 System.err.println(jawtStr2("componentResized")+": "+s(e));
208 }
209 layoutSurfaceLayerIfEnabled(isShowing);
210 }
211
212 @Override
213 public final void componentMoved(final ComponentEvent e) {
214 if(DEBUG) {
215 System.err.println(jawtStr2("componentMoved")+": "+s(e));
216 }
217 layoutSurfaceLayerIfEnabled(isShowing);
218 }
219
220 @Override
221 public final void componentShown(final ComponentEvent e) {
222 if(DEBUG) {
223 System.err.println(jawtStr2("componentShown")+": "+s(e));
224 }
225 layoutSurfaceLayerIfEnabled(isShowing);
226 }
227
228 @Override
229 public final void componentHidden(final ComponentEvent e) {
230 if(DEBUG) {
231 System.err.println(jawtStr2("componentHidden")+": "+s(e));
232 }
233 layoutSurfaceLayerIfEnabled(isShowing);
234 }
235
236 @Override
237 public final void hierarchyChanged(final HierarchyEvent e) {
238 final boolean wasShowing = isShowing;
239 isShowing = component.isShowing();
240 int action = 0;
241 if( 0 != ( java.awt.event.HierarchyEvent.SHOWING_CHANGED & e.getChangeFlags() ) ) {
242 if( e.getChanged() != component && wasShowing != isShowing ) {
243 // A parent component changed and caused a 'showing' state change,
244 // propagate to offscreen-layer!
245 layoutSurfaceLayerIfEnabled(isShowing);
246 action = 1;
247 }
248 }
249 if(DEBUG) {
250 final java.awt.Component changed = e.getChanged();
251 final boolean displayable = changed.isDisplayable();
252 final boolean showing = changed.isShowing();
253 System.err.println(jawtStr2("hierarchyChanged")+": action "+action+", displayable "+displayable+", showing [changed "+showing+", comp "+wasShowing+" -> "+isShowing+"], "+s(e));
254 }
255 }
256 }
257
258 private static String getThreadName() { return Thread.currentThread().getName(); }
259
260 protected synchronized void invalidate() {
261 if(DEBUG) {
262 System.err.println(jawtStr2("invalidate")+" - "+jawtComponentListener.toString());
263 if( isSurfaceLayerAttached() ) {
264 System.err.println("OffscreenSurfaceLayer still attached: 0x"+Long.toHexString(offscreenSurfaceLayer));
265 }
266 // Thread.dumpStack();
267 }
268 {
269 final long osl = offscreenSurfaceLayer;
270 offscreenSurfaceLayer = 0;
271 invalidateNative(osl);
272 }
273 jawt = null;
274 awtConfig = null;
275 offscreenSurfaceLayer = 0; // Bug 1389
276 isOffscreenLayerSurface = false;
277 drawable= 0;
278 drawable_old = 0;
280 insets = new Insets();
281 hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
282 hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
283 hasPixelScaleChanged = false;
284 }
285 protected abstract void invalidateNative(final long _offscreenSurfaceLayer);
286
287 /**
288 * Set a new {@link AWTGraphicsConfiguration} instance,
289 * as required if {@link #getAWTComponent() upstream component}'s {@link GraphicsConfiguration} has been changed
290 * due to reconfiguration, e.g. moving to a different monitor or changed capabilities.
291 * <p>
292 * {@link #getAWTComponent() Upstream component} shall override {@link Component#getGraphicsConfiguration()},
293 * which shall call this method if detecting a reconfiguration.
294 * See JOGL's GLCanvas and NewtCanvasAWT.
295 * </p>
296 * @param config the new {@link AWTGraphicsConfiguration}
297 * @see #getAWTGraphicsConfiguration()
298 */
300 if(DEBUG) {
301 System.err.println(jawtStr2("setAWTGraphicsConfiguration")+": "+this.awtConfig+" -> "+config);
302 // Thread.dumpStack();
303 }
304 if( null == awtConfig ) {
305 throw new IllegalArgumentException(jawtStr2("")+": null config");
306 }
307 this.awtConfig = config;
308 }
309 /**
310 * Return the current {@link AWTGraphicsConfiguration} instance,
311 * which also holds its {@link #getAWTComponent() upstream component}'s {@link GraphicsConfiguration}
312 * @see #setAWTGraphicsConfiguration(AWTGraphicsConfiguration)
313 */
315 return awtConfig;
316 }
317
318 /**
319 * {@inheritDoc}
320 * <p>
321 * This implementation returns false, i.e. not supporting manual change of pixel-scale.
322 * </p>
323 */
324 @Override
325 public final boolean canSetSurfaceScale() { return false; }
326
327 /**
328 * {@inheritDoc}
329 * <p>
330 * Ignored for an AWT widget since pixelScale is dictated by AWT mechanisms.
331 * </p>
332 */
333 @Override
334 public boolean setSurfaceScale(final float[] pixelScale) {
335 return false;
336 }
337
338 /**
339 * {@inheritDoc}
340 * <p>
341 * Returns {@link ScalableSurface#AUTOMAX_PIXELSCALE}, always.
342 * </p>
343 */
344 @Override
345 public final float[] getRequestedSurfaceScale(final float[] result) {
348 return result;
349 }
350
351 @Override
352 public final float[] getCurrentSurfaceScale(final float[] result) {
353 System.arraycopy(hasPixelScale, 0, result, 0, 2);
354 return result;
355 }
356
357 /**
358 * {@inheritDoc}
359 * <p>
360 * Returns 1.0, always.
361 * </p>
362 */
363 @Override
364 public float[] getMinimumSurfaceScale(final float[] result) {
365 result[0] = 1f;
366 result[1] = 1f;
367 return result;
368 }
369
370 /**
371 * {@inheritDoc}
372 * <p>
373 * Returns {@link #getCurrentSurfaceScale(float[])}.
374 * </p>
375 */
376 @Override
377 public final float[] getMaximumSurfaceScale(final float[] result) {
378 System.arraycopy(hasPixelScale, 0, result, 0, 2);
379 return result;
380 }
381
382 /**
383 * Updates bounds and pixelScale
384 * @param gc GraphicsConfiguration for {@link #updatePixelScale(GraphicsConfiguration, boolean)}
385 * @return true if bounds or pixelScale has changed, otherwise false
386 */
387 protected final boolean updateLockedData(final JAWT_Rectangle jawtBounds, final GraphicsConfiguration gc) {
388 final Rectangle jb = new Rectangle(jawtBounds.getX(), jawtBounds.getY(), jawtBounds.getWidth(), jawtBounds.getHeight());
389 final boolean changedBounds = !jawt_surface_bounds.equals(jb);
390
391 if( changedBounds ) {
392 if( DEBUG ) {
393 System.err.println("JAWTWindow.updateBounds: "+jawt_surface_bounds+" -> "+jb);
394 }
395 jawt_surface_bounds.set(jawtBounds.getX(), jawtBounds.getY(), jawtBounds.getWidth(), jawtBounds.getHeight());
396
397 if(component instanceof Container) {
398 final java.awt.Insets contInsets = ((Container)component).getInsets();
399 insets.set(contInsets.left, contInsets.right, contInsets.top, contInsets.bottom);
400 }
401 }
402
403 updatePixelScale(gc, false);
404 return hasPixelScaleChanged || changedBounds;
405 }
406
407 /**
408 * Updates the minimum and maximum pixel-scale values
409 * and returns {@code true} if they were updated.
410 * @param gc pre-fetched {@link GraphicsConfiguration} instance of {@link #getAWTComponent() upstream component},
411 * caller may use cached {@link #getAWTGraphicsConfiguration()}'s {@link AWTGraphicsConfiguration#getAWTGraphicsConfiguration() GC}
412 * or a {@link Component#getGraphicsConfiguration()}.
413 * @param clearFlag if {@code true}, the {@code hasPixelScaleChanged} flag will be cleared
414 * @return {@code true} if values were updated, otherwise {@code false}.
415 * @see #hasPixelScaleChanged()
416 * @see #getAWTGraphicsConfiguration()
417 * @see Component#getGraphicsConfiguration()
418 */
419 public final boolean updatePixelScale(final GraphicsConfiguration gc, final boolean clearFlag) {
420 final float[] min = { 1, 1 };
421 final float[] max = { hasPixelScale[0], hasPixelScale[1] };
422 if( JAWTUtil.getPixelScale(gc, min, max) ) {
423 // Enforce maxPixelScale as used by AWT
424 if( DEBUG ) {
425 System.err.println("JAWTWindow.updatePixelScale: ["+hasPixelScale[0]+", "+hasPixelScale[1]+"] -> ["+max[0]+", "+max[1]+"]");
426 }
427 hasPixelScaleChanged = true;
428 System.arraycopy(max, 0, hasPixelScale, 0, 2);
429 }
430 if( clearFlag ) {
431 final boolean r = hasPixelScaleChanged;
432 hasPixelScaleChanged = false;
433 return r;
434 } else {
435 return hasPixelScaleChanged;
436 }
437 }
438
439 /**
440 * Returns and clears the {@code hasPixelScaleChanged} flag, as set via {@link #lockSurface()}.
441 * <p>
442 * {@code hasPixelScaleChanged} is {@code true},
443 * if the {@link #getMinimumSurfaceScale(float[]) minimum} or {@link #getMaximumSurfaceScale(float[]) maximum}
444 * pixel scale has changed.
445 * User needs to {@link #setSurfaceScale(float[]) set the current pixel scale} in this case
446 * using the {@link #getRequestedSurfaceScale(float[]) requested pixel scale}
447 * to update the surface pixel scale.
448 * </p>
449 */
450 public final boolean hasPixelScaleChanged() {
451 final boolean v = hasPixelScaleChanged;
452 hasPixelScaleChanged = false;
453 return v;
454 }
455
456 /** @return the JAWT_DrawingSurfaceInfo's (JAWT_Rectangle) bounds in pixel units, updated with lock */
458
459 /** @return the safe pixelScale value for x-direction, i.e. never negative or zero. Updated with lock. */
460 protected final float getPixelScaleX() { return hasPixelScale[0]; }
461
462 /** @return the safe pixelScale value for y-direction, i.e. never negative or zero. Updated with lock. */
463 protected final float getPixelScaleY() { return hasPixelScale[1]; }
464
465 @Override
466 public final InsetsImmutable getInsets() { return insets; }
467
468 public final Component getAWTComponent() {
469 return component;
470 }
471
472 /**
473 *
474 * Return false since there is no more {@link java.applet.Applet} support.
475 *
476 * Historical: Returns true if the AWT component is parented to an {@link java.applet.Applet},
477 * otherwise false. This information is valid only after {@link #lockSurface()}.
478 */
479 public final boolean isApplet() {
480 return false; // return isApplet;
481 }
482
483 /** Returns the underlying JAWT instance created @ {@link #lockSurface()}. */
484 public final JAWT getJAWT() {
485 return jawt;
486 }
487
488 //
489 // OffscreenLayerOption
490 //
491
492 @Override
493 public void setShallUseOffscreenLayer(final boolean v) {
495 }
496
497 @Override
498 public final boolean getShallUseOffscreenLayer() {
500 }
501
502 @Override
503 public final boolean isOffscreenLayerSurfaceEnabled() {
504 return isOffscreenLayerSurface;
505 }
506
507 //
508 // OffscreenLayerSurface
509 //
510
511 @Override
512 public final void attachSurfaceLayer(final long layerHandle) throws NativeWindowException {
513 if( null == appContextInfo ) { // !JAWTUtil.isOffscreenLayerSupported()
514 throw new NativeWindowException("Offscreen layer not supported");
515 }
517 throw new NativeWindowException("Not an offscreen layer surface");
518 }
519 attachSurfaceLayerImpl(layerHandle);
520 offscreenSurfaceLayer = layerHandle;
521 appContextInfo.invokeOnAppContextThread(false /* waitUntilDone */, repaintTask, "Repaint");
522 }
523 private final Runnable repaintTask = new Runnable() {
524 @Override
525 public void run() {
526 final Component c = component;
527 if( DEBUG ) {
528 System.err.println("Bug 1004: RepaintTask on "+Thread.currentThread()+": Has Comp "+(null != c));
529 }
530 if( null != c ) {
531 c.repaint();
532 }
533 } };
534
535 protected void attachSurfaceLayerImpl(final long _offscreenSurfaceLayer) {
536 throw new UnsupportedOperationException("offscreen layer not supported");
537 }
538
539 /**
540 * Layout the offscreen layer according to the implementing class's constraints.
541 * <p>
542 * This method allows triggering a re-layout of the offscreen surface
543 * in case the implementation requires it.
544 * </p>
545 * <p>
546 * Call this method if any parent or ancestor's layout has been changed,
547 * which could affects the layout of this surface.
548 * </p>
549 * @see #isOffscreenLayerSurfaceEnabled()
550 * @throws NativeWindowException if {@link #isOffscreenLayerSurfaceEnabled()} == false
551 */
552 protected void layoutSurfaceLayerImpl(final boolean visible) {}
553
554 private final void layoutSurfaceLayerIfEnabled(final boolean visible) throws NativeWindowException {
555 if( isOffscreenLayerSurfaceEnabled() && 0 != offscreenSurfaceLayer ) {
556 layoutSurfaceLayerImpl(visible);
557 }
558 }
559
560
561 @Override
562 public final void detachSurfaceLayer() throws NativeWindowException {
563 if( 0 == offscreenSurfaceLayer) {
564 throw new NativeWindowException("No offscreen layer attached: "+this);
565 }
566 if(DEBUG) {
567 System.err.println("JAWTWindow.detachSurfaceHandle(): osh "+toHexString(offscreenSurfaceLayer)+" - "+Thread.currentThread().getName());
568 }
569 {
570 final long osl = offscreenSurfaceLayer;
571 offscreenSurfaceLayer = 0;
573 }
574 }
575
576 /**
577 * @param detachNotify Runnable to be called before native detachment
578 */
579 protected void detachSurfaceLayerImpl(final long _offscreenSurfaceLayer) {
580 throw new UnsupportedOperationException("offscreen layer not supported");
581 }
582
583
584 @Override
585 public final long getAttachedSurfaceLayer() {
586 return offscreenSurfaceLayer;
587 }
588
589 @Override
590 public final boolean isSurfaceLayerAttached() {
591 return 0 != offscreenSurfaceLayer;
592 }
593
594 @Override
595 public final void setChosenCapabilities(final CapabilitiesImmutable caps) {
597 awtConfig.setChosenCapabilities(caps);
598 }
599
600 @Override
601 public final RecursiveLock getLock() {
602 return surfaceLock;
603 }
604
605 @Override
606 public final boolean setCursor(final PixelRectangle pixelrect, final PointImmutable hotSpot) {
607 AWTEDTExecutor.singleton.invoke(false, new Runnable() {
608 @Override
609 public void run() {
610 Cursor c = null;
611 if( null == pixelrect || null == hotSpot ) {
612 c = Cursor.getDefaultCursor();
613 } else {
614 final java.awt.Point awtHotspot = new java.awt.Point(hotSpot.getX(), hotSpot.getY());
615 try {
616 c = AWTMisc.getCursor(pixelrect, awtHotspot);
617 } catch (final Exception e) {
618 e.printStackTrace();
619 }
620 }
621 if( null != c ) {
622 component.setCursor(c);
623 }
624 } } );
625 return true;
626 }
627
628 @Override
629 public final boolean hideCursor() {
630 AWTEDTExecutor.singleton.invoke(false, new Runnable() {
631 @Override
632 public void run() {
633 final Cursor cursor = AWTMisc.getNullCursor();
634 if( null != cursor ) {
635 component.setCursor(cursor);
636 }
637 } } );
638 return true;
639 }
640
641 //
642 // NativeSurface
643 //
644
645 /**
646 private void determineIfApplet() {
647 boolean isApplet = false; // dummy
648 Component c = component;
649 while(!isApplet && null != c) {
650 isApplet = c instanceof java.applet.Applet;
651 c = c.getParent();
652 }
653 } */
654
655 /**
656 * If JAWT offscreen layer is supported,
657 * implementation shall respect {@link #getShallUseOffscreenLayer()}
658 * and may respect {@link #isApplet()}.
659 *
660 * @return The JAWT instance reflecting offscreen layer support, etc.
661 *
662 * @throws NativeWindowException
663 */
664 protected abstract JAWT fetchJAWTImpl() throws NativeWindowException;
665 protected abstract int lockSurfaceImpl(GraphicsConfiguration gc) throws NativeWindowException;
666
667 protected void dumpJAWTInfo() {
668 System.err.println(jawt2String(null).toString());
669 // Thread.dumpStack();
670 }
671
672 @Override
673 public final int lockSurface() throws NativeWindowException, RuntimeException {
674 surfaceLock.lock();
675 int res = surfaceLock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ?
676
677 if ( LOCK_SURFACE_NOT_READY == res ) {
678 if( !component.isDisplayable() ) {
679 // W/o native peer, we cannot utilize JAWT for locking.
680 surfaceLock.unlock();
681 if(DEBUG) {
682 System.err.println("JAWTWindow: Can't lock surface, component peer n/a. Component displayable "+component.isDisplayable()+", "+component);
683 ExceptionUtils.dumpStack(System.err);
684 }
685 } else {
686 final GraphicsConfiguration gc;
687 if( EventQueue.isDispatchThread() || Thread.holdsLock(component.getTreeLock()) ) {
688 /**
689 * Trigger detection of possible reconfiguration before 'sun.awt.SunToolkit.awtLock()',
690 * which maybe triggered via adevice.lock() below (X11).
691 * See setAWTGraphicsConfiguration(..).
692 */
693 gc = component.getGraphicsConfiguration();
694 } else {
695 // Reuse cached instance
696 gc = awtConfig.getAWTGraphicsConfiguration();
697 }
698
699 // determineIfApplet();
700 try {
702 adevice.lock();
703 try {
704 if(null == jawt) { // no need to re-fetch for each frame
705 jawt = fetchJAWTImpl();
706 isOffscreenLayerSurface = JAWTUtil.isJAWTUsingOffscreenLayer(jawt);
707 }
708 res = lockSurfaceImpl(gc);
709 if(LOCK_SUCCESS == res && drawable_old != drawable) {
711 if(DEBUG) {
712 System.err.println("JAWTWindow: surface change "+toHexString(drawable_old)+" -> "+toHexString(drawable));
713 // Thread.dumpStack();
714 }
715 }
716 } finally {
717 if (LOCK_SURFACE_NOT_READY >= res) {
718 adevice.unlock();
719 }
720 }
721 } finally {
722 if (LOCK_SURFACE_NOT_READY >= res) {
723 surfaceLock.unlock();
724 }
725 }
726 }
727 }
728 return res;
729 }
730
731 protected abstract void unlockSurfaceImpl() throws NativeWindowException;
732
733 @Override
734 public final void unlockSurface() {
735 surfaceLock.validateLocked();
736 drawable_old = drawable;
737
738 if (surfaceLock.getHoldCount() == 1) {
740 try {
741 if(null != jawt) {
743 }
744 } finally {
745 adevice.unlock();
746 }
747 }
748 surfaceLock.unlock();
749 }
750
751 @Override
752 public final boolean isSurfaceLockedByOtherThread() {
753 return surfaceLock.isLockedByOtherThread();
754 }
755
756 @Override
757 public final Thread getSurfaceLockOwner() {
758 return surfaceLock.getOwner();
759 }
760
761 @Override
762 public boolean surfaceSwap() {
763 return false;
764 }
765
766 @Override
768 surfaceUpdatedHelper.addSurfaceUpdatedListener(l);
769 }
770
771 @Override
772 public void addSurfaceUpdatedListener(final int index, final SurfaceUpdatedListener l) throws IndexOutOfBoundsException {
773 surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l);
774 }
775
776 @Override
778 surfaceUpdatedHelper.removeSurfaceUpdatedListener(l);
779 }
780
781 @Override
782 public void surfaceUpdated(final Object updater, final NativeSurface ns, final long when) {
783 surfaceUpdatedHelper.surfaceUpdated(updater, ns, when);
784 }
785
786 @Override
787 public long getSurfaceHandle() {
788 return drawable;
789 }
790
791 @Override
793 if( null == awtConfig ) {
794 throw new NativeWindowException(jawtStr2("")+": null awtConfig, invalidated");
795 }
796 return awtConfig.getNativeGraphicsConfiguration();
797 }
798
799 @Override
800 public final long getDisplayHandle() {
802 }
803
804 @Override
805 public final int getScreenIndex() {
807 }
808
809 @Override
810 public final int getSurfaceWidth() {
811 return SurfaceScaleUtils.scale(getWidth(), getPixelScaleX());
812 }
813
814 @Override
815 public final int getSurfaceHeight() {
816 return SurfaceScaleUtils.scale(getHeight(), getPixelScaleY());
817 }
818
819 @Override
820 public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) {
821 return SurfaceScaleUtils.scaleInv(pixelUnitsAndResult, pixelUnitsAndResult, hasPixelScale);
822 }
823
824 @Override
825 public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) {
826 return SurfaceScaleUtils.scale(windowUnitsAndResult, windowUnitsAndResult, hasPixelScale);
827 }
828
829 @Override
830 public final NativeSurface getNativeSurface() { return this; }
831
832 //
833 // NativeWindow
834 //
835
836 @Override
837 public final int getX() {
838 return component.getX();
839 }
840
841 @Override
842 public final int getY() {
843 return component.getY();
844 }
845
846 @Override
847 public final int getWidth() {
848 return component.getWidth();
849 }
850
851 @Override
852 public final int getHeight() {
853 return component.getHeight();
854 }
855
856 @Override
857 public final Rectangle getBounds() {
858 return new Rectangle(getX(), getY(), getWidth(), getHeight());
859 }
860
861 @Override
863 return new Rectangle(SurfaceScaleUtils.scale(getX(), getPixelScaleX()),
864 SurfaceScaleUtils.scale(getY(), getPixelScaleY()),
866 }
867
868 @Override
869 public void destroy() {
870 surfaceLock.lock();
871 try {
872 if(DEBUG) {
873 System.err.println(jawtStr2("destroy"));
874 }
875 jawtComponentListener.detach();
876 invalidate();
877 } finally {
878 surfaceLock.unlock();
879 }
880 }
881
882 @Override
883 public final NativeWindow getParent() {
884 return null;
885 }
886
887 @Override
888 public long getWindowHandle() {
889 return drawable;
890 }
891
892 /**
893 * {@inheritDoc}
894 *
895 * <p>
896 * This JAWT default implementation is currently still using
897 * a blocking implementation. It first attempts to retrieve the location
898 * via a native implementation. If this fails, it tries the blocking AWT implementation.
899 * If the latter fails due to an external AWT tree-lock, the non block
900 * implementation {@link #getLocationOnScreenNonBlocking(Point, Component)} is being used.
901 * The latter simply traverse up to the AWT component tree and sums the rel. position.
902 * We have to determine whether the latter is good enough for all cases,
903 * currently only OS X utilizes the non blocking method per default.
904 * </p>
905 */
906 @Override
907 public Point getLocationOnScreen(final Point storage) {
908 Point los = getLocationOnScreenNative(storage);
909 if(null == los) {
910 los = AWTMisc.getLocationOnScreenSafe(storage, component, DEBUG);
911 }
912 return los;
913 }
914
915 protected Point getLocationOnScreenNative(final Point storage) {
916 final int lockRes = lockSurface();
917 if(LOCK_SURFACE_NOT_READY == lockRes) {
918 if(DEBUG) {
919 System.err.println("Warning: JAWT Lock couldn't be acquired: "+this);
920 ExceptionUtils.dumpStack(System.err);
921 }
922 return null;
923 }
924 try {
925 final Point d = getLocationOnScreenNativeImpl(0, 0);
926 if(null!=d) {
927 if(null!=storage) {
928 storage.translate(d.getX(),d.getY());
929 return storage;
930 }
931 }
932 return d;
933 } finally {
935 }
936 }
937 protected abstract Point getLocationOnScreenNativeImpl(int x, int y);
938
939 @Override
940 public boolean hasFocus() {
941 return component.hasFocus();
942 }
943
944 protected StringBuilder jawt2String(StringBuilder sb) {
945 if( null == sb ) {
946 sb = new StringBuilder();
947 }
948 sb.append("JVM version: ").append(PlatformPropsImpl.JAVA_VERSION).append(" (").
949 append(PlatformPropsImpl.JAVA_VERSION_NUMBER).
950 append(" update ").append(PlatformPropsImpl.JAVA_VERSION_UPDATE).append(")").append(Platform.getNewline());
951 if(null != jawt) {
952 sb.append("JAWT version: ").append(toHexString(jawt.getCachedVersion())).
953 append(", CA_LAYER: ").append(JAWTUtil.isJAWTUsingOffscreenLayer(jawt)).
954 append(", isLayeredSurface ").append(isOffscreenLayerSurfaceEnabled()).
955 append(", bounds ").append(jawt_surface_bounds).append(", insets ").append(insets).
956 append(", pixelScale ").append(getPixelScaleX()).append("x").append(getPixelScaleY());
957 } else {
958 sb.append("JAWT n/a, bounds ").append(jawt_surface_bounds).append(", insets ").append(insets);
959 }
960 return sb;
961 }
962
963 @Override
964 public String toString() {
965 final StringBuilder sb = new StringBuilder();
966
967 sb.append(jawtStr1()+"[");
968 jawt2String(sb);
969 sb.append( ", shallUseOffscreenLayer "+shallUseOffscreenLayer+", isOffscreenLayerSurface "+isOffscreenLayerSurface+
970 ", attachedSurfaceLayer "+toHexString(getAttachedSurfaceLayer())+
971 ", windowHandle "+toHexString(getWindowHandle())+
972 ", surfaceHandle "+toHexString(getSurfaceHandle())+
973 ", bounds "+jawt_surface_bounds+", insets "+insets
974 );
975 sb.append(", window ["+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+
976 "], pixels[scale "+getPixelScaleX()+", "+getPixelScaleY()+" -> "+getSurfaceWidth()+"x"+getSurfaceHeight()+"]"+
977 ", visible "+component.isVisible());
978 sb.append(", lockedExt "+isSurfaceLockedByOtherThread()+
979 ",\n\tconfig "+awtConfig+
980 ",\n\tawtComponent "+getAWTComponent()+
981 ",\n\tsurfaceLock "+surfaceLock+"]");
982
983 return sb.toString();
984 }
985
986 protected static final String toHexString(final long l) {
987 return "0x"+Long.toHexString(l);
988 }
989 protected static final String toHexString(final int i) {
990 return "0x"+Integer.toHexString(i);
991 }
992
993}
A generic exception for OpenGL errors used throughout the binding as a substitute for RuntimeExceptio...
A wrapper for an AWT GraphicsConfiguration allowing it to be handled in a toolkit-independent manner.
GraphicsConfiguration getAWTGraphicsConfiguration()
Return the AWT GraphicsConfiguration.
AbstractGraphicsConfiguration getNativeGraphicsConfiguration()
In case the implementation utilizes a delegation pattern to wrap abstract toolkits,...
void setChosenCapabilities(final CapabilitiesImmutable capsChosen)
Set the capabilities to a new value.
Instance of this class holds information about a ThreadGroup associated sun.awt.AppContext.
RunnableTask invokeOnAppContextThread(final boolean waitUntilDone, final Runnable runnable, final String threadBaseName)
Invokes runnable on a Thread belonging to the sun.awt.AppContext ThreadGroup, see getCachedThreadGrou...
final AbstractGraphicsConfiguration getGraphicsConfiguration()
Returns the graphics configuration corresponding to this window.
final boolean hasPixelScaleChanged()
Returns and clears the hasPixelScaleChanged flag, as set via lockSurface().
final int getY()
Returns the current y position of the top-left corner of the client area relative to it's parent in w...
abstract void invalidateNative(final long _offscreenSurfaceLayer)
final int[] convertToWindowUnits(final int[] pixelUnitsAndResult)
Converts the given pixel units into window units in place.
StringBuilder jawt2String(StringBuilder sb)
boolean setSurfaceScale(final float[] pixelScale)
Request a pixel scale in x- and y-direction for the associated NativeSurface, where size_in_pixel_uni...
final void attachSurfaceLayer(final long layerHandle)
Attach the offscreen layer to this offscreen layer surface.
final boolean updateLockedData(final JAWT_Rectangle jawtBounds, final GraphicsConfiguration gc)
Updates bounds and pixelScale.
final RectangleImmutable getJAWTSurfaceBounds()
final int getSurfaceHeight()
Returns the height of the client area excluding insets (window decorations) in pixel units.
abstract Point getLocationOnScreenNativeImpl(int x, int y)
final JAWT getJAWT()
Returns the underlying JAWT instance created @ lockSurface().
boolean surfaceSwap()
Provide a mechanism to utilize custom (pre-) swap surface code.
final int getWidth()
Returns the width of the client area excluding insets (window decorations) in window units.
void detachSurfaceLayerImpl(final long _offscreenSurfaceLayer)
final boolean canSetSurfaceScale()
Returns true if setSurfaceScale(float[]) is supported, otherwise false.For pure downstream scalable s...
abstract JAWT fetchJAWTImpl()
private void determineIfApplet() { boolean isApplet = false; // dummy Component c = component; while(...
boolean hasFocus()
Returns true if this native window owns the focus, otherwise false.
long getWindowHandle()
Returns the window handle for this NativeWindow.
static final String toHexString(final long l)
final long getDisplayHandle()
Convenience: Get display handle from AbstractGraphicsConfiguration .
final boolean isSurfaceLayerAttached()
Returns true if a surface layer is attached, otherwise false.
final float[] getCurrentSurfaceScale(final float[] result)
Returns the current pixel scale of the associated NativeSurface.
final void detachSurfaceLayer()
Detaches a previously attached offscreen layer from this offscreen layer surface.
final Rectangle getSurfaceBounds()
Returns a newly created Rectangle containing window's surface origin and size in pixel units.
final RecursiveLock getLock()
Returns the recursive lock object of this surface, which synchronizes multithreaded access.
JAWTWindow(final Object comp, final AbstractGraphicsConfiguration config)
Constructed by jogamp.nativewindow.NativeWindowFactoryImpl#getNativeWindow(Object,...
final int getScreenIndex()
Convenience: Get display handle from AbstractGraphicsConfiguration .
final Thread getSurfaceLockOwner()
Return the locking owner's Thread, or null if not locked.
long getSurfaceHandle()
Returns the handle to the surface for this NativeSurface.
Point getLocationOnScreenNative(final Point storage)
final boolean isApplet()
Return false since there is no more java.applet.Applet support.
abstract int lockSurfaceImpl(GraphicsConfiguration gc)
final boolean setCursor(final PixelRectangle pixelrect, final PointImmutable hotSpot)
Optional method setting cursor in the corresponding on-screen surface/window, if exists.
final boolean hideCursor()
Optional method hiding the cursor in the corresponding on-screen surface/window, if exists.
void addSurfaceUpdatedListener(final SurfaceUpdatedListener l)
Appends the given SurfaceUpdatedListener to the end of the list.
Point getLocationOnScreen(final Point storage)
Returns the window's top-left client-area position in the screen.If Point is not null,...
void destroy()
Destroys this window incl.
final long getAttachedSurfaceLayer()
Returns the attached surface layer or null if none is attached.
final boolean isOffscreenLayerSurfaceEnabled()
Returns true if this instance uses an offscreen layer, otherwise false.
final int getHeight()
Returns the height of the client area excluding insets (window decorations) in window units.
final int lockSurface()
Lock the surface of this native window.
final float[] getRequestedSurfaceScale(final float[] result)
Returns the requested pixel scale of the associated NativeSurface.If canSetSurfaceScale() returns fal...
final Rectangle getBounds()
Returns a newly created Rectangle containing window origin, getX() & getY(), and size,...
static final String toHexString(final int i)
final void setChosenCapabilities(final CapabilitiesImmutable caps)
Sets the capabilities of this instance, allowing upstream API's to refine it, i.e.
void removeSurfaceUpdatedListener(final SurfaceUpdatedListener l)
Remove the specified SurfaceUpdatedListener from the list.
float[] getMinimumSurfaceScale(final float[] result)
Returns the minimum pixel scale of the associated NativeSurface.the passed storage containing the min...
final int getX()
Returns the current x position of this window, relative to it's parent.
void layoutSurfaceLayerImpl(final boolean visible)
Layout the offscreen layer according to the implementing class's constraints.
void setShallUseOffscreenLayer(final boolean v)
Request an offscreen layer, if supported.
final int getSurfaceWidth()
Returns the width of the client area excluding insets (window decorations) in pixel units.
void surfaceUpdated(final Object updater, final NativeSurface ns, final long when)
Notification of a surface update event, eg.
final AWTGraphicsConfiguration getAWTGraphicsConfiguration()
Return the current AWTGraphicsConfiguration instance, which also holds its upstream component's Graph...
void addSurfaceUpdatedListener(final int index, final SurfaceUpdatedListener l)
Inserts the given SurfaceUpdatedListener at the specified position in the list.
final boolean getShallUseOffscreenLayer()
Returns the property set by setShallUseOffscreenLayer(boolean).
final float[] getMaximumSurfaceScale(final float[] result)
Returns the maximum pixel scale of the associated NativeSurface.The maximum pixel scale maybe used to...
final NativeSurface getNativeSurface()
Returns the associated NativeSurface of this NativeSurfaceHolder.Returns this instance,...
final void unlockSurface()
Unlock the surface of this native window.
final InsetsImmutable getInsets()
Returns the insets defined as the width and height of the window decoration on the left,...
final boolean updatePixelScale(final GraphicsConfiguration gc, final boolean clearFlag)
Updates the minimum and maximum pixel-scale values and returns true if they were updated.
final int[] convertToPixelUnits(final int[] windowUnitsAndResult)
Converts the given window units into pixel units in place.
void attachSurfaceLayerImpl(final long _offscreenSurfaceLayer)
final boolean isSurfaceLockedByOtherThread()
Query if surface is locked by another thread, i.e.
final void setAWTGraphicsConfiguration(final AWTGraphicsConfiguration config)
Set a new AWTGraphicsConfiguration instance, as required if upstream component's GraphicsConfiguratio...
Mutable insets representing rectangular window decoration insets on all four edges in window units.
Definition: Insets.java:35
final void set(final int left, final int right, final int top, final int bottom)
Set the inset values of this instance in window units.
Definition: Insets.java:86
final Point translate(final Point pd)
Translate this instance's x- and y-components, i.e.
Definition: Point.java:131
final Rectangle set(final int x, final int y, final int width, final int height)
Definition: Rectangle.java:76
boolean equals(final Object obj)
Checks whether two rect objects are equal.
Definition: Rectangle.java:258
A marker interface describing a graphics configuration, visual, or pixel format in a toolkit-independ...
AbstractGraphicsScreen getScreen()
Return the screen this graphics configuration is valid for.
A interface describing a graphics device in a toolkit-independent manner.
void lock()
Optionally locking the device, utilizing eg com.jogamp.nativewindow.ToolkitLock#lock().
void unlock()
Optionally unlocking the device, utilizing eg com.jogamp.nativewindow.ToolkitLock#unlock().
long getHandle()
Returns the native handle of the underlying native device, if such thing exist.
int getIndex()
Returns the screen index this graphics screen is valid for.
AbstractGraphicsDevice getDevice()
Return the device this graphics configuration is valid for.
Specifies an immutable set of capabilities that a window's rendering context must support,...
Provides low-level information required for hardware-accelerated rendering using a surface in a platf...
static final int LOCK_SURFACE_NOT_READY
Returned by lockSurface() if the surface is not ready to be locked, {@value}.
static final int LOCK_SURFACE_CHANGED
Returned by lockSurface() if the surface is locked, but has changed, {@value}.
static final int LOCK_SUCCESS
Returned by lockSurface() if the surface is locked, and is unchanged, {@value}.
Extend the NativeSurface interface with windowing information such as window-handle,...
Handling requests for using an OffscreenLayerSurface within the implementation.
Interface specifying the offscreen layer surface protocol.
Adding mutable surface pixel scale property to implementing class, usually to a NativeSurface impleme...
static final float IDENTITY_PIXELSCALE
Setting surface-pixel-scale of {@value}, results in same pixel- and window-units.
static final float AUTOMAX_PIXELSCALE
Setting surface-pixel-scale of {@value}, results in maximum platform dependent pixel-scale,...
Clients may add their SurfaceUpdateListener implementation to a com.jogamp.nativewindow....
Immutable insets representing rectangular window decoration insets on all four edges in window units.
Pixel Rectangle identified by it's hashCode().
Immutable Rectangle interface, with its position on the top-left.