Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / cinelerra / main.C
1 /*
2  * CINELERRA
3  * Copyright (C) 2010 Adam Williams <broadcast at earthling dot net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 #include "arraylist.h"
22 #include "batchrender.h"
23 #include "bcsignals.h"
24 #include "edl.h"
25 #include "file.inc"
26 #include "filexml.h"
27 #include "filesystem.h"
28 #include "language.h"
29 #include "langinfo.h"
30 #include "loadfile.inc"
31 #include "mainmenu.h"
32 #include "mutex.h"
33 #include "mwindow.h"
34 #include "mwindowgui.h"
35 #include "pluginserver.h"
36 #include "preferences.h"
37 #include "renderfarmclient.h"
38 #include "versioninfo.h"
39
40 #include <locale.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #define PACKAGE "cinelerra"
45 #define LOCALEDIR "/locale/"
46
47
48 enum
49 {
50         DO_GUI,
51         DO_DEAMON,
52         DO_DEAMON_FG,
53         DO_BRENDER,
54         DO_USAGE,
55         DO_BATCHRENDER
56 };
57
58 #include "thread.h"
59
60
61 class CommandLineThread : public Thread
62 {
63 public:
64         CommandLineThread(ArrayList<char*> *filenames,
65                 MWindow *mwindow)
66         {
67                 this->filenames = filenames;
68                 this->mwindow = mwindow;
69         }
70
71
72         ~CommandLineThread()
73         {
74         }
75
76         void run()
77         {
78 //PRINT_TRACE
79                 mwindow->gui->lock_window("main");
80 //PRINT_TRACE
81                 mwindow->load_filenames(filenames, LOADMODE_REPLACE);
82 //PRINT_TRACE
83                 if(filenames->size() == 1)
84                         mwindow->gui->mainmenu->add_load(filenames->get(0));
85 //PRINT_TRACE
86                 mwindow->gui->unlock_window();
87 //PRINT_TRACE
88         }
89
90         MWindow *mwindow;
91         ArrayList<char*> *filenames;
92 };
93
94
95 int main(int argc, char *argv[])
96 {
97 // handle command line arguments first
98         srand(time(0));
99         ArrayList<char*> filenames;
100         FileSystem fs;
101
102
103         int operation = DO_GUI;
104         int deamon_port = DEAMON_PORT;
105         char deamon_path[BCTEXTLEN];
106         char config_path[BCTEXTLEN];
107         char batch_path[BCTEXTLEN];
108         char locale_path[BCTEXTLEN];
109         char exe_path[BCTEXTLEN];
110         char env_path[BCTEXTLEN];
111         int nice_value = 20;
112         config_path[0] = 0;
113         batch_path[0] = 0;
114         deamon_path[0] = 0;
115         EDL::id_lock = new Mutex("EDL::id_lock");
116
117         get_exe_path(exe_path);
118         snprintf(env_path, sizeof(env_path), "CINELERRA_PATH=%s", exe_path);
119         putenv(env_path);
120         sprintf(locale_path, "%s%s", exe_path, LOCALEDIR);
121
122 // detect an UTF-8 locale and try to use a non-Unicode locale instead
123 // <---Beginning of dirty hack
124 // This hack will be removed as soon as Cinelerra is UTF-8 compliant
125 //    char *s, *language;
126
127 // Query user locale
128 //    if ((s = getenv("LC_ALL"))  ||
129 //              (s = getenv("LC_MESSAGES")) ||
130 //              (s = getenv("LC_CTYPE")) ||
131 //              (s = getenv ("LANG")))
132 //    {
133 // Test if user locale is set to Unicode
134 //        if (strstr(s, ".UTF-8"))
135 //        {
136 // extract language  from language-charset@variant
137 //          language = strtok (s, ".@");
138 // set language as the default locale
139 //          setenv("LANG", language, 1);
140 //        }
141 //    }
142 // End of dirty hack --->
143
144         bindtextdomain (PACKAGE, locale_path);
145         textdomain (PACKAGE);
146         setlocale (LC_MESSAGES, "");
147 #ifdef X_HAVE_UTF8_STRING
148         char *loc = setlocale(LC_CTYPE, "");
149         if( loc ) {
150                 strcpy(BC_Resources::encoding, nl_langinfo(CODESET));
151                 BC_Resources::locale_utf8 = !strcmp(BC_Resources::encoding, "UTF-8");
152
153                 // Extract from locale language & region
154                 char locbuf[32], *p;
155                 locbuf[0] = 0;
156                 if((p = strchr(loc, '.')) != 0 && (p - loc) < (int)sizeof(locbuf)-1) {
157                         strncpy(locbuf, loc, p - loc);
158                         locbuf[p - loc] = 0;
159                 }
160                 else if(strlen(loc) < sizeof(locbuf)-1)
161                         strcpy(locbuf, loc);
162
163                 // Locale 'C' does not give useful language info - assume en
164                 if(!locbuf[0] || locbuf[0] == 'C')
165                         strcpy(locbuf, "en");
166
167                 if((p = strchr(locbuf, '_')) && p - locbuf < LEN_LANG) {
168                         *p++ = 0;
169                         strcpy(BC_Resources::language, locbuf);
170                         if(strlen(p) < LEN_LANG)
171                                 strcpy(BC_Resources::region, p);
172                 }
173                 else if(strlen(locbuf) < LEN_LANG)
174                         strcpy(BC_Resources::language, locbuf);
175         }
176         else
177                 printf(_(PROGRAM_NAME ": Could not set locale.\n"));
178 #else
179         setlocale(LC_CTYPE, "");
180 #endif
181         tzset();
182
183         int load_backup = 0;
184         int start_remote_control = 0;
185
186         for(int i = 1; i < argc; i++)
187         {
188                 if(!strcmp(argv[i], "-h"))
189                 {
190                         operation = DO_USAGE;
191                 }
192                 else
193                 if(!strcmp(argv[i], "-z"))
194                 {
195                         start_remote_control = 1;
196                 }
197                 else
198                 if(!strcmp(argv[i], "-r"))
199                 {
200                         operation = DO_BATCHRENDER;
201                         if(argc > i + 1)
202                         {
203                                 if(argv[i + 1][0] != '-')
204                                 {
205                                         strcpy(batch_path, argv[i + 1]);
206                                         i++;
207                                 }
208                         }
209                 }
210                 else
211                 if(!strcmp(argv[i], "-c"))
212                 {
213                         if(argc > i + 1)
214                         {
215                                 strcpy(config_path, argv[i + 1]);
216                                 i++;
217                         }
218                         else
219                         {
220                                 fprintf(stderr, _("%s: -c needs a filename.\n"), argv[0]);
221                         }
222                 }
223                 else
224                 if(!strcmp(argv[i], "-d") || !strcmp(argv[i], "-f"))
225                 {
226                         if(!strcmp(argv[i], "-d"))
227                                 operation = DO_DEAMON;
228                         else
229                                 operation = DO_DEAMON_FG;
230
231                         if(argc > i + 1)
232                         {
233                                 if(atol(argv[i + 1]) > 0)
234                                 {
235                                         deamon_port = atol(argv[i + 1]);
236                                         i++;
237                                 }
238                         }
239                 }
240                 else
241                 if(!strcmp(argv[i], "-b"))
242                 {
243                         operation = DO_BRENDER;
244                         if(i > argc - 2)
245                         {
246                                 fprintf(stderr, _("-b may not be used by the user.\n"));
247                                 exit(1);
248                         }
249                         else
250                                 strcpy(deamon_path, argv[i + 1]);
251                 }
252                 else
253                 if(!strcmp(argv[i], "-n"))
254                 {
255                         if(argc > i + 1)
256                         {
257                                 nice_value = atol(argv[i + 1]);
258                                 i++;
259                         }
260                 }
261                 else
262                 if(!strcmp(argv[i], "-x"))
263                 {
264                         load_backup = 1;
265                 }
266                 else
267                 {
268                         char *new_filename;
269                         new_filename = new char[BCTEXTLEN];
270                         strcpy(new_filename, argv[i]);
271                         fs.complete_path(new_filename);
272                         filenames.append(new_filename);
273                 }
274         }
275
276
277
278         if(operation == DO_GUI ||
279                 operation == DO_DEAMON ||
280                 operation == DO_DEAMON_FG ||
281                 operation == DO_USAGE ||
282                 operation == DO_BATCHRENDER) {
283
284                 fprintf(stderr, PROGRAM_NAME " " CINELERRA_VERSION);
285 #ifndef REPOMAINTXT
286 #define REPOMAINTXT ""
287 #endif
288 #ifndef COPYRIGHTTEXT1
289 #define COPYRIGHTTEXT1 ""
290 #endif
291 #ifndef COPYRIGHTTEXT2
292 #define COPYRIGHTTEXT2 ""
293 #endif
294 #ifndef COMPILEDATE
295 #define COMPILEDATE ""
296 #endif
297                 fprintf(stderr, REPOMAINTXT COPYRIGHTTEXT1 COPYRIGHTTEXT2 COMPILEDATE
298                         PROGRAM_NAME " is free software, covered by the GNU General Public License,\n"
299                         "and you are welcome to change it and/or distribute copies of it under\n"
300                         "certain conditions. There is absolutely no warranty for " PROGRAM_NAME ".\n\n");
301         }
302
303         switch(operation)
304         {
305                 case DO_USAGE:
306                         printf(_("\nUsage:\n"));
307                         printf(_("%s [-f] [-c configuration] [-d port] [-n nice] [-r batch file] [filenames]\n\n"), argv[0]);
308                         printf(_("-d = Run in the background as renderfarm client.  The port (400) is optional.\n"));
309                         printf(_("-f = Run in the foreground as renderfarm client.  Substitute for -d.\n"));
310                         printf(_("-n = Nice value if running as renderfarm client. (20)\n"));
311                         printf(_("-c = Configuration file to use instead of %s%s.\n"),
312                                 BCASTDIR,
313                                 CONFIG_FILE);
314                         printf(_("-r = batch render the contents of the batch file (%s%s) with no GUI.  batch file is optional.\n"),
315                                 BCASTDIR,
316                                 BATCH_PATH);
317                         printf(_("filenames = files to load\n\n\n"));
318                         exit(0);
319                         break;
320
321                 case DO_DEAMON:
322                 case DO_DEAMON_FG:
323                 {
324                         if(operation == DO_DEAMON)
325                         {
326                                 int pid = fork();
327
328                                 if(pid)
329                                 {
330 // Redhat 9 requires _exit instead of exit here.
331                                         _exit(0);
332                                 }
333                         }
334
335                         RenderFarmClient client(deamon_port,
336                                 0,
337                                 nice_value,
338                                 config_path);
339                         client.main_loop();
340                         break;
341                 }
342
343 // Same thing without detachment
344                 case DO_BRENDER:
345                 {
346                         RenderFarmClient client(0,
347                                 deamon_path,
348                                 20,
349                                 config_path);
350                         client.main_loop();
351                         break;
352                 }
353
354                 case DO_BATCHRENDER:
355                 {
356                         BatchRenderThread *thread = new BatchRenderThread;
357                         thread->start_rendering(config_path,
358                                 batch_path);
359                         break;
360                 }
361
362                 case DO_GUI:
363                 {
364                         int restart = 0, done = 0;
365                         while( !done ) {
366                                 BC_WindowBase::get_resources()->vframe_shm = 0;
367                                 MWindow mwindow;
368                                 mwindow.create_objects(1, !filenames.total, config_path);
369                                 CommandLineThread *thread  = 0;
370 //SET_TRACE
371 // load the initial files on seperate tracks
372 // use a new thread so it doesn't block the GUI
373                                 if( filenames.total ) {
374                                         thread  = new CommandLineThread(&filenames, &mwindow);
375                                         thread->start();
376 //PRINT_TRACE
377                                 }
378                                 if( load_backup ) {
379                                         load_backup = 0;
380                                         mwindow.gui->lock_window("main");
381                                         mwindow.load_backup();
382                                         mwindow.gui->unlock_window();
383                                 }
384                                 if( start_remote_control ) {
385                                         start_remote_control = 0;
386                                         mwindow.gui->remote_control->activate();
387                                 }
388 // run the program
389 //PRINT_TRACE
390                                 mwindow.start();
391                                 mwindow.run();
392 //PRINT_TRACE
393                                 restart = mwindow.restart();
394                                 if( restart ) {
395                                         mwindow.save_backup();
396                                         load_backup = 1;
397                                         start_remote_control =
398                                                 mwindow.gui->remote_control->is_active();
399                                 }
400                                 if( restart <= 0 )
401                                         done = 1;
402
403                                 mwindow.save_defaults();
404 //PRINT_TRACE
405                                 filenames.remove_all_objects();
406                                 delete thread;
407                         }
408
409                         if( restart < 0 ) {
410                                 char exe_path[BCTEXTLEN];
411                                 int len = readlink("/proc/self/exe", exe_path, sizeof(exe_path)-1);
412                                 if( len < 0 ) break;
413                                 exe_path[len] = 0;
414                                 char *av[4] = { 0, };  int ac = 0;
415                                 av[ac++] = exe_path;
416                                 if( load_backup ) av[ac++] = (char*) "-x";
417                                 if( start_remote_control ) av[ac++] = (char*) "-z";
418                                 av[ac++] = 0;
419                                 execv(exe_path, av);
420                         }
421                 }
422 //SET_TRACE
423 DISABLE_BUFFER
424                 break;
425         }
426
427         filenames.remove_all_objects();
428         delete EDL::id_lock;  EDL::id_lock = 0;
429
430         return 0;
431 }
432