JOGL v2.6.0-rc-20250712
JOGL, High-Performance Graphics Binding for Java™ (public API).
NativeWindowFactory.java
Go to the documentation of this file.
1/*
2 * Copyright (c) 2010-2023 JogAmp Community. All rights reserved.
3 * Copyright (c) 2008-2009 Sun Microsystems, Inc. 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
34package com.jogamp.nativewindow;
35
36import java.io.File;
37import java.lang.reflect.Method;
38import java.security.PrivilegedAction;
39import java.util.ArrayList;
40import java.util.Collections;
41import java.util.HashMap;
42import java.util.List;
43import java.util.Map;
44
45import com.jogamp.nativewindow.util.Point;
46
47import jogamp.common.os.PlatformPropsImpl;
48import jogamp.nativewindow.BcmVCArtifacts;
49import jogamp.nativewindow.Debug;
50import jogamp.nativewindow.NativeWindowFactoryImpl;
51import jogamp.nativewindow.ResourceToolkitLock;
52import jogamp.nativewindow.ToolkitProperties;
53import jogamp.nativewindow.WrappedWindow;
54
55import com.jogamp.common.os.Platform;
56import com.jogamp.common.util.InterruptSource;
57import com.jogamp.common.util.PropertyAccess;
58import com.jogamp.common.util.ReflectionUtil;
59import com.jogamp.common.util.SecurityUtil;
60
61/** Provides a pluggable mechanism for arbitrary window toolkits to
62 adapt their components to the {@link NativeWindow} interface,
63 which provides a platform-independent mechanism of accessing the
64 information required to perform operations like
65 hardware-accelerated rendering using the OpenGL API.
66 * <p>
67 * FIXME: Bug 973 Needs service provider interface (SPI) for TK dependent implementation
68 * </p>
69 */
70public abstract class NativeWindowFactory {
71 protected static final boolean DEBUG;
72
73 /** Wayland/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}.*/
74 public static final String TYPE_WAYLAND = ".wayland";
75
76 /** DRM/GBM type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}.*/
77 public static final String TYPE_DRM_GBM = ".egl.gbm"; // We leave the sub-package name as .egl.gbm for NEWT as it uses EGL
78
79 /** OpenKODE/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}.*/
80 public static final String TYPE_EGL = ".egl";
81
82 /** Microsoft Windows type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */
83 public static final String TYPE_WINDOWS = ".windows";
84
85 /** X11 type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */
86 public static final String TYPE_X11 = ".x11";
87
88 /** Broadcom VC IV/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */
89 public static final String TYPE_BCM_VC_IV = ".bcm.vc.iv";
90
91 /** Android/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}.*/
92 public static final String TYPE_ANDROID = ".android";
93
94 /** Mac OS X type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */
95 public static final String TYPE_MACOSX = ".macosx";
96
97 /** iOS type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */
98 public static final String TYPE_IOS = ".ios";
99
100 /** Generic AWT type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */
101 public static final String TYPE_AWT = ".awt";
102
103 /** Generic DEFAULT type, where platform implementation don't care, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */
104 public static final String TYPE_DEFAULT = ".default";
105
106 private static final String nativeWindowingTypeNative; // canonical String via String.intern()
107 private static final String nativeWindowingTypeCustom; // canonical String via String.intern()
108
109 private static NativeWindowFactory defaultFactory;
110 private static Map<Class<?>, NativeWindowFactory> registeredFactories;
111
112 private static Class<?> nativeWindowClass;
113 private static boolean isAWTAvailable;
114
115 private static final String JAWTUtilClassName = "jogamp.nativewindow.jawt.JAWTUtil" ;
116 /** {@link jogamp.nativewindow.x11.X11Util} implements {@link ToolkitProperties}. */
117 private static final String X11UtilClassName = "jogamp.nativewindow.x11.X11Util";
118 /** {@link jogamp.nativewindow.drm.DRMUtil} implements {@link ToolkitProperties}. */
119 private static final String DRMUtilClassName = "jogamp.nativewindow.drm.DRMUtil";
120 /** {@link jogamp.nativewindow.macosx.OSXUtil} implements {@link ToolkitProperties}. */
121 private static final String OSXUtilClassName = "jogamp.nativewindow.macosx.OSXUtil";
122 /** {@link jogamp.nativewindow.ios.IOSUtil} implements {@link ToolkitProperties}. */
123 private static final String IOSUtilClassName = "jogamp.nativewindow.ios.IOSUtil";
124 /** {@link jogamp.nativewindow.windows.GDIUtil} implements {@link ToolkitProperties}. */
125 private static final String GDIClassName = "jogamp.nativewindow.windows.GDIUtil";
126
127 private static ToolkitLock jawtUtilJAWTToolkitLock;
128
129 private static boolean requiresToolkitLock;
130 private static boolean desktopHasThreadingIssues;
131
132 // Shutdown hook mechanism for the factory
133 private static volatile boolean isJVMShuttingDown = false;
134 private static final List<Runnable> customShutdownHooks = new ArrayList<Runnable>();
135
136 /** Creates a new NativeWindowFactory instance. End users do not
137 need to call this method. */
139 }
140
141 private static String _getNativeWindowingType(final boolean debug) {
142 switch(PlatformPropsImpl.OS_TYPE) {
143 case ANDROID:
144 return TYPE_ANDROID;
145 case MACOS:
146 return TYPE_MACOSX;
147 case IOS:
148 return TYPE_IOS;
149 case WINDOWS:
150 return TYPE_WINDOWS;
151 case OPENKODE:
152 return TYPE_EGL;
153 case LINUX:
154 case FREEBSD:
155 case SUNOS:
156 case HPUX:
157 default:
158 if( debug ) {
159 guessX(true);
160 guessWayland(true);
161 guessGBM(true);
162 BcmVCArtifacts.guessVCIVUsed(true);
163 }
164 if( BcmVCArtifacts.guessVCIVUsed(false) ) {
165 /* Broadcom VC IV can be used from
166 * both console and from inside X11
167 *
168 * When used from inside X11
169 * rendering is done on an DispmanX overlay surface
170 * while keeping an X11 nativewindow under as input.
171 *
172 * When Broadcom VC IV is guessed
173 * only the Broadcom DispmanX EGL driver is loaded.
174 * Therefore standard TYPE_X11 EGL can not be used.
175 */
176 return TYPE_BCM_VC_IV;
177 }
178 if( guessX(false) ) {
179 return TYPE_X11;
180 }
181 if( guessWayland(false) ) {
182 //TODO
183 return TYPE_WAYLAND;
184 }
185 if( guessGBM(false) ) {
186 return TYPE_DRM_GBM;
187 }
188 return TYPE_X11;
189 }
190 }
191
192 private static boolean guessX(final boolean debug) {
193 final String s = System.getenv("DISPLAY");
194 if ( debug ) {
195 System.err.println("guessX: <"+s+"> isSet "+(null!=s));
196 }
197 return null != s;
198 }
199
200 private static boolean guessWayland(final boolean debug) {
201 //TODO we can/should do a more elaborate check and try looking for a wayland-0 socket in $XDG_RUNTIME_DIR
202 final String s = System.getenv("WAYLAND_DISPLAY");
203 if ( debug ) {
204 System.err.println("guessWayland: <"+s+"> isSet "+(null!=s));
205 }
206 return null != s;
207 }
208
209 private static boolean guessGBM(final boolean debug) {
210 //FIXME this is not the best way to check if we have gbm-egl support, but does a good easy way actually exist?
211 final File f = new File( "/dev/dri/card0" );
212 if ( debug ) {
213 System.err.println("guessGBM: <"+f.toString()+"> exists "+f.exists());
214 }
215 return f.exists(); // not a normal file
216 }
217
218 static {
219 final boolean[] _DEBUG = new boolean[] { false };
220 final String[] _tmp = new String[] { null };
221 final String[] _nativeWindowingTypeNative = new String[] { null };
222
223 SecurityUtil.doPrivileged(new PrivilegedAction<Object>() {
224 @Override
225 public Object run() {
226 Platform.initSingleton(); // last resort ..
227 _DEBUG[0] = Debug.debug("NativeWindow");
228 _tmp[0] = PropertyAccess.getProperty("nativewindow.ws.name", true);
229 _nativeWindowingTypeNative[0] = _getNativeWindowingType(_DEBUG[0]);
230 Runtime.getRuntime().addShutdownHook(
231 new InterruptSource.Thread(null, new Runnable() {
232 @Override
233 public void run() {
234 NativeWindowFactory.shutdown(true);
235 } }, "NativeWindowFactory_ShutdownHook" ) ) ;
236 return null;
237 } } ) ;
238
239 DEBUG = _DEBUG[0];
240
241 nativeWindowingTypeNative = _nativeWindowingTypeNative[0];
242 if(null==_tmp[0] || _tmp[0].length()==0) {
243 nativeWindowingTypeCustom = nativeWindowingTypeNative;
244 } else {
245 nativeWindowingTypeCustom = _tmp[0].intern(); // canonical representation
246 }
247 if(DEBUG) {
248 System.err.println(Thread.currentThread().getName()+" - Info: NativeWindowFactory.<init>: Type "+nativeWindowingTypeCustom+" custom / "+nativeWindowingTypeNative+" native");
249 // Thread.dumpStack();
250 }
251 }
252
253 private static boolean initialized = false;
254
255 private static String getNativeWindowingTypeClassName() {
256 final String clazzName;
257 switch( nativeWindowingTypeNative ) {
258 case TYPE_X11:
259 clazzName = X11UtilClassName;
260 break;
261 case TYPE_DRM_GBM:
262 clazzName = DRMUtilClassName;
263 break;
264 case TYPE_WINDOWS:
265 clazzName = GDIClassName;
266 break;
267 case TYPE_MACOSX:
268 clazzName = OSXUtilClassName;
269 break;
270 case TYPE_IOS:
271 clazzName = IOSUtilClassName;
272 break;
273 default:
274 clazzName = null;
275 }
276 return clazzName;
277 }
278 private static void initSingletonNativeImpl(final ClassLoader cl) {
279 final String clazzName = getNativeWindowingTypeClassName();
280 if( null != clazzName ) {
281 ReflectionUtil.callStaticMethod(clazzName, "initSingleton", null, null, cl );
282
283 final Boolean res1 = (Boolean) ReflectionUtil.callStaticMethod(clazzName, "requiresToolkitLock", null, null, cl);
284 requiresToolkitLock = res1.booleanValue();
285 final Boolean res2 = (Boolean) ReflectionUtil.callStaticMethod(clazzName, "hasThreadingIssues", null, null, cl);
286 desktopHasThreadingIssues = res2.booleanValue();
287 } else {
288 requiresToolkitLock = false;
289 desktopHasThreadingIssues = false;
290 }
291 }
292
293 /** Returns true if the JVM is shutting down, otherwise false. */
294 public static final boolean isJVMShuttingDown() { return isJVMShuttingDown; }
295
296 /**
297 * Add a custom shutdown hook to be performed at JVM shutdown before shutting down NativeWindowFactory instance.
298 *
299 * @param head if true add runnable at the start, otherwise at the end
300 * @param runnable runnable to be added.
301 */
302 public static void addCustomShutdownHook(final boolean head, final Runnable runnable) {
303 synchronized( customShutdownHooks ) {
304 if( !customShutdownHooks.contains( runnable ) ) {
305 if( head ) {
306 customShutdownHooks.add(0, runnable);
307 } else {
308 customShutdownHooks.add( runnable );
309 }
310 }
311 }
312 }
313
314 /**
315 * Cleanup resources at JVM shutdown
316 */
317 public static synchronized void shutdown(final boolean _isJVMShuttingDown) {
318 isJVMShuttingDown = _isJVMShuttingDown;
319 if(DEBUG) {
320 System.err.println("NativeWindowFactory.shutdown() START: JVM Shutdown "+isJVMShuttingDown+", on thread "+Thread.currentThread().getName());
321 }
322 synchronized(customShutdownHooks) {
323 final int cshCount = customShutdownHooks.size();
324 for(int i=0; i < cshCount; i++) {
325 try {
326 if( DEBUG ) {
327 System.err.println("NativeWindowFactory.shutdown - customShutdownHook #"+(i+1)+"/"+cshCount);
328 }
329 customShutdownHooks.get(i).run();
330 } catch(final Throwable t) {
331 System.err.println("NativeWindowFactory.shutdown: Caught "+t.getClass().getName()+" during customShutdownHook #"+(i+1)+"/"+cshCount);
332 if( DEBUG ) {
333 t.printStackTrace();
334 }
335 }
336 }
337 customShutdownHooks.clear();
338 }
339 if(DEBUG) {
340 System.err.println("NativeWindowFactory.shutdown(): Post customShutdownHook");
341 }
342
343 if(initialized) {
344 initialized = false;
345 if(null != registeredFactories) {
346 registeredFactories.clear();
347 registeredFactories = null;
348 }
350 }
351
352 shutdownNativeImpl(NativeWindowFactory.class.getClassLoader()); // always re-shutdown
353 // SharedResourceToolkitLock.shutdown(DEBUG); // not used yet
354 if(DEBUG) {
355 System.err.println(Thread.currentThread().getName()+" - NativeWindowFactory.shutdown() END JVM Shutdown "+isJVMShuttingDown);
356 }
357 }
358
359 private static void shutdownNativeImpl(final ClassLoader cl) {
360 final String clazzName = getNativeWindowingTypeClassName();
361 if( null != clazzName ) {
362 ReflectionUtil.callStaticMethod(clazzName, "shutdown", null, null, cl );
363 }
364 }
365
366 /** Returns true if {@link #initSingleton()} has been called w/o subsequent {@link #shutdown(boolean)}. */
367 public static synchronized boolean isInitialized() { return initialized; }
368
369 /**
370 * Static one time initialization of this factory.<br>
371 * This initialization method <b>must be called</b> once by the program or utilizing modules!
372 */
373 public static synchronized void initSingleton() {
374 if(!initialized) {
375 initialized = true;
376
377 if(DEBUG) {
378 System.err.println(Thread.currentThread().getName()+" - NativeWindowFactory.initSingleton()");
379 }
380
381 final ClassLoader cl = NativeWindowFactory.class.getClassLoader();
382
383 isAWTAvailable = false; // may be set to true below
384
385 if( Platform.AWT_AVAILABLE &&
386 ReflectionUtil.isClassAvailable("com.jogamp.nativewindow.awt.AWTGraphicsDevice", cl) ) {
387
388 final Method[] jawtUtilMethods = SecurityUtil.doPrivileged(new PrivilegedAction<Method[]>() {
389 @Override
390 public Method[] run() {
391 try {
392 final Class<?> _jawtUtilClass = Class.forName(JAWTUtilClassName, true, NativeWindowFactory.class.getClassLoader());
393 final Method jawtUtilIsHeadlessMethod = _jawtUtilClass.getDeclaredMethod("isHeadlessMode", (Class[])null);
394 jawtUtilIsHeadlessMethod.setAccessible(true);
395 final Method jawtUtilInitMethod = _jawtUtilClass.getDeclaredMethod("initSingleton", (Class[])null);
396 jawtUtilInitMethod.setAccessible(true);
397 final Method jawtUtilGetJAWTToolkitLockMethod = _jawtUtilClass.getDeclaredMethod("getJAWTToolkitLock", new Class[]{});
398 jawtUtilGetJAWTToolkitLockMethod.setAccessible(true);
399 return new Method[] { jawtUtilInitMethod, jawtUtilIsHeadlessMethod, jawtUtilGetJAWTToolkitLockMethod };
400 } catch (final Exception e) {
401 if(DEBUG) {
402 e.printStackTrace();
403 }
404 }
405 return null;
406 }
407 });
408 if(null != jawtUtilMethods) {
409 final Method jawtUtilInitMethod = jawtUtilMethods[0];
410 final Method jawtUtilIsHeadlessMethod = jawtUtilMethods[1];
411 final Method jawtUtilGetJAWTToolkitLockMethod = jawtUtilMethods[2];
412
413 ReflectionUtil.callMethod(null, jawtUtilInitMethod);
414
415 Object resO = ReflectionUtil.callMethod(null, jawtUtilIsHeadlessMethod);
416 if(resO instanceof Boolean) {
417 // AWT is only available in case all above classes are available
418 // and AWT is not int headless mode
419 isAWTAvailable = ((Boolean)resO).equals(Boolean.FALSE);
420 } else {
421 throw new RuntimeException("JAWTUtil.isHeadlessMode() didn't return a Boolean");
422 }
423 resO = ReflectionUtil.callMethod(null, jawtUtilGetJAWTToolkitLockMethod);
424 if(resO instanceof ToolkitLock) {
425 jawtUtilJAWTToolkitLock = (ToolkitLock) resO;
426 } else {
427 throw new RuntimeException("JAWTUtil.getJAWTToolkitLock() didn't return a ToolkitLock");
428 }
429 }
430 }
431
432 // X11 initialization after possible AWT initialization
433 // This is performed post AWT initialization, allowing AWT to complete the same,
434 // which may have been triggered before NativeWindow initialization.
435 // This way behavior is more uniforms across configurations (Applet/RCP, applications, ..).
436 initSingletonNativeImpl(cl);
437
438 registeredFactories = Collections.synchronizedMap(new HashMap<Class<?>, NativeWindowFactory>());
439
440 // register our default factory -> NativeWindow
441 final NativeWindowFactory factory = new NativeWindowFactoryImpl();
442 nativeWindowClass = com.jogamp.nativewindow.NativeWindow.class;
443 registerFactory(nativeWindowClass, factory);
444 defaultFactory = factory;
445
446 if ( isAWTAvailable ) {
447 // register either our default factory or (if exist) the X11/AWT one -> AWT Component
448 registerFactory(ReflectionUtil.getClass(ReflectionUtil.AWTNames.ComponentClass, false, cl), factory);
449 }
450
451 if(DEBUG) {
452 System.err.println("NativeWindowFactory requiresToolkitLock "+requiresToolkitLock+", desktopHasThreadingIssues "+desktopHasThreadingIssues);
453 System.err.println("NativeWindowFactory isAWTAvailable "+isAWTAvailable+", defaultFactory "+factory);
454 }
455
457 }
458 }
459
460 /** @return true if the underlying toolkit requires locking, otherwise false. */
461 public static boolean requiresToolkitLock() {
462 return requiresToolkitLock;
463 }
464
465 /** @return true if not headless, AWT Component and NativeWindow's AWT part available */
466 public static boolean isAWTAvailable() { return isAWTAvailable; }
467
468 /**
469 * @param useCustom if false return the native value, if true return a custom value if set, otherwise fallback to the native value.
470 * @return the native window type, e.g. {@link #TYPE_X11}, which is canonical via {@link String#intern()}.
471 * Hence {@link String#equals(Object)} and <code>==</code> produce the same result.
472 */
473 public static String getNativeWindowType(final boolean useCustom) {
474 return useCustom?nativeWindowingTypeCustom:nativeWindowingTypeNative;
475 }
476
477 /** Don't know if we shall add this factory here ..
478 * <p>
479 * FIXME: Bug 973 Needs service provider interface (SPI) for TK dependent implementation
480 * </p>
481 public static AbstractGraphicsDevice createGraphicsDevice(String type, String connection, int unitID, long handle, ToolkitLock locker) {
482 if(TYPE_EGL == type) {
483 return new
484 } else if(TYPE_X11 == type) {
485 } else if(TYPE_WINDOWS == type) {
486 } else if(TYPE_MACOSX == type)) {
487 } else if(TYPE_AWT == type) {
488 } else if(TYPE_DEFAULT == type) {
489 }
490 } */
491
492 /** Sets the default NativeWindowFactory. */
493 public static void setDefaultFactory(final NativeWindowFactory factory) {
494 defaultFactory = factory;
495 }
496
497 /** Gets the default NativeWindowFactory. */
499 return defaultFactory;
500 }
501
502 /**
503 * Returns the AWT {@link ToolkitLock} (JAWT based) if {@link #isAWTAvailable}, otherwise null.
504 * <p>
505 * The JAWT based {@link ToolkitLock} also locks the global lock,
506 * which matters if the latter is required.
507 * </p>
508 */
510 return jawtUtilJAWTToolkitLock;
511 }
512
514 return NativeWindowFactoryImpl.getNullToolkitLock();
515 }
516
517 /**
518 * Provides the system default {@link ToolkitLock} for the default system windowing type.
519 * @see #getNativeWindowType(boolean)
520 * @see #getDefaultToolkitLock(java.lang.String)
521 */
523 return getDefaultToolkitLock(nativeWindowingTypeNative);
524 }
525
526 /**
527 * Provides the default {@link ToolkitLock} for <code>type</code>.
528 * <ul>
529 * <li> JAWT {@link ToolkitLock} if required and <code>type</code> is of {@link #TYPE_AWT} and AWT available,</li>
530 * <li> {@link jogamp.nativewindow.ResourceToolkitLock} if required, otherwise</li>
531 * <li> {@link jogamp.nativewindow.NullToolkitLock} </li>
532 * </ul>
533 */
534 public static ToolkitLock getDefaultToolkitLock(final String type) {
535 if( requiresToolkitLock ) {
536 if( TYPE_AWT == type && isAWTAvailable() ) { // uses .intern()!
537 return getAWTToolkitLock();
538 }
539 return ResourceToolkitLock.create();
540 }
541 return NativeWindowFactoryImpl.getNullToolkitLock();
542 }
543
544 /**
545 * @param device
546 * @param screen -1 is default screen of the given device, e.g. maybe 0 or determined by native API. >= 0 is specific screen
547 * @return newly created AbstractGraphicsScreen matching device's native type
548 */
549 public static AbstractGraphicsScreen createScreen(final AbstractGraphicsDevice device, int screen) {
550 final String type = device.getType();
551 if( TYPE_X11 == type ) {
552 final com.jogamp.nativewindow.x11.X11GraphicsDevice x11Device = (com.jogamp.nativewindow.x11.X11GraphicsDevice)device;
553 if(0 > screen) {
554 screen = x11Device.getDefaultScreen();
555 }
556 return new com.jogamp.nativewindow.x11.X11GraphicsScreen(x11Device, screen);
557 }
558 if(0 > screen) {
559 screen = 0; // FIXME: Needs native API utilization
560 }
561 if( TYPE_AWT == type ) {
562 final com.jogamp.nativewindow.awt.AWTGraphicsDevice awtDevice = (com.jogamp.nativewindow.awt.AWTGraphicsDevice) device;
563 return new com.jogamp.nativewindow.awt.AWTGraphicsScreen(awtDevice);
564 }
565 return new DefaultGraphicsScreen(device, screen);
566 }
567
568 /** Returns the appropriate NativeWindowFactory to handle window
569 objects of the given type. The windowClass might be {@link
570 NativeWindow NativeWindow}, in which case the client has
571 already assumed the responsibility of creating a compatible
572 NativeWindow implementation, or it might be that of a toolkit
573 class like {@link java.awt.Component Component}. */
574 public static NativeWindowFactory getFactory(final Class<?> windowClass) throws IllegalArgumentException {
575 if (nativeWindowClass.isAssignableFrom(windowClass)) {
576 return registeredFactories.get(nativeWindowClass);
577 }
578 Class<?> clazz = windowClass;
579 while (clazz != null) {
580 final NativeWindowFactory factory = registeredFactories.get(clazz);
581 if (factory != null) {
582 return factory;
583 }
584 clazz = clazz.getSuperclass();
585 }
586 throw new IllegalArgumentException("No registered NativeWindowFactory for class " + windowClass.getName());
587 }
588
589 /** Registers a NativeWindowFactory handling window objects of the
590 given class. This does not need to be called by end users,
591 only implementors of new NativeWindowFactory subclasses. */
592 protected static void registerFactory(final Class<?> windowClass, final NativeWindowFactory factory) {
593 if(DEBUG) {
594 System.err.println("NativeWindowFactory.registerFactory() "+windowClass+" -> "+factory);
595 }
596 registeredFactories.put(windowClass, factory);
597 }
598
599 /** Converts the given window object and it's
600 {@link AbstractGraphicsConfiguration AbstractGraphicsConfiguration} into a
601 {@link NativeWindow NativeWindow} which can be operated upon by a custom
602 toolkit, e.g. {@link com.jogamp.opengl.GLDrawableFactory com.jogamp.opengl.GLDrawableFactory}.<br>
603 The object may be a component for a particular window toolkit, such as an AWT
604 Canvas. It may also be a NativeWindow object itself.<br>
605 You shall utilize {@link com.jogamp.nativewindow.GraphicsConfigurationFactory GraphicsConfigurationFactory}
606 to construct a proper {@link AbstractGraphicsConfiguration AbstractGraphicsConfiguration}.<br>
607 The particular implementation of the
608 NativeWindowFactory is responsible for handling objects from a
609 particular window toolkit. The built-in NativeWindowFactory
610 handles NativeWindow instances as well as AWT Components.<br>
611
612 @throws IllegalArgumentException if the given window object
613 could not be handled by any of the registered
614 NativeWindowFactory instances
615
616 @see com.jogamp.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(Capabilities, CapabilitiesChooser, AbstractGraphicsScreen)
617 */
618 public static NativeWindow getNativeWindow(final Object winObj, final AbstractGraphicsConfiguration config) throws IllegalArgumentException, NativeWindowException {
619 if (winObj == null) {
620 throw new IllegalArgumentException("Null window object");
621 }
622
623 return getFactory(winObj.getClass()).getNativeWindowImpl(winObj, config);
624 }
625
626 /** Performs the conversion from a toolkit's window object to a
627 NativeWindow. Implementors of concrete NativeWindowFactory
628 subclasses should override this method. */
629 protected abstract NativeWindow getNativeWindowImpl(Object winObj, AbstractGraphicsConfiguration config) throws IllegalArgumentException;
630
631 /**
632 * Returns the {@link OffscreenLayerSurface} instance of this {@link NativeSurface}.
633 * <p>
634 * In case this surface is a {@link NativeWindow}, we traverse from the given surface
635 * up to root until an implementation of {@link OffscreenLayerSurface} is found.
636 * In case <code>ifEnabled</code> is true, the surface must also implement {@link OffscreenLayerOption}
637 * where {@link OffscreenLayerOption#isOffscreenLayerSurfaceEnabled()} is <code>true</code>.
638 * </p>
639 *
640 * @param surface The surface to query.
641 * @param ifEnabled If true, only return the enabled {@link OffscreenLayerSurface}, see {@link OffscreenLayerOption#isOffscreenLayerSurfaceEnabled()}.
642 * @return
643 */
644 public static OffscreenLayerSurface getOffscreenLayerSurface(final NativeSurface surface, final boolean ifEnabled) {
645 if(surface instanceof OffscreenLayerSurface &&
646 ( !ifEnabled || surface instanceof OffscreenLayerOption ) ) {
647 final OffscreenLayerSurface ols = (OffscreenLayerSurface) surface;
648 return ( !ifEnabled || ((OffscreenLayerOption)ols).isOffscreenLayerSurfaceEnabled() ) ? ols : null;
649 }
650 if(surface instanceof NativeWindow) {
651 NativeWindow nw = ((NativeWindow) surface).getParent();
652 while(null != nw) {
653 if(nw instanceof OffscreenLayerSurface &&
654 ( !ifEnabled || nw instanceof OffscreenLayerOption ) ) {
656 return ( !ifEnabled || ((OffscreenLayerOption)ols).isOffscreenLayerSurfaceEnabled() ) ? ols : null;
657 }
658 nw = nw.getParent();
659 }
660 }
661 return null;
662 }
663
664 /**
665 * Returns true if the given visualID is valid for further processing, i.e. OpenGL usage,
666 * otherwise return false.
667 * <p>
668 * On certain platforms, i.e. X11, a valid visualID is required at window creation.
669 * Other platforms may determine it later on, e.g. OSX and Windows. </p>
670 * <p>
671 * If the visualID is {@link VisualIDHolder#VID_UNDEFINED} and the platform requires it
672 * at creation time (see above), it is not valid for further processing.
673 * </p>
674 * <p>
675 * FIXME: Bug 973 Needs service provider interface (SPI) for TK dependent implementation
676 * </p>
677 */
678 public static boolean isNativeVisualIDValidForProcessing(final int visualID) {
679 return NativeWindowFactory.TYPE_X11 != NativeWindowFactory.getNativeWindowType(false) ||
680 VisualIDHolder.VID_UNDEFINED != visualID ;
681 }
682
683 public static String getDefaultDisplayConnection() {
685 }
686 public static String getDefaultDisplayConnection(final String nwt) {
687 if(NativeWindowFactory.TYPE_X11 == nwt) {
688 return jogamp.nativewindow.x11.X11Util.getNullDisplayName();
689 } else {
691 }
692 }
693
694 /**
695 * Creates a native device type, following {@link #getNativeWindowType(boolean) getNativeWindowType(true)}.
696 * <p>
697 * The device will be opened if <code>own</code> is true, otherwise no native handle will ever be acquired.
698 * </p>
699 */
700 public static AbstractGraphicsDevice createDevice(final String displayConnection, final boolean own) {
701 return createDevice(NativeWindowFactory.getNativeWindowType(true), displayConnection, own);
702 }
703
704 /**
705 * Creates a native device type, following the given {@link #getNativeWindowType(boolean) native-window-type}.
706 * <p>
707 * The device will be opened if <code>own</code> is true, otherwise no native handle will ever be acquired.
708 * </p>
709 * <p>
710 * FIXME: Bug 973 Needs service provider interface (SPI) for TK dependent implementation
711 * </p>
712 */
713 public static AbstractGraphicsDevice createDevice(final String nwt, final String displayConnection, final boolean own) {
714 return createDevice(nwt, displayConnection, AbstractGraphicsDevice.DEFAULT_UNIT, own);
715 }
716
717 /**
718 * Creates a native device type, following the given {@link #getNativeWindowType(boolean) native-window-type}.
719 * <p>
720 * The device will be opened if <code>own</code> is true, otherwise no native handle will ever be acquired.
721 * </p>
722 * <p>
723 * FIXME: Bug 973 Needs service provider interface (SPI) for TK dependent implementation
724 * </p>
725 */
726 public static AbstractGraphicsDevice createDevice(final String nwt, final String displayConnection, final int unitID, final boolean own) {
727 if( NativeWindowFactory.TYPE_X11 == nwt ) {
728 if( own ) {
729 return new com.jogamp.nativewindow.x11.X11GraphicsDevice(displayConnection, unitID, null /* ToolkitLock */);
730 } else {
731 return new com.jogamp.nativewindow.x11.X11GraphicsDevice(displayConnection, unitID);
732 }
733 } else if( NativeWindowFactory.TYPE_WINDOWS == nwt ) {
734 return new com.jogamp.nativewindow.windows.WindowsGraphicsDevice(unitID);
735 } else if( NativeWindowFactory.TYPE_MACOSX == nwt ) {
736 return new com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice(unitID);
737 } else if( NativeWindowFactory.TYPE_IOS == nwt ) {
738 return new com.jogamp.nativewindow.ios.IOSGraphicsDevice(unitID);
739 } else if( NativeWindowFactory.TYPE_EGL == nwt ) {
741 if( own ) {
742 Object odev = null;
743 try {
744 // EGLDisplayUtil.eglCreateEGLGraphicsDevice(EGL.EGL_DEFAULT_DISPLAY, AbstractGraphicsDevice.DEFAULT_CONNECTION, unitID);
745 odev = ReflectionUtil.callStaticMethod("jogamp.opengl.egl.EGLDisplayUtil", "eglCreateEGLGraphicsDevice",
746 new Class<?>[] { Long.class, String.class, Integer.class},
747 new Object[] { 0L /* EGL.EGL_DEFAULT_DISPLAY */, DefaultGraphicsDevice.getDefaultDisplayConnection(nwt), unitID },
748 NativeWindowFactory.class.getClassLoader());
749 } catch (final Exception e) {
750 throw new NativeWindowException("EGLDisplayUtil.eglCreateEGLGraphicsDevice failed", e);
751 }
752 if( odev instanceof com.jogamp.nativewindow.egl.EGLGraphicsDevice ) {
753 device = (com.jogamp.nativewindow.egl.EGLGraphicsDevice)odev;
754 device.open();
755 } else {
756 throw new NativeWindowException("EGLDisplayUtil.eglCreateEGLGraphicsDevice failed");
757 }
758 } else {
759 device = new com.jogamp.nativewindow.egl.EGLGraphicsDevice(0 /* EGL.EGL_DEFAULT_DISPLAY */, displayConnection, unitID);
760 }
761 return device;
762 } else if( NativeWindowFactory.TYPE_AWT == nwt ) {
763 throw new UnsupportedOperationException("n/a for windowing system: "+nwt);
764 } else {
765 return new DefaultGraphicsDevice(nwt, displayConnection, unitID);
766 }
767 }
768
769 /**
770 * Creates a wrapped {@link NativeWindow} with given native handles and {@link AbstractGraphicsScreen}.
771 * <p>
772 * The given {@link UpstreamWindowHookMutableSizePos} maybe used to reflect resizes and repositioning of the native window.
773 * </p>
774 * <p>
775 * The {@link AbstractGraphicsScreen} may be created via {@link #createScreen(AbstractGraphicsDevice, int)}.
776 * </p>
777 * <p>
778 * The {@link AbstractGraphicsScreen} may have an underlying open {@link AbstractGraphicsDevice}
779 * or a simple <i>dummy</i> instance, see {@link #createDevice(String, boolean)}.
780 * </p>
781 */
782 public static NativeWindow createWrappedWindow(final AbstractGraphicsScreen aScreen, final long surfaceHandle, final long windowHandle,
784 final CapabilitiesImmutable caps = new Capabilities();
785 final AbstractGraphicsConfiguration config = new DefaultGraphicsConfiguration(aScreen, caps, caps);
786 return new WrappedWindow(config, surfaceHandle, hook, true, windowHandle);
787 }
788
789 /**
790 * @param nw
791 * @return top-left client-area position in window units
792 * <p>
793 * FIXME: Bug 973 Needs service provider interface (SPI) for TK dependent implementation
794 * </p>
795 */
796 public static Point getLocationOnScreen(final NativeWindow nw) {
797 final String nwt = NativeWindowFactory.getNativeWindowType(true);
798 if( NativeWindowFactory.TYPE_X11 == nwt ) {
799 return jogamp.nativewindow.x11.X11Lib.GetRelativeLocation(nw.getDisplayHandle(), nw.getScreenIndex(), nw.getWindowHandle(), 0, 0, 0);
800 } else if( NativeWindowFactory.TYPE_WINDOWS == nwt ) {
801 return jogamp.nativewindow.windows.GDIUtil.GetRelativeLocation(nw.getWindowHandle(), 0, 0, 0);
802 } else if( NativeWindowFactory.TYPE_MACOSX == nwt ) {
803 return jogamp.nativewindow.macosx.OSXUtil.GetLocationOnScreen(nw.getWindowHandle(), 0, 0);
804 } else if( NativeWindowFactory.TYPE_IOS == nwt ) {
805 return jogamp.nativewindow.ios.IOSUtil.GetLocationOnScreen(nw.getWindowHandle(), 0, 0);
806 /**
807 * FIXME: Needs service provider interface (SPI) for TK dependent implementation
808 } else if( NativeWindowFactory.TYPE_BCM_VC_IV == nwt ) {
809 } else if( NativeWindowFactory.TYPE_ANDROID== nwt ) {
810 } else if( NativeWindowFactory.TYPE_EGL == nwt ) {
811 } else if( NativeWindowFactory.TYPE_BCM_VC_IV == nwt ) {
812 } else if( NativeWindowFactory.TYPE_AWT == nwt ) {
813 */
814 }
815 throw new UnsupportedOperationException("n/a for windowing system: "+nwt);
816 }
817}
Specifies a set of capabilities that a window's rendering context must support, such as color depth p...
static String getDefaultDisplayConnection()
Return the default display connection for the given windowing toolkit type gathered via NativeWindowF...
Provides the mechanism by which the graphics configuration for a window can be chosen before the wind...
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 final String TYPE_EGL
OpenKODE/EGL type, as retrieved with getNativeWindowType(boolean).
static final String TYPE_WINDOWS
Microsoft Windows type, as retrieved with getNativeWindowType(boolean).
static AbstractGraphicsDevice createDevice(final String nwt, final String displayConnection, final int unitID, final boolean own)
Creates a native device type, following the given native-window-type.
static AbstractGraphicsDevice createDevice(final String nwt, final String displayConnection, final boolean own)
Creates a native device type, following the given native-window-type.
static final String TYPE_DEFAULT
Generic DEFAULT type, where platform implementation don't care, as retrieved with getNativeWindowType...
static ToolkitLock getDefaultToolkitLock()
Provides the system default ToolkitLock for the default system windowing type.
static final String TYPE_DRM_GBM
DRM/GBM type, as retrieved with getNativeWindowType(boolean).
static ToolkitLock getDefaultToolkitLock(final String type)
Provides the default ToolkitLock for type.
static final String TYPE_WAYLAND
Wayland/EGL type, as retrieved with getNativeWindowType(boolean).
static void registerFactory(final Class<?> windowClass, final NativeWindowFactory factory)
Registers a NativeWindowFactory handling window objects of the given class.
static boolean isNativeVisualIDValidForProcessing(final int visualID)
Returns true if the given visualID is valid for further processing, i.e.
static final String TYPE_X11
X11 type, as retrieved with getNativeWindowType(boolean).
static final String TYPE_IOS
iOS type, as retrieved with getNativeWindowType(boolean).
static final String TYPE_MACOSX
Mac OS X type, as retrieved with getNativeWindowType(boolean).
static final boolean isJVMShuttingDown()
Returns true if the JVM is shutting down, otherwise false.
static final String TYPE_BCM_VC_IV
Broadcom VC IV/EGL type, as retrieved with getNativeWindowType(boolean).
static NativeWindowFactory getFactory(final Class<?> windowClass)
Returns the appropriate NativeWindowFactory to handle window objects of the given type.
static final String TYPE_AWT
Generic AWT type, as retrieved with getNativeWindowType(boolean).
static ToolkitLock getAWTToolkitLock()
Returns the AWT ToolkitLock (JAWT based) if isAWTAvailable, otherwise null.
static synchronized void initSingleton()
Static one time initialization of this factory.
static Point getLocationOnScreen(final NativeWindow nw)
static AbstractGraphicsDevice createDevice(final String displayConnection, final boolean own)
Creates a native device type, following getNativeWindowType(true).
NativeWindowFactory()
Creates a new NativeWindowFactory instance.
static OffscreenLayerSurface getOffscreenLayerSurface(final NativeSurface surface, final boolean ifEnabled)
Returns the OffscreenLayerSurface instance of this NativeSurface.
static NativeWindow createWrappedWindow(final AbstractGraphicsScreen aScreen, final long surfaceHandle, final long windowHandle, final UpstreamWindowHookMutableSizePos hook)
Creates a wrapped NativeWindow with given native handles and AbstractGraphicsScreen.
static String getNativeWindowType(final boolean useCustom)
static String getDefaultDisplayConnection(final String nwt)
static synchronized void shutdown(final boolean _isJVMShuttingDown)
Cleanup resources at JVM shutdown.
static NativeWindowFactory getDefaultFactory()
Gets the default NativeWindowFactory.
static AbstractGraphicsScreen createScreen(final AbstractGraphicsDevice device, int screen)
static final String TYPE_ANDROID
Android/EGL type, as retrieved with getNativeWindowType(boolean).
static NativeWindow getNativeWindow(final Object winObj, final AbstractGraphicsConfiguration config)
Converts the given window object and it's AbstractGraphicsConfiguration into a NativeWindow which can...
static void addCustomShutdownHook(final boolean head, final Runnable runnable)
Add a custom shutdown hook to be performed at JVM shutdown before shutting down NativeWindowFactory i...
abstract NativeWindow getNativeWindowImpl(Object winObj, AbstractGraphicsConfiguration config)
Performs the conversion from a toolkit's window object to a NativeWindow.
static void setDefaultFactory(final NativeWindowFactory factory)
Don't know if we shall add this factory here .
static synchronized boolean isInitialized()
Returns true if initSingleton() has been called w/o subsequent shutdown(boolean).
A wrapper for an AWT GraphicsDevice allowing it to be handled in a toolkit-independent manner.
Encapsulates a graphics device on EGL platforms.
boolean open()
Opens the EGL device if handle is null and it's EGLDisplayLifecycleCallback is valid.
Encapsulates a graphics device on X11 platforms.
int getDefaultScreen()
Returns the default screen number as referenced by the display connection, i.e.
A marker interface describing a graphics configuration, visual, or pixel format in a toolkit-independ...
A interface describing a graphics device in a toolkit-independent manner.
String getType()
Returns the type of the underlying subsystem, ie NativeWindowFactory.TYPE_KD, NativeWindowFactory....
static int DEFAULT_UNIT
Default unit id for the 1st device: 0.
static String DEFAULT_CONNECTION
Dummy connection value for a default connection where no native support for multiple devices is avail...
A interface describing a graphics screen in a toolkit-independent manner.
Specifies an immutable set of capabilities that a window's rendering context must support,...
Provides low-level information required for hardware-accelerated rendering using a surface in a platf...
long getDisplayHandle()
Convenience: Get display handle from AbstractGraphicsConfiguration .
int getScreenIndex()
Convenience: Get display handle from AbstractGraphicsConfiguration .
Extend the NativeSurface interface with windowing information such as window-handle,...
long getWindowHandle()
Returns the window handle for this NativeWindow.
Handling requests for using an OffscreenLayerSurface within the implementation.
Interface specifying the offscreen layer surface protocol.
Marker for a singleton global recursive blocking lock implementation, optionally locking a native win...