Jogamp
Bug 741 HiDPI: Add ScalableSurface interface to get/set pixelScale w/ full OSX impl.
[jogl.git] / src / nativewindow / classes / com / jogamp / nativewindow / awt / JAWTWindow.java
1 /*
2  * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
3  * Copyright (c) 2010 JogAmp Community. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * - Redistribution of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * - Redistribution in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of Sun Microsystems, Inc. or the names of
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * This software is provided "AS IS," without a warranty of any kind. ALL
21  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
22  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
23  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
24  * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
25  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
26  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
27  * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
28  * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
29  * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
30  * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
31  * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
32  *
33  * You acknowledge that this software is not designed or intended for use
34  * in the design, construction, operation or maintenance of any nuclear
35  * facility.
36  */
37
38 package com.jogamp.nativewindow.awt;
39
40 import com.jogamp.common.os.Platform;
41 import com.jogamp.common.util.awt.AWTEDTExecutor;
42 import com.jogamp.common.util.locks.LockFactory;
43 import com.jogamp.common.util.locks.RecursiveLock;
44 import com.jogamp.nativewindow.MutableGraphicsConfiguration;
45
46 import java.awt.Component;
47 import java.awt.Container;
48 import java.awt.Cursor;
49 import java.awt.Window;
50 import java.awt.event.ComponentEvent;
51 import java.awt.event.ComponentListener;
52 import java.awt.event.HierarchyEvent;
53 import java.awt.event.HierarchyListener;
54 import java.applet.Applet;
55
56 import javax.media.nativewindow.AbstractGraphicsConfiguration;
57 import javax.media.nativewindow.AbstractGraphicsDevice;
58 import javax.media.nativewindow.CapabilitiesImmutable;
59 import javax.media.nativewindow.NativeSurface;
60 import javax.media.nativewindow.NativeWindow;
61 import javax.media.nativewindow.NativeWindowException;
62 import javax.media.nativewindow.OffscreenLayerOption;
63 import javax.media.nativewindow.OffscreenLayerSurface;
64 import javax.media.nativewindow.ScalableSurface;
65 import javax.media.nativewindow.SurfaceUpdatedListener;
66 import javax.media.nativewindow.util.Insets;
67 import javax.media.nativewindow.util.InsetsImmutable;
68 import javax.media.nativewindow.util.PixelRectangle;
69 import javax.media.nativewindow.util.Point;
70 import javax.media.nativewindow.util.PointImmutable;
71 import javax.media.nativewindow.util.Rectangle;
72 import javax.media.nativewindow.util.RectangleImmutable;
73
74 import jogamp.nativewindow.SurfaceScaleUtils;
75 import jogamp.nativewindow.SurfaceUpdatedHelper;
76 import jogamp.nativewindow.awt.AWTMisc;
77 import jogamp.nativewindow.jawt.JAWT;
78 import jogamp.nativewindow.jawt.JAWTUtil;
79 import jogamp.nativewindow.jawt.JAWT_Rectangle;
80
81 public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, OffscreenLayerOption, ScalableSurface {
82   protected static final boolean DEBUG = JAWTUtil.DEBUG;
83
84   // user properties
85   protected boolean shallUseOffscreenLayer = false;
86
87   // lifetime: forever
88   protected final Component component;
89   private final AppContextInfo appContextInfo;
90   private final AWTGraphicsConfiguration config; // control access due to delegation
91   private final SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper();
92   private final RecursiveLock surfaceLock = LockFactory.createRecursiveLock();
93   private final JAWTComponentListener jawtComponentListener;
94
95   // lifetime: valid after lock but may change with each 1st lock, purges after invalidate
96   private boolean isApplet;
97   private JAWT jawt;
98   private boolean isOffscreenLayerSurface;
99   protected long drawable;
100   protected Rectangle bounds;
101   protected Insets insets;
102   private volatile long offscreenSurfaceLayer;
103
104   private volatile int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
105   protected final int[] reqPixelScale = new int[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
106
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(Object comp, AbstractGraphicsConfiguration config) {
117     if (config == null) {
118         throw new NativeWindowException("Error: AbstractGraphicsConfiguration is null");
119     }
120     if(! ( config instanceof AWTGraphicsConfiguration ) ) {
121         throw new NativeWindowException("Error: AbstractGraphicsConfiguration is not an AWTGraphicsConfiguration: "+config);
122     }
123     appContextInfo = new AppContextInfo("<init>");
124     this.component = (Component)comp;
125     this.config = (AWTGraphicsConfiguration) config;
126     this.jawtComponentListener = new JAWTComponentListener();
127     invalidate();
128     this.isApplet = false;
129     this.offscreenSurfaceLayer = 0;
130   }
131   private static String id(Object obj) { return ( null!=obj ? toHexString(obj.hashCode()) : "nil" ); }
132   private String jawtStr() { return "JAWTWindow["+id(JAWTWindow.this)+"]"; }
133
134   private class JAWTComponentListener implements ComponentListener, HierarchyListener {
135         private boolean isShowing;
136
137         private String str(final Object obj) {
138             if( null == obj ) {
139                 return "0xnil: null";
140             } else if( obj instanceof Component ) {
141                 final Component c = (Component)obj;
142                 return id(obj)+": "+c.getClass().getSimpleName()+"[visible "+c.isVisible()+", showing "+c.isShowing()+", valid "+c.isValid()+
143                         ", displayable "+c.isDisplayable()+", "+c.getX()+"/"+c.getY()+" "+c.getWidth()+"x"+c.getHeight()+"]";
144             } else {
145                 return id(obj)+": "+obj.getClass().getSimpleName()+"[..]";
146             }
147         }
148         private String s(final ComponentEvent e) {
149             return "visible[isShowing "+isShowing+"],"+Platform.getNewline()+
150                    "    ** COMP "+str(e.getComponent())+Platform.getNewline()+
151                    "    ** SOURCE "+str(e.getSource())+Platform.getNewline()+
152                    "    ** THIS "+str(component)+Platform.getNewline()+
153                    "    ** THREAD "+getThreadName();
154         }
155         private String s(final HierarchyEvent e) {
156             return "visible[isShowing "+isShowing+"], changeBits 0x"+Long.toHexString(e.getChangeFlags())+Platform.getNewline()+
157                    "    ** COMP "+str(e.getComponent())+Platform.getNewline()+
158                    "    ** SOURCE "+str(e.getSource())+Platform.getNewline()+
159                    "    ** CHANGED "+str(e.getChanged())+Platform.getNewline()+
160                    "    ** CHANGEDPARENT "+str(e.getChangedParent())+Platform.getNewline()+
161                    "    ** THIS "+str(component)+Platform.getNewline()+
162                    "    ** THREAD "+getThreadName();
163         }
164         @Override
165         public final String toString() {
166             return "visible[isShowing "+isShowing+"],"+Platform.getNewline()+
167                    "    ** THIS "+str(component)+Platform.getNewline()+
168                    "    ** THREAD "+getThreadName();
169         }
170
171         private JAWTComponentListener() {
172             isShowing = component.isShowing();
173             AWTEDTExecutor.singleton.invoke(false, new Runnable() { // Bug 952: Avoid deadlock via AWTTreeLock acquisition ..
174                 @Override
175                 public void run() {
176                     if(DEBUG) {
177                         System.err.println(jawtStr()+".attach @ Thread "+getThreadName()+": "+JAWTComponentListener.this.toString());
178                     }
179                     component.addComponentListener(JAWTComponentListener.this);
180                     component.addHierarchyListener(JAWTComponentListener.this);
181                 } } );
182         }
183
184         private final void detach() {
185             AWTEDTExecutor.singleton.invoke(false, new Runnable() { // Bug 952: Avoid deadlock via AWTTreeLock acquisition ..
186                 @Override
187                 public void run() {
188                     if(DEBUG) {
189                         System.err.println(jawtStr()+".detach @ Thread "+getThreadName()+": "+JAWTComponentListener.this.toString());
190                     }
191                     component.removeComponentListener(JAWTComponentListener.this);
192                     component.removeHierarchyListener(JAWTComponentListener.this);
193                 } } );
194         }
195
196         @Override
197         public final void componentResized(ComponentEvent e) {
198             if(DEBUG) {
199                 System.err.println(jawtStr()+".componentResized: "+s(e));
200             }
201             layoutSurfaceLayerIfEnabled(isShowing);
202         }
203
204         @Override
205         public final void componentMoved(ComponentEvent e) {
206             if(DEBUG) {
207                 System.err.println(jawtStr()+".componentMoved: "+s(e));
208             }
209             layoutSurfaceLayerIfEnabled(isShowing);
210         }
211
212         @Override
213         public final void componentShown(ComponentEvent e) {
214             if(DEBUG) {
215                 System.err.println(jawtStr()+".componentShown: "+s(e));
216             }
217             layoutSurfaceLayerIfEnabled(isShowing);
218         }
219
220         @Override
221         public final void componentHidden(ComponentEvent e) {
222             if(DEBUG) {
223                 System.err.println(jawtStr()+".componentHidden: "+s(e));
224             }
225             layoutSurfaceLayerIfEnabled(isShowing);
226         }
227
228         @Override
229         public final void hierarchyChanged(HierarchyEvent e) {
230             final boolean wasShowing = isShowing;
231             isShowing = component.isShowing();
232             int action = 0;
233             if( 0 != ( java.awt.event.HierarchyEvent.SHOWING_CHANGED & e.getChangeFlags() ) ) {
234                 if( e.getChanged() != component && wasShowing != isShowing ) {
235                     // A parent component changed and caused a 'showing' state change,
236                     // propagate to offscreen-layer!
237                     layoutSurfaceLayerIfEnabled(isShowing);
238                     action = 1;
239                 }
240             }
241             if(DEBUG) {
242                 final java.awt.Component changed = e.getChanged();
243                 final boolean displayable = changed.isDisplayable();
244                 final boolean showing = changed.isShowing();
245                 System.err.println(jawtStr()+".hierarchyChanged: action "+action+", displayable "+displayable+", showing [changed "+showing+", comp "+isShowing+"], "+s(e));
246             }
247         }
248   }
249
250   private static String getThreadName() { return Thread.currentThread().getName(); }
251
252   protected synchronized void invalidate() {
253     if(DEBUG) {
254         System.err.println(jawtStr()+".invalidate() - "+jawtComponentListener.toString());
255         if( isSurfaceLayerAttached() ) {
256             System.err.println("OffscreenSurfaceLayer still attached: 0x"+Long.toHexString(offscreenSurfaceLayer));
257         }
258         // Thread.dumpStack();
259     }
260     invalidateNative();
261     jawt = null;
262     isOffscreenLayerSurface = false;
263     drawable= 0;
264     drawable_old = 0;
265     bounds = new Rectangle();
266     insets = new Insets();
267     hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
268     hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
269   }
270   protected abstract void invalidateNative();
271
272   /**
273    * {@inheritDoc}
274    * <p>
275    * Per default impl. only works for not yet {@link #isRealized() realized} instances,
276    * current exception OSX.
277    * </p>
278    */
279   @Override
280   public void setSurfaceScale(final int[] pixelScale) {
281       SurfaceScaleUtils.validateReqPixelScale(reqPixelScale, pixelScale, DEBUG ? getClass().getSimpleName() : null);
282   }
283
284   @Override
285   public final int[] getSurfaceScale(final int[] result) {
286       // 0 != drawable -> locked at least once !
287       System.arraycopy(0 != drawable ? hasPixelScale : reqPixelScale, 0, result, 0, 2);
288       return result;
289   }
290
291   /**
292    * Updates bounds and pixelScale
293    * @return true if bounds or pixelScale has changed, otherwise false
294    */
295   protected final boolean updateLockedData(JAWT_Rectangle jawtBounds) {
296     final Rectangle jb = new Rectangle(jawtBounds.getX(), jawtBounds.getY(), jawtBounds.getWidth(), jawtBounds.getHeight());
297     final boolean changedBounds = !bounds.equals(jb);
298
299     if( changedBounds ) {
300         if( DEBUG ) {
301             System.err.println("JAWTWindow.updateBounds: "+bounds+" -> "+jb);
302         }
303         bounds.set(jawtBounds.getX(), jawtBounds.getY(), jawtBounds.getWidth(), jawtBounds.getHeight());
304
305         if(component instanceof Container) {
306             final java.awt.Insets contInsets = ((Container)component).getInsets();
307             insets.set(contInsets.left, contInsets.right, contInsets.top, contInsets.bottom);
308         }
309     }
310
311     return updatePixelScale() || changedBounds;
312   }
313
314   /**
315    * Update pixelScale
316    * @return true if pixelScale has changed, otherwise false
317    */
318   protected final boolean updatePixelScale() {
319     final int[] pixelScaleInt;
320     {
321         final int ps = JAWTUtil.getPixelScale(config.getAWTGraphicsConfiguration());
322         pixelScaleInt = new int[] { ps, ps };
323     }
324     return SurfaceScaleUtils.computePixelScale(hasPixelScale, hasPixelScale, reqPixelScale, pixelScaleInt, DEBUG ? getClass().getSimpleName() : null);
325   }
326
327   /** @return the JAWT_DrawingSurfaceInfo's (JAWT_Rectangle) bounds, updated with lock */
328   public final RectangleImmutable getBounds() { return bounds; }
329
330   /** @return the safe pixelScale value for x-direction, i.e. never negative or zero. Updated with lock. */
331   protected final int getPixelScaleX() { return hasPixelScale[0]; }
332
333   /** @return the safe pixelScale value for y-direction, i.e. never negative or zero. Updated with lock. */
334   protected final int getPixelScaleY() { return hasPixelScale[1]; }
335
336   @Override
337   public final InsetsImmutable getInsets() { return insets; }
338
339   public final Component getAWTComponent() {
340     return component;
341   }
342
343   /**
344    * Returns true if the AWT component is parented to an {@link java.applet.Applet},
345    * otherwise false. This information is valid only after {@link #lockSurface()}.
346    */
347   public final boolean isApplet() {
348       return isApplet;
349   }
350
351   /** Returns the underlying JAWT instance created @ {@link #lockSurface()}. */
352   public final JAWT getJAWT() {
353       return jawt;
354   }
355
356   //
357   // OffscreenLayerOption
358   //
359
360   @Override
361   public void setShallUseOffscreenLayer(boolean v) {
362       shallUseOffscreenLayer = v;
363   }
364
365   @Override
366   public final boolean getShallUseOffscreenLayer() {
367       return shallUseOffscreenLayer;
368   }
369
370   @Override
371   public final boolean isOffscreenLayerSurfaceEnabled() {
372       return isOffscreenLayerSurface;
373   }
374
375   //
376   // OffscreenLayerSurface
377   //
378
379   @Override
380   public final void attachSurfaceLayer(final long layerHandle) throws NativeWindowException {
381       if( !isOffscreenLayerSurfaceEnabled() ) {
382           throw new NativeWindowException("Not an offscreen layer surface");
383       }
384       attachSurfaceLayerImpl(layerHandle);
385       offscreenSurfaceLayer = layerHandle;
386       appContextInfo.invokeOnAppContextThread(false /* waitUntilDone */, repaintTask, "Repaint");
387   }
388   private final Runnable repaintTask = new Runnable() {
389           @Override
390           public void run() {
391               final Component c = component;
392               if( DEBUG ) {
393                   System.err.println("Bug 1004: RepaintTask on "+Thread.currentThread()+": Has Comp "+(null != c));
394               }
395               if( null != c ) {
396                   c.repaint();
397               }
398           } };
399
400   protected void attachSurfaceLayerImpl(final long layerHandle) {
401       throw new UnsupportedOperationException("offscreen layer not supported");
402   }
403
404   /**
405    * Layout the offscreen layer according to the implementing class's constraints.
406    * <p>
407    * This method allows triggering a re-layout of the offscreen surface
408    * in case the implementation requires it.
409    * </p>
410    * <p>
411    * Call this method if any parent or ancestor's layout has been changed,
412    * which could affects the layout of this surface.
413    * </p>
414    * @see #isOffscreenLayerSurfaceEnabled()
415    * @throws NativeWindowException if {@link #isOffscreenLayerSurfaceEnabled()} == false
416    */
417   protected void layoutSurfaceLayerImpl(long layerHandle, boolean visible) {}
418
419   private final void layoutSurfaceLayerIfEnabled(boolean visible) throws NativeWindowException {
420       if( isOffscreenLayerSurfaceEnabled() && 0 != offscreenSurfaceLayer ) {
421           layoutSurfaceLayerImpl(offscreenSurfaceLayer, visible);
422       }
423   }
424
425
426   @Override
427   public final void detachSurfaceLayer() throws NativeWindowException {
428       if( 0 == offscreenSurfaceLayer) {
429           throw new NativeWindowException("No offscreen layer attached: "+this);
430       }
431       if(DEBUG) {
432         System.err.println("JAWTWindow.detachSurfaceHandle(): osh "+toHexString(offscreenSurfaceLayer));
433       }
434       detachSurfaceLayerImpl(offscreenSurfaceLayer, detachSurfaceLayerNotify);
435   }
436   private final Runnable detachSurfaceLayerNotify = new Runnable() {
437     @Override
438     public void run() {
439         offscreenSurfaceLayer = 0;
440     }
441   };
442
443   /**
444    * @param detachNotify Runnable to be called before native detachment
445    */
446   protected void detachSurfaceLayerImpl(final long layerHandle, final Runnable detachNotify) {
447       throw new UnsupportedOperationException("offscreen layer not supported");
448   }
449
450
451   @Override
452   public final long getAttachedSurfaceLayer() {
453       return offscreenSurfaceLayer;
454   }
455
456   @Override
457   public final boolean isSurfaceLayerAttached() {
458       return 0 != offscreenSurfaceLayer;
459   }
460
461   @Override
462   public final void setChosenCapabilities(CapabilitiesImmutable caps) {
463       ((MutableGraphicsConfiguration)getGraphicsConfiguration()).setChosenCapabilities(caps);
464       config.setChosenCapabilities(caps);
465   }
466
467   @Override
468   public final RecursiveLock getLock() {
469       return surfaceLock;
470   }
471
472   @Override
473   public final boolean setCursor(final PixelRectangle pixelrect, final PointImmutable hotSpot) {
474       AWTEDTExecutor.singleton.invoke(false, new Runnable() {
475           public void run() {
476               Cursor c = null;
477               if( null == pixelrect || null == hotSpot ) {
478                   c = Cursor.getDefaultCursor();
479               } else {
480                   final java.awt.Point awtHotspot = new java.awt.Point(hotSpot.getX(), hotSpot.getY());
481                   try {
482                       c = AWTMisc.getCursor(pixelrect, awtHotspot);
483                   } catch (Exception e) {
484                       e.printStackTrace();
485                   }
486               }
487               if( null != c ) {
488                   component.setCursor(c);
489               }
490           } } );
491       return true;
492   }
493
494   @Override
495   public final boolean hideCursor() {
496       AWTEDTExecutor.singleton.invoke(false, new Runnable() {
497           public void run() {
498               final Cursor cursor = AWTMisc.getNullCursor();
499               if( null != cursor ) {
500                   component.setCursor(cursor);
501               }
502           } } );
503       return true;
504   }
505
506   //
507   // NativeSurface
508   //
509
510   private void determineIfApplet() {
511     Component c = component;
512     while(!isApplet && null != c) {
513         isApplet = c instanceof Applet;
514         c = c.getParent();
515     }
516   }
517
518   /**
519    * If JAWT offscreen layer is supported,
520    * implementation shall respect {@link #getShallUseOffscreenLayer()}
521    * and may respect {@link #isApplet()}.
522    *
523    * @return The JAWT instance reflecting offscreen layer support, etc.
524    *
525    * @throws NativeWindowException
526    */
527   protected abstract JAWT fetchJAWTImpl() throws NativeWindowException;
528   protected abstract int lockSurfaceImpl() throws NativeWindowException;
529
530   protected void dumpJAWTInfo() {
531       System.err.println(jawt2String(null).toString());
532       // Thread.dumpStack();
533   }
534
535   @Override
536   public final int lockSurface() throws NativeWindowException, RuntimeException  {
537     surfaceLock.lock();
538     int res = surfaceLock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ?
539
540     if ( LOCK_SURFACE_NOT_READY == res ) {
541         if( !component.isDisplayable() ) {
542             // W/o native peer, we cannot utilize JAWT for locking.
543             surfaceLock.unlock();
544             if(DEBUG) {
545                 System.err.println("JAWTWindow: Can't lock surface, component peer n/a. Component displayable "+component.isDisplayable()+", "+component);
546                 Thread.dumpStack();
547             }
548         } else {
549             determineIfApplet();
550             try {
551                 final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice();
552                 adevice.lock();
553                 try {
554                     if(null == jawt) { // no need to re-fetch for each frame
555                         jawt = fetchJAWTImpl();
556                         isOffscreenLayerSurface = JAWTUtil.isJAWTUsingOffscreenLayer(jawt);
557                     }
558                     res = lockSurfaceImpl();
559                     if(LOCK_SUCCESS == res && drawable_old != drawable) {
560                         res = LOCK_SURFACE_CHANGED;
561                         if(DEBUG) {
562                             System.err.println("JAWTWindow: surface change "+toHexString(drawable_old)+" -> "+toHexString(drawable));
563                             // Thread.dumpStack();
564                         }
565                     }
566                 } finally {
567                     if (LOCK_SURFACE_NOT_READY >= res) {
568                         adevice.unlock();
569                     }
570                 }
571             } finally {
572                 if (LOCK_SURFACE_NOT_READY >= res) {
573                     surfaceLock.unlock();
574                 }
575             }
576         }
577     }
578     return res;
579   }
580
581   protected abstract void unlockSurfaceImpl() throws NativeWindowException;
582
583   @Override
584   public final void unlockSurface() {
585     surfaceLock.validateLocked();
586     drawable_old = drawable;
587
588     if (surfaceLock.getHoldCount() == 1) {
589         final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice();
590         try {
591             if(null != jawt) {
592                 unlockSurfaceImpl();
593             }
594         } finally {
595             adevice.unlock();
596         }
597     }
598     surfaceLock.unlock();
599   }
600
601   @Override
602   public final boolean isSurfaceLockedByOtherThread() {
603     return surfaceLock.isLockedByOtherThread();
604   }
605
606   @Override
607   public final Thread getSurfaceLockOwner() {
608     return surfaceLock.getOwner();
609   }
610
611   @Override
612   public boolean surfaceSwap() {
613     return false;
614   }
615
616   @Override
617   public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) {
618       surfaceUpdatedHelper.addSurfaceUpdatedListener(l);
619   }
620
621   @Override
622   public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException {
623       surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l);
624   }
625
626   @Override
627   public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) {
628       surfaceUpdatedHelper.removeSurfaceUpdatedListener(l);
629   }
630
631   @Override
632   public void surfaceUpdated(Object updater, NativeSurface ns, long when) {
633       surfaceUpdatedHelper.surfaceUpdated(updater, ns, when);
634   }
635
636   @Override
637   public long getSurfaceHandle() {
638     return drawable;
639   }
640
641   @Override
642   public final AbstractGraphicsConfiguration getGraphicsConfiguration() {
643     return config.getNativeGraphicsConfiguration();
644   }
645
646   @Override
647   public final long getDisplayHandle() {
648     return getGraphicsConfiguration().getScreen().getDevice().getHandle();
649   }
650
651   @Override
652   public final int getScreenIndex() {
653     return getGraphicsConfiguration().getScreen().getIndex();
654   }
655
656   @Override
657   public final int getSurfaceWidth() {
658     return getWidth() * getPixelScaleX();
659   }
660
661   @Override
662   public final int getSurfaceHeight() {
663     return getHeight() * getPixelScaleY();
664   }
665
666   @Override
667   public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) {
668       pixelUnitsAndResult[0] /= getPixelScaleX();
669       pixelUnitsAndResult[1] /= getPixelScaleY();
670       return pixelUnitsAndResult;
671   }
672
673   @Override
674   public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) {
675       windowUnitsAndResult[0] *= getPixelScaleX();
676       windowUnitsAndResult[1] *= getPixelScaleY();
677       return windowUnitsAndResult;
678   }
679
680   @Override
681   public final NativeSurface getNativeSurface() { return this; }
682
683   //
684   // NativeWindow
685   //
686
687   @Override
688   public final int getWidth() {
689       return component.getWidth();
690   }
691
692   @Override
693   public final int getHeight() {
694       return component.getHeight();
695   }
696
697   @Override
698   public void destroy() {
699     surfaceLock.lock();
700     try {
701         if(DEBUG) {
702             System.err.println(jawtStr()+".destroy @ Thread "+getThreadName());
703         }
704         jawtComponentListener.detach();
705         invalidate();
706     } finally {
707         surfaceLock.unlock();
708     }
709   }
710
711   @Override
712   public final NativeWindow getParent() {
713       return null;
714   }
715
716   @Override
717   public long getWindowHandle() {
718     return drawable;
719   }
720
721   @Override
722   public final int getX() {
723       return component.getX();
724   }
725
726   @Override
727   public final int getY() {
728       return component.getY();
729   }
730
731   /**
732    * {@inheritDoc}
733    *
734    * <p>
735    * This JAWT default implementation is currently still using
736    * a blocking implementation. It first attempts to retrieve the location
737    * via a native implementation. If this fails, it tries the blocking AWT implementation.
738    * If the latter fails due to an external AWT tree-lock, the non block
739    * implementation {@link #getLocationOnScreenNonBlocking(Point, Component)} is being used.
740    * The latter simply traverse up to the AWT component tree and sums the rel. position.
741    * We have to determine whether the latter is good enough for all cases,
742    * currently only OS X utilizes the non blocking method per default.
743    * </p>
744    */
745   @Override
746   public Point getLocationOnScreen(Point storage) {
747       Point los = getLocationOnScreenNative(storage);
748       if(null == los) {
749           if(!Thread.holdsLock(component.getTreeLock())) {
750               // avoid deadlock ..
751               if(DEBUG) {
752                   System.err.println("Warning: JAWT Lock hold, but not the AWT tree lock: "+this);
753                   Thread.dumpStack();
754               }
755               if( null == storage ) {
756                   storage = new Point();
757               }
758               getLocationOnScreenNonBlocking(storage, component);
759               return storage;
760           }
761           java.awt.Point awtLOS = component.getLocationOnScreen();
762           if(null!=storage) {
763               los = storage.translate(awtLOS.x, awtLOS.y);
764           } else {
765               los = new Point(awtLOS.x, awtLOS.y);
766           }
767       }
768       return los;
769   }
770
771   protected Point getLocationOnScreenNative(Point storage) {
772       int lockRes = lockSurface();
773       if(LOCK_SURFACE_NOT_READY == lockRes) {
774           if(DEBUG) {
775               System.err.println("Warning: JAWT Lock couldn't be acquired: "+this);
776               Thread.dumpStack();
777           }
778           return null;
779       }
780       try {
781           Point d = getLocationOnScreenNativeImpl(0, 0);
782           if(null!=d) {
783             if(null!=storage) {
784                 storage.translate(d.getX(),d.getY());
785                 return storage;
786             }
787           }
788           return d;
789       } finally {
790           unlockSurface();
791       }
792   }
793   protected abstract Point getLocationOnScreenNativeImpl(int x, int y);
794
795   protected static Component getLocationOnScreenNonBlocking(Point storage, Component comp) {
796       final java.awt.Insets insets = new java.awt.Insets(0, 0, 0, 0); // DEBUG
797       Component last = null;
798       while(null != comp) {
799           final int dx = comp.getX();
800           final int dy = comp.getY();
801           if( DEBUG ) {
802               final java.awt.Insets ins = AWTMisc.getInsets(comp, false);
803               if( null != ins ) {
804                   insets.bottom += ins.bottom;
805                   insets.top += ins.top;
806                   insets.left += ins.left;
807                   insets.right += ins.right;
808               }
809               System.err.print("LOS: "+storage+" + "+comp.getClass().getName()+"["+dx+"/"+dy+", vis "+comp.isVisible()+", ins "+ins+" -> "+insets+"] -> ");
810           }
811           storage.translate(dx, dy);
812           if( DEBUG ) {
813               System.err.println(storage);
814           }
815           last = comp;
816           if( comp instanceof Window ) { // top-level heavy-weight ?
817               break;
818           }
819           comp = comp.getParent();
820       }
821       return last;
822   }
823
824   @Override
825   public boolean hasFocus() {
826       return component.hasFocus();
827   }
828
829   protected StringBuilder jawt2String(StringBuilder sb) {
830       if( null == sb ) {
831           sb = new StringBuilder();
832       }
833       sb.append("JVM version: ").append(Platform.JAVA_VERSION).append(" (").
834       append(Platform.JAVA_VERSION_NUMBER).
835       append(" update ").append(Platform.JAVA_VERSION_UPDATE).append(")").append(Platform.getNewline());
836       if(null != jawt) {
837           sb.append("JAWT version: ").append(toHexString(jawt.getCachedVersion())).
838           append(", CA_LAYER: ").append(JAWTUtil.isJAWTUsingOffscreenLayer(jawt)).
839           append(", isLayeredSurface ").append(isOffscreenLayerSurfaceEnabled()).
840           append(", bounds ").append(bounds).append(", insets ").append(insets).
841           append(", pixelScale ").append(getPixelScaleX()).append("x").append(getPixelScaleY());
842       } else {
843           sb.append("JAWT n/a, bounds ").append(bounds).append(", insets ").append(insets);
844       }
845       return sb;
846   }
847
848   @Override
849   public String toString() {
850     StringBuilder sb = new StringBuilder();
851
852     sb.append(jawtStr()+"[");
853     jawt2String(sb);
854     sb.append(  ", shallUseOffscreenLayer "+shallUseOffscreenLayer+", isOffscreenLayerSurface "+isOffscreenLayerSurface+
855                 ", attachedSurfaceLayer "+toHexString(getAttachedSurfaceLayer())+
856                 ", windowHandle "+toHexString(getWindowHandle())+
857                 ", surfaceHandle "+toHexString(getSurfaceHandle())+
858                 ", bounds "+bounds+", insets "+insets
859                 );
860     sb.append(", window ["+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+
861              "], pixels[s "+getPixelScaleX()+"x"+getPixelScaleY()+" -> "+getSurfaceWidth()+"x"+getSurfaceHeight()+"]"+
862               ", visible "+component.isVisible());
863     sb.append(", lockedExt "+isSurfaceLockedByOtherThread()+
864               ",\n\tconfig "+config+
865               ",\n\tawtComponent "+getAWTComponent()+
866               ",\n\tsurfaceLock "+surfaceLock+"]");
867
868     return sb.toString();
869   }
870
871   protected static final String toHexString(final long l) {
872       return "0x"+Long.toHexString(l);
873   }
874   protected static final String toHexString(final int i) {
875       return "0x"+Integer.toHexString(i);
876   }
877
878 }
http://JogAmp.org git info: FAQ, tutorial and man pages.