Jogamp
d235a2a29dba7ff4594f6d7e52d946ac9e2307d8
[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 int[] setSurfaceScale(final int[] result, final int[] pixelScale) {
281       SurfaceScaleUtils.validateReqPixelScale(reqPixelScale, pixelScale, DEBUG ? getClass().getSimpleName() : null);
282       if( null != result ) {
283           System.arraycopy(reqPixelScale, 0, result, 0, 2);
284       }
285       return result;
286   }
287
288   @Override
289   public final int[] getSurfaceScale(final int[] result) {
290       System.arraycopy(hasPixelScale, 0, result, 0, 2);
291       return result;
292   }
293
294   /**
295    * Updates bounds and pixelScale
296    * @return true if bounds or pixelScale has changed, otherwise false
297    */
298   protected final boolean updateLockedData(JAWT_Rectangle jawtBounds) {
299     final Rectangle jb = new Rectangle(jawtBounds.getX(), jawtBounds.getY(), jawtBounds.getWidth(), jawtBounds.getHeight());
300     final boolean changedBounds = !bounds.equals(jb);
301
302     if( changedBounds ) {
303         if( DEBUG ) {
304             System.err.println("JAWTWindow.updateBounds: "+bounds+" -> "+jb);
305         }
306         bounds.set(jawtBounds.getX(), jawtBounds.getY(), jawtBounds.getWidth(), jawtBounds.getHeight());
307
308         if(component instanceof Container) {
309             final java.awt.Insets contInsets = ((Container)component).getInsets();
310             insets.set(contInsets.left, contInsets.right, contInsets.top, contInsets.bottom);
311         }
312     }
313
314     return updatePixelScale() || changedBounds;
315   }
316
317   /**
318    * Update pixelScale
319    * @return true if pixelScale has changed, otherwise false
320    */
321   protected final boolean updatePixelScale() {
322     final int[] pixelScaleInt;
323     {
324         final int ps = JAWTUtil.getPixelScale(config.getAWTGraphicsConfiguration());
325         pixelScaleInt = new int[] { ps, ps };
326     }
327     return SurfaceScaleUtils.computePixelScale(hasPixelScale, hasPixelScale, reqPixelScale, pixelScaleInt, DEBUG ? getClass().getSimpleName() : null);
328   }
329
330   /** @return the JAWT_DrawingSurfaceInfo's (JAWT_Rectangle) bounds, updated with lock */
331   public final RectangleImmutable getBounds() { return bounds; }
332
333   /** @return the safe pixelScale value for x-direction, i.e. never negative or zero. Updated with lock. */
334   protected final int getPixelScaleX() { return hasPixelScale[0]; }
335
336   /** @return the safe pixelScale value for y-direction, i.e. never negative or zero. Updated with lock. */
337   protected final int getPixelScaleY() { return hasPixelScale[1]; }
338
339   @Override
340   public final InsetsImmutable getInsets() { return insets; }
341
342   public final Component getAWTComponent() {
343     return component;
344   }
345
346   /**
347    * Returns true if the AWT component is parented to an {@link java.applet.Applet},
348    * otherwise false. This information is valid only after {@link #lockSurface()}.
349    */
350   public final boolean isApplet() {
351       return isApplet;
352   }
353
354   /** Returns the underlying JAWT instance created @ {@link #lockSurface()}. */
355   public final JAWT getJAWT() {
356       return jawt;
357   }
358
359   //
360   // OffscreenLayerOption
361   //
362
363   @Override
364   public void setShallUseOffscreenLayer(boolean v) {
365       shallUseOffscreenLayer = v;
366   }
367
368   @Override
369   public final boolean getShallUseOffscreenLayer() {
370       return shallUseOffscreenLayer;
371   }
372
373   @Override
374   public final boolean isOffscreenLayerSurfaceEnabled() {
375       return isOffscreenLayerSurface;
376   }
377
378   //
379   // OffscreenLayerSurface
380   //
381
382   @Override
383   public final void attachSurfaceLayer(final long layerHandle) throws NativeWindowException {
384       if( !isOffscreenLayerSurfaceEnabled() ) {
385           throw new NativeWindowException("Not an offscreen layer surface");
386       }
387       attachSurfaceLayerImpl(layerHandle);
388       offscreenSurfaceLayer = layerHandle;
389       appContextInfo.invokeOnAppContextThread(false /* waitUntilDone */, repaintTask, "Repaint");
390   }
391   private final Runnable repaintTask = new Runnable() {
392           @Override
393           public void run() {
394               final Component c = component;
395               if( DEBUG ) {
396                   System.err.println("Bug 1004: RepaintTask on "+Thread.currentThread()+": Has Comp "+(null != c));
397               }
398               if( null != c ) {
399                   c.repaint();
400               }
401           } };
402
403   protected void attachSurfaceLayerImpl(final long layerHandle) {
404       throw new UnsupportedOperationException("offscreen layer not supported");
405   }
406
407   /**
408    * Layout the offscreen layer according to the implementing class's constraints.
409    * <p>
410    * This method allows triggering a re-layout of the offscreen surface
411    * in case the implementation requires it.
412    * </p>
413    * <p>
414    * Call this method if any parent or ancestor's layout has been changed,
415    * which could affects the layout of this surface.
416    * </p>
417    * @see #isOffscreenLayerSurfaceEnabled()
418    * @throws NativeWindowException if {@link #isOffscreenLayerSurfaceEnabled()} == false
419    */
420   protected void layoutSurfaceLayerImpl(long layerHandle, boolean visible) {}
421
422   private final void layoutSurfaceLayerIfEnabled(boolean visible) throws NativeWindowException {
423       if( isOffscreenLayerSurfaceEnabled() && 0 != offscreenSurfaceLayer ) {
424           layoutSurfaceLayerImpl(offscreenSurfaceLayer, visible);
425       }
426   }
427
428
429   @Override
430   public final void detachSurfaceLayer() throws NativeWindowException {
431       if( 0 == offscreenSurfaceLayer) {
432           throw new NativeWindowException("No offscreen layer attached: "+this);
433       }
434       if(DEBUG) {
435         System.err.println("JAWTWindow.detachSurfaceHandle(): osh "+toHexString(offscreenSurfaceLayer));
436       }
437       detachSurfaceLayerImpl(offscreenSurfaceLayer, detachSurfaceLayerNotify);
438   }
439   private final Runnable detachSurfaceLayerNotify = new Runnable() {
440     @Override
441     public void run() {
442         offscreenSurfaceLayer = 0;
443     }
444   };
445
446   /**
447    * @param detachNotify Runnable to be called before native detachment
448    */
449   protected void detachSurfaceLayerImpl(final long layerHandle, final Runnable detachNotify) {
450       throw new UnsupportedOperationException("offscreen layer not supported");
451   }
452
453
454   @Override
455   public final long getAttachedSurfaceLayer() {
456       return offscreenSurfaceLayer;
457   }
458
459   @Override
460   public final boolean isSurfaceLayerAttached() {
461       return 0 != offscreenSurfaceLayer;
462   }
463
464   @Override
465   public final void setChosenCapabilities(CapabilitiesImmutable caps) {
466       ((MutableGraphicsConfiguration)getGraphicsConfiguration()).setChosenCapabilities(caps);
467       config.setChosenCapabilities(caps);
468   }
469
470   @Override
471   public final RecursiveLock getLock() {
472       return surfaceLock;
473   }
474
475   @Override
476   public final boolean setCursor(final PixelRectangle pixelrect, final PointImmutable hotSpot) {
477       AWTEDTExecutor.singleton.invoke(false, new Runnable() {
478           public void run() {
479               Cursor c = null;
480               if( null == pixelrect || null == hotSpot ) {
481                   c = Cursor.getDefaultCursor();
482               } else {
483                   final java.awt.Point awtHotspot = new java.awt.Point(hotSpot.getX(), hotSpot.getY());
484                   try {
485                       c = AWTMisc.getCursor(pixelrect, awtHotspot);
486                   } catch (Exception e) {
487                       e.printStackTrace();
488                   }
489               }
490               if( null != c ) {
491                   component.setCursor(c);
492               }
493           } } );
494       return true;
495   }
496
497   @Override
498   public final boolean hideCursor() {
499       AWTEDTExecutor.singleton.invoke(false, new Runnable() {
500           public void run() {
501               final Cursor cursor = AWTMisc.getNullCursor();
502               if( null != cursor ) {
503                   component.setCursor(cursor);
504               }
505           } } );
506       return true;
507   }
508
509   //
510   // NativeSurface
511   //
512
513   private void determineIfApplet() {
514     Component c = component;
515     while(!isApplet && null != c) {
516         isApplet = c instanceof Applet;
517         c = c.getParent();
518     }
519   }
520
521   /**
522    * If JAWT offscreen layer is supported,
523    * implementation shall respect {@link #getShallUseOffscreenLayer()}
524    * and may respect {@link #isApplet()}.
525    *
526    * @return The JAWT instance reflecting offscreen layer support, etc.
527    *
528    * @throws NativeWindowException
529    */
530   protected abstract JAWT fetchJAWTImpl() throws NativeWindowException;
531   protected abstract int lockSurfaceImpl() throws NativeWindowException;
532
533   protected void dumpJAWTInfo() {
534       System.err.println(jawt2String(null).toString());
535       // Thread.dumpStack();
536   }
537
538   @Override
539   public final int lockSurface() throws NativeWindowException, RuntimeException  {
540     surfaceLock.lock();
541     int res = surfaceLock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ?
542
543     if ( LOCK_SURFACE_NOT_READY == res ) {
544         if( !component.isDisplayable() ) {
545             // W/o native peer, we cannot utilize JAWT for locking.
546             surfaceLock.unlock();
547             if(DEBUG) {
548                 System.err.println("JAWTWindow: Can't lock surface, component peer n/a. Component displayable "+component.isDisplayable()+", "+component);
549                 Thread.dumpStack();
550             }
551         } else {
552             determineIfApplet();
553             try {
554                 final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice();
555                 adevice.lock();
556                 try {
557                     if(null == jawt) { // no need to re-fetch for each frame
558                         jawt = fetchJAWTImpl();
559                         isOffscreenLayerSurface = JAWTUtil.isJAWTUsingOffscreenLayer(jawt);
560                     }
561                     res = lockSurfaceImpl();
562                     if(LOCK_SUCCESS == res && drawable_old != drawable) {
563                         res = LOCK_SURFACE_CHANGED;
564                         if(DEBUG) {
565                             System.err.println("JAWTWindow: surface change "+toHexString(drawable_old)+" -> "+toHexString(drawable));
566                             // Thread.dumpStack();
567                         }
568                     }
569                 } finally {
570                     if (LOCK_SURFACE_NOT_READY >= res) {
571                         adevice.unlock();
572                     }
573                 }
574             } finally {
575                 if (LOCK_SURFACE_NOT_READY >= res) {
576                     surfaceLock.unlock();
577                 }
578             }
579         }
580     }
581     return res;
582   }
583
584   protected abstract void unlockSurfaceImpl() throws NativeWindowException;
585
586   @Override
587   public final void unlockSurface() {
588     surfaceLock.validateLocked();
589     drawable_old = drawable;
590
591     if (surfaceLock.getHoldCount() == 1) {
592         final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice();
593         try {
594             if(null != jawt) {
595                 unlockSurfaceImpl();
596             }
597         } finally {
598             adevice.unlock();
599         }
600     }
601     surfaceLock.unlock();
602   }
603
604   @Override
605   public final boolean isSurfaceLockedByOtherThread() {
606     return surfaceLock.isLockedByOtherThread();
607   }
608
609   @Override
610   public final Thread getSurfaceLockOwner() {
611     return surfaceLock.getOwner();
612   }
613
614   @Override
615   public boolean surfaceSwap() {
616     return false;
617   }
618
619   @Override
620   public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) {
621       surfaceUpdatedHelper.addSurfaceUpdatedListener(l);
622   }
623
624   @Override
625   public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException {
626       surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l);
627   }
628
629   @Override
630   public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) {
631       surfaceUpdatedHelper.removeSurfaceUpdatedListener(l);
632   }
633
634   @Override
635   public void surfaceUpdated(Object updater, NativeSurface ns, long when) {
636       surfaceUpdatedHelper.surfaceUpdated(updater, ns, when);
637   }
638
639   @Override
640   public long getSurfaceHandle() {
641     return drawable;
642   }
643
644   @Override
645   public final AbstractGraphicsConfiguration getGraphicsConfiguration() {
646     return config.getNativeGraphicsConfiguration();
647   }
648
649   @Override
650   public final long getDisplayHandle() {
651     return getGraphicsConfiguration().getScreen().getDevice().getHandle();
652   }
653
654   @Override
655   public final int getScreenIndex() {
656     return getGraphicsConfiguration().getScreen().getIndex();
657   }
658
659   @Override
660   public final int getSurfaceWidth() {
661     return getWidth() * getPixelScaleX();
662   }
663
664   @Override
665   public final int getSurfaceHeight() {
666     return getHeight() * getPixelScaleY();
667   }
668
669   @Override
670   public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) {
671       pixelUnitsAndResult[0] /= getPixelScaleX();
672       pixelUnitsAndResult[1] /= getPixelScaleY();
673       return pixelUnitsAndResult;
674   }
675
676   @Override
677   public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) {
678       windowUnitsAndResult[0] *= getPixelScaleX();
679       windowUnitsAndResult[1] *= getPixelScaleY();
680       return windowUnitsAndResult;
681   }
682
683   @Override
684   public final NativeSurface getNativeSurface() { return this; }
685
686   //
687   // NativeWindow
688   //
689
690   @Override
691   public final int getWidth() {
692       return component.getWidth();
693   }
694
695   @Override
696   public final int getHeight() {
697       return component.getHeight();
698   }
699
700   @Override
701   public void destroy() {
702     surfaceLock.lock();
703     try {
704         if(DEBUG) {
705             System.err.println(jawtStr()+".destroy @ Thread "+getThreadName());
706         }
707         jawtComponentListener.detach();
708         invalidate();
709     } finally {
710         surfaceLock.unlock();
711     }
712   }
713
714   @Override
715   public final NativeWindow getParent() {
716       return null;
717   }
718
719   @Override
720   public long getWindowHandle() {
721     return drawable;
722   }
723
724   @Override
725   public final int getX() {
726       return component.getX();
727   }
728
729   @Override
730   public final int getY() {
731       return component.getY();
732   }
733
734   /**
735    * {@inheritDoc}
736    *
737    * <p>
738    * This JAWT default implementation is currently still using
739    * a blocking implementation. It first attempts to retrieve the location
740    * via a native implementation. If this fails, it tries the blocking AWT implementation.
741    * If the latter fails due to an external AWT tree-lock, the non block
742    * implementation {@link #getLocationOnScreenNonBlocking(Point, Component)} is being used.
743    * The latter simply traverse up to the AWT component tree and sums the rel. position.
744    * We have to determine whether the latter is good enough for all cases,
745    * currently only OS X utilizes the non blocking method per default.
746    * </p>
747    */
748   @Override
749   public Point getLocationOnScreen(Point storage) {
750       Point los = getLocationOnScreenNative(storage);
751       if(null == los) {
752           if(!Thread.holdsLock(component.getTreeLock())) {
753               // avoid deadlock ..
754               if(DEBUG) {
755                   System.err.println("Warning: JAWT Lock hold, but not the AWT tree lock: "+this);
756                   Thread.dumpStack();
757               }
758               if( null == storage ) {
759                   storage = new Point();
760               }
761               getLocationOnScreenNonBlocking(storage, component);
762               return storage;
763           }
764           java.awt.Point awtLOS = component.getLocationOnScreen();
765           if(null!=storage) {
766               los = storage.translate(awtLOS.x, awtLOS.y);
767           } else {
768               los = new Point(awtLOS.x, awtLOS.y);
769           }
770       }
771       return los;
772   }
773
774   protected Point getLocationOnScreenNative(Point storage) {
775       int lockRes = lockSurface();
776       if(LOCK_SURFACE_NOT_READY == lockRes) {
777           if(DEBUG) {
778               System.err.println("Warning: JAWT Lock couldn't be acquired: "+this);
779               Thread.dumpStack();
780           }
781           return null;
782       }
783       try {
784           Point d = getLocationOnScreenNativeImpl(0, 0);
785           if(null!=d) {
786             if(null!=storage) {
787                 storage.translate(d.getX(),d.getY());
788                 return storage;
789             }
790           }
791           return d;
792       } finally {
793           unlockSurface();
794       }
795   }
796   protected abstract Point getLocationOnScreenNativeImpl(int x, int y);
797
798   protected static Component getLocationOnScreenNonBlocking(Point storage, Component comp) {
799       final java.awt.Insets insets = new java.awt.Insets(0, 0, 0, 0); // DEBUG
800       Component last = null;
801       while(null != comp) {
802           final int dx = comp.getX();
803           final int dy = comp.getY();
804           if( DEBUG ) {
805               final java.awt.Insets ins = AWTMisc.getInsets(comp, false);
806               if( null != ins ) {
807                   insets.bottom += ins.bottom;
808                   insets.top += ins.top;
809                   insets.left += ins.left;
810                   insets.right += ins.right;
811               }
812               System.err.print("LOS: "+storage+" + "+comp.getClass().getName()+"["+dx+"/"+dy+", vis "+comp.isVisible()+", ins "+ins+" -> "+insets+"] -> ");
813           }
814           storage.translate(dx, dy);
815           if( DEBUG ) {
816               System.err.println(storage);
817           }
818           last = comp;
819           if( comp instanceof Window ) { // top-level heavy-weight ?
820               break;
821           }
822           comp = comp.getParent();
823       }
824       return last;
825   }
826
827   @Override
828   public boolean hasFocus() {
829       return component.hasFocus();
830   }
831
832   protected StringBuilder jawt2String(StringBuilder sb) {
833       if( null == sb ) {
834           sb = new StringBuilder();
835       }
836       sb.append("JVM version: ").append(Platform.JAVA_VERSION).append(" (").
837       append(Platform.JAVA_VERSION_NUMBER).
838       append(" update ").append(Platform.JAVA_VERSION_UPDATE).append(")").append(Platform.getNewline());
839       if(null != jawt) {
840           sb.append("JAWT version: ").append(toHexString(jawt.getCachedVersion())).
841           append(", CA_LAYER: ").append(JAWTUtil.isJAWTUsingOffscreenLayer(jawt)).
842           append(", isLayeredSurface ").append(isOffscreenLayerSurfaceEnabled()).
843           append(", bounds ").append(bounds).append(", insets ").append(insets).
844           append(", pixelScale ").append(getPixelScaleX()).append("x").append(getPixelScaleY());
845       } else {
846           sb.append("JAWT n/a, bounds ").append(bounds).append(", insets ").append(insets);
847       }
848       return sb;
849   }
850
851   @Override
852   public String toString() {
853     StringBuilder sb = new StringBuilder();
854
855     sb.append(jawtStr()+"[");
856     jawt2String(sb);
857     sb.append(  ", shallUseOffscreenLayer "+shallUseOffscreenLayer+", isOffscreenLayerSurface "+isOffscreenLayerSurface+
858                 ", attachedSurfaceLayer "+toHexString(getAttachedSurfaceLayer())+
859                 ", windowHandle "+toHexString(getWindowHandle())+
860                 ", surfaceHandle "+toHexString(getSurfaceHandle())+
861                 ", bounds "+bounds+", insets "+insets
862                 );
863     sb.append(", window ["+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+
864              "], pixels[s "+getPixelScaleX()+"x"+getPixelScaleY()+" -> "+getSurfaceWidth()+"x"+getSurfaceHeight()+"]"+
865               ", visible "+component.isVisible());
866     sb.append(", lockedExt "+isSurfaceLockedByOtherThread()+
867               ",\n\tconfig "+config+
868               ",\n\tawtComponent "+getAWTComponent()+
869               ",\n\tsurfaceLock "+surfaceLock+"]");
870
871     return sb.toString();
872   }
873
874   protected static final String toHexString(final long l) {
875       return "0x"+Long.toHexString(l);
876   }
877   protected static final String toHexString(final int i) {
878       return "0x"+Integer.toHexString(i);
879   }
880
881 }
http://JogAmp.org git info: FAQ, tutorial and man pages.