Jogamp
12e574ced0509216fea3b927bf11d467eaf61be9
[jogl.git] / src / nativewindow / classes / jogamp / nativewindow / macosx / OSXUtil.java
1 /**
2  * Copyright 2011 JogAmp Community. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification, are
5  * permitted provided that the following conditions are met:
6  *
7  *    1. Redistributions of source code must retain the above copyright notice, this list of
8  *       conditions and the following disclaimer.
9  *
10  *    2. Redistributions in binary form must reproduce the above copyright notice, this list
11  *       of conditions and the following disclaimer in the documentation and/or other materials
12  *       provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  *
24  * The views and conclusions contained in the software and documentation are those of the
25  * authors and should not be interpreted as representing official policies, either expressed
26  * or implied, of JogAmp Community.
27  */
28 package jogamp.nativewindow.macosx;
29
30 import javax.media.nativewindow.NativeWindowException;
31 import javax.media.nativewindow.NativeWindowFactory;
32 import javax.media.nativewindow.util.Insets;
33 import javax.media.nativewindow.util.Point;
34
35 import com.jogamp.common.util.Function;
36 import com.jogamp.common.util.FunctionTask;
37 import com.jogamp.common.util.RunnableTask;
38
39 import jogamp.nativewindow.Debug;
40 import jogamp.nativewindow.NWJNILibLoader;
41 import jogamp.nativewindow.ToolkitProperties;
42
43 public class OSXUtil implements ToolkitProperties {
44     private static boolean isInit = false;
45     private static final boolean DEBUG = Debug.debug("OSXUtil");
46
47     /**
48      * Called by {@link NativeWindowFactory#initSingleton()}
49      * @see ToolkitProperties
50      */
51     public static synchronized void initSingleton() {
52       if(!isInit) {
53           if(DEBUG) {
54               System.out.println("OSXUtil.initSingleton()");
55           }
56           if(!NWJNILibLoader.loadNativeWindow("macosx")) {
57               throw new NativeWindowException("NativeWindow MacOSX native library load error.");
58           }
59
60           if( !initIDs0() ) {
61               throw new NativeWindowException("MacOSX: Could not initialized native stub");
62           }
63           isInit = true;
64       }
65     }
66
67     /**
68      * Called by {@link NativeWindowFactory#shutdown()}
69      * @see ToolkitProperties
70      */
71     public static void shutdown() { }
72
73     /**
74      * Called by {@link NativeWindowFactory#initSingleton()}
75      * @see ToolkitProperties
76      */
77     public static boolean requiresToolkitLock() { return false; }
78
79     /**
80      * Called by {@link NativeWindowFactory#initSingleton()}
81      * @see ToolkitProperties
82      */
83     public static final boolean hasThreadingIssues() { return false; }
84
85     public static boolean isNSView(long object) {
86         return 0 != object ? isNSView0(object) : false;
87     }
88
89     public static boolean isNSWindow(long object) {
90         return 0 != object ? isNSWindow0(object) : false;
91     }
92
93     /**
94      * @param windowOrView
95      * @param src_x
96      * @param src_y
97      * @return top-left client-area position in window units
98      */
99     public static Point GetLocationOnScreen(long windowOrView, int src_x, int src_y) {
100       return (Point) GetLocationOnScreen0(windowOrView, src_x, src_y);
101     }
102
103     public static Insets GetInsets(long windowOrView) {
104       return (Insets) GetInsets0(windowOrView);
105     }
106
107     public static double GetPixelScale(int screenIndex) {
108       return GetPixelScale0(screenIndex);
109     }
110
111     public static double GetPixelScale(long windowOrView) {
112       return GetPixelScale1(windowOrView);
113     }
114
115     public static long CreateNSWindow(int x, int y, int width, int height) {
116       return CreateNSWindow0(x, y, width, height);
117     }
118     public static void DestroyNSWindow(long nsWindow) {
119         DestroyNSWindow0(nsWindow);
120     }
121     public static long GetNSView(long nsWindow) {
122       return GetNSView0(nsWindow);
123     }
124     public static long GetNSWindow(long nsView) {
125       return GetNSWindow0(nsView);
126     }
127
128     /**
129      * Create a CALayer suitable to act as a root CALayer.
130      * @param width width of the CALayer in window units (points)
131      * @param height height of the CALayer in window units (points)
132      * @param contentsScale scale for HiDPI support: pixel-dim = window-dim x scale
133      * @return the new CALayer object
134      * @see #DestroyCALayer(long)
135      * @see #AddCASublayer(long, long)
136      */
137     public static long CreateCALayer(final int width, final int height, final float contentsScale) {
138       final long l = CreateCALayer0(width, height, contentsScale);
139       if(DEBUG) {
140           System.err.println("OSXUtil.CreateCALayer: 0x"+Long.toHexString(l)+" - "+Thread.currentThread().getName());
141       }
142       return l;
143     }
144
145     /**
146      * Attach a sub CALayer to the root CALayer
147      * <p>
148      * Method will trigger a <code>display</code>
149      * call to the CALayer hierarchy to enforce resource creation if required, e.g. an NSOpenGLContext.
150      * </p>
151      * <p>
152      * Hence it is important that related resources are not locked <i>if</i>
153      * they will be used for creation.
154      * </p>
155      * @param rootCALayer
156      * @param subCALayer
157      * @param x x-coord of the sub-CALayer in window units (points)
158      * @param y y-coord of the sub-CALayer in window units (points)
159      * @param width width of the sub-CALayer in window units (points)
160      * @param height height of the sub-CALayer in window units (points)
161      * @param contentsScale scale for HiDPI support: pixel-dim = window-dim x scale
162      * @param caLayerQuirks
163      * @see #CreateCALayer(int, int, float)
164      * @see #RemoveCASublayer(long, long, boolean)
165      */
166     public static void AddCASublayer(final long rootCALayer, final long subCALayer,
167                                      final int x, final int y, final int width, final int height,
168                                      final float contentsScale, final int caLayerQuirks) {
169         if(0==rootCALayer || 0==subCALayer) {
170             throw new IllegalArgumentException("rootCALayer 0x"+Long.toHexString(rootCALayer)+", subCALayer 0x"+Long.toHexString(subCALayer));
171         }
172         if(DEBUG) {
173             System.err.println("OSXUtil.AttachCALayer: caLayerQuirks "+caLayerQuirks+", 0x"+Long.toHexString(subCALayer)+" - "+Thread.currentThread().getName());
174         }
175         AddCASublayer0(rootCALayer, subCALayer, x, y, width, height, contentsScale, caLayerQuirks);
176     }
177
178     /**
179      * Fix root and sub CALayer position to 0/0 and size
180      * <p>
181      * If the sub CALayer implements the Objective-C NativeWindow protocol NWDedicatedSize (e.g. JOGL's MyNSOpenGLLayer),
182      * the dedicated size is passed to the layer, which propagates it appropriately.
183      * </p>
184      * <p>
185      * On OSX/Java7 our root CALayer's frame position and size gets corrupted by its NSView,
186      * hence we have created the NWDedicatedSize protocol.
187      * </p>
188      *
189      * @param rootCALayer the root surface layer, maybe null.
190      * @param subCALayer the client surface layer, maybe null.
191      * @param visible TODO
192      * @param width the expected width in window units (points)
193      * @param height the expected height in window units (points)
194      * @param caLayerQuirks TODO
195      */
196     public static void FixCALayerLayout(final long rootCALayer, final long subCALayer, final boolean visible, final int x, final int y, final int width, final int height, final int caLayerQuirks) {
197         if( 0==rootCALayer && 0==subCALayer ) {
198             return;
199         }
200         FixCALayerLayout0(rootCALayer, subCALayer, visible, x, y, width, height, caLayerQuirks);
201     }
202
203     /**
204      * Detach a sub CALayer from the root CALayer.
205      */
206     public static void RemoveCASublayer(final long rootCALayer, final long subCALayer) {
207         if(0==rootCALayer || 0==subCALayer) {
208             throw new IllegalArgumentException("rootCALayer 0x"+Long.toHexString(rootCALayer)+", subCALayer 0x"+Long.toHexString(subCALayer));
209         }
210         if(DEBUG) {
211             System.err.println("OSXUtil.DetachCALayer: 0x"+Long.toHexString(subCALayer)+" - "+Thread.currentThread().getName());
212         }
213         RemoveCASublayer0(rootCALayer, subCALayer);
214     }
215
216     /**
217      * Destroy a CALayer.
218      * @see #CreateCALayer(int, int, float)
219      */
220     public static void DestroyCALayer(final long caLayer) {
221         if(0==caLayer) {
222             throw new IllegalArgumentException("caLayer 0x"+Long.toHexString(caLayer));
223         }
224         if(DEBUG) {
225             System.err.println("OSXUtil.DestroyCALayer: 0x"+Long.toHexString(caLayer)+" - "+Thread.currentThread().getName());
226         }
227         DestroyCALayer0(caLayer);
228     }
229
230     /**
231      * Run on OSX UI main thread.
232      * <p>
233      * 'waitUntilDone' is implemented on Java site via lock/wait on {@link RunnableTask} to not freeze OSX main thread.
234      * </p>
235      *
236      * @param waitUntilDone
237      * @param runnable
238      */
239     public static void RunOnMainThread(boolean waitUntilDone, Runnable runnable) {
240         if( IsMainThread0() ) {
241             runnable.run(); // don't leave the JVM
242         } else {
243             // Utilize Java side lock/wait and simply pass the Runnable async to OSX main thread,
244             // otherwise we may freeze the OSX main thread.
245             Throwable throwable = null;
246             final Object sync = new Object();
247             final RunnableTask rt = new RunnableTask( runnable, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err );
248             synchronized(sync) {
249                 RunOnMainThread0(rt);
250                 if( waitUntilDone ) {
251                     try {
252                         sync.wait();
253                     } catch (InterruptedException ie) {
254                         throwable = ie;
255                     }
256                     if(null==throwable) {
257                         throwable = rt.getThrowable();
258                     }
259                     if(null!=throwable) {
260                         throw new RuntimeException(throwable);
261                     }
262                 }
263             }
264         }
265     }
266
267     /**
268      * Run later on ..
269      * @param onMain if true, run on main-thread, otherwise on the current OSX thread.
270      * @param runnable
271      * @param delay delay to run the runnable in milliseconds
272      */
273     public static void RunLater(boolean onMain, Runnable runnable, int delay) {
274         RunLater0(onMain, new RunnableTask( runnable, null, true, System.err ), delay);
275     }
276
277     private static Runnable _nop = new Runnable() { @Override public void run() {}; };
278
279     /** Issues a {@link #RunOnMainThread(boolean, Runnable)} w/ an <i>NOP</i> runnable, while waiting until done. */
280     public static void WaitUntilFinish() {
281         RunOnMainThread(true, _nop);
282     }
283
284     /**
285      * Run on OSX UI main thread.
286      * <p>
287      * 'waitUntilDone' is implemented on Java site via lock/wait on {@link FunctionTask} to not freeze OSX main thread.
288      * </p>
289      *
290      * @param waitUntilDone
291      * @param func
292      */
293     public static <R,A> R RunOnMainThread(boolean waitUntilDone, Function<R,A> func, A... args) {
294         if( IsMainThread0() ) {
295             return func.eval(args); // don't leave the JVM
296         } else {
297             // Utilize Java side lock/wait and simply pass the Runnable async to OSX main thread,
298             // otherwise we may freeze the OSX main thread.
299             Throwable throwable = null;
300             final Object sync = new Object();
301             final FunctionTask<R,A> rt = new FunctionTask<R,A>( func, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err );
302             synchronized(sync) {
303                 rt.setArgs(args);
304                 RunOnMainThread0(rt);
305                 if( waitUntilDone ) {
306                     try {
307                         sync.wait();
308                     } catch (InterruptedException ie) {
309                         throwable = ie;
310                     }
311                     if(null==throwable) {
312                         throwable = rt.getThrowable();
313                     }
314                     if(null!=throwable) {
315                         throw new RuntimeException(throwable);
316                     }
317                 }
318             }
319             return rt.getResult();
320         }
321     }
322
323     public static boolean IsMainThread() {
324         return IsMainThread0();
325     }
326
327     /** Returns the screen refresh rate in Hz. If unavailable, returns 60Hz. */
328     public static int GetScreenRefreshRate(int scrn_idx) {
329         return GetScreenRefreshRate0(scrn_idx);
330     }
331
332     /***
333     private static boolean  isAWTEDTMainThreadInit = false;
334     private static boolean  isAWTEDTMainThread;
335
336     public synchronized static boolean isAWTEDTMainThread() {
337         if(!isAWTEDTMainThreadInit) {
338             isAWTEDTMainThreadInit = true;
339             if(Platform.AWT_AVAILABLE) {
340                 AWTEDTExecutor.singleton.invoke(true, new Runnable() {
341                    public void run() {
342                        isAWTEDTMainThread = IsMainThread();
343                        System.err.println("XXX: "+Thread.currentThread().getName()+" - isAWTEDTMainThread "+isAWTEDTMainThread);
344                    }
345                 });
346             } else {
347                 isAWTEDTMainThread = false;
348             }
349         }
350         return isAWTEDTMainThread;
351     } */
352
353     private static native boolean initIDs0();
354     private static native boolean isNSView0(long object);
355     private static native boolean isNSWindow0(long object);
356     private static native Object GetLocationOnScreen0(long windowOrView, int src_x, int src_y);
357     private static native Object GetInsets0(long windowOrView);
358     private static native double GetPixelScale0(int screenIndex);
359     private static native double GetPixelScale1(long windowOrView);
360     private static native long CreateNSWindow0(int x, int y, int width, int height);
361     private static native void DestroyNSWindow0(long nsWindow);
362     private static native long GetNSView0(long nsWindow);
363     private static native long GetNSWindow0(long nsView);
364     private static native long CreateCALayer0(int width, int height, float contentsScale);
365     private static native void AddCASublayer0(long rootCALayer, long subCALayer, int x, int y, int width, int height, float contentsScale, int caLayerQuirks);
366     private static native void FixCALayerLayout0(long rootCALayer, long subCALayer, boolean visible, int x, int y, int width, int height, int caLayerQuirks);
367     private static native void RemoveCASublayer0(long rootCALayer, long subCALayer);
368     private static native void DestroyCALayer0(long caLayer);
369     private static native void RunOnMainThread0(Runnable runnable);
370     private static native void RunLater0(boolean onMain, Runnable runnable, int delay);
371     private static native boolean IsMainThread0();
372     private static native int GetScreenRefreshRate0(int scrn_idx);
373 }
http://JogAmp.org git info: FAQ, tutorial and man pages.