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