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