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