add layout_scale preference, scaling cleanup, rework init bc_resources, init tip_info...
[goodguy/cinelerra.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 "aboutprefs.h"
22 #include "arraylist.h"
23 #include "batchrender.h"
24 #include "bcsignals.h"
25 #include "edl.h"
26 #include "file.h"
27 #include "filexml.h"
28 #include "filesystem.h"
29 #include "language.h"
30 #include "langinfo.h"
31 #include "loadfile.inc"
32 #include "mainmenu.h"
33 #include "mutex.h"
34 #include "mwindow.h"
35 #include "mwindowgui.h"
36 #include "pluginserver.h"
37 #include "preferences.h"
38 #include "renderfarmclient.h"
39 #include "units.h"
40 #include "versioninfo.h"
41
42 #include <locale.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <sys/time.h>
46 #include <sys/resource.h>
47
48 #ifdef LEAKER
49 #if 0  // track allocators
50 #include <execinfo.h>
51 #define BT_BUF_SIZE 100
52 static void leaker()
53 {
54         void *buffer[BT_BUF_SIZE];
55         int nptrs = backtrace(buffer, BT_BUF_SIZE);
56         char **trace = backtrace_symbols(buffer, nptrs);
57         if( !trace ) return;
58         for( int i=0; i<nptrs; ) printf("%s ", trace[i++]);
59         printf("\n");
60         free(trace);
61 }
62 #define STRB ;leaker()
63 #else
64 #define STRB
65 #endif
66 #define STRC(v) printf("==new %p from %p sz %jd\n", v, __builtin_return_address(0), n)STRB
67 #define STRD(v) printf("==del %p from %p\n", v, __builtin_return_address(0))
68 void *operator new(size_t n) { void *vp = malloc(n); STRC(vp); bzero(vp,n); return vp; }
69 void operator delete(void *t) { STRD(t); free(t); }
70 void operator delete(void *t,size_t n) { STRD(t); free(t); }
71 void *operator new[](size_t n) { void *vp = malloc(n); STRC(vp); bzero(vp,n); return vp; }
72 void operator delete[](void *t) { STRD(t); free(t); }
73 void operator delete[](void *t,size_t n) { STRD(t); free(t); }
74 #endif
75
76 enum
77 {
78         DO_GUI,
79         DO_DEAMON,
80         DO_DEAMON_FG,
81         DO_BRENDER,
82         DO_USAGE,
83         DO_BATCHRENDER
84 };
85
86 #include "thread.h"
87
88
89 class CommandLineThread : public Thread
90 {
91 public:
92         CommandLineThread(ArrayList<char*> *filenames,
93                 MWindow *mwindow)
94         {
95                 this->filenames = filenames;
96                 this->mwindow = mwindow;
97         }
98
99
100         ~CommandLineThread()
101         {
102         }
103
104         void run()
105         {
106 //PRINT_TRACE
107                 mwindow->gui->lock_window("main");
108 //PRINT_TRACE
109                 mwindow->load_filenames(filenames, LOADMODE_REPLACE);
110 //PRINT_TRACE
111                 if( filenames->size() == 1 )
112                         mwindow->gui->mainmenu->add_load(filenames->get(0));
113 //PRINT_TRACE
114                 mwindow->gui->unlock_window();
115 //PRINT_TRACE
116         }
117
118         MWindow *mwindow;
119         ArrayList<char*> *filenames;
120 };
121
122 long cin_timezone;
123
124 static float get_layout_scale()
125 {
126         char config_path[BCTEXTLEN];
127         sprintf(config_path,"%s/%s", File::get_config_path(), CONFIG_FILE);
128         FILE *fp = fopen(config_path,"r");
129         if( !fp ) return 0;
130         float scale = 0;
131         char line[BCTEXTLEN];
132         line[BCTEXTLEN-1] = 0;
133         while( fgets(line, BCTEXTLEN-1, fp) ) {
134                 if( !strncmp(line, "LAYOUT_SCALE ",12+1) ) {
135                         scale = atof(line+12);
136                         break;
137                 }
138         }
139         fclose(fp);
140         return scale;
141 }
142
143 int main(int argc, char *argv[])
144 {
145 // handle command line arguments first
146         srand(time(0));
147         ArrayList<char*> filenames;
148         FileSystem fs;
149
150         time_t st; time(&st);
151         struct tm ltm, gtm;
152         localtime_r(&st, &ltm);
153         gmtime_r(&st, &gtm);
154         int tzofs = ltm.tm_hour - gtm.tm_hour;
155         cin_timezone = tzofs * 60*60;
156
157         int operation = DO_GUI;
158         int deamon_port = DEAMON_PORT;
159         char deamon_path[BCTEXTLEN];
160         char config_path[BCTEXTLEN];
161         char batch_path[BCTEXTLEN];
162         int nice_value = 20;
163         int load_perpetual = 1;
164         config_path[0] = 0;
165         batch_path[0] = 0;
166         deamon_path[0] = 0;
167         Units::init();
168
169         File::init_cin_path();
170         const char *locale_path = File::get_locale_path();
171         const char *cin = File::get_cin();
172
173         bindtextdomain(cin, locale_path);
174         textdomain(cin);
175         setlocale(LC_MESSAGES, "");
176
177 #ifdef X_HAVE_UTF8_STRING
178         char *loc = setlocale(LC_CTYPE, "");
179         if( loc ) {
180                 strcpy(BC_Resources::encoding, nl_langinfo(CODESET));
181                 BC_Resources::locale_utf8 = !strcmp(BC_Resources::encoding, "UTF-8");
182
183                 // Extract from locale language & region
184                 char locbuf[32], *p;
185                 locbuf[0] = 0;
186                 if( (p = strchr(loc, '.')) != 0 && (p - loc) < (int)sizeof(locbuf)-1 ) {
187                         strncpy(locbuf, loc, p - loc);
188                         locbuf[p - loc] = 0;
189                 }
190                 else if( strlen(loc) < sizeof(locbuf)-1 )
191                         strcpy(locbuf, loc);
192
193                 // Locale 'C' does not give useful language info - assume en
194                 if( !locbuf[0] || locbuf[0] == 'C' )
195                         strcpy(locbuf, "en");
196
197                 if( (p = strchr(locbuf, '_')) && p - locbuf < LEN_LANG ) {
198                         *p++ = 0;
199                         strcpy(BC_Resources::language, locbuf);
200                         if( strlen(p) < LEN_LANG )
201                                 strcpy(BC_Resources::region, p);
202                 }
203                 else if( strlen(locbuf) < LEN_LANG )
204                         strcpy(BC_Resources::language, locbuf);
205         }
206         else
207                 printf(_(PROGRAM_NAME ": Could not set locale.\n"));
208 #else
209         setlocale(LC_CTYPE, "");
210 #endif
211         tzset();
212
213         int load_backup = 0;
214         int start_remote_control = 0;
215
216         for( int i = 1; i < argc; i++ ) {
217                 if( !strcmp(argv[i], "-h") ) {
218                         operation = DO_USAGE;
219                 }
220                 else if( !strcmp(argv[i], "-z") ) {
221                         start_remote_control = 1;
222                 }
223                 else if( !strcmp(argv[i], "-r") ) {
224                         operation = DO_BATCHRENDER;
225                         if( argc > i + 1 ) {
226                                 if( argv[i + 1][0] != '-' ) {
227                                         strcpy(batch_path, argv[i + 1]);
228                                         i++;
229                                 }
230                         }
231                 }
232                 else if( !strcmp(argv[i], "-c") ) {
233                         if( argc > i + 1 ) {
234                                 strcpy(config_path, argv[i + 1]);
235                                 i++;
236                         }
237                         else {
238                                 fprintf(stderr, _("%s: -c needs a filename.\n"), argv[0]);
239                         }
240                 }
241                 else if( !strcmp(argv[i], "-d") || !strcmp(argv[i], "-f") ) {
242                         operation = !strcmp(argv[i], "-d") ? DO_DEAMON : DO_DEAMON_FG;
243                         if( argc > i + 1 ) {
244                                 if( atol(argv[i + 1]) > 0 ) {
245                                         deamon_port = atol(argv[i + 1]);
246                                         i++;
247                                 }
248                         }
249                 }
250                 else if( !strcmp(argv[i], "-b") ) {
251                         operation = DO_BRENDER;
252                         if( i > argc - 2 ) {
253                                 fprintf(stderr, _("-b may not be used by the user.\n"));
254                                 exit(1);
255                         }
256                         else
257                                 strcpy(deamon_path, argv[i + 1]);
258                 }
259                 else if( !strcmp(argv[i], "-n") ) {
260                         if( argc > i + 1 ) {
261                                 nice_value = atol(argv[i + 1]);
262                                 i++;
263                         }
264                 }
265                 else if( !strcmp(argv[i], "-x") ) {
266                         load_backup = 1;
267                 }
268                 else if( !strcmp(argv[i], "-S") ) {
269                         load_perpetual = 0;
270                 }
271                 else {
272                         char *new_filename;
273                         new_filename = new char[BCTEXTLEN];
274                         strcpy(new_filename, argv[i]);
275                         fs.complete_path(new_filename);
276                         filenames.append(new_filename);
277                 }
278         }
279
280         float scale = operation == DO_GUI ?
281                 get_layout_scale() : 1;
282         // runs XInitThreads
283         BC_WindowBase::init_resources(scale);
284
285         if( operation == DO_GUI ||
286             operation == DO_DEAMON || operation == DO_DEAMON_FG ||
287             operation == DO_USAGE  || operation == DO_BATCHRENDER) {
288
289 #ifndef REPOMAINTXT
290 #define REPOMAINTXT ""
291 #endif
292 #ifndef COPYRIGHTTEXT1
293 #define COPYRIGHTTEXT1 ""
294 #endif
295 #ifndef COPYRIGHTTEXT2
296 #define COPYRIGHTTEXT2 ""
297 #endif
298                 fprintf(stderr, "%s %s - %s\n%s",
299                         PROGRAM_NAME,CINELERRA_VERSION, AboutPrefs::build_timestamp,
300                         REPOMAINTXT COPYRIGHTTEXT1 COPYRIGHTTEXT2);
301                 fprintf(stderr, "%s is free software, covered by the GNU General Public License,\n"
302                         "and you are welcome to change it and/or distribute copies of it under\n"
303                         "certain conditions. There is absolutely no warranty for %s.\n\n",
304                         PROGRAM_NAME, PROGRAM_NAME);
305         }
306
307         switch( operation ) {
308                 case DO_USAGE:
309                         printf(_("\nUsage:\n"));
310                         printf(_("%s [-f] [-c configuration] [-d port] [-n nice] [-r batch file] [filenames]\n\n"), argv[0]);
311                         printf(_("-d = Run in the background as renderfarm client.  The port (400) is optional.\n"));
312                         printf(_("-f = Run in the foreground as renderfarm client.  Substitute for -d.\n"));
313                         printf(_("-n = Nice value if running as renderfarm client. (19)\n"));
314                         printf(_("-c = Configuration file to use instead of %s/%s.\n"),
315                                 File::get_config_path(), CONFIG_FILE);
316                         printf(_("-r = batch render the contents of the batch file (%s/%s) with no GUI.  batch file is optional.\n"),
317                                 File::get_config_path(), BATCH_PATH);
318                         printf(_("-S = do not reload perpetual session\n"));
319                         printf(_("-x = reload from backup\n"));
320                         printf(_("filenames = files to load\n\n\n"));
321                         exit(0);
322                         break;
323
324                 case DO_DEAMON:
325                 case DO_DEAMON_FG: {
326                         if( operation == DO_DEAMON ) {
327                                 int pid = fork();
328
329                                 if( pid ) {
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 // Same thing without detachment
343                 case DO_BRENDER: {
344                         RenderFarmClient client(0,
345                                 deamon_path,
346                                 20,
347                                 config_path);
348                         client.main_loop();
349                         break; }
350
351                 case DO_BATCHRENDER: {
352                         BatchRenderThread *thread = new BatchRenderThread(0);
353                         thread->start_rendering(config_path,
354                                 batch_path);
355                         break; }
356
357                 case DO_GUI: {
358                         int restart = 0, done = 0;
359                         while( !done ) {
360                                 BC_WindowBase::get_resources()->vframe_shm = 0;
361                                 MWindow mwindow;
362                                 mwindow.create_objects(1, !filenames.total, config_path);
363                                 CommandLineThread *thread  = 0;
364                                 if( mwindow.preferences->perpetual_session && load_perpetual )
365                                         mwindow.load_undo_data();
366 //SET_TRACE
367 // load the initial files on seperate tracks
368 // use a new thread so it doesn't block the GUI
369                                 if( filenames.total ) {
370                                         thread  = new CommandLineThread(&filenames, &mwindow);
371                                         thread->start();
372 //PRINT_TRACE
373                                 }
374                                 if( load_backup ) {
375                                         load_backup = 0;
376                                         mwindow.gui->lock_window("main");
377                                         mwindow.load_backup();
378                                         mwindow.gui->unlock_window();
379                                 }
380                                 if( start_remote_control ) {
381                                         start_remote_control = 0;
382                                         mwindow.gui->remote_control->activate();
383                                 }
384 // run the program
385 //PRINT_TRACE
386                                 mwindow.start();
387                                 mwindow.run();
388 //PRINT_TRACE
389                                 restart = mwindow.restart();
390                                 if( restart ) {
391                                         mwindow.save_backup();
392                                         load_backup = 1;
393                                         start_remote_control =
394                                                 mwindow.gui->remote_control->is_active();
395                                 }
396                                 if( restart <= 0 )
397                                         done = 1;
398
399                                 mwindow.save_defaults();
400                                 if( mwindow.preferences->perpetual_session )
401                                         mwindow.save_undo_data();
402 //PRINT_TRACE
403                                 filenames.remove_all_objects();
404                                 delete thread;
405                         }
406
407                         if( restart < 0 ) {
408                                 char exe_path[BCTEXTLEN];
409                                 int len = readlink("/proc/self/exe", exe_path, sizeof(exe_path)-1);
410                                 if( len < 0 ) break;
411                                 exe_path[len] = 0;
412                                 char *av[4] = { 0, };  int ac = 0;
413                                 av[ac++] = exe_path;
414                                 if( load_backup ) av[ac++] = (char*) "-x";
415                                 if( start_remote_control ) av[ac++] = (char*) "-z";
416                                 av[ac++] = 0;
417                                 execv(exe_path, av);
418                         }
419 //SET_TRACE
420 DISABLE_BUFFER
421                 break; }
422         }
423
424         filenames.remove_all_objects();
425         Units::finit();
426         BC_WindowBase::finit_resources();
427
428         time_t et; time(&et);
429         long dt = et - st;
430         printf("Session time: %ld:%02ld:%02ld\n", dt/3600, dt%3600/60, dt%60);
431         struct rusage ru;
432         getrusage(RUSAGE_SELF, &ru);
433         long usr_ms = ru.ru_utime.tv_sec*1000 + ru.ru_utime.tv_usec/1000;
434         long us = usr_ms/1000;  int ums = usr_ms%1000;
435         long sys_ms = ru.ru_stime.tv_sec*1000 + ru.ru_stime.tv_usec/1000;
436         long ss = sys_ms/1000;  int sms = sys_ms%1000;
437         printf("Cpu time: user: %ld:%02ld:%02ld.%03d sys: %ld:%02ld:%02ld.%03d\n",
438                 us/3600, us%3600/60, us%60, ums, ss/3600, ss%3600/60, ss%60, sms);
439         return 0;
440 }
441