Create startup module for real MAIN function. Fix MacOSX compilation
[scilab.git] / scilab / modules / console / src / c / others / initMacOSXEnv.c
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2007 - DIGITEO - Sylvestre LEDRU
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  *
11  */
12 #include <stdlib.h>
13 #include "scilabmode.h"
14 #include "realmain.h"
15 #include "initMacOSXEnv.h"
16
17 #if defined(__APPLE__) && !defined(WITHOUT_GUI)
18 #include <pthread.h>
19 #include <CoreFoundation/CoreFoundation.h>
20 #include <sys/stat.h>
21 #include <ApplicationServices/ApplicationServices.h>
22 #endif
23
24
25 #if defined(__APPLE__) && !defined(WITHOUT_GUI)
26
27 typedef struct
28 {
29     int   no_startup_flag_l;
30     char  *initial_script;
31     InitScriptType initial_script_type;
32     int memory;
33 } thread_parm_t;
34
35 /*
36 Some parts of the next three functions have been taken from simpleJavaLauncher.
37
38
39   Copyright:   ¬© Copyright 2003 Apple Computer, Inc. All rights reserved.
40
41   Disclaimer:  IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
42         ("Apple") in consideration of your agreement to the following terms, and your
43         use, installation, modification or redistribution of this Apple software
44         constitutes acceptance of these terms.  If you do not agree with these terms,
45         please do not use, install, modify or redistribute this Apple software.
46
47         In consideration of your agreement to abide by the following terms, and subject
48         to these terms, Apple grants you a personal, non-exclusive license, under Apple's
49         copyrights in this original Apple software (the "Apple Software"), to use,
50         reproduce, modify and redistribute the Apple Software, with or without
51         modifications, in source and/or binary forms; provided that if you redistribute
52         the Apple Software in its entirety and without modifications, you must retain
53         this notice and the following text and disclaimers in all such redistributions of
54         the Apple Software.  Neither the name, trademarks, service marks or logos of
55         Apple Computer, Inc. may be used to endorse or promote products derived from the
56         Apple Software without specific prior written permission from Apple.  Except as
57         expressly stated in this notice, no other rights or licenses, express or implied,
58         are granted by Apple herein, including but not limited to any patent rights that
59         may be infringed by your derivative works or by other works in which the Apple
60         Software may be incorporated.
61
62         The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
63         WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
64         WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
65         PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
66         COMBINATION WITH YOUR PRODUCTS.
67
68         IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
69         CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
70         GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
71         ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
72         OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
73         (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
74         ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
75 */
76
77 /**
78  * Set the name of the application (the mac os x way)
79  * @param name the name of the application
80  */
81 static void setAppName(const char * name)
82 {
83     char a[32];
84     pid_t id = getpid();
85     sprintf(a, "APP_NAME_%ld", (long)id);
86     setenv(a, name, 1);
87 }
88
89 /**
90  * Actually launch Scilab under Mac OS X. Need to be in a specific thread.
91  * See http://wiki.scilab.org/Compiling_Scilab_5.x_under_MacOSX
92  * @param param The structure containing the missing argument mandatory for realmain
93  * @return the result of the operation (0 if OK ...)
94  */
95 static int launchMacOSXEnv(thread_parm_t *param)
96 {
97     thread_parm_t *p = (thread_parm_t *)param;
98     int ret = -1;
99     {
100         CFStringRef targetJVM = CFSTR("1.5");
101         CFBundleRef JavaVMBundle;
102         CFURLRef    JavaVMBundleURL;
103         CFURLRef    JavaVMBundlerVersionsDirURL;
104         CFURLRef    TargetJavaVM;
105         UInt8 pathToTargetJVM [PATH_MAX] = "\0";
106         struct stat sbuf;
107
108         /*
109          * This piece of code is mandatory because Mac OS X implementation of Java has a bug here.
110          * Cocoa does not know how to handle the new window created this way.
111          * See: http://lists.apple.com/archives/Java-dev/2009/Jan/msg00062.html
112          * Or Mac Os X bug #6484319
113          * Thanks to Mike Swingler
114          */
115         ProcessSerialNumber psn;
116         GetCurrentProcess(&psn);
117         TransformProcessType(&psn, kProcessTransformToForegroundApplication);
118         /* End of the workaround */
119
120         // Look for the JavaVM bundle using its identifier
121         JavaVMBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.JavaVM") );
122
123         if (JavaVMBundle != NULL)
124         {
125             // Get a path for the JavaVM bundle
126             JavaVMBundleURL = CFBundleCopyBundleURL(JavaVMBundle);
127             CFRelease(JavaVMBundle);
128
129             if (JavaVMBundleURL != NULL)
130             {
131                 // Append to the path the Versions Component
132                 JavaVMBundlerVersionsDirURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, JavaVMBundleURL, CFSTR("Versions"), true);
133                 CFRelease(JavaVMBundleURL);
134
135                 if (JavaVMBundlerVersionsDirURL != NULL)
136                 {
137                     // Append to the path the target JVM's Version
138                     TargetJavaVM = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, JavaVMBundlerVersionsDirURL, targetJVM, true);
139                     CFRelease(JavaVMBundlerVersionsDirURL);
140                     if (TargetJavaVM != NULL)
141                     {
142                         if (CFURLGetFileSystemRepresentation (TargetJavaVM, true, pathToTargetJVM, PATH_MAX ))
143                         {
144                             // Check to see if the directory, or a sym link for the target JVM directory exists, and if so set the
145                             // environment variable JAVA_JVM_VERSION to the target JVM.
146                             if (stat((char*)pathToTargetJVM, &sbuf) == 0)
147                             {
148                                 // Ok, the directory exists, so now we need to set the environment var JAVA_JVM_VERSION to the CFSTR targetJVM
149                                 // We can reuse the pathToTargetJVM buffer to set the environement var.
150                                 if (CFStringGetCString(targetJVM, (char*)pathToTargetJVM, PATH_MAX, kCFStringEncodingUTF8))
151                                 {
152                                     setenv("JAVA_JVM_VERSION", (char*)pathToTargetJVM, 1);
153                                     ret = 0;
154                                 }
155                                 else
156                                 {
157                                     fprintf(stderr, "Could not get the path to the target JVM.\n");
158                                 }
159                             }
160                             else
161                             {
162                                 fprintf(stderr, "Error checking symlink for the target jvm.\n");
163                             }
164                         }
165                         else
166                         {
167                             fprintf(stderr, "Error getting file system representation for bundle url.\n");
168                             CFRelease(TargetJavaVM);
169                         }
170                     }
171                     else
172                     {
173                         fprintf(stderr, "Error appending version component to bundle url.\n");
174                     }
175                 }
176                 else
177                 {
178                     fprintf(stderr, "Error appending path component to bundle url.\n");
179                 }
180             }
181             else
182             {
183                 fprintf(stderr, "Error copying bundle url.\n");
184             }
185         }
186         else
187         {
188             fprintf(stderr, "Error: cant find bundle: com.apple.JavaVM.\n");
189         }
190     }
191
192     if (ret == 0)
193     {
194         /* Call the actual startup script of Scilab */
195         ret = realmain(p->no_startup_flag_l, p->initial_script, p->initial_script_type, p->memory);
196         free(p);
197         exit(ret);
198     }
199     free(p);
200     return ret;
201
202 }
203
204 /* call back for dummy source used to make sure the CFRunLoop doesn't exit right away */
205 /* This callback is called when the source has fired. */
206 static void sourceCallBack (  void *info  ) {}
207
208 /* Specific wrapper for mac os X which is going to call realmin in a specific thread.
209  * Takes the same args as realmain
210  */
211 int initMacOSXEnv(int no_startup_flag_l, char *initial_script, InitScriptType initial_script_type, int memory)
212 {
213
214     CFRunLoopSourceContext sourceContext;
215     /* Start the thread that runs the VM. */
216     pthread_t vmthread;
217     setAppName("Scilab");
218
219     /* Create the structure which is going to be giving to the function inside the thread */
220     thread_parm_t         *param = NULL;
221     param = malloc(sizeof(thread_parm_t));
222     param->no_startup_flag_l = no_startup_flag_l;
223     param->initial_script = initial_script;
224     param->initial_script_type = initial_script_type;
225     param->memory = memory;
226
227     /* create a new pthread copying the stack size of the primordial pthread */
228     struct rlimit limit;
229     size_t stack_size = 0;
230     int rc = getrlimit(RLIMIT_STACK, &limit);
231     if (rc == 0)
232     {
233         if (limit.rlim_cur != 0LL)
234         {
235             stack_size = (size_t)limit.rlim_cur;
236         }
237     }
238     pthread_attr_t thread_attr;
239     pthread_attr_init(&thread_attr);
240     pthread_attr_setscope(&thread_attr, PTHREAD_SCOPE_SYSTEM);
241     pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
242     if (stack_size > 0)
243     {
244         pthread_attr_setstacksize(&thread_attr, stack_size);
245     }
246
247     /* Start the thread that we will start the JVM on. */
248     pthread_create(&vmthread, &thread_attr,  launchMacOSXEnv, (void*)param);
249     pthread_attr_destroy(&thread_attr);
250
251     /* Create a sourceContext to be used by our source that makes */
252     /* sure the CFRunLoop doesn't exit right away */
253     sourceContext.version = 0;
254     sourceContext.info = NULL;
255     sourceContext.retain = NULL;
256     sourceContext.release = NULL;
257     sourceContext.copyDescription = NULL;
258     sourceContext.equal = NULL;
259     sourceContext.hash = NULL;
260     sourceContext.schedule = NULL;
261     sourceContext.cancel = NULL;
262     sourceContext.perform = &sourceCallBack;
263
264     /* Create the Source from the sourceContext */
265     CFRunLoopSourceRef sourceRef = CFRunLoopSourceCreate (NULL, 0, &sourceContext);
266
267     /* Use the constant kCFRunLoopCommonModes to add the source to the set of objects */
268     /* monitored by all the common modes */
269     CFRunLoopAddSource (CFRunLoopGetCurrent(), sourceRef, kCFRunLoopCommonModes);
270
271     /* Park this thread in the runloop */
272     CFRunLoopRun();
273
274     return 0;
275 }
276 #endif