separate JVM start and SwingView register at scilab start in mn mode
[scilab.git] / scilab / modules / core / src / java / org / scilab / modules / core / Scilab.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2007-2008 - INRIA - Allan CORNET
4  * Copyright (C) 2007-2008 - INRIA - Vincent COUVERT
5  * Copyright (C) 2007-2008 - INRIA - Sylvestre LEDRU
6  * Copyright (C) 2007-2008 - INRIA - Jean-Baptiste SILVY
7  * Copyright (C) 2007-2008 - INRIA - Bruno JOFRET
8  * Copyright (C) 2011 - Calixte DENIZET
9  *
10  * Copyright (C) 2012 - 2016 - Scilab Enterprises
11  *
12  * This file is hereby licensed under the terms of the GNU GPL v2.0,
13  * pursuant to article 5.3.4 of the CeCILL v.2.1.
14  * This file was originally licensed under the terms of the CeCILL v2.1,
15  * and continues to be available under such terms.
16  * For more information, see the COPYING file which you should have received
17  * along with this program.
18  *
19  */
20
21 package org.scilab.modules.core;
22
23 import java.awt.GraphicsEnvironment;
24 import java.awt.Toolkit;
25 import java.util.ArrayList;
26 import java.util.List;
27
28 import javax.swing.JPopupMenu;
29 import javax.swing.SwingUtilities;
30
31 import org.flexdock.docking.DockingConstants;
32 import org.flexdock.docking.DockingManager;
33 import org.scilab.modules.commons.OS;
34 import org.scilab.modules.commons.ScilabCommonsUtils;
35 import org.scilab.modules.commons.ScilabConstants;
36 import org.scilab.modules.commons.xml.XConfiguration;
37 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
38 import org.scilab.modules.graphic_objects.graphicObject.GraphicObject.Type;
39 import org.scilab.modules.graphic_objects.utils.MenuBarBuilder;
40 import org.scilab.modules.gui.SwingView;
41 import org.scilab.modules.gui.bridge.console.SwingScilabConsole;
42 import org.scilab.modules.gui.bridge.tab.SwingScilabDockablePanel;
43 import org.scilab.modules.gui.bridge.window.SwingScilabWindow;
44 import org.scilab.modules.gui.console.ScilabConsole;
45 import org.scilab.modules.gui.tabfactory.ScilabTabFactory;
46 import org.scilab.modules.gui.utils.ClosingOperationsManager;
47 import org.scilab.modules.gui.utils.ConfigManager;
48 import org.scilab.modules.gui.utils.LookAndFeelManager;
49 import org.scilab.modules.gui.utils.WindowsConfigurationManager;
50
51 /**
52  * Main Class for Scilab
53  * @author Allan CORNET
54  * @author Jean-Baptiste SILVY
55  * @author Vincent COUVERT
56  * @author Sylvestre Ledru
57  * @author Bruno JOFRET
58  * @author Calixte DENIZET
59  */
60 public class Scilab {
61
62     static {
63         System.setProperty("java.protocol.handler.pkgs", "org.scilab.modules.commons");
64         XConfiguration.getXConfigurationDocument();
65     }
66
67     /** Index of windows vista version */
68     private static final double VISTA_VERSION = 6.0;
69
70     private static final String ENABLE_JAVA2D_OPENGL_PIPELINE = "sun.java2d.opengl";
71     private static final String ENABLE = "true";
72     private static final String DISABLE = "false";
73     private static final String DISABLE_DDRAW = "sun.java2d.noddraw";
74     private static final String OSNAME = "os.name";
75     private static final String MACOS = "mac";
76
77     private static boolean success;
78     private static boolean finish;
79     private static boolean exitCalled;
80     private static int mode;
81
82     private static List<Runnable> finalhooks = new ArrayList<Runnable>();
83     private static List<Runnable> initialhooks = new ArrayList<Runnable>();
84
85     /**
86      * WARNING : mainView is directly referenced from a JNI even it's private.
87      * TODO : Better add getter for this variable.
88      */
89     private SwingScilabWindow mainView;
90
91     /**
92      * Constructor Scilab Class.
93      * @param mode Mode Scilab -NW -NWNI -STD -API
94      */
95     public Scilab(int mode) {
96         Scilab.mode = mode;
97         ScilabConstants.setMode(mode);
98
99         DockingManager.setDockableFactory(ScilabTabFactory.getInstance());
100
101         /*
102          * Set Scilab directory. Note that it is done in the constructor
103          * and not as directly when setting the member because we had some
104          * race condition. See bug #4419
105          */
106         try {
107             /*
108              * Set Java directories to Scilab ones
109              */
110             if (mode != 1) {
111                 /* only modify these properties if Scilab is not called by another application */
112                 /* In this case, we let the calling application to use its own properties */
113                 System.setProperty("java.io.tmpdir", ScilabConstants.TMPDIR.getCanonicalPath());
114                 System.setProperty("user.home", ScilabConstants.SCIHOME.getCanonicalPath());
115             }
116
117         } catch (Exception e) {
118             System.err.println("Cannot retrieve the variable SCI. Please report on http://bugzilla.scilab.org/");
119             System.err.println(e.getLocalizedMessage());
120             System.exit(-1);
121         }
122
123         /*
124          * Set options for JOGL
125          * they must be set before creating GUI
126          */
127         setJOGLFlags();
128         /* Mode GUI */
129         if(mode == 2) {
130             SwingView.registerSwingView();
131         }
132
133         /*
134          * if not API mode
135          * bug 3673 by default in API mode we dont modify look n feel
136          * If SCI_JAVA_ENABLE_HEADLESS is set, do not set the look and feel.
137          * (needed when building the documentation under *ux)
138          */
139         if (mode != 1 && System.getenv("SCI_JAVA_ENABLE_HEADLESS") == null) {
140             /* http://java.sun.com/docs/books/tutorial/uiswing/lookandfeel/plaf.html */
141             try {
142
143                 String scilabLookAndFeel = "javax.swing.plaf.metal.MetalLookAndFeel";
144
145                 if (OS.get() == OS.WINDOWS) {
146                     scilabLookAndFeel = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
147                 } else if (System.getProperty(OSNAME).toLowerCase().indexOf(MACOS) != -1) {
148                     /** OPTION ADDED TO ALLOW DOCKING UNDER MACOSX */
149                     System.setProperty(DockingConstants.HEAVYWEIGHT_DOCKABLES, ENABLE);
150                     scilabLookAndFeel = "apple.laf.AquaLookAndFeel";
151                 } else {
152                     scilabLookAndFeel = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
153
154                     /*
155                      * Linux specific desktop integration
156                      */
157                     if (!GraphicsEnvironment.isHeadless()) {
158                         try {
159                             Toolkit xToolkit = Toolkit.getDefaultToolkit();
160                             java.lang.reflect.Field awtAppClassNameField =
161                                 xToolkit.getClass().getDeclaredField("awtAppClassName");
162                             awtAppClassNameField.setAccessible(true);
163
164                             awtAppClassNameField.set(xToolkit, "Scilab");
165                         } catch (Exception e) {
166                             System.err.println("Unable to set WM_CLASS, please report a bug on http://bugzilla.scilab.org/.");
167                             System.err.println("Error: " + e.getLocalizedMessage());
168                         }
169                     }
170                 }
171
172                 /* Init the LookAndFeelManager all the time since we can
173                  * create windows in the NW mode */
174                 if (!GraphicsEnvironment.isHeadless()) {
175                     LookAndFeelManager lookAndFeel = new LookAndFeelManager();
176
177                     if (lookAndFeel.isSupportedLookAndFeel(scilabLookAndFeel)) {
178                         lookAndFeel.setLookAndFeel(scilabLookAndFeel);
179                     } else {
180                         lookAndFeel.setSystemLookAndFeel();
181                     }
182                 }
183             } catch (java.lang.NoClassDefFoundError exception) {
184                 System.err.println("Could not initialize graphics Environment");
185                 System.err.println("Scilab Graphical option may not be working correctly.");
186                 System.err.println("An error occurred: " + exception.getLocalizedMessage());
187             }
188         }
189
190         if (mode == 2) { /* Mode GUI */
191             // Create a user config file if not already exists
192             ConfigManager.createUserCopy();
193
194             Integer consoleId = GraphicController.getController().askObject(Type.JAVACONSOLE);
195             MenuBarBuilder.buildConsoleMenuBar(consoleId);
196
197             SwingScilabConsole sciConsole = ((SwingScilabConsole) ScilabConsole.getConsole().getAsSimpleConsole());
198             SwingScilabDockablePanel consoleTab = (SwingScilabDockablePanel) sciConsole.getParent();
199
200             WindowsConfigurationManager.restorationFinished(consoleTab);
201
202             mainView = SwingScilabWindow.allScilabWindows.get(consoleTab.getParentWindowId());
203         } else {
204             GraphicController.getController().askObject(Type.CONSOLE);
205         }
206     }
207
208     /**
209      * @return the current mode
210      */
211     public static int getMode() {
212         return mode;
213     }
214
215     /**
216      * Sets the prompt displayed in Scilab console
217      * @param prompt the prompt to be displayed as a String
218      */
219     public void setPrompt(String prompt) {
220         ScilabConsole.getConsole().setPrompt(prompt);
221     }
222
223     /**
224      * Set the command line flags to the JVM
225      */
226     public static void setJOGLFlags() {
227
228         // Must give popUpMenu heavy weight
229         // in case we enable GLCanvas
230         JPopupMenu.setDefaultLightWeightPopupEnabled(false);
231         // Uneash OpenGL power
232         // Not yet
233         //System.setProperty(ENABLE_JAVA2D_OPENGL_PIPELINE, ENABLE_WITH_DEBUG);
234         System.setProperty(ENABLE_JAVA2D_OPENGL_PIPELINE, DISABLE);
235
236         if (OS.get() == OS.WINDOWS) {
237             if ((Double) OS.get().getVersion() >= VISTA_VERSION) {
238                 // don't enable OpenGL because of aero
239                 System.setProperty(ENABLE_JAVA2D_OPENGL_PIPELINE, DISABLE);
240             }
241             // desactivate direct3d and direct draw under windows
242             System.setProperty(DISABLE_DDRAW, ENABLE);
243         }
244     }
245
246     /**
247      * Call from canCloseMainScilabObject (call itself from sci_exit)
248      * @return true if the console is closed
249      */
250     public static boolean canClose() {
251         final Object lock = new Object();
252
253         SwingUtilities.invokeLater(new Runnable() {
254             @Override
255             public void run() {
256                 exitCalled = true;
257                 success = ClosingOperationsManager.startClosingOperationOnRoot();
258                 exitCalled = false;
259
260                 finish = true;
261                 synchronized (lock) {
262                     lock.notify();
263                 }
264             }
265         });
266
267         try {
268             synchronized (lock) {
269                 while (!finish) {
270                     lock.wait();
271                 }
272             }
273         } catch (InterruptedException e) {
274             System.err.println(e);
275         }
276         finish = false;
277
278         return success;
279     }
280
281     /**
282      * Call from forceCloseMainScilabObject (call itself from sci_exit)
283      */
284     public static void forceClose() {
285         final Object lock = new Object();
286
287         SwingUtilities.invokeLater(new Runnable() {
288             @Override
289             public void run() {
290                 exitCalled = true;
291                 ClosingOperationsManager.forceClosingOperationOnRoot();
292                 exitCalled = false;
293
294                 finish = true;
295                 synchronized (lock) {
296                     lock.notify();
297                 }
298             }
299         });
300
301         try {
302             synchronized (lock) {
303                 while (!finish) {
304                     lock.wait();
305                 }
306             }
307         } catch (InterruptedException e) {
308             System.err.println(e);
309         }
310         finish = false;
311     }
312
313     /**
314      * @return true if exit has been called from command line
315      */
316     public static boolean getExitCalled() {
317         return exitCalled;
318     }
319
320     /**
321      * Register a hook to execute just before the JVM shutdown.
322      * A hook should not contain threads, there is no warranty that they will be fully executed.
323      */
324     public static void registerFinalHook(Runnable hook) {
325         finalhooks.add(hook);
326     }
327
328     /**
329      * Remove a hook
330      */
331     public static void removeFinalHook(Runnable hook) {
332         finalhooks.remove(hook);
333     }
334
335     /**
336      * This method should be called from jni (finishMainScilabObject())
337      */
338     public static void executeFinalHooks() {
339         for (Runnable hook : finalhooks) {
340             hook.run();
341         }
342     }
343
344     /**
345      * Register a hook to execute after the Scilab initialization.
346      * A hook should not contain threads, there is no warranty that they will be fully executed.
347      */
348     public static void registerInitialHook(Runnable hook) {
349         initialhooks.add(hook);
350     }
351
352     /**
353      * Remove a hook
354      */
355     public static void removeInitialHook(Runnable hook) {
356         initialhooks.remove(hook);
357     }
358
359     /**
360      * This method should be called from C (realmain)
361      */
362     public static void executeInitialHooks() {
363         ScilabCommonsUtils.registerScilabThread();
364
365         for (final Runnable hook : initialhooks) {
366             hook.run();
367         }
368     }
369 }
370 /*--------------------------------------------------------------------------*/