From ee2c18211a5128f5cde5312a7bbb5c0e80674903 Mon Sep 17 00:00:00 2001
From: Sven Gothel <sgothel@jausoft.com>
Date: Fri, 27 Mar 2015 15:10:54 +0100
Subject: Bug 1116: Add ShutdownHook for all factories and devices to
 StereoDeviceFactory using NativeWindowFactory

---
 .../jogamp/opengl/util/stereo/StereoDevice.java    |  8 +-
 .../opengl/util/stereo/StereoDeviceFactory.java    | 89 +++++++++++++++++++++-
 .../stereo/generic/GenericStereoDeviceFactory.java | 16 +++-
 3 files changed, 105 insertions(+), 8 deletions(-)

(limited to 'src/jogl/classes/com/jogamp/opengl/util')

diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java
index 6d8b85d8e..d59863530 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java
@@ -44,9 +44,15 @@ public interface StereoDevice {
     /** Return the factory used to create this device. */
     public StereoDeviceFactory getFactory();
 
-    /** Disposes this {@link StereoDevice}. */
+    /** Disposes this {@link StereoDevice}, if {@link #isValid() valid}. */
     public void dispose();
 
+    /**
+     * Returns {@code true}, if instance is created and not {@link #dispose() disposed},
+     * otherwise returns {@code false}.
+     */
+    public boolean isValid();
+
     /**
      * If operation within a device spanning virtual desktop,
      * returns the device position.
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceFactory.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceFactory.java
index 3847b7d3e..105fe6c70 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceFactory.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceFactory.java
@@ -27,7 +27,11 @@
  */
 package com.jogamp.opengl.util.stereo;
 
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
 import com.jogamp.common.util.ReflectionUtil;
+import com.jogamp.nativewindow.NativeWindowFactory;
 
 /**
  * Platform agnostic {@link StereoDevice} factory.
@@ -44,6 +48,14 @@ public abstract class StereoDeviceFactory {
     private static final String OVRStereoDeviceClazzName = "jogamp.opengl.oculusvr.OVRStereoDeviceFactory";
     private static final String GenericStereoDeviceClazzName = com.jogamp.opengl.util.stereo.generic.GenericStereoDeviceFactory.class.getName();
     private static final String isAvailableMethodName = "isAvailable";
+    static {
+        NativeWindowFactory.addCustomShutdownHook(false /* head */, new Runnable() {
+           @Override
+           public void run() {
+               shutdownAll();
+           }
+        });
+    }
 
     /** {@link StereoDevice} type used for {@link StereoDeviceFactory#createFactory(DeviceType) createFactory(type)}. */
     public static enum DeviceType {
@@ -91,12 +103,16 @@ public abstract class StereoDeviceFactory {
     }
 
     public static StereoDeviceFactory createFactory(final ClassLoader cl, final String implName) {
+        StereoDeviceFactory res = null;
         try {
             if(((Boolean)ReflectionUtil.callStaticMethod(implName, isAvailableMethodName, null, null, cl)).booleanValue()) {
-                return (StereoDeviceFactory) ReflectionUtil.createInstance(implName, cl);
+                res = (StereoDeviceFactory) ReflectionUtil.createInstance(implName, cl);
             }
         } catch (final Throwable t) { if(StereoDevice.DEBUG) { System.err.println("Caught "+t.getClass().getName()+": "+t.getMessage()); t.printStackTrace(); } }
-        return null;
+        if( null != res ) {
+            addFactory2List(res);
+        }
+        return res;
     }
 
     /**
@@ -106,10 +122,75 @@ public abstract class StereoDeviceFactory {
      * @param verbose
      * @return
      */
-    public abstract StereoDevice createDevice(final int deviceIndex, final StereoDeviceConfig config, final boolean verbose);
+    public final StereoDevice createDevice(final int deviceIndex, final StereoDeviceConfig config, final boolean verbose) {
+        final StereoDevice device = createDeviceImpl(deviceIndex, config, verbose);
+        if( null != device ) {
+            addDevice2List(device);
+        }
+        return device;
+    }
+    protected abstract StereoDevice createDeviceImpl(final int deviceIndex, final StereoDeviceConfig config, final boolean verbose);
+
+    /**
+     * Returns {@code true}, if instance is created and not {@link #shutdown()}
+     * otherwise returns {@code false}.
+     */
+    public abstract boolean isValid();
 
     /**
-     * Shutdown factory
+     * Shutdown factory if {@link #isValid() valid}.
      */
     public abstract void shutdown();
+
+    private static final ArrayList<WeakReference<StereoDeviceFactory>> factoryList = new ArrayList<WeakReference<StereoDeviceFactory>>();
+    private static void addFactory2List(final StereoDeviceFactory factory) {
+        synchronized(factoryList) {
+            // GC before add
+            int i=0;
+            while( i < factoryList.size() ) {
+                if( null == factoryList.get(i).get() ) {
+                    factoryList.remove(i);
+                } else {
+                    i++;
+                }
+            }
+            factoryList.add(new WeakReference<StereoDeviceFactory>(factory));
+        }
+    }
+    private static final ArrayList<WeakReference<StereoDevice>> deviceList = new ArrayList<WeakReference<StereoDevice>>();
+    private static void addDevice2List(final StereoDevice device) {
+        synchronized(deviceList) {
+            // GC before add
+            int i=0;
+            while( i < deviceList.size() ) {
+                if( null == deviceList.get(i).get() ) {
+                    deviceList.remove(i);
+                } else {
+                    i++;
+                }
+            }
+            deviceList.add(new WeakReference<StereoDevice>(device));
+        }
+    }
+
+    private final static void shutdownAll() {
+        shutdownDevices();
+        shutdownFactories();
+    }
+    private final static void shutdownFactories() {
+        while( 0 < factoryList.size() ) {
+            final StereoDeviceFactory f = factoryList.remove(0).get();
+            if( null != f && f.isValid() ) {
+                f.shutdown();
+            }
+        }
+    }
+    private final static void shutdownDevices() {
+        while( 0 < deviceList.size() ) {
+            final StereoDevice d = deviceList.remove(0).get();
+            if( null != d && d.isValid() ) {
+                d.dispose();
+            }
+        }
+    }
 }
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceFactory.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceFactory.java
index 9c28c0767..6adb96ba4 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceFactory.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceFactory.java
@@ -187,12 +187,22 @@ public class GenericStereoDeviceFactory extends StereoDeviceFactory {
     }
 
     @Override
-    public final StereoDevice createDevice(final int deviceIndex, final StereoDeviceConfig config, final boolean verbose) {
+    protected final StereoDevice createDeviceImpl(final int deviceIndex, final StereoDeviceConfig config, final boolean verbose) {
         return new GenericStereoDevice(this, deviceIndex, config);
     }
 
+    private boolean isValid = true;
+
     @Override
-    public void shutdown() {
-        // NOP
+    public boolean isValid() {
+        return isValid;
+    }
+
+    @Override
+    public final void shutdown() {
+        if( isValid ) {
+            // NOP
+            isValid = false;
+        }
     }
 }
-- 
cgit v1.2.3