JOGL v2.6.0-rc-20250712
JOGL, High-Performance Graphics Binding for Java™ (public API).
JFXAccessor.java
Go to the documentation of this file.
1/**
2 * Copyright 2019 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 */
28package com.jogamp.nativewindow.javafx;
29
30import java.lang.reflect.Method;
31import java.security.PrivilegedAction;
32
33import com.jogamp.nativewindow.AbstractGraphicsDevice;
34import com.jogamp.nativewindow.AbstractGraphicsScreen;
35import com.jogamp.nativewindow.NativeWindowException;
36import com.jogamp.nativewindow.NativeWindowFactory;
37import com.jogamp.nativewindow.VisualIDHolder;
38import com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice;
39import com.jogamp.nativewindow.windows.WindowsGraphicsDevice;
40import com.jogamp.nativewindow.x11.X11GraphicsDevice;
41import com.jogamp.common.ExceptionUtils;
42import com.jogamp.common.util.InterruptedRuntimeException;
43import com.jogamp.common.util.ReflectionUtil;
44import com.jogamp.common.util.RunnableTask;
45import com.jogamp.common.util.SecurityUtil;
46import com.sun.javafx.tk.TKStage;
47
48import javafx.application.Platform;
49import javafx.stage.Window;
50import jogamp.nativewindow.Debug;
51import jogamp.nativewindow.x11.X11Lib;
52import jogamp.nativewindow.x11.X11Util;
53
54public class JFXAccessor {
55 private static final boolean DEBUG;
56
57 private static final boolean jfxAvailable;
58 private static final Method fxUserThreadGetter;
59 private static final Method tkStageGetter;
60 private static final Method glassWindowGetter;
61 private static final Method nativeWindowGetter;
62
63 private static final String nwt;
64 private static final boolean isOSX;
65 private static final boolean isIOS;
66 private static final boolean isWindows;
67 private static final boolean isX11;
68
69 static {
70 final boolean[] _DEBUG = new boolean[] { true };
71
72 final Method[] res = SecurityUtil.doPrivileged(new PrivilegedAction<Method[]>() {
73 @Override
74 public Method[] run() {
75 NativeWindowFactory.initSingleton(); // last resort ..
76 final Method[] res = new Method[] { null, null, null, null };
77 try {
78 int i=0;
79 _DEBUG[0] = Debug.debug("JFX");
80 /**
81 * com.sun.javafx.tk.Toolkit
82 */
83 final Class<?> jfxToolkitClz = ReflectionUtil.getClass("com.sun.javafx.tk.Toolkit", false, JFXAccessor.class.getClassLoader());
84 res[i] = jfxToolkitClz.getDeclaredMethod("getFxUserThread");
85 res[i++].setAccessible(true);
86
87 /***
88 * class javafx.stage.Window
89 * class javafx.stage.Stage extends javafx.stage.Window
90 * class com.sun.javafx.tk.quantum.WindowStage extends com.sun.javafx.tk.quantum.GlassStage implements com.sun.javafx.tk.TKStage
91 * abstract com.sun.glass.ui.Window
92 *
93 * javafx.stage.Window: com.sun.javafx.tk.TKStage [impl_]getPeer()
94 * com.sun.javafx.tk.quantum.WindowStage: final com.sun.glass.ui.Window getPlatformWindow()
95 * com.sun.glass.ui.Window: public long getNativeWindow()
96 */
97 final Class<?> jfxStageWindowClz = ReflectionUtil.getClass("javafx.stage.Window", false, JFXAccessor.class.getClassLoader());
98 // final Class<?> jfxTkTKStageClz = ReflectionUtil.getClass("com.sun.javafx.tk.TKStage", false, JFXAccessor.class.getClassLoader());
99 final Class<?> jfxTkQuWindowStageClz = ReflectionUtil.getClass("com.sun.javafx.tk.quantum.WindowStage", false, JFXAccessor.class.getClassLoader());
100 final Class<?> jfxGlassUiWindowClz = ReflectionUtil.getClass("com.sun.glass.ui.Window", false, JFXAccessor.class.getClassLoader());
101
102 try {
103 // jfx 9, 11, 12, ..
104 res[i] = jfxStageWindowClz.getDeclaredMethod("getPeer");
105 } catch (final NoSuchMethodException ex) {
106 // jfx 8
107 res[i] = jfxStageWindowClz.getDeclaredMethod("impl_getPeer");
108 }
109 res[i++].setAccessible(true);
110
111 res[i] = jfxTkQuWindowStageClz.getDeclaredMethod("getPlatformWindow");
112 res[i++].setAccessible(true);
113 res[i] = jfxGlassUiWindowClz.getDeclaredMethod("getNativeWindow");
114 res[i++].setAccessible(true);
115 } catch (final Throwable t) {
116 if(_DEBUG[0]) {
117 ExceptionUtils.dumpThrowable("jfx-init", t);
118 }
119 }
120 return res;
121 }
122 });
123 {
124 int i=0;
125 fxUserThreadGetter = res[i++];
126 tkStageGetter = res[i++];
127 glassWindowGetter = res[i++];
128 nativeWindowGetter = res[i++];
129 }
130 jfxAvailable = null != fxUserThreadGetter && null != tkStageGetter && null != glassWindowGetter && null != nativeWindowGetter;
131
133 isOSX = NativeWindowFactory.TYPE_MACOSX == nwt;
134 isIOS = NativeWindowFactory.TYPE_IOS == nwt;
135 isWindows = NativeWindowFactory.TYPE_WINDOWS == nwt;
136 isX11 = NativeWindowFactory.TYPE_X11 == nwt;
137
138 DEBUG = _DEBUG[0];
139 if(DEBUG) {
140 System.err.println(Thread.currentThread().getName()+" - Info: JFXAccessor.<init> available "+jfxAvailable+", nwt "+nwt+"( x11 "+isX11+", win "+isWindows+", osx "+isOSX+")");
141 }
142 }
143
144 //
145 // Common any toolkit
146 //
147
148 public static boolean isJFXAvailable() { return jfxAvailable; }
149
150 /**
151 * Runs given {@code task} on the JFX Thread if it has not stopped and if caller is not already on the JFX Thread,
152 * otherwise execute given {@code task} on the current thread.
153 * @param wait
154 * @param task
155 * @see #isJFXThreadOrHasJFXThreadStopped()
156 */
157 public static void runOnJFXThread(final boolean wait, final Runnable task) {
158 final Object rTaskLock = new Object();
159 synchronized(rTaskLock) { // lock the task execution
161 task.run();
162 } else if( !wait ) {
163 Platform.runLater(task);
164 } else {
165 final RunnableTask rTask = new RunnableTask(task,
166 rTaskLock,
167 true /* always catch and report Exceptions, don't disturb EDT */,
168 null);
169 Platform.runLater(rTask);
170 try {
171 while( rTask.isInQueue() ) {
172 rTaskLock.wait(); // free lock, allow execution of rTask
173 }
174 } catch (final InterruptedException ie) {
175 throw new InterruptedRuntimeException(ie);
176 }
177 final Throwable throwable = rTask.getThrowable();
178 if(null!=throwable) {
179 if(throwable instanceof NativeWindowException) {
180 throw (NativeWindowException)throwable;
181 }
182 throw new RuntimeException(throwable);
183 }
184 }
185 }
186 }
187
188 public static Thread getJFXThread() throws NativeWindowException {
189 try {
190 return (Thread) fxUserThreadGetter.invoke(null);
191 } catch (final Throwable e) {
192 throw new NativeWindowException("Error getting JFX-Thread", e);
193 }
194 }
195 public static String getJFXThreadName() {
196 final Thread t = getJFXThread();
197 return null != t ? t.getName() : null;
198 }
199 /**
200 * @return true if the JFX Thread has stopped
201 */
202 public static boolean hasJFXThreadStopped() {
203 final Thread t = getJFXThread();
204 return null == t || !t.isAlive();
205 }
206 /**
207 * @return true if caller is on the JFX Thread
208 */
209 public static boolean isJFXThread() {
210 final Thread t = getJFXThread();
211 return Thread.currentThread() == t;
212 }
213 /**
214 * @return true if the JFX Thread has stopped or if caller is on the JFX Thread
215 */
216 public static boolean isJFXThreadOrHasJFXThreadStopped() {
217 final Thread t = getJFXThread();
218 return null == t || !t.isAlive() || Thread.currentThread() == t;
219 }
220
221 /**
222 * @param stageWindow the JavaFX top heavyweight window handle
223 * @return the AbstractGraphicsDevice w/ the native device handle
224 * @throws NativeWindowException if an exception occurs retrieving the window handle or deriving the native device
225 * @throws UnsupportedOperationException if the windowing system is not supported
226 */
227 public static AbstractGraphicsDevice getDevice(final Window stageWindow) throws NativeWindowException, UnsupportedOperationException {
228 if( isX11 ) {
229 // Decoupled X11 Device/Screen allowing X11 display lock-free off-thread rendering
230 final String connection = null;
231 final long x11DeviceHandle = X11Util.openDisplay(connection);
232 if( 0 == x11DeviceHandle ) {
233 throw new NativeWindowException("Error creating display: "+connection);
234 }
235 return new X11GraphicsDevice(x11DeviceHandle, AbstractGraphicsDevice.DEFAULT_UNIT, true /* owner */);
236 }
237 if( isWindows ) {
239 }
240 if( isOSX ) {
242 }
243 throw new UnsupportedOperationException("n/a for this windowing system: "+nwt);
244 }
245
246 /**
247 * @param device
248 * @param screen -1 is default screen of the given device, e.g. maybe 0 or determined by native API. >= 0 is specific screen
249 * @return
250 */
251 public static AbstractGraphicsScreen getScreen(final AbstractGraphicsDevice device, final int screen) {
252 return NativeWindowFactory.createScreen(device, screen);
253 }
254
255 public static int getNativeVisualID(final AbstractGraphicsDevice device, final long windowHandle) {
256 if( isX11 ) {
257 return X11Lib.GetVisualIDFromWindow(device.getHandle(), windowHandle);
258 }
259 if( isWindows || isOSX ) {
261 }
262 throw new UnsupportedOperationException("n/a for this windowing system: "+nwt);
263 }
264
265 /**
266 * @param stageWindow the JavaFX top heavyweight window handle
267 * @return the native window handle
268 * @throws NativeWindowException if an exception occurs retrieving the window handle
269 */
270 public static long getWindowHandle(final Window stageWindow) throws NativeWindowException {
271 final long h[] = { 0 };
272 runOnJFXThread(true, new Runnable() {
273 @Override
274 public void run() {
275 try {
276 final TKStage tkStage = (TKStage) tkStageGetter.invoke(stageWindow);
277 if( null != tkStage ) {
278 final Object platformWindow = glassWindowGetter.invoke(tkStage);
279 if( null != platformWindow ) {
280 final Object nativeHandle = nativeWindowGetter.invoke(platformWindow);
281 h[0] = ((Long) nativeHandle).longValue();
282 } else if(DEBUG) {
283 System.err.println(Thread.currentThread().getName()+" - Info: JFXAccessor null GlassWindow");
284 }
285 } else if(DEBUG) {
286 System.err.println(Thread.currentThread().getName()+" - Info: JFXAccessor null TKStage");
287 }
288 } catch (final Throwable e) {
289 throw new NativeWindowException("Error getting Window handle", e);
290 }
291 } });
292 return h[0];
293 }
294}
A generic exception for OpenGL errors used throughout the binding as a substitute for RuntimeExceptio...
Provides a pluggable mechanism for arbitrary window toolkits to adapt their components to the NativeW...
static synchronized void initSingleton()
Static one time initialization of this factory.
static String getNativeWindowType(final boolean useCustom)
static AbstractGraphicsScreen createScreen(final AbstractGraphicsDevice device, int screen)
static long getWindowHandle(final Window stageWindow)
static AbstractGraphicsScreen getScreen(final AbstractGraphicsDevice device, final int screen)
static AbstractGraphicsDevice getDevice(final Window stageWindow)
static int getNativeVisualID(final AbstractGraphicsDevice device, final long windowHandle)
static void runOnJFXThread(final boolean wait, final Runnable task)
Runs given task on the JFX Thread if it has not stopped and if caller is not already on the JFX Threa...
Encapsulates a graphics device on MacOSX platforms.
Encapsulates a graphics device on Windows platforms.
Encapsulates a graphics device on X11 platforms.
A interface describing a graphics device in a toolkit-independent manner.
long getHandle()
Returns the native handle of the underlying native device, if such thing exist.
static int DEFAULT_UNIT
Default unit id for the 1st device: 0.
A interface describing a graphics screen in a toolkit-independent manner.
static final int VID_UNDEFINED
getVisualID(VIDType) result indicating an undefined value, which could be cause by an unsupported que...