Cross DrawerVisitor dispose/finalize may kill wrong JoGL component.
[scilab.git] / scilab / modules / gui / src / java / org / scilab / modules / gui / bridge / canvas / SwingScilabCanvasImpl.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2008 - DIGITEO - Bruno JOFRET
4  * Copyright (C) 2012 - Scilab Enterprises - Bruno JOFRET
5  *
6  * This file must be used under the terms of the CeCILL.
7  * This source file is licensed as described in the file COPYING, which
8  * you should have received as part of this distribution.  The terms
9  * are also available at
10  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
11  *
12  */
13
14 package org.scilab.modules.gui.bridge.canvas;
15
16 import java.awt.Component;
17 import java.awt.Frame;
18 import java.awt.HeadlessException;
19 import java.util.Calendar;
20 import java.util.StringTokenizer;
21
22 import javax.media.opengl.GL;
23 import javax.media.opengl.GLCapabilities;
24 import javax.media.opengl.GLException;
25 import javax.media.opengl.GLProfile;
26 import javax.media.opengl.awt.GLCanvas;
27 import javax.media.opengl.awt.GLJPanel;
28
29 import org.scilab.modules.action_binding.InterpreterManagement;
30 import org.scilab.modules.commons.OS;
31 import org.scilab.modules.gui.utils.Debug;
32 import org.scilab.modules.localization.Messages;
33
34 public class SwingScilabCanvasImpl {
35
36     private static final long serialVersionUID = -3110280842744630282L;
37
38     static boolean forceGLCanvas = false;
39     static boolean noGLJPanel = false;
40     static boolean testCanvasAtStartup = false;
41
42     static {
43         if (testCanvasAtStartup && OS.get() != OS.MAC) {
44             long lastTime = Calendar.getInstance().getTimeInMillis();
45
46             Debug.DEBUG("SwingScilabCanvasImpl", "=======================================");
47             String OS_NAME = System.getProperty("os.name");
48             Debug.DEBUG("SwingScilabCanvasImpl", "os.name=" + OS_NAME);
49             String OS_ARCH = System.getProperty("os.arch");
50             Debug.DEBUG("SwingScilabCanvasImpl", "os.arch=" + OS_ARCH);
51             Debug.DEBUG("SwingScilabCanvasImpl", "=======================================");
52
53             /*
54              * Bug #7526: moved out of the try/catch block since it contains
55              * no OpenGL calls.
56              */
57
58             if ( OS_NAME.contains("Windows") && OS_ARCH.equals("amd64") ) {
59                 // bug 3919 : JOGL x64 doesn't like x64 remote desktop on Windows
60                 // @TODO : bug report to JOGL
61                 String REMOTEDESKTOP = System.getenv("SCILAB_MSTS_SESSION");
62                 if (REMOTEDESKTOP != null) {
63                     if ( REMOTEDESKTOP.equals("OK") ) {
64                         noGLJPanel = true;
65                     }
66                 }
67
68                 if (noGLJPanel) {
69                     /** Inform the users */
70                     InterpreterManagement.requestScilabExec(
71                             String.format("disp(\"%s\"), disp(\"%s\")",
72                                     String.format(Messages.gettext("WARNING: Due to your configuration limitations, Scilab switched in a mode where mixing uicontrols and graphics is not available. Type %s for more information."), "\"\"help usecanvas\"\""),
73                                     String.format(Messages.gettext("In some cases, %s fixes the issue"), "\"\"system_setproperty(''jogl.gljpanel.nohw'','''');\"\"")
74                                     )
75                             );
76                 }
77             }
78
79             /*
80              * Bug #7526: this code block causes a crash on Windows and Intel Graphic HD cards
81              * with graphics drivers older than 8.15.10.2279 and is therefore not executed if
82              * Windows is the OS (the tests on driver and OpenGL versions are Linux-specific).
83              * Consequently, updateMaxCanvasSize, which determines the canvas size, is not called
84              * any more on Windows. However, it is still called when an actual graphics window is created
85              * (by the renderer module's SciRenderer init method), which still allows getting the maximum
86              * canvas dimensions, so this should not be an issue.
87              */
88             if (!OS_NAME.contains("Windows")) {
89
90                 try {
91                     GLCanvas tmpCanvas = new GLCanvas(new GLCapabilities(GLProfile.getDefault()));
92                     Frame tmpFrame = new Frame();
93                     tmpFrame.add(tmpCanvas);
94                     tmpFrame.setVisible(true);
95
96                     tmpCanvas.getContext().makeCurrent();
97                     GL gl = tmpCanvas.getGL();
98
99                     String GL_VENDOR = gl.glGetString(GL.GL_VENDOR);
100                     Debug.DEBUG("SwingScilabCanvasImpl", "GL_VENDOR=" + GL_VENDOR);
101                     String GL_RENDERER = gl.glGetString(GL.GL_RENDERER);
102                     Debug.DEBUG("SwingScilabCanvasImpl", "GL_RENDERER=" + GL_RENDERER);
103                     String GL_VERSION = gl.glGetString(GL.GL_VERSION);
104                     Debug.DEBUG("SwingScilabCanvasImpl", "GL_VERSION=" + GL_VERSION);
105                     //Debug.DEBUG("SwingScilabCanvasImpl", "GL_EXTENSIONS="+gl.glGetString(GL.GL_EXTENSIONS));
106                     Debug.DEBUG("SwingScilabCanvasImpl", "=======================================");
107                     //System.getProperties().list(System.err);
108
109                     // get maximum axes size
110                     //RenderingCapabilities.updateMaxCanvasSize(gl);
111
112                     tmpCanvas.getContext().release();
113                     tmpFrame.remove(tmpCanvas);
114                     tmpFrame.setVisible(false);
115                     tmpFrame.dispose();
116                     Debug.DEBUG("SwingScilabCanvasImpl", "Testing time = " + (Calendar.getInstance().getTimeInMillis() - lastTime) + "ms");
117
118                     noGLJPanel = false;
119
120                     // By default disable GLJPanel on Linux
121                     if (OS_NAME.contains("Linux")) {
122                         noGLJPanel = true;
123                         // Linux && NVIDIA
124                         if (GL_VENDOR.contains("NVIDIA")) {
125                             noGLJPanel = false;
126                         }
127                         // Linux && ATI
128                         if (GL_VENDOR.contains("ATI")) {
129                             StringTokenizer stSpace = new StringTokenizer(GL_VERSION, " ");
130                             StringTokenizer stDot = new StringTokenizer(stSpace.nextToken(), ".");
131                             int majorVersion = Integer.parseInt(stDot.nextToken());
132                             int minorVersion = Integer.parseInt(stDot.nextToken());
133                             int releaseVersion = Integer.parseInt(stDot.nextToken());
134                             // Only OpenGL version newer than 2.1.7873 works
135                             // available through ATI 8.8 installer
136                             // and driver newer than 8.52.3
137                             Debug.DEBUG("SwingScilabCanvasImpl", "majorVersion = "
138                                     + majorVersion + " minorVersion = " + minorVersion
139                                     + " releaseVersion = " + releaseVersion);
140                             if (majorVersion > 2
141                                     || majorVersion == 2 && minorVersion > 1
142                                     || majorVersion == 2 && minorVersion == 1 && releaseVersion >= 7873) {
143                                 noGLJPanel = false;
144                             }
145                         }
146                     }
147
148                     if (noGLJPanel) {
149                         /** Inform the users */
150                         InterpreterManagement.requestScilabExec(
151                                 String.format("disp(\"%s\"), disp(\"%s\")",
152                                         String.format(Messages.gettext("WARNING: Due to your configuration limitations, Scilab switched in a mode where mixing uicontrols and graphics is not available. Type %s for more information."), "\"\"help usecanvas\"\""),
153                                         String.format(Messages.gettext("In some cases, %s fixes the issue"), "\"\"system_setproperty(''jogl.gljpanel.nohw'','''');\"\"")
154                                         )
155                                 );
156                     }
157                 } catch (GLException e) {
158                     noGLJPanel = true;
159                     /** Inform the users */
160                     InterpreterManagement.requestScilabExec(
161                             String.format("disp(\"%s\"), disp(\"%s\")",
162                                     Messages.gettext("Due to your video card drivers limitations, that are not able to manage OpenGL, Scilab will not be able to draw any graphics. Please update your driver."),
163                                     String.format(Messages.gettext("In some cases, %s fixes the issue"), "\"\"system_setproperty(''jogl.gljpanel.nohw'','''');\"\"")
164                                     )
165                             );
166                 } catch (HeadlessException e) {
167                     // do not print anything on a CLI only environment
168                     noGLJPanel = true;
169                 }
170
171             }
172         }
173
174     }
175
176     static boolean enableGLCanvas = forceGLCanvas || noGLJPanel;
177
178     /**
179      * Change Global property forceGLCanvas
180      * if no GLJPanel is available, GLCanvas is forced
181      */
182     public static boolean switchToGLCanvas(boolean onOrOff) {
183         Debug.DEBUG("SwingScilabCanvasImpl", "switchToGLCanvas " + onOrOff);
184         if (!onOrOff && noGLJPanel) {
185             InterpreterManagement.requestScilabExec(Messages.gettext("disp(\"WARNING: Despite of our previous warning, you choose to use Scilab with advanced graphics capabilities. Type \"\"help usecanvas\"\" for more information.\")"));
186         }
187         enableGLCanvas = onOrOff;
188         return enableGLCanvas;
189     }
190
191     /**
192      * Get Global property forceGLCanvas
193      * if no GLJPanel is available, GLCanvas is forced
194      */
195     public static boolean isGLCanvasEnabled() {
196         return enableGLCanvas;
197     }
198
199     /*
200      * Using SafeGLJPanel for all platform to catch some EDT deletion/creation.
201      * Some buffer can be lost causing JoGL to crash
202      * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6503420
203      */
204     private final class SafeGLJPanel extends GLJPanel {
205         private static final long serialVersionUID = -6166986369022555750L;
206
207         public void display() {
208             try {
209                 super.display();
210             } catch (Exception e) {
211                 // Catch JoGL Exceptions and hide it ...
212                 // Make another try
213                 //System.err.println("[SafeGLJPanel.display] catching "+e.toString());
214                 super.reshape(getX(),getY(),getWidth(),getHeight());
215                 super.display();
216             }
217         }
218
219         // protected void paintComponent(final Graphics g) {
220         //     try {
221         //         super.paintComponent(g);
222         //     } catch (Exception e) {
223         //         // Catch JoGL Exceptions and hide it ...
224         //         // Make another try
225         //         System.err.println("[SafeGLJPanel.paintComponent] catching "+e.toString());
226         //     }
227         // }
228     }
229     
230     /*
231     * Empty class to allow xlick/xgetmouse
232     * catch same cannonical name
233     */
234     private final class SafeGLCanvas extends GLCanvas {
235         private static final long serialVersionUID = -3315164314205693678L;
236     }
237
238     private static SwingScilabCanvasImpl me = null;
239
240     public static SwingScilabCanvasImpl getInstance() {
241         if (me == null) {
242             me = new SwingScilabCanvasImpl();
243         }
244
245         return me;
246     }
247
248     public Component createOpenGLComponent() {
249         if (enableGLCanvas) {
250             return new SafeGLCanvas();
251         } else {
252             return new SafeGLJPanel();
253         }
254     }
255
256     public SwingScilabCanvasImpl() {}
257 }