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