nix startup on theme fail, fixes for font init and titler color model
[goodguy/history.git] / cinelerra-5.0 / cinelerra / mwindow.C
1 /*
2  * CINELERRA
3  * Copyright (C) 1997-2014 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 "asset.h"
22 #include "assets.h"
23 #include "audioalsa.h"
24 #include "awindowgui.h"
25 #include "awindow.h"
26 #include "batchrender.h"
27 #include "bcdisplayinfo.h"
28 #include "bcsignals.h"
29 #include "bctimer.h"
30 #include "brender.h"
31 #include "cache.h"
32 #include "channel.h"
33 #include "channeldb.h"
34 #include "channelinfo.h"
35 #include "clip.h"
36 #include "colormodels.h"
37 #include "commercials.h"
38 #include "cplayback.h"
39 #include "ctimebar.h"
40 #include "cwindowgui.h"
41 #include "cwindow.h"
42 #include "bchash.h"
43 #include "devicedvbinput.inc"
44 #include "editpanel.h"
45 #include "edl.h"
46 #include "edlsession.h"
47 #include "errorbox.h"
48 #include "fileformat.h"
49 #include "file.h"
50 #include "fileserver.h"
51 #include "filesystem.h"
52 #include "filexml.h"
53 #include "format.inc"
54 #include "framecache.h"
55 #include "gwindow.h"
56 #include "gwindowgui.h"
57 #include "keyframegui.h"
58 #include "indexfile.h"
59 #include "language.h"
60 #include "levelwindowgui.h"
61 #include "levelwindow.h"
62 #include "loadfile.inc"
63 #include "localsession.h"
64 #include "maincursor.h"
65 #include "mainerror.h"
66 #include "mainindexes.h"
67 #include "mainmenu.h"
68 #include "mainprogress.h"
69 #include "mainsession.h"
70 #include "mainundo.h"
71 #include "mbuttons.h"
72 #include "mutex.h"
73 #include "mwindowgui.h"
74 #include "mwindow.h"
75 #include "nestededls.h"
76 #include "new.h"
77 #include "patchbay.h"
78 #include "playback3d.h"
79 #include "playbackengine.h"
80 #include "plugin.h"
81 #include "pluginserver.h"
82 #include "pluginset.h"
83 #include "preferences.h"
84 #include "record.h"
85 #include "recordmonitor.h"
86 #include "recordlabel.h"
87 #include "removefile.h"
88 #include "render.h"
89 #include "samplescroll.h"
90 #include "sha1.h"
91 #include "sighandler.h"
92 #include "splashgui.h"
93 #include "statusbar.h"
94 #include "theme.h"
95 #include "threadloader.h"
96 #include "timebar.h"
97 #include "tipwindow.h"
98 #include "trackcanvas.h"
99 #include "track.h"
100 #include "tracking.h"
101 #include "trackscroll.h"
102 #include "tracks.h"
103 #include "transition.h"
104 #include "transportque.h"
105 #include "vframe.h"
106 #include "videodevice.inc"
107 #include "videowindow.h"
108 #include "vplayback.h"
109 #include "vwindowgui.h"
110 #include "vwindow.h"
111 #include "wavecache.h"
112 #include "zoombar.h"
113
114 #include <string.h>
115 #include <sys/stat.h>
116
117
118 extern "C"
119 {
120
121
122
123
124 // Hack for libdv to remove glib dependancy
125
126 // void
127 // g_log (const char    *log_domain,
128 //        int  log_level,
129 //        const char    *format,
130 //        ...)
131 // {
132 // }
133 // 
134 // void
135 // g_logv (const char    *log_domain,
136 //        int  log_level,
137 //        const char    *format,
138 //        ...)
139 // {
140 // }
141 // 
142
143
144 // Hack for XFree86 4.1.0
145
146 int atexit(void (*function)(void))
147 {
148         return 0;
149 }
150
151
152
153 }
154
155
156
157 ArrayList<PluginServer*>* MWindow::plugindb = 0;
158 FileServer* MWindow::file_server = 0;
159 Commercials* MWindow::commercials = 0;
160
161
162 MWindow::MWindow()
163  : Thread(1, 0, 0)
164 {
165         plugin_gui_lock = new Mutex("MWindow::plugin_gui_lock");
166         dead_plugin_lock = new Mutex("MWindow::dead_plugin_lock");
167         vwindows_lock = new Mutex("MWindow::vwindows_lock");
168         brender_lock = new Mutex("MWindow::brender_lock");
169         keyframe_gui_lock = new Mutex("MWindow::keyframe_gui_lock");
170
171         playback_3d = 0;
172         splash_window = 0;
173         undo = 0;
174         defaults = 0;
175         assets = 0;
176         //commercials = 0;
177         commercial_active = 0;
178         audio_cache = 0;
179         video_cache = 0;
180         frame_cache = 0;
181         wave_cache = 0;
182         preferences = 0;
183         session = 0;
184         theme = 0;
185         mainindexes = 0;
186         mainprogress = 0;
187         brender = 0;
188         channeldb_buz =  new ChannelDB;
189         channeldb_v4l2jpeg =  new ChannelDB;
190         //file_server = 0;
191         plugin_guis = 0;
192         dead_plugins = 0;
193         keyframe_threads = 0;
194         create_dvd = 0;
195         batch_render = 0;
196         render = 0;
197         edl = 0;
198         gui = 0;
199         cwindow = 0;
200         awindow = 0;
201         gwindow = 0;
202         twindow = 0;
203         lwindow = 0;
204         sighandler = 0;
205         reload_status = 0;
206         screens = 1;
207         in_destructor = 0;
208 }
209
210
211 // Need to delete brender temporary here.
212 MWindow::~MWindow()
213 {
214         in_destructor = 1;
215 //printf("MWindow::~MWindow %d\n", __LINE__);
216         gui->stop_drawing();
217         gui->remote_control->deactivate();
218         gui->record->stop();
219         gui->channel_info->stop();
220         brender_lock->lock("MWindow::quit");
221         delete brender;         brender = 0;
222         brender_lock->unlock();
223         delete create_dvd;      create_dvd = 0;
224         delete batch_render;    batch_render = 0;
225         commit_commercial();
226         if( commercials && !commercials->remove_user() ) commercials = 0;
227
228 // Save defaults for open plugins
229         plugin_gui_lock->lock("MWindow::~MWindow");
230         for(int i = 0; i < plugin_guis->size(); i++)
231         {
232                 plugin_guis->get(i)->hide_gui();
233         }
234         plugin_gui_lock->unlock();
235         hide_keyframe_guis();
236         clean_indexes();
237         save_defaults();
238
239 // Give up and go to a movie
240 //  cant run valgrind if this is used
241 //      if( !reload_status ) exit(0);
242
243         gui->del_keyboard_listener(
244                 (int (BC_WindowBase::*)(BC_WindowBase *))
245                 &MWindowGUI::keyboard_listener);
246 #if 0
247 // release the hounds
248         if( awindow && awindow->gui ) awindow->gui->close(0);
249         if( cwindow && cwindow->gui ) cwindow->gui->close(0);
250         if( lwindow && lwindow->gui ) lwindow->gui->close(0);
251         if( gwindow && gwindow->gui ) gwindow->gui->close(0);
252         if( twindow && twindow->is_running() ) twindow->close_window();
253         vwindows.remove_all_objects();
254         gui->close(0);
255         if( awindow ) awindow->join();
256         if( cwindow ) cwindow->join();
257         if( lwindow ) lwindow->join();
258         if( twindow ) twindow->join();
259         if( gwindow ) gwindow->join();
260         join();
261 #else
262 // one at a time, or nouveau chokes
263 #define close_gui(win) if( win ) { \
264   if( win->gui ) win->gui->close(0); \
265   win->join(); }
266         close_gui(awindow);
267         close_gui(cwindow);
268         close_gui(lwindow);
269         close_gui(gwindow);
270         close_gui(twindow);
271         vwindows.remove_all_objects();
272         gui->close(0);
273         join();
274 #endif
275         reset_caches();
276         delete_plugins();
277         dead_plugins->remove_all();
278         finit_error();
279         keyframe_threads->remove_all_objects();
280         if( !edl->Garbage::remove_user() ) edl = 0;
281         colormodels.remove_all_objects();
282         delete gui;             gui = 0;
283         delete render;          render = 0;
284         delete awindow;         awindow = 0;
285         delete lwindow;         lwindow = 0;
286         delete twindow;         twindow = 0;
287         delete gwindow;         gwindow = 0;
288         // must be last or nouveau chokes
289         delete cwindow;         cwindow = 0;
290         //delete file_server;  file_server = 0; // reusable
291         delete mainindexes;     mainindexes = 0;
292         delete mainprogress;    mainprogress = 0;
293         delete audio_cache;     audio_cache = 0;  // delete the cache after the assets
294         delete video_cache;     video_cache = 0;  // delete the cache after the assets
295         delete frame_cache;     frame_cache = 0;
296         delete wave_cache;      wave_cache = 0;
297         delete plugin_guis;     plugin_guis = 0;
298         delete dead_plugins;    dead_plugins = 0;
299         delete keyframe_threads;  keyframe_threads = 0;
300         delete undo;            undo = 0;
301         delete preferences;     preferences = 0;
302         delete session;         session = 0;
303         delete defaults;        defaults = 0;
304         delete assets;          assets = 0;
305         delete splash_window;   splash_window = 0;
306         delete theme;           theme = 0;
307         delete channeldb_buz;
308         delete channeldb_v4l2jpeg;
309 // This must be last thread to exit
310         delete playback_3d;     playback_3d = 0;
311         delete dead_plugin_lock;
312         delete plugin_gui_lock;
313         delete vwindows_lock;
314         delete brender_lock;
315         delete keyframe_gui_lock;
316         sighandler->terminate();
317         delete sighandler;
318 }
319
320
321 void MWindow::quit(int unlock)
322 {
323         stop_playback(1);
324         if(unlock) gui->unlock_window();
325
326         brender_lock->lock("MWindow::quit");
327         delete brender;         brender = 0;
328         brender_lock->unlock();
329
330         interrupt_indexes();
331         clean_indexes();
332         save_defaults();
333 // This is the last thread to exit
334         playback_3d->quit();
335         if(unlock) gui->lock_window("MWindow::quit");
336 }
337
338 void MWindow::init_error()
339 {
340         MainError::init_error(this);
341 }
342
343 void MWindow::finit_error()
344 {
345         MainError::finit_error();
346 }
347
348 void MWindow::create_defaults_path(char *string, const char *config_file)
349 {
350 // set the .bcast path
351         FileSystem fs;
352
353         sprintf(string, "%s", BCASTDIR);
354         fs.complete_path(string);
355         if(!fs.is_dir(string)) 
356                 fs.create_dir(string); 
357
358 // load the defaults
359         strcat(string, config_file);
360 }
361
362 void MWindow::init_defaults(BC_Hash* &defaults, char *config_path)
363 {
364         char path[BCTEXTLEN];
365 // Use user supplied path
366         if(config_path[0])
367                 strcpy(path, config_path);
368         else
369                 create_defaults_path(path, CONFIG_FILE);
370
371         defaults = new BC_Hash(path);
372         defaults->load();
373 }
374
375 int MWindow::load_plugin_index(MWindow *mwindow, char *path)
376 {
377 // load index
378         FILE *fp = fopen(path, "r");
379         if( !fp ) return 1;
380         char index_line[BCTEXTLEN];
381         int index_version = -1, ret = 0;
382         if( !fgets(index_line, BCTEXTLEN, fp) ||
383             sscanf(index_line, "%d", &index_version) != 1 ||
384             index_version != PLUGIN_FILE_VERSION ) ret = 1;
385
386         while( !ret && !feof(fp)) {
387                 char *sp = index_line, *plugin_path = 0, *plugin_title = 0;
388                 if( fgets(sp, BCTEXTLEN, fp) ) {
389                         plugin_path = PluginServer::table_quoted_field(sp);
390                         if( plugin_exists(plugin_path) ) continue;
391                         plugin_title = PluginServer::table_quoted_field(sp);
392                 }
393                 if( plugin_path && plugin_title ) {
394 // Create plugin server from index entry
395                         PluginServer *new_plugin = new PluginServer(path, mwindow);
396                         new_plugin->set_path(plugin_path);
397                         new_plugin->set_title(plugin_title);
398                         if( new_plugin->read_table(sp) ) {
399                                 delete new_plugin;
400                                 ret = 1;  break;
401                         }
402                         plugindb->append(new_plugin);
403                 }
404         }
405
406         fclose(fp);
407         return ret;
408 }
409
410 void MWindow::init_plugin_index(MWindow *mwindow, Preferences *preferences, FILE *fp,
411         const char *plug_dir, const char *plug_path, int &idx)
412 {
413         char plugin_path[BCTEXTLEN];
414         if( *plug_path != '/' )
415                 sprintf(plugin_path, "%s/%s", plug_dir, plug_path);
416         else
417                 strcpy(plugin_path, plug_path);
418         FileSystem fs;
419         fs.set_filter( "[*.plugin][*.so]" );
420         int result = fs.update(plugin_path);
421         if( result || !fs.dir_list.total ) return;
422         int vis_id = ++idx;
423
424         for( int i=0; i<fs.dir_list.total; ++i ) {
425                 char *fs_path = fs.dir_list.values[i]->path;
426                 char *base_path = FileSystem::basepath(fs_path), *bp = base_path;
427                 const char *dp = plug_dir;
428                 while( *bp && *dp && *bp == *dp ) { ++bp; ++dp; }
429                 strcpy(plugin_path, !*dp && *bp == '/' ? bp+1 : base_path);
430                 delete [] base_path;
431                 if( fs.is_dir(fs_path) ) {
432                         init_plugin_index(mwindow, preferences, fp, plug_dir, plugin_path, idx);
433                         continue;
434                 }
435                 if( plugin_exists(plugin_path) ) continue;
436                 PluginServer *new_plugin = new PluginServer(plugin_path, mwindow);
437                 result = new_plugin->open_plugin(1, preferences, 0, 0);
438                 if( !result ) {
439                         new_plugin->write_table(fp,vis_id);
440                         new_plugin->close_plugin();
441                         new_plugin->delete_this();
442                         continue;
443                 }
444                 if( result != PLUGINSERVER_IS_LAD ) continue;
445                 int lad_index = 0;
446                 for(;;) {
447                         PluginServer *new_plugin = new PluginServer(plugin_path, mwindow);
448                         new_plugin->set_lad_index(lad_index++);
449                         result = new_plugin->open_plugin(1, preferences, 0, 0);
450                         if( result ) break;
451                         new_plugin->write_table(fp,vis_id);
452                         new_plugin->close_plugin();
453                         new_plugin->delete_this();
454                 }
455         }
456 }
457
458 int MWindow::init_plugins(MWindow *mwindow, Preferences *preferences)
459 {
460         if( !plugindb ) plugindb = new ArrayList<PluginServer*>;
461         char index_path[BCTEXTLEN];
462         sprintf(index_path, "%s/%s", preferences->plugin_dir, PLUGIN_FILE);
463         if( !load_plugin_index(mwindow, index_path) ) return 1;
464         FILE *fp = fopen(index_path,"w");
465         if( !fp ) {
466                 fprintf(stderr," MWindow::init_plugins: "
467                         "can't create plugin index: %s\n", index_path);
468                 return 1;
469         }
470         fprintf(fp, "%d\n", PLUGIN_FILE_VERSION);
471         char *plug_path = FileSystem::basepath(preferences->plugin_dir);
472         int dir_id = 0;
473         init_plugin_index(mwindow, preferences, fp, plug_path, ".", dir_id);
474         fclose(fp);
475         delete [] plug_path;
476         return load_plugin_index(mwindow, index_path);
477 }
478
479 void MWindow::delete_plugins()
480 {
481         plugindb->remove_all_objects();
482         delete plugindb;
483         plugindb = 0;
484 }
485
486 void MWindow::search_plugindb(int do_audio, 
487                 int do_video, 
488                 int is_realtime, 
489                 int is_transition,
490                 int is_theme,
491                 ArrayList<PluginServer*> &results)
492 {
493 // Get plugins
494         for(int i = 0; i < MWindow::plugindb->total; i++)
495         {
496                 PluginServer *current = MWindow::plugindb->values[i];
497
498                 if(current->audio == do_audio &&
499                         current->video == do_video &&
500                         (current->realtime == is_realtime || is_realtime < 0) &&
501                         current->transition == is_transition &&
502                         current->theme == is_theme)
503                         results.append(current);
504         }
505
506 // Alphabetize list by title
507         int done = 0;
508         while(!done)
509         {
510                 done = 1;
511                 
512                 for(int i = 0; i < results.total - 1; i++)
513                 {
514                         PluginServer *value1 = results.values[i];
515                         PluginServer *value2 = results.values[i + 1];
516                         if(strcmp(_(value1->title), _(value2->title)) > 0)
517                         {
518                                 done = 0;
519                                 results.values[i] = value2;
520                                 results.values[i + 1] = value1;
521                         }
522                 }
523         }
524 }
525
526 PluginServer* MWindow::scan_plugindb(char *title,
527                 int data_type)
528 {
529 //      if(data_type < 0)
530 //      {
531 //              printf("MWindow::scan_plugindb data_type < 0\n");
532 //              return 0;
533 //      }
534
535         for(int i = 0; i < plugindb->total; i++)
536         {
537                 PluginServer *server = plugindb->values[i];
538                 if(server->title &&
539                         !strcasecmp(server->title, title) &&
540                         (data_type < 0 ||
541                                 (data_type == TRACK_AUDIO && server->audio) ||
542                                 (data_type == TRACK_VIDEO && server->video))) 
543                         return plugindb->values[i];
544         }
545         return 0;
546 }
547
548 int MWindow::plugin_exists(char *plugin_path)
549 {
550         for( int i=0; i<plugindb->total; ++i ) {
551                 PluginServer *server = plugindb->values[i];
552                 if( !strcmp(plugin_path, server->get_path()) ) return 1;
553         }
554         return 0;
555 }
556
557 void MWindow::init_preferences()
558 {
559         preferences = new Preferences;
560         preferences->load_defaults(defaults);
561         session = new MainSession(this);
562         session->load_defaults(defaults);
563         // set x11_host, screens, window_config
564         screens = session->set_default_x11_host();
565         BC_Signals::set_trap_path("/tmp/cinelerra_%d.dmp");
566         BC_Signals::set_trap_hook(trap_hook, this);
567         BC_Signals::set_catch_segv(preferences->trap_sigsegv);
568         BC_Signals::set_catch_intr(preferences->trap_sigintr);
569 }
570
571 void MWindow::clean_indexes()
572 {
573         FileSystem fs;
574         int total_excess;
575         long oldest = 0;
576         int oldest_item = -1;
577         int result;
578         char string[BCTEXTLEN];
579         char string2[BCTEXTLEN];
580
581 // Delete extra indexes
582         fs.set_filter("*.idx");
583         fs.complete_path(preferences->index_directory);
584         fs.update(preferences->index_directory);
585 //printf("MWindow::clean_indexes 1 %d\n", fs.dir_list.total);
586
587 // Eliminate directories
588         result = 1;
589         while(result)
590         {
591                 result = 0;
592                 for(int i = 0; i < fs.dir_list.total && !result; i++)
593                 {
594                         fs.join_names(string, preferences->index_directory, fs.dir_list.values[i]->name);
595                         if(fs.is_dir(string))
596                         {
597                                 delete fs.dir_list.values[i];
598                                 fs.dir_list.remove_number(i);
599                                 result = 1;
600                         }
601                 }
602         }
603         total_excess = fs.dir_list.total - preferences->index_count;
604
605 //printf("MWindow::clean_indexes 2 %d\n", fs.dir_list.total);
606         while(total_excess > 0)
607         {
608 // Get oldest
609                 for(int i = 0; i < fs.dir_list.total; i++)
610                 {
611                         fs.join_names(string, preferences->index_directory, fs.dir_list.values[i]->name);
612
613                         if(i == 0 || fs.get_date(string) <= oldest)
614                         {
615                                 oldest = fs.get_date(string);
616                                 oldest_item = i;
617                         }
618                 }
619
620                 if(oldest_item >= 0)
621                 {
622 // Remove index file
623                         fs.join_names(string, 
624                                 preferences->index_directory, 
625                                 fs.dir_list.values[oldest_item]->name);
626 //printf("MWindow::clean_indexes 1 %s\n", string);
627                         if(remove(string))
628                                 perror("delete_indexes");
629                         delete fs.dir_list.values[oldest_item];
630                         fs.dir_list.remove_number(oldest_item);
631
632 // Remove table of contents if it exists
633                         strcpy(string2, string);
634                         char *ptr = strrchr(string2, '.');
635                         if(ptr)
636                         {
637 //printf("MWindow::clean_indexes 2 %s\n", string2);
638                                 sprintf(ptr, ".toc");
639                                 remove(string2);
640                         }
641                 }
642
643                 total_excess--;
644         }
645 }
646
647 void MWindow::init_awindow()
648 {
649         awindow = new AWindow(this);
650         awindow->create_objects();
651 }
652
653 void MWindow::init_gwindow()
654 {
655         gwindow = new GWindow(this);
656         gwindow->create_objects();
657 }
658
659 void MWindow::init_tipwindow()
660 {
661         twindow = new TipWindow(this);
662         twindow->start();
663 }
664
665 void MWindow::init_theme()
666 {
667         Timer timer;
668         theme = 0;
669
670 // Replace blond theme with SUV since it doesn't work
671         if(!strcasecmp(preferences->theme, "Blond"))
672                 strcpy(preferences->theme, DEFAULT_THEME);
673
674         PluginServer *theme_plugin = 0;
675         for(int i = 0; i < plugindb->total && !theme_plugin; i++) {
676                 if( plugindb->values[i]->theme &&
677                     !strcasecmp(preferences->theme, plugindb->values[i]->title) )
678                         theme_plugin = plugindb->values[i];
679         }
680
681         if( !theme_plugin )
682                 fprintf(stderr, _("MWindow::init_theme: prefered theme %s not found.\n"),
683                          preferences->theme);
684
685         if( !theme_plugin && strcasecmp(preferences->theme, DEFAULT_THEME) ) {
686                 fprintf(stderr, _("MWindow::init_theme: trying default theme %s\n"),
687                         DEFAULT_THEME);
688                 for(int i = 0; i < plugindb->total && !theme_plugin; i++) {
689                         if( plugindb->values[i]->theme &&
690                             !strcasecmp(DEFAULT_THEME, plugindb->values[i]->title) )
691                                 theme_plugin = plugindb->values[i];
692                 }
693         }
694
695         if(!theme_plugin) {
696                 fprintf(stderr, _("MWindow::init_theme: theme_plugin not found.\n"));
697                 exit(1);
698         }
699
700         PluginServer plugin = *theme_plugin;
701         if( plugin.open_plugin(0, preferences, 0, 0) ) {
702                 fprintf(stderr, _("MWindow::init_theme: unable to load theme %s\n"),
703                         theme_plugin->title);
704                 exit(1);
705         }
706
707         theme = plugin.new_theme();
708         theme->mwindow = this;
709         strcpy(theme->path, plugin.path);
710         plugin.close_plugin();
711
712 // Load default images & settings
713         theme->Theme::initialize();
714 // Load user images & settings
715         theme->initialize();
716 // Create menus with user colors
717         theme->build_menus();
718         init_menus();
719
720         theme->check_used();
721
722 //printf("MWindow::init_theme %d total_time=%d\n", __LINE__, (int)timer.get_difference());
723 }
724
725 void MWindow::init_3d()
726 {
727         playback_3d = new Playback3D(this);
728         playback_3d->create_objects();
729 }
730
731 void MWindow::init_edl()
732 {
733         edl = new EDL;
734         edl->create_objects();
735         edl->load_defaults(defaults);
736         edl->create_default_tracks();
737         edl->tracks->update_y_pixels(theme);
738 }
739
740 void MWindow::init_compositor()
741 {
742         cwindow = new CWindow(this);
743         cwindow->create_objects();
744 }
745
746 void MWindow::init_levelwindow()
747 {
748         lwindow = new LevelWindow(this);
749         lwindow->create_objects();
750 }
751
752 VWindow *MWindow::get_viewer(int start_it, int idx)
753 {
754         vwindows_lock->lock("MWindow::get_viewer");
755         VWindow *vwindow = idx >= 0 && idx < vwindows.size() ? vwindows.get(idx) : 0;
756         if( !vwindow ) idx = vwindows.size();
757         while( !vwindow && --idx >= 0 ) {
758                 VWindow *vwin = vwindows.get(idx);
759                 if( !vwin->is_running() || !vwin->get_edl() )
760                         vwindow = vwin;
761         }
762         if( !vwindow ) {
763                 vwindow = new VWindow(this);
764                 vwindow->load_defaults();
765                 vwindow->create_objects();
766                 vwindows.append(vwindow);
767         }
768         vwindows_lock->unlock();
769         if( start_it ) vwindow->start();
770         return vwindow;
771 }
772
773 void MWindow::init_cache()
774 {
775         audio_cache = new CICache(preferences);
776         video_cache = new CICache(preferences);
777         frame_cache = new FrameCache;
778         wave_cache = new WaveCache;
779 }
780
781 void MWindow::init_channeldb()
782 {
783         channeldb_buz->load("channeldb_buz");
784         channeldb_v4l2jpeg->load("channeldb_v4l2jpeg");
785 }
786
787 void MWindow::init_menus()
788 {
789         char string[BCTEXTLEN];
790         cmodel_to_text(string, BC_RGB888);
791         colormodels.append(new ColormodelItem(string, BC_RGB888));
792         cmodel_to_text(string, BC_RGBA8888);
793         colormodels.append(new ColormodelItem(string, BC_RGBA8888));
794 //      cmodel_to_text(string, BC_RGB161616);
795 //      colormodels.append(new ColormodelItem(string, BC_RGB161616));
796 //      cmodel_to_text(string, BC_RGBA16161616);
797 //      colormodels.append(new ColormodelItem(string, BC_RGBA16161616));
798         cmodel_to_text(string, BC_RGB_FLOAT);
799         colormodels.append(new ColormodelItem(string, BC_RGB_FLOAT));
800         cmodel_to_text(string, BC_RGBA_FLOAT);
801         colormodels.append(new ColormodelItem(string, BC_RGBA_FLOAT));
802         cmodel_to_text(string, BC_YUV888);
803         colormodels.append(new ColormodelItem(string, BC_YUV888));
804         cmodel_to_text(string, BC_YUVA8888);
805         colormodels.append(new ColormodelItem(string, BC_YUVA8888));
806 //      cmodel_to_text(string, BC_YUV161616);
807 //      colormodels.append(new ColormodelItem(string, BC_YUV161616));
808 //      cmodel_to_text(string, BC_YUVA16161616);
809 //      colormodels.append(new ColormodelItem(string, BC_YUVA16161616));
810 }
811
812 void MWindow::init_indexes()
813 {
814         mainindexes = new MainIndexes(this);
815         mainindexes->start_loop();
816 }
817
818 void MWindow::init_gui()
819 {
820         gui = new MWindowGUI(this);
821         gui->lock_window("MWindow::init_gui");
822         gui->create_objects();
823         gui->unlock_window();
824         gui->load_defaults(defaults);
825 }
826
827 void MWindow::init_signals()
828 {
829         sighandler = new SigHandler;
830         sighandler->initialize();
831 ENABLE_BUFFER
832 }
833
834 void MWindow::init_render()
835 {
836         render = new Render(this);
837         create_dvd = new CreateDVD_Thread(this);
838         batch_render = new BatchRenderThread(this);
839 }
840
841 void MWindow::init_brender()
842 {
843         if(preferences->use_brender && !brender)
844         {
845                 brender_lock->lock("MWindow::init_brender 1");
846                 brender = new BRender(this);
847                 brender->initialize();
848                 session->brender_end = 0;
849                 brender_lock->unlock();
850         }
851         else
852         if(!preferences->use_brender && brender)
853         {
854                 brender_lock->lock("MWindow::init_brender 2");
855                 delete brender;
856                 brender = 0;
857                 session->brender_end = 0;
858                 brender_lock->unlock();
859         }
860         if(brender) brender->restart(edl);
861 }
862
863 void MWindow::restart_brender()
864 {
865 //printf("MWindow::restart_brender 1\n");
866         if(brender) brender->restart(edl);
867 }
868
869 void MWindow::stop_brender()
870 {
871         if(brender) brender->stop();
872 }
873
874 int MWindow::brender_available(int position)
875 {
876         int result = 0;
877         brender_lock->lock("MWindow::brender_available 1");
878         if(brender)
879         {
880                 if(brender->map_valid)
881                 {
882                         brender->map_lock->lock("MWindow::brender_available 2");
883                         if(position < brender->map_size &&
884                                 position >= 0)
885                         {
886 //printf("MWindow::brender_available 1 %d %d\n", position, brender->map[position]);
887                                 if(brender->map[position] == BRender::RENDERED)
888                                         result = 1;
889                         }
890                         brender->map_lock->unlock();
891                 }
892         }
893         brender_lock->unlock();
894         return result;
895 }
896
897 void MWindow::set_brender_start()
898 {
899         edl->session->brender_start = edl->local_session->get_selectionstart(1);
900         restart_brender();
901         gui->draw_overlays(1);
902 }
903
904
905 int MWindow::has_commercials()
906 {
907         return theme->use_commercials;
908 }
909
910 void MWindow::init_commercials()
911 {
912         if( !commercials ) {
913                 commercials = new Commercials(this);
914                 commercial_active = 0;
915         }
916         else
917                 commercials->add_user();
918 }
919
920 void MWindow::commit_commercial()
921 {
922         if( !commercial_active ) return;
923         commercial_active = 0;
924         if( !commercials ) return;
925         commercials->commitDb();
926 }
927
928 void MWindow::undo_commercial()
929 {
930         if( !commercial_active ) return;
931         commercial_active = 0;
932         if( !commercials ) return;
933         commercials->undoDb();
934 }
935
936 int MWindow::put_commercial()
937 {
938         double start = edl->local_session->get_selectionstart();
939         double end = edl->local_session->get_selectionend();
940         if( start >= end ) return 0;
941
942         const char *errmsg = 0;
943         int count = 0;
944         Tracks *tracks = edl->tracks;
945         int result = 0;
946         //check it
947         for(Track *track=tracks->first; track && !errmsg; track=track->next) {
948                 if( track->data_type != TRACK_VIDEO ) continue;
949                 if( !track->record ) continue;
950                 if( count > 0 ) { errmsg = "multiple video tracks"; break; }
951                 ++count;
952                 int64_t units_start = track->to_units(start,0);
953                 int64_t units_end = track->to_units(end,0);
954                 Edits *edits = track->edits;
955                 Edit *edit1 = edits->editof(units_start, PLAY_FORWARD, 0);
956                 Edit *edit2 = edits->editof(units_end, PLAY_FORWARD, 0);
957                 if(!edit1 && !edit2) continue;  // nothing selected
958                 if(!edit2) {                    // edit2 beyond end of track
959                         edit2 = edits->last;
960                         units_end = edits->length();
961                 }
962                 if(edit1 != edit2) { errmsg = "crosses edits"; break; }
963                 Indexable *indexable = edit1->get_source();
964                 if( !indexable->is_asset ) { errmsg = "not asset"; break; }
965         }
966         //run it
967         for(Track *track=tracks->first; track && !errmsg; track=track->next) {
968                 if( track->data_type != TRACK_VIDEO ) continue;
969                 if( !track->record ) continue;
970                 int64_t units_start = track->to_units(start,0);
971                 int64_t units_end = track->to_units(end,0);
972                 Edits *edits = track->edits;
973                 Edit *edit1 = edits->editof(units_start, PLAY_FORWARD, 0);
974                 Edit *edit2 = edits->editof(units_end, PLAY_FORWARD, 0);
975                 if(!edit1 && !edit2) continue;  // nothing selected
976                 if(!edit2) {                    // edit2 beyond end of track
977                         edit2 = edits->last;
978                         units_end = edits->length();
979                 }
980                 Indexable *indexable = edit1->get_source();
981                 Asset *asset = (Asset *)indexable;
982                 File *file = video_cache->check_out(asset, edl);
983                 if( !file ) { errmsg = "no file"; break; }
984                 int64_t edit_length = units_end - units_start;
985                 int64_t edit_start = units_start - edit1->startproject + edit1->startsource;
986                 result = commercials->put_clip(file, edit1->channel,
987                         track->from_units(edit_start), track->from_units(edit_length));
988                 video_cache->check_in(asset);
989                 if( result ) { errmsg = "db failed"; break; }
990         }
991         if( errmsg ) {
992                 char string[BCTEXTLEN];
993                 sprintf(string, "put_commercial: %s", errmsg);
994                 MainError::show_error(string);
995                 undo_commercial();
996                 result = 1;
997         }
998         return result;
999 }
1000
1001 void MWindow::stop_playback(int wait)
1002 {
1003         int locked  = gui->get_window_lock();
1004         if( locked ) gui->unlock_window();
1005
1006         cwindow->playback_engine->que->send_command(STOP,
1007                 CHANGE_NONE, 
1008                 0,
1009                 0);
1010         cwindow->playback_engine->interrupt_playback(wait);
1011
1012         for(int i = 0; i < vwindows.size(); i++)
1013         {
1014                 VWindow *vwindow = vwindows.get(i);
1015                 if(vwindow->running())
1016                 {
1017                         vwindow->playback_engine->que->send_command(STOP,
1018                                 CHANGE_NONE, 
1019                                 0,
1020                                 0);
1021                         vwindow->playback_engine->interrupt_playback(wait);
1022                 }
1023         }
1024         if( locked ) gui->lock_window("MWindow::stop_playback");
1025 }
1026
1027 int MWindow::load_filenames(ArrayList<char*> *filenames, 
1028         int load_mode,
1029         int update_filename)
1030 {
1031         ArrayList<EDL*> new_edls;
1032         ArrayList<Asset*> new_assets;
1033         ArrayList<File*> new_files;
1034         const int debug = 0;
1035 if(debug) printf("MWindow::load_filenames %d\n", __LINE__);
1036
1037 //      save_defaults();
1038         gui->start_hourglass();
1039
1040 // Need to stop playback since tracking depends on the EDL not getting
1041 // deleted.
1042         stop_playback(1);
1043
1044         undo->update_undo_before();
1045
1046
1047 if(debug) printf("MWindow::load_filenames %d\n", __LINE__);
1048
1049 // Define new_edls and new_assets to load
1050         int result = 0, ftype = -1;
1051         for(int i = 0; i < filenames->total; i++)
1052         {
1053 // Get type of file
1054                 File *new_file = new File;
1055                 Asset *new_asset = new Asset(filenames->values[i]);
1056                 EDL *new_edl = new EDL;
1057                 char string[BCTEXTLEN];
1058
1059                 new_edl->create_objects();
1060                 new_edl->copy_session(edl);
1061                 new_file->set_program(edl->session->program_no);
1062
1063                 sprintf(string, "Loading %s", new_asset->path);
1064                 gui->show_message(string);
1065 if(debug) printf("MWindow::load_filenames %d\n", __LINE__);
1066
1067                 ftype = new_file->open_file(preferences, new_asset, 1, 0);
1068 if(debug) printf("MWindow::load_filenames %d\n", __LINE__);
1069
1070                 result = 1;
1071                 switch(ftype)
1072                 {
1073 // Convert media file to EDL
1074                         case FILE_OK:
1075 // Warn about odd image dimensions
1076                                 if(new_asset->video_data &&
1077                                         ((new_asset->width % 2) ||
1078                                         (new_asset->height % 2)))
1079                                 {
1080                                         char string[BCTEXTLEN];
1081                                         sprintf(string, "%s's resolution is %dx%d.\nImages with odd dimensions may not decode properly.",
1082                                                 new_asset->path,
1083                                                 new_asset->width,
1084                                                 new_asset->height);
1085                                         MainError::show_error(string);
1086                                 }
1087
1088                                 if(new_asset->program >= 0 &&
1089                                         edl->session->program_no != new_asset->program)
1090                                 {
1091                                         char string[BCTEXTLEN];
1092                                         sprintf(string, "%s's index was built for program number %d\n"
1093                                                 "Playback preference is %d.\n  Using program %d.",
1094                                                 new_asset->path, new_asset->program,
1095                                                 edl->session->program_no, new_asset->program);
1096                                         MainError::show_error(string);
1097                                 }
1098
1099
1100                                 if(load_mode != LOADMODE_RESOURCESONLY)
1101                                 {
1102 SET_TRACE
1103                                         RecordLabels *labels = edl->session->label_cells ?
1104                                                 new RecordLabels(new_file) : 0;
1105 SET_TRACE
1106                                         asset_to_edl(new_edl, new_asset, labels);
1107 SET_TRACE
1108                                         new_edls.append(new_edl);
1109 SET_TRACE
1110                                         new_asset->Garbage::remove_user();
1111                                         delete labels;
1112                                         new_asset = 0;
1113                                 }
1114                                 else
1115                                 {
1116                                         new_assets.append(new_asset);
1117                                         new_asset = 0;
1118                                 }
1119
1120 // Set filename to nothing for assets since save EDL would overwrite them.
1121                                 if(load_mode == LOADMODE_REPLACE || 
1122                                         load_mode == LOADMODE_REPLACE_CONCATENATE)
1123                                 {
1124                                         set_filename("");
1125 // Reset timeline position
1126                                         for(int i = 0; i < TOTAL_PANES; i++)
1127                                         {
1128                                                 new_edl->local_session->view_start[i] = 0;
1129                                                 new_edl->local_session->track_start[i] = 0;
1130                                         }
1131                                 }
1132
1133                                 result = 0;
1134                                 break;
1135
1136 // File not found
1137                         case FILE_NOT_FOUND:
1138                                 sprintf(string, _("Failed to open %s"), new_asset->path);
1139                                 gui->show_message(string, theme->message_error);
1140                                 break;
1141
1142 // Unknown format
1143                         case FILE_UNRECOGNIZED_CODEC:
1144                         {
1145 // Test index file
1146                                 IndexFile indexfile(this, new_asset);
1147                                 result = indexfile.open_index();
1148                                 if(!result)
1149                                 {
1150                                         indexfile.close_index();
1151                                 }
1152
1153 // Test existing EDLs
1154                                 if(result)
1155                                 {
1156                                         for(int j = 0; j < new_edls.total + 1; j++)
1157                                         {
1158                                                 Asset *old_asset;
1159                                                 if(j == new_edls.total)
1160                                                 {
1161                                                         old_asset = edl->assets->get_asset(new_asset->path);
1162                                                         if( old_asset )
1163                                                         {
1164                                                                 *new_asset = *old_asset;
1165                                                                 result = 0;
1166                                                         }
1167                                                 }
1168                                                 else
1169                                                 {
1170                                                         old_asset = new_edls.values[j]->assets->get_asset(new_asset->path);
1171                                                         if( old_asset )
1172                                                         {
1173                                                                 *new_asset = *old_asset;
1174                                                                 result = 0;
1175                                                         }
1176                                                 }
1177                                         }
1178                                 }
1179
1180 // Prompt user
1181                                 if(result)
1182                                 {
1183                                         char string[BCTEXTLEN];
1184                                         FileSystem fs;
1185                                         fs.extract_name(string, new_asset->path);
1186
1187                                         strcat(string, _("'s format couldn't be determined."));
1188                                         new_asset->audio_data = 1;
1189                                         new_asset->format = FILE_PCM;
1190                                         new_asset->channels = defaults->get("AUDIO_CHANNELS", 2);
1191                                         new_asset->sample_rate = defaults->get("SAMPLE_RATE", 44100);
1192                                         new_asset->bits = defaults->get("AUDIO_BITS", 16);
1193                                         new_asset->byte_order = defaults->get("BYTE_ORDER", 1);
1194                                         new_asset->signed_ = defaults->get("SIGNED_", 1);
1195                                         new_asset->header = defaults->get("HEADER", 0);
1196
1197                                         FileFormat fwindow(this);
1198                                         fwindow.create_objects(new_asset, string);
1199                                         result = fwindow.run_window();
1200
1201
1202                                         defaults->update("AUDIO_CHANNELS", new_asset->channels);
1203                                         defaults->update("SAMPLE_RATE", new_asset->sample_rate);
1204                                         defaults->update("AUDIO_BITS", new_asset->bits);
1205                                         defaults->update("BYTE_ORDER", new_asset->byte_order);
1206                                         defaults->update("SIGNED_", new_asset->signed_);
1207                                         defaults->update("HEADER", new_asset->header);
1208                                         save_defaults();
1209                                 }
1210
1211 // Append to list
1212                                 if(!result)
1213                                 {
1214 // Recalculate length
1215                                         delete new_file;
1216                                         new_file = new File;
1217                                         result = new_file->open_file(preferences, new_asset, 1, 0);
1218
1219                                         if(load_mode != LOADMODE_RESOURCESONLY)
1220                                         {
1221                                                 RecordLabels *labels = edl->session->label_cells ?
1222                                                         new RecordLabels(new_file) : 0;
1223                                                 asset_to_edl(new_edl, new_asset, labels);
1224                                                 new_edls.append(new_edl);
1225                                                 new_asset->Garbage::remove_user();
1226                                                 delete labels;
1227                                                 new_asset = 0;
1228                                         }
1229                                         else
1230                                         {
1231                                                 new_assets.append(new_asset);
1232                                                 new_asset = 0;
1233                                         }
1234                                 }
1235                                 else
1236                                 {
1237                                         result = 1;
1238                                 }
1239                                 break;
1240                         }
1241
1242                         case FILE_IS_XML:
1243                         {
1244                                 FileXML xml_file;
1245 if(debug) printf("MWindow::load_filenames %d\n", __LINE__);
1246                                 xml_file.read_from_file(filenames->values[i]);
1247 if(debug) printf("MWindow::load_filenames %d\n", __LINE__);
1248
1249                                 if(load_mode == LOADMODE_NESTED)
1250                                 {
1251 // Load temporary EDL for nesting.
1252                                         EDL *nested_edl = new EDL;
1253                                         nested_edl->create_objects();
1254                                         nested_edl->set_path(filenames->values[i]);
1255                                         nested_edl->load_xml(&xml_file, LOAD_ALL);
1256 //printf("MWindow::load_filenames %p %s\n", nested_edl, nested_edl->project_path);
1257                                         edl_to_nested(new_edl, nested_edl);
1258                                         nested_edl->Garbage::remove_user();
1259                                 }
1260                                 else
1261                                 {
1262 // Load EDL for pasting
1263                                         new_edl->load_xml(&xml_file, LOAD_ALL);
1264 if(debug) printf("MWindow::load_filenames %d\n", __LINE__);
1265                                         test_plugins(new_edl, filenames->values[i]);
1266 if(debug) printf("MWindow::load_filenames %d\n", __LINE__);
1267
1268                                         if(load_mode == LOADMODE_REPLACE || 
1269                                                 load_mode == LOADMODE_REPLACE_CONCATENATE)
1270                                         {
1271                                                 strcpy(session->filename, filenames->values[i]);
1272                                                 strcpy(new_edl->local_session->clip_title, 
1273                                                         filenames->values[i]);
1274                                                 if(update_filename)
1275                                                         set_filename(new_edl->local_session->clip_title);
1276                                         }
1277                                 }               
1278
1279                                 new_edls.append(new_edl);
1280                                 result = 0;
1281                                 break;
1282                         }
1283                 }
1284
1285 // edls are in new_edls
1286                 if( result && new_edl ) new_edl->Garbage::remove_user();
1287 // assets are copied
1288                 if( new_asset ) new_asset->Garbage::remove_user();
1289
1290 // Store for testing index
1291                 new_files.append(new_file);
1292         }
1293
1294 if(debug) printf("MWindow::load_filenames %d\n", __LINE__);
1295
1296
1297         if(!result) gui->statusbar->default_message();
1298
1299
1300
1301
1302
1303
1304
1305 if(debug) printf("MWindow::load_filenames %d\n", __LINE__);
1306
1307 // Paste them.
1308 // Don't back up here.
1309         if(new_edls.size())
1310         {
1311 // For pasting, clear the active region
1312                 if(load_mode == LOADMODE_PASTE ||
1313                         load_mode == LOADMODE_NESTED)
1314                 {
1315                         double start = edl->local_session->get_selectionstart();
1316                         double end = edl->local_session->get_selectionend();
1317                         if(!EQUIV(start, end))
1318                                 edl->clear(start, 
1319                                         end,
1320                                         edl->session->labels_follow_edits,
1321                                         edl->session->plugins_follow_edits,
1322                                         edl->session->autos_follow_edits);
1323                 }
1324
1325                 paste_edls(&new_edls, 
1326                         load_mode,
1327                         0,
1328                         -1,
1329                         edl->session->labels_follow_edits, 
1330                         edl->session->plugins_follow_edits,
1331                         edl->session->autos_follow_edits);
1332         }
1333
1334
1335
1336
1337 if(debug) printf("MWindow::load_filenames %d\n", __LINE__);
1338
1339 // Add new assets to EDL and schedule assets for index building.
1340         int got_indexes = 0;
1341         for(int i = 0; i < new_edls.size(); i++)
1342         {
1343                 EDL *new_edl = new_edls.get(i);
1344                 for(int j = 0; j < new_edl->nested_edls->size(); j++)
1345                 {
1346                         mainindexes->add_next_asset(0, 
1347                                 new_edl->nested_edls->get(j));
1348                         got_indexes = 1;
1349                         edl->nested_edls->update_index(new_edl->nested_edls->get(j));
1350                 }
1351
1352         }
1353
1354 if(debug) printf("MWindow::load_filenames %d\n", __LINE__);
1355         if(new_assets.size())
1356         {
1357                 for(int i = 0; i < new_assets.size(); i++)
1358                 {
1359                         Asset *new_asset = new_assets.get(i);
1360
1361                         File *new_file = 0;
1362                         int got_it = 0;
1363                         for(int j = 0; j < new_files.size(); j++)
1364                         {
1365                                 new_file = new_files.get(j);
1366                                 if(!strcmp(new_file->asset->path,
1367                                         new_asset->path))
1368                                 {
1369                                         got_it = 1;
1370                                         break;
1371                                 }
1372                         }
1373
1374                         mainindexes->add_next_asset(got_it ? new_file : 0, new_asset);
1375                         got_indexes = 1;
1376                         edl->assets->update(new_asset);
1377
1378                 }
1379
1380
1381         }
1382 if(debug) printf("MWindow::load_filenames %d\n", __LINE__);
1383
1384 // Start examining next batch of index files
1385         if(got_indexes) mainindexes->start_build();
1386 if(debug) printf("MWindow::load_filenames %d\n", __LINE__);
1387
1388 // Open plugin GUIs
1389         Track *track = edl->tracks->first;
1390         while(track)
1391         {
1392                 for(int j = 0; j < track->plugin_set.size(); j++)
1393                 {
1394                         PluginSet *plugins = track->plugin_set.get(j);
1395                         Plugin *plugin = plugins->get_first_plugin();
1396
1397                         while(plugin)
1398                         {
1399                                 if(load_mode == LOADMODE_REPLACE ||
1400                                         load_mode == LOADMODE_REPLACE_CONCATENATE)
1401                                 {
1402                                         if(plugin->plugin_type == PLUGIN_STANDALONE &&
1403                                                 plugin->show)
1404                                         {
1405                                                 show_plugin(plugin);
1406                                         }
1407                                 }
1408                                 else
1409                                 {
1410                                         plugin->show = 0;
1411                                 }
1412
1413                                 plugin = (Plugin*)plugin->next;
1414                         }
1415                 }
1416
1417                 track = track->next;
1418         }
1419
1420         // if just opening one new resource in replace mode
1421         if( load_mode == LOADMODE_REPLACE && new_edls.size() == 1 &&
1422                 ftype != FILE_IS_XML )
1423         {
1424                 select_asset(0, 0);
1425                 edl->local_session->preview_start = 0;
1426                 edl->local_session->preview_end = edl->tracks->total_playable_length();
1427                 edl->local_session->set_selectionstart(0);
1428                 edl->local_session->set_selectionend(0);
1429                 fit_selection();
1430                 goto_start();
1431         }
1432
1433
1434         update_project(load_mode);
1435
1436 if(debug) printf("MWindow::load_filenames %d\n", __LINE__);
1437
1438         for(int i = 0; i < new_edls.size(); i++)
1439         {
1440                 new_edls.get(i)->remove_user();
1441         }
1442 if(debug) printf("MWindow::load_filenames %d\n", __LINE__);
1443
1444         new_edls.remove_all();
1445
1446         for(int i = 0; i < new_assets.size(); i++)
1447         {
1448                 new_assets.get(i)->Garbage::remove_user();
1449         }
1450
1451         new_assets.remove_all();
1452         new_files.remove_all_objects();
1453
1454         undo->update_undo_after(_("load"), LOAD_ALL);
1455
1456         if(load_mode == LOADMODE_REPLACE ||
1457                 load_mode == LOADMODE_REPLACE_CONCATENATE)
1458         {
1459                 session->changes_made = 0;
1460         }
1461         else
1462         {
1463                 session->changes_made = 1;
1464         }
1465
1466         gui->stop_hourglass();
1467
1468
1469 if(debug) printf("MWindow::load_filenames %d\n", __LINE__);
1470         return 0;
1471 }
1472
1473
1474
1475
1476 void MWindow::test_plugins(EDL *new_edl, char *path)
1477 {
1478         char string[BCTEXTLEN];
1479
1480 // Do a check weather plugins exist
1481         for(Track *track = new_edl->tracks->first; track; track = track->next)
1482         {
1483                 for(int k = 0; k < track->plugin_set.total; k++)
1484                 {
1485                         PluginSet *plugin_set = track->plugin_set.values[k];
1486                         for(Plugin *plugin = (Plugin*)plugin_set->first; 
1487                                 plugin; 
1488                                 plugin = (Plugin*)plugin->next)
1489                         {
1490                                 if(plugin->plugin_type == PLUGIN_STANDALONE)
1491                                 {
1492 // ok we need to find it in plugindb
1493                                         int plugin_found = 0;
1494
1495                                         for(int j = 0; j < plugindb->size(); j++)
1496                                         {
1497                                                 PluginServer *server = plugindb->get(j);
1498                                                 if(server->title &&
1499                                                         !strcasecmp(server->title, plugin->title) &&
1500                                                         ((track->data_type == TRACK_AUDIO && server->audio) ||
1501                                                         (track->data_type == TRACK_VIDEO && server->video)) &&
1502                                                         (!server->transition))
1503                                                         plugin_found = 1;
1504                                         }
1505
1506                                         if (!plugin_found) 
1507                                         {
1508                                                 sprintf(string, 
1509                                                         "The effect '%s' in file '%s' is not part of your installation of Cinelerra.\n"
1510                                                         "The project won't be rendered as it was meant and Cinelerra might crash.\n",
1511                                                         plugin->title, 
1512                                                         path); 
1513                                                 MainError::show_error(string);
1514                                         }
1515                                 }
1516                         }
1517                 }
1518
1519                 for(Edit *edit = (Edit*)track->edits->first; 
1520                         edit; 
1521                         edit = (Edit*)edit->next)
1522                 {
1523                         if (edit->transition)
1524                         {
1525 // ok we need to find transition in plugindb
1526
1527                                 int transition_found = 0;
1528                                 for(int j = 0; j < plugindb->size(); j++)
1529                                 {
1530                                         PluginServer *server = plugindb->get(j);
1531                                         if(server->title &&
1532                                                 !strcasecmp(server->title, edit->transition->title) &&
1533                                                 ((track->data_type == TRACK_AUDIO && server->audio) ||
1534                                                 (track->data_type == TRACK_VIDEO && server->video)) &&
1535                                                 (server->transition))
1536                                                 transition_found = 1;
1537                                 }
1538
1539                                 if (!transition_found) 
1540                                 {
1541                                         sprintf(string, 
1542                                                 "The transition '%s' in file '%s' is not part of your installation of Cinelerra.\n"
1543                                                 "The project won't be rendered as it was meant and Cinelerra might crash.\n",
1544                                                 edit->transition->title, 
1545                                                 path); 
1546                                         MainError::show_error(string);
1547                                 }
1548                         }
1549                 }
1550         }
1551 }
1552
1553
1554 void MWindow::init_shm()
1555 {
1556 // Fix shared memory
1557         FILE *fd = fopen("/proc/sys/kernel/shmmax", "w");
1558         if(fd) {
1559                 fprintf(fd, "0x7fffffff");
1560                 fclose(fd);
1561         }
1562         fd = 0;
1563
1564         fd = fopen("/proc/sys/kernel/shmmax", "r");
1565         if(!fd) {
1566                 MainError::show_error("MWindow::init_shm: couldn't open /proc/sys/kernel/shmmax for reading.\n");
1567                 return;
1568         }
1569
1570         int64_t result = 0;
1571         fscanf(fd, _LD, &result);
1572         fclose(fd);
1573         fd = 0;
1574         if(result < 0x7fffffff) {
1575                 char string[BCTEXTLEN];
1576                 sprintf(string, "MWindow::init_shm: /proc/sys/kernel/shmmax is 0x" _LX ".\n"
1577                         "you probably need to be root, or:\n"
1578                         "as root, run: echo 0x7fffffff > /proc/sys/kernel/shmmax\n"
1579                         "before trying to start cinelerra.\n"
1580                         "It should be at least 0x7fffffff for Cinelerra.\n", result);
1581                 MainError::show_error(string);
1582         }
1583 }
1584
1585
1586 void MWindow::init_fileserver(Preferences *preferences)
1587 {
1588 #ifdef USE_FILEFORK
1589         if( !file_server && preferences->file_forking ) {
1590                 file_server = new FileServer(preferences);
1591                 file_server->start();
1592         }
1593 #endif
1594 }
1595
1596 void MWindow::create_objects(int want_gui, 
1597         int want_new,
1598         char *config_path)
1599 {
1600         FileSystem fs;
1601         const int debug = 0;
1602         if(debug) PRINT_TRACE
1603
1604 // For some reason, init_signals must come after show_splash or the signals won't
1605 // get trapped.
1606         init_signals();
1607         if(debug) PRINT_TRACE
1608         init_3d();
1609
1610         if(debug) PRINT_TRACE
1611 //      show_splash();
1612
1613         if(debug) PRINT_TRACE
1614         init_defaults(defaults, config_path);
1615         init_preferences();
1616         init_plugins(this, preferences);
1617         if(debug) PRINT_TRACE
1618         if(splash_window) splash_window->operation->update(_("Initializing GUI"));
1619         if(debug) PRINT_TRACE
1620         init_theme();
1621         if(debug) PRINT_TRACE
1622         init_error();
1623
1624         char string[BCTEXTLEN];
1625         strcpy(string, preferences->plugin_dir);
1626         strcat(string, "/fonts");
1627         BC_Resources::init_fontconfig(string);
1628         if(debug) PRINT_TRACE
1629
1630 // Initialize before too much else is running
1631 // Preferences & theme are required for building MPEG table of contents
1632         init_fileserver(preferences);
1633
1634 // Default project created here
1635         init_edl();
1636         if(debug) PRINT_TRACE
1637
1638         init_cache();
1639         if(debug) PRINT_TRACE
1640
1641         Timer timer;
1642
1643         init_compositor();
1644         if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1645
1646 //printf("MWindow::create_objects %d session->show_vwindow=%d\n", __LINE__, session->show_vwindow);
1647         if(session->show_vwindow)
1648                 get_viewer(1, DEFAULT_VWINDOW);
1649         if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1650
1651         init_gui();
1652         if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1653
1654         init_awindow();
1655         if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1656
1657         init_levelwindow();
1658         if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1659
1660         if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1661
1662         init_indexes();
1663         if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1664
1665         init_channeldb();
1666
1667         if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1668         init_gwindow();
1669         if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1670         init_render();
1671         if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1672         init_brender();
1673         init_commercials();
1674         if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1675         mainprogress = new MainProgress(this, gui);
1676         if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1677         undo = new MainUndo(this);
1678
1679         if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1680
1681         plugin_guis = new ArrayList<PluginServer*>;
1682         dead_plugins = new ArrayList<PluginServer*>;
1683         keyframe_threads = new ArrayList<KeyFrameThread*>;
1684
1685         if(debug) printf("MWindow::create_objects %d vwindows=%d show_vwindow=%d\n", 
1686                 __LINE__, 
1687                 vwindows.size(),
1688                 session->show_vwindow);
1689
1690 // Show all vwindows
1691 //      if(session->show_vwindow)
1692 //      {
1693 //              for(int j = 0; j < vwindows.size(); j++)
1694 //              {
1695 //                      VWindow *vwindow = vwindows.get(j);
1696 //                      if(debug) printf("MWindow::create_objects %d vwindow=%p\n", 
1697 //                              __LINE__, 
1698 //                              vwindow);
1699 //                      if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1700 //                      vwindow->gui->lock_window("MWindow::create_objects 1");
1701 //                      if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1702 //                      vwindow->gui->show_window();
1703 //                      if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1704 //                      vwindow->gui->unlock_window();
1705 //              }
1706 //      }
1707
1708
1709         if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1710
1711         if(session->show_cwindow) 
1712         {
1713                 cwindow->gui->lock_window("MWindow::create_objects 1");
1714                 cwindow->gui->show_window();
1715                 cwindow->gui->unlock_window();
1716         }
1717
1718         if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1719         if(session->show_awindow)
1720         {
1721                 awindow->gui->lock_window("MWindow::create_objects 1");
1722                 awindow->gui->show_window();
1723                 awindow->gui->unlock_window();
1724         }
1725
1726         if(debug) printf("MWindow::create_objects %d total_time=%d\n", __LINE__, (int)timer.get_difference());
1727         if(session->show_lwindow)
1728         {
1729                 lwindow->gui->lock_window("MWindow::create_objects 1");
1730                 lwindow->gui->show_window();
1731                 lwindow->gui->unlock_window();
1732         }
1733
1734         if(debug) printf("MWindow::create_objects %d total_time=%d gwindow=%p\n", 
1735                 __LINE__, 
1736                 (int)timer.get_difference(),
1737                 gwindow->gui);
1738         if(session->show_gwindow)
1739         {
1740                 gwindow->gui->lock_window("MWindow::create_objects 1");
1741                 gwindow->gui->show_window();
1742                 gwindow->gui->unlock_window();
1743         }
1744
1745         if(debug) PRINT_TRACE
1746
1747         gui->lock_window("MWindow::create_objects 1");
1748         gui->mainmenu->load_defaults(defaults);
1749         gui->mainmenu->update_toggles(0);
1750         gui->update_patchbay();
1751         gui->draw_canvas(0, 0);
1752         gui->draw_cursor(1);
1753         gui->show_window();
1754         gui->raise_window();
1755         gui->unlock_window();
1756
1757         if(debug) PRINT_TRACE
1758
1759
1760
1761         if(preferences->use_tipwindow)
1762                 init_tipwindow();
1763         if(debug) PRINT_TRACE
1764
1765         gui->add_keyboard_listener(
1766                 (int (BC_WindowBase::*)(BC_WindowBase *))
1767                 &MWindowGUI::keyboard_listener);
1768
1769         hide_splash();
1770         init_shm();
1771         if(debug) PRINT_TRACE
1772
1773         BC_WindowBase::get_resources()->vframe_shm = 1;
1774
1775 }
1776
1777
1778 void MWindow::show_splash()
1779 {
1780 #include "data/heroine_logo11_png.h"
1781         VFrame *frame = new VFrame(heroine_logo11_png);
1782         BC_DisplayInfo display_info;
1783         splash_window = new SplashGUI(frame, 
1784                 display_info.get_root_w() / 2 - frame->get_w() / 2,
1785                 display_info.get_root_h() / 2 - frame->get_h() / 2);
1786         splash_window->create_objects();
1787 }
1788
1789 void MWindow::hide_splash()
1790 {
1791         if(splash_window)
1792                 delete splash_window;
1793         splash_window = 0;
1794 }
1795
1796
1797 void MWindow::start()
1798 {
1799 ENABLE_BUFFER
1800 //PRINT_TRACE
1801 //      vwindows.get(DEFAULT_VWINDOW)->start();
1802         awindow->start();
1803 //PRINT_TRACE
1804         cwindow->start();
1805 //PRINT_TRACE
1806         lwindow->start();
1807 //PRINT_TRACE
1808         gwindow->start();
1809 //PRINT_TRACE
1810         Thread::start();
1811 //PRINT_TRACE
1812         playback_3d->start();
1813 //PRINT_TRACE
1814 }
1815
1816 void MWindow::run()
1817 {
1818         gui->run_window();
1819 }
1820
1821 void MWindow::show_vwindow()
1822 {
1823         int total_running = 0;
1824         session->show_vwindow = 1;
1825
1826
1827 // Raise all windows which are visible
1828         for(int j = 0; j < vwindows.size(); j++)
1829         {
1830                 VWindow *vwindow = vwindows.get(j);
1831                 if(vwindow->is_running())
1832                 {
1833                         vwindow->gui->lock_window("MWindow::show_vwindow");
1834                         vwindow->gui->show_window(0);
1835                         vwindow->gui->raise_window();
1836                         vwindow->gui->flush();
1837                         vwindow->gui->unlock_window();
1838                         total_running++;
1839                 }
1840         }
1841
1842 //printf("MWindow::show_vwindow %d %d\n", __LINE__, vwindows.size());
1843 // If no windows visible
1844         if(!total_running)
1845         {
1846                 get_viewer(1, DEFAULT_VWINDOW);
1847         }
1848
1849         gui->mainmenu->show_vwindow->set_checked(1);
1850 }
1851
1852 void MWindow::show_awindow()
1853 {
1854         session->show_awindow = 1;
1855         awindow->gui->lock_window("MWindow::show_awindow");
1856         awindow->gui->show_window();
1857         awindow->gui->raise_window();
1858         awindow->gui->flush();
1859         awindow->gui->unlock_window();
1860         gui->mainmenu->show_awindow->set_checked(1);
1861 }
1862
1863 char *MWindow::get_cwindow_display()
1864 {
1865         char *x11_host = screens < 2 || session->window_config == 0 ?
1866                 session->a_x11_host : session->b_x11_host;
1867         return *x11_host ? x11_host : 0;
1868 }
1869
1870 void MWindow::show_cwindow()
1871 {
1872         session->show_cwindow = 1;
1873         cwindow->show_window();
1874         gui->mainmenu->show_cwindow->set_checked(1);
1875 }
1876
1877 void MWindow::show_gwindow()
1878 {
1879         session->show_gwindow = 1;
1880
1881         gwindow->gui->lock_window("MWindow::show_gwindow");
1882         gwindow->gui->show_window();
1883         gwindow->gui->raise_window();
1884         gwindow->gui->flush();
1885         gwindow->gui->unlock_window();
1886
1887         gui->mainmenu->show_gwindow->set_checked(1);
1888 }
1889
1890 void MWindow::show_lwindow()
1891 {
1892         session->show_lwindow = 1;
1893         lwindow->gui->lock_window("MWindow::show_lwindow");
1894         lwindow->gui->show_window();
1895         lwindow->gui->raise_window();
1896         lwindow->gui->flush();
1897         lwindow->gui->unlock_window();
1898         gui->mainmenu->show_lwindow->set_checked(1);
1899 }
1900
1901 int MWindow::tile_windows(int window_config)
1902 {
1903         int need_reload = 0;
1904         int play_config = window_config==0 ? 0 : 1;
1905         edl->session->playback_config->load_defaults(defaults, play_config);
1906         session->default_window_positions(window_config);
1907         if( screens == 1 ) {
1908                 gui->default_positions();
1909                 sync_parameters(CHANGE_ALL);
1910         }
1911         else
1912                 need_reload = 1;
1913         return need_reload;
1914 }
1915
1916 void MWindow::toggle_loop_playback()
1917 {
1918         edl->local_session->loop_playback = !edl->local_session->loop_playback;
1919         set_loop_boundaries();
1920         save_backup();
1921
1922         gui->draw_overlays(1);
1923         sync_parameters(CHANGE_PARAMS);
1924 }
1925
1926 //void MWindow::set_titles(int value)
1927 //{
1928 //      edl->session->show_titles = value;
1929 //      trackmovement(edl->local_session->track_start);
1930 //}
1931
1932 void MWindow::set_screens(int value)
1933 {
1934         screens = value;
1935 }
1936
1937 void MWindow::set_auto_keyframes(int value, int lock_mwindow, int lock_cwindow)
1938 {
1939         if(lock_mwindow) gui->lock_window("MWindow::set_auto_keyframes");
1940         edl->session->auto_keyframes = value;
1941         gui->mbuttons->edit_panel->keyframe->update(value);
1942         gui->flush();
1943         if(lock_mwindow) gui->unlock_window();
1944
1945         if(lock_cwindow) cwindow->gui->lock_window("MWindow::set_auto_keyframes");
1946         cwindow->gui->edit_panel->keyframe->update(value);
1947         cwindow->gui->flush();
1948         if(lock_cwindow) cwindow->gui->unlock_window();
1949 }
1950
1951 void MWindow::set_keyframe_type(int mode)
1952 {
1953         gui->lock_window("MWindow::set_keyframe_type");
1954         edl->local_session->floatauto_type = mode;
1955         gui->mainmenu->update_toggles(0);
1956         gui->unlock_window();
1957 }
1958
1959 int MWindow::set_editing_mode(int new_editing_mode, int lock_mwindow, int lock_cwindow)
1960 {
1961         if(lock_mwindow) gui->lock_window("MWindow::set_editing_mode");
1962         edl->session->editing_mode = new_editing_mode;
1963         gui->mbuttons->edit_panel->editing_mode = edl->session->editing_mode;
1964         gui->mbuttons->edit_panel->update();
1965         gui->set_editing_mode(1);
1966         if(lock_mwindow) gui->unlock_window();
1967
1968
1969         if(lock_cwindow) cwindow->gui->lock_window("MWindow::set_editing_mode");
1970         cwindow->gui->edit_panel->update();
1971         cwindow->gui->edit_panel->editing_mode = edl->session->editing_mode;
1972         if(lock_cwindow) cwindow->gui->unlock_window();
1973         return 0;
1974 }
1975
1976
1977 void MWindow::sync_parameters(int change_type)
1978 {
1979
1980 // Sync engines which are playing back
1981         if(cwindow->playback_engine->is_playing_back)
1982         {
1983                 if(change_type == CHANGE_PARAMS)
1984                 {
1985 // TODO: block keyframes until synchronization is done
1986                         cwindow->playback_engine->sync_parameters(edl);
1987                 }
1988                 else
1989 // Stop and restart
1990                 {
1991                         int command = cwindow->playback_engine->command->command;
1992                         cwindow->playback_engine->que->send_command(STOP,
1993                                 CHANGE_NONE, 
1994                                 0,
1995                                 0);
1996 // Waiting for tracking to finish would make the restart position more
1997 // accurate but it can't lock the window to stop tracking for some reason.
1998 // Not waiting for tracking gives a faster response but restart position is
1999 // only as accurate as the last tracking update.
2000                         cwindow->playback_engine->interrupt_playback(0);
2001                         cwindow->playback_engine->que->send_command(command,
2002                                         change_type, 
2003                                         edl,
2004                                         1,
2005                                         0);
2006                 }
2007         }
2008         else
2009         {
2010                 cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
2011                                                         change_type,
2012                                                         edl,
2013                                                         1);
2014         }
2015 }
2016
2017 void MWindow::age_caches()
2018 {
2019 // printf("MWindow::age_caches %d %lld %lld %lld %lld\n", 
2020 // __LINE__, 
2021 // preferences->cache_size,
2022 // audio_cache->get_memory_usage(1),
2023 // video_cache->get_memory_usage(1),
2024 // frame_cache->get_memory_usage(), 
2025 // wave_cache->get_memory_usage(),
2026 // memory_usage);
2027         frame_cache->age_cache(512);
2028         wave_cache->age_cache(8192);
2029
2030         int64_t memory_usage;
2031         int64_t prev_memory_usage = 0;
2032         int result = 0;
2033         int64_t video_size = (int64_t)(preferences->cache_size * 0.80);
2034         while( !result && prev_memory_usage !=
2035                 (memory_usage=video_cache->get_memory_usage(1)) &&
2036                 memory_usage > video_size ) {
2037                 video_cache->delete_oldest();
2038                 prev_memory_usage = memory_usage;
2039         }
2040
2041         prev_memory_usage = 0;
2042         result = 0;
2043         int64_t audio_size = (int64_t)(preferences->cache_size * 0.20);
2044         while( !result && prev_memory_usage !=
2045                 (memory_usage=audio_cache->get_memory_usage(1)) &&
2046                 memory_usage > audio_size ) {
2047                 audio_cache->delete_oldest();
2048                 prev_memory_usage = memory_usage;
2049         }
2050 }
2051
2052 void MWindow::reset_android_remote()
2053 {
2054         gui->use_android_remote(preferences->android_remote);
2055 }
2056
2057
2058 void MWindow::show_keyframe_gui(Plugin *plugin)
2059 {
2060         keyframe_gui_lock->lock("MWindow::show_keyframe_gui");
2061 // Find existing thread
2062         for(int i = 0; i < keyframe_threads->size(); i++)
2063         {
2064                 if(keyframe_threads->get(i)->plugin == plugin)
2065                 {
2066                         keyframe_threads->get(i)->start_window(plugin, 0);
2067                         keyframe_gui_lock->unlock();
2068                         return;
2069                 }
2070         }
2071
2072 // Find unused thread
2073         for(int i = 0; i < keyframe_threads->size(); i++)
2074         {
2075                 if(!keyframe_threads->get(i)->plugin)
2076                 {
2077                         keyframe_threads->get(i)->start_window(plugin, 0);
2078                         keyframe_gui_lock->unlock();
2079                         return;
2080                 }
2081         }
2082
2083 // Create new thread
2084         KeyFrameThread *thread = new KeyFrameThread(this);
2085         keyframe_threads->append(thread);
2086         thread->start_window(plugin, 0);
2087
2088         keyframe_gui_lock->unlock();
2089 }
2090
2091
2092
2093
2094
2095 void MWindow::show_plugin(Plugin *plugin)
2096 {
2097         int done = 0;
2098
2099 SET_TRACE
2100 // Remove previously deleted plugin GUIs
2101         dead_plugin_lock->lock("MWindow::delete_plugin");
2102         for(int i = 0; i < dead_plugins->size(); i++)
2103         {
2104                 delete dead_plugins->get(i);
2105         }
2106         dead_plugins->remove_all();
2107         dead_plugin_lock->unlock();
2108
2109 //printf("MWindow::show_plugin %d\n", __LINE__);
2110 SET_TRACE
2111
2112
2113         plugin_gui_lock->lock("MWindow::show_plugin");
2114         for(int i = 0; i < plugin_guis->total; i++)
2115         {
2116 // Pointer comparison
2117                 if(plugin_guis->values[i]->plugin == plugin)
2118                 {
2119                         plugin_guis->values[i]->raise_window();
2120                         done = 1;
2121                         break;
2122                 }
2123         }
2124 SET_TRACE
2125
2126 //printf("MWindow::show_plugin 1\n");
2127         if(!done)
2128         {
2129                 if(!plugin->track)
2130                 {
2131                         printf("MWindow::show_plugin track not defined.\n");
2132                 }
2133                 PluginServer *server = scan_plugindb(plugin->title,
2134                         plugin->track->data_type);
2135
2136 //printf("MWindow::show_plugin %p %d\n", server, server->uses_gui);
2137                 if(server && server->uses_gui)
2138                 {
2139                         PluginServer *gui = plugin_guis->append(new PluginServer(*server));
2140 // Needs mwindow to do GUI
2141                         gui->set_mwindow(this);
2142                         gui->open_plugin(0, preferences, edl, plugin);
2143                         gui->show_gui();
2144                         plugin->show = 1;
2145                 }
2146         }
2147         plugin_gui_lock->unlock();
2148 //printf("MWindow::show_plugin %d\n", __LINE__);
2149 SET_TRACE
2150 //sleep(1);
2151 //printf("MWindow::show_plugin 2\n");
2152 }
2153
2154 void MWindow::hide_plugin(Plugin *plugin, int lock)
2155 {
2156         plugin->show = 0;
2157 // Update the toggle
2158         gui->lock_window("MWindow::hide_plugin");
2159         gui->update(0, 1, 0, 0, 0, 0, 0);
2160         gui->unlock_window();
2161
2162         if(lock) plugin_gui_lock->lock("MWindow::hide_plugin");
2163         for(int i = 0; i < plugin_guis->total; i++)
2164         {
2165                 if(plugin_guis->values[i]->plugin == plugin)
2166                 {
2167                         PluginServer *ptr = plugin_guis->values[i];
2168                         plugin_guis->remove(ptr);
2169                         if(lock) plugin_gui_lock->unlock();
2170 // Last command executed in client side close
2171 // Schedule for deletion
2172                         ptr->hide_gui();
2173                         delete_plugin(ptr);
2174 //sleep(1);
2175 //                      return;
2176                 }
2177         }
2178         if(lock) plugin_gui_lock->unlock();
2179 }
2180
2181 void MWindow::delete_plugin(PluginServer *plugin)
2182 {
2183         dead_plugin_lock->lock("MWindow::delete_plugin");
2184         dead_plugins->append(plugin);
2185         dead_plugin_lock->unlock();
2186 }
2187
2188 void MWindow::hide_plugins()
2189 {
2190         plugin_gui_lock->lock("MWindow::hide_plugins 1");
2191         while(plugin_guis->size())
2192         {
2193                 PluginServer *ptr = plugin_guis->get(0);
2194                 plugin_guis->remove(ptr);
2195                 plugin_gui_lock->unlock();
2196 // Last command executed in client side close
2197 // Schedule for deletion
2198                 ptr->hide_gui();
2199                 delete_plugin(ptr);
2200                 plugin_gui_lock->lock("MWindow::hide_plugins 2");
2201         }
2202         plugin_gui_lock->unlock();
2203
2204         hide_keyframe_guis();
2205 }
2206
2207 void MWindow::hide_keyframe_guis()
2208 {
2209         keyframe_gui_lock->lock("MWindow::hide_keyframe_guis");
2210         for(int i = 0; i < keyframe_threads->size(); i++)
2211         {
2212                 keyframe_threads->get(i)->close_window();
2213         }
2214         keyframe_gui_lock->unlock();
2215 }
2216
2217 void MWindow::hide_keyframe_gui(Plugin *plugin)
2218 {
2219         keyframe_gui_lock->lock("MWindow::hide_keyframe_gui");
2220         for(int i = 0; i < keyframe_threads->size(); i++)
2221         {
2222                 if(keyframe_threads->get(i)->plugin == plugin)
2223                 {
2224                         keyframe_threads->get(i)->close_window();
2225                         break;
2226                 }
2227         }
2228         keyframe_gui_lock->unlock();
2229 }
2230
2231 void MWindow::update_keyframe_guis()
2232 {
2233 // Send new configuration to keyframe GUI's
2234         keyframe_gui_lock->lock("MWindow::update_keyframe_guis");
2235         for(int i = 0; i < keyframe_threads->size(); i++)
2236         {
2237                 KeyFrameThread *ptr = keyframe_threads->get(i);
2238                 if(edl->tracks->plugin_exists(ptr->plugin))
2239                         ptr->update_gui(1);
2240                 else
2241                 {
2242                         ptr->close_window();
2243                 }
2244         }
2245         keyframe_gui_lock->unlock();
2246 }
2247
2248 void MWindow::update_plugin_guis(int do_keyframe_guis)
2249 {
2250 // Send new configuration to plugin GUI's
2251         plugin_gui_lock->lock("MWindow::update_plugin_guis");
2252
2253         for(int i = 0; i < plugin_guis->size(); i++)
2254         {
2255                 PluginServer *ptr = plugin_guis->get(i);
2256                 if(edl->tracks->plugin_exists(ptr->plugin))
2257                         ptr->update_gui();
2258                 else
2259                 {
2260 // Schedule for deletion if no plugin
2261                         plugin_guis->remove_number(i);
2262                         i--;
2263                         
2264                         ptr->hide_gui();
2265                         delete_plugin(ptr);
2266                 }
2267         }
2268
2269
2270 // Change plugin variable if not visible
2271         Track *track = edl->tracks->first;
2272         while(track)
2273         {
2274                 for(int i = 0; i < track->plugin_set.size(); i++)
2275                 {
2276                         Plugin *plugin = (Plugin*)track->plugin_set.get(i)->first;
2277                         while(plugin)
2278                         {
2279                                 int got_it = 0;
2280                                 for(int i = 0; i < plugin_guis->size(); i++)
2281                                 {
2282                                         PluginServer *server = plugin_guis->get(i);
2283                                         if(server->plugin == plugin) 
2284                                         {
2285                                                 got_it = 1;
2286                                                 break;
2287                                         }
2288                                 }
2289                                 
2290                                 if(!got_it) plugin->show = 0;
2291
2292                                 plugin = (Plugin*)plugin->next;
2293                         }
2294                 }
2295                 
2296                 track = track->next;
2297         }
2298
2299         plugin_gui_lock->unlock();
2300
2301
2302         if(do_keyframe_guis) update_keyframe_guis();
2303 }
2304
2305 int MWindow::plugin_gui_open(Plugin *plugin)
2306 {
2307         int result = 0;
2308         plugin_gui_lock->lock("MWindow::plugin_gui_open");
2309         for(int i = 0; i < plugin_guis->total; i++)
2310         {
2311                 if(plugin_guis->values[i]->plugin->identical_location(plugin))
2312                 {
2313                         result = 1;
2314                         break;
2315                 }
2316         }
2317         plugin_gui_lock->unlock();
2318         return result;
2319 }
2320
2321 void MWindow::render_plugin_gui(void *data, Plugin *plugin)
2322 {
2323         plugin_gui_lock->lock("MWindow::render_plugin_gui");
2324         for(int i = 0; i < plugin_guis->total; i++)
2325         {
2326                 if(plugin_guis->values[i]->plugin->identical_location(plugin))
2327                 {
2328                         plugin_guis->values[i]->render_gui(data);
2329                         break;
2330                 }
2331         }
2332         plugin_gui_lock->unlock();
2333 }
2334
2335 void MWindow::render_plugin_gui(void *data, int size, Plugin *plugin)
2336 {
2337         plugin_gui_lock->lock("MWindow::render_plugin_gui");
2338         for(int i = 0; i < plugin_guis->total; i++)
2339         {
2340                 if(plugin_guis->values[i]->plugin->identical_location(plugin))
2341                 {
2342                         plugin_guis->values[i]->render_gui(data, size);
2343                         break;
2344                 }
2345         }
2346         plugin_gui_lock->unlock();
2347 }
2348
2349
2350 void MWindow::update_plugin_states()
2351 {
2352         plugin_gui_lock->lock("MWindow::update_plugin_states");
2353         for(int i = 0; i < plugin_guis->total; i++)
2354         {
2355                 int result = 0;
2356 // Get a plugin GUI
2357                 Plugin *src_plugin = plugin_guis->values[i]->plugin;
2358                 PluginServer *src_plugingui = plugin_guis->values[i];
2359
2360 // Search for plugin in EDL.  Only the master EDL shows plugin GUIs.
2361                 for(Track *track = edl->tracks->first; 
2362                         track && !result; 
2363                         track = track->next)
2364                 {
2365                         for(int j = 0; 
2366                                 j < track->plugin_set.total && !result; 
2367                                 j++)
2368                         {
2369                                 PluginSet *plugin_set = track->plugin_set.values[j];
2370                                 for(Plugin *plugin = (Plugin*)plugin_set->first; 
2371                                         plugin && !result; 
2372                                         plugin = (Plugin*)plugin->next)
2373                                 {
2374                                         if(plugin == src_plugin &&
2375                                                 !strcmp(plugin->title, src_plugingui->title)) result = 1;
2376                                 }
2377                         }
2378                 }
2379
2380
2381 // Doesn't exist anymore
2382                 if(!result)
2383                 {
2384                         hide_plugin(src_plugin, 0);
2385                         i--;
2386                 }
2387         }
2388         plugin_gui_lock->unlock();
2389 }
2390
2391
2392 void MWindow::update_plugin_titles()
2393 {
2394         for(int i = 0; i < plugin_guis->total; i++)
2395         {
2396                 plugin_guis->values[i]->update_title();
2397         }
2398 }
2399
2400 int MWindow::asset_to_edl(EDL *new_edl, 
2401         Asset *new_asset, 
2402         RecordLabels *labels)
2403 {
2404 const int debug = 0;
2405 if(debug) printf("MWindow::asset_to_edl %d new_asset->layers=%d\n", 
2406 __LINE__,
2407 new_asset->layers);
2408 // Keep frame rate, sample rate, and output size unchanged.
2409 // These parameters would revert the project if VWindow displayed an asset
2410 // of different size than the project.
2411         if(new_asset->video_data)
2412         {
2413                 new_edl->session->video_tracks = new_asset->layers;
2414         }
2415         else
2416                 new_edl->session->video_tracks = 0;
2417
2418 if(debug) printf("MWindow::asset_to_edl %d\n", __LINE__);
2419
2420
2421
2422
2423
2424         if(new_asset->audio_data)
2425         {
2426                 new_edl->session->audio_tracks = new_asset->channels;
2427         }
2428         else
2429                 new_edl->session->audio_tracks = 0;
2430 //printf("MWindow::asset_to_edl 2 %d %d\n", new_edl->session->video_tracks, new_edl->session->audio_tracks);
2431
2432 if(debug) printf("MWindow::asset_to_edl %d\n", __LINE__);
2433         new_edl->create_default_tracks();
2434 //printf("MWindow::asset_to_edl 2 %d %d\n", new_edl->session->video_tracks, new_edl->session->audio_tracks);
2435 if(debug) printf("MWindow::asset_to_edl %d\n", __LINE__);
2436
2437
2438
2439 //printf("MWindow::asset_to_edl 3\n");
2440         new_edl->insert_asset(new_asset,
2441                 0,
2442                 0, 
2443                 0, 
2444                 labels);
2445 //printf("MWindow::asset_to_edl 3\n");
2446 if(debug) printf("MWindow::asset_to_edl %d\n", __LINE__);
2447
2448
2449
2450
2451
2452         char string[BCTEXTLEN];
2453         FileSystem fs;
2454         fs.extract_name(string, new_asset->path);
2455 //printf("MWindow::asset_to_edl 3\n");
2456
2457         strcpy(new_edl->local_session->clip_title, string);
2458 //printf("MWindow::asset_to_edl 4 %s\n", string);
2459 if(debug) printf("MWindow::asset_to_edl %d\n", __LINE__);
2460
2461         return 0;
2462 }
2463
2464 int MWindow::edl_to_nested(EDL *new_edl, 
2465         EDL *nested_edl)
2466 {
2467
2468 // Keep frame rate, sample rate, and output size unchanged.
2469 // These parameters would revert the project if VWindow displayed an asset
2470 // of different size than the project.
2471
2472
2473
2474 // Nest all video & audio outputs
2475         new_edl->session->video_tracks = 1;
2476         new_edl->session->audio_tracks = nested_edl->session->audio_channels;
2477         new_edl->create_default_tracks();
2478
2479
2480
2481         new_edl->insert_asset(0,
2482                 nested_edl,
2483                 0, 
2484                 0, 
2485                 0);
2486
2487         char string[BCTEXTLEN];
2488         FileSystem fs;
2489         fs.extract_name(string, nested_edl->path);
2490 //printf("MWindow::edl_to_nested %p %s\n", nested_edl, nested_edl->path);
2491
2492         strcpy(new_edl->local_session->clip_title, string);
2493
2494         return 0;
2495 }
2496
2497 // Reset everything after a load.
2498 void MWindow::update_project(int load_mode)
2499 {
2500         const int debug = 0;
2501         
2502         if(debug) PRINT_TRACE
2503         restart_brender();
2504         edl->tracks->update_y_pixels(theme);
2505
2506         if(debug) PRINT_TRACE
2507
2508         if(load_mode == LOADMODE_REPLACE ||
2509                 load_mode == LOADMODE_REPLACE_CONCATENATE)
2510         {
2511                 gui->load_panes();
2512         }
2513
2514         gui->update(1, 1, 1, 1, 1, 1, 1);
2515         if(debug) PRINT_TRACE
2516         gui->unlock_window();
2517
2518         cwindow->gui->lock_window("MWindow::update_project 1");
2519         cwindow->update(0, 0, 1, 1, 1);
2520         cwindow->gui->unlock_window();
2521
2522         if(debug) PRINT_TRACE
2523
2524 // Close all the vwindows
2525         if(load_mode == LOADMODE_REPLACE ||
2526                 load_mode == LOADMODE_REPLACE_CONCATENATE)
2527         {
2528                 if(debug) PRINT_TRACE
2529                 int first_vwindow = 0;
2530                 if(session->show_vwindow) first_vwindow = 1;
2531 // Change visible windows to no source
2532                 for(int i = 0; i < first_vwindow && i < vwindows.size(); i++)
2533                 {
2534                         vwindows.get(i)->change_source(-1);
2535                 }
2536
2537 // Close remaining windows
2538                 for(int i = first_vwindow; i < vwindows.size(); i++)
2539                 {
2540                         vwindows.get(i)->close_window();
2541                 }
2542                 if(debug) PRINT_TRACE
2543         }
2544         else
2545         if(vwindows.size())
2546         {
2547                 VWindow *vwindow = vwindows.get(DEFAULT_VWINDOW);
2548                 if(vwindow->is_running())
2549                 {
2550                         vwindow->gui->lock_window("MWindow::update_project");
2551                         vwindow->update(1);
2552                         vwindow->gui->unlock_window();
2553                 }
2554         }
2555
2556         if(debug) PRINT_TRACE
2557         cwindow->gui->lock_window("MWindow::update_project 2");
2558         cwindow->gui->timebar->update(0);
2559         cwindow->gui->unlock_window();
2560
2561         if(debug) PRINT_TRACE
2562         cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
2563                 CHANGE_ALL,
2564                 edl,
2565                 1);
2566
2567         if(debug) PRINT_TRACE
2568
2569         awindow->gui->lock_window("MWindow::update_project");
2570         awindow->gui->update_assets();
2571         awindow->gui->flush();
2572         awindow->gui->unlock_window();
2573
2574         if(debug) PRINT_TRACE
2575
2576         gui->lock_window("MWindow::update_project");
2577         gui->flush();
2578         if(debug) PRINT_TRACE
2579 }
2580
2581 void MWindow::remove_indexfile(Indexable *indexable)
2582 {
2583         if( !indexable->is_asset ) return;
2584         Asset *asset = (Asset *)indexable;
2585 // Erase file
2586         IndexFile::delete_index(preferences, asset, ".toc");
2587         IndexFile::delete_index(preferences, asset, ".idx");
2588 }
2589
2590 void MWindow::rebuild_indices()
2591 {
2592         for(int i = 0; i < session->drag_assets->total; i++)
2593         {
2594                 Indexable *indexable = session->drag_assets->values[i];
2595 //printf("MWindow::rebuild_indices 1 %s\n", indexable->path);
2596                 remove_indexfile(indexable);
2597 // Schedule index build
2598                 IndexState *index_state = indexable->index_state;
2599                 index_state->index_status = INDEX_NOTTESTED;
2600                 if( indexable->is_asset ) {
2601                         Asset *asset = (Asset *)indexable;
2602                         if( asset->format != FILE_PCM )
2603                                 asset->reset_audio();
2604                         asset->reset_video();
2605                 }
2606                 mainindexes->add_next_asset(0, indexable);
2607         }
2608         mainindexes->start_build();
2609 }
2610
2611
2612 void MWindow::save_backup()
2613 {
2614         FileXML file;
2615         edl->set_path(session->filename);
2616         edl->save_xml(&file, 
2617                 BACKUP_PATH,
2618                 0,
2619                 0);
2620         file.terminate_string();
2621         char path[BCTEXTLEN];
2622         FileSystem fs;
2623         strcpy(path, BACKUP_PATH);
2624         fs.complete_path(path);
2625
2626         if(file.write_to_file(path))
2627         {
2628                 char string2[256];
2629                 sprintf(string2, _("Couldn't open %s for writing."), BACKUP_PATH);
2630                 gui->show_message(string2);
2631         }
2632 }
2633
2634 void MWindow::load_backup()
2635 {
2636         ArrayList<char*> path_list;
2637         path_list.set_array_delete();
2638         char *out_path;
2639         char string[BCTEXTLEN];
2640         strcpy(string, BACKUP_PATH);
2641         FileSystem fs;
2642         fs.complete_path(string);
2643         
2644         path_list.append(out_path = new char[strlen(string) + 1]);
2645         strcpy(out_path, string);
2646         
2647         load_filenames(&path_list, LOADMODE_REPLACE, 0);
2648         edl->local_session->clip_title[0] = 0;
2649 // This is unique to backups since the path of the backup is different than the
2650 // path of the project.
2651         set_filename(edl->path);
2652         path_list.remove_all_objects();
2653         save_backup();
2654 }
2655
2656 static inline int gcd(int m, int n)
2657 {
2658         int r;
2659         if( m < n ) { r = m;  m = n;  n = r; }
2660         while( (r = m % n) != 0 ) { m = n;  n = r; }
2661         return n;
2662 }
2663
2664 int MWindow::create_aspect_ratio(float &w, float &h, int width, int height)
2665 {
2666         if(!width || !height) return 1;
2667         double ar = (double)width / height;
2668         int ww = width, hh = height;
2669         // numerator, denominator must be under mx
2670         int mx = 255, n = gcd(ww, hh);
2671         if( n > 1 ) { ww /= n; hh /= n; }
2672         // search near height in case extra/missing lines
2673         if( ww >= mx || hh >= mx ) {
2674                 double err = height;  // +/- 2 percent height
2675                 for( int m=2*height/100, i=1; m>0; i=i>0 ? -i : (--m, -i+1) ) {
2676                         int iw = width, ih = height+i;
2677                         if( (n=gcd(iw, ih)) > 1 ) {
2678                                 int u = iw/n;  if( u >= mx ) continue;
2679                                 int v = ih/n;  if( v >= mx ) continue;
2680                                 double r = (double) u/v, er = fabs(ar-r);
2681                                 if( er >= err ) continue;
2682                                 err = er;  ww = u;  hh = v;
2683                         }
2684                 }
2685         }
2686
2687         w = ww;  h = hh;
2688         return 0;
2689 }
2690
2691 void MWindow::reset_caches()
2692 {
2693         frame_cache->remove_all();
2694         wave_cache->remove_all();
2695         audio_cache->remove_all();
2696         video_cache->remove_all();
2697         if( cwindow->playback_engine && cwindow->playback_engine->audio_cache )
2698                 cwindow->playback_engine->audio_cache->remove_all();
2699         if( cwindow->playback_engine && cwindow->playback_engine->video_cache )
2700                 cwindow->playback_engine->video_cache->remove_all();
2701         
2702         for(int i = 0; i < vwindows.size(); i++)
2703         {
2704                 VWindow *vwindow = vwindows.get(i);
2705                 if(vwindow->is_running())
2706                 {
2707                         if(vwindow->playback_engine && vwindow->playback_engine->audio_cache)
2708                                 vwindow->playback_engine->audio_cache->remove_all();
2709                         if(vwindow->playback_engine && vwindow->playback_engine->video_cache)
2710                                 vwindow->playback_engine->video_cache->remove_all();
2711                 }
2712         }
2713 }
2714
2715 void MWindow::remove_asset_from_caches(Asset *asset)
2716 {
2717         frame_cache->remove_asset(asset);
2718         wave_cache->remove_asset(asset);
2719         audio_cache->delete_entry(asset);
2720         video_cache->delete_entry(asset);
2721         if( cwindow->playback_engine && cwindow->playback_engine->audio_cache )
2722                 cwindow->playback_engine->audio_cache->delete_entry(asset);
2723         if( cwindow->playback_engine && cwindow->playback_engine->video_cache )
2724                 cwindow->playback_engine->video_cache->delete_entry(asset);
2725         for(int i = 0; i < vwindows.size(); i++)
2726         {
2727                 VWindow *vwindow = vwindows.get(i);
2728                 if(vwindow->is_running())
2729                 {
2730                         if(vwindow->playback_engine && vwindow->playback_engine->audio_cache)
2731                                 vwindow->playback_engine->audio_cache->delete_entry(asset);
2732                         if(vwindow->playback_engine && vwindow->playback_engine->video_cache)
2733                                 vwindow->playback_engine->video_cache->delete_entry(asset);
2734                 }
2735         }
2736 }
2737
2738
2739
2740 void MWindow::remove_assets_from_project(int push_undo)
2741 {
2742         for(int i = 0; i < session->drag_assets->total; i++)
2743         {
2744                 Indexable *indexable = session->drag_assets->values[i];
2745                 if(indexable->is_asset) remove_asset_from_caches((Asset*)indexable);
2746         }
2747
2748 // Remove from VWindow.
2749         for(int i = 0; i < session->drag_clips->total; i++)
2750         {
2751                 for(int j = 0; j < vwindows.size(); j++)
2752                 {
2753                         VWindow *vwindow = vwindows.get(j);
2754                         if(vwindow->is_running())
2755                         {
2756                                 if(session->drag_clips->values[i] == vwindow->get_edl())
2757                                 {
2758                                         vwindow->gui->lock_window("MWindow::remove_assets_from_project 1");
2759                                         vwindow->delete_source(1, 1);
2760                                         vwindow->gui->unlock_window();
2761                                 }
2762                         }
2763                 }
2764         }
2765         
2766         for(int i = 0; i < session->drag_assets->size(); i++)
2767         {
2768                 for(int j = 0; j < vwindows.size(); j++)
2769                 {
2770                         VWindow *vwindow = vwindows.get(j);
2771                         if(vwindow->is_running())
2772                         {
2773                                 if(session->drag_assets->get(i) == vwindow->get_source())
2774                                 {
2775                                         vwindow->gui->lock_window("MWindow::remove_assets_from_project 2");
2776                                         vwindow->delete_source(1, 1);
2777                                         vwindow->gui->unlock_window();
2778                                 }
2779                         }
2780                 }
2781         }
2782         
2783         if(push_undo) undo->update_undo_before();
2784         edl->remove_from_project(session->drag_assets);
2785         edl->remove_from_project(session->drag_clips);
2786         save_backup();
2787         if(push_undo) undo->update_undo_after(_("remove assets"), LOAD_ALL);
2788         restart_brender();
2789
2790         gui->lock_window("MWindow::remove_assets_from_project 3");
2791         gui->update(1,
2792                 1,
2793                 1,
2794                 1,
2795                 0, 
2796                 1,
2797                 0);
2798         gui->unlock_window();
2799
2800         awindow->gui->lock_window("MWindow::remove_assets_from_project 4");
2801         awindow->gui->update_assets();
2802         awindow->gui->flush();
2803         awindow->gui->unlock_window();
2804
2805 // Removes from playback here
2806         sync_parameters(CHANGE_ALL);
2807 }
2808
2809 void MWindow::remove_assets_from_disk()
2810 {
2811 // Remove from disk
2812         for(int i = 0; i < session->drag_assets->total; i++)
2813         {
2814                 remove(session->drag_assets->values[i]->path);
2815         }
2816
2817         remove_assets_from_project(1);
2818 }
2819
2820 void MWindow::dump_plugins(FILE *fp)
2821 {
2822         if( !plugindb ) return;
2823         for(int i = 0; i < plugindb->total; i++)
2824         {
2825                 fprintf(fp, "audio=%d video=%d rt=%d multi=%d"
2826                         " synth=%d transition=%d theme=%d %s\n",
2827                         plugindb->values[i]->audio,
2828                         plugindb->values[i]->video,
2829                         plugindb->values[i]->realtime,
2830                         plugindb->values[i]->multichannel,
2831                         plugindb->values[i]->get_synthesis(),
2832                         plugindb->values[i]->transition,
2833                         plugindb->values[i]->theme,
2834                         plugindb->values[i]->title);
2835         }
2836 }
2837
2838 void MWindow::dump_edl(FILE *fp)
2839 {
2840         if( !edl ) return;
2841         edl->dump(fp);
2842 }
2843
2844 void MWindow::dump_undo(FILE *fp)
2845 {
2846         if( !undo ) return;
2847         undo->dump(fp);
2848 }
2849
2850 void MWindow::dump_exe(FILE *fp)
2851 {
2852         char proc_path[BCTEXTLEN], exe_path[BCTEXTLEN];
2853         sprintf(proc_path, "/proc/%d/exe", (int)getpid());
2854         int len = readlink(proc_path, exe_path, sizeof(exe_path));
2855         if( len < 0 ) { fprintf(fp,"readlink: %m\n"); return; }
2856         exe_path[len] = 0;
2857         struct stat st;
2858         if( stat(exe_path,&st) ) { fprintf(fp,"stat: %m\n"); return; }
2859         fprintf(fp, "path: %s = %9jd bytes\n",exe_path,st.st_size);
2860         int fd = open(exe_path,O_RDONLY);
2861         if( fd < 0 ) { fprintf(fp,"open: %m\n"); return; }
2862         uint8_t buf[65536];  SHA1 sha1;
2863         while( (len=read(fd,buf,sizeof(buf))) > 0 ) {
2864                 sha1.addBytes(buf, len);
2865         }
2866         close(fd);
2867         fprintf(fp, "SHA1: ");
2868         uint8_t digest[20];  sha1.computeHash(digest);
2869         for( int i=0; i<20; ++i ) fprintf(fp, "%02x", digest[i]);
2870         fprintf(fp, "\n");
2871 }
2872
2873
2874 void MWindow::trap_hook(FILE *fp, void *vp)
2875 {
2876         MWindow *mwindow = (MWindow *)vp;
2877         fprintf(fp, "\nEXE:\n");
2878         mwindow->dump_exe(fp);
2879         fprintf(fp, "\nPLUGINS:\n");
2880         mwindow->dump_plugins(fp);
2881         fprintf(fp, "\nEDL:\n");
2882         mwindow->dump_edl(fp);
2883         fprintf(fp, "\nUNDO:\n");
2884         mwindow->dump_undo(fp);
2885 }
2886
2887
2888
2889
2890
2891
2892 int MWindow::save_defaults()
2893 {
2894         gui->save_defaults(defaults);
2895         edl->save_defaults(defaults);
2896         session->save_defaults(defaults);
2897         preferences->save_defaults(defaults);
2898
2899         for(int i = 0; i < plugin_guis->total; i++)
2900         {
2901 // Pointer comparison
2902                 plugin_guis->values[i]->save_defaults();
2903         }
2904
2905         defaults->save();
2906         return 0;
2907 }
2908
2909 int MWindow::run_script(FileXML *script)
2910 {
2911         int result = 0, result2 = 0;
2912         while(!result && !result2)
2913         {
2914                 result = script->read_tag();
2915                 if(!result)
2916                 {
2917                         if(script->tag.title_is("new_project"))
2918                         {
2919 // Run new in immediate mode.
2920 //                              gui->mainmenu->new_project->run_script(script);
2921                         }
2922                         else
2923                         if(script->tag.title_is("record"))
2924                         {
2925 // Run record as a thread.  It is a terminal command.
2926                                 ;
2927 // Will read the complete scipt file without letting record read it if not
2928 // terminated.
2929                                 result2 = 1;
2930                         }
2931                         else
2932                         {
2933                                 printf("MWindow::run_script: Unrecognized command: %s\n",script->tag.get_title() );
2934                         }
2935                 }
2936         }
2937         return result2;
2938 }
2939
2940 // ================================= synchronization
2941
2942
2943 int MWindow::interrupt_indexes()
2944 {
2945         mainindexes->interrupt_build();
2946         return 0; 
2947 }
2948
2949
2950
2951 void MWindow::next_time_format()
2952 {
2953         switch(edl->session->time_format)
2954         {
2955                 case TIME_HMS: edl->session->time_format = TIME_HMSF; break;
2956                 case TIME_HMSF: edl->session->time_format = TIME_SAMPLES; break;
2957                 case TIME_SAMPLES: edl->session->time_format = TIME_SAMPLES_HEX; break;
2958                 case TIME_SAMPLES_HEX: edl->session->time_format = TIME_FRAMES; break;
2959                 case TIME_FRAMES: edl->session->time_format = TIME_FEET_FRAMES; break;
2960                 case TIME_FEET_FRAMES: edl->session->time_format = TIME_SECONDS; break;
2961                 case TIME_SECONDS: edl->session->time_format = TIME_HMS; break;
2962         }
2963
2964         time_format_common();
2965 }
2966
2967 void MWindow::prev_time_format()
2968 {
2969         switch(edl->session->time_format)
2970         {
2971                 case TIME_HMS: edl->session->time_format = TIME_SECONDS; break;
2972                 case TIME_SECONDS: edl->session->time_format = TIME_FEET_FRAMES; break;
2973                 case TIME_FEET_FRAMES: edl->session->time_format = TIME_FRAMES; break;
2974                 case TIME_FRAMES: edl->session->time_format = TIME_SAMPLES_HEX; break;
2975                 case TIME_SAMPLES_HEX: edl->session->time_format = TIME_SAMPLES; break;
2976                 case TIME_SAMPLES: edl->session->time_format = TIME_HMSF; break;
2977                 case TIME_HMSF: edl->session->time_format = TIME_HMS; break;
2978         }
2979
2980         time_format_common();
2981 }
2982
2983 void MWindow::time_format_common()
2984 {
2985         gui->lock_window("MWindow::next_time_format");
2986         gui->redraw_time_dependancies();
2987
2988
2989         char string[BCTEXTLEN], string2[BCTEXTLEN];
2990         sprintf(string, _("Using %s"), Units::print_time_format(edl->session->time_format, string2));
2991         gui->show_message(string);
2992         gui->flush();
2993         gui->unlock_window();
2994 }
2995
2996
2997 int MWindow::set_filename(const char *filename)
2998 {
2999         if( filename != session->filename )
3000                 strcpy(session->filename, filename);
3001         if( filename != edl->path )
3002                 strcpy(edl->path, filename);
3003
3004         if(gui)
3005         {
3006                 if(filename[0] == 0)
3007                 {
3008                         gui->set_title(PROGRAM_NAME);
3009                 }
3010                 else
3011                 {
3012                         FileSystem dir;
3013                         char string[BCTEXTLEN], string2[BCTEXTLEN];
3014                         dir.extract_name(string, filename);
3015                         sprintf(string2, PROGRAM_NAME ": %s", string);
3016                         gui->set_title(string2);
3017                 }
3018         }
3019         return 0; 
3020 }
3021
3022
3023
3024
3025
3026
3027
3028
3029 int MWindow::set_loop_boundaries()
3030 {
3031         double start = edl->local_session->get_selectionstart();
3032         double end = edl->local_session->get_selectionend();
3033         
3034         if(start != 
3035                 end) 
3036         {
3037                 ;
3038         }
3039         else
3040         if(edl->tracks->total_length())
3041         {
3042                 start = 0;
3043                 end = edl->tracks->total_length();
3044         }
3045         else
3046         {
3047                 start = end = 0;
3048         }
3049
3050         if(edl->local_session->loop_playback && start != end)
3051         {
3052                 edl->local_session->loop_start = start;
3053                 edl->local_session->loop_end = end;
3054         }
3055         return 0; 
3056 }
3057
3058
3059
3060
3061
3062
3063
3064 int MWindow::reset_meters()
3065 {
3066         cwindow->gui->lock_window("MWindow::reset_meters 1");
3067         cwindow->gui->meters->reset_meters();
3068         cwindow->gui->unlock_window();
3069
3070         for(int j = 0; j < vwindows.size(); j++)
3071         {
3072                 VWindow *vwindow = vwindows.get(j);
3073                 if(vwindow->is_running())
3074                 {
3075                         vwindow->gui->lock_window("MWindow::reset_meters 2");
3076                         vwindow->gui->meters->reset_meters();
3077                         vwindow->gui->unlock_window();
3078                 }
3079         }
3080
3081         lwindow->gui->lock_window("MWindow::reset_meters 3");
3082         lwindow->gui->panel->reset_meters();
3083         lwindow->gui->unlock_window();
3084
3085         gui->lock_window("MWindow::reset_meters 4");
3086         gui->reset_meters();
3087         gui->unlock_window();
3088         return 0; 
3089 }
3090
3091
3092 void MWindow::resync_guis()
3093 {
3094 // Update GUIs
3095         restart_brender();
3096         gui->lock_window("MWindow::resync_guis");
3097         gui->update(1, 1, 1, 1, 1, 1, 0);
3098         gui->unlock_window();
3099
3100         cwindow->gui->lock_window("MWindow::resync_guis");
3101         cwindow->gui->resize_event(cwindow->gui->get_w(), 
3102                 cwindow->gui->get_h());
3103         int channels = edl->session->audio_channels;
3104         cwindow->gui->meters->set_meters(channels, 1);
3105         cwindow->gui->flush();
3106         cwindow->gui->unlock_window();
3107
3108         for(int i = 0; i < vwindows.size(); i++)
3109         {
3110                 VWindow *vwindow = vwindows.get(i);
3111                 vwindow->gui->lock_window("MWindow::resync_guis");
3112                 vwindow->gui->resize_event(vwindow->gui->get_w(), 
3113                         vwindow->gui->get_h());
3114                 vwindow->gui->meters->set_meters(channels, 1);
3115                 vwindow->gui->flush();
3116                 vwindow->gui->unlock_window();
3117         }
3118
3119         lwindow->gui->lock_window("MWindow::resync_guis");
3120         lwindow->gui->panel->set_meters(channels, 1);
3121         lwindow->gui->flush();
3122         lwindow->gui->unlock_window();
3123
3124 // Warn user
3125         if(((edl->session->output_w % 4) ||
3126                 (edl->session->output_h % 4)) &&
3127                 edl->session->playback_config->vconfig->driver == PLAYBACK_X11_GL)
3128         {
3129                 MainError::show_error(
3130                         _("This project's dimensions are not multiples of 4 so\n"
3131                         "it can't be rendered by OpenGL."));
3132         }
3133
3134
3135 // Flash frame
3136         sync_parameters(CHANGE_ALL);
3137 }
3138
3139 int MWindow::select_asset(Asset *asset, int vstream, int astream, int delete_tracks)
3140 {
3141         File *file = new File;
3142         EDLSession *session = edl->session;
3143         double old_framerate = session->frame_rate;
3144         double old_samplerate = session->sample_rate;
3145         int result = file->open_file(preferences, asset, 1, 0);
3146         if( !result && delete_tracks > 0 )
3147                 undo->update_undo_before();
3148         if( !result && asset->get_video_layers() > 0 ) {
3149                 // try to get asset up to date, may fail
3150                 file->select_video_stream(asset, vstream);
3151                 // either way use what was/is there.
3152                 double framerate = asset->get_frame_rate();
3153                 int width = asset->get_w();
3154                 int height = asset->get_h();
3155                 // must be multiple of 4 for opengl
3156                 width = (width+3) & ~3;  height = (height+3) & ~3;
3157                 int driver = session->playback_config->vconfig->driver;
3158                 int color_model = file->get_best_colormodel(asset, driver);
3159                 color_model = BC_CModels::is_yuv(color_model) ?
3160                                 BC_CModels::has_alpha(color_model) ? BC_YUVA8888 : BC_YUV888 :
3161                         BC_CModels::is_float(color_model) ?
3162                                 BC_CModels::has_alpha(color_model) ? BC_RGBA_FLOAT : BC_RGB_FLOAT :
3163                                 BC_CModels::has_alpha(color_model) ? BC_RGBA8888 : BC_RGB888;
3164                 session->color_model = color_model;
3165                 session->output_w = width;
3166                 session->output_h = height;
3167                 session->frame_rate = framerate;
3168                 // not, asset->actual_width/actual_height
3169                 asset->width = session->output_w;
3170                 asset->height = session->output_h;
3171                 asset->frame_rate = session->frame_rate;
3172                 create_aspect_ratio(session->aspect_w, session->aspect_h,
3173                         session->output_w, session->output_h);
3174                 Track *track = edl->tracks->first;
3175                 for( Track *next_track=0; track; track=next_track ) {
3176                         next_track = track->next;
3177                         if( track->data_type != TRACK_VIDEO ) continue;
3178                         if( delete_tracks ) {
3179                                 Edit *edit = track->edits->first;
3180                                 for( Edit *next_edit=0; edit; edit=next_edit ) {
3181                                         next_edit = edit->next;
3182                                         if( edit->channel != vstream ||
3183                                             !edit->asset || !edit->asset->is_asset ||
3184                                             *asset != *edit->asset )
3185                                                 delete edit;
3186                                 }
3187                         }
3188                         if( track->edits->first ) {
3189                                 track->track_w = edl->session->output_w;
3190                                 track->track_h = edl->session->output_h;
3191                         }
3192                         else if( delete_tracks )
3193                                 edl->tracks->delete_track(track);
3194                 }
3195                 edl->resample(old_framerate, session->frame_rate, TRACK_VIDEO);
3196         }
3197         if( !result && asset->channels > 0 ) {
3198                 session->sample_rate = asset->get_sample_rate();
3199                 int64_t channel_mask = 0;
3200                 int astrm = file->get_audio_for_video(vstream, astream, channel_mask);
3201                 if( astrm >= 0 ) file->select_audio_stream(asset, astrm);
3202                 if( astrm < 0 || !channel_mask ) channel_mask = (1<<asset->channels)-1;
3203                 int channels = 0;
3204                 for( uint64_t mask=channel_mask; mask!=0; mask>>=1 ) channels += mask & 1;
3205                 if( channels > 6 ) channels = 6;
3206                 session->audio_tracks = session->audio_channels = channels;
3207                 switch( channels ) {
3208                 case 6:
3209                         session->achannel_positions[0] = 90;
3210                         session->achannel_positions[1] = 150;
3211                         session->achannel_positions[2] = 30;
3212                         session->achannel_positions[3] = 210;
3213                         session->achannel_positions[4] = 330;
3214                         session->achannel_positions[5] = 270;
3215                         break;
3216                 case 2:
3217                         session->achannel_positions[0] = 180;
3218                         session->achannel_positions[1] = 0;
3219                         break;
3220                 }
3221                 remap_audio(MWindow::AUDIO_1_TO_1);
3222
3223                 if( delete_tracks ) {
3224                         Track *track = edl->tracks->first;
3225                         for( Track *next_track=0; track; track=next_track ) {
3226                                 next_track = track->next;
3227                                 if( track->data_type != TRACK_AUDIO ) continue;
3228                                 Edit *edit = track->edits->first;
3229                                         for( Edit *next_edit=0; edit; edit=next_edit ) {
3230                                         next_edit = edit->next;
3231                                         if( !((1<<edit->channel) & channel_mask) ||
3232                                             !edit->asset || !edit->asset->is_asset ||
3233                                             *asset != *edit->asset )
3234                                                 delete edit;
3235                                 }
3236                                 if( !track->edits->first )
3237                                         edl->tracks->delete_track(track);
3238                         }
3239                 }
3240                 edl->rechannel();
3241                 edl->resample(old_samplerate, session->sample_rate, TRACK_AUDIO);
3242         }
3243         delete file;
3244         if( !result && delete_tracks > 0 ) {
3245                 save_backup();
3246                 undo->update_undo_after(_("select asset"), LOAD_ALL);
3247         }
3248         resync_guis();
3249         return result;
3250 }
3251
3252 int MWindow::select_asset(int vtrack, int delete_tracks)
3253 {
3254         Track *track = edl->tracks->get(vtrack, TRACK_VIDEO);
3255         if( !track ) return 1;
3256         Edit *edit = track->edits->first;
3257         if( !edit ) return 1;
3258         Asset *asset = edit->asset;
3259         if( !asset || !asset->is_asset ) return 1;
3260         return select_asset(asset, edit->channel, -1, delete_tracks);
3261 }
3262
3263 void MWindow::dump_plugindb(FILE *fp)
3264 {
3265         if( !plugindb ) return;
3266         for(int i = 0; i < plugindb->total; i++)
3267                 plugindb->values[i]->dump(fp);
3268 }
3269