1 // main.c
2 // LiVES (lives-exe)
3 // (c) G. Finch 2003 - 2020 <salsaman+lives@gmail.com>
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 version 3 or higher as published by
7     the Free Software Foundation.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 */
18 
19 // flow is: main() -> real_main() [entry point for liblives]
20 // real_main() -> pre_init() [early initialisation, initialise prefs system]
21 //   initialise prefs
22 //   initialise weed_memory
23 //   initialise message log
24 //   initialise widget_helper
25 // real_main() [parse startup opts]
26 // real_main() -> lives_startup() [added as idle function]
27 // lives_startup ->lives_init
28 // lives_startup2 [added as idle from lives_startup]
29 // real_main() -> gtk_main()
30 
31 // idlefuncion:
32 // lives_startup() [handle any prefs touched by opts which are needed for the GUI]
33 //   on fresh install: do_workdir_query()
34 //   create_LiVES() [create the GUI interface]
35 //   splash_end -> create MT interface if wanted
36 //   show_lives()
37 //   check_for_recovery files, load them if wanted
38 //   do_layout_recovery
39 //   lives_init() [set remaining variables and preferences]
40 
41 #ifdef USE_GLIB
42 #include <glib.h>
43 #endif
44 
45 #define NEED_ENDIAN_TEST
46 
47 #define _MAIN_C_
48 #include "main.h"
49 #include "interface.h"
50 #include "callbacks.h"
51 
52 #include "effects.h"
53 #include "rte_window.h"
54 #include "resample.h"
55 #include "audio.h"
56 #include "paramwindow.h"
57 #include "stream.h"
58 #include "startup.h"
59 #include "cvirtual.h"
60 #include "ce_thumbs.h"
61 #include "rfx-builder.h"
62 
63 #ifndef ENABLE_DIAGNOSTICS
64 #include "diagnostics.h"
65 #endif
66 
67 #ifdef ENABLE_OSC
68 #include "omc-learn.h"
69 #endif
70 
71 #ifdef HAVE_YUV4MPEG
72 #include "lives-yuv4mpeg.h"
73 #endif
74 
75 #ifdef HAVE_UNICAP
76 #include "videodev.h"
77 #endif
78 
79 #include <getopt.h>
80 
81 #ifdef IS_DARWIN
82 #include <mach/mach.h>
83 #include <mach/processor_info.h>
84 #include <mach/mach_host.h>
85 #endif
86 #ifdef USE_LIBPNG
87 #include <png.h>
88 #include <setjmp.h>
89 #endif
90 
91 #ifdef HAVE_PRCTL
92 #include <sys/prctl.h>
93 #endif
94 
95 #ifdef LIVES_OS_UNIX
96 #include <glib-unix.h>
97 #endif
98 
99 
100 ////////////////////////////////
101 _palette *palette;
102 ssize_t sizint, sizdbl, sizshrt;
103 mainwindow *mainw;
104 
105 //////////////////////////////////////////
106 static char buff[256];
107 
108 static char devmap[PATH_MAX];
109 
110 static boolean no_recover = FALSE, auto_recover = FALSE;
111 static boolean upgrade_error = FALSE;
112 static boolean info_only;
113 
114 static char *newconfigfile = NULL;
115 
116 static char start_file[PATH_MAX];
117 static double start = 0.;
118 static int end = 0;
119 
120 static boolean theme_error;
121 
122 static _ign_opts ign_opts;
123 
124 static int zargc;
125 static char **zargv;
126 
127 #ifndef NO_PROG_LOAD
128 static int xxwidth = 0, xxheight = 0;
129 #endif
130 
131 static char *old_vhash = NULL;
132 static int initial_startup_phase = 0;
133 static boolean needs_workdir = FALSE;
134 static boolean ran_ds_dlg = FALSE;
135 
136 static void do_start_messages(void);
137 
138 ////////////////////
139 
140 #ifdef GUI_GTK
141 LiVESTargetEntry target_table[]  = {
142   { "STRING",                     GTK_TARGET_OTHER_APP, 0 },
143   { "text/uri-list",              GTK_TARGET_OTHER_APP, 0 },
144 };
145 #endif
146 
147 /////////////////////////////////
148 #ifdef NO_COMPILE // never compile this
tr_msg(void)149 void tr_msg(void) {
150   // TRANSLATORS: do not translate this message
151   char *msg =
152     (_("Attention Translators !\nThis message is intended for you, so please do not translate it.\n\n"
153        "All translators should read the LiVES translation notes at\n"
154        "http://lives-video.com/TRANS-README.txt"));
155 }
156 #endif
157 
158 
break_me(const char * brkstr)159 void break_me(const char *brkstr) {
160   if (prefs && prefs->show_dev_opts)
161     g_print("BANG ! hit breakpoint %s\n", brkstr ? brkstr : "???");
162   // breakpoint for gdb
163 }
164 
165 
166 // in library we run gtk in a thread so we can return to caller
gtk_thread_wrapper(void * data)167 void *gtk_thread_wrapper(void *data) {
168   gtk_main();
169   return NULL;
170 }
171 
172 
173 #ifdef USE_GLIB
lives_log_handler(const char * domain,LiVESLogLevelFlags level,const char * message,livespointer data)174 static void lives_log_handler(const char *domain, LiVESLogLevelFlags level, const char *message,  livespointer data) {
175   if (prefs && prefs->vj_mode) return;
176   if (level & LIVES_LOG_FATAL_MASK) {
177 #ifndef IGNORE_FATAL_ERRORS
178     raise(LIVES_SIGSEGV);
179 #endif
180   } else {
181     char *msg;
182     LiVESLogLevelFlags xlevel = level & LIVES_LOG_LEVEL_MASK;
183 
184 #ifdef LIVES_NO_DEBUG
185     if (prefs && !prefs->show_dev_opts) return;
186 #endif
187 
188 #ifndef SHOW_ALL_ERRORS
189 #ifdef LIVES_NO_DEBUG
190     if (xlevel >= LIVES_LOG_LEVEL_DEBUG) return;
191 #endif
192     //#define SHOW_INFO_ERRORS
193 #ifndef SHOW_INFO_ERRORS
194     if (xlevel == LIVES_LOG_LEVEL_INFO) return;
195 #endif
196     //#define SHOW_MSG_ERRORS
197 #ifndef SHOW_MSG_ERRORS
198     if (xlevel == LIVES_LOG_LEVEL_MESSAGE) return;
199 #endif
200 #define NO_WARN_ERRORS
201 #ifdef NO_WARN_ERRORS
202     if (xlevel == LIVES_LOG_LEVEL_WARNING) {
203       return;
204     }
205 #endif
206     #define NO_CRITICAL_ERRORS
207 #ifdef NO_CRITICAL_ERRORS
208     if (xlevel == LIVES_LOG_LEVEL_CRITICAL) return;
209 #endif
210 #endif
211 
212     //#define TRAP_THEME_ERRORS
213     //#define SHOW_THEME_ERRORS
214 #ifndef SHOW_THEME_ERRORS
215     if (prefs->show_dev_opts)
216       if (!strncmp(message, "Theme parsing", strlen("Theme parsing"))) {
217 #ifdef TRAP_THEME_ERRORS
218         raise(LIVES_SIGTRAP);
219 #endif
220         return;
221       }
222 #endif
223 
224     //#define TRAP_ERRMSG ""
225 #ifdef TRAP_ERRMSG
226     if (!strncmp(message, TRAP_ERRMSG, strlen(TRAP_ERRMSG))) {
227       fprintf(stderr, "Trapped message %s\n", message);
228       raise(LIVES_SIGTRAP);
229     }
230 #endif
231     if (xlevel == LIVES_LOG_LEVEL_FATAL)
232       msg = lives_strdup_printf("%s Fatal error: %s\n", domain, message);
233     else if (xlevel == LIVES_LOG_LEVEL_CRITICAL)
234       msg = lives_strdup_printf("%s Critical error: %s\n", domain, message);
235     else if (xlevel == LIVES_LOG_LEVEL_WARNING)
236       msg = lives_strdup_printf("%s Warning: %s\n", domain, message);
237     else if (xlevel == LIVES_LOG_LEVEL_MESSAGE)
238       msg = lives_strdup_printf("%s Warning: %s\n", domain, message);
239     else if (xlevel == LIVES_LOG_LEVEL_INFO)
240       msg = lives_strdup_printf("%s Warning: %s\n", domain, message);
241     else if (xlevel == LIVES_LOG_LEVEL_DEBUG)
242       msg = lives_strdup_printf("%s Warning: %s\n", domain, message);
243     else {
244       msg = lives_strdup_printf("%s (Unknown level %u error: %s\n", domain, xlevel, message);
245     }
246 
247     if (mainw->is_ready) d_print(msg);
248     fprintf(stderr, "%s", msg);
249     lives_free(msg);
250 
251 #define BREAK_ON_CRIT
252     if (xlevel <= LIVES_LOG_LEVEL_CRITICAL) {
253 #ifdef BREAK_ON_CRIT
254       raise(LIVES_SIGTRAP);
255 #endif
256     }
257 
258     //#define BREAK_ON_WARN
259 #ifdef BREAK_ON_WARN
260     if (xlevel <= LIVES_LOG_LEVEL_WARNING) raise(LIVES_SIGTRAP);
261 #endif
262 
263     //#define BREAK_ON_ALL
264 #ifdef BREAK_ON_ALL
265     raise(LIVES_SIGTRAP);
266 #endif
267   }
268 }
269 #endif // USE_GLIB
270 
271 
272 #ifdef ENABLE_JACK
jack_warn()273 LIVES_LOCAL_INLINE void jack_warn() {
274   do_jack_noopen_warn3();
275   if (prefs->startup_phase == 4) {
276     do_jack_noopen_warn2();
277   } else do_jack_noopen_warn4();
278 }
279 #endif
280 
281 
defer_sigint(int signum)282 void defer_sigint(int signum) {
283   mainw->signal_caught = signum;
284   switch (mainw->crash_possible) {
285   case 1:
286     // crash in jack_client_open()
287     //jack_warn();
288     break;
289   default:
290     break;
291   }
292   return;
293 }
294 
295 //#define QUICK_EXIT
catch_sigint(int signum)296 void catch_sigint(int signum) {
297   // trap for ctrl-C and others
298   //if (mainw->jackd) lives_jack_end();
299 
300   if (prefs->show_desktop_panel && (capable->wm_caps.pan_annoy & ANNOY_DISPLAY)
301       && (capable->wm_caps.pan_annoy & ANNOY_FS) && (capable->wm_caps.pan_res & RES_HIDE) &&
302       capable->wm_caps.pan_res & RESTYPE_ACTION) {
303     mainw->ignore_screen_size = TRUE;
304     show_desktop_panel();
305   }
306 
307   if (capable && !pthread_equal(capable->main_thread, pthread_self())) {
308     lives_proc_thread_t lpt = THREADVAR(tinfo);
309     weed_set_int_value(lpt, WEED_LEAF_SIGNALLED, signum);
310     weed_set_voidptr_value(lpt, WEED_LEAF_SIGNAL_DATA, THREADVAR(mydata));
311     g_print("Thread got signal %d\n", signum);
312     sleep(3600);
313     pthread_exit(NULL);
314   }
315   if (mainw->record) backup_recording(NULL, NULL);
316 #ifdef QUICK_EXIT
317   /* shoatend(); */
318   /* fprintf(stderr, "shoatt end"); */
319   /* fflush(stderr); */
320   exit(signum);
321 #endif
322   if (mainw) {
323     if (LIVES_MAIN_WINDOW_WIDGET) {
324       if (mainw->foreign) {
325         exit(signum);
326       }
327 
328       if (mainw->multitrack) mainw->multitrack->idlefunc = 0;
329       mainw->fatal = TRUE;
330 
331       if (signum == LIVES_SIGABRT || signum == LIVES_SIGSEGV) {
332         mainw->memok = FALSE;
333         signal(LIVES_SIGSEGV, SIG_DFL);
334         signal(LIVES_SIGABRT, SIG_DFL);
335         fprintf(stderr, _("\nUnfortunately LiVES crashed.\nPlease report this bug at %s\n"
336                           "Thanks. Recovery should be possible if you restart LiVES.\n"), LIVES_BUG_URL);
337         fprintf(stderr, _("\n\nWhen reporting crashes, please include details of your operating system, "
338                           "distribution, and the LiVES version (%s)\n"), LiVES_VERSION);
339 
340         if (capable->has_gdb) {
341           if (mainw->debug) fprintf(stderr, "%s", _("and any information shown below:\n\n"));
342           else fprintf(stderr, "%s", _("Please try running LiVES with the -debug option to collect more information.\n\n"));
343         } else {
344           fprintf(stderr, "%s", _("Please install gdb and then run LiVES with the -debug option "
345                                   "to collect more information.\n\n"));
346         }
347 
348 #ifdef USE_GLIB
349 #ifdef LIVES_NO_DEBUG
350         if (mainw->debug) {
351 #endif
352 #ifdef HAVE_PRCTL
353           prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY);
354 #endif
355           g_on_error_query(capable->myname_full);
356 #ifdef LIVES_NO_DEBUG
357         }
358 #endif
359 #endif
360 #ifndef GDB_ON
361         _exit(signum);
362 #endif
363       }
364 
365       if (mainw->was_set) {
366         if (mainw->memok) fprintf(stderr, "%s", _("Preserving set.\n"));
367       }
368 
369       mainw->leave_recovery = mainw->leave_files = TRUE;
370 
371       mainw->only_close = FALSE;
372       lives_exit(signum);
373     }
374   }
375   exit(signum);
376 }
377 
378 #ifdef USE_GLIB
glib_sighandler(livespointer data)379 static boolean glib_sighandler(livespointer data) {
380   int signum = LIVES_POINTER_TO_INT(data);
381   catch_sigint(signum);
382   return TRUE;
383 }
384 #endif
385 
386 
387 #ifdef GUI_GTK
get_screen_scale(GdkScreen * screen,double * pdpi)388 static double get_screen_scale(GdkScreen *screen, double *pdpi) {
389   double scale = 1.0;
390   double dpi = gdk_screen_get_resolution(screen);
391   if (dpi == 120.) scale = 1.25;
392   else if (dpi == 144.) scale = 1.5;
393   else if (dpi == 192.) scale = 2.0;
394   if (pdpi) *pdpi = dpi;
395   return scale;
396 }
397 #endif
398 
399 
get_monitors(boolean reset)400 void get_monitors(boolean reset) {
401 #ifdef GUI_GTK
402   GdkDisplay *disp;
403   GdkScreen *screen;
404 #if GTK_CHECK_VERSION(3, 22, 0)
405   GdkMonitor *moni;
406 #endif
407   GdkRectangle rect;
408   GdkDevice *device;
409   double scale, dpi;
410   int play_moni = 1;
411 #if !GTK_CHECK_VERSION(3, 22, 0)
412   GSList *dlist, *dislist;
413   int nscreens, nmonitors;
414 #if LIVES_HAS_DEVICE_MANAGER
415   GdkDeviceManager *devman;
416   LiVESList *devlist;
417   int k;
418 #endif
419   int i, j;
420 #endif
421   int idx = 0;
422 
423   if (mainw->ignore_screen_size) return;
424 
425   lives_freep((void **)&mainw->mgeom);
426   capable->nmonitors = 0;
427 
428 #if !GTK_CHECK_VERSION(3, 22, 0)
429   dlist = dislist = gdk_display_manager_list_displays(gdk_display_manager_get());
430 
431   // for each display get list of screens
432 
433   while (dlist) {
434     disp = (GdkDisplay *)dlist->data;
435 
436     // get screens
437     nscreens = lives_display_get_n_screens(disp);
438     for (i = 0; i < nscreens; i++) {
439       screen = gdk_display_get_screen(disp, i);
440       capable->nmonitors += gdk_screen_get_n_monitors(screen);
441     }
442     dlist = dlist->next;
443   }
444 #else
445   disp = gdk_display_get_default();
446   capable->nmonitors += gdk_display_get_n_monitors(disp);
447 #endif
448 
449   mainw->mgeom = (lives_mgeometry_t *)lives_calloc(capable->nmonitors, sizeof(lives_mgeometry_t));
450 
451 
452 #if !GTK_CHECK_VERSION(3, 22, 0)
453   dlist = dislist;
454 
455   while (dlist) {
456     disp = (GdkDisplay *)dlist->data;
457 
458 #if LIVES_HAS_DEVICE_MANAGER
459     devman = gdk_display_get_device_manager(disp);
460     devlist = gdk_device_manager_list_devices(devman, GDK_DEVICE_TYPE_MASTER);
461 #endif
462     // get screens
463     nscreens = lives_display_get_n_screens(disp);
464     for (i = 0; i < nscreens; i++) {
465       screen = gdk_display_get_screen(disp, i);
466       scale = get_screen_scale(screen, &dpi);
467       nmonitors = gdk_screen_get_n_monitors(screen);
468       for (j = 0; j < nmonitors; j++) {
469         gdk_screen_get_monitor_geometry(screen, j, &(rect));
470         mainw->mgeom[idx].x = rect.x;
471         mainw->mgeom[idx].y = rect.y;
472         mainw->mgeom[idx].width = mainw->mgeom[idx].phys_width = rect.width;
473         mainw->mgeom[idx].height = mainw->mgeom[idx].phys_height = rect.height;
474         mainw->mgeom[idx].mouse_device = NULL;
475         mainw->mgeom[idx].dpi = dpi;
476         mainw->mgeom[idx].scale = scale;
477 #if GTK_CHECK_VERSION(3, 4, 0)
478         gdk_screen_get_monitor_workarea(screen, j, &(rect));
479         mainw->mgeom[idx].width = rect.width;
480         mainw->mgeom[idx].height = rect.height;
481 #endif
482 #if LIVES_HAS_DEVICE_MANAGER
483         // get (virtual) mouse device for this screen
484         for (k = 0; k < lives_list_length(devlist); k++) {
485           device = (GdkDevice *)lives_list_nth_data(devlist, k);
486           if (gdk_device_get_display(device) == disp &&
487               gdk_device_get_source(device) == GDK_SOURCE_MOUSE) {
488             mainw->mgeom[idx].mouse_device = device;
489             break;
490           }
491         }
492 #endif
493         mainw->mgeom[idx].disp = disp;
494         mainw->mgeom[idx].screen = screen;
495         idx++;
496         if (idx >= capable->nmonitors) break;
497       }
498     }
499 #if LIVES_HAS_DEVICE_MANAGER
500     lives_list_free(devlist);
501 #endif
502     dlist = dlist->next;
503   }
504 
505   lives_slist_free(dislist);
506 #else
507   screen = gdk_display_get_default_screen(disp);
508   scale = get_screen_scale(screen, &dpi);
509   device = gdk_seat_get_pointer(gdk_display_get_default_seat(disp));
510   for (idx = 0; idx < capable->nmonitors; idx++) {
511     mainw->mgeom[idx].disp = disp;
512     mainw->mgeom[idx].monitor = moni = gdk_display_get_monitor(disp, idx);
513     mainw->mgeom[idx].screen = screen;
514     gdk_monitor_get_geometry(moni, (GdkRectangle *)&rect);
515     mainw->mgeom[idx].x = rect.x;
516     mainw->mgeom[idx].y = rect.y;
517     mainw->mgeom[idx].phys_width = rect.width;
518     mainw->mgeom[idx].phys_height = rect.height;
519     mainw->mgeom[idx].mouse_device = device;
520     mainw->mgeom[idx].dpi = dpi;
521     mainw->mgeom[idx].scale = scale;
522     gdk_monitor_get_workarea(moni, &(rect));
523     mainw->mgeom[idx].width = rect.width;
524     mainw->mgeom[idx].height = rect.height;
525     if (gdk_monitor_is_primary(moni)) {
526       capable->primary_monitor = idx;
527       mainw->mgeom[idx].primary = TRUE;
528     } else if (play_moni == 1) play_moni = idx + 1;
529   }
530 #endif
531 #endif
532 
533   if (prefs->force_single_monitor) capable->nmonitors = 1; // force for clone mode
534 
535   if (!reset) return;
536 
537   prefs->gui_monitor = 0;
538   prefs->play_monitor = play_moni;
539 
540   if (capable->nmonitors > 1) {
541     get_string_pref(PREF_MONITORS, buff, 256);
542 
543     if (*buff && get_token_count(buff, ',') > 1) {
544       char **array = lives_strsplit(buff, ",", 2);
545       prefs->gui_monitor = atoi(array[0]);
546       prefs->play_monitor = atoi(array[1]);
547       lives_strfreev(array);
548     }
549 
550     if (prefs->gui_monitor < 1) prefs->gui_monitor = 1;
551     if (prefs->play_monitor < 0) prefs->play_monitor = 0;
552     if (prefs->gui_monitor > capable->nmonitors) prefs->gui_monitor = capable->nmonitors;
553     if (prefs->play_monitor > capable->nmonitors) prefs->play_monitor = capable->nmonitors;
554   }
555 
556   widget_opts.monitor = prefs->gui_monitor > 0 ? prefs->gui_monitor - 1 : capable->primary_monitor;
557 
558   mainw->old_scr_width = GUI_SCREEN_WIDTH;
559   mainw->old_scr_height = GUI_SCREEN_HEIGHT;
560 
561   prefs->screen_scale = get_double_prefd(PREF_SCREEN_SCALE, 0.);
562   if (prefs->screen_scale == 0.) {
563     prefs->screen_scale = (double)GUI_SCREEN_WIDTH / (double)SCREEN_SCALE_DEF_WIDTH;
564     prefs->screen_scale = (prefs->screen_scale - 1.) * 1.5 + 1.;
565   }
566 
567   if (!prefs->vj_mode && GUI_SCREEN_HEIGHT >= MIN_MSG_AREA_SCRNHEIGHT) prefs->show_msg_area = TRUE;
568   else prefs->show_msg_area = FALSE;
569 
570   widget_opts_rescale(prefs->screen_scale);
571 }
572 
573 
print_notice(void)574 static void print_notice(void) {
575   fprintf(stderr, "\nLiVES %s\n", LiVES_VERSION);
576   fprintf(stderr, "Copyright "LIVES_COPYRIGHT_YEARS" Gabriel Finch ("LIVES_AUTHOR_EMAIL") and others.\n");
577   fprintf(stderr, "LiVES comes with ABSOLUTELY NO WARRANTY\nThis is free software, and you are welcome to redistribute it\n"
578           "under certain conditions; "
579           "see the file COPYING for details.\n\n");
580 }
581 
582 
pre_init(void)583 static boolean pre_init(void) {
584   // stuff which should be done *before* mainwindow is created
585   // returns TRUE if we got an error loading the theme
586 
587 #ifdef GUI_GTK
588   LiVESError *gerr = NULL;
589   char *icon;
590 #endif
591 
592   pthread_mutexattr_t mattr;
593 
594   char *msg, *tmp, *tmp2, *cfgdir;
595 
596   boolean needs_update = FALSE;
597 
598   int i;
599 
600   /// create context data for main thread; must be called before get_capabilities()
601   lives_thread_data_create(0);
602 
603   // need to create directory for configfile before calling get_capabilities()
604   cfgdir = get_dir(prefs->configfile);
605   lives_make_writeable_dir(cfgdir);
606   lives_free(cfgdir);
607 
608   // pre-checked conditions. We will check for these agian
609   if (capable->has_perl && capable->can_write_to_workdir && capable->can_write_to_config &&
610       capable->can_write_to_config_backup && capable->can_write_to_config_new && capable->can_read_from_config &&
611       capable->has_smogrify && capable->smog_version_correct) {
612     // check the backend is there, get some system details and prefs
613     capable = get_capabilities();
614   }
615 
616   //FATAL ERRORS
617 
618   if (!mainw->foreign) {
619     if (!capable->has_perl) {
620       startup_message_fatal(lives_strdup(
621                               _("\nPerl must be installed and in your path.\n\n"
622                                 "Please review the README file which came with this package\nbefore running LiVES.\n\n"
623                                 "Thankyou.\n")));
624     }
625     if (!capable->has_smogrify) {
626       msg = lives_strdup(
627               _("\n`smogrify` must be in your path, and be executable\n\n"
628                 "Please review the README file which came with this package\nbefore running LiVES.\n"));
629       startup_message_fatal(msg);
630     }
631     if (!capable->smog_version_correct) {
632       startup_message_fatal(lives_strdup(
633                               _("\nAn incorrect version of smogrify was found in your path.\n\n"
634                                 "Please review the README file which came with this package\nbefore running LiVES."
635                                 "\n\nThankyou.\n")));
636     }
637 
638     if (!capable->can_read_from_config) {
639       msg = lives_strdup_printf(
640               _("\nLiVES was unable to read from its configuration file\n%s\n\n"
641                 "Please check the file permissions for this file and try again.\n"),
642               (tmp = lives_filename_to_utf8(prefs->configfile, -1, NULL, NULL, NULL)));
643       lives_free(tmp);
644       startup_message_fatal(msg);
645     }
646 
647     if (!capable->can_write_to_config_new || !capable->can_write_to_config_backup || !capable->can_write_to_config) {
648       msg = lives_strdup_printf(
649               _("\nAn error occurred when writing to the configuration files\n%s*\n\n"
650                 "Please check the file permissions for this file and directory\nand try again.\n"),
651               (tmp2 = ensure_extension((tmp = lives_filename_to_utf8(prefs->configfile, -1, NULL, NULL, NULL)),
652                                        LIVES_FILE_EXT_NEW)));
653       lives_free(tmp);
654       lives_free(tmp2);
655       startup_message_fatal(msg);
656     }
657 
658     if (!capable->can_write_to_workdir) {
659       if (!mainw->has_session_workdir) {
660         tmp2 = lives_strdup_printf(_("Please check the %s setting in \n%s\nand try again.\n"),
661                                    (mainw->old_vhash && atoi(mainw->old_vhash) != 0 && atoi(mainw->old_vhash) < 3003003)
662                                    ? "<tempdir>" : "<workdir>",
663                                    (tmp = lives_filename_to_utf8(prefs->configfile, -1, NULL, NULL, NULL)));
664         lives_free(tmp);
665       } else tmp2 = lives_strdup("");
666 
667       msg = lives_strdup_printf(_("\nLiVES was unable to use the working directory\n%s\n\n%s"),
668                                 prefs->workdir, tmp2);
669       lives_free(tmp2);
670       startup_message_fatal(msg);
671     }
672     if (mainw->error) {
673       msg = lives_strdup_printf(_("\nSomething went wrong during startup\n%s"), mainw->msg);
674       startup_message_fatal(msg);
675     }
676   }
677 
678   sizint = sizeof(int);
679   sizdbl = sizeof(double);
680   sizshrt = sizeof(short);
681 
682   // TRANSLATORS: text saying "Any", for encoder and output format (as in "does not matter")
683   mainw->string_constants[LIVES_STRING_CONSTANT_ANY] = (_("Any"));
684   // TRANSLATORS: text saying "None", for playback plugin name (as in "none specified")
685   mainw->string_constants[LIVES_STRING_CONSTANT_NONE] = (_("None"));
686   // TRANSLATORS: text saying "recommended", for plugin names, etc.
687   mainw->string_constants[LIVES_STRING_CONSTANT_RECOMMENDED] = (_("recommended"));
688   // TRANSLATORS: text saying "disabled", (as in "not enabled")
689   mainw->string_constants[LIVES_STRING_CONSTANT_DISABLED] = (_("disabled !"));
690   // TRANSLATORS: text saying "**The current layout**", to warn users that the current layout is affected
691   mainw->string_constants[LIVES_STRING_CONSTANT_CL] = (_("**The current layout**"));
692   // TRANSLATORS: adjective for "Built in" type effects
693   mainw->string_constants[LIVES_STRING_CONSTANT_BUILTIN] = (_("Builtin"));
694   // TRANSLATORS: adjective for "Custom" type effects
695   mainw->string_constants[LIVES_STRING_CONSTANT_CUSTOM] = (_("Custom"));
696   // TRANSLATORS: adjective for "Test" type effects
697   mainw->string_constants[LIVES_STRING_CONSTANT_TEST] = (_("Test"));
698 
699   // now we can use PREFS properly
700   mainw->prefs_cache = cache_file_contents(prefs->configfile);
701 
702   prefs->show_dev_opts = get_boolean_prefd(PREF_SHOW_DEVOPTS, FALSE);
703   prefs->dev_show_dabg = prefs->dev_show_timing = FALSE;
704 
705   prefs->back_compat = get_boolean_prefd(PREF_BACK_COMPAT, TRUE);
706 
707   future_prefs->vj_mode = get_boolean_prefd(PREF_VJMODE, FALSE);
708   if (!ign_opts.ign_vjmode) prefs->vj_mode = future_prefs->vj_mode;
709 
710 #ifdef GUI_GTK
711   if (!prefs->show_dev_opts || prefs->vj_mode) {
712     // don't crash on GTK+ fatals
713     g_log_set_always_fatal((GLogLevelFlags)0);
714   }
715 #endif
716 
717   if (!prefs->vj_mode) {
718     check_for_executable(&capable->has_mplayer, EXEC_MPLAYER);
719     check_for_executable(&capable->has_mplayer2, EXEC_MPLAYER2);
720     check_for_executable(&capable->has_mpv, EXEC_MPV);
721 
722     check_for_executable(&capable->has_convert, EXEC_CONVERT);
723     check_for_executable(&capable->has_composite, EXEC_COMPOSITE);
724     check_for_executable(&capable->has_identify, EXEC_IDENTIFY);
725 
726     check_for_executable(&capable->has_gzip, EXEC_GZIP);
727     check_for_executable(&capable->has_gdb, EXEC_GDB);
728   }
729 
730   /// kick off the thread pool ////////////////////////////////
731   /// this must be done before we can check the disk status
732   future_prefs->nfx_threads = prefs->nfx_threads = get_int_prefd(PREF_NFX_THREADS, capable->ncpus);
733 
734 #ifdef VALGRIND_ON
735   prefs->nfx_threads = 2;
736 #endif
737 
738   lives_threadpool_init();
739 
740   capable->gui_thread = pthread_self();
741 
742   /// check disk storage status /////////////////////////////////////
743   mainw->ds_status = LIVES_STORAGE_STATUS_UNKNOWN;
744 
745   if (!ign_opts.ign_dscrit)
746     prefs->ds_crit_level = (uint64_t)get_int64_prefd(PREF_DS_CRIT_LEVEL, DEF_DS_CRIT_LEVEL);
747   if (prefs->ds_crit_level < 0) prefs->ds_crit_level = 0;
748 
749   prefs->ds_warn_level = (uint64_t)get_int64_prefd(PREF_DS_WARN_LEVEL, DEF_DS_WARN_LEVEL);
750   if (prefs->ds_warn_level < prefs->ds_crit_level) prefs->ds_warn_level = prefs->ds_crit_level;
751   mainw->next_ds_warn_level = prefs->ds_warn_level;
752   prefs->show_disk_quota = get_boolean_prefd(PREF_SHOW_QUOTA, prefs->show_disk_quota);
753   prefs->disk_quota = get_int64_prefd(PREF_DISK_QUOTA, 0);
754   if (prefs->disk_quota < 0) prefs->disk_quota = 0;
755 
756   prefs->quota_limit = 90.0;
757 
758   if (mainw->has_session_workdir) {
759     prefs->show_disk_quota = FALSE;
760     prefs->disk_quota = 0;
761   }
762 
763   future_prefs->disk_quota = prefs->disk_quota;
764 
765   if (!prefs->vj_mode) {
766     /// start a bg thread to get diskspace used
767     if (!needs_workdir && prefs->disk_quota && !needs_workdir && initial_startup_phase == 0)
768       mainw->helper_procthreads[PT_LAZY_DSUSED] = disk_monitor_start(prefs->workdir);
769 
770     if (!needs_workdir && mainw->next_ds_warn_level > 0) {
771       int64_t dsval = disk_monitor_check_result(prefs->workdir);
772       if (dsval > 0) capable->ds_used = dsval;
773       else dsval = capable->ds_used;
774       mainw->ds_status = get_storage_status(prefs->workdir, mainw->next_ds_warn_level, &dsval, 0);
775       capable->ds_free = dsval;
776       if (mainw->ds_status == LIVES_STORAGE_STATUS_CRITICAL) {
777         tmp = ds_critical_msg(prefs->workdir, &capable->mountpoint, dsval);
778         msg = lives_strdup_printf("\n%s\n", tmp);
779         lives_free(tmp);
780         widget_opts.use_markup = TRUE;
781         startup_message_nonfatal(msg);
782         widget_opts.use_markup = FALSE;
783         lives_free(msg);
784       }
785     }
786   }
787 
788   // get some prefs we need to set menu options
789   prefs->gui_monitor = -1;
790 
791   if (prefs->vj_mode) {
792     check_for_executable(&capable->has_wmctrl, EXEC_WMCTRL);
793     check_for_executable(&capable->has_xwininfo, EXEC_XWININFO);
794     check_for_executable(&capable->has_xdotool, EXEC_XDOTOOL);
795   }
796   mainw->mgeom = NULL;
797 
798   prefs->force_single_monitor = get_boolean_pref(PREF_FORCE_SINGLE_MONITOR);
799   mainw->ignore_screen_size = FALSE;
800 
801   capable->primary_monitor = 0;
802 
803   // sets prefs->screen_scale, capable->nmonitors, mainw->mgeom, prefs->play_monitor, prefs->gui_monitor
804   // prefs->show_msg_area, mainw->old_screen_height, mainw->old_screen_width
805   // widget_opts.monitor, widget_opts.screen and various widget_opts sizes
806   get_monitors(TRUE);
807 
808   // set to allow multiple locking by the same thread
809   pthread_mutexattr_init(&mattr);
810   pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
811 
812   // recursive locks
813   pthread_mutex_init(&mainw->abuf_mutex, &mattr);
814   pthread_mutex_init(&mainw->instance_ref_mutex, &mattr);
815 
816   // non-recursive
817   pthread_mutex_init(&mainw->abuf_frame_mutex, NULL);
818   pthread_mutex_init(&mainw->fxd_active_mutex, NULL);
819   pthread_mutex_init(&mainw->event_list_mutex, NULL);
820   pthread_mutex_init(&mainw->clip_list_mutex, NULL);
821   pthread_mutex_init(&mainw->vpp_stream_mutex, NULL);
822   pthread_mutex_init(&mainw->cache_buffer_mutex, NULL);
823   pthread_mutex_init(&mainw->audio_filewriteend_mutex, NULL);
824   pthread_mutex_init(&mainw->exit_mutex, NULL);
825   pthread_mutex_init(&mainw->fbuffer_mutex, NULL);
826   pthread_mutex_init(&mainw->avseek_mutex, NULL);
827   pthread_mutex_init(&mainw->alarmlist_mutex, NULL);
828 
829   // conds
830   pthread_cond_init(&mainw->avseek_cond, NULL);
831 
832   if (prefs->vj_mode)
833     prefs->load_rfx_builtin = FALSE;
834   else
835     prefs->load_rfx_builtin = get_boolean_prefd(PREF_LOAD_RFX_BUILTIN, TRUE);
836 
837   for (i = 0; i < FX_KEYS_MAX; i++) {
838     pthread_mutex_init(&mainw->fx_mutex[i], NULL);
839   }
840 
841   mainw->vrfx_update = NULL;
842 
843   mainw->kb_timer = -1;
844 
845   prefs->sleep_time = 1000;
846 
847   prefs->present = FALSE;
848 
849   get_string_prefd(PREF_DEFAULT_IMAGE_TYPE, prefs->image_type, 16, LIVES_IMAGE_TYPE_PNG);
850   lives_snprintf(prefs->image_ext, 16, "%s",
851                  get_image_ext_for_type(lives_image_type_to_img_type(prefs->image_type)));
852 
853   /// eye candy
854   prefs->extra_colours = get_boolean_prefd(PREF_EXTRA_COLOURS, TRUE);
855   prefs->show_button_images = widget_opts.show_button_images =
856                                 get_boolean_prefd(PREF_SHOW_BUTTON_ICONS, TRUE);
857 
858   prefs->mt_show_ctx = get_boolean_prefd(PREF_MT_SHOW_CTX, TRUE);
859 
860   mainw->threaded_dialog = FALSE;
861   clear_mainw_msg();
862 
863   info_only = FALSE;
864   palette = (_palette *)(lives_malloc(sizeof(_palette)));
865 
866   prefs->sepwin_type = future_prefs->sepwin_type = get_int_prefd(PREF_SEPWIN_TYPE, SEPWIN_TYPE_STICKY);
867 
868   if (!ign_opts.ign_aplayer) {
869     prefs->audio_player = AUD_PLAYER_SOX;
870     lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_SOX);
871   }
872 
873   prefs->open_decorated = TRUE;
874 
875 #ifdef ENABLE_GIW
876   prefs->lamp_buttons = TRUE;
877 #else
878   prefs->lamp_buttons = FALSE;
879 #endif
880 
881   prefs->autoload_subs = get_boolean_prefd(PREF_AUTOLOAD_SUBS, TRUE);
882   prefs->show_subtitles = get_boolean_prefd(PREF_SHOW_SUBS, TRUE);
883 
884   prefs->pa_restart = get_boolean_prefd(PREF_PARESTART, FALSE);
885   get_string_prefd(PREF_PASTARTOPTS, prefs->pa_start_opts, 255, "--high-priority");
886 
887   prefs->letterbox = get_boolean_prefd(PREF_LETTERBOX, TRUE);
888   future_prefs->letterbox_mt = prefs->letterbox_mt = get_boolean_prefd(PREF_LETTERBOXMT, TRUE);
889 
890   prefs->rte_keys_virtual = get_int_prefd(PREF_RTE_KEYS_VIRTUAL, FX_KEYS_PHYSICAL_EXTRA);
891   if (prefs->rte_keys_virtual < 0) prefs->rte_keys_virtual = 0;
892   if (prefs->rte_keys_virtual > FX_KEYS_MAX_VIRTUAL) prefs->rte_keys_virtual = FX_KEYS_MAX_VIRTUAL;
893 
894   prefs->bigendbug = 0;
895 
896 #if GTK_CHECK_VERSION(3, 0, 0)
897   prefs->funky_widgets = TRUE;
898 #else
899   prefs->funky_widgets = FALSE;
900 #endif
901 
902   prefs->show_splash = TRUE;
903   prefs->hide_framebar = FALSE;
904 
905   // get some prefs we need to set menu options
906   future_prefs->show_recent = prefs->show_recent = get_boolean_prefd(PREF_SHOW_RECENT_FILES, TRUE);
907 
908   get_string_pref(PREF_PREFIX_DIR, prefs->prefix_dir, PATH_MAX);
909 
910   if (!(*prefs->prefix_dir)) {
911     if (strcmp(PREFIX, "NONE")) {
912       lives_snprintf(prefs->prefix_dir, PATH_MAX, "%s", PREFIX);
913     } else {
914       lives_snprintf(prefs->prefix_dir, PATH_MAX, "%s", PREFIX_DEFAULT);
915     }
916     needs_update = TRUE;
917   }
918 
919   if (ensure_isdir(prefs->prefix_dir)) needs_update = TRUE;
920 
921   if (needs_update) set_string_pref(PREF_PREFIX_DIR, prefs->prefix_dir);
922 
923 #ifdef GUI_GTK
924   icon = lives_build_filename(prefs->prefix_dir, DESKTOP_ICON_DIR, "lives." LIVES_FILE_EXT_PNG, NULL);
925   gtk_window_set_default_icon_from_file(icon, &gerr);
926   lives_free(icon);
927 
928   if (gerr) lives_error_free(gerr);
929 #endif
930   mainw->first_free_file = 1;
931 
932   needs_update = FALSE;
933 
934   get_string_pref(PREF_LIB_DIR, prefs->lib_dir, PATH_MAX);
935 
936   if (!(*prefs->lib_dir)) {
937     lives_snprintf(prefs->lib_dir, PATH_MAX, "%s", LIVES_LIBDIR);
938     needs_update = TRUE;
939   }
940 
941   if (ensure_isdir(prefs->lib_dir)) needs_update = TRUE;
942   if (needs_update) set_string_pref(PREF_LIB_DIR, prefs->lib_dir);
943 
944   lives_memset(mainw->sepimg_path, 0, 1);
945   lives_memset(mainw->frameblank_path, 0, 1);
946 
947   mainw->imsep = mainw->imframe = NULL;
948 
949   prefs->max_messages = get_int_prefd(PREF_MAX_MSGS, DEF_MAX_MSGS);
950   future_prefs->msg_textsize = prefs->msg_textsize = get_int_prefd(PREF_MSG_TEXTSIZE, DEF_MSG_TEXTSIZE);
951 
952   mainw->msg_list = NULL;
953   mainw->n_messages = 0;
954   mainw->ref_message = NULL;
955   mainw->ref_message_n = 0;
956   add_messages_to_list(_("Starting...\n"));
957 
958   get_string_pref(PREF_GUI_THEME, prefs->theme, 64);
959 
960   if (!(*prefs->theme)) {
961     lives_snprintf(prefs->theme, 64, LIVES_THEME_NONE);
962   }
963 
964   lives_snprintf(future_prefs->theme, 64, "%s", prefs->theme);
965 
966   if (!set_palette_colours(initial_startup_phase == -1)) {
967     lives_snprintf(prefs->theme, 64, LIVES_THEME_NONE);
968     set_palette_colours(initial_startup_phase != -1);
969   } else if (palette->style & STYLE_1) {
970     widget_opts.apply_theme = 1;
971   }
972   if (!mainw->foreign) {
973     if (prefs->startup_phase == -1 && prefs->show_splash) splash_init();
974     print_notice();
975   }
976 
977   get_string_pref(PREF_CDPLAY_DEVICE, prefs->cdplay_device, PATH_MAX);
978 
979   prefs->warning_mask = (uint64_t)get_int64_prefd(PREF_LIVES_WARNING_MASK, DEF_WARNING_MASK);
980 
981   if (!ign_opts.ign_jackopts) {
982     prefs->jack_opts = future_prefs->jack_opts = get_int_prefd(PREF_JACK_OPTS, 16);
983   }
984 
985 #ifdef GUI_GTK
986   if (!has_pref(PREF_SHOW_TOOLTIPS)) {
987     lives_widget_object_get(gtk_settings_get_default(), "gtk-enable-tooltips", &prefs->show_tooltips);
988   } else
989 #endif
990     prefs->show_tooltips = get_boolean_prefd(PREF_SHOW_TOOLTIPS, TRUE);
991 
992   prefs->show_urgency_msgs = get_boolean_prefd(PREF_SHOW_URGENCY, TRUE);
993   prefs->show_overlay_msgs = get_boolean_prefd(PREF_SHOW_OVERLAY_MSGS, TRUE);
994 
995   prefs->allow_easing = get_boolean_prefd(PREF_ALLOW_EASING, TRUE);
996 
997   prefs->render_overlay = prefs->show_dev_opts;
998 
999   if (prefs->show_dev_opts) {
1000     prefs->btgamma = get_boolean_prefd(PREF_BTGAMMA, FALSE);
1001   }
1002 
1003   for (i = 0; i < MAX_FX_CANDIDATE_TYPES; i++) {
1004     mainw->fx_candidates[i].delegate = -1;
1005     mainw->fx_candidates[i].list = NULL;
1006     mainw->fx_candidates[i].func = 0l;
1007     mainw->fx_candidates[i].rfx = NULL;
1008   }
1009 
1010   prefs->volume = (float)get_double_prefd(PREF_MASTER_VOLUME, 1.0);
1011   future_prefs->volume = prefs->volume;
1012   mainw->uflow_count = 0;
1013 
1014   prefs->open_maximised = get_boolean_prefd(PREF_OPEN_MAXIMISED, TRUE);
1015 
1016   for (i = 0; i < MAX_EXT_CNTL; i++) mainw->ext_cntl[i] = FALSE;
1017 
1018   prefs->omc_dev_opts = get_int_prefd(PREF_OMC_DEV_OPTS, 3);
1019 
1020   get_utf8_pref(PREF_OMC_JS_FNAME, prefs->omc_js_fname, PATH_MAX);
1021 
1022 #ifdef ENABLE_OSC
1023 #ifdef OMC_JS_IMPL
1024   if (!*prefs->omc_js_fname) {
1025     const char *tmp = get_js_filename();
1026     if (tmp) {
1027       lives_snprintf(prefs->omc_js_fname, PATH_MAX, "%s", tmp);
1028     }
1029   }
1030 #endif
1031 #endif
1032 
1033   get_utf8_pref(PREF_OMC_MIDI_FNAME, prefs->omc_midi_fname, PATH_MAX);
1034 #ifdef ENABLE_OSC
1035 #ifdef OMC_MIDI_IMPL
1036   if (!*prefs->omc_midi_fname) {
1037     const char *tmp = get_midi_filename();
1038     if (tmp) {
1039       lives_snprintf(prefs->omc_midi_fname, PATH_MAX, "%s", tmp);
1040     }
1041   }
1042 #endif
1043 #endif
1044 
1045 #ifdef ALSA_MIDI
1046   prefs->use_alsa_midi = TRUE;
1047   prefs->alsa_midi_dummy = FALSE;
1048   mainw->seq_handle = NULL;
1049 
1050   if (prefs->omc_dev_opts & OMC_DEV_FORCE_RAW_MIDI) prefs->use_alsa_midi = FALSE;
1051   if (prefs->omc_dev_opts & OMC_DEV_MIDI_DUMMY) prefs->alsa_midi_dummy = TRUE;
1052 #endif
1053 
1054   prefs->midi_rcv_channel = get_int_prefd(PREF_MIDI_RCV_CHANNEL, MIDI_OMNI);
1055 
1056   mainw->ccpd_with_sound = TRUE;
1057   mainw->loop = TRUE;
1058   mainw->loop_cont = FALSE;
1059   mainw->fs = FALSE;
1060 
1061   if (prefs->vj_mode) {
1062     auto_recover = TRUE;
1063     mainw->loop_cont = TRUE;
1064     mainw->ccpd_with_sound = FALSE;
1065     prefs->sepwin_type = SEPWIN_TYPE_NON_STICKY;
1066     prefs->letterbox = FALSE;
1067     prefs->autoload_subs = FALSE;
1068     prefs->use_screen_gamma = TRUE;
1069     prefs->screen_gamma = 1.5;
1070   }
1071 
1072 #ifdef GUI_GTK
1073   mainw->target_table = target_table;
1074 #endif
1075 
1076   prefs->show_asrc = get_boolean_prefd(PREF_SHOW_ASRC, TRUE);
1077   prefs->hfbwnp = get_boolean_prefd(PREF_HFBWNP, FALSE);
1078 
1079   mainw->next_free_alarm = 0;
1080 
1081   for (i = 0; i < LIVES_MAX_ALARMS; i++) {
1082     mainw->alarms[i].lastcheck = 0;
1083   }
1084 
1085   if (lives_ascii_strcasecmp(prefs->theme, future_prefs->theme)) return TRUE;
1086   return FALSE;
1087 }
1088 
1089 
replace_with_delegates(void)1090 void replace_with_delegates(void) {
1091   weed_plant_t *filter;
1092 
1093   lives_rfx_t *rfx;
1094 
1095   int resize_fx;
1096   int deint_idx;
1097 
1098   if (mainw->fx_candidates[FX_CANDIDATE_RESIZER].delegate != -1) {
1099     resize_fx = LIVES_POINTER_TO_INT(lives_list_nth_data(mainw->fx_candidates[FX_CANDIDATE_RESIZER].list,
1100                                      mainw->fx_candidates[FX_CANDIDATE_RESIZER].delegate));
1101     filter = get_weed_filter(resize_fx);
1102     rfx = weed_to_rfx(filter, TRUE);
1103 
1104     rfx->is_template = FALSE;
1105     rfx->props |= RFX_PROPS_MAY_RESIZE;
1106 
1107     lives_free(rfx->action_desc);
1108     rfx->action_desc = (_("Resizing"));
1109 
1110     rfx->min_frames = 1;
1111 
1112     lives_free(rfx->menu_text);
1113 
1114     if (!mainw->resize_menuitem) {
1115       rfx->menu_text = (_("_Resize All Frames..."));
1116       mainw->resize_menuitem = lives_standard_menu_item_new_with_label(rfx->menu_text);
1117       lives_widget_show(mainw->resize_menuitem);
1118       lives_menu_shell_insert(LIVES_MENU_SHELL(mainw->tools_menu), mainw->resize_menuitem, RFX_TOOL_MENU_POSN);
1119     } else {
1120       // disconnect old menu entry
1121       lives_signal_handler_disconnect(mainw->resize_menuitem, mainw->fx_candidates[FX_CANDIDATE_RESIZER].func);
1122     }
1123     // connect new menu entry
1124     mainw->fx_candidates[FX_CANDIDATE_RESIZER].func = lives_signal_connect(LIVES_GUI_OBJECT(mainw->resize_menuitem),
1125         LIVES_WIDGET_ACTIVATE_SIGNAL,
1126         LIVES_GUI_CALLBACK(on_render_fx_pre_activate),
1127         (livespointer)rfx);
1128     mainw->fx_candidates[FX_CANDIDATE_RESIZER].rfx = rfx;
1129   }
1130 
1131   if (mainw->resize_menuitem) lives_widget_set_sensitive(mainw->resize_menuitem, CURRENT_CLIP_HAS_VIDEO);
1132 
1133   deint_idx = weed_get_idx_for_hashname("deinterlacedeinterlace", FALSE);
1134   if (deint_idx > -1) {
1135     mainw->fx_candidates[FX_CANDIDATE_DEINTERLACE].list
1136       = lives_list_append(mainw->fx_candidates[FX_CANDIDATE_DEINTERLACE].list,
1137                           LIVES_INT_TO_POINTER(deint_idx));
1138     mainw->fx_candidates[FX_CANDIDATE_DEINTERLACE].delegate = 0;
1139   }
1140 }
1141 
1142 
lives_init(_ign_opts * ign_opts)1143 static void lives_init(_ign_opts *ign_opts) {
1144   // init mainwindow data
1145   LiVESList *encoders = NULL;
1146   LiVESList *encoder_capabilities = NULL;
1147 
1148   char **array;
1149   char mppath[PATH_MAX];
1150 
1151   char *weed_plugin_path;
1152 #ifdef HAVE_FREI0R
1153   char *frei0r_path;
1154 #endif
1155 #ifdef HAVE_LADSPA
1156   char *ladspa_path;
1157 #endif
1158 #ifdef HAVE_LIBVISUAL
1159   char *libvis_path;
1160 #endif
1161   char *msg;
1162 
1163   boolean needs_free;
1164 
1165   int naudp = 0;
1166 
1167   int i;
1168 
1169   for (i = 0; i <= MAX_FILES; mainw->files[i++] = NULL);
1170   mainw->prefs_changed = FALSE;
1171   mainw->insert_after = TRUE;
1172   mainw->mute = FALSE;
1173   mainw->faded = FALSE;
1174   if (!prefs->vj_mode)
1175     mainw->save_with_sound = TRUE;   // also affects loading
1176   else
1177     mainw->save_with_sound = FALSE;
1178   mainw->preview = FALSE;
1179   mainw->selwidth_locked = FALSE;
1180   mainw->untitled_number = mainw->cap_number = 1;
1181   mainw->sel_start = 0;
1182   mainw->sel_move = SEL_MOVE_AUTO;
1183   mainw->record_foreign = FALSE;
1184   mainw->play_window = NULL;
1185   mainw->opwx = mainw->opwy = -1;
1186   mainw->frame_layer = NULL;
1187   mainw->in_fs_preview = FALSE;
1188   mainw->effects_paused = FALSE;
1189   mainw->play_start = 0;
1190   mainw->opening_loc = FALSE;
1191   mainw->toy_type = LIVES_TOY_NONE;
1192   mainw->framedraw = mainw->framedraw_spinbutton = NULL;
1193   mainw->fd_layer = NULL;
1194   mainw->fd_layer_orig = NULL;
1195   mainw->is_processing = FALSE;
1196   mainw->is_rendering = FALSE;
1197   mainw->is_generating = FALSE;
1198   mainw->resizing = FALSE;
1199   mainw->switch_during_pb = FALSE;
1200   mainw->playing_sel = FALSE;
1201   mainw->aframeno = 0;
1202   if (capable->byte_order == LIVES_LITTLE_ENDIAN) {
1203     mainw->endian = 0;
1204   } else {
1205     mainw->endian = AFORM_BIG_ENDIAN;
1206   }
1207 
1208   mainw->leave_files = FALSE;
1209   mainw->was_set = FALSE;
1210   mainw->toy_go_wild = FALSE;
1211 
1212   for (i = 0; i < FN_KEYS - 1; i++) {
1213     mainw->clipstore[i][0] = -1;
1214   }
1215 
1216   mainw->ping_pong = FALSE;
1217 
1218   mainw->nervous = FALSE;
1219   fx_dialog[0] = fx_dialog[1] = NULL;
1220 
1221   mainw->rte_keys = -1;
1222   rte_window = NULL;
1223 
1224   mainw->rte = EFFECT_NONE;
1225 
1226   mainw->preview_box = NULL;
1227   mainw->prv_link = PRV_PTR;
1228 
1229   mainw->internal_messaging = FALSE;
1230   mainw->progress_fn = NULL;
1231 
1232   mainw->last_grabbable_effect = -1;
1233   mainw->blend_file = -1;
1234 
1235   mainw->pre_src_file = -2;
1236   mainw->pre_src_audio_file = -1;
1237 
1238   mainw->size_warn = 0;
1239   mainw->dvgrab_preview = FALSE;
1240 
1241   mainw->file_open_params = NULL;
1242   mainw->whentostop = NEVER_STOP;
1243 
1244   mainw->audio_start = mainw->audio_end = 0;
1245   mainw->cliplist = NULL;
1246 
1247   // rendered_fx number of last transition
1248   mainw->last_transition_idx = -1;
1249   mainw->last_transition_loops = 1;
1250   mainw->last_transition_align_start = TRUE;
1251   mainw->last_transition_loop_to_fit = mainw->last_transition_ins_frames = FALSE;
1252   mainw->num_tr_applied = 0;
1253 
1254   mainw->blend_factor = 0.;
1255 
1256   mainw->fixed_fps_numer = -1;
1257   mainw->fixed_fps_denom = 1;
1258   mainw->fixed_fpsd = -1.;
1259   mainw->noswitch = mainw->cs_permitted = mainw->cs_is_permitted = FALSE;
1260   mainw->osc_block = FALSE;
1261 
1262   mainw->cancelled = CANCEL_NONE;
1263   mainw->cancel_type = CANCEL_KILL;
1264 
1265   mainw->framedraw_reset = NULL;
1266 
1267   // setting this to TRUE can possibly increase smoothness for lower framerates
1268   // needs more testing and a preference in prefs window- TODO
1269   // can also be set through OSC: /output/nodrop/enable
1270   prefs->noframedrop = get_boolean_prefd(PREF_NOFRAMEDROP, FALSE);
1271 
1272   prefs->omc_noisy = FALSE;
1273   prefs->omc_events = TRUE;
1274 
1275   if (!ign_opts->ign_osc) {
1276     prefs->osc_udp_started = FALSE;
1277     prefs->osc_udp_port = 0;
1278 #ifdef ENABLE_OSC
1279     if (!mainw->foreign) {
1280       prefs->osc_udp_port = get_int_prefd(PREF_OSC_PORT, DEF_OSC_LISTEN_PORT);
1281       future_prefs->osc_start = prefs->osc_start = get_boolean_prefd(PREF_OSC_START, FALSE);
1282     } else {
1283       future_prefs->osc_start = prefs->osc_start = FALSE;
1284     }
1285 #endif
1286   }
1287 
1288   prefs->fps_tolerance = .0005;
1289   prefs->rec_opts = get_int_prefd(PREF_RECORD_OPTS, -1);
1290 
1291   if (prefs->rec_opts == -1) {
1292     prefs->rec_opts = REC_FPS | REC_FRAMES | REC_EFFECTS | REC_CLIPS | REC_AUDIO;
1293     set_int_pref(PREF_RECORD_OPTS, prefs->rec_opts);
1294   }
1295 
1296   prefs->rec_opts |= (REC_FPS + REC_FRAMES);
1297 
1298   mainw->new_clip = -1;
1299   mainw->record = FALSE;
1300   mainw->event_list = NULL;
1301   mainw->clip_switched = FALSE;
1302   mainw->scrap_file = -1;
1303   mainw->ascrap_file = -1;
1304 
1305   mainw->jack_can_stop = FALSE;
1306   mainw->jack_can_start = TRUE;
1307 
1308   if (!mainw->foreign) mainw->video_seek_ready = mainw->audio_seek_ready = FALSE;
1309   else mainw->video_seek_ready = mainw->audio_seek_ready = TRUE;
1310 
1311   mainw->filter_map = NULL; // filter map for video rendering
1312   mainw->afilter_map = NULL; // filter map for audio rendering
1313   mainw->audio_event = NULL;
1314 
1315   mainw->did_rfx_preview = FALSE;
1316 
1317   prefsw = NULL;
1318   rdet = NULL;
1319   resaudw = NULL;
1320 
1321   mainw->actual_frame = 0;
1322 
1323   mainw->scratch = SCRATCH_NONE;
1324 
1325   mainw->clip_index = NULL;
1326   mainw->frame_index = NULL;
1327 
1328   mainw->affected_layouts_map = mainw->current_layouts_map = NULL;
1329 
1330   mainw->leave_recovery = TRUE;
1331 
1332   mainw->pchains = NULL;
1333 
1334   mainw->preview_frame = 0;
1335 
1336   mainw->unordered_blocks = FALSE;
1337 
1338   mainw->only_close = FALSE;
1339 
1340   mainw->no_exit = FALSE;
1341 
1342   mainw->multi_opts.set = FALSE;
1343 
1344   mainw->clip_header = NULL;
1345 
1346   mainw->new_blend_file = -1;
1347 
1348   mainw->jackd = mainw->jackd_read = NULL;
1349 
1350   mainw->pulsed = mainw->pulsed_read = NULL;
1351 
1352   mainw->show_procd = TRUE;
1353 
1354   mainw->framedraw_preview = mainw->framedraw_reset = NULL;
1355 
1356   mainw->block_param_updates = mainw->no_interp = FALSE;
1357 
1358   mainw->cevent_tc = 0;
1359 
1360   mainw->opening_multi = FALSE;
1361 
1362   mainw->img_concat_clip = -1;
1363 
1364   mainw->record_paused = mainw->record_starting = FALSE;
1365 
1366   mainw->gen_to_clipboard = FALSE;
1367 
1368   mainw->open_deint = FALSE;
1369 
1370   mainw->write_vpp_file = FALSE;
1371 
1372   mainw->stream_ticks = -1;
1373 
1374   mainw->keep_pre = FALSE;
1375 
1376   mainw->reverse_pb = FALSE;
1377 
1378   mainw->osc_auto = 0;
1379   mainw->osc_enc_width = mainw->osc_enc_height = 0;
1380 
1381   mainw->no_switch_dprint = FALSE;
1382 
1383   mainw->rte_textparm = NULL;
1384 
1385   mainw->abufs_to_fill = 0;
1386 
1387   mainw->recoverable_layout = mainw->recording_recovered = FALSE;
1388 
1389   mainw->iochan = NULL;
1390 
1391   mainw->stored_event_list = NULL;
1392   mainw->stored_event_list_changed = mainw->stored_event_list_auto_changed = FALSE;
1393   mainw->stored_layout_save_all_vals = TRUE;
1394 
1395   mainw->affected_layout_marks = NULL;
1396 
1397   mainw->stored_layout_undos = NULL;
1398   mainw->sl_undo_mem = NULL;
1399   mainw->sl_undo_buffer_used = 0;
1400   mainw->sl_undo_offset = 0;
1401 
1402   mainw->go_away = TRUE;
1403 
1404   mainw->aud_file_to_kill = -1;
1405 
1406   mainw->aud_rec_fd = -1;
1407 
1408   mainw->decoders_loaded = FALSE;
1409   mainw->decoder_list = NULL;
1410 
1411   mainw->subt_save_file = NULL;
1412 
1413   mainw->fonts_array = get_font_list();
1414 
1415   mainw->nfonts = 0;
1416   if (mainw->fonts_array)
1417     while (mainw->fonts_array[mainw->nfonts++]);
1418 
1419   mainw->videodevs = NULL;
1420 
1421   mainw->camframe = NULL;
1422 
1423   mainw->has_custom_effects = FALSE;
1424   mainw->has_custom_tools = FALSE;
1425   mainw->has_custom_gens = FALSE;
1426   mainw->has_custom_utilities = FALSE;
1427 
1428   mainw->log_fd = -2;
1429 
1430   mainw->last_display_ticks = 0;
1431 
1432   mainw->alives_pgid = 0;
1433 
1434   mainw->aplayer_broken = FALSE;
1435 
1436   mainw->render_error = LIVES_RENDER_ERROR_NONE;
1437 
1438   mainw->add_clear_ds_button = FALSE;
1439   mainw->add_clear_ds_adv = FALSE;
1440   mainw->tried_ds_recover = FALSE;
1441 
1442   mainw->foreign_visual = NULL;
1443 
1444   mainw->pconx = NULL;
1445   mainw->cconx = NULL;
1446 
1447   cached_key = cached_mod = 0;
1448 
1449   mainw->agen_key = 0;
1450   mainw->agen_needs_reinit = FALSE;
1451   mainw->agen_samps_count = 0;
1452 
1453   mainw->ce_frame_height = mainw->ce_frame_width = -1;
1454 
1455   mainw->cursor_style = LIVES_CURSOR_NORMAL;
1456 
1457   mainw->sepwin_minwidth = MIN_SEPWIN_WIDTH;
1458   mainw->sepwin_minheight = PREVIEW_BOX_HT;
1459 
1460   mainw->signal_caught = 0;
1461   mainw->signals_deferred = FALSE;
1462 
1463   mainw->n_screen_areas = SCREEN_AREA_USER_DEFINED1;
1464   mainw->screen_areas = (lives_screen_area_t *)lives_malloc(mainw->n_screen_areas * sizeof(lives_screen_area_t));
1465   mainw->screen_areas[SCREEN_AREA_FOREGROUND].name = (_("Foreground"));
1466   mainw->screen_areas[SCREEN_AREA_BACKGROUND].name = (_("Background"));
1467 
1468   mainw->active_sa_clips = mainw->active_sa_fx = SCREEN_AREA_FOREGROUND;
1469 
1470   mainw->file_buffers = NULL;
1471 
1472   mainw->blend_layer = NULL;
1473 
1474   mainw->ce_upd_clip = FALSE;
1475 
1476   mainw->clips_group = NULL;
1477 
1478   mainw->fx_is_auto = FALSE;
1479   mainw->gen_started_play = FALSE;
1480 
1481   mainw->audio_frame_buffer = NULL;
1482   mainw->afbuffer_clients = mainw->afbuffer_clients_read = 0;
1483   mainw->afb[0] = mainw->afb[1] = NULL;
1484 
1485   lives_memset(mainw->recent_file, 0, 1);
1486 
1487   mainw->aud_data_written = 0;
1488 
1489   mainw->rendered_fx = NULL;
1490 
1491   mainw->midi_channel_lock = FALSE;
1492 
1493   mainw->crash_possible = 0;
1494 
1495   mainw->scrap_pixbuf = NULL;
1496 
1497   mainw->close_keep_frames = FALSE;
1498 
1499 #ifdef ENABLE_JACK
1500   mainw->jack_inited = FALSE;
1501   mainw->jack_trans_poll = FALSE;
1502 #endif
1503 
1504   mainw->recovering_files = FALSE;
1505 
1506   mainw->num_rendered_effects_builtin = mainw->num_rendered_effects_custom = mainw->num_rendered_effects_test = 0;
1507 
1508   mainw->flush_audio_tc = 0;
1509 
1510   mainw->idlemax = 0;
1511   mainw->reconfig = FALSE;
1512 
1513   mainw->fsp_func = 0;
1514 
1515   mainw->swapped_clip = -1;
1516 
1517   mainw->urgency_msg = mainw->overlay_msg = NULL;
1518 
1519   mainw->xlays = NULL;
1520 
1521   mainw->preview_rendering = FALSE;
1522 
1523   mainw->new_lmap_errors = NULL;
1524 
1525   mainw->ncbstores = 0;
1526 
1527   mainw->loop_locked = FALSE;
1528 
1529   mainw->invalid_clips = FALSE;
1530 
1531   mainw->blend_palette = WEED_PALETTE_END;
1532   mainw->blend_width = mainw->blend_height = 0;
1533 
1534   mainw->force_show = FALSE;
1535 
1536   mainw->effort = 0;
1537 
1538   mainw->frame_layer_preload = NULL;
1539   mainw->pred_frame = 0;
1540   mainw->pred_clip = 0;
1541 
1542   mainw->lockstats = FALSE;
1543 
1544   mainw->audio_stretch = 1.0;
1545 
1546   mainw->play_sequence = 0;
1547 
1548   mainw->record_frame = -1;
1549 
1550   mainw->debug_ptr = NULL;
1551 
1552   mainw->inst_fps = 0.;
1553 
1554   mainw->pre_play_file = -1;
1555 
1556   mainw->st_fcache = mainw->en_fcache = mainw->pr_fcache = NULL;
1557 
1558   mainw->ptrtime = 0.;
1559 
1560   mainw->proc_ptr = NULL;
1561 
1562   mainw->permmgr = NULL;
1563 
1564   mainw->set_list = NULL;
1565   mainw->num_sets = -1;
1566 
1567   mainw->mt_needs_idlefunc = FALSE;
1568 
1569   mainw->suppress_layout_warnings = FALSE;
1570 
1571   mainw->add_trash_rb = FALSE;
1572 
1573   mainw->cs_manage = FALSE;
1574 
1575   mainw->dsu_valid = FALSE;
1576   mainw->dsu_widget = NULL;
1577 
1578   mainw->drawsrc = -1;
1579 
1580   mainw->lazy = 0;
1581 
1582   mainw->disk_mon = 0;
1583 
1584   mainw->wall_ticks = -1;
1585 
1586   /////////////////////////////////////////////////// add new stuff just above here ^^
1587 
1588   lives_memset(mainw->set_name, 0, 1);
1589   mainw->clips_available = 0;
1590 
1591   prefs->pause_effect_during_preview = FALSE;
1592 
1593   future_prefs->pb_quality = prefs->pb_quality = get_int_prefd(PREF_PB_QUALITY, PB_QUALITY_MED);
1594   if (prefs->pb_quality != PB_QUALITY_LOW && prefs->pb_quality != PB_QUALITY_HIGH &&
1595       prefs->pb_quality != PB_QUALITY_MED) prefs->pb_quality = PB_QUALITY_MED;
1596 
1597   prefs->pbq_adaptive = get_boolean_prefd(PREF_PBQ_ADAPTIVE, TRUE);
1598 
1599   mainw->ext_playback = mainw->ext_audio = FALSE;
1600 
1601   prefs->loop_recording = TRUE;
1602   prefs->no_bandwidth = FALSE;
1603   prefs->ocp = get_int_prefd(PREF_OPEN_COMPRESSION_PERCENT, 15);
1604 
1605   prefs->stop_screensaver = get_boolean_prefd(PREF_STOP_SCREENSAVER, TRUE);
1606   prefs->show_tool = get_boolean_prefd(PREF_SHOW_TOOLBAR, TRUE);
1607 
1608   if (prefs->gui_monitor != 0) {
1609     lives_window_center(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
1610   }
1611 
1612   prefs->default_fps = get_double_prefd(PREF_DEFAULT_FPS, DEF_FPS);
1613   if (prefs->default_fps < 1.) prefs->default_fps = 1.;
1614   if (prefs->default_fps > FPS_MAX) prefs->default_fps = FPS_MAX;
1615 
1616   // values for trickplay
1617   prefs->blendchange_amount = get_double_prefd(PREF_BLEND_AMOUNT, DEF_BLENDCHANGE_AMOUNT);
1618   prefs->scratchfwd_amount  = get_int_prefd(PREF_SCFWD_AMOUNT, DEF_SCRATCHFWD_AMOUNT);
1619   prefs->scratchback_amount = get_int_prefd(PREF_SCBACK_AMOUNT, DEF_SCRATCHBACK_AMOUNT);
1620   prefs->fpschange_amount   = get_double_prefd(PREF_FPSCHANGE_AMOUNT, DEF_FPSCHANGE_AMOUNT);
1621 
1622   prefs->q_type = Q_SMOOTH;
1623 
1624   prefs->event_window_show_frame_events = FALSE;
1625   if (!mainw->foreign) prefs->crash_recovery = TRUE;
1626   else prefs->crash_recovery = FALSE;
1627 
1628   prefs->acodec_list = NULL;
1629 
1630   prefs->render_audio = TRUE;
1631   prefs->normalise_audio = TRUE;
1632 
1633   prefs->num_rtaudiobufs = 4;
1634 
1635   prefs->safe_symlinks = FALSE; // set to TRUE for dynebolic and other live CDs
1636 
1637   prefs->ce_maxspect = get_boolean_prefd(PREF_CE_MAXSPECT, TRUE);
1638 
1639   prefs->rec_stop_gb = get_double_prefd(PREF_REC_STOP_GB, DEF_REC_STOP_GB);
1640 
1641   if (prefs->max_modes_per_key == 0) prefs->max_modes_per_key = atoi(DEF_FX_KEYMODES);
1642 
1643   prefs->stream_audio_out = get_boolean_pref(PREF_STREAM_AUDIO_OUT);
1644 
1645   prefs->unstable_fx = get_boolean_prefd(PREF_UNSTABLE_FX, TRUE);
1646 
1647   prefs->disabled_decoders = get_list_pref(PREF_DISABLED_DECODERS);
1648 
1649   prefs->enc_letterbox = FALSE;
1650 
1651   prefs->clear_disk_opts = get_int_prefd(PREF_CLEAR_DISK_OPTS, 0);
1652 
1653   prefs->force_system_clock = TRUE;
1654 
1655   prefs->alpha_post = FALSE; ///< allow pre-multiplied alpha internally
1656 
1657   prefs->auto_trim_audio = get_boolean_prefd(PREF_AUTO_TRIM_PAD_AUDIO, TRUE);
1658   prefs->keep_all_audio = get_boolean_prefd(PREF_KEEP_ALL_AUDIO, FALSE);
1659 
1660   prefs->force64bit = FALSE;
1661 
1662 #if LIVES_HAS_GRID_WIDGET
1663   prefs->ce_thumb_mode = get_boolean_prefd(PREF_CE_THUMB_MODE, FALSE);
1664 #else
1665   prefs->ce_thumb_mode = FALSE;
1666 #endif
1667 
1668   prefs->push_audio_to_gens = get_boolean_prefd(PREF_PUSH_AUDIO_TO_GENS, TRUE);
1669 
1670   prefs->perm_audio_reader = TRUE;
1671 
1672   prefs->max_disp_vtracks = get_int_prefd(PREF_MAX_DISP_VTRACKS, DEF_MT_DISP_TRACKS);
1673 
1674   prefs->mt_load_fuzzy = FALSE;
1675 
1676   prefs->ahold_threshold = get_double_pref(PREF_AHOLD_THRESHOLD);
1677 
1678   prefs->use_screen_gamma = get_boolean_prefd(PREF_USE_SCREEN_GAMMA, FALSE);
1679   prefs->screen_gamma = get_double_prefd(PREF_SCREEN_GAMMA, DEF_SCREEN_GAMMA);
1680   prefs->apply_gamma = get_boolean_prefd(PREF_APPLY_GAMMA, TRUE);
1681   prefs->btgamma = FALSE;
1682 
1683   prefs->msgs_pbdis = get_boolean_prefd(PREF_MSG_PBDIS, TRUE);
1684 
1685   prefs->cb_is_switch = FALSE;
1686 
1687   prefs->autoclean = get_boolean_prefd(PREF_AUTOCLEAN_TRASH, TRUE);
1688 
1689   future_prefs->pref_trash = prefs->pref_trash = get_boolean_prefd(PREF_PREF_TRASH, FALSE);
1690 
1691   // get window manager capabilities
1692 #ifdef GDK_WINDOWING_WAYLAND
1693   if (GDK_IS_WAYLAND_DISPLAY(mainw->mgeom[0].disp))
1694     capable->wm_name = lives_strdup("Wayland");
1695 #endif
1696 #ifdef GDK_WINDOWING_X11
1697   if (GDK_IS_X11_DISPLAY(mainw->mgeom[0].disp))
1698     capable->wm_name = lives_strdup(gdk_x11_screen_get_window_manager_name(gdk_screen_get_default()));
1699 #endif
1700 
1701   *capable->wm_caps.wm_name = 0;
1702   capable->has_wm_caps = FALSE;
1703   get_wm_caps();
1704 
1705   if (*capable->wm_caps.panel)
1706     prefs->show_desktop_panel = get_x11_visible(capable->wm_caps.panel);
1707   //prefs->show_desktop_panel = TRUE;
1708 
1709   prefs->show_msgs_on_startup = get_boolean_prefd(PREF_MSG_START, TRUE);
1710 
1711   /// record rendering options
1712   prefs->rr_crash = get_boolean_prefd(PREF_RRCRASH, TRUE);
1713   prefs->rr_super = get_boolean_prefd(PREF_RRSUPER, TRUE);
1714   prefs->rr_pre_smooth = get_boolean_prefd(PREF_RRPRESMOOTH, TRUE);
1715   prefs->rr_qsmooth = get_boolean_prefd(PREF_RRQSMOOTH, TRUE);
1716   prefs->rr_amicro = get_boolean_prefd(PREF_RRAMICRO, TRUE);
1717   prefs->rr_ramicro = get_boolean_prefd(PREF_RRRAMICRO, TRUE);
1718 
1719   prefs->rr_qmode = get_int_prefd(PREF_RRQMODE, 0);
1720   prefs->rr_qmode = INT_CLAMP(prefs->rr_qmode, 0, 1);
1721   prefs->rr_fstate = get_int_prefd(PREF_RRFSTATE, 0);
1722   prefs->rr_fstate = INT_CLAMP(prefs->rr_fstate, 0, 1);
1723 
1724   /// new prefs here:
1725   //////////////////////////////////////////////////////////////////
1726 
1727   get_string_prefd(PREF_DEF_AUTHOR, prefs->def_author, 1024, "");
1728 
1729   if (!mainw->foreign) {
1730     prefs->midi_check_rate = get_int_pref(PREF_MIDI_CHECK_RATE);
1731     if (prefs->midi_check_rate == 0) prefs->midi_check_rate = DEF_MIDI_CHECK_RATE;
1732 
1733     if (prefs->midi_check_rate < 1) prefs->midi_check_rate = 1;
1734 
1735     prefs->midi_rpt = get_int_pref(PREF_MIDI_RPT);
1736     if (prefs->midi_rpt == 0) prefs->midi_rpt = DEF_MIDI_RPT;
1737 
1738     prefs->mouse_scroll_clips = get_boolean_prefd(PREF_MOUSE_SCROLL_CLIPS, TRUE);
1739 
1740     prefs->mt_auto_back = get_int_prefd(PREF_MT_AUTO_BACK, 120);
1741 
1742     get_string_pref(PREF_VIDEO_OPEN_COMMAND, prefs->video_open_command, PATH_MAX * 2);
1743 
1744     if (!*prefs->video_open_command) {
1745       lives_memset(mppath, 0, 1);
1746 
1747       if (!(*prefs->video_open_command) && capable->has_mplayer) {
1748         get_location(EXEC_MPLAYER, mppath, PATH_MAX);
1749       }
1750 
1751       if (!(*prefs->video_open_command) && capable->has_mplayer2) {
1752         get_location(EXEC_MPLAYER2, mppath, PATH_MAX);
1753       }
1754 
1755       if (!(*prefs->video_open_command) && capable->has_mpv) {
1756         get_location(EXEC_MPV, mppath, PATH_MAX);
1757       }
1758 
1759       if (*mppath) {
1760         lives_snprintf(prefs->video_open_command, PATH_MAX + 2, "\"%s\"", mppath);
1761         set_string_pref(PREF_VIDEO_OPEN_COMMAND, prefs->video_open_command);
1762       }
1763     }
1764 
1765     prefs->warn_file_size = get_int_prefd(PREF_WARN_FILE_SIZE, WARN_FILE_SIZE);
1766 
1767     prefs->show_rdet = TRUE;
1768     prefs->move_effects = TRUE;
1769     prefs->mt_undo_buf = get_int_prefd(PREF_MT_UNDO_BUF, DEF_MT_UNDO_SIZE);
1770     prefs->mt_enter_prompt = get_boolean_prefd(PREF_MT_ENTER_PROMPT, TRUE);
1771 
1772     // default frame sizes (TODO - allow pref)
1773     mainw->def_width = DEF_FRAME_HSIZE;
1774     mainw->def_height = DEF_FRAME_HSIZE;
1775 
1776     prefs->mt_def_width = get_int_prefd(PREF_MT_DEF_WIDTH, DEF_FRAME_HSIZE_UNSCALED);
1777     prefs->mt_def_height = get_int_prefd(PREF_MT_DEF_HEIGHT, DEF_FRAME_VSIZE_UNSCALED);
1778     prefs->mt_def_fps = get_double_prefd(PREF_MT_DEF_FPS, prefs->default_fps);
1779     prefs->mt_def_arate = get_int_prefd(PREF_MT_DEF_ARATE, DEFAULT_AUDIO_RATE);
1780     prefs->mt_def_achans = get_int_prefd(PREF_MT_DEF_ACHANS, DEFAULT_AUDIO_CHANS);
1781     prefs->mt_def_asamps = get_int_prefd(PREF_MT_DEF_ASAMPS, DEFAULT_AUDIO_SAMPS);
1782     prefs->mt_def_signed_endian = get_int_prefd(PREF_MT_DEF_SIGNED_ENDIAN, (capable->byte_order == LIVES_BIG_ENDIAN)
1783                                   ? 2 : 0 + ((prefs->mt_def_asamps == 8) ? 1 : 0));
1784 
1785     prefs->mt_exit_render = get_boolean_prefd(PREF_MT_EXIT_RENDER, TRUE);
1786     prefs->render_prompt = get_boolean_prefd(PREF_RENDER_PROMPT, TRUE);
1787 
1788     prefs->mt_pertrack_audio = get_boolean_prefd(PREF_MT_PERTRACK_AUDIO, TRUE);
1789     prefs->mt_backaudio = get_int_prefd(PREF_MT_BACKAUDIO, 1);
1790 
1791     prefs->instant_open = get_boolean_prefd(PREF_INSTANT_OPEN, TRUE);
1792     prefs->auto_deint = get_boolean_prefd(PREF_AUTO_DEINTERLACE, TRUE);
1793     prefs->auto_nobord = get_boolean_prefd(PREF_AUTO_CUT_BORDERS, FALSE);
1794 
1795     future_prefs->ar_clipset = FALSE;
1796 
1797     if (!ign_opts->ign_clipset) {
1798       get_string_prefd(PREF_AR_CLIPSET, prefs->ar_clipset_name, 128, "");
1799       if (*prefs->ar_clipset_name) future_prefs->ar_clipset = prefs->ar_clipset = TRUE;
1800       else prefs->ar_clipset = FALSE;
1801     } else set_string_pref(PREF_AR_CLIPSET, "");
1802 
1803     if (!ign_opts->ign_layout) {
1804       get_string_prefd(PREF_AR_LAYOUT, prefs->ar_layout_name, PATH_MAX, "");
1805       if (*prefs->ar_layout_name) prefs->ar_layout = TRUE;
1806       else prefs->ar_layout = FALSE;
1807     } else set_string_pref(PREF_AR_LAYOUT, "");
1808 
1809     prefs->rec_desktop_audio = get_boolean_prefd(PREF_REC_DESKTOP_AUDIO, FALSE);
1810 
1811     future_prefs->startup_interface = get_int_prefd(PREF_STARTUP_INTERFACE, STARTUP_CE);
1812     if (!ign_opts->ign_stmode) {
1813       prefs->startup_interface = future_prefs->startup_interface;
1814     }
1815 
1816     // scan for encoder plugins
1817     if ((encoders = get_plugin_list(PLUGIN_ENCODERS, FALSE, NULL, NULL)) != NULL) {
1818       capable->has_encoder_plugins = TRUE;
1819       lives_list_free_all(&encoders);
1820     }
1821 
1822     lives_memset(prefs->encoder.of_name, 0, 1);
1823     lives_memset(prefs->encoder.of_desc, 0, 1);
1824 
1825     if ((prefs->startup_phase == 1 || prefs->startup_phase == -1) && capable->has_encoder_plugins && capable->has_python) {
1826       LiVESList *ofmt_all = NULL;
1827       char **array;
1828       if (check_for_executable(&capable->has_ffmpeg, EXEC_FFMPEG)) {
1829         lives_snprintf(prefs->encoder.name, 64, "%s", FFMPEG_ENCODER_NAME);
1830       } else {
1831         if (capable->python_version >= 3000000)
1832           lives_snprintf(prefs->encoder.name, 64, "%s", MULTI_ENCODER3_NAME);
1833         else
1834           lives_snprintf(prefs->encoder.name, 64, "%s", MULTI_ENCODER_NAME);
1835       }
1836       // need to change the output format
1837 
1838       if ((ofmt_all = plugin_request_by_line(PLUGIN_ENCODERS, prefs->encoder.name, "get_formats")) != NULL) {
1839         set_string_pref(PREF_ENCODER, prefs->encoder.name);
1840 
1841         for (i = 0; i < lives_list_length(ofmt_all); i++) {
1842           if (get_token_count((char *)lives_list_nth_data(ofmt_all, i), '|') > 2) {
1843             array = lives_strsplit((char *)lives_list_nth_data(ofmt_all, i), "|", -1);
1844 
1845             if (!strcmp(array[0], HI_THEORA_FORMAT)) {
1846               lives_snprintf(prefs->encoder.of_name, 64, "%s", array[0]);
1847               lives_strfreev(array);
1848               break;
1849             }
1850             if (!strcmp(array[0], HI_MPEG_FORMAT)) {
1851               lives_snprintf(prefs->encoder.of_name, 64, "%s", array[0]);
1852             } else if (!strcmp(array[0], HI_H_MKV_FORMAT) && strcmp(prefs->encoder.of_name, HI_MPEG_FORMAT)) {
1853               lives_snprintf(prefs->encoder.of_name, 64, "%s", array[0]);
1854             } else if (!strcmp(array[0], HI_H_AVI_FORMAT) && strcmp(prefs->encoder.of_name, HI_MPEG_FORMAT) &&
1855                        strcmp(prefs->encoder.of_name, HI_H_MKV_FORMAT)) {
1856               lives_snprintf(prefs->encoder.of_name, 64, "%s", array[0]);
1857             } else if (!(*prefs->encoder.of_name)) {
1858               lives_snprintf(prefs->encoder.of_name, 64, "%s", array[0]);
1859             }
1860 
1861             lives_strfreev(array);
1862           }
1863         }
1864 
1865         set_string_pref(PREF_OUTPUT_TYPE, prefs->encoder.of_name);
1866 
1867         lives_list_free_all(&ofmt_all);
1868       }
1869     }
1870 
1871     if (!(*prefs->encoder.of_name)) {
1872       get_string_pref(PREF_ENCODER, prefs->encoder.name, 64);
1873       get_string_pref(PREF_OUTPUT_TYPE, prefs->encoder.of_name, 64);
1874     }
1875 
1876     future_prefs->encoder.audio_codec = prefs->encoder.audio_codec = get_int_prefd(PREF_ENCODER_ACODEC, -1);
1877     prefs->encoder.capabilities = 0;
1878     prefs->encoder.of_allowed_acodecs = AUDIO_CODEC_UNKNOWN;
1879 
1880     lives_snprintf(future_prefs->encoder.name, 64, "%s", prefs->encoder.name);
1881 
1882     lives_memset(future_prefs->encoder.of_restrict, 0, 1);
1883     lives_memset(prefs->encoder.of_restrict, 0, 1);
1884 
1885     if (capable->has_encoder_plugins) {
1886       char **array;
1887       int numtok;
1888       LiVESList *ofmt_all, *dummy_list;
1889 
1890       dummy_list = plugin_request("encoders", prefs->encoder.name, "init");
1891       lives_list_free_all(&dummy_list);
1892 
1893       if (((encoder_capabilities = plugin_request(PLUGIN_ENCODERS, prefs->encoder.name, "get_capabilities")) != NULL)) {
1894         prefs->encoder.capabilities = atoi((char *)lives_list_nth_data(encoder_capabilities, 0));
1895         lives_list_free_all(&encoder_capabilities);
1896         if ((ofmt_all = plugin_request_by_line(PLUGIN_ENCODERS, prefs->encoder.name, "get_formats")) != NULL) {
1897           // get any restrictions for the current format
1898           LiVESList *list = ofmt_all;
1899           while (list) {
1900             if ((numtok = get_token_count((char *)list->data, '|')) > 2) {
1901               array = lives_strsplit((char *)list->data, "|", -1);
1902               if (!strcmp(array[0], prefs->encoder.of_name)) {
1903                 if (numtok > 1) {
1904                   lives_snprintf(prefs->encoder.of_desc, 128, "%s", array[1]);
1905                 }
1906                 lives_strfreev(array);
1907                 break;
1908               }
1909               lives_strfreev(array);
1910             }
1911             list = list->next;
1912           }
1913           lives_list_free_all(&ofmt_all);
1914         }
1915       }
1916     }
1917 
1918     get_utf8_pref(PREF_VID_LOAD_DIR, prefs->def_vid_load_dir, PATH_MAX);
1919     if (!(*prefs->def_vid_load_dir)) {
1920 #ifdef USE_GLIB
1921 #if GLIB_CHECK_VERSION(2, 14, 0)
1922       lives_snprintf(prefs->def_vid_load_dir, PATH_MAX, "%s", g_get_user_special_dir(G_USER_DIRECTORY_VIDEOS));
1923 #else
1924       lives_snprintf(prefs->def_vid_load_dir, PATH_MAX, "%s", capable->home_dir);
1925 #endif
1926 #endif
1927       set_utf8_pref(PREF_VID_LOAD_DIR, prefs->def_vid_load_dir);
1928     }
1929     lives_snprintf(mainw->vid_load_dir, PATH_MAX, "%s", prefs->def_vid_load_dir);
1930     ensure_isdir(mainw->vid_load_dir);
1931 
1932     get_utf8_pref(PREF_VID_SAVE_DIR, prefs->def_vid_save_dir, PATH_MAX);
1933     if (!(*prefs->def_vid_save_dir)) {
1934 #ifdef USE_GLIB
1935 #if GLIB_CHECK_VERSION(2, 14, 0)
1936       lives_snprintf(prefs->def_vid_save_dir, PATH_MAX, "%s", g_get_user_special_dir(G_USER_DIRECTORY_VIDEOS));
1937 #else
1938       lives_snprintf(prefs->def_vid_save_dir, PATH_MAX, "%s", capable->home_dir);
1939 #endif
1940 #endif
1941       set_utf8_pref(PREF_VID_SAVE_DIR, prefs->def_vid_save_dir);
1942     }
1943     lives_snprintf(mainw->vid_save_dir, PATH_MAX, "%s", prefs->def_vid_save_dir);
1944     ensure_isdir(mainw->vid_save_dir);
1945 
1946     lives_snprintf(mainw->vid_dl_dir, PATH_MAX, "%s", mainw->vid_save_dir);
1947 
1948     get_utf8_pref(PREF_AUDIO_DIR, prefs->def_audio_dir, PATH_MAX);
1949     if (!(*prefs->def_audio_dir)) {
1950 #ifdef USE_GLIB
1951 #if GLIB_CHECK_VERSION(2, 14, 0)
1952       lives_snprintf(prefs->def_audio_dir, PATH_MAX, "%s", g_get_user_special_dir(G_USER_DIRECTORY_MUSIC));
1953 #else
1954       lives_snprintf(prefs->def_audio_dir, PATH_MAX, "%s", capable->home_dir);
1955 #endif
1956 #endif
1957       set_utf8_pref(PREF_AUDIO_DIR, prefs->def_audio_dir);
1958     }
1959     lives_snprintf(mainw->audio_dir, PATH_MAX, "%s", prefs->def_audio_dir);
1960     ensure_isdir(mainw->audio_dir);
1961 
1962     get_utf8_pref(PREF_IMAGE_DIR, prefs->def_image_dir, PATH_MAX);
1963     if (!(*prefs->def_image_dir)) {
1964 #ifdef USE_GLIB
1965 #if GLIB_CHECK_VERSION(2, 14, 0)
1966       lives_snprintf(prefs->def_image_dir, PATH_MAX, "%s", g_get_user_special_dir(G_USER_DIRECTORY_PICTURES));
1967 #else
1968       lives_snprintf(prefs->def_image_dir, PATH_MAX, "%s", capable->home_dir);
1969 #endif
1970 #endif
1971       set_utf8_pref(PREF_IMAGE_DIR, prefs->def_image_dir);
1972     }
1973     lives_snprintf(mainw->image_dir, PATH_MAX, "%s", prefs->def_image_dir);
1974     ensure_isdir(mainw->image_dir);
1975 
1976     get_utf8_pref(PREF_PROJ_DIR, prefs->def_proj_dir, PATH_MAX);
1977     if (!(*prefs->def_proj_dir)) {
1978       lives_snprintf(prefs->def_proj_dir, PATH_MAX, "%s", capable->home_dir);
1979       set_utf8_pref(PREF_PROJ_DIR, prefs->def_proj_dir);
1980     }
1981     lives_snprintf(mainw->proj_load_dir, PATH_MAX, "%s", prefs->def_proj_dir);
1982     ensure_isdir(mainw->proj_load_dir);
1983     lives_snprintf(mainw->proj_save_dir, PATH_MAX, "%s", mainw->proj_load_dir);
1984 
1985     prefs->show_player_stats = get_boolean_prefd(PREF_SHOW_PLAYER_STATS, FALSE);
1986 
1987     prefs->dl_bandwidth = get_int_prefd(PREF_DL_BANDWIDTH_K, DEF_DL_BANDWIDTH);
1988     prefs->fileselmax = get_boolean_prefd(PREF_FILESEL_MAXIMISED, TRUE);
1989 
1990     prefs->midisynch = get_boolean_prefd(PREF_MIDISYNCH, FALSE);
1991     if (prefs->midisynch && !capable->has_midistartstop) {
1992       set_boolean_pref(PREF_MIDISYNCH, FALSE);
1993       prefs->midisynch = FALSE;
1994     }
1995 
1996     prefs->discard_tv = FALSE;
1997 
1998     // conserve disk space ?
1999     prefs->conserve_space = get_boolean_prefd(PREF_CONSERVE_SPACE, FALSE);
2000     prefs->ins_resample = get_boolean_prefd(PREF_INSERT_RESAMPLE, TRUE);
2001 
2002     // need better control of audio channels first
2003     prefs->pause_during_pb = FALSE;
2004 
2005     // should we always use the last directory ?
2006     // TODO - add to GUI
2007     prefs->save_directories = get_boolean_prefd(PREF_SAVE_DIRECTORIES, FALSE);
2008     prefs->antialias = get_boolean_prefd(PREF_ANTIALIAS, TRUE);
2009 
2010     prefs->concat_images = get_boolean_prefd(PREF_CONCAT_IMAGES, TRUE);
2011 
2012     prefs->fxdefsfile = NULL;
2013     prefs->fxsizesfile = NULL;
2014 
2015     if (!needs_workdir && initial_startup_phase == 0) {
2016       disk_monitor_start(prefs->workdir);
2017     }
2018 
2019     // anything that d_prints messages should go here:
2020     do_start_messages();
2021 
2022     needs_free = FALSE;
2023     get_string_pref(PREF_WEED_PLUGIN_PATH, prefs->weed_plugin_path, PATH_MAX);
2024     if (!*prefs->weed_plugin_path) {
2025       weed_plugin_path = getenv("WEED_PLUGIN_PATH");
2026       if (!weed_plugin_path) {
2027         weed_plugin_path = lives_build_path(prefs->lib_dir, PLUGIN_EXEC_DIR,
2028                                             PLUGIN_WEED_FX_BUILTIN, NULL);
2029         needs_free = TRUE;
2030       }
2031       lives_snprintf(prefs->weed_plugin_path, PATH_MAX, "%s", weed_plugin_path);
2032       if (needs_free) lives_free(weed_plugin_path);
2033       set_string_pref(PREF_WEED_PLUGIN_PATH, prefs->weed_plugin_path);
2034     }
2035     lives_setenv("WEED_PLUGIN_PATH", prefs->weed_plugin_path);
2036 
2037 #ifdef HAVE_FREI0R
2038     needs_free = FALSE;
2039     get_string_pref(PREF_FREI0R_PATH, prefs->frei0r_path, PATH_MAX);
2040     if (!*prefs->frei0r_path) {
2041       frei0r_path = getenv("FREI0R_PATH");
2042       if (!frei0r_path) {
2043         frei0r_path =
2044           lives_strdup_printf("/usr/lib/frei0r-1:/usr/local/lib/frei0r-1:%s/frei0r-1",
2045                               capable->home_dir);
2046         needs_free = TRUE;
2047       }
2048       lives_snprintf(prefs->frei0r_path, PATH_MAX, "%s", frei0r_path);
2049       if (needs_free) lives_free(frei0r_path);
2050       set_string_pref(PREF_FREI0R_PATH, prefs->frei0r_path);
2051     }
2052     lives_setenv("FREI0R_PATH", prefs->frei0r_path);
2053 #endif
2054 
2055 #if HAVE_LADSPA
2056     needs_free = FALSE;
2057     get_string_pref(PREF_LADSPA_PATH, prefs->ladspa_path, PATH_MAX);
2058     if (!*prefs->ladspa_path) {
2059       ladspa_path = getenv("LADSPA_PATH");
2060       if (!ladspa_path) {
2061         ladspa_path = lives_build_path(prefs->lib_dir, "ladspa", NULL);
2062         needs_free = TRUE;
2063       }
2064       lives_snprintf(prefs->ladspa_path, PATH_MAX, "%s", ladspa_path);
2065       if (needs_free) lives_free(ladspa_path);
2066       set_string_pref(PREF_LADSPA_PATH, prefs->ladspa_path);
2067     }
2068     lives_setenv("LADSPA_PATH", prefs->ladspa_path);
2069 #endif
2070 
2071 #if HAVE_LIBVISUAL
2072     needs_free = FALSE;
2073     get_string_pref(PREF_LIBVISUAL_PATH, prefs->libvis_path, PATH_MAX);
2074     if (!*prefs->libvis_path) {
2075       libvis_path = getenv("VISUAL_PLUGIN_PATH");
2076       if (!libvis_path) {
2077         libvis_path = "";
2078       }
2079       lives_snprintf(prefs->libvis_path, PATH_MAX, "%s", libvis_path);
2080       set_string_pref(PREF_LIBVISUAL_PATH, prefs->libvis_path);
2081     }
2082     lives_setenv("VISUAL_PLUGIN_PATH", prefs->libvis_path);
2083 #endif
2084 
2085     splash_msg(_("Loading realtime effect plugins..."), SPLASH_LEVEL_LOAD_RTE);
2086     weed_load_all();
2087 
2088     // replace any multi choice effects with their delegates
2089     replace_with_delegates();
2090 
2091     threaded_dialog_spin(0.);
2092     load_default_keymap();
2093     threaded_dialog_spin(0.);
2094 
2095     future_prefs->audio_opts = prefs->audio_opts = get_int_prefd(PREF_AUDIO_OPTS, 3);
2096 
2097 #ifdef ENABLE_JACK
2098     lives_snprintf(prefs->jack_aserver, PATH_MAX, "%s/.jackdrc", capable->home_dir);
2099     lives_snprintf(prefs->jack_tserver, PATH_MAX, "%s/.jackdrc", capable->home_dir);
2100 #endif
2101 
2102     array = lives_strsplit(DEF_AUTOTRANS, "|", 3);
2103     mainw->def_trans_idx = weed_filter_highest_version(array[0], array[1], array[2], NULL);
2104     if (mainw->def_trans_idx == - 1) {
2105       msg = lives_strdup_printf(_("System default transition (%s from package %s by %s) not found."),
2106                                 array[1], array[0], array[2]);
2107       LIVES_WARN(msg);
2108       lives_free(msg);
2109     }
2110     lives_strfreev(array);
2111 
2112     get_string_prefd(PREF_ACTIVE_AUTOTRANS, buff, 256, DEF_AUTOTRANS);
2113     if (!strcmp(buff, "none")) prefs->atrans_fx = -1;
2114     else {
2115       if (!lives_utf8_strcasecmp(buff, DEF_AUTOTRANS) || get_token_count(buff, '|') < 3)
2116         prefs->atrans_fx = mainw->def_trans_idx;
2117       else {
2118         array = lives_strsplit(buff, "|", 3);
2119         prefs->atrans_fx = weed_filter_highest_version(array[0], array[1], array[2], NULL);
2120         if (prefs->atrans_fx == - 1) {
2121           msg = lives_strdup_printf(_("User default transition (%s from package %s by %s) not found."),
2122                                     array[1], array[0], array[2]);
2123           LIVES_WARN(msg);
2124           lives_free(msg);
2125         }
2126         lives_strfreev(array);
2127       }
2128     }
2129 
2130     mainw->recovery_file = lives_strdup_printf("%s/recovery.%d.%d.%d", prefs->workdir, lives_getuid(),
2131                            lives_getgid(), capable->mainpid);
2132 
2133     if (capable->has_jackd) naudp++;
2134     if (capable->has_pulse_audio) naudp++;
2135     if (capable->has_sox_play) naudp++;
2136 
2137     if (naudp > 1) {
2138       if (prefs->startup_phase > 0 && prefs->startup_phase <= 4) {
2139         splash_end();
2140         if (!do_audio_choice_dialog(prefs->startup_phase)) {
2141           lives_exit(0);
2142         }
2143         if (prefs->audio_player == AUD_PLAYER_JACK) future_prefs->jack_opts = prefs->jack_opts = JACK_OPTS_START_ASERVER;
2144         else future_prefs->jack_opts = prefs->jack_opts = 0;
2145         set_int_pref(PREF_JACK_OPTS, prefs->jack_opts);
2146 
2147         prefs->startup_phase = 4;
2148         set_int_pref(PREF_STARTUP_PHASE, 4);
2149       }
2150 
2151       // audio startup
2152 #ifdef ENABLE_JACK
2153       if (prefs->jack_opts & JACK_OPTS_TRANSPORT_MASTER || prefs->jack_opts & JACK_OPTS_TRANSPORT_CLIENT ||
2154           prefs->jack_opts & JACK_OPTS_START_ASERVER ||
2155           prefs->jack_opts & JACK_OPTS_START_TSERVER) {
2156         // start jack transport polling
2157         if (prefs->jack_opts & JACK_OPTS_START_ASERVER) splash_msg(_("Starting jack audio server..."),
2158               SPLASH_LEVEL_LOAD_APLAYER);
2159         else {
2160           if (prefs->jack_opts & JACK_OPTS_START_TSERVER) splash_msg(_("Starting jack transport server..."),
2161                 SPLASH_LEVEL_LOAD_APLAYER);
2162           else splash_msg(_("Connecting to jack server..."), SPLASH_LEVEL_LOAD_APLAYER);
2163         }
2164         if (!lives_jack_init()) {
2165           if ((prefs->jack_opts & JACK_OPTS_START_ASERVER) || (prefs->jack_opts & JACK_OPTS_START_TSERVER))
2166             do_jack_noopen_warn();
2167           else do_jack_noopen_warn3();
2168           if (prefs->startup_phase == 4) {
2169             do_jack_noopen_warn2();
2170           }
2171           future_prefs->jack_opts = 0; // jack is causing hassle, get rid of it
2172           set_int_pref(PREF_JACK_OPTS, 0);
2173           lives_exit(0);
2174         }
2175       }
2176 
2177       if (prefs->audio_player == AUD_PLAYER_JACK) {
2178         jack_audio_init();
2179         jack_audio_read_init();
2180         mainw->jackd = jack_get_driver(0, TRUE);
2181         if (mainw->jackd) {
2182           if (!jack_create_client_writer(mainw->jackd)) mainw->jackd = NULL;
2183 
2184           if (!mainw->jackd && prefs->startup_phase == 0) {
2185 #ifdef HAVE_PULSE_AUDIO
2186             char *otherbit = lives_strdup("\"lives -aplayer pulse\".");
2187 #else
2188             char *otherbit = lives_strdup("\"lives -aplayer sox\".");
2189 #endif
2190             char *tmp;
2191 
2192             char *msg = lives_strdup_printf(
2193                           _("\n\nManual start of jackd required. Please make sure jackd is running, \n"
2194                             "or else change the value of <jack_opts> in %s to 16\nand restart LiVES.\n\n"
2195                             "Alternatively, try to start lives with either \"lives -jackopts 16\", or "),
2196                           (tmp = lives_filename_to_utf8(prefs->configfile, -1, NULL, NULL, NULL)));
2197             fprintf(stderr, "%s%s\n\n", msg, otherbit);
2198             lives_free(msg);
2199             lives_free(tmp);
2200             lives_free(otherbit);
2201           }
2202 
2203           if (!mainw->jackd) {
2204             do_jack_noopen_warn3();
2205             if (prefs->startup_phase == 4) {
2206               do_jack_noopen_warn2();
2207             } else do_jack_noopen_warn4();
2208             lives_exit(0);
2209           }
2210 
2211           mainw->jackd->whentostop = &mainw->whentostop;
2212           mainw->jackd->cancelled = &mainw->cancelled;
2213           mainw->jackd->in_use = FALSE;
2214           mainw->jackd->play_when_stopped = (prefs->jack_opts & JACK_OPTS_NOPLAY_WHEN_PAUSED)
2215                                             ? FALSE : TRUE;
2216 
2217           jack_write_driver_activate(mainw->jackd);
2218 
2219           if (prefs->perm_audio_reader) {
2220             // create reader connection now, if permanent
2221             jack_rec_audio_to_clip(-1, -1, RECA_EXTERNAL);
2222 	    // *INDENT-OFF*
2223           }}}
2224       // *INDENT-ON*
2225 #endif
2226     }
2227 
2228 #ifdef HAVE_PULSE_AUDIO
2229     if (prefs->audio_player == AUD_PLAYER_PULSE) {
2230       splash_msg(_("Starting pulseaudio server..."), SPLASH_LEVEL_LOAD_APLAYER);
2231 
2232       if (!mainw->foreign) {
2233         if (prefs->pa_restart && !prefs->vj_mode) {
2234           char *com = lives_strdup_printf("%s -k %s", EXEC_PULSEAUDIO, prefs->pa_start_opts);
2235           lives_system(com, TRUE);
2236           lives_free(com);
2237         }
2238       }
2239 
2240       if (!lives_pulse_init(prefs->startup_phase)) {
2241         if (prefs->startup_phase == 4) {
2242           lives_exit(0);
2243         }
2244       } else {
2245         pulse_audio_init();
2246         pulse_audio_read_init();
2247         mainw->pulsed = pulse_get_driver(TRUE);
2248         mainw->pulsed->whentostop = &mainw->whentostop;
2249         mainw->pulsed->cancelled = &mainw->cancelled;
2250         mainw->pulsed->in_use = FALSE;
2251 
2252         pulse_driver_activate(mainw->pulsed);
2253 
2254         if (prefs->perm_audio_reader) {
2255           // create reader connection now, if permanent
2256           pulse_rec_audio_to_clip(-1, -1, RECA_EXTERNAL);
2257 	  // *INDENT-OFF*
2258         }}}
2259     // *INDENT-ON*
2260 #endif
2261   }
2262 
2263   if (prefs->startup_phase != 0) {
2264     splash_end();
2265     set_int_pref(PREF_STARTUP_PHASE, 5);
2266     prefs->startup_phase = 5;
2267     do_startup_interface_query();
2268 
2269     set_int_pref(PREF_STARTUP_PHASE, 6);
2270     prefs->startup_phase = 6;
2271 
2272     if (prefs->show_disk_quota && !prefs->vj_mode) {
2273       if (!disk_monitor_running(prefs->workdir))
2274         disk_monitor_start(prefs->workdir);
2275 
2276       capable->ds_used = disk_monitor_wait_result(prefs->workdir, LIVES_DEFAULT_TIMEOUT);
2277       if (capable->ds_used >= 0) {
2278         ran_ds_dlg = TRUE;
2279         run_diskspace_dialog();
2280       } else {
2281         disk_monitor_forget();
2282         if (prefs->show_disk_quota)
2283           mainw->helper_procthreads[PT_LAZY_DSUSED] = disk_monitor_start(prefs->workdir);
2284       }
2285     } else {
2286       disk_monitor_forget();
2287     }
2288 
2289     set_int_pref(PREF_STARTUP_PHASE, 100); // tell backend to delete this
2290     prefs->startup_phase = 100;
2291 
2292     /* if (prefs->show_splash) { */
2293     /*   splash_init(); */
2294     /* } */
2295   }
2296 
2297   if (strcmp(future_prefs->theme, prefs->theme)) {
2298     // we set the theme here in case it got reset to 'none'
2299     set_string_pref(PREF_GUI_THEME, prefs->theme);
2300     lives_snprintf(future_prefs->theme, 64, "%s", prefs->theme);
2301   }
2302 
2303   if (mainw->vpp && mainw->vpp->get_audio_fmts) mainw->vpp->audio_codec = get_best_audio(mainw->vpp);
2304 } // end of lives_init
2305 
2306 
show_detected_or_not(boolean cap,const char * pname)2307 static void show_detected_or_not(boolean cap, const char *pname) {
2308   if (cap) d_print(_("%s...detected... "), pname);
2309   else d_print(_("%s...NOT DETECTED... "), pname);
2310 }
2311 
2312 #define SHOWDETx(cap, exec) show_detected_or_not(capable->has_##cap, exec)
2313 #define SHOWDET(cap) SHOWDETx(cap, QUOTEME(cap))
2314 //   SHOWDET(, EXEC_);
2315 
do_start_messages(void)2316 static void do_start_messages(void) {
2317   int w, h;
2318   char *tmp, *endian, *fname, *phase = NULL;
2319 
2320   if (prefs->vj_mode) {
2321     d_print(_("Starting in VJ MODE: Skipping most startup checks\n"));
2322 #ifndef IS_MINGW
2323     SHOWDET(wmctrl);
2324     SHOWDET(xdotool);
2325     SHOWDET(xwininfo);
2326 #endif
2327     d_print("\n\n");
2328     return;
2329   }
2330 
2331   d_print(_("\nMachine details:\n"));
2332 
2333   get_machine_dets();
2334   d_print(_("OS is %s %s, running on %s\n"),
2335           capable->os_name ? capable->os_name : _("unknown"),
2336           capable->os_release ? capable->os_release : "?",
2337           capable->os_hardware ? capable->os_hardware : "????");
2338 
2339   d_print(_("CPU type is %s "), capable->cpu_name);
2340   d_print(P_("(%d core, ", "(%d cores, ", capable->ncpus), capable->ncpus);
2341 
2342   if (capable->byte_order == LIVES_LITTLE_ENDIAN) endian = (_("little endian"));
2343   else endian = (_("big endian"));
2344   d_print(_("%d bits, %s)\n"), capable->cpu_bits, endian);
2345   lives_free(endian);
2346 
2347   d_print(_("Machine name is '%s'\n"), capable->mach_name);
2348 
2349   d_print(_("Number of monitors detected: %d: "), capable->nmonitors);
2350 
2351   d_print(_("GUI screen size is %d X %d (usable: %d X %d); %d dpi.\nWidget scaling has been set to %.3f.\n"),
2352           mainw->mgeom[widget_opts.monitor].phys_width, mainw->mgeom[widget_opts.monitor].phys_height,
2353           GUI_SCREEN_WIDTH, GUI_SCREEN_HEIGHT,
2354           (int)mainw->mgeom[widget_opts.monitor].dpi,
2355           widget_opts.scale);
2356 
2357   if (get_screen_usable_size(&w, &h)) {
2358     d_print(_("Actual usable size appears to be %d X %d\n"), w, h);
2359   }
2360 
2361   get_wm_caps();
2362 
2363   d_print(_("Window manager reports as \"%s\" (%s)"),
2364           capable->wm_name ? capable->wm_name : _("UNKNOWN - please patch me !"),
2365           capable->wm_caps.wm_name ? capable->wm_caps.wm_name : "unknown");
2366 
2367   if (capable->wm_type && *capable->wm_type)
2368     d_print(_(", running on %s"), capable->wm_type);
2369 
2370   d_print(_("; compositing is %s.\n"), capable->wm_caps.is_composited ? _("supported") : _("not supported"));
2371 
2372   get_distro_dets();
2373 
2374   if (capable->distro_codename) tmp = lives_strdup_printf(" (%s)", capable->distro_codename);
2375   else tmp = lives_strdup("");
2376 
2377   d_print(_("Distro is %s %s %s\n"), capable->distro_name ? capable->distro_name : "?????",
2378           capable->distro_ver ? capable->distro_ver : "?????", tmp);
2379   lives_free(tmp);
2380 
2381   d_print("%s", _("GUI type is: "));
2382 
2383 #ifdef GUI_GTK
2384 #if GTK_CHECK_VERSION(3, 0, 0)
2385   d_print(_("GTK+ version %d.%d.%d (compiled with %d.%d.%d)"),
2386           gtk_get_major_version(), gtk_get_minor_version(),
2387           gtk_get_micro_version(),
2388           GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
2389           GTK_MICRO_VERSION
2390          );
2391 #else
2392   d_print(_("GTK+ (compiled with %d.%d.%d)"),
2393           GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION);
2394 #endif
2395 #endif
2396 
2397 #ifdef LIVES_PAINTER_IS_CAIRO
2398   d_print(_(", with cairo support\n"));
2399 #else
2400   d_print(_("\n"));
2401 #endif
2402 
2403   if (*capable->gui_theme_name) tmp = lives_strdup(capable->gui_theme_name);
2404   else tmp = lives_strdup_printf("lives-%s-dynamic", prefs->theme);
2405 
2406   d_print("GUI theme set to %s, icon theme set to %s\n", tmp,
2407           capable->icon_theme_name);
2408 
2409   lives_free(tmp);
2410 
2411 
2412 #ifndef RT_AUDIO
2413   d_print(_("WARNING - this version of LiVES was compiled without either\njack or pulseaudio support.\n"
2414             "Many audio features will be unavailable.\n"));
2415 # else
2416 #ifdef ENABLE_JACK
2417   d_print(_("Compiled with jack support, good !\n"));
2418 #endif
2419 #ifdef HAVE_PULSE_AUDIO
2420   d_print(_("Compiled with pulseaudio support, wonderful !\n"));
2421 #endif
2422 #endif
2423 
2424   if (ign_opts.ign_configfile) {
2425     tmp = (_("set via -configfile commandline option"));
2426   } else {
2427     tmp = (_("default value"));
2428   }
2429   d_print(_("\nConfig file is %s (%s)\n"), prefs->configfile, tmp);
2430   lives_free(tmp);
2431 
2432   if (!capable->mountpoint || !*capable->mountpoint)
2433     capable->mountpoint = get_mountpoint_for(prefs->workdir);
2434   if (capable->mountpoint && *capable->mountpoint) tmp = lives_strdup_printf(_(", contained in volume %s"), capable->mountpoint);
2435   else tmp = lives_strdup("");
2436 
2437   d_print(_("\nWorking directory is %s%s\n"), prefs->workdir, tmp);
2438   lives_free(tmp);
2439 
2440   if (mainw->has_session_workdir) {
2441     d_print(_("(Set by -workdir commandline option)\n"));
2442   } else {
2443     if (initial_startup_phase != -1) {
2444       if (!strcmp(mainw->version_hash, mainw->old_vhash)) {
2445         lives_free(old_vhash);
2446         old_vhash = lives_strdup(LiVES_VERSION);
2447       }
2448       d_print(_("(Retrieved from %s, version %s)\n"), prefs->configfile, old_vhash);
2449     } else {
2450       d_print(_("(Set by user during setup phase)\n"));
2451     }
2452   }
2453 
2454   if (initial_startup_phase == 0) {
2455     if (!*mainw->old_vhash || !strcmp(mainw->old_vhash, "0")) {
2456       phase = (_("STARTUP ERROR OCCURRED - FORCED REINSTALL"));
2457     } else {
2458       if (atoi(mainw->old_vhash) < atoi(mainw->version_hash)) {
2459         phase = lives_strdup_printf(_("upgrade from version %s. Welcome !"), mainw->old_vhash);
2460       } else if (atoi(mainw->old_vhash) > atoi(mainw->version_hash)) {
2461         phase = lives_strdup_printf(_("downgrade from version %s !"), mainw->old_vhash);
2462       }
2463     }
2464   } else if (initial_startup_phase == -1) {
2465     if (!strcmp(mainw->old_vhash, "0")) {
2466       phase = (_("REINSTALL AFTER FAILED RECOVERY"));
2467       fname = lives_strdup_printf("%s.damaged", prefs->configfile);
2468       if (lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) {
2469         tmp = lives_strdup_printf(_("%s; check %s for possible errors before re-running LiVES"), phase, fname);
2470         lives_free(phase);
2471         phase = tmp;
2472       }
2473       lives_free(fname);
2474       d_print("\n");
2475     } else {
2476       phase = (_("fresh install. Welcome !"));
2477     }
2478   } else {
2479     phase = lives_strdup_printf(_("continue with installation"), initial_startup_phase);
2480   }
2481   if (!phase) phase = (_("normal startup"));
2482   d_print(_("Initial startup phase was %d: (%s)\n"), initial_startup_phase, phase);
2483   lives_free(phase);
2484   lives_free(old_vhash);
2485 
2486   if (initial_startup_phase == 0) {
2487     fname = lives_strdup_printf("%s.recovery.tried.succeeded", prefs->configfile);
2488     if (lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) {
2489       phase = lives_strdup_printf(_("%s WAS POSSIBLY RECOVERED FROM %s.recovery\n"), prefs->configfile, prefs->configfile);
2490       d_print("%s", phase);
2491       lives_free(phase);
2492     }
2493     lives_free(fname);
2494   }
2495 
2496 
2497   d_print(_("\nChecking RECOMMENDED dependencies: "));
2498 
2499   SHOWDET(mplayer);
2500   if (!capable->has_mplayer) {
2501     SHOWDET(mplayer2);
2502     if (!capable->has_mplayer2) {
2503       SHOWDET(mpv);
2504     }
2505   }
2506   //SHOWDET(file);
2507   SHOWDET(identify);
2508   if (!capable->has_jackd)
2509     SHOWDETx(pulse_audio, EXEC_PULSEAUDIO);
2510   SHOWDETx(sox_sox, EXEC_SOX);
2511   SHOWDET(convert);
2512   SHOWDET(composite);
2513   SHOWDET(ffprobe);
2514   SHOWDET(gzip);
2515   SHOWDET(md5sum);
2516   if (!check_for_executable(&capable->has_youtube_dl, EXEC_YOUTUBE_DL)
2517       && check_for_executable(&capable->has_youtube_dlc, EXEC_YOUTUBE_DLC)) {
2518     SHOWDETx(youtube_dlc, EXEC_YOUTUBE_DLC);
2519   } else SHOWDETx(youtube_dl, EXEC_YOUTUBE_DL);
2520 
2521   d_print(_("\n\nChecking OPTIONAL dependencies: "));
2522   SHOWDET(jackd);
2523   SHOWDET(python);
2524   SHOWDET(xwininfo);
2525   SHOWDETx(cdda2wav, "cdda2wav/icedax");
2526   SHOWDET(dvgrab);
2527   SHOWDET(gdb);
2528   SHOWDETx(gconftool_2, EXEC_GCONFTOOL_2);
2529   SHOWDETx(xdg_screensaver, EXEC_XDG_SCREENSAVER);
2530 
2531   d_print("\n\n");
2532 }
2533 #undef SHOWDETx
2534 #undef SHOWDET
2535 
set_toolkit_theme(int prefer)2536 static void set_toolkit_theme(int prefer) {
2537   char *lname, *ic_dir;
2538   //  LiVESList *list;
2539   char *tmp;
2540 
2541   lives_widget_object_get(gtk_settings_get_default(), "gtk-double-click-time", &capable->dclick_time);
2542   if (capable->dclick_time <= 0) capable->dclick_time = LIVES_DEF_DCLICK_TIME;
2543 
2544   lives_widget_object_get(gtk_settings_get_default(), "gtk-double-click-distance", &capable->dclick_dist);
2545   if (capable->dclick_dist <= 0) capable->dclick_dist = LIVES_DEF_DCLICK_DIST;
2546 
2547   lives_widget_object_get(gtk_settings_get_default(), "gtk-font-name", &tmp);
2548 
2549   /// stretch, style, weight not used
2550   lives_parse_font_string(tmp, &widget_opts.font_name, &widget_opts.font_size, NULL, NULL, NULL);
2551   lives_free(tmp);
2552 
2553   lives_widget_object_get(gtk_settings_get_default(), "gtk-alternative-button-order", &widget_opts.alt_button_order);
2554 
2555   lives_widget_object_get(gtk_settings_get_default(), "gtk-icon-theme-name", &capable->icon_theme_name);
2556   lives_widget_object_get(gtk_settings_get_default(), "gtk-theme-name", &capable->gui_theme_name);
2557 
2558   if (prefer & LIVES_THEME_DARK) {
2559     lives_widget_object_set(gtk_settings_get_default(), "gtk-application-prefer-dark-theme", TRUE);
2560   }
2561 
2562   if (prefer & USE_LIVES_THEMEING) {
2563     lives_widget_object_set(gtk_settings_get_default(), "gtk-theme-name", "");
2564 
2565     lname = lives_strdup("-lives-hybrid");
2566     capable->icon_theme_name = lives_concat(capable->icon_theme_name, lname);
2567 
2568     lname = lives_strdup("-lives-hybrid-dynamic");
2569     capable->gui_theme_name = lives_concat(capable->gui_theme_name, lname);
2570   }
2571 
2572   capable->extra_icon_path = lives_build_path(prefs->config_datadir, STOCK_ICONS_DIR, NULL);
2573 
2574   widget_opts.icon_theme = gtk_icon_theme_new();
2575 
2576   gtk_icon_theme_set_custom_theme((LiVESIconTheme *)widget_opts.icon_theme, capable->icon_theme_name);
2577   gtk_icon_theme_prepend_search_path((LiVESIconTheme *)widget_opts.icon_theme, capable->extra_icon_path);
2578 
2579   ic_dir = lives_build_path(prefs->prefix_dir, ICON_DIR, NULL);
2580   gtk_icon_theme_prepend_search_path((LiVESIconTheme *)widget_opts.icon_theme, ic_dir);
2581   lives_free(ic_dir);
2582 
2583   capable->all_icons = gtk_icon_theme_list_icons((LiVESIconTheme *)widget_opts.icon_theme, NULL);
2584   if (0) {
2585     LiVESList *list = capable->all_icons;
2586     for (; list; list = list->next) if (!strncmp((char *)list->data, "gtk-", 4)) g_print("icon: %s\n", (char *)list->data);
2587   }
2588 
2589   widget_helper_set_stock_icon_alts((LiVESIconTheme *)widget_opts.icon_theme);
2590 }
2591 
2592 
2593 #ifndef VALGRIND_ON
pick_custom_colours(void)2594 static void pick_custom_colours(void) {
2595   double lmin, lmax;
2596   uint8_t ncr, ncg, ncb;
2597   if (!(palette->style & STYLE_LIGHT)) {
2598     lmin = .05; lmax = .4;
2599   } else {
2600     lmin = .6; lmax = .8;
2601   }
2602   ncr = palette->menu_and_bars.red * 255.;
2603   ncg = palette->menu_and_bars.green * 255.;
2604   ncb = palette->menu_and_bars.blue * 255.;
2605   prefs->pb_quality = PB_QUALITY_HIGH;
2606   if (pick_nice_colour(palette->normal_back.red * 255., palette->normal_back.green * 255.,
2607                        palette->normal_back.blue * 255., &ncr, &ncg, &ncb, 1.5, .25, .75)) {
2608     // nice1 - used for outlines
2609     palette->nice1.red = LIVES_WIDGET_COLOR_SCALE_255(ncr);
2610     palette->nice1.green = LIVES_WIDGET_COLOR_SCALE_255(ncg);
2611     palette->nice1.blue = LIVES_WIDGET_COLOR_SCALE_255(ncb);
2612     palette->nice1.alpha = 1.;
2613 
2614     ncr = palette->menu_and_bars.red * 255.;
2615     ncg = palette->menu_and_bars.green * 255.;
2616     ncb = palette->menu_and_bars.blue * 255.;
2617 
2618     if (pick_nice_colour(palette->nice1.red * 255., palette->nice1.green * 255.,
2619                          palette->nice1.blue * 255., &ncr, &ncg, &ncb, 1., lmin, lmax)) {
2620       // nice2 - alt for menu_and_bars
2621       // insensitive colour ?
2622       palette->nice2.red = LIVES_WIDGET_COLOR_SCALE_255(ncr);
2623       palette->nice2.green = LIVES_WIDGET_COLOR_SCALE_255(ncg);
2624       palette->nice2.blue = LIVES_WIDGET_COLOR_SCALE_255(ncb);
2625       palette->nice2.alpha = 1.;
2626       mainw->pretty_colours = TRUE;
2627 
2628       if (!(palette->style & STYLE_LIGHT)) {
2629         lmin = .6; lmax = .8;
2630       } else {
2631         lmin = .2; lmax = .4;
2632       }
2633       pick_nice_colour(palette->normal_fore.red * 255., palette->normal_fore.green * 255.,
2634                        palette->normal_fore.blue * 255., &ncr, &ncg, &ncb, 1., lmin, lmax);
2635       // nice3 - alt for menu_and_bars_fore
2636       palette->nice3.red = LIVES_WIDGET_COLOR_SCALE_255(ncr);
2637       palette->nice3.green = LIVES_WIDGET_COLOR_SCALE_255(ncg);
2638       palette->nice3.blue = LIVES_WIDGET_COLOR_SCALE_255(ncb);
2639       palette->nice3.alpha = 1.;
2640     }
2641   }
2642   if (prefs->extra_colours && mainw->pretty_colours) {
2643     char *colref, *tmp;
2644     colref = gdk_rgba_to_string(&palette->nice1);
2645     set_css_value_direct(NULL, LIVES_WIDGET_STATE_PRELIGHT, "combobox window menu menuitem", "border-color", colref);
2646 
2647     tmp = lives_strdup_printf("0 -3px %s inset", colref);
2648     set_css_value_direct(NULL, LIVES_WIDGET_STATE_CHECKED, "notebook header tabs *", "box-shadow", tmp);
2649     set_css_value_direct(NULL, LIVES_WIDGET_STATE_PRELIGHT, "menuitem", "box-shadow", tmp);
2650     set_css_value_direct(NULL, LIVES_WIDGET_STATE_PRELIGHT, "menu menuitem", "box-shadow", "none");
2651     lives_free(tmp);
2652 
2653     set_css_value_direct(NULL, LIVES_WIDGET_STATE_ACTIVE, "scrollbar slider", "background-color", colref);
2654     tmp = lives_strdup_printf("0 0 0 4px %s inset", colref);
2655     set_css_value_direct(NULL, LIVES_WIDGET_STATE_PRELIGHT, "combobox window menu menuitem", "box-shadow", tmp);
2656     lives_free(tmp);
2657     lives_free(colref);
2658   }
2659 }
2660 #endif
2661 
2662 
set_palette_colours(boolean force_reload)2663 boolean set_palette_colours(boolean force_reload) {
2664   // force_reload should only be set when the theme changes in prefs.
2665   lives_colRGBA64_t lcol;
2666   LiVESList *cache_backup;
2667 
2668   char *themedir, *themefile, *othemefile, *fname, *tmp;
2669   char *pstyle, *colref;
2670 
2671   boolean is_OK = TRUE;
2672   boolean cached = FALSE;
2673 
2674   lcol.alpha = 65535;
2675 
2676   // set configurable colours and theme colours for the app
2677   lcol.red = lcol.green = lcol.blue = 0;
2678   lives_rgba_to_widget_color(&palette->black, &lcol);
2679 
2680   lcol.red = lcol.green = lcol.blue = 65535;
2681   lives_rgba_to_widget_color(&palette->white, &lcol);
2682 
2683   // salmon
2684   lcol.red = 63750;
2685   lcol.green = 32767;
2686   lcol.blue = 29070;
2687   lives_rgba_to_widget_color(&palette->light_red, &lcol);
2688 
2689   // SeaGreen3
2690   lcol.red = 17219;
2691   lcol.green = 52685;
2692   lcol.blue = 32896;
2693   lives_rgba_to_widget_color(&palette->light_green, &lcol);
2694 
2695   // dark red
2696   lcol.red = 30723;
2697   lcol.green = 0;
2698   lcol.blue = 0;
2699   lives_rgba_to_widget_color(&palette->dark_red, &lcol);
2700 
2701   // darkorange4
2702   lcol.red = 35723;
2703   lcol.green = 17733;
2704   lcol.blue = 0;
2705   lives_rgba_to_widget_color(&palette->dark_orange, &lcol);
2706 
2707   lives_widget_color_copy(&palette->fade_colour, &palette->black);
2708   lives_widget_color_copy(&palette->banner_fade_text, &palette->white);
2709 
2710   palette->style = STYLE_PLAIN;
2711 
2712   // defaults
2713   palette->frame_surround.red = palette->frame_surround.green
2714                                 = palette->frame_surround.blue = palette->frame_surround.alpha = 65535;
2715 
2716   palette->audcol.blue = palette->audcol.red = 16384;
2717   palette->audcol.green = palette->audcol.alpha = 65535;
2718 
2719   palette->vidcol.red = 0;
2720   palette->vidcol.green = 16384;
2721   palette->vidcol.blue = palette->vidcol.alpha = 65535;
2722 
2723   palette->fxcol.red = palette->fxcol.alpha = 65535;
2724   palette->fxcol.green = palette->fxcol.blue = 0;
2725 
2726   palette->mt_mark.red = palette->mt_mark.green = 0;
2727   palette->mt_mark.blue = palette->mt_mark.alpha = 65535;
2728 
2729   palette->mt_timeline_reg.red = palette->mt_timeline_reg.green = palette->mt_timeline_reg.blue = 0;
2730   palette->mt_timeline_reg.alpha = 65535;
2731 
2732   palette->mt_evbox.red = palette->mt_evbox.green = palette->mt_evbox.blue = palette->mt_evbox.alpha = 65535;
2733 
2734   palette->ce_unsel.red = palette->ce_unsel.green = palette->ce_unsel.blue = 0;
2735   palette->ce_unsel.alpha = 65535;
2736 
2737   palette->ce_sel.red = palette->ce_sel.green = palette->ce_sel.blue = palette->ce_sel.alpha = 65535;
2738 
2739   lives_widget_color_copy(&palette->mt_timecode_bg, &palette->black);
2740   lives_widget_color_copy(&palette->mt_timecode_fg, &palette->light_green);
2741 
2742   lcol.red = 0;
2743 
2744   // if theme is not "none" and we dont find stuff in prefs then we must reload
2745   if (!lives_ascii_strcasecmp(future_prefs->theme, LIVES_THEME_NONE)) {
2746     set_toolkit_theme(0);
2747     return TRUE;
2748   } else if (!get_colour_pref(THEME_DETAIL_STYLE, &lcol)) {
2749     force_reload = TRUE;
2750   } else {
2751     // pull our colours from normal prefs
2752     palette->style = lcol.red;
2753     if (!(palette->style & STYLE_LIGHT)) {
2754       if (mainw->sep_image) lives_widget_set_opacity(mainw->sep_image, 0.8);
2755       if (mainw->multitrack && mainw->multitrack->sep_image)
2756         lives_widget_set_opacity(mainw->multitrack->sep_image, 0.8);
2757       palette->ce_unsel.red = palette->ce_unsel.green = palette->ce_unsel.blue = 6554;
2758       set_toolkit_theme(USE_LIVES_THEMEING | LIVES_THEME_DARK | LIVES_THEME_COMPACT);
2759     } else {
2760       set_toolkit_theme(USE_LIVES_THEMEING | LIVES_THEME_COMPACT);
2761       palette->ce_unsel.red = palette->ce_unsel.green = palette->ce_unsel.blue = 0;
2762       if (mainw->sep_image) lives_widget_set_opacity(mainw->sep_image, 0.4);
2763       if (mainw->multitrack && mainw->multitrack->sep_image)
2764         lives_widget_set_opacity(mainw->multitrack->sep_image, 0.4);
2765     }
2766     get_string_pref(THEME_DETAIL_SEPWIN_IMAGE, mainw->sepimg_path, PATH_MAX);
2767     get_string_pref(THEME_DETAIL_FRAMEBLANK_IMAGE, mainw->frameblank_path, PATH_MAX);
2768 
2769     get_colour_pref(THEME_DETAIL_NORMAL_FORE, &lcol);
2770     lives_rgba_to_widget_color(&palette->normal_fore, &lcol);
2771 
2772     get_colour_pref(THEME_DETAIL_NORMAL_BACK, &lcol);
2773     lives_rgba_to_widget_color(&palette->normal_back, &lcol);
2774 
2775     get_colour_pref(THEME_DETAIL_ALT_FORE, &lcol);
2776     lives_rgba_to_widget_color(&palette->menu_and_bars_fore, &lcol);
2777 
2778     get_colour_pref(THEME_DETAIL_ALT_BACK, &lcol);
2779     lives_rgba_to_widget_color(&palette->menu_and_bars, &lcol);
2780 
2781     get_colour_pref(THEME_DETAIL_INFO_TEXT, &lcol);
2782     lives_rgba_to_widget_color(&palette->info_text, &lcol);
2783 
2784     get_colour_pref(THEME_DETAIL_INFO_BASE, &lcol);
2785     lives_rgba_to_widget_color(&palette->info_base, &lcol);
2786 
2787     // extended colours
2788 
2789     get_colour_pref(THEME_DETAIL_MT_TCFG, &lcol);
2790     lives_rgba_to_widget_color(&palette->mt_timecode_fg, &lcol);
2791 
2792     get_colour_pref(THEME_DETAIL_MT_TCBG, &lcol);
2793     lives_rgba_to_widget_color(&palette->mt_timecode_bg, &lcol);
2794 
2795     get_colour_pref(THEME_DETAIL_AUDCOL, &palette->audcol);
2796     get_colour_pref(THEME_DETAIL_VIDCOL, &palette->vidcol);
2797     get_colour_pref(THEME_DETAIL_FXCOL, &palette->fxcol);
2798 
2799     get_colour_pref(THEME_DETAIL_MT_TLREG, &palette->mt_timeline_reg);
2800     get_colour_pref(THEME_DETAIL_MT_MARK, &palette->mt_mark);
2801     get_colour_pref(THEME_DETAIL_MT_EVBOX, &palette->mt_evbox);
2802 
2803     get_colour_pref(THEME_DETAIL_FRAME_SURROUND, &palette->frame_surround);
2804 
2805     get_colour_pref(THEME_DETAIL_CE_SEL, &palette->ce_sel);
2806     get_colour_pref(THEME_DETAIL_CE_UNSEL, &palette->ce_unsel);
2807   }
2808 
2809   if (force_reload) {
2810     // check if theme is custom:
2811     themedir = lives_build_path(prefs->config_datadir, PLUGIN_THEMES, prefs->theme, NULL);
2812     if (!lives_file_test(themedir, LIVES_FILE_TEST_IS_DIR)) {
2813       lives_free(themedir);
2814       // if not custom, check if builtin
2815       themedir = lives_build_path(prefs->prefix_dir, THEME_DIR, prefs->theme, NULL);
2816       if (!lives_file_test(themedir, LIVES_FILE_TEST_IS_DIR)) {
2817         if (!mainw->is_ready) {
2818           lives_free(themedir);
2819           set_toolkit_theme(0);
2820           return FALSE;
2821         }
2822         is_OK = FALSE;
2823       }
2824     }
2825 
2826     fname = lives_strdup_printf("%s.%s", THEME_SEP_IMG_LITERAL, LIVES_FILE_EXT_JPG);
2827     tmp = lives_build_filename(themedir, fname, NULL);
2828     lives_free(fname);
2829     if (lives_file_test(tmp, LIVES_FILE_TEST_EXISTS)) {
2830       lives_snprintf(mainw->sepimg_path, PATH_MAX, "%s", tmp);
2831       lives_free(tmp);
2832     } else {
2833       fname = lives_strdup_printf("%s.%s", THEME_SEP_IMG_LITERAL, LIVES_FILE_EXT_PNG);
2834       lives_free(tmp);
2835       tmp = lives_build_filename(themedir, fname, NULL);
2836       lives_free(fname);
2837       lives_snprintf(mainw->sepimg_path, PATH_MAX, "%s", tmp);
2838       lives_free(tmp);
2839     }
2840 
2841     fname = lives_strdup_printf("%s.%s", THEME_FRAME_IMG_LITERAL, LIVES_FILE_EXT_JPG);
2842     tmp = lives_build_filename(themedir, fname, NULL);
2843     lives_free(fname);
2844     if (lives_file_test(tmp, LIVES_FILE_TEST_EXISTS)) {
2845       lives_snprintf(mainw->frameblank_path, PATH_MAX, "%s", tmp);
2846       lives_free(tmp);
2847     } else {
2848       fname = lives_strdup_printf("%s.%s", THEME_FRAME_IMG_LITERAL, LIVES_FILE_EXT_PNG);
2849       tmp = lives_build_filename(themedir, fname, NULL);
2850       lives_free(fname);
2851       lives_snprintf(mainw->frameblank_path, PATH_MAX, "%s", tmp);
2852       lives_free(tmp);
2853     }
2854 
2855     // load from file
2856     themefile = lives_build_filename(themedir, THEME_HEADER, NULL);
2857 #ifdef GUI_GTK
2858 #if !GTK_CHECK_VERSION(3, 0, 0)
2859     lives_free(themefile);
2860     themefile = lives_build_filename(themedir, THEME_HEADER_2, NULL);
2861 #endif
2862 #endif
2863 
2864     if (!lives_file_test(themefile, LIVES_FILE_TEST_EXISTS)) {
2865       lives_free(themefile);
2866       themefile = lives_build_filename(themedir, THEME_HEADER_2, NULL);
2867 #ifdef GUI_GTK
2868 #if !GTK_CHECK_VERSION(3, 0, 0)
2869       lives_free(themefile);
2870       themefile = lives_build_filename(themedir, THEME_HEADER, NULL);
2871 #endif
2872 #endif
2873       if (!lives_file_test(themefile, LIVES_FILE_TEST_EXISTS)) {
2874         is_OK = FALSE;
2875       }
2876     }
2877 
2878     lives_free(themedir);
2879 
2880     // cache the themefile
2881     othemefile = themefile;
2882     cache_backup = mainw->gen_cache;
2883     if (!(mainw->gen_cache = cache_file_contents(themefile))) themefile = NULL;
2884     else cached = TRUE;
2885 
2886     /// get mandatory details
2887 
2888     if (!is_OK || !(pstyle = get_val_from_cached_list(THEME_DETAIL_STYLE, 8, mainw->gen_cache))) {
2889       if (pstyle) lives_free(pstyle);
2890       is_OK = FALSE;
2891       set_toolkit_theme(0);
2892     } else {
2893       palette->style = atoi(pstyle);
2894       lives_free(pstyle);
2895       if (!(palette->style & STYLE_LIGHT)) {
2896         palette->ce_unsel.red = palette->ce_unsel.green = palette->ce_unsel.blue = 6554;
2897         if (mainw->sep_image) lives_widget_set_opacity(mainw->sep_image, 0.8);
2898         if (mainw->multitrack && mainw->multitrack->sep_image)
2899           lives_widget_set_opacity(mainw->multitrack->sep_image, 0.8);
2900         set_toolkit_theme(USE_LIVES_THEMEING | LIVES_THEME_DARK | LIVES_THEME_COMPACT);
2901       } else {
2902         if (mainw->sep_image) lives_widget_set_opacity(mainw->sep_image, 0.4);
2903         if (mainw->multitrack && mainw->multitrack->sep_image)
2904           lives_widget_set_opacity(mainw->multitrack->sep_image, 0.4);
2905         set_toolkit_theme(USE_LIVES_THEMEING | LIVES_THEME_COMPACT);
2906         palette->ce_unsel.red = palette->ce_unsel.green = palette->ce_unsel.blue = 0;
2907       }
2908     }
2909 
2910     if (!is_OK || !get_theme_colour_pref(THEME_DETAIL_NORMAL_FORE, &lcol)) {
2911       is_OK = FALSE;
2912     } else lives_rgba_to_widget_color(&palette->normal_fore, &lcol);
2913 
2914     if (!is_OK || !get_theme_colour_pref(THEME_DETAIL_NORMAL_BACK, &lcol)) {
2915       is_OK = FALSE;
2916     } else lives_rgba_to_widget_color(&palette->normal_back, &lcol);
2917 
2918     if (!is_OK || !get_theme_colour_pref(THEME_DETAIL_ALT_FORE, &lcol)) {
2919       is_OK = FALSE;
2920     } else lives_rgba_to_widget_color(&palette->menu_and_bars_fore, &lcol);
2921 
2922     if (!is_OK || !get_theme_colour_pref(THEME_DETAIL_ALT_BACK, &lcol)) {
2923       is_OK = FALSE;
2924     } else lives_rgba_to_widget_color(&palette->menu_and_bars, &lcol);
2925 
2926     if (!is_OK || !get_theme_colour_pref(THEME_DETAIL_INFO_TEXT, &lcol)) {
2927       is_OK = FALSE;
2928     } else lives_rgba_to_widget_color(&palette->info_text, &lcol);
2929 
2930     if (!is_OK || !get_theme_colour_pref(THEME_DETAIL_INFO_BASE, &lcol)) {
2931       is_OK = FALSE;
2932     } else lives_rgba_to_widget_color(&palette->info_base, &lcol);
2933 
2934     if (!is_OK) {
2935       if (cached) {
2936         lives_list_free_all(&mainw->gen_cache);
2937         mainw->gen_cache = cache_backup;
2938         themefile = othemefile;
2939       }
2940       if (mainw->is_ready) do_bad_theme_error(themefile);
2941       lives_free(themefile);
2942       return FALSE;
2943     }
2944 
2945     // get optional elements
2946     if (get_theme_colour_pref(THEME_DETAIL_MT_TCFG, &lcol)) {
2947       lives_rgba_to_widget_color(&palette->mt_timecode_fg, &lcol);
2948     }
2949 
2950     if (get_theme_colour_pref(THEME_DETAIL_MT_TCBG, &lcol)) {
2951       lives_rgba_to_widget_color(&palette->mt_timecode_bg, &lcol);
2952     }
2953 
2954     get_theme_colour_pref(THEME_DETAIL_AUDCOL, &palette->audcol);
2955     get_theme_colour_pref(THEME_DETAIL_VIDCOL, &palette->vidcol);
2956     get_theme_colour_pref(THEME_DETAIL_FXCOL, &palette->fxcol);
2957 
2958     get_theme_colour_pref(THEME_DETAIL_MT_TLREG, &palette->mt_timeline_reg);
2959     get_theme_colour_pref(THEME_DETAIL_MT_MARK, &palette->mt_mark);
2960     get_theme_colour_pref(THEME_DETAIL_MT_EVBOX, &palette->mt_evbox);
2961 
2962     get_theme_colour_pref(THEME_DETAIL_FRAME_SURROUND, &palette->frame_surround);
2963 
2964     get_theme_colour_pref(THEME_DETAIL_CE_SEL, &palette->ce_sel);
2965     get_theme_colour_pref(THEME_DETAIL_CE_UNSEL, &palette->ce_unsel);
2966 
2967     if (cached) {
2968       lives_list_free_all(&mainw->gen_cache);
2969       mainw->gen_cache = cache_backup;
2970       themefile = othemefile;
2971     }
2972 
2973     lives_free(themefile);
2974 
2975     // set details in prefs
2976     set_palette_prefs(force_reload);
2977   }
2978 
2979 #ifndef VALGRIND_ON
2980   /// generate some complementary colours
2981   // still experimenting...some values may need tweaking
2982   // suggested uses for each colour in the process of being defined
2983   // TODO - run a bg thread until we create GUI
2984   if (!prefs->vj_mode) {
2985     /// create thread to pick custom colours
2986     lives_proc_thread_create(LIVES_THRDATTR_NONE, (lives_funcptr_t)pick_custom_colours, 0, "");
2987   }
2988 #endif
2989   /// set global values
2990 
2991   set_css_value_direct(NULL, LIVES_WIDGET_STATE_PRELIGHT, "toolbutton *", "background-image", "none");
2992 
2993   colref = gdk_rgba_to_string(&palette->normal_back);
2994   set_css_value_direct(NULL, LIVES_WIDGET_STATE_NORMAL, "combobox window menu", "background-color", colref);
2995   lives_free(colref);
2996   colref = gdk_rgba_to_string(&palette->normal_fore);
2997   set_css_value_direct(NULL, LIVES_WIDGET_STATE_NORMAL, "combobox window menu", "color", colref);
2998   lives_free(colref);
2999 
3000   colref = gdk_rgba_to_string(&palette->menu_and_bars);
3001   set_css_value_direct(NULL, LIVES_WIDGET_STATE_NORMAL, "scrollbar", "background-color", colref);
3002   set_css_value_direct(NULL, LIVES_WIDGET_STATE_PRELIGHT, "combobox window menu menuitem", "background-color", colref);
3003   lives_free(colref);
3004   colref = gdk_rgba_to_string(&palette->menu_and_bars_fore);
3005   set_css_value_direct(NULL, LIVES_WIDGET_STATE_PRELIGHT, "combobox window menu menuitem", "color", colref);
3006   lives_free(colref);
3007 
3008   set_css_value_direct(NULL, LIVES_WIDGET_STATE_NORMAL, "combobox window menu menuitem", "border-width", "2px");
3009 
3010   tmp = lives_strdup_printf("%dpx", ((widget_opts.css_min_height * 3 + 3) >> 2) << 1);
3011   set_css_value_direct(NULL, LIVES_WIDGET_STATE_NORMAL, "combobox window menu menuitem", "min-height", tmp);
3012   lives_free(tmp);
3013   colref = gdk_rgba_to_string(&palette->menu_and_bars_fore);
3014   set_css_value_direct(NULL, LIVES_WIDGET_STATE_NORMAL, "scrollbar", "color", colref);
3015   lives_free(colref);
3016 
3017   //set_css_value_direct(NULL, LIVES_WIDGET_STATE_INSENSITIVE, "spinbutton button", "opacity", "0.5");
3018 
3019   return TRUE;
3020 }
3021 
3022 
get_capabilities(void)3023 capability *get_capabilities(void) {
3024   // get capabilities of backend system
3025   char **array;
3026   char *msg, *tmp;
3027 
3028   char buffer[PATH_MAX * 4];
3029   char command[PATH_MAX * 4];
3030   char dir[PATH_MAX];
3031   int numtok;
3032   size_t xs;
3033 
3034 #ifdef IS_DARWIN
3035   processor_info_array_t processorInfo;
3036   mach_msg_type_number_t numProcessorInfo;
3037   natural_t numProcessors = 0U;
3038   kern_return_t kerr;
3039 #endif
3040 
3041   buffer[0] = '\0';
3042   command[0] = '\0';
3043 
3044   if (!check_for_executable(&capable->has_perl, EXEC_PERL)) return capable;
3045 
3046   // this is _compile time_ bits, not runtime bits
3047   capable->cpu_bits = (sizeof(void *)) * 8;
3048 
3049   capable->ds_used = capable->ds_free = capable->ds_tot = -1;
3050 
3051   capable->mainpid = lives_getpid();
3052 
3053   get_location("cp", capable->cp_cmd, PATH_MAX);
3054   capable->sysbindir = get_dir(capable->cp_cmd);
3055 
3056   get_location("mv", capable->mv_cmd, PATH_MAX);
3057   get_location("ln", capable->ln_cmd, PATH_MAX);
3058   get_location("chmod", capable->chmod_cmd, PATH_MAX);
3059   get_location("cat", capable->cat_cmd, PATH_MAX);
3060   get_location("echo", capable->echo_cmd, PATH_MAX);
3061   get_location("eject", capable->eject_cmd, PATH_MAX);
3062 
3063   capable->wm_name = NULL;
3064   capable->wm_type = NULL;
3065 
3066   capable->python_version = 0;
3067   capable->xstdout = STDOUT_FILENO;
3068 
3069   lives_snprintf(capable->backend_path, PATH_MAX, "%s", (tmp = lives_find_program_in_path(BACKEND_NAME)));
3070   lives_free(tmp);
3071   if (!*capable->backend_path) return capable;
3072   capable->has_smogrify = PRESENT;
3073 
3074 retry_configfile:
3075 
3076   if (!mainw->has_session_workdir) {
3077     lives_snprintf(prefs->backend, PATH_MAX * 4, "%s -s \"%s\" -CONFIGFILE=\"%s\" --", EXEC_PERL, capable->backend_path,
3078                    prefs->configfile);
3079     lives_snprintf(prefs->backend_sync, PATH_MAX * 4, "%s", prefs->backend);
3080   } else {
3081     // if the user passed a -workdir option, we will use that, and the backend won't attempt to find an existing value
3082     lives_snprintf(prefs->backend, PATH_MAX * 4, "%s -s \"%s\" -WORKDIR=\"%s\" -CONFIGFILE=\"%s\" --", EXEC_PERL,
3083                    capable->backend_path, prefs->workdir, prefs->configfile);
3084     lives_snprintf(prefs->backend_sync, PATH_MAX * 4, "%s", prefs->backend);
3085   }
3086 
3087   if (!newconfigfile) {
3088     capable->has_smogrify = UNCHECKED;
3089     lives_snprintf(command, PATH_MAX * 4, "%s version", prefs->backend_sync);
3090 
3091     lives_popen(command, TRUE, buffer, PATH_MAX * 4);
3092 
3093     if (THREADVAR(com_failed)) {
3094       return capable;
3095     }
3096 
3097     xs = lives_strlen(buffer);
3098     if (xs < 5) return capable;
3099 
3100     lives_chomp(buffer);
3101     numtok = get_token_count(buffer, ' ') ;
3102     if (numtok < 2) return capable;
3103 
3104     array = lives_strsplit(buffer, " ", numtok);
3105     if (strcmp(array[0], "smogrify")) {
3106       lives_strfreev(array);
3107       return capable;
3108     }
3109 
3110     capable->has_smogrify = PRESENT;
3111     capable->smog_version_correct = FALSE;
3112 
3113     if (strcmp(array[1], LiVES_VERSION)) {
3114       msg = lives_strdup_printf("Version mismatch: smogrify = %s, LiVES = %s\n", array[1], LiVES_VERSION);
3115       LIVES_ERROR(msg);
3116       lives_free(msg);
3117       lives_strfreev(array);
3118       return capable;
3119     }
3120 
3121     lives_strfreev(array);
3122     capable->smog_version_correct = TRUE;
3123   }
3124 
3125   if (!newconfigfile)
3126     lives_snprintf(command, PATH_MAX * 4, "%s report -", prefs->backend_sync);
3127   else
3128     lives_snprintf(command, PATH_MAX * 4, "%s report", prefs->backend_sync);
3129 
3130   // check_settings:
3131 
3132   capable->has_smogrify = UNCHECKED;
3133   lives_popen(command, TRUE, buffer, PATH_MAX * 4);
3134   if (THREADVAR(com_failed) || lives_strlen(buffer) < 6) return capable;
3135   capable->has_smogrify = PRESENT;
3136 
3137   numtok = get_token_count(buffer, '|');
3138   if (numtok < 2) {
3139     capable->smog_version_correct = FALSE;
3140     return capable;
3141   }
3142 
3143   array = lives_strsplit(buffer, "|", numtok);
3144 
3145   if (!newconfigfile) {
3146     if (!strcmp(array[0], "smogrify::error")) {
3147       LIVES_ERROR(buffer);
3148       if (!strcmp(array[1], "config_get")) {
3149         lives_strfreev(array);
3150         capable->can_read_from_config = FALSE;
3151         return capable;
3152       }
3153       if (!strcmp(array[1], "config_set_new")) {
3154         lives_strfreev(array);
3155         capable->can_write_to_config_new = FALSE;
3156         return capable;
3157       }
3158       if (!strcmp(array[1], "config_set_rec")) {
3159         lives_strfreev(array);
3160         capable->can_write_to_config_backup = FALSE;
3161         return capable;
3162       }
3163       if (!strcmp(array[1], "config_set")) {
3164         lives_strfreev(array);
3165         capable->can_write_to_config = FALSE;
3166         return capable;
3167       }
3168       // other unspecified error
3169       mainw->error = TRUE;
3170       lives_snprintf(mainw->msg, MAINW_MSG_SIZE, "%s", buff);
3171       return capable;
3172     }
3173   }
3174 
3175   // the startup phase
3176   // this is 0 for normal operation
3177   // -1 for a fresh install
3178   // after this the value goes to 1....n
3179   // then finally gets set to 100, which instructs the backend to remove this preference, and return 0
3180   initial_startup_phase = prefs->startup_phase = atoi(array[2]);
3181 
3182   if (!newconfigfile) {
3183     if (initial_startup_phase == -1 && !ign_opts.ign_configfile) {
3184       /// if no configfile:
3185       /// check for migration:
3186       /// if $HOME/.lives exists, get the verhash from it
3187       char *oldconfig  = lives_build_filename(capable->home_dir, LIVES_DEF_CONFIG_FILE_OLD, NULL);
3188       if (lives_file_test(oldconfig, LIVES_FILE_TEST_EXISTS)) {
3189         lives_strfreev(array);
3190         newconfigfile = lives_strdup(prefs->configfile);
3191         lives_snprintf(prefs->configfile, PATH_MAX, "%s", oldconfig);
3192         lives_free(oldconfig);
3193         goto retry_configfile;
3194       }
3195       lives_free(oldconfig);
3196     }
3197   }
3198 
3199   // hash of last version used,
3200   // or 0 if rcfile existed, but we couldn't extract a version
3201   if (numtok > 3) {
3202     mainw->old_vhash = lives_strdup(array[3]);
3203   }
3204 
3205   if (!mainw->old_vhash) {
3206     old_vhash = lives_strdup("NULL");
3207   } else if (!*mainw->old_vhash) {
3208     old_vhash = lives_strdup("not present");
3209   } else if (!strcmp(mainw->old_vhash, "0")) {
3210     old_vhash = lives_strdup("unrecoverable");
3211   } else {
3212     old_vhash = lives_strdup(mainw->old_vhash);
3213 
3214     if (newconfigfile && *newconfigfile) {
3215       /// if < 3200000, migrate (copy) .lives and .lives-dir
3216       /// this should only happen once, since version will now have been updated in .lives
3217       /// after startup, we will offer to remove the old files
3218       migrate_config(old_vhash, newconfigfile);
3219     }
3220   }
3221 
3222   if (newconfigfile && *newconfigfile) {
3223     lives_strfreev(array);
3224     lives_snprintf(prefs->configfile, PATH_MAX, "%s", newconfigfile);
3225     lives_free(newconfigfile);
3226     newconfigfile = lives_strdup("");
3227     lives_free(old_vhash);
3228     lives_free(mainw->old_vhash);
3229     goto retry_configfile;
3230   }
3231 
3232   lives_snprintf(dir, PATH_MAX, "%s", array[1]);
3233 
3234   if (!mainw->has_session_workdir) {
3235     size_t dirlen = lives_strlen(dir);
3236     boolean dir_valid = TRUE;
3237 
3238     if (dirlen && strncmp(dir, "(null)", 6)) {
3239       if (!mainw->old_vhash || !*mainw->old_vhash || !strcmp(mainw->old_vhash, "0")) {
3240         msg = lives_strdup_printf("The backend found a workdir (%s), but claimed old version was %s !", dir, old_vhash);
3241         LIVES_WARN(msg);
3242         lives_free(msg);
3243       }
3244 
3245       if (dirlen < PATH_MAX - MAX_SET_NAME_LEN * 2) {
3246         ensure_isdir(dir);
3247 
3248         if (dirlen >= PATH_MAX - MAX_SET_NAME_LEN * 2) {
3249           dir_toolong_error(dir, (tmp = (_("working directory"))), PATH_MAX - MAX_SET_NAME_LEN * 2, TRUE);
3250           lives_free(tmp);
3251           dir_valid = FALSE;
3252         }
3253 
3254         if (!lives_make_writeable_dir(dir)) {
3255           do_dir_perm_error(dir, FALSE);
3256           dir_valid = FALSE;
3257         }
3258       }
3259 
3260       if (dir_valid) {
3261         lives_snprintf(prefs->workdir, PATH_MAX, "%s", dir);
3262         lives_snprintf(prefs->backend, PATH_MAX * 4, "%s -s \"%s\" -WORKDIR=\"%s\" -CONFIGFILE=\"%s\" --", EXEC_PERL,
3263                        capable->backend_path, prefs->workdir, prefs->configfile);
3264         lives_snprintf(prefs->backend_sync, PATH_MAX * 4, "%s", prefs->backend);
3265 
3266         set_string_pref_priority(PREF_WORKING_DIR, prefs->workdir);
3267 
3268         // for backwards compatibility only
3269         set_string_pref(PREF_WORKING_DIR_OLD, prefs->workdir);
3270       } else {
3271         needs_workdir = TRUE;
3272         prefs->startup_phase = -1;
3273       }
3274     } else {
3275       if (prefs->startup_phase != -1) {
3276         msg = lives_strdup_printf("The backend found no workdir, but set startup_phase to %d !\n%s",
3277                                   prefs->startup_phase, prefs->workdir);
3278         LIVES_ERROR(msg);
3279         lives_free(msg);
3280       }
3281       needs_workdir = TRUE;
3282       prefs->startup_phase = -1;
3283     }
3284 
3285     if (*mainw->old_vhash && strcmp(mainw->old_vhash, "0")) {
3286       if (atoi(mainw->old_vhash) < atoi(mainw->version_hash)) {
3287         if (prefs->startup_phase == 0) {
3288           msg = get_upd_msg();
3289           lives_snprintf(capable->startup_msg, 1024, "%s", msg);
3290           lives_free(msg);
3291           if (numtok > 4 && *array[4]) {
3292             lives_strappend(capable->startup_msg, 1024, array[4]);
3293 	    // *INDENT-OFF*
3294           }}}}}
3295   // *INDENT-ON*
3296 
3297   if ((prefs->startup_phase == 1 || prefs->startup_phase == -1)) {
3298     needs_workdir = TRUE;
3299   }
3300 
3301   lives_strfreev(array);
3302 
3303   ///////////////////////////////////////////////////////
3304 
3305   check_for_executable(&capable->has_md5sum, EXEC_MD5SUM);
3306   check_for_executable(&capable->has_du, EXEC_DU);
3307   check_for_executable(&capable->has_ffprobe, EXEC_FFPROBE);
3308   check_for_executable(&capable->has_sox_play, EXEC_PLAY);
3309 
3310   if (!check_for_executable(&capable->has_youtube_dl, EXEC_YOUTUBE_DL)) {
3311     check_for_executable(&capable->has_youtube_dlc, EXEC_YOUTUBE_DLC);
3312   }
3313   check_for_executable(&capable->has_sox_sox, EXEC_SOX);
3314   check_for_executable(&capable->has_dvgrab, EXEC_DVGRAB);
3315 
3316   if (!check_for_executable(&capable->has_cdda2wav, EXEC_CDDA2WAV)) {
3317     check_for_executable(&capable->has_icedax, EXEC_ICEDAX);
3318   }
3319 
3320   check_for_executable(&capable->has_jackd, EXEC_JACKD);
3321   check_for_executable(&capable->has_pulse_audio, EXEC_PULSEAUDIO);
3322 
3323   if (check_for_executable(&capable->has_python, EXEC_PYTHON)) {
3324     capable->python_version = get_version_hash(EXEC_PYTHON " -V 2>&1", " ", 1);
3325   }
3326 
3327   check_for_executable(&capable->has_xwininfo, EXEC_XWININFO);
3328   check_for_executable(&capable->has_gconftool_2, EXEC_GCONFTOOL_2);
3329   check_for_executable(&capable->has_xdg_screensaver, EXEC_XDG_SCREENSAVER);
3330 
3331   if (check_for_executable(NULL, EXEC_MIDISTART)) {
3332     check_for_executable(&capable->has_midistartstop, EXEC_MIDISTOP);
3333   }
3334 
3335   capable->ncpus = get_num_cpus();
3336   if (capable->ncpus == 0) capable->ncpus = 1;
3337 
3338   return capable;
3339 }
3340 
3341 
print_opthelp(void)3342 void print_opthelp(void) {
3343   char *tmp;
3344   print_notice();
3345 
3346   lives_printerr(_("\nStartup syntax is: %s [OPTS] [filename [start_time] [frames]]\n"), capable->myname);
3347   fprintf(stderr, "%s", _("Where: filename is the name of a media file or backup file to import\n"));
3348   fprintf(stderr, "%s", _("start_time : filename start time in seconds\n"));
3349   fprintf(stderr, "%s", _("frames : maximum number of frames to open\n"));
3350   fprintf(stderr, "%s", "\n");
3351   fprintf(stderr, "%s", _("OPTS can be:\n"));
3352   fprintf(stderr, "%s", _("-help | --help \t\t\t: print this help text on stderr and exit\n"));
3353   fprintf(stderr, "%s", _("-version | --version\t\t: print the LiVES version on stderr and exit\n"));
3354   fprintf(stderr, "%s", _("-workdir <workdir>\t\t: specify the working directory for the session, "
3355                           "overriding any value set in preferences\n"));
3356   fprintf(stderr, "%s", _("\t\t\t\t\t(disables any disk quota checking)"));
3357   fprintf(stderr, "%s", _("-configfile <path_to_file>\t: override the default configuration file for the session\n"));
3358   tmp = lives_build_filename(capable->home_dir, LIVES_DEF_CONFIG_DIR, "lives", LIVES_DEF_CONFIG_FILE, NULL);
3359   fprintf(stderr, _("\t\t\t\t\t(default is %s)\n"), tmp);
3360   lives_free(tmp);
3361 
3362   tmp = lives_build_path(capable->home_dir, LOCAL_HOME_DIR, LIVES_DEF_CONFIG_DATADIR, NULL);
3363   fprintf(stderr, "%s", _("-configdatadir <dir>\t\t: override the default configuration data directory for the session\n"));
3364   fprintf(stderr, _("\t\t\t\t\t(default is %s\n"), tmp);
3365   lives_free(tmp);
3366 
3367   fprintf(stderr, "%s", _("-dscrit <bytes>\t\t\t: temporarily sets the free disk space critical level for workdir to <bytes>\n"));
3368   fprintf(stderr, "%s", _("\t\t\t\t\t(intended to allow correction of erroneous values within the app; "
3369                           "<= 0 disables checks)\n"));
3370   fprintf(stderr, "%s", _("-set <setname>\t\t\t: autoload clip set <setname>\n"));
3371   fprintf(stderr, "%s", _("-noset\t\t\t\t: do not reload any clip set on startup (overrides -set)\n"));
3372   fprintf(stderr, "%s", _("-layout <layout_name>\t\t: autoload multitrack layout <layout_name> (if successful, "
3373                           "overrides -startup-ce)\n"));
3374   fprintf(stderr, "%s", _("-nolayout\t\t\t: do not reload any multitrack layout on startup (overrides -layout)\n"));
3375   fprintf(stderr, "%s", _("-norecover\t\t\t: force non-loading of crash recovery files (overrides -recover / -autorecover)\n"));
3376   fprintf(stderr, "%s",
3377           _("-recover | -autorecover\t\t: force reloading of any crash recovery files (may override -noset and -nolayout)\n"));
3378   fprintf(stderr, "%s", _("-nogui\t\t\t\t: do not show the gui (still shows the play window when active)\n"));
3379   fprintf(stderr, "%s", _("-nosplash\t\t\t: do not show the splash window\n"));
3380   fprintf(stderr, "%s",
3381           _("-noplaywin\t\t\t: do not show the play window (still shows the internal player; intended for remote streaming)\n"));
3382   fprintf(stderr, "%s",
3383           _("-noninteractive\t\t\t: disable menu interactivity (intended for scripting applications, e.g liblives)\n"));
3384   fprintf(stderr, "%s", _("-startup-ce\t\t\t: start in clip editor mode (overrides -startup-mt)\n"));
3385   fprintf(stderr, "%s", _("-startup-mt\t\t\t: start in multitrack mode\n"));
3386   fprintf(stderr, "%s", _("-vjmode\t\t\t\t: start in VJ mode (implicitly sets -startup-ce -autorecover "
3387                           "-nolayout -asource external)\n"));
3388   fprintf(stderr, "%s",
3389           _("-fxmodesmax <n>\t\t\t: allow <n> modes per effect key (overrides any value set in preferences; minimum is 1)\n"));
3390 #ifdef ENABLE_OSC
3391   fprintf(stderr,  _("-oscstart <port>\t\t: start OSC listener on UDP port <port> (default is %d)\n"), DEF_OSC_LISTEN_PORT);
3392   fprintf(stderr, "%s",
3393           _("-nooscstart\t\t\t: do not start the OSC listener (the default, unless set in preferences)\n"));
3394 #endif
3395   fprintf(stderr, "%s",
3396           _("-asource <source>\t\t: set the initial audio source (<source> can be 'internal' or 'external')\n"));
3397   fprintf(stderr, _("\t\t\t\t\t(only valid for %s and %s players)\n"), AUDIO_PLAYER_JACK, AUDIO_PLAYER_PULSE_AUDIO);
3398   fprintf(stderr, "%s", _("-aplayer <ap>\t\t\t: start with the selected audio player (<ap> can be: "));
3399 #ifdef HAVE_PULSE_AUDIO
3400   fprintf(stderr, "'%s'", AUDIO_PLAYER_PULSE);
3401 #endif
3402 #ifdef ENABLE_JACK
3403 #ifdef HAVE_PULSE_AUDIO
3404   fprintf(stderr, ", "); // comma after pulse
3405 #endif
3406   fprintf(stderr, "'%s'", AUDIO_PLAYER_JACK);
3407   if (capable->has_sox_play) lives_printerr(", '%s'", AUDIO_PLAYER_SOX); // comma after jack
3408   fprintf(stderr, " or '%s')\n", AUDIO_PLAYER_NONE);
3409   fprintf(stderr, "%s",
3410           _("-jackopts <opts>\t\t: opts is a bitmap of jackd startup / playback options (default is 16, "
3411             "unless set in Preferences)\n"
3412             "\t\t\t\t\t 1 = LiVES is a jack transport slave, \n"
3413             "\t\t\t\t\t 2 = LiVES is a jack transport master, \n"
3414             "\t\t\t\t\t 4 = start/stop jack transport server on LiVES playback start / stop\n"
3415             "\t\t\t\t\t\t(must be transport master), \n"
3416             "\t\t\t\t\t 8 = pause jack transport when video paused\n"
3417             "\t\t\t\t\t\t(must be transport master),\n"
3418             "\t\t\t\t\t16 = start/stop jack audio server on LiVES startup / shutdown\n"
3419             "\t\t\t\t\t\t(only if audio player is jack)) \n"));
3420 #else // no jack
3421   if (capable->has_sox_play) {
3422 #ifdef HAVE_PULSE_AUDIO
3423     fprintf(stderr, ", "); // comma after pulse
3424 #endif
3425     fprintf(stderr, _("'%s' or "), AUDIO_PLAYER_SOX);
3426   }
3427 #ifdef HAVE_PULSE_AUDIO
3428   else fprintf(stderr, "%s", _(" or ")); // no sox, 'or' after pulse
3429 #endif
3430   fprintf(stderr, "'%s')\n", AUDIO_PLAYER_NONE);
3431 #endif
3432   fprintf(stderr, "%s", _("-devicemap <mapname>\t\t: autoload devicemap <mapname> (for MIDI / joystick control)\n"));
3433   fprintf(stderr, "%s", _("-vppdefaults <file>\t\t: load defaults for video playback plugin from <file>\n"
3434                           "\t\t\t\t\t(Note: only affects the plugin settings, not the plugin type)\n"));
3435 #ifdef HAVE_YUV4MPEG
3436   fprintf(stderr, "%s",  _("-yuvin <fifo>\t\t\t: autoplay yuv4mpeg from stream <fifo> on startup\n"));
3437   fprintf(stderr, "%s", _("\t\t\t\t\t(only valid in clip edit startup mode)\n"));
3438 #endif
3439   fprintf(stderr, "%s", _("-debug\t\t\t\t: try to debug crashes (requires 'gdb' to be installed)\n"));
3440   fprintf(stderr, "%s", "\n");
3441 }
3442 
3443 //// things to do - on startup
3444 #ifdef HAVE_YUV4MPEG
open_yuv4m_startup(livespointer data)3445 static boolean open_yuv4m_startup(livespointer data) {
3446   on_open_yuv4m_activate(NULL, data);
3447   return FALSE;
3448 }
3449 #endif
3450 
3451 
3452 ///////////////////////////////// TODO - move idle functions into another file //////////////////////////////////////
3453 
render_choice_idle(livespointer data)3454 boolean render_choice_idle(livespointer data) {
3455   static boolean norecurse = FALSE;
3456   boolean rec_recovered = FALSE;
3457   boolean is_recovery = LIVES_POINTER_TO_INT(data);
3458   if (norecurse) return FALSE;
3459   if (mainw->noswitch) return TRUE;
3460   norecurse = TRUE;
3461   if (!is_recovery || mt_load_recovery_layout(NULL)) {
3462     if (mainw->event_list) {
3463       if (mainw->multitrack) {
3464         /// exit multitrack, backup mainw->event_as it will get set to NULL
3465         weed_plant_t *backup_elist = mainw->event_list;
3466         multitrack_delete(mainw->multitrack, FALSE);
3467         mainw->event_list = backup_elist;
3468       }
3469 
3470       deal_with_render_choice(is_recovery);
3471       if (is_recovery && mainw->multitrack) rec_recovered = TRUE;
3472     }
3473   }
3474   if (is_recovery) mainw->recording_recovered = rec_recovered;
3475   norecurse = FALSE;
3476   return FALSE;
3477 }
3478 
3479 
lazy_startup_checks(void * data)3480 boolean lazy_startup_checks(void *data) {
3481   static boolean checked_trash = FALSE;
3482   static boolean mwshown = FALSE;
3483   static boolean dqshown = FALSE;
3484   static boolean tlshown = FALSE;
3485   static boolean extra_caps = FALSE;
3486   static boolean is_first = TRUE;
3487 
3488   if (LIVES_IS_PLAYING) {
3489     dqshown = mwshown = tlshown = TRUE;
3490     return FALSE;
3491   }
3492 
3493   if (is_first) {
3494     if (prefs->open_maximised && prefs->show_gui)
3495       lives_window_maximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
3496     is_first = FALSE;
3497     return TRUE;
3498   }
3499 
3500   if (!tlshown) {
3501     //g_print("val is $d\n", check_snap("youtube-dl"));
3502     if (!mainw->multitrack) redraw_timeline(mainw->current_file);
3503     tlshown = TRUE;
3504     return TRUE;
3505   }
3506 
3507   if (prefs->vj_mode) {
3508     resize(1.);
3509     if (prefs->open_maximised) {
3510       int bx, by;
3511       get_border_size(LIVES_MAIN_WINDOW_WIDGET, &bx, &by);
3512       if (by > MENU_HIDE_LIM)
3513         lives_window_set_hide_titlebar_when_maximized(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), TRUE);
3514       lives_window_maximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
3515     }
3516     return FALSE;
3517   }
3518 
3519   if (mainw->dsu_widget) return TRUE;
3520 
3521   if (!checked_trash) {
3522     if (prefs->autoclean) {
3523       char *com = lives_strdup_printf("%s empty_trash . general %s", prefs->backend, TRASH_NAME);
3524       lives_system(com, FALSE);
3525       lives_free(com);
3526     }
3527     checked_trash = TRUE;
3528   }
3529   if (!dqshown) {
3530     boolean do_show_quota = prefs->show_disk_quota;
3531     if (ran_ds_dlg) do_show_quota = FALSE;
3532     dqshown = TRUE;
3533     if (mainw->helper_procthreads[PT_LAZY_DSUSED]) {
3534       if (disk_monitor_running(prefs->workdir)) {
3535         int64_t dsval = capable->ds_used = disk_monitor_check_result(prefs->workdir);
3536         mainw->ds_status = get_storage_status(prefs->workdir, mainw->next_ds_warn_level, &dsval, 0);
3537         capable->ds_free = dsval;
3538         if (capable->ds_used < 0)
3539           capable->ds_used = disk_monitor_check_result(prefs->workdir);
3540         if (!prefs->disk_quota && (mainw->ds_status == LIVES_STORAGE_STATUS_NORMAL
3541                                    || mainw->ds_status == LIVES_STORAGE_STATUS_UNKNOWN)) {
3542           if (capable->ds_used < 0) disk_monitor_forget();
3543         } else {
3544           if (capable->ds_used < 0) {
3545             capable->ds_used = disk_monitor_wait_result(prefs->workdir, LIVES_DEFAULT_TIMEOUT);
3546           }
3547         }
3548       }
3549       mainw->helper_procthreads[PT_LAZY_DSUSED] = NULL;
3550       if (capable->ds_used > prefs->disk_quota * .9 || (mainw->ds_status != LIVES_STORAGE_STATUS_NORMAL
3551           && mainw->ds_status != LIVES_STORAGE_STATUS_UNKNOWN)) {
3552         if (capable->ds_used > prefs->disk_quota * .9 && (mainw->ds_status == LIVES_STORAGE_STATUS_NORMAL
3553             || mainw->ds_status == LIVES_STORAGE_STATUS_UNKNOWN)) {
3554           mainw->ds_status = LIVES_STORAGE_STATUS_OVER_QUOTA;
3555         }
3556         do_show_quota = TRUE;
3557       }
3558     }
3559     if (do_show_quota) {
3560       run_diskspace_dialog();
3561       return TRUE;
3562     }
3563   }
3564 
3565   if (!mwshown) {
3566     mwshown = TRUE;
3567     if (prefs->show_msgs_on_startup) do_messages_window(TRUE);
3568   }
3569 
3570   if (!extra_caps) {
3571     extra_caps = TRUE;
3572     capable->boot_time = get_cpu_load(-1);
3573   }
3574 
3575   if (mainw->ldg_menuitem) {
3576     if (!RFX_LOADED) return TRUE;
3577     lives_widget_destroy(mainw->ldg_menuitem);
3578     mainw->ldg_menuitem = NULL;
3579     add_rfx_effects2(RFX_STATUS_ANY);
3580     if (LIVES_IS_SENSITIZED) sensitize(); // call fn again to sens. new menu entries
3581   }
3582 
3583   mainw->lazy = 0;
3584   return FALSE;
3585 }
3586 
3587 
resize_message_area(livespointer data)3588 boolean resize_message_area(livespointer data) {
3589   // workaround because the window manager will resize the window asynchronously
3590   static boolean isfirst = TRUE;
3591   int bx, by;
3592 
3593   if (data) isfirst = TRUE;
3594 
3595   if (!prefs->show_gui || LIVES_IS_PLAYING || mainw->is_processing || mainw->is_rendering || !prefs->show_msg_area) {
3596     mainw->assumed_height = mainw->assumed_width = -1;
3597     mainw->idlemax = 0;
3598     return FALSE;
3599   }
3600 
3601   if (mainw->idlemax-- == DEF_IDLE_MAX) mainw->msg_area_configed = FALSE;
3602 
3603   get_border_size(LIVES_MAIN_WINDOW_WIDGET, &bx, &by);
3604 
3605   if (mainw->idlemax == DEF_IDLE_MAX / 2 && prefs->open_maximised && (by > 0 || bx > 0)) {
3606     if (by > MENU_HIDE_LIM)
3607       lives_window_set_hide_titlebar_when_maximized(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), TRUE);
3608     lives_window_maximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
3609     mainw->assumed_height = mainw->assumed_width = -1;
3610     return TRUE;
3611   }
3612 
3613   if (mainw->msg_area_configed) mainw->idlemax = 0;
3614 
3615   if (mainw->idlemax > 0 && mainw->assumed_height != -1 &&
3616       mainw->assumed_height != lives_widget_get_allocation_height(LIVES_MAIN_WINDOW_WIDGET)) return TRUE;
3617   if (mainw->idlemax > 0 && lives_widget_get_allocation_height(mainw->end_image) != mainw->ce_frame_height) return TRUE;
3618 
3619   mainw->idlemax = 0;
3620   mainw->assumed_height = mainw->assumed_width = -1;
3621   msg_area_scroll(LIVES_ADJUSTMENT(mainw->msg_adj), mainw->msg_area);
3622   //#if !GTK_CHECK_VERSION(3, 0, 0)
3623   msg_area_config(mainw->msg_area);
3624   //#endif
3625   if (isfirst) {
3626     lives_widget_set_vexpand(mainw->msg_area, TRUE);
3627     if (prefs->open_maximised && prefs->show_gui) {
3628       lives_window_maximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
3629     }
3630     if (!CURRENT_CLIP_IS_VALID) {
3631       d_print("");
3632     }
3633     msg_area_scroll_to_end(mainw->msg_area, mainw->msg_adj);
3634     lives_widget_queue_draw_if_visible(mainw->msg_area);
3635     isfirst = FALSE;
3636   }
3637   resize(1.);
3638   lives_widget_queue_draw(mainw->LiVES);
3639   return FALSE;
3640 }
3641 
3642 /////////////////////////////////////////////////////////////////////////////////////////////////
3643 static boolean got_files = FALSE;
3644 static boolean lives_startup2(livespointer data);
lives_startup(livespointer data)3645 static boolean lives_startup(livespointer data) {
3646   // this is run in an idlefunc
3647 
3648   char *tmp, *tmp2, *msg;
3649 
3650   // check the working directory
3651   if (needs_workdir) {
3652     // get initial workdir
3653     if (!do_workdir_query()) {
3654       lives_exit(0);
3655     }
3656     prefs->startup_phase = 2;
3657     set_int_pref(PREF_STARTUP_PHASE, 2);
3658   }
3659   if (prefs->startup_phase > 0 && prefs->startup_phase < 3) {
3660     if (!do_startup_tests(FALSE)) {
3661       lives_exit(0);
3662     }
3663     prefs->startup_phase = 3;
3664     set_int_pref(PREF_STARTUP_PHASE, 3);
3665 
3666     // we can show this now
3667     if (prefs->show_splash) splash_init();
3668   }
3669 
3670   if (newconfigfile || prefs->startup_phase == 3) {
3671     /// CREATE prefs->config_datadir, and default items inside it
3672     build_init_config(prefs->config_datadir, ign_opts.ign_config_datadir);
3673   }
3674 
3675   get_string_pref(PREF_VID_PLAYBACK_PLUGIN, buff, 256);
3676 
3677   if (*buff && strcmp(buff, "(null)") && strcmp(buff, "none")) {
3678     mainw->vpp = open_vid_playback_plugin(buff, TRUE);
3679   } else if (prefs->startup_phase == 3) {
3680     mainw->vpp = open_vid_playback_plugin(DEFAULT_VPP, TRUE);
3681     if (mainw->vpp) {
3682       lives_snprintf(future_prefs->vpp_name, 64, "%s", mainw->vpp->name);
3683       set_string_pref(PREF_VID_PLAYBACK_PLUGIN, mainw->vpp->name);
3684     }
3685   }
3686 
3687   if (!ign_opts.ign_aplayer) {
3688     get_string_pref(PREF_AUDIO_PLAYER, buff, 256);
3689     if (!strcmp(buff, AUDIO_PLAYER_NONE)) {
3690       prefs->audio_player = AUD_PLAYER_NONE;  ///< experimental
3691       lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_NONE);
3692     } else if (!strcmp(buff, AUDIO_PLAYER_SOX)) {
3693       prefs->audio_player = AUD_PLAYER_SOX;
3694       lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_SOX);
3695     } else if (!strcmp(buff, AUDIO_PLAYER_JACK)) {
3696       prefs->audio_player = AUD_PLAYER_JACK;
3697       lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_JACK);
3698     } else if (!strcmp(buff, AUDIO_PLAYER_PULSE) || !strcmp(buff, AUDIO_PLAYER_PULSE_AUDIO)) {
3699       prefs->audio_player = AUD_PLAYER_PULSE;
3700       lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_PULSE);
3701     }
3702   } else {
3703     set_string_pref(PREF_AUDIO_PLAYER, prefs->aplayer);
3704   }
3705 
3706 #ifdef HAVE_PULSE_AUDIO
3707   if ((prefs->startup_phase == 1 || prefs->startup_phase == -1) && capable->has_pulse_audio) {
3708     if (prefs->pa_restart) {
3709       char *com = lives_strdup_printf("%s -k %s", EXEC_PULSEAUDIO, prefs->pa_start_opts);
3710       lives_system(com, TRUE);
3711       lives_free(com);
3712     }
3713     prefs->audio_player = AUD_PLAYER_PULSE;
3714     lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_PULSE);
3715     set_string_pref(PREF_AUDIO_PLAYER, AUDIO_PLAYER_PULSE);
3716   } else {
3717 #endif
3718 #ifdef ENABLE_JACK
3719     if ((prefs->startup_phase == 1 || prefs->startup_phase == -1) && capable->has_jackd && prefs->audio_player == -1) {
3720       prefs->audio_player = AUD_PLAYER_JACK;
3721       lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_JACK);
3722       set_string_pref(PREF_AUDIO_PLAYER, AUDIO_PLAYER_JACK);
3723     }
3724 #endif
3725 #ifdef HAVE_PULSE_AUDIO
3726   }
3727 #endif
3728 
3729   if (!ign_opts.ign_asource) {
3730     if (prefs->vj_mode)
3731       prefs->audio_src = AUDIO_SRC_EXT;
3732     else
3733       prefs->audio_src = get_int_prefd(PREF_AUDIO_SRC, AUDIO_SRC_INT);
3734   }
3735 
3736   if (!((prefs->audio_player == AUD_PLAYER_JACK && capable->has_jackd) || (prefs->audio_player == AUD_PLAYER_PULSE &&
3737         capable->has_pulse_audio)) && prefs->audio_src == AUDIO_SRC_EXT) {
3738     prefs->audio_src = AUDIO_SRC_INT;
3739     set_int_pref(PREF_AUDIO_SRC, prefs->audio_src);
3740   }
3741 
3742   future_prefs->audio_src = prefs->audio_src;
3743 
3744   splash_msg(_("Starting GUI..."), SPLASH_LEVEL_BEGIN);
3745   LIVES_MAIN_WINDOW_WIDGET = NULL;
3746 
3747   create_LiVES();
3748 
3749   if (prefs->open_maximised && prefs->show_gui) {
3750     int bx, by;
3751     get_border_size(LIVES_MAIN_WINDOW_WIDGET, &bx, &by);
3752     if (by > MENU_HIDE_LIM)
3753       lives_window_set_hide_titlebar_when_maximized(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), TRUE);
3754     lives_window_maximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
3755   }
3756 
3757   // needed to avoid priv->pulse2 > priv->pulse1 gtk error
3758   lives_widget_context_update();
3759 
3760   lives_widget_queue_draw(LIVES_MAIN_WINDOW_WIDGET);
3761   lives_widget_context_update();
3762 
3763   mainw->startup_error = FALSE;
3764 
3765   if (theme_error && !mainw->foreign) {
3766     // non-fatal errors
3767     msg = lives_strdup_printf(
3768             _("\n\nThe theme you requested (%s) could not be located.\n"
3769               "Please make sure you have the themes installed in\n%s/%s.\n"
3770               "(Maybe you need to change the value of <prefix_dir> in your %s file)\n"
3771               "or you may be missing a custom theme.\n"), future_prefs->theme,
3772             (tmp = lives_filename_to_utf8(prefs->prefix_dir, -1, NULL, NULL, NULL)), THEME_DIR,
3773             (tmp2 = lives_filename_to_utf8(prefs->configfile, -1, NULL, NULL, NULL)));
3774     lives_free(tmp2);
3775     lives_free(tmp);
3776     startup_message_nonfatal(msg);
3777     lives_free(msg);
3778     lives_snprintf(prefs->theme, 64, LIVES_THEME_NONE);
3779     upgrade_error = TRUE;
3780   }
3781 
3782   lives_init(&ign_opts);
3783 
3784   // non-fatal errors
3785 
3786   if (!mainw->foreign) {
3787     if (*capable->startup_msg) {
3788       if (info_only) startup_message_info(capable->startup_msg);
3789       else startup_message_nonfatal(capable->startup_msg);
3790     } else {
3791       if (!prefs->vj_mode) {
3792         if (!capable->has_mplayer && !capable->has_mplayer2 && !capable->has_mpv
3793             && !(prefs->warning_mask & WARN_MASK_NO_MPLAYER)) {
3794           startup_message_nonfatal_dismissable(
3795             _("\nLiVES was unable to locate 'mplayer','mplayer2' or 'mpv'. "
3796               "You may wish to install one of these to use LiVES more fully.\n"),
3797             WARN_MASK_NO_MPLAYER);
3798         }
3799         if (!capable->has_convert) {
3800           startup_message_nonfatal_dismissable(
3801             _("\nLiVES was unable to locate 'convert'. "
3802               "You should install convert and image-magick "
3803               "if you want to use rendered effects.\n"),
3804             WARN_MASK_NO_MPLAYER);
3805         }
3806         if (!capable->has_composite) {
3807           startup_message_nonfatal_dismissable(
3808             _("\nLiVES was unable to locate 'composite'. "
3809               "You should install composite and image-magick "
3810               "if you want to use the merge function.\n"),
3811             WARN_MASK_NO_MPLAYER);
3812         }
3813         if (!capable->has_sox_sox) {
3814           startup_message_nonfatal_dismissable(
3815             _("\nLiVES was unable to locate 'sox'. Some audio features may not work. "
3816               "You should install 'sox'.\n"),
3817             WARN_MASK_NO_MPLAYER);
3818         }
3819         if (!capable->has_encoder_plugins) {
3820           msg = lives_strdup_printf(
3821                   _("\nLiVES was unable to find any encoder plugins.\n"
3822                     "Please check that you have them installed correctly in\n%s%s%s/\n"
3823                     "You will not be able to 'Save' without them.\n"
3824                     "You may need to change the value of <lib_dir> in %s\n"),
3825                   prefs->lib_dir, PLUGIN_EXEC_DIR, PLUGIN_ENCODERS,
3826                   (tmp = lives_filename_to_utf8(prefs->configfile, -1, NULL, NULL, NULL)));
3827           lives_free(tmp);
3828           startup_message_nonfatal_dismissable(msg, WARN_MASK_NO_ENCODERS);
3829           lives_free(msg);
3830           upgrade_error = TRUE;
3831         }
3832 
3833         if (mainw->next_ds_warn_level > 0) {
3834           if (mainw->ds_status == LIVES_STORAGE_STATUS_WARNING) {
3835             uint64_t curr_ds_warn = mainw->next_ds_warn_level;
3836             mainw->next_ds_warn_level >>= 1;
3837             if (mainw->next_ds_warn_level > (capable->ds_free >> 1)) mainw->next_ds_warn_level = capable->ds_free >> 1;
3838             if (mainw->next_ds_warn_level < prefs->ds_crit_level) mainw->next_ds_warn_level = prefs->ds_crit_level;
3839             tmp = ds_warning_msg(prefs->workdir, &capable->mountpoint, capable->ds_free, curr_ds_warn, mainw->next_ds_warn_level);
3840             msg = lives_strdup_printf("\n%s\n", tmp);
3841             lives_free(tmp);
3842             startup_message_nonfatal(msg);
3843             lives_free(msg);
3844 	    // *INDENT-OFF*
3845           }}}}
3846     // *INDENT-ON*
3847     splash_msg(_("Loading rendered effect plugins..."), SPLASH_LEVEL_LOAD_RFX);
3848     // must call this at least to set up rendered_fx[0]
3849   } else {
3850     // capture mode
3851     mainw->foreign_key = atoi(zargv[2]);
3852 
3853 #if GTK_CHECK_VERSION(3, 0, 0) || defined GUI_QT
3854     mainw->foreign_id = (Window)atoi(zargv[3]);
3855 #else
3856     mainw->foreign_id = (GdkNativeWindow)atoi(zargv[3]);
3857 #endif
3858 
3859     mainw->foreign_width = atoi(zargv[4]);
3860     mainw->foreign_height = atoi(zargv[5]);
3861     lives_snprintf(prefs->image_ext, 16, "%s", zargv[6]);
3862     lives_snprintf(prefs->image_type, 16, "%s", image_ext_to_lives_image_type(prefs->image_ext));
3863     mainw->foreign_bpp = atoi(zargv[7]);
3864     mainw->rec_vid_frames = atoi(zargv[8]);
3865     mainw->rec_fps = strtod(zargv[9], NULL);
3866     mainw->rec_arate = atoi(zargv[10]);
3867     mainw->rec_asamps = atoi(zargv[11]);
3868     mainw->rec_achans = atoi(zargv[12]);
3869     mainw->rec_signed_endian = atoi(zargv[13]);
3870 
3871     if (zargc > 14) {
3872       mainw->foreign_visual = lives_strdup(zargv[14]);
3873       if (!strcmp(mainw->foreign_visual, "(null)")) {
3874         lives_free(mainw->foreign_visual);
3875         mainw->foreign_visual = NULL;
3876       }
3877     }
3878 
3879 #ifdef ENABLE_JACK
3880     if (prefs->audio_player == AUD_PLAYER_JACK && capable->has_jackd && mainw->rec_achans > 0) {
3881       lives_jack_init();
3882       jack_audio_read_init();
3883     }
3884 #endif
3885 #ifdef HAVE_PULSE_AUDIO
3886     if (prefs->audio_player == AUD_PLAYER_PULSE && capable->has_pulse_audio && mainw->rec_achans > 0) {
3887       lives_pulse_init(0);
3888       pulse_audio_read_init();
3889     }
3890 #endif
3891 
3892     lives_widget_show(LIVES_MAIN_WINDOW_WIDGET);
3893     lives_widget_context_update();
3894     mainw->go_away = FALSE;
3895     on_capture2_activate();  // exits
3896   }
3897 
3898   //#define NOTTY
3899 #ifdef NOTTY
3900   if (!mainw->foreign) {
3901     capable->xstdout = dup(STDOUT_FILENO);
3902     close(STDOUT_FILENO);
3903   }
3904 #endif
3905 
3906   if (mainw->prefs_cache) cached_list_free(&mainw->prefs_cache);
3907 
3908   if (!prefs->show_gui) lives_widget_hide(LIVES_MAIN_WINDOW_WIDGET);
3909 
3910   if (prefs->startup_phase == 100) {
3911     if (upgrade_error) {
3912       do_upgrade_error_dialog();
3913     }
3914     prefs->startup_phase = 0;
3915   }
3916 
3917   // splash_end() will start up multitrack if in STARTUP_MT mode
3918   if (*start_file && strcmp(start_file, "-")) {
3919     splash_end();
3920     deduce_file(start_file, start, end);
3921     got_files = TRUE;
3922   } else {
3923     set_main_title(NULL, 0);
3924     splash_end();
3925   }
3926 
3927   if (prefs->startup_phase == 0) show_lives();
3928   mainw->is_ready = TRUE;
3929 
3930   if (!strcmp(buff, AUDIO_PLAYER_SOX)) {
3931     switch_aud_to_sox(FALSE);
3932   }
3933   if (!strcmp(buff, AUDIO_PLAYER_NONE)) {
3934     // still experimental
3935     switch_aud_to_none(FALSE);
3936   }
3937 
3938   lives_idle_add_simple(lives_startup2, NULL);
3939   return FALSE;
3940 }
3941 
3942 
lives_startup2(livespointer data)3943 static boolean lives_startup2(livespointer data) {
3944   char *ustr;
3945   boolean layout_recovered = FALSE;
3946 
3947   if (prefs->crash_recovery && !no_recover) got_files = check_for_recovery_files(auto_recover);
3948 
3949   if (!mainw->foreign && !got_files && prefs->ar_clipset) {
3950     d_print(lives_strdup_printf(_("Autoloading set %s..."), prefs->ar_clipset_name));
3951     if (!reload_set(prefs->ar_clipset_name) || mainw->current_file == -1) {
3952       set_string_pref(PREF_AR_CLIPSET, "");
3953       prefs->ar_clipset = FALSE;
3954     }
3955     future_prefs->ar_clipset = FALSE;
3956   }
3957 
3958 #ifdef ENABLE_OSC
3959   if (prefs->osc_start) prefs->osc_udp_started = lives_osc_init(prefs->osc_udp_port);
3960 #endif
3961 
3962   if (mainw->recoverable_layout) {
3963     if (!prefs->vj_mode) layout_recovered = do_layout_recover_dialog();
3964     else mainw->recoverable_layout = FALSE;
3965   }
3966 
3967   if (!mainw->recording_recovered) {
3968     if (mainw->ascrap_file != -1) {
3969       if (!layout_recovered || !mainw->multitrack || !used_in_current_layout(mainw->multitrack, mainw->ascrap_file)) {
3970         close_ascrap_file(FALSE); // ignore but leave file on disk for recovery purposes
3971       }
3972     }
3973     if (mainw->scrap_file != -1) {
3974       if (!layout_recovered || mainw->multitrack || !used_in_current_layout(mainw->multitrack, mainw->scrap_file)) {
3975         close_scrap_file(FALSE); // ignore but leave file on disk for recovery purposes
3976       }
3977     }
3978   } else {
3979     if (mainw->multitrack) multitrack_delete(mainw->multitrack, FALSE);
3980   }
3981 
3982 #ifdef HAVE_YUV4MPEG
3983   if (*prefs->yuvin) lives_idle_add_simple(open_yuv4m_startup, NULL);
3984 #endif
3985 
3986   mainw->no_switch_dprint = TRUE;
3987   if (mainw->current_file > -1 && !mainw->multitrack) {
3988     switch_clip(1, mainw->current_file, TRUE);
3989   }
3990 
3991   if (!palette || !(palette->style & STYLE_LIGHT)) {
3992     lives_widget_set_opacity(mainw->sep_image, 0.4);
3993   } else {
3994     lives_widget_set_opacity(mainw->sep_image, 0.8);
3995   }
3996   lives_widget_queue_draw(mainw->sep_image);
3997 
3998   if (*devmap) on_devicemap_load_activate(NULL, devmap);
3999 
4000   if (capable->username)
4001     ustr = lives_strdup_printf(", %s", capable->username);
4002   else
4003     ustr = lives_strdup("");
4004 
4005   d_print(_("\nWelcome to LiVES version %s%s !\n"), LiVES_VERSION, ustr);
4006   lives_free(ustr);
4007 
4008   mainw->no_switch_dprint = FALSE;
4009   d_print("");
4010 
4011   if (!mainw->multitrack) {
4012     if (mainw->current_file == -1) {
4013       resize(1.);
4014       if (prefs->show_msg_area) {
4015         // the message area must fit exactly to the screen size, so we update it in an idle function
4016         // due to the fact that the window manager may resize the window asynchronously
4017         if (mainw->idlemax == 0)
4018           lives_idle_add_simple(resize_message_area, NULL);
4019         mainw->idlemax = DEF_IDLE_MAX;
4020       }
4021     }
4022   } else {
4023     lives_idle_add_simple(mt_idle_show_current_frame, (livespointer)mainw->multitrack);
4024     if (mainw->multitrack->idlefunc == 0) {
4025       mainw->multitrack->idlefunc = mt_idle_add(mainw->multitrack);
4026     }
4027   }
4028 
4029   mainw->go_away = FALSE;
4030   if (!mainw->multitrack) sensitize();
4031 
4032   if (prefs->vj_mode) {
4033     char *wid = lives_strdup_printf("0x%08lx",
4034                                     (uint64_t)LIVES_XWINDOW_XID(lives_widget_get_xwindow(LIVES_MAIN_WINDOW_WIDGET)));
4035     if (wid) activate_x11_window(wid);
4036   }
4037   if (mainw->recording_recovered) {
4038     lives_idle_add_simple(render_choice_idle, LIVES_INT_TO_POINTER(TRUE));
4039   }
4040 
4041   mainw->overlay_alarm = lives_alarm_set(0);
4042 
4043   if (!mainw->multitrack)
4044     lives_notify_int(LIVES_OSC_NOTIFY_MODE_CHANGED, STARTUP_CE);
4045   else
4046     lives_notify_int(LIVES_OSC_NOTIFY_MODE_CHANGED, STARTUP_MT);
4047 
4048   if (!prefs->vj_mode && !prefs->startup_phase) {
4049     mainw->helper_procthreads[PT_LAZY_RFX] =
4050       lives_proc_thread_create(LIVES_THRDATTR_NONE, (lives_funcptr_t)add_rfx_effects, -1, "i", RFX_STATUS_ANY);
4051   }
4052 
4053   mainw->lazy = lives_idle_add_simple(lazy_startup_checks, NULL);
4054 
4055   // timer to poll for external commands: MIDI, joystick, jack transport, osc, etc.
4056   mainw->kb_timer = lives_timer_add_simple(EXT_TRIGGER_INTERVAL, &ext_triggers_poll, NULL);
4057 
4058   if (!CURRENT_CLIP_IS_VALID) lives_ce_update_timeline(0, 0.);
4059 
4060   if (newconfigfile) {
4061     cleanup_old_config();
4062     lives_free(newconfigfile);
4063   }
4064 
4065   if (!mainw->mute) {
4066     lives_widget_set_opacity(mainw->m_mutebutton, .75);
4067   }
4068   lives_widget_set_opacity(mainw->m_sepwinbutton, .75);
4069   lives_widget_set_opacity(mainw->m_loopbutton, .75);
4070 
4071   if (prefs->interactive) set_interactive(TRUE);
4072 
4073   return FALSE;
4074 } // end lives_startup2()
4075 
4076 
set_signal_handlers(SignalHandlerPointer sigfunc)4077 void set_signal_handlers(SignalHandlerPointer sigfunc) {
4078   sigset_t smask;
4079   struct sigaction sact;
4080 
4081   sigemptyset(&smask);
4082 
4083 #define USE_GLIB_SIGHANDLER
4084 #ifdef USE_GLIB_SIGHANDLER
4085   g_unix_signal_add(LIVES_SIGINT, glib_sighandler, LIVES_INT_TO_POINTER(LIVES_SIGINT));
4086   g_unix_signal_add(LIVES_SIGTERM, glib_sighandler, LIVES_INT_TO_POINTER(LIVES_SIGTERM));
4087 #else
4088   sigaddset(&smask, LIVES_SIGINT);
4089   sigaddset(&smask, LIVES_SIGTERM);
4090 #endif
4091 
4092   sigaddset(&smask, LIVES_SIGSEGV);
4093   sigaddset(&smask, LIVES_SIGABRT);
4094 
4095   sact.sa_handler = sigfunc;
4096   sact.sa_flags = 0;
4097   sact.sa_mask = smask;
4098 
4099   sigaction(LIVES_SIGINT, &sact, NULL);
4100   sigaction(LIVES_SIGTERM, &sact, NULL);
4101   sigaction(LIVES_SIGSEGV, &sact, NULL);
4102   sigaction(LIVES_SIGABRT, &sact, NULL);
4103 
4104   if (mainw) {
4105     if (sigfunc == defer_sigint) mainw->signals_deferred = TRUE;
4106     else mainw->signals_deferred = FALSE;
4107   }
4108 }
4109 
4110 
real_main(int argc,char * argv[],pthread_t * gtk_thread,ulong id)4111 int real_main(int argc, char *argv[], pthread_t *gtk_thread, ulong id) {
4112   weed_error_t werr;
4113   ssize_t mynsize;
4114   char cdir[PATH_MAX];
4115   boolean toolong = FALSE;
4116   char *tmp, *dir, *msg;
4117   pthread_mutexattr_t mattr;
4118 #ifndef IS_LIBLIVES
4119   weed_plant_t *test_plant;
4120 #endif
4121 
4122   mainw = NULL;
4123   prefs = NULL;
4124   capable = NULL;
4125 
4126   set_signal_handlers((SignalHandlerPointer)catch_sigint);
4127 
4128   lives_memset(&ign_opts, 0, sizeof(ign_opts));
4129 
4130 #ifdef ENABLE_OIL
4131   oil_init();
4132 #endif
4133 
4134   init_memfuncs();
4135 
4136 #ifdef IS_LIBLIVES
4137 #ifdef GUI_GTK
4138   if (gtk_thread) {
4139     pthread_create(gtk_thread, NULL, gtk_thread_wrapper, NULL);
4140   }
4141 #endif
4142 #endif
4143 
4144   capable = (capability *)lives_calloc(1, sizeof(capability));
4145   capable->cacheline_size = sizeof(void *) * 8;
4146 
4147   // _runtime_ byte order, needed for lives_strlen and other things
4148   if (IS_BIG_ENDIAN)
4149     capable->byte_order = LIVES_BIG_ENDIAN;
4150   else
4151     capable->byte_order = LIVES_LITTLE_ENDIAN;
4152 
4153   capable->main_thread = pthread_self();
4154 
4155   zargc = argc;
4156   zargv = argv;
4157 
4158   //setlocale(LC_ALL, "");
4159 
4160   // force decimal point to be a "."
4161   putenv("LC_NUMERIC=C");
4162   setlocale(LC_NUMERIC, "C");
4163 
4164 #ifdef ENABLE_NLS
4165   textdomain(GETTEXT_PACKAGE);
4166   bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
4167 #ifdef UTF8_CHARSET
4168   bind_textdomain_codeset(GETTEXT_PACKAGE, nl_langinfo(CODESET));
4169 #endif
4170 #endif
4171 
4172 #ifdef GDK_WINDOWING_X11
4173   XInitThreads();
4174 #endif
4175 
4176 #ifdef GUI_GTK
4177 #if GTK_CHECK_VERSION(4, 0, 0)
4178   gtk_init();
4179 #else
4180   gtk_init(&argc, &argv);
4181 #endif
4182 #endif
4183 
4184   g_log_set_default_handler(lives_log_handler, NULL);
4185 
4186   //gtk_window_set_interactive_debugging(TRUE);
4187 #ifndef LIVES_NO_DEBUG
4188   g_printerr("FULL DEBUGGING IS ON !!\n");
4189 #endif
4190 
4191 #ifndef IS_LIBLIVES
4192   // start up the Weed system
4193   weed_abi_version = weed_get_abi_version();
4194   if (weed_abi_version > WEED_ABI_VERSION) weed_abi_version = WEED_ABI_VERSION;
4195   //werr = weed_init(weed_abi_version, WEED_INIT_DEBUGMODE);
4196   werr = weed_init(weed_abi_version, 0);
4197   if (werr != WEED_SUCCESS) {
4198     lives_notify(LIVES_OSC_NOTIFY_QUIT, "Failed to init Weed");
4199     LIVES_FATAL("Failed to init Weed");
4200     _exit(1);
4201   }
4202 #ifndef USE_STD_MEMFUNCS
4203   weed_utils_set_custom_memfuncs(lives_malloc, lives_calloc, lives_memcpy, NULL, lives_free);
4204 #endif
4205 #endif
4206 
4207   // backup the core functions so we can override them
4208   _weed_plant_new = weed_plant_new;
4209   _weed_plant_free = weed_plant_free;
4210   _weed_leaf_set = weed_leaf_set;
4211   _weed_leaf_get = weed_leaf_get;
4212   _weed_leaf_delete = weed_leaf_delete;
4213   _weed_plant_list_leaves = weed_plant_list_leaves;
4214   _weed_leaf_num_elements = weed_leaf_num_elements;
4215   _weed_leaf_element_size = weed_leaf_element_size;
4216   _weed_leaf_seed_type = weed_leaf_seed_type;
4217   _weed_leaf_get_flags = weed_leaf_get_flags;
4218   _weed_leaf_set_flags = weed_leaf_set_flags;
4219 
4220   mainw = (mainwindow *)(lives_calloc(1, sizeof(mainwindow)));
4221   init_random();
4222 
4223 #ifdef ENABLE_DIAGNOSTICS
4224   run_weed_startup_tests();
4225   check_random();
4226   lives_struct_test();
4227   test_palette_conversions();
4228 #endif
4229 
4230   // allow us to set immutable values (plugins can't)
4231   weed_leaf_set = weed_leaf_set_host;
4232 
4233   // allow us to delete undeletable leaves (plugins can't)
4234   weed_leaf_delete = weed_leaf_delete_host;
4235 
4236   // allow us to set immutable values (plugins can't)
4237   //weed_leaf_get = weed_leaf_get_monitor;
4238 
4239   // allow us to free undeletable plants (plugins cant')
4240   weed_plant_free = weed_plant_free_host;
4241   // weed_plant_new = weed_plant_new_host;
4242 
4243   init_colour_engine();
4244 
4245   weed_threadsafe = FALSE;
4246   test_plant = weed_plant_new(0);
4247   if (weed_leaf_set_private_data(test_plant, WEED_LEAF_TYPE, NULL) == WEED_ERROR_CONCURRENCY)
4248     weed_threadsafe = TRUE;
4249   else weed_threadsafe = FALSE;
4250   weed_plant_free(test_plant);
4251 
4252   widget_helper_init();
4253 
4254   /* TRANSLATORS: localised name may be used here */
4255   lives_set_application_name(_("LiVES"));
4256   widget_opts.title_prefix = lives_strdup_printf("%s-%s: - ", lives_get_application_name(), LiVES_VERSION);
4257 
4258   // init prefs
4259   prefs = (_prefs *)lives_calloc(1, sizeof(_prefs));
4260   future_prefs = (_future_prefs *)lives_calloc(1, sizeof(_future_prefs));
4261   prefs->workdir[0] = '\0';
4262   future_prefs->workdir[0] = '\0';
4263   prefs->config_datadir[0] = '\0';
4264   prefs->configfile[0] = '\0';
4265 
4266   prefs->show_gui = TRUE;
4267   prefs->show_splash = FALSE;
4268   prefs->show_playwin = TRUE;
4269   prefs->show_dev_opts = FALSE;
4270   prefs->interactive = TRUE;
4271   prefs->show_disk_quota = FALSE;
4272 
4273   lives_snprintf(prefs->cmd_log, PATH_MAX, LIVES_DEVNULL);
4274 
4275 #ifdef HAVE_YUV4MPEG
4276   prefs->yuvin[0] = '\0';
4277 #endif
4278 
4279   mainw->version_hash = lives_strdup_printf("%d", verhash(LiVES_VERSION));
4280   mainw->mgeom = NULL;
4281   mainw->msg[0] = '\0';
4282   mainw->error = FALSE;
4283   mainw->is_exiting = FALSE;
4284   mainw->multitrack = NULL;
4285   mainw->splash_window = NULL;
4286   mainw->is_ready = mainw->fatal = FALSE;
4287   mainw->memok = TRUE;
4288   mainw->go_away = TRUE;
4289   mainw->last_dprint_file = mainw->current_file = mainw->playing_file = -1;
4290   mainw->no_context_update = FALSE;
4291   mainw->ce_thumbs = FALSE;
4292   mainw->LiVES = NULL;
4293   mainw->suppress_dprint = FALSE;
4294   mainw->clutch = TRUE;
4295   mainw->mbar_res = 0;
4296   mainw->max_textsize = N_TEXT_SIZES;
4297   mainw->no_configs = FALSE;
4298 
4299   pthread_mutexattr_init(&mattr);
4300   pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
4301 
4302   mainw->has_session_workdir = FALSE;
4303   mainw->old_vhash = NULL;
4304 
4305   mainw->prefs_cache = mainw->hdrs_cache = mainw->gen_cache = NULL;
4306 
4307   // mainw->foreign is set if we are grabbing an external window
4308   mainw->foreign = FALSE;
4309 
4310   mainw->debug = FALSE;
4311 
4312   mainw->sense_state = LIVES_SENSE_STATE_INSENSITIZED;
4313 
4314   prefs->max_modes_per_key = atoi(DEF_FX_KEYMODES);
4315 
4316   devmap[0] = '\0';
4317   capable->mountpoint = NULL;
4318   capable->startup_msg[0] = '\0';
4319   capable->has_perl = TRUE;
4320   capable->has_smogrify = TRUE;
4321   capable->smog_version_correct = TRUE;
4322   capable->can_read_from_config = TRUE;
4323   capable->can_write_to_config = TRUE;
4324   capable->can_write_to_config_backup = TRUE;
4325   capable->can_write_to_config_new = TRUE;
4326   capable->can_write_to_workdir = TRUE;
4327 
4328   // this is the version we should pass into mkdir
4329   capable->umask = umask(0);
4330   umask(capable->umask);
4331   capable->umask = (0777 & ~capable->umask);
4332 
4333 #ifdef GUI_GTK
4334   lives_snprintf(capable->home_dir, PATH_MAX, "%s", g_get_home_dir());
4335 #else
4336   tmp = getenv("HOME");
4337   lives_snprintf(capable->home_dir, PATH_MAX, "%s", tmp);
4338   lives_free(tmp);
4339 #endif
4340 
4341   ensure_isdir(capable->home_dir);
4342   get_location("touch", capable->touch_cmd, PATH_MAX); // needed for make_writeable_dir()
4343   get_location("rm", capable->rm_cmd, PATH_MAX); // ditto
4344   get_location("rmdir", capable->rmdir_cmd, PATH_MAX); // ditto
4345   get_location("sed", capable->sed_cmd, PATH_MAX); // nice to know
4346   get_location("grep", capable->grep_cmd, PATH_MAX); // ditto
4347   get_location("wc", capable->wc_cmd, PATH_MAX); // ditto
4348 
4349   // get opts first
4350   if (argc > 1) {
4351     if (!strcmp(argv[1], "-capture")) {
4352       // special mode for grabbing external window
4353       mainw->foreign = TRUE;
4354       future_prefs->audio_src = prefs->audio_src = AUDIO_SRC_EXT;
4355       ign_opts.ign_asource = TRUE;
4356     } else if (!strcmp(argv[1], "-help") || !strcmp(argv[1], "--help")) {
4357       char string[256];
4358       get_location(EXEC_PLAY, string, 256);
4359       if (*string) capable->has_sox_play = TRUE;
4360 
4361       capable->myname_full = lives_find_program_in_path(argv[0]);
4362 
4363       if ((mynsize = lives_readlink(capable->myname_full, cdir, PATH_MAX)) != -1) {
4364         lives_memset(cdir + mynsize, 0, 1);
4365         lives_free(capable->myname_full);
4366         capable->myname_full = lives_strdup(cdir);
4367       }
4368 
4369       lives_snprintf(cdir, PATH_MAX, "%s", capable->myname_full);
4370       get_basename(cdir);
4371       capable->myname = lives_strdup(cdir);
4372 
4373       print_opthelp();
4374       exit(0);
4375     } else if (!strcmp(argv[1], "-version") || !strcmp(argv[1], "--version")) {
4376       print_notice();
4377       exit(0);
4378     } else {
4379       struct option longopts[] = {
4380         {"aplayer", 1, 0, 0},
4381         {"asource", 1, 0, 0},
4382         {"workdir", 1, 0, 0},
4383         {"configfile", 1, 0, 0},
4384         {"configdatadir", 1, 0, 0},
4385         {"dscrit", 1, 0, 0},
4386         {"set", 1, 0, 0},
4387         {"noset", 0, 0, 0},
4388 #ifdef ENABLE_OSC
4389         {"devicemap", 1, 0, 0},
4390 #endif
4391         {"vppdefaults", 1, 0, 0},
4392         {"recover", 0, 0, 0},
4393         {"autorecover", 0, 0, 0},
4394         {"norecover", 0, 0, 0},
4395         {"nogui", 0, 0, 0},
4396         {"nosplash", 0, 0, 0},
4397         {"noplaywin", 0, 0, 0},
4398         {"noninteractive", 0, 0, 0},
4399         {"startup-ce", 0, 0, 0},
4400         {"startup-mt", 0, 0, 0},
4401         {"vjmode", 0, 0, 0},
4402         {"fxmodesmax", 1, 0, 0},
4403         {"yuvin", 1, 0, 0},
4404         {"debug", 0, 0, 0},
4405 #ifdef ENABLE_OSC
4406         {"oscstart", 1, 0, 0},
4407         {"nooscstart", 0, 0, 0},
4408 #endif
4409 #ifdef ENABLE_JACK
4410         {"jackopts", 1, 0, 0},
4411 #endif
4412         // deprecated
4413         {"nothreaddialog", 0, 0, 0},
4414         {"bigendbug", 1, 0, 0},
4415         {"tmpdir", 1, 0, 0},
4416         {0, 0, 0, 0}
4417       };
4418 
4419       int option_index = 0;
4420       const char *charopt;
4421       int c;
4422       int count = 0;
4423 
4424       while (1) {
4425         count++;
4426         c = getopt_long_only(argc, argv, "", longopts, &option_index);
4427         if (c == -1) break; // end of options
4428         charopt = longopts[option_index].name;
4429         if (c == '?') {
4430           msg = lives_strdup_printf(_("Invalid option %s on commandline\n"), argv[count]);
4431           LIVES_FATAL(msg);
4432         }
4433         if (!strcmp(charopt, "workdir") || !strcmp(charopt, "tmpdir")) {
4434           if (!*optarg) {
4435             do_abortblank_error(charopt);
4436             continue;
4437           }
4438           if (optarg[0] == '-') {
4439             do_abortblank_error(charopt);
4440             optind--;
4441             continue;
4442           }
4443           if (lives_strlen(optarg) > PATH_MAX - MAX_SET_NAME_LEN * 2) {
4444             toolong = TRUE;
4445           } else {
4446             ensure_isdir(optarg);
4447             if (lives_strlen(optarg) > PATH_MAX - MAX_SET_NAME_LEN * 2) {
4448               toolong = TRUE;
4449             }
4450           }
4451           if (toolong) {
4452             dir_toolong_error(optarg, (tmp = (_("working directory"))), PATH_MAX - MAX_SET_NAME_LEN * 2, TRUE);
4453             lives_free(tmp);
4454             capable->can_write_to_workdir = FALSE;
4455             break;
4456           }
4457 
4458           mainw->has_session_workdir = TRUE;
4459           lives_snprintf(prefs->workdir, PATH_MAX, "%s", optarg);
4460 
4461           if (!lives_make_writeable_dir(prefs->workdir)) {
4462             // abort if we cannot write to the specified workdir
4463             capable->can_write_to_workdir = FALSE;
4464             break;
4465           }
4466           continue;
4467         }
4468 
4469         if (!strcmp(charopt, "configdatadir")) {
4470           if (!*optarg) {
4471             do_abortblank_error(charopt);
4472             continue;
4473           }
4474           if (optarg[0] == '-') {
4475             do_abortblank_error(charopt);
4476             optind--;
4477             continue;
4478           }
4479           if (lives_strlen(optarg) > PATH_MAX - 64) {
4480             toolong = TRUE;
4481           } else {
4482             ensure_isdir(optarg);
4483             if (lives_strlen(optarg) > PATH_MAX - 64) {
4484               toolong = TRUE;
4485             }
4486           }
4487           if (toolong) {
4488             /// FALSE => exit via startup_msg_fatal()
4489             dir_toolong_error(optarg, _("config data directory"), PATH_MAX - 64, FALSE);
4490           }
4491 
4492           lives_snprintf(prefs->config_datadir, PATH_MAX, "%s", optarg);
4493           ign_opts.ign_config_datadir = TRUE;
4494           continue;
4495         }
4496 
4497         if (!strcmp(charopt, "configfile")) {
4498           if (!*optarg) {
4499             do_abortblank_error(charopt);
4500             continue;
4501           }
4502           if (optarg[0] == '-') {
4503             do_abortblank_error(charopt);
4504             optind--;
4505             continue;
4506           }
4507           if (lives_strlen(optarg) > PATH_MAX - 64) {
4508             toolong = TRUE;
4509           }
4510           if (toolong) {
4511             /// FALSE => exit via startup_msg_fatal()
4512             filename_toolong_error(optarg, _("configuration file"), PATH_MAX, FALSE);
4513           }
4514 
4515           lives_snprintf(prefs->configfile, PATH_MAX, "%s", optarg);
4516           ign_opts.ign_configfile = TRUE;
4517           continue;
4518         }
4519 
4520         if (!strcmp(charopt, "norecover")) {
4521           // auto no-recovery
4522           no_recover = TRUE;
4523           continue;
4524         }
4525 
4526         if (!strcmp(charopt, "recover") || !strcmp(charopt, "autorecover")) {
4527           // auto recovery
4528           auto_recover = TRUE;
4529           continue;
4530         }
4531 
4532         if (!strcmp(charopt, "debug")) {
4533           // debug crashes
4534           mainw->debug = TRUE;
4535           continue;
4536         }
4537 
4538         if (!strcmp(charopt, "yuvin")) {
4539 #ifdef HAVE_YUV4MPEG
4540           char *dir;
4541           if (!*optarg) {
4542             continue;
4543           }
4544           if (optarg[0] == '-') {
4545             optind--;
4546             continue;
4547           }
4548           lives_snprintf(prefs->yuvin, PATH_MAX, "%s", optarg);
4549           prefs->startup_interface = STARTUP_CE;
4550           ign_opts.ign_stmode = TRUE;
4551           dir = get_dir(prefs->yuvin);
4552           get_basename(prefs->yuvin);
4553           lives_snprintf(prefs->yuvin, PATH_MAX, "%s", (tmp = lives_build_filename(dir, prefs->yuvin, NULL)));
4554           lives_free(tmp);
4555           lives_free(dir);
4556 #else
4557           msg = (_("Must have mjpegtools installed for -yuvin to work"));
4558           do_abort_ok_dialog(msg);
4559           lives_free(msg);
4560 #endif
4561           continue;
4562         }
4563 
4564         if (!strcmp(charopt, "dscrit") && optarg) {
4565           // force clipset loading
4566           if (!*optarg) {
4567             do_abortblank_error(charopt);
4568             continue;
4569           }
4570           if (optarg[0] == '-') {
4571             do_abortblank_error(charopt);
4572             optind--;
4573             continue;
4574           }
4575           prefs->ds_crit_level = atoll(optarg);
4576           ign_opts.ign_dscrit = TRUE;
4577           continue;
4578         }
4579 
4580         if (!strcmp(charopt, "noset")) {
4581           // override clipset loading
4582           lives_memset(prefs->ar_clipset_name, 0, 1);
4583           prefs->ar_clipset = FALSE;
4584           ign_opts.ign_clipset = TRUE;
4585           continue;
4586         }
4587 
4588         if (!strcmp(charopt, "set") && optarg) {
4589           // force clipset loading
4590           if (!*optarg) {
4591             do_abortblank_error(charopt);
4592             continue;
4593           }
4594           if (optarg[0] == '-') {
4595             do_abortblank_error(charopt);
4596             optind--;
4597             continue;
4598           }
4599           if (!is_legal_set_name(optarg, TRUE, TRUE)) {
4600             msg = (_("Abort and retry or continue ?"));
4601             do_abort_ok_dialog(msg);
4602             lives_free(msg);
4603           }
4604           lives_snprintf(prefs->ar_clipset_name, 128, "%s", optarg);
4605           prefs->ar_clipset = TRUE;
4606           ign_opts.ign_clipset = TRUE;
4607           continue;
4608         }
4609 
4610         if (!strcmp(charopt, "nolayout")) {
4611           // override layout loading
4612           lives_memset(prefs->ar_layout_name, 0, 1);
4613           prefs->ar_layout = FALSE;
4614           ign_opts.ign_layout = TRUE;
4615           continue;
4616         }
4617 
4618         if (!strcmp(charopt, "layout") && optarg) {
4619           // force layout loading
4620           if (!*optarg) {
4621             do_optarg_blank_err(charopt);
4622             continue;
4623           }
4624           if (optarg[0] == '-') {
4625             do_optarg_blank_err(charopt);
4626             optind--;
4627             continue;
4628           }
4629           lives_snprintf(prefs->ar_layout_name, PATH_MAX, "%s", optarg);
4630           prefs->ar_layout = TRUE;
4631           ign_opts.ign_layout = TRUE;
4632           continue;
4633         }
4634 
4635 #ifdef ENABLE_OSC
4636         if (!strcmp(charopt, "devicemap") && optarg) {
4637           // force devicemap loading
4638           char *devmap2;
4639           if (!*optarg) {
4640             do_optarg_blank_err(charopt);
4641             continue;
4642           }
4643           if (optarg[0] == '-') {
4644             do_optarg_blank_err(charopt);
4645             optind--;
4646             continue;
4647           }
4648           lives_snprintf(devmap, PATH_MAX, "%s", optarg);
4649           devmap2 = lives_strdup(devmap);
4650           get_basename(devmap);
4651           if (!strcmp(devmap, devmap2)) {
4652             dir = lives_build_filename(prefs->config_datadir, LIVES_DEVICEMAP_DIR, NULL);
4653           } else dir = get_dir(devmap);
4654           lives_snprintf(devmap, PATH_MAX, "%s", (tmp = lives_build_filename(dir, devmap, NULL)));
4655           lives_free(tmp);
4656           lives_free(dir);
4657           lives_free(devmap2);
4658           continue;
4659         }
4660 #endif
4661 
4662         if (!strcmp(charopt, "vppdefaults") && optarg) {
4663           // load alternate vpp file
4664           if (!*optarg) {
4665             do_optarg_blank_err(charopt);
4666             continue;
4667           }
4668           if (optarg[0] == '-') {
4669             do_optarg_blank_err(charopt);
4670             optind--;
4671             continue;
4672           }
4673           lives_snprintf(mainw->vpp_defs_file, PATH_MAX, "%s", optarg);
4674           ign_opts.ign_vppdefs = TRUE;
4675           dir = get_dir(mainw->vpp_defs_file);
4676           get_basename(mainw->vpp_defs_file);
4677           lives_snprintf(mainw->vpp_defs_file, PATH_MAX, "%s", (tmp = lives_build_filename(dir, mainw->vpp_defs_file, NULL)));
4678           lives_free(tmp);
4679           lives_free(dir);
4680           continue;
4681         }
4682 
4683         if (!strcmp(charopt, "aplayer")) {
4684           boolean apl_valid = FALSE;
4685           if (!*optarg) {
4686             do_optarg_blank_err(charopt);
4687             continue;
4688           }
4689           if (optarg[0] == '-') {
4690             do_optarg_blank_err(charopt);
4691             optind--;
4692             continue;
4693           }
4694           lives_snprintf(buff, 256, "%s", optarg);
4695           // override aplayer default
4696           if (!strcmp(buff, AUDIO_PLAYER_SOX)) {
4697             prefs->audio_player = AUD_PLAYER_SOX;
4698             lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_SOX);
4699             apl_valid = TRUE;
4700           }
4701 
4702           if (!strcmp(buff, AUDIO_PLAYER_NONE)) {
4703             // still experimental
4704             prefs->audio_player = AUD_PLAYER_NONE;
4705             lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_NONE);
4706             apl_valid = TRUE;
4707           }
4708 
4709           if (!strcmp(buff, AUDIO_PLAYER_JACK)) {
4710 #ifdef ENABLE_JACK
4711             prefs->audio_player = AUD_PLAYER_JACK;
4712             lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_JACK);
4713             apl_valid = TRUE;
4714 #endif
4715           }
4716 
4717           if (!strcmp(buff, AUDIO_PLAYER_PULSE) || !strcmp(buff, AUDIO_PLAYER_PULSE_AUDIO)) {
4718 #ifdef HAVE_PULSE_AUDIO
4719             prefs->audio_player = AUD_PLAYER_PULSE;
4720             lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_PULSE);
4721             apl_valid = TRUE;
4722 #endif
4723           }
4724           if (apl_valid) ign_opts.ign_aplayer = TRUE;
4725           else {
4726             msg = lives_strdup_printf(_("Invalid audio player %s"), buff);
4727             LIVES_ERROR(msg);
4728             lives_free(msg);
4729           }
4730           continue;
4731         }
4732 
4733         if (!strcmp(charopt, "asource")) {
4734           if (!*optarg) {
4735             do_optarg_blank_err(charopt);
4736             continue;
4737           }
4738           if (optarg[0] == '-') {
4739             do_optarg_blank_err(charopt);
4740             optind--;
4741             continue;
4742           }
4743           lives_snprintf(buff, 256, "%s", optarg);
4744           // override audio source
4745           if (!strcmp(buff, _("external")) || !strcmp(buff, "external")) { // handle translated and original strings
4746             future_prefs->audio_src = prefs->audio_src = AUDIO_SRC_EXT;
4747             ign_opts.ign_asource = TRUE;
4748           } else if (strcmp(buff, _("internal")) && strcmp(buff, "internal")) { // handle translated and original strings
4749             fprintf(stderr, _("Invalid audio source %s\n"), buff);
4750           } else {
4751             future_prefs->audio_src = prefs->audio_src = AUDIO_SRC_INT;
4752             ign_opts.ign_asource = TRUE;
4753           }
4754           continue;
4755         }
4756 
4757         if (!strcmp(charopt, "nogui")) {
4758           // force headless mode
4759           prefs->show_gui = FALSE;
4760           continue;
4761         }
4762 
4763         if (!strcmp(charopt, "nosplash")) {
4764           // do not show splash
4765           prefs->show_splash = FALSE;
4766           continue;
4767         }
4768 
4769         if (!strcmp(charopt, "noplaywin")) {
4770           // do not show the play window
4771           prefs->show_playwin = FALSE;
4772           continue;
4773         }
4774 
4775         if (!strcmp(charopt, "noninteractive")) {
4776           // disable menu/toolbar interactivity
4777           prefs->interactive = FALSE;
4778           continue;
4779         }
4780 
4781         if (!strcmp(charopt, "nothreaddialog")) {
4782           continue;
4783         }
4784 
4785         if (!strcmp(charopt, "fxmodesmax") && optarg) {
4786           if (!*optarg) {
4787             do_optarg_blank_err(charopt);
4788             continue;
4789           }
4790           if (optarg[0] == '-') {
4791             do_optarg_blank_err(charopt);
4792             optind--;
4793             continue;
4794           }
4795           // set number of fx modes
4796           prefs->max_modes_per_key = atoi(optarg);
4797           if (prefs->max_modes_per_key < 1) prefs->max_modes_per_key = 1;
4798           continue;
4799         }
4800 
4801         if (!strcmp(charopt, "bigendbug")) {
4802           // only for backwards comptaibility
4803           if (optarg) {
4804             // set bigendbug
4805             prefs->bigendbug = atoi(optarg);
4806           } else prefs->bigendbug = 1;
4807           continue;
4808         }
4809 #ifdef ENABLE_OSC
4810 
4811         if (!strcmp(charopt, "oscstart") && optarg) {
4812           if (!*optarg) {
4813             do_optarg_blank_err(charopt);
4814             continue;
4815           }
4816           if (optarg[0] == '-') {
4817             do_optarg_blank_err(charopt);
4818             optind--;
4819             continue;
4820           }
4821           // force OSC start
4822           prefs->osc_udp_port = atoi(optarg);
4823           prefs->osc_start = TRUE;
4824           ign_opts.ign_osc = TRUE;
4825           continue;
4826         }
4827 
4828         if (!strcmp(charopt, "nooscstart")) {
4829           // force no OSC start
4830           prefs->osc_start = FALSE;
4831           ign_opts.ign_osc = TRUE;
4832           continue;
4833         }
4834 #endif
4835 
4836 #ifdef ENABLE_JACK
4837         if (!strcmp(charopt, "jackopts") && optarg) {
4838           if (!*optarg) {
4839             do_optarg_blank_err(charopt);
4840             continue;
4841           }
4842           if (optarg[0] == '-') {
4843             do_optarg_blank_err(charopt);
4844             optind--;
4845             continue;
4846           }
4847           // override jackopts in config file
4848           ign_opts.ign_jackopts = TRUE;
4849           future_prefs->jack_opts = prefs->jack_opts = atoi(optarg);
4850           continue;
4851         }
4852 #endif
4853         if (!strcmp(charopt, "startup-ce")) {
4854           // force start in clip editor mode
4855           if (!ign_opts.ign_stmode) {
4856             prefs->startup_interface = STARTUP_CE;
4857             ign_opts.ign_stmode = TRUE;
4858           }
4859           continue;
4860         }
4861 
4862         if (!strcmp(charopt, "startup-mt")) {
4863           // force start in multitrack mode
4864           if (!ign_opts.ign_stmode) {
4865             prefs->startup_interface = STARTUP_MT;
4866             ign_opts.ign_stmode = TRUE;
4867           }
4868           continue;
4869         }
4870 
4871         if (!strcmp(charopt, "vjmode")) {
4872           // force start in multitrack mode
4873           prefs->vj_mode = TRUE;
4874           ign_opts.ign_vjmode = TRUE;
4875           continue;
4876         }
4877       }
4878 
4879       if (optind < argc) {
4880         // remaining opts are filename [start_time] [end_frame]
4881         char *dir;
4882         lives_snprintf(start_file, PATH_MAX, "%s", argv[optind++]); // filename
4883         if (optind < argc) start = lives_strtod(argv[optind++], NULL); // start time (seconds)
4884         if (optind < argc) end = atoi(argv[optind++]); // number of frames
4885 
4886         if (lives_strrstr(start_file, "://") == NULL) {
4887           // prepend current directory if needed (unless file contains :// - eg. dvd:// or http://)
4888           dir = get_dir(start_file);
4889           get_basename(start_file);
4890           lives_snprintf(start_file, PATH_MAX, "%s", (tmp = lives_build_filename(dir, start_file, NULL)));
4891           lives_free(tmp);
4892           lives_free(dir);
4893 	  // *INDENT-OFF*
4894         }}}}
4895   // *INDENT-ON*
4896 
4897   if (!ign_opts.ign_configfile) {
4898     tmp = lives_build_filename(capable->home_dir, LIVES_DEF_CONFIG_DIR, "lives", LIVES_DEF_CONFIG_FILE, NULL);
4899     lives_snprintf(prefs->configfile, PATH_MAX, "%s", tmp);
4900     lives_free(tmp);
4901   }
4902 
4903   if (!ign_opts.ign_config_datadir) {
4904     tmp = lives_build_path(capable->home_dir, LOCAL_HOME_DIR, LIVES_DEF_CONFIG_DATADIR, NULL);
4905     lives_snprintf(prefs->config_datadir, PATH_MAX, "%s", tmp);
4906     lives_free(tmp);
4907   }
4908 
4909   // get capabilities and if OK set some initial prefs
4910   theme_error = pre_init();
4911 
4912   lives_memset(start_file, 0, 1);
4913 
4914   mainw->libthread = gtk_thread;
4915 
4916   // what's my name ?
4917   capable->myname_full = lives_find_program_in_path(argv[0]);
4918 
4919   if ((mynsize = lives_readlink(capable->myname_full, cdir, PATH_MAX)) != -1) {
4920     // no. i mean, what's my real name ?
4921     lives_memset(cdir + mynsize, 0, 1);
4922     lives_free(capable->myname_full);
4923     capable->myname_full = lives_strdup(cdir);
4924   }
4925 
4926   // what's my short name (without the path) ?
4927   lives_snprintf(cdir, PATH_MAX, "%s", capable->myname_full);
4928   get_basename(cdir);
4929   capable->myname = lives_strdup(cdir);
4930 
4931   // format is:
4932   // lives [opts] [filename [start_time] [frames]]
4933 
4934   // need to do this here, before lives_startup but afer setting ign_opts
4935   mainw->new_vpp = NULL;
4936   mainw->vpp = NULL;
4937   lives_memset(future_prefs->vpp_name, 0, 64);
4938   future_prefs->vpp_argv = NULL;
4939 
4940   if (!ign_opts.ign_vppdefs) {
4941     tmp = lives_build_filename(prefs->config_datadir, VPP_DEFS_FILE, NULL);
4942     lives_snprintf(mainw->vpp_defs_file, PATH_MAX, "%s", tmp);
4943     lives_free(tmp);
4944   }
4945 
4946   lives_idle_add_simple(lives_startup, NULL);
4947 
4948 #ifdef GUI_GTK
4949   if (!gtk_thread) {
4950     gtk_main();
4951   }
4952 #endif
4953 
4954 #ifdef GUI_QT
4955   return qapp->exec();
4956 #endif
4957 
4958   return 0;
4959 }
4960 
4961 
startup_message_fatal(char * msg)4962 void startup_message_fatal(char *msg) {
4963   if (mainw) {
4964     if (mainw->splash_window) splash_end();
4965 
4966     lives_freep((void **)&mainw->old_vhash);
4967     lives_freep((void **)&old_vhash);
4968   }
4969 
4970   do_error_dialog(msg);
4971 
4972   LIVES_FATAL(msg);
4973   // needs notify_socket and prefs->omc_events, so seems unlikely it will do anything, but anyway...
4974   lives_notify(LIVES_OSC_NOTIFY_QUIT, msg);
4975   lives_free(msg);
4976   _exit(1);
4977 }
4978 
4979 
startup_message_nonfatal(const char * msg)4980 LIVES_GLOBAL_INLINE boolean startup_message_nonfatal(const char *msg) {
4981   if (mainw && mainw->ds_status == LIVES_STORAGE_STATUS_CRITICAL) do_abort_ok_dialog(msg);
4982   else do_error_dialog(msg);
4983   return TRUE;
4984 }
4985 
4986 
startup_message_info(const char * msg)4987 boolean startup_message_info(const char *msg) {
4988   widget_opts.non_modal = TRUE;
4989   do_info_dialog(msg);
4990   widget_opts.non_modal = FALSE;
4991   return TRUE;
4992 }
4993 
4994 
startup_message_nonfatal_dismissable(const char * msg,uint64_t warning_mask)4995 boolean startup_message_nonfatal_dismissable(const char *msg, uint64_t warning_mask) {
4996   widget_opts.non_modal = TRUE;
4997   do_error_dialog_with_check(msg, warning_mask);
4998   widget_opts.non_modal = FALSE;
4999   return TRUE;
5000 }
5001 
5002 
5003 ///////////////////////////////// GUI section - TODO: move into another file //////////////////////////////////////
5004 
set_main_title(const char * file,int untitled)5005 void set_main_title(const char *file, int untitled) {
5006   char *title, *tmp, *tmp2;
5007   char short_file[256];
5008 
5009   if (file && CURRENT_CLIP_IS_VALID) {
5010     if (untitled) {
5011       title = lives_strdup_printf((tmp = _("<%s> %dx%d : %d frames %d bpp %.3f fps")), (tmp2 = get_untitled_name(untitled)),
5012                                   cfile->hsize, cfile->vsize, cfile->frames, cfile->bpp, cfile->fps);
5013     } else {
5014       lives_snprintf(short_file, 256, "%s", file);
5015       if (cfile->restoring || (cfile->opening && cfile->frames == 123456789)) {
5016         title = lives_strdup_printf((tmp = _("<%s> %dx%d : ??? frames ??? bpp %.3f fps")),
5017                                     (tmp2 = lives_path_get_basename(file)), cfile->hsize, cfile->vsize, cfile->fps);
5018       } else {
5019         title = lives_strdup_printf((tmp = _("<%s> %dx%d : %d frames %d bpp %.3f fps")),
5020                                     cfile->clip_type != CLIP_TYPE_VIDEODEV ? (tmp2 = lives_path_get_basename(file))
5021                                     : (tmp2 = lives_strdup(file)), cfile->hsize, cfile->vsize, cfile->frames, cfile->bpp, cfile->fps);
5022       }
5023     }
5024     lives_free(tmp); lives_free(tmp2);
5025   } else {
5026     title = (_("<No File>"));
5027   }
5028 
5029   lives_window_set_title(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), title);
5030   lives_free(title);
5031 
5032   if (!LIVES_IS_PLAYING && mainw->play_window) play_window_set_title();
5033 }
5034 
5035 
sensitize_rfx(void)5036 void sensitize_rfx(void) {
5037   if (!mainw->foreign) {
5038     if (mainw->rendered_fx) {
5039       for (int i = 1; i <= mainw->num_rendered_effects_builtin + mainw->num_rendered_effects_custom +
5040            mainw->num_rendered_effects_test; i++)
5041         if (mainw->rendered_fx[i].menuitem && mainw->rendered_fx[i].min_frames >= 0)
5042           lives_widget_set_sensitive(mainw->rendered_fx[i].menuitem, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5043       if (mainw->rendered_fx[0].menuitem && LIVES_IS_WIDGET(mainw->rendered_fx[0].menuitem)) {
5044         if (!CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID
5045             && ((has_video_filters(FALSE) && !has_video_filters(TRUE)) ||
5046                 (cfile->achans > 0 && prefs->audio_src == AUDIO_SRC_INT
5047                  && has_audio_filters(AF_TYPE_ANY))
5048                 || mainw->agen_key != 0)) {
5049           lives_widget_set_sensitive(mainw->rendered_fx[0].menuitem, TRUE);
5050         } else lives_widget_set_sensitive(mainw->rendered_fx[0].menuitem, FALSE);
5051 	// *INDENT-OFF*
5052       }}
5053     // *INDENT-ON*
5054 
5055     if (mainw->num_rendered_effects_test > 0) {
5056       lives_widget_set_sensitive(mainw->run_test_rfx_submenu, TRUE);
5057     }
5058 
5059     if (mainw->has_custom_gens) {
5060       lives_widget_set_sensitive(mainw->custom_gens_submenu, TRUE);
5061     }
5062 
5063     if (mainw->has_custom_tools) {
5064       lives_widget_set_sensitive(mainw->custom_tools_submenu, TRUE);
5065     }
5066 
5067     if (mainw->has_custom_effects) {
5068       lives_widget_set_sensitive(mainw->custom_effects_submenu, TRUE);
5069     }
5070 
5071     if (mainw->resize_menuitem) {
5072       lives_widget_set_sensitive(mainw->resize_menuitem, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5073     }
5074   }
5075 }
5076 
5077 
sensitize(void)5078 void sensitize(void) {
5079   // sensitize main window controls
5080   // READY MODE
5081   int i;
5082 
5083   if (LIVES_IS_PLAYING || mainw->is_processing || mainw->go_away) return;
5084 
5085   if (mainw->multitrack) {
5086     mt_sensitise(mainw->multitrack);
5087     return;
5088   }
5089 
5090   mainw->sense_state &= LIVES_SENSE_STATE_INTERACTIVE;
5091   mainw->sense_state |= LIVES_SENSE_STATE_SENSITIZED;
5092 
5093   lives_widget_set_sensitive(mainw->open, TRUE);
5094   lives_widget_set_sensitive(mainw->open_sel, TRUE);
5095   lives_widget_set_sensitive(mainw->open_vcd_menu, TRUE);
5096 #ifdef HAVE_WEBM
5097   lives_widget_set_sensitive(mainw->open_loc_menu, TRUE);
5098 #else
5099   lives_widget_set_sensitive(mainw->open_loc, TRUE);
5100 #endif
5101   lives_widget_set_sensitive(mainw->open_device_menu, TRUE);
5102   lives_widget_set_sensitive(mainw->restore, TRUE);
5103   lives_widget_set_sensitive(mainw->recent_menu, TRUE);
5104   lives_widget_set_sensitive(mainw->save_as, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID
5105                              && capable->has_encoder_plugins);
5106 #ifdef LIBAV_TRANSCODE
5107   lives_widget_set_sensitive(mainw->transcode, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5108 #endif
5109   if (!prefs->vj_mode) {
5110     lives_widget_set_sensitive(mainw->backup, CURRENT_CLIP_IS_VALID && !CURRENT_CLIP_IS_CLIPBOARD);
5111     lives_widget_set_sensitive(mainw->save_selection, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO &&
5112                                capable->has_encoder_plugins);
5113   }
5114   lives_widget_set_sensitive(mainw->clear_ds, TRUE);
5115   lives_widget_set_sensitive(mainw->load_cdtrack, TRUE);
5116   lives_widget_set_sensitive(mainw->playsel, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5117 
5118   if (!prefs->vj_mode) {
5119     lives_widget_set_sensitive(mainw->copy, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5120     lives_widget_set_sensitive(mainw->cut, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5121     lives_widget_set_sensitive(mainw->rev_clipboard, !(clipboard == NULL));
5122     lives_widget_set_sensitive(mainw->playclip, !(clipboard == NULL));
5123     lives_widget_set_sensitive(mainw->paste_as_new, !(clipboard == NULL));
5124     lives_widget_set_sensitive(mainw->insert, !(clipboard == NULL));
5125     lives_widget_set_sensitive(mainw->merge, (clipboard != NULL && !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO));
5126   }
5127   lives_widget_set_sensitive(mainw->xdelete, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5128   lives_widget_set_sensitive(mainw->playall, CURRENT_CLIP_IS_VALID && !CURRENT_CLIP_IS_CLIPBOARD);
5129   lives_widget_set_sensitive(mainw->m_playbutton, CURRENT_CLIP_IS_VALID && !CURRENT_CLIP_IS_CLIPBOARD);
5130   lives_widget_set_sensitive(mainw->m_playselbutton, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5131   lives_widget_set_sensitive(mainw->m_rewindbutton, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID &&
5132                              cfile->real_pointer_time > 0.);
5133   lives_widget_set_sensitive(mainw->m_loopbutton, TRUE);
5134   lives_widget_set_sensitive(mainw->m_mutebutton, TRUE);
5135   if (mainw->preview_box) {
5136     lives_widget_set_sensitive(mainw->p_playbutton, CURRENT_CLIP_IS_VALID && !CURRENT_CLIP_IS_CLIPBOARD);
5137     lives_widget_set_sensitive(mainw->p_playselbutton, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5138     lives_widget_set_sensitive(mainw->p_rewindbutton, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID &&
5139                                cfile->real_pointer_time > 0.);
5140     lives_widget_set_sensitive(mainw->p_loopbutton, TRUE);
5141     lives_widget_set_sensitive(mainw->p_mutebutton, TRUE);
5142   }
5143 
5144   lives_widget_set_sensitive(mainw->rewind, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && cfile->real_pointer_time > 0.);
5145   lives_widget_set_sensitive(mainw->show_file_info, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID);
5146   lives_widget_set_sensitive(mainw->show_file_comments, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID);
5147   lives_widget_set_sensitive(mainw->full_screen, TRUE);
5148   if (!prefs->vj_mode)
5149     lives_widget_set_sensitive(mainw->mt_menu, TRUE);
5150   lives_widget_set_sensitive(mainw->unicap, TRUE);
5151   lives_widget_set_sensitive(mainw->firewire, TRUE);
5152   lives_widget_set_sensitive(mainw->tvdev, TRUE);
5153 
5154   if (!prefs->vj_mode) {
5155     lives_widget_set_sensitive(mainw->export_proj, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID);
5156     lives_widget_set_sensitive(mainw->import_proj, TRUE);
5157   }
5158 
5159   if (is_realtime_aplayer(prefs->audio_player) && prefs->audio_player != AUD_PLAYER_NONE) {
5160     lives_widget_set_sensitive(mainw->int_audio_checkbutton, prefs->audio_src != AUDIO_SRC_INT);
5161     lives_widget_set_sensitive(mainw->ext_audio_checkbutton, prefs->audio_src != AUDIO_SRC_EXT);
5162   }
5163 
5164   if (!prefs->vj_mode) {
5165     if (RFX_LOADED) {
5166       sensitize_rfx();
5167     }
5168   }
5169   lives_widget_set_sensitive(mainw->record_perf, TRUE);
5170   if (!prefs->vj_mode) {
5171     lives_widget_set_sensitive(mainw->export_submenu, !CURRENT_CLIP_IS_CLIPBOARD && (CURRENT_CLIP_HAS_AUDIO));
5172     lives_widget_set_sensitive(mainw->export_selaudio, (CURRENT_CLIP_HAS_VIDEO && CURRENT_CLIP_HAS_AUDIO));
5173     lives_widget_set_sensitive(mainw->export_allaudio, CURRENT_CLIP_HAS_AUDIO);
5174     lives_widget_set_sensitive(mainw->normalize_audio, CURRENT_CLIP_HAS_AUDIO);
5175     lives_widget_set_sensitive(mainw->recaudio_submenu, TRUE);
5176     lives_widget_set_sensitive(mainw->recaudio_sel, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5177     lives_widget_set_sensitive(mainw->append_audio, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_AUDIO);
5178     lives_widget_set_sensitive(mainw->trim_submenu, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_AUDIO);
5179     lives_widget_set_sensitive(mainw->voladj, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_AUDIO);
5180     lives_widget_set_sensitive(mainw->fade_aud_in, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_AUDIO);
5181     lives_widget_set_sensitive(mainw->fade_aud_out, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_AUDIO);
5182     lives_widget_set_sensitive(mainw->trim_audio, !CURRENT_CLIP_IS_CLIPBOARD
5183                                && CURRENT_CLIP_HAS_VIDEO && CURRENT_CLIP_HAS_AUDIO);
5184     lives_widget_set_sensitive(mainw->trim_to_pstart, !CURRENT_CLIP_IS_CLIPBOARD && (CURRENT_CLIP_HAS_AUDIO &&
5185                                cfile->real_pointer_time > 0.));
5186     lives_widget_set_sensitive(mainw->delaudio_submenu, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_AUDIO);
5187     lives_widget_set_sensitive(mainw->delsel_audio, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO
5188                                && CURRENT_CLIP_HAS_AUDIO);
5189     lives_widget_set_sensitive(mainw->delall_audio, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO
5190                                && CURRENT_CLIP_HAS_AUDIO);
5191     lives_widget_set_sensitive(mainw->resample_audio, !CURRENT_CLIP_IS_CLIPBOARD && (CURRENT_CLIP_HAS_AUDIO &&
5192                                capable->has_sox_sox));
5193   }
5194   lives_widget_set_sensitive(mainw->dsize, TRUE);
5195   lives_widget_set_sensitive(mainw->fade, !(mainw->fs));
5196   lives_widget_set_sensitive(mainw->mute_audio, TRUE);
5197   lives_widget_set_sensitive(mainw->loop_video, !CURRENT_CLIP_IS_CLIPBOARD && (CURRENT_CLIP_TOTAL_TIME > 0.));
5198   lives_widget_set_sensitive(mainw->loop_continue, TRUE);
5199   lives_widget_set_sensitive(mainw->load_audio, TRUE);
5200   lives_widget_set_sensitive(mainw->load_subs, CURRENT_CLIP_IS_VALID && !CURRENT_CLIP_IS_CLIPBOARD);
5201   lives_widget_set_sensitive(mainw->erase_subs, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && cfile->subt != NULL);
5202   if ((check_for_executable(&capable->has_cdda2wav, EXEC_CDDA2WAV)
5203        || check_for_executable(&capable->has_icedax, EXEC_ICEDAX))
5204       && *prefs->cdplay_device) lives_widget_set_sensitive(mainw->load_cdtrack, TRUE);
5205   lives_widget_set_sensitive(mainw->rename, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && !cfile->opening);
5206   lives_widget_set_sensitive(mainw->change_speed, CURRENT_CLIP_IS_VALID && !CURRENT_CLIP_IS_CLIPBOARD);
5207   if (!prefs->vj_mode)
5208     lives_widget_set_sensitive(mainw->resample_video, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5209   lives_widget_set_sensitive(mainw->preferences, TRUE);
5210   if (!prefs->vj_mode)
5211     lives_widget_set_sensitive(mainw->ins_silence, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5212   lives_widget_set_sensitive(mainw->close, CURRENT_CLIP_IS_VALID && !CURRENT_CLIP_IS_CLIPBOARD);
5213   lives_widget_set_sensitive(mainw->select_submenu, !CURRENT_CLIP_IS_CLIPBOARD && !mainw->selwidth_locked &&
5214                              CURRENT_CLIP_HAS_VIDEO);
5215   update_sel_menu();
5216 #ifdef HAVE_YUV4MPEG
5217   lives_widget_set_sensitive(mainw->open_yuv4m, TRUE);
5218 #endif
5219 
5220   lives_widget_set_sensitive(mainw->select_new, !CURRENT_CLIP_IS_CLIPBOARD
5221                              && CURRENT_CLIP_IS_VALID && (cfile->insert_start > 0));
5222   lives_widget_set_sensitive(mainw->select_last, !CURRENT_CLIP_IS_CLIPBOARD
5223                              && CURRENT_CLIP_IS_VALID && (cfile->undo_start > 0));
5224   lives_widget_set_sensitive(mainw->lock_selwidth, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_HAS_VIDEO);
5225 
5226   lives_widget_set_sensitive(mainw->undo, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && cfile->undoable);
5227   lives_widget_set_sensitive(mainw->redo, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && cfile->redoable);
5228   lives_widget_set_sensitive(mainw->show_clipboard_info, !(clipboard == NULL));
5229   lives_widget_set_sensitive(mainw->capture, TRUE);
5230   lives_widget_set_sensitive(mainw->vj_save_set, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID);
5231   lives_widget_set_sensitive(mainw->vj_load_set, !*mainw->set_name);
5232   lives_widget_set_sensitive(mainw->vj_reset, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID);
5233   lives_widget_set_sensitive(mainw->vj_realize, !CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID &&
5234                              cfile->frame_index != NULL);
5235   lives_widget_set_sensitive(mainw->midi_learn, TRUE);
5236   lives_widget_set_sensitive(mainw->midi_save, has_devicemap(-1));
5237   lives_widget_set_sensitive(mainw->toy_tv, TRUE);
5238   lives_widget_set_sensitive(mainw->autolives, TRUE);
5239   lives_widget_set_sensitive(mainw->toy_random_frames, TRUE);
5240   //lives_widget_set_sensitive(mainw->open_lives2lives, TRUE);
5241   if (!prefs->vj_mode)
5242     lives_widget_set_sensitive(mainw->gens_submenu, TRUE);
5243   lives_widget_set_sensitive(mainw->troubleshoot, TRUE);
5244   lives_widget_set_sensitive(mainw->expl_missing, TRUE);
5245 
5246   lives_widget_set_sensitive(mainw->show_quota, TRUE);
5247 
5248   if (!CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && (cfile->start == 1 || cfile->end == cfile->frames) &&
5249       !(cfile->start == 1 &&
5250         cfile->end == cfile->frames)) {
5251     lives_widget_set_sensitive(mainw->select_invert, TRUE);
5252   } else {
5253     lives_widget_set_sensitive(mainw->select_invert, FALSE);
5254   }
5255 
5256   if (!CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && cfile->menuentry) {
5257     lives_signal_handler_block(mainw->spinbutton_end, mainw->spin_end_func);
5258     lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_end), 1, cfile->frames);
5259     lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->end);
5260     lives_signal_handler_unblock(mainw->spinbutton_end, mainw->spin_end_func);
5261 
5262     lives_signal_handler_block(mainw->spinbutton_start, mainw->spin_start_func);
5263     lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_start), 1, cfile->frames);
5264     lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->start);
5265     lives_signal_handler_unblock(mainw->spinbutton_start, mainw->spin_start_func);
5266 
5267     if (LIVES_IS_INTERACTIVE) {
5268       lives_widget_set_sensitive(mainw->spinbutton_start, TRUE);
5269       lives_widget_set_sensitive(mainw->spinbutton_end, TRUE);
5270     }
5271 
5272     if (mainw->play_window && (mainw->prv_link == PRV_START || mainw->prv_link == PRV_END)) {
5273       // unblock spinbutton in play window
5274       lives_widget_set_sensitive(mainw->preview_spinbutton, TRUE);
5275     }
5276   }
5277 
5278   // clips menu
5279   for (i = 1; i < MAX_FILES; i++) {
5280     if (mainw->files[i]) {
5281       if (mainw->files[i]->menuentry) {
5282         lives_widget_set_sensitive(mainw->files[i]->menuentry, TRUE);
5283 	// *INDENT-OFF*
5284       }}}
5285   // *INDENT-ON*
5286   if (prefs->vj_mode) {
5287 #ifdef LIBAV_TRANSCODE
5288     lives_widget_set_sensitive(mainw->transcode, FALSE);
5289 #endif
5290     lives_widget_set_sensitive(mainw->import_theme, FALSE);
5291     lives_widget_set_sensitive(mainw->export_theme, FALSE);
5292     lives_widget_set_sensitive(mainw->backup, FALSE);
5293     lives_widget_set_sensitive(mainw->capture, FALSE);
5294     lives_widget_set_sensitive(mainw->save_as, FALSE);
5295     lives_widget_set_sensitive(mainw->mt_menu, FALSE);
5296     lives_widget_set_sensitive(mainw->gens_submenu, FALSE);
5297     lives_widget_set_sensitive(mainw->utilities_submenu, FALSE);
5298   }
5299 }
5300 
5301 
desensitize(void)5302 void desensitize(void) {
5303   // desensitize the main window when we are playing/processing a clip
5304   int i;
5305 
5306   if (mainw->multitrack) {
5307     mt_desensitise(mainw->multitrack);
5308     return;
5309   }
5310 
5311   mainw->sense_state &= LIVES_SENSE_STATE_INTERACTIVE;
5312   mainw->sense_state |= LIVES_SENSE_STATE_INSENSITIZED;
5313 
5314   //lives_widget_set_sensitive (mainw->open, mainw->playing_file>-1);
5315   lives_widget_set_sensitive(mainw->open, FALSE);
5316   lives_widget_set_sensitive(mainw->open_sel, FALSE);
5317   lives_widget_set_sensitive(mainw->open_vcd_menu, FALSE);
5318 #ifdef HAVE_WEBM
5319   lives_widget_set_sensitive(mainw->open_loc_menu, FALSE);
5320 #else
5321   lives_widget_set_sensitive(mainw->open_loc, FALSE);
5322 #endif
5323   lives_widget_set_sensitive(mainw->open_device_menu, FALSE);
5324 #ifdef HAVE_YUV4MPEG
5325   lives_widget_set_sensitive(mainw->open_yuv4m, FALSE);
5326 #endif
5327 
5328   lives_widget_set_sensitive(mainw->firewire, FALSE);
5329   lives_widget_set_sensitive(mainw->tvdev, FALSE);
5330 
5331   lives_widget_set_sensitive(mainw->recent_menu, FALSE);
5332   lives_widget_set_sensitive(mainw->restore, FALSE);
5333   lives_widget_set_sensitive(mainw->clear_ds, FALSE);
5334   lives_widget_set_sensitive(mainw->midi_learn, FALSE);
5335   lives_widget_set_sensitive(mainw->midi_save, FALSE);
5336   lives_widget_set_sensitive(mainw->load_cdtrack, FALSE);
5337   lives_widget_set_sensitive(mainw->save_as, FALSE);
5338 #ifdef LIBAV_TRANSCODE
5339   lives_widget_set_sensitive(mainw->transcode, FALSE);
5340 #endif
5341   lives_widget_set_sensitive(mainw->backup, FALSE);
5342   lives_widget_set_sensitive(mainw->playsel, FALSE);
5343   lives_widget_set_sensitive(mainw->playclip, FALSE);
5344   lives_widget_set_sensitive(mainw->copy, FALSE);
5345   lives_widget_set_sensitive(mainw->cut, FALSE);
5346   lives_widget_set_sensitive(mainw->preferences, FALSE);
5347   lives_widget_set_sensitive(mainw->rev_clipboard, FALSE);
5348   lives_widget_set_sensitive(mainw->insert, FALSE);
5349   lives_widget_set_sensitive(mainw->merge, FALSE);
5350   lives_widget_set_sensitive(mainw->xdelete, FALSE);
5351   if (!prefs->pause_during_pb) {
5352     lives_widget_set_sensitive(mainw->playall, FALSE);
5353   }
5354   lives_widget_set_sensitive(mainw->rewind, FALSE);
5355   if (!prefs->vj_mode) {
5356     if (RFX_LOADED) {
5357       if (!mainw->foreign) {
5358         for (i = 0; i <= mainw->num_rendered_effects_builtin + mainw->num_rendered_effects_custom +
5359              mainw->num_rendered_effects_test; i++)
5360           if (mainw->rendered_fx[i].menuitem && mainw->rendered_fx[i].menuitem &&
5361               mainw->rendered_fx[i].min_frames >= 0)
5362             lives_widget_set_sensitive(mainw->rendered_fx[i].menuitem, FALSE);
5363       }
5364     }
5365   }
5366 
5367   if (mainw->resize_menuitem) {
5368     lives_widget_set_sensitive(mainw->resize_menuitem, FALSE);
5369   }
5370 
5371   if (!prefs->vj_mode)
5372     if (mainw->num_rendered_effects_test > 0) {
5373       lives_widget_set_sensitive(mainw->run_test_rfx_submenu, FALSE);
5374     }
5375 
5376 
5377   if (mainw->has_custom_gens) {
5378     lives_widget_set_sensitive(mainw->custom_gens_submenu, FALSE);
5379   }
5380 
5381   if (mainw->has_custom_tools) {
5382     lives_widget_set_sensitive(mainw->custom_tools_submenu, FALSE);
5383   }
5384 
5385   if (!mainw->foreign)
5386     if (mainw->has_custom_effects) {
5387       lives_widget_set_sensitive(mainw->custom_effects_submenu, FALSE);
5388     }
5389 
5390   lives_widget_set_sensitive(mainw->export_submenu, FALSE);
5391   lives_widget_set_sensitive(mainw->recaudio_submenu, FALSE);
5392   lives_widget_set_sensitive(mainw->append_audio, FALSE);
5393   lives_widget_set_sensitive(mainw->trim_submenu, FALSE);
5394   lives_widget_set_sensitive(mainw->delaudio_submenu, FALSE);
5395   lives_widget_set_sensitive(mainw->gens_submenu, FALSE);
5396   lives_widget_set_sensitive(mainw->troubleshoot, FALSE);
5397   lives_widget_set_sensitive(mainw->expl_missing, FALSE);
5398   lives_widget_set_sensitive(mainw->resample_audio, FALSE);
5399   lives_widget_set_sensitive(mainw->voladj, FALSE);
5400   lives_widget_set_sensitive(mainw->fade_aud_in, FALSE);
5401   lives_widget_set_sensitive(mainw->fade_aud_out, FALSE);
5402   lives_widget_set_sensitive(mainw->normalize_audio, FALSE);
5403   lives_widget_set_sensitive(mainw->ins_silence, FALSE);
5404   lives_widget_set_sensitive(mainw->loop_video, is_realtime_aplayer(prefs->audio_player));
5405   if (!is_realtime_aplayer(prefs->audio_player)) lives_widget_set_sensitive(mainw->mute_audio, FALSE);
5406   lives_widget_set_sensitive(mainw->load_audio, FALSE);
5407   lives_widget_set_sensitive(mainw->load_subs, FALSE);
5408   lives_widget_set_sensitive(mainw->erase_subs, FALSE);
5409   lives_widget_set_sensitive(mainw->save_selection, FALSE);
5410   lives_widget_set_sensitive(mainw->close, FALSE);
5411   lives_widget_set_sensitive(mainw->change_speed, FALSE);
5412   lives_widget_set_sensitive(mainw->resample_video, FALSE);
5413   lives_widget_set_sensitive(mainw->undo, FALSE);
5414   lives_widget_set_sensitive(mainw->redo, FALSE);
5415   lives_widget_set_sensitive(mainw->paste_as_new, FALSE);
5416   lives_widget_set_sensitive(mainw->capture, FALSE);
5417   lives_widget_set_sensitive(mainw->toy_tv, FALSE);
5418   lives_widget_set_sensitive(mainw->vj_save_set, FALSE);
5419   lives_widget_set_sensitive(mainw->vj_load_set, FALSE);
5420   lives_widget_set_sensitive(mainw->vj_realize, FALSE);
5421   lives_widget_set_sensitive(mainw->vj_reset, FALSE);
5422   lives_widget_set_sensitive(mainw->show_quota, FALSE);
5423   lives_widget_set_sensitive(mainw->export_proj, FALSE);
5424   lives_widget_set_sensitive(mainw->import_proj, FALSE);
5425   lives_widget_set_sensitive(mainw->recaudio_sel, FALSE);
5426   lives_widget_set_sensitive(mainw->mt_menu, FALSE);
5427 
5428   lives_widget_set_sensitive(mainw->int_audio_checkbutton, FALSE);
5429   lives_widget_set_sensitive(mainw->ext_audio_checkbutton, FALSE);
5430 
5431   if (mainw->current_file >= 0 && (!LIVES_IS_PLAYING || mainw->foreign)) {
5432     //  if (!cfile->opening||mainw->dvgrab_preview||mainw->preview||cfile->opening_only_audio) {
5433     // disable the 'clips' menu entries
5434     for (i = 1; i < MAX_FILES; i++) {
5435       if (mainw->files[i]) {
5436         if (mainw->files[i]->menuentry) {
5437           if (i != mainw->current_file) {
5438             lives_widget_set_sensitive(mainw->files[i]->menuentry, FALSE);
5439 	    // *INDENT-OFF*
5440           }}}}}
5441   // *INDENT-ON*
5442 }
5443 
5444 
procw_desensitize(void)5445 void procw_desensitize(void) {
5446   // switch on/off a few extra widgets in the processing dialog
5447 
5448   int current_file;
5449 
5450   if (mainw->multitrack) return;
5451 
5452   mainw->sense_state &= LIVES_SENSE_STATE_INTERACTIVE;
5453   mainw->sense_state |= LIVES_SENSE_STATE_PROC_INSENSITIZED | LIVES_SENSE_STATE_INSENSITIZED;
5454 
5455   if (!CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID
5456       && (cfile->menuentry || cfile->opening) && !mainw->preview) {
5457     // an effect etc,
5458     lives_widget_set_sensitive(mainw->loop_video, CURRENT_CLIP_HAS_AUDIO && CURRENT_CLIP_HAS_VIDEO);
5459     lives_widget_set_sensitive(mainw->loop_continue, TRUE);
5460 
5461     if (CURRENT_CLIP_HAS_AUDIO && CURRENT_CLIP_HAS_VIDEO) {
5462       mainw->loop = lives_check_menu_item_get_active(LIVES_CHECK_MENU_ITEM(mainw->loop_video));
5463     }
5464     if (CURRENT_CLIP_HAS_AUDIO && CURRENT_CLIP_HAS_VIDEO) {
5465       mainw->mute = lives_check_menu_item_get_active(LIVES_CHECK_MENU_ITEM(mainw->mute_audio));
5466     }
5467   }
5468   if (!CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && !cfile->menuentry) {
5469     lives_widget_set_sensitive(mainw->rename, FALSE);
5470     if (cfile->opening || cfile->restoring) {
5471       // loading, restoring etc
5472       lives_widget_set_sensitive(mainw->lock_selwidth, FALSE);
5473       lives_widget_set_sensitive(mainw->show_file_comments, FALSE);
5474       if (!cfile->opening_only_audio) {
5475         lives_widget_set_sensitive(mainw->toy_random_frames, FALSE);
5476       }
5477     }
5478   }
5479 
5480   current_file = mainw->current_file;
5481   if (CURRENT_CLIP_IS_VALID && cfile->cb_src != -1) mainw->current_file = cfile->cb_src;
5482 
5483   if (CURRENT_CLIP_IS_VALID) {
5484     // stop the start and end from being changed
5485     // better to clamp the range than make insensitive, this way we stop
5486     // other widgets (like the video bar) updating it
5487     lives_signal_handler_block(mainw->spinbutton_end, mainw->spin_end_func);
5488     lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->end, cfile->end);
5489     lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->end);
5490     lives_signal_handler_unblock(mainw->spinbutton_end, mainw->spin_end_func);
5491     lives_signal_handler_block(mainw->spinbutton_start, mainw->spin_start_func);
5492     lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->start, cfile->start);
5493     lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->start);
5494     lives_signal_handler_unblock(mainw->spinbutton_start, mainw->spin_start_func);
5495   }
5496 
5497   mainw->current_file = current_file;
5498 
5499   if (mainw->play_window && (mainw->prv_link == PRV_START || mainw->prv_link == PRV_END)) {
5500     // block spinbutton in play window
5501     lives_widget_set_sensitive(mainw->preview_spinbutton, FALSE);
5502   }
5503 
5504   lives_widget_set_sensitive(mainw->sa_button, FALSE);
5505   lives_widget_set_sensitive(mainw->select_submenu, FALSE);
5506   lives_widget_set_sensitive(mainw->toy_tv, FALSE);
5507   lives_widget_set_sensitive(mainw->autolives, FALSE);
5508   lives_widget_set_sensitive(mainw->export_submenu, FALSE);
5509   lives_widget_set_sensitive(mainw->trim_submenu, FALSE);
5510   lives_widget_set_sensitive(mainw->delaudio_submenu, FALSE);
5511   lives_widget_set_sensitive(mainw->load_cdtrack, FALSE);
5512   lives_widget_set_sensitive(mainw->open_lives2lives, FALSE);
5513   lives_widget_set_sensitive(mainw->record_perf, FALSE);
5514   lives_widget_set_sensitive(mainw->unicap, FALSE);
5515 
5516   if (!CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && cfile->nopreview) {
5517     lives_widget_set_sensitive(mainw->m_playbutton, FALSE);
5518     if (mainw->preview_box) lives_widget_set_sensitive(mainw->p_playbutton, FALSE);
5519     lives_widget_set_sensitive(mainw->m_playselbutton, FALSE);
5520     if (mainw->preview_box) lives_widget_set_sensitive(mainw->p_playselbutton, FALSE);
5521   }
5522 }
5523 
5524 
set_drawing_area_from_pixbuf(LiVESWidget * widget,LiVESPixbuf * pixbuf,lives_painter_surface_t * surface)5525 void set_drawing_area_from_pixbuf(LiVESWidget * widget, LiVESPixbuf * pixbuf,
5526                                   lives_painter_surface_t *surface) {
5527   LiVESXWindow *xwin;
5528   lives_rect_t update_rect;
5529   lives_painter_t *cr;
5530   int cx, cy;
5531   int rwidth, rheight, width, height, owidth, oheight;
5532 
5533   if (!surface || !widget) return;
5534 
5535   xwin = lives_widget_get_xwindow(widget);
5536   if (!LIVES_IS_XWINDOW(xwin)) return;
5537 
5538   cr = lives_painter_create_from_surface(surface);
5539 
5540   if (!cr) return;
5541 
5542   rwidth = lives_widget_get_allocation_width(widget);
5543   rheight = lives_widget_get_allocation_height(widget);
5544 
5545   if (!rwidth || !rheight) return;
5546 
5547   rwidth = (rwidth >> 1) << 1;
5548   rheight = (rheight >> 1) << 1;
5549 
5550   if (pixbuf) {
5551     owidth = width = lives_pixbuf_get_width(pixbuf);
5552     oheight = height = lives_pixbuf_get_height(pixbuf);
5553 
5554     cx = (rwidth - width) >> 1;
5555     if (cx < 0) cx = 0;
5556     cy = (rheight - height) >> 1;
5557     if (cy < 0) cy = 0;
5558 
5559     if (widget == mainw->start_image || widget == mainw->end_image
5560         || (mainw->multitrack && widget == mainw->play_image)
5561         || (widget == mainw->play_window && !mainw->fs)) {
5562       int xrwidth, xrheight;
5563       LiVESWidget *p = lives_widget_get_parent(widget);
5564 
5565       p = lives_widget_get_parent(p);
5566 
5567       xrwidth = lives_widget_get_allocation_width(p);
5568       xrheight = lives_widget_get_allocation_height(p);
5569       lives_painter_render_background(p, cr, 0., 0., xrwidth, xrheight);
5570 
5571       if (mainw->multitrack) {
5572         rwidth = xrwidth;
5573         rheight = xrheight;
5574       }
5575 
5576       if (!mainw->multitrack && (prefs->ce_maxspect || prefs->letterbox)) {
5577         calc_maxspect(rwidth, rheight, &width, &height);
5578 
5579         width = (width >> 1) << 1;
5580         height = (height >> 1) << 1;
5581 
5582         if (width > owidth && height > oheight) {
5583           width = owidth;
5584           height = oheight;
5585         }
5586       }
5587 
5588       if (mainw->multitrack) {
5589         cx = (rwidth - width) >> 1;
5590         if (cx < 0) cx = 0;
5591         cy = (rheight - height) >> 1;
5592         if (cy < 0) cy = 0;
5593       }
5594     }
5595 
5596     lives_widget_set_opacity(widget, 1.);
5597 
5598     if ((!mainw->multitrack || widget != mainw->play_image) && widget != mainw->preview_image) {
5599       if (!LIVES_IS_PLAYING && mainw->multitrack && widget == mainw->play_image) clear_widget_bg(widget, surface);
5600       if (prefs->funky_widgets) {
5601         lives_painter_set_source_rgb_from_lives_rgba(cr, &palette->frame_surround);
5602         if (widget == mainw->start_image || widget == mainw->end_image || widget == mainw->play_image) {
5603           lives_painter_move_to(cr, 0, 0);
5604           lives_painter_line_to(cr, rwidth, 0);
5605           lives_painter_move_to(cr, 0, rheight);
5606           lives_painter_line_to(cr, rwidth, rheight);
5607         } else lives_painter_rectangle(cr, cx - 1, cy - 1, width + 2, height + 2);
5608         // frame
5609         lives_painter_stroke(cr);
5610         cx += 2;
5611         cy += 4;
5612       }
5613     }
5614 
5615     /// x, y values are offset of top / left of image in drawing area
5616     lives_painter_set_source_pixbuf(cr, pixbuf, cx, cy);
5617     lives_painter_rectangle(cr, cx, cy, rwidth - cx * 2, rheight + 2 - cy * 2);
5618   } else {
5619     lives_widget_set_opacity(widget, 0.);
5620     clear_widget_bg(widget, surface);
5621   }
5622   lives_painter_fill(cr);
5623   lives_painter_destroy(cr);
5624 
5625   if (widget == mainw->play_window && rheight > mainw->pheight) rheight = mainw->pheight;
5626 
5627   update_rect.x = update_rect.y = 0;
5628   update_rect.width = rwidth;
5629   update_rect.height = rheight;
5630 
5631   if (!LIVES_IS_XWINDOW(xwin)) return;
5632   lives_xwindow_invalidate_rect(lives_widget_get_xwindow(widget), &update_rect, FALSE);
5633 }
5634 
5635 
showclipimgs(void)5636 void showclipimgs(void) {
5637   if (CURRENT_CLIP_IS_VALID) {
5638     load_end_image(cfile->end);
5639     load_start_image(cfile->start);
5640   } else {
5641     load_end_image(0);
5642     load_start_image(0);
5643   }
5644   lives_widget_queue_draw(mainw->start_image);
5645   lives_widget_queue_draw(mainw->end_image);
5646   lives_widget_context_update();
5647 }
5648 
5649 
load_start_image(int frame)5650 void load_start_image(int frame) {
5651   LiVESPixbuf *start_pixbuf = NULL;
5652   LiVESPixbuf *orig_pixbuf = NULL;
5653   weed_layer_t *layer = NULL;
5654   weed_timecode_t tc;
5655   LiVESInterpType interp;
5656   char *xmd5sum = NULL;
5657   char *fname = NULL;
5658   boolean expose = FALSE;
5659   boolean cache_it = TRUE;
5660   int rwidth, rheight, width, height;
5661   int tries = 2;
5662   frames_t xpf;
5663 
5664   if (!prefs->show_gui) return;
5665   if (mainw->multitrack) return;
5666 
5667   if (LIVES_IS_PLAYING && mainw->fs && (!mainw->sep_win || ((prefs->gui_monitor == prefs->play_monitor ||
5668                                         capable->nmonitors == 1) &&
5669                                         (!mainw->ext_playback ||
5670                                          (mainw->vpp->capabilities & VPP_LOCAL_DISPLAY))))) return;
5671   if (frame < 0) {
5672     frame = -frame;
5673     expose = TRUE;
5674   }
5675 
5676   lives_widget_set_opacity(mainw->start_image, 1.);
5677 
5678   if (!CURRENT_CLIP_IS_NORMAL || frame < 1 || frame > cfile->frames) {
5679     int bx, by, hsize, vsize;
5680     int scr_width = GUI_SCREEN_WIDTH;
5681     int scr_height = GUI_SCREEN_HEIGHT;
5682     int vspace = get_vspace();
5683     get_border_size(LIVES_MAIN_WINDOW_WIDGET, &bx, &by);
5684     if (by > MENU_HIDE_LIM)
5685       lives_window_set_hide_titlebar_when_maximized(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), TRUE);
5686     hsize = (scr_width - (H_RESIZE_ADJUST * 3 + bx)) / 3;
5687     vsize = scr_height - (CE_TIMELINE_VSPACE * 1.01 / sqrt(widget_opts.scale) + vspace + by
5688                           + (prefs->show_msg_area ? mainw->mbar_res : 0)
5689                           + widget_opts.border_width * 2);
5690     if (LIVES_IS_PLAYING && mainw->double_size) {
5691       hsize /= 2;
5692       vsize /= 2;
5693     }
5694     lives_widget_set_size_request(mainw->start_image, hsize, vsize);
5695     lives_widget_set_size_request(mainw->frame1, hsize, vsize);
5696     lives_widget_set_size_request(mainw->eventbox3, hsize, vsize);
5697 
5698     lives_widget_set_hexpand(mainw->frame1, FALSE);
5699     lives_widget_set_vexpand(mainw->frame1, FALSE);
5700   }
5701 
5702   if (CURRENT_CLIP_IS_VALID && (cfile->clip_type == CLIP_TYPE_YUV4MPEG || cfile->clip_type == CLIP_TYPE_VIDEODEV)) {
5703     if (!mainw->camframe) {
5704       LiVESError *error = NULL;
5705       char *fname = lives_strdup_printf("%s.%s", THEME_FRAME_IMG_LITERAL, LIVES_FILE_EXT_JPG);
5706       char *tmp = lives_build_filename(prefs->prefix_dir, THEME_DIR, LIVES_THEME_CAMERA, fname, NULL);
5707       mainw->camframe = lives_pixbuf_new_from_file(tmp, &error);
5708       if (mainw->camframe) lives_pixbuf_saturate_and_pixelate(mainw->camframe, mainw->camframe, 0.0, FALSE);
5709       lives_free(tmp); lives_free(fname);
5710     }
5711     set_drawing_area_from_pixbuf(mainw->start_image, mainw->camframe, mainw->si_surface);
5712     return;
5713   }
5714 
5715   if (!CURRENT_CLIP_IS_NORMAL || mainw->current_file == mainw->scrap_file || frame < 1 || frame > cfile->frames) {
5716     if (mainw->imframe) {
5717       set_drawing_area_from_pixbuf(mainw->start_image, mainw->imframe, mainw->si_surface);
5718     } else {
5719       set_drawing_area_from_pixbuf(mainw->start_image, NULL, mainw->si_surface);
5720     }
5721     if (!palette || !(palette->style & STYLE_LIGHT)) {
5722       lives_widget_set_opacity(mainw->start_image, 0.8);
5723     } else {
5724       lives_widget_set_opacity(mainw->start_image, 0.4);
5725     }
5726     return;
5727   }
5728 
5729   xpf = ABS(get_indexed_frame(mainw->current_file, frame));
5730 
5731 check_stcache:
5732   if (mainw->st_fcache) {
5733     if (lives_layer_get_clip(mainw->st_fcache) == mainw->current_file
5734         && lives_layer_get_frame(mainw->st_fcache) == xpf) {
5735       if (is_virtual_frame(mainw->current_file, frame)) layer = mainw->st_fcache;
5736       else {
5737         if (cfile->clip_type == CLIP_TYPE_DISK && capable->has_md5sum) {
5738           char *md5sum = weed_get_string_value(mainw->st_fcache, WEED_LEAF_MD5SUM, NULL);
5739           if (md5sum) {
5740             if (!fname) fname = make_image_file_name(cfile, frame, get_image_ext_for_type(cfile->img_type));
5741             if (!xmd5sum) xmd5sum = get_md5sum(fname);
5742             if (!lives_strcmp(md5sum, xmd5sum)) layer = mainw->st_fcache;
5743             lives_free(md5sum);
5744 	    // *INDENT-OFF*
5745 	  }}}}}
5746   // *INDENT-ON*
5747 
5748   if (!layer) {
5749     if (mainw->st_fcache) {
5750       if (mainw->st_fcache != mainw->en_fcache && mainw->st_fcache != mainw->pr_fcache)
5751         weed_layer_free(mainw->st_fcache);
5752       mainw->st_fcache = NULL;
5753     }
5754     if (tries--) {
5755       if (tries == 1) mainw->st_fcache = mainw->pr_fcache;
5756       else mainw->st_fcache = mainw->en_fcache;
5757       goto check_stcache;
5758     }
5759   }
5760   lives_freep((void **)&fname);
5761 
5762   tc = ((frame - 1.)) / cfile->fps * TICKS_PER_SECOND;
5763 
5764   if (!prefs->ce_maxspect && !prefs->letterbox) {
5765     // if we are not playing, and it would be slow to seek to the frame, convert it to an image
5766     if (!LIVES_IS_PLAYING && !layer && cfile->clip_type == CLIP_TYPE_FILE && is_virtual_frame(mainw->current_file, frame) &&
5767         cfile->ext_src) {
5768       lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
5769       if (cdata && (expose || !(cdata->seek_flag & LIVES_SEEK_FAST))) {
5770         virtual_to_images(mainw->current_file, frame, frame, FALSE, &start_pixbuf);
5771         cache_it = FALSE;
5772       }
5773     }
5774 
5775     if (!layer && !start_pixbuf) {
5776       layer = lives_layer_new_for_frame(mainw->current_file, frame);
5777       if (pull_frame_at_size(layer, get_image_ext_for_type(cfile->img_type), tc, cfile->hsize, cfile->vsize,
5778                              WEED_PALETTE_RGB24)) {
5779         check_layer_ready(layer);
5780         interp = get_interp_value(prefs->pb_quality, TRUE);
5781         if (!resize_layer(layer, cfile->hsize, cfile->vsize, interp, WEED_PALETTE_RGB24, 0) ||
5782             !convert_layer_palette(layer, WEED_PALETTE_RGB24, 0)) {
5783           if (xmd5sum) lives_free(xmd5sum);
5784           return;
5785         }
5786       }
5787     }
5788 
5789     if (!start_pixbuf) start_pixbuf = layer_to_pixbuf(layer, TRUE, TRUE);
5790 
5791     if (LIVES_IS_PIXBUF(start_pixbuf)) {
5792       set_drawing_area_from_pixbuf(mainw->start_image, start_pixbuf, mainw->si_surface);
5793       if (!cache_it || weed_layer_get_pixel_data_packed(layer) || !(pixbuf_to_layer(layer, start_pixbuf)))
5794         lives_widget_object_unref(start_pixbuf);
5795     } else cache_it = FALSE;
5796 
5797     if (!cache_it) {
5798       if (layer) weed_layer_free(layer);
5799       mainw->st_fcache = NULL;
5800     } else {
5801       if (!mainw->st_fcache) {
5802         mainw->st_fcache = layer;
5803         if (!is_virtual_frame(mainw->current_file, frame)) {
5804           if (cfile->clip_type == CLIP_TYPE_DISK && capable->has_md5sum) {
5805             if (!xmd5sum) {
5806               char *fname = make_image_file_name(cfile, frame, get_image_ext_for_type(cfile->img_type));
5807               xmd5sum = get_md5sum(fname);
5808               lives_free(fname);
5809             }
5810             weed_set_string_value(layer, WEED_LEAF_MD5SUM, xmd5sum);
5811 	    // *INDENT-OFF*
5812 	  }}
5813         lives_layer_set_frame(layer, xpf);
5814 	lives_layer_set_clip(layer, mainw->current_file);
5815       }}
5816     // *INDENT-ON*
5817     if (xmd5sum) lives_free(xmd5sum);
5818     return;
5819   }
5820 
5821   do {
5822     width = cfile->hsize;
5823     height = cfile->vsize;
5824 
5825     // TODO *** - if width*height==0, show broken frame image
5826 
5827     rwidth = lives_widget_get_allocation_width(mainw->start_image);
5828     rheight = lives_widget_get_allocation_height(mainw->start_image);
5829 
5830     calc_maxspect(rwidth, rheight, &width, &height);
5831     width = (width >> 2) << 2;
5832     height = (height >> 2) << 2;
5833 
5834     // if we are not playing, and it would be slow to seek to the frame, convert it to an image
5835     if (!LIVES_IS_PLAYING && !layer && cfile->clip_type == CLIP_TYPE_FILE && is_virtual_frame(mainw->current_file, frame) &&
5836         cfile->ext_src) {
5837       lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
5838       if (cdata && (expose || !(cdata->seek_flag & LIVES_SEEK_FAST))) {
5839         // TODO: make background thread
5840         virtual_to_images(mainw->current_file, frame, frame, FALSE, &start_pixbuf);
5841         cache_it = FALSE;
5842       }
5843     }
5844 
5845     if (!layer && !start_pixbuf) {
5846       layer = lives_layer_new_for_frame(mainw->current_file, frame);
5847       if (pull_frame_at_size(layer, get_image_ext_for_type(cfile->img_type), tc, width, height, WEED_PALETTE_RGB24)) {
5848         check_layer_ready(layer);
5849         interp = get_interp_value(prefs->pb_quality, TRUE);
5850         if (!resize_layer(layer, width, height, interp, WEED_PALETTE_RGB24, 0) ||
5851             !convert_layer_palette(layer, WEED_PALETTE_RGB24, 0)) {
5852           weed_layer_free(layer);
5853           if (xmd5sum) lives_free(xmd5sum);
5854           return;
5855         }
5856       }
5857     }
5858 
5859     if (!start_pixbuf || lives_pixbuf_get_width(start_pixbuf) != width || lives_pixbuf_get_height(start_pixbuf) != height) {
5860       if (!orig_pixbuf) {
5861         if (layer) orig_pixbuf = layer_to_pixbuf(layer, TRUE, TRUE);
5862         else orig_pixbuf = start_pixbuf;
5863       }
5864       if (start_pixbuf != orig_pixbuf && LIVES_IS_PIXBUF(start_pixbuf)) {
5865         start_pixbuf = NULL;
5866       }
5867       if (LIVES_IS_PIXBUF(orig_pixbuf)) {
5868         if (lives_pixbuf_get_width(orig_pixbuf) == width && lives_pixbuf_get_height(orig_pixbuf) == height)
5869           start_pixbuf = orig_pixbuf;
5870         else {
5871           start_pixbuf = lives_pixbuf_scale_simple(orig_pixbuf, width, height, LIVES_INTERP_BEST);
5872         }
5873       }
5874     }
5875 
5876     if (LIVES_IS_PIXBUF(start_pixbuf)) {
5877       set_drawing_area_from_pixbuf(mainw->start_image, start_pixbuf, mainw->si_surface);
5878     }
5879 
5880 #if !GTK_CHECK_VERSION(3, 0, 0)
5881     lives_widget_queue_resize(mainw->start_image);
5882     lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
5883   } while (rwidth != lives_widget_get_allocation_width(mainw->start_image) ||
5884            rheight != lives_widget_get_allocation_height(mainw->start_image));
5885 #else
5886   }
5887   while (FALSE);
5888 #endif
5889   if (start_pixbuf != orig_pixbuf && LIVES_IS_PIXBUF(start_pixbuf)) {
5890     lives_widget_object_unref(start_pixbuf);
5891   }
5892 
5893   if (LIVES_IS_PIXBUF(orig_pixbuf)) {
5894     if (!cache_it || weed_layer_get_pixel_data_packed(layer) || !(pixbuf_to_layer(layer, orig_pixbuf)))
5895       lives_widget_object_unref(orig_pixbuf);
5896   } else cache_it = FALSE;
5897 
5898   if (!cache_it) {
5899     weed_layer_free(layer);
5900     mainw->st_fcache = NULL;
5901   } else {
5902     if (!mainw->st_fcache) {
5903       mainw->st_fcache = layer;
5904       if (!is_virtual_frame(mainw->current_file, frame)) {
5905         if (cfile->clip_type == CLIP_TYPE_DISK && capable->has_md5sum) {
5906           if (!xmd5sum) {
5907             char *fname = make_image_file_name(cfile, frame, get_image_ext_for_type(cfile->img_type));
5908             xmd5sum = get_md5sum(fname);
5909             lives_free(fname);
5910           }
5911           weed_set_string_value(layer, WEED_LEAF_MD5SUM, xmd5sum);
5912 	// *INDENT-OFF*
5913       }}
5914     lives_layer_set_frame(layer, xpf);
5915     lives_layer_set_clip(layer, mainw->current_file);
5916   }}
5917 // *INDENT-ON*
5918   if (xmd5sum) lives_free(xmd5sum);
5919 }
5920 
5921 
load_end_image(int frame)5922 void load_end_image(int frame) {
5923   LiVESPixbuf *end_pixbuf = NULL;
5924   LiVESPixbuf *orig_pixbuf = NULL;
5925   weed_layer_t *layer = NULL;
5926   weed_timecode_t tc;
5927   LiVESInterpType interp;
5928   char *xmd5sum = NULL;
5929   char *fname = NULL;
5930   boolean expose = FALSE;
5931   boolean cache_it = TRUE;
5932   int rwidth, rheight, width, height;
5933   int tries = 2;
5934   frames_t xpf;
5935 
5936   if (!prefs->show_gui) return;
5937   if (mainw->multitrack) return;
5938 
5939   if (LIVES_IS_PLAYING && mainw->fs && (!mainw->sep_win || ((prefs->gui_monitor == prefs->play_monitor ||
5940                                         capable->nmonitors == 1) &&
5941                                         (!mainw->ext_playback ||
5942                                          (mainw->vpp->capabilities & VPP_LOCAL_DISPLAY))))) return;
5943   if (frame < 0) {
5944     frame = -frame;
5945     expose = TRUE;
5946   }
5947 
5948   lives_widget_set_opacity(mainw->end_image, 1.);
5949 
5950   if (!CURRENT_CLIP_IS_NORMAL || frame < 1 || frame > cfile->frames) {
5951     int bx, by, hsize, vsize;
5952     int scr_width = GUI_SCREEN_WIDTH;
5953     int scr_height = GUI_SCREEN_HEIGHT;
5954     int vspace = get_vspace();
5955     get_border_size(LIVES_MAIN_WINDOW_WIDGET, &bx, &by);
5956     if (by > MENU_HIDE_LIM)
5957       lives_window_set_hide_titlebar_when_maximized(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), TRUE);
5958     hsize = (scr_width - (H_RESIZE_ADJUST * 3 + bx)) / 3;
5959     vsize = scr_height - (CE_TIMELINE_VSPACE * 1.01 / sqrt(widget_opts.scale) + vspace + by
5960                           + (prefs->show_msg_area ? mainw->mbar_res : 0)
5961                           + widget_opts.border_width * 2);
5962     if (LIVES_IS_PLAYING && mainw->double_size) {
5963       hsize /= 2;
5964       vsize /= 2;
5965     }
5966     lives_widget_set_size_request(mainw->end_image, hsize, vsize);
5967     lives_widget_set_size_request(mainw->frame2, hsize, vsize);
5968     lives_widget_set_size_request(mainw->eventbox4, hsize, vsize);
5969 
5970     lives_widget_set_hexpand(mainw->frame2, FALSE);
5971     lives_widget_set_vexpand(mainw->frame2, FALSE);
5972   }
5973 
5974   if (CURRENT_CLIP_IS_VALID && (cfile->clip_type == CLIP_TYPE_YUV4MPEG || cfile->clip_type == CLIP_TYPE_VIDEODEV)) {
5975     if (!mainw->camframe) {
5976       LiVESError *error = NULL;
5977       char *fname = lives_strdup_printf("%s.%s", THEME_FRAME_IMG_LITERAL, LIVES_FILE_EXT_JPG);
5978       char *tmp = lives_build_filename(prefs->prefix_dir, THEME_DIR, LIVES_THEME_CAMERA, fname, NULL);
5979       mainw->camframe = lives_pixbuf_new_from_file(tmp, &error);
5980       if (mainw->camframe) lives_pixbuf_saturate_and_pixelate(mainw->camframe, mainw->camframe, 0.0, FALSE);
5981       lives_free(tmp); lives_free(fname);
5982     }
5983 
5984     set_drawing_area_from_pixbuf(mainw->end_image, mainw->camframe, mainw->ei_surface);
5985     return;
5986   }
5987 
5988   if (!CURRENT_CLIP_IS_NORMAL || mainw->current_file == mainw->scrap_file || frame < 1 || frame > cfile->frames) {
5989     if (mainw->imframe) {
5990       set_drawing_area_from_pixbuf(mainw->end_image, mainw->imframe, mainw->ei_surface);
5991     } else {
5992       set_drawing_area_from_pixbuf(mainw->end_image, NULL, mainw->ei_surface);
5993     }
5994     if (!palette || !(palette->style & STYLE_LIGHT)) {
5995       lives_widget_set_opacity(mainw->end_image, 0.8);
5996     } else {
5997       lives_widget_set_opacity(mainw->end_image, 0.4);
5998     }
5999     return;
6000   }
6001 
6002   xpf = ABS(get_indexed_frame(mainw->current_file, frame));
6003 check_encache:
6004   if (mainw->en_fcache) {
6005     if (lives_layer_get_clip(mainw->en_fcache) == mainw->current_file
6006         && lives_layer_get_frame(mainw->en_fcache) == xpf) {
6007       if (is_virtual_frame(mainw->current_file, frame)) layer = mainw->en_fcache;
6008       else {
6009         if (cfile->clip_type == CLIP_TYPE_DISK && capable->has_md5sum) {
6010           char *md5sum = weed_get_string_value(mainw->en_fcache, WEED_LEAF_MD5SUM, NULL);
6011           if (md5sum) {
6012             if (!fname) fname = make_image_file_name(cfile, frame, get_image_ext_for_type(cfile->img_type));
6013             if (!xmd5sum) xmd5sum = get_md5sum(fname);
6014             if (!lives_strcmp(md5sum, xmd5sum)) layer = mainw->en_fcache;
6015             lives_free(md5sum);
6016 	    // *INDENT-OFF*
6017 	  }}}}}
6018   // *INDENT-ON*
6019 
6020   if (!layer) {
6021     if (mainw->en_fcache) {
6022       if (mainw->en_fcache != mainw->st_fcache && mainw->en_fcache != mainw->pr_fcache)
6023         weed_layer_free(mainw->en_fcache);
6024       mainw->en_fcache = NULL;
6025     }
6026     if (tries--) {
6027       if (tries == 1) mainw->en_fcache = mainw->pr_fcache;
6028       else mainw->en_fcache = mainw->st_fcache;
6029       goto check_encache;
6030     }
6031   }
6032 
6033   lives_freep((void **)&fname);
6034 
6035   tc = (frame - 1.) / cfile->fps * TICKS_PER_SECOND;
6036 
6037   if (!prefs->ce_maxspect && !prefs->letterbox) {
6038     // if we are not playing, and it would be slow to seek to the frame, convert it to an image
6039     if (!LIVES_IS_PLAYING && !layer && cfile->clip_type == CLIP_TYPE_FILE && is_virtual_frame(mainw->current_file, frame) &&
6040         cfile->ext_src) {
6041       lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
6042       if (cdata && (expose || !(cdata->seek_flag & LIVES_SEEK_FAST))) {
6043         virtual_to_images(mainw->current_file, frame, frame, FALSE, &end_pixbuf);
6044         cache_it = FALSE;
6045       }
6046     }
6047 
6048     if (!layer && !end_pixbuf) {
6049       layer = lives_layer_new_for_frame(mainw->current_file, frame);
6050       if (pull_frame_at_size(layer, get_image_ext_for_type(cfile->img_type), tc, cfile->hsize, cfile->vsize,
6051                              WEED_PALETTE_RGB24)) {
6052         check_layer_ready(layer);
6053         interp = get_interp_value(prefs->pb_quality, TRUE);
6054         if (!resize_layer(layer, cfile->hsize, cfile->vsize, interp, WEED_PALETTE_RGB24, 0) ||
6055             !convert_layer_palette(layer, WEED_PALETTE_RGB24, 0)) {
6056           if (xmd5sum) lives_free(xmd5sum);
6057           return;
6058         }
6059       }
6060     }
6061 
6062     if (!end_pixbuf) end_pixbuf = layer_to_pixbuf(layer, TRUE, TRUE);
6063 
6064     if (LIVES_IS_PIXBUF(end_pixbuf)) {
6065       set_drawing_area_from_pixbuf(mainw->end_image, end_pixbuf, mainw->ei_surface);
6066       if (!cache_it || weed_layer_get_pixel_data_packed(layer) || !(pixbuf_to_layer(layer, end_pixbuf)))
6067         lives_widget_object_unref(end_pixbuf);
6068     } else cache_it = FALSE;
6069 
6070     if (!cache_it) {
6071       if (layer) weed_layer_free(layer);
6072       mainw->en_fcache = NULL;
6073     } else {
6074       if (!mainw->en_fcache) {
6075         mainw->en_fcache = layer;
6076         if (!is_virtual_frame(mainw->current_file, frame)) {
6077           if (cfile->clip_type == CLIP_TYPE_DISK && capable->has_md5sum) {
6078             if (!xmd5sum) {
6079               char *fname = make_image_file_name(cfile, frame, get_image_ext_for_type(cfile->img_type));
6080               xmd5sum = get_md5sum(fname);
6081               lives_free(fname);
6082             }
6083             weed_set_string_value(layer, WEED_LEAF_MD5SUM, xmd5sum);
6084 	    // *INDENT-OFF*
6085 	  }}
6086 	lives_layer_set_frame(layer, xpf);
6087 	lives_layer_set_clip(layer, mainw->current_file);
6088       }}
6089     // *INDENT-ON*
6090     return;
6091   }
6092 
6093   do {
6094     width = cfile->hsize;
6095     height = cfile->vsize;
6096 
6097     rwidth = lives_widget_get_allocation_width(mainw->end_image);
6098     rheight = lives_widget_get_allocation_height(mainw->end_image);
6099 
6100     calc_maxspect(rwidth, rheight, &width, &height);
6101     width = (width >> 2) << 2;
6102     height = (height >> 2) << 2;
6103 
6104     // if we are not playing, and it would be slow to seek to the frame, convert it to an image
6105     if (!LIVES_IS_PLAYING && !layer && cfile->clip_type == CLIP_TYPE_FILE && is_virtual_frame(mainw->current_file, frame) &&
6106         cfile->ext_src) {
6107       lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
6108       if (cdata && (expose || !(cdata->seek_flag & LIVES_SEEK_FAST))) {
6109         virtual_to_images(mainw->current_file, frame, frame, FALSE, &end_pixbuf);
6110         cache_it = FALSE;
6111       }
6112     }
6113 
6114     if (!layer && !end_pixbuf) {
6115       layer = lives_layer_new_for_frame(mainw->current_file, frame);
6116       if (pull_frame_at_size(layer, get_image_ext_for_type(cfile->img_type), tc, width, height, WEED_PALETTE_RGB24)) {
6117         check_layer_ready(layer);
6118         interp = get_interp_value(prefs->pb_quality, TRUE);
6119         if (!resize_layer(layer, width, height, interp, WEED_PALETTE_RGB24, 0) ||
6120             !convert_layer_palette(layer, WEED_PALETTE_RGB24, 0)) {
6121           weed_layer_free(layer);
6122           if (xmd5sum) lives_free(xmd5sum);
6123           return;
6124         }
6125       }
6126     }
6127 
6128     if (!end_pixbuf || lives_pixbuf_get_width(end_pixbuf) != width || lives_pixbuf_get_height(end_pixbuf) != height) {
6129       if (!orig_pixbuf) {
6130         if (layer) orig_pixbuf = layer_to_pixbuf(layer, TRUE, TRUE);
6131         else orig_pixbuf = end_pixbuf;
6132       }
6133       if (end_pixbuf != orig_pixbuf && LIVES_IS_PIXBUF(end_pixbuf)) {
6134         lives_widget_object_unref(end_pixbuf);
6135         end_pixbuf = NULL;
6136       }
6137       if (LIVES_IS_PIXBUF(orig_pixbuf)) {
6138         if (lives_pixbuf_get_width(orig_pixbuf) == width && lives_pixbuf_get_height(orig_pixbuf) == height)
6139           end_pixbuf = orig_pixbuf;
6140         else {
6141           end_pixbuf = lives_pixbuf_scale_simple(orig_pixbuf, width, height, LIVES_INTERP_BEST);
6142         }
6143       }
6144     }
6145 
6146     if (LIVES_IS_PIXBUF(end_pixbuf)) {
6147       set_drawing_area_from_pixbuf(mainw->end_image, end_pixbuf, mainw->ei_surface);
6148     }
6149 
6150 #if !GTK_CHECK_VERSION(3, 0, 0)
6151     lives_widget_queue_resize(mainw->end_image);
6152     lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET, TRUE);
6153   } while (rwidth != lives_widget_get_allocation_width(mainw->end_image) ||
6154            rheight != lives_widget_get_allocation_height(mainw->end_image));
6155 #if 0
6156   {
6157 #endif
6158 #else
6159   } while (FALSE);
6160 #endif
6161 
6162     if (end_pixbuf != orig_pixbuf && LIVES_IS_PIXBUF(end_pixbuf)) {
6163       lives_widget_object_unref(end_pixbuf);
6164     }
6165 
6166     if (LIVES_IS_PIXBUF(orig_pixbuf)) {
6167       if (!cache_it || weed_layer_get_pixel_data_packed(layer) || !(pixbuf_to_layer(layer, orig_pixbuf)))
6168         lives_widget_object_unref(orig_pixbuf);
6169     } else cache_it = FALSE;
6170 
6171     if (!cache_it) {
6172       weed_layer_free(layer);
6173       mainw->en_fcache = NULL;
6174     } else {
6175       if (!mainw->en_fcache) {
6176         mainw->en_fcache = layer;
6177         if (!is_virtual_frame(mainw->current_file, frame)) {
6178           if (cfile->clip_type == CLIP_TYPE_DISK && capable->has_md5sum) {
6179             if (!xmd5sum) {
6180               char *fname = make_image_file_name(cfile, frame, get_image_ext_for_type(cfile->img_type));
6181               xmd5sum = get_md5sum(fname);
6182               lives_free(fname);
6183             }
6184             weed_set_string_value(layer, WEED_LEAF_MD5SUM, xmd5sum);
6185 	  // *INDENT-OFF*
6186 	}}
6187       lives_layer_set_frame(layer, xpf);
6188       lives_layer_set_clip(layer, mainw->current_file);
6189     }}
6190   // *INDENT-ON*
6191     if (xmd5sum) lives_free(xmd5sum);
6192   }
6193 #if 0
6194 }
6195 #endif
6196 
6197 #ifndef IS_LIBLIVES
main(int argc,char * argv[])6198 int main(int argc, char *argv[]) {
6199   // call any hooks here
6200   return real_main(argc, argv, NULL, 0l);
6201 }
6202 #endif
6203 
6204 
load_preview_image(boolean update_always)6205 void load_preview_image(boolean update_always) {
6206   // this is for the sepwin preview
6207   // update_always==TRUE = update widgets from mainw->preview_frame
6208   LiVESPixbuf *pixbuf = NULL;
6209   weed_layer_t *layer = NULL;
6210   boolean cache_it = TRUE;
6211   char *xmd5sum = NULL;
6212   char *fname = NULL;
6213   frames_t xpf = -1;
6214   int tries = 2;
6215   int preview_frame;
6216   int width, height;
6217 
6218   if (!prefs->show_gui) return;
6219   if (LIVES_IS_PLAYING) return;
6220 
6221   lives_widget_set_opacity(mainw->preview_image, 1.);
6222 
6223   if (CURRENT_CLIP_IS_VALID && (cfile->clip_type == CLIP_TYPE_YUV4MPEG || cfile->clip_type == CLIP_TYPE_VIDEODEV)) {
6224     if (!mainw->camframe) {
6225       LiVESError *error = NULL;
6226       char *fname = lives_strdup_printf("%s.%s", THEME_FRAME_IMG_LITERAL, LIVES_FILE_EXT_JPG);
6227       char *tmp = lives_build_filename(prefs->prefix_dir, THEME_DIR, LIVES_THEME_CAMERA, fname, NULL);
6228       mainw->camframe = lives_pixbuf_new_from_file(tmp, &error);
6229       if (mainw->camframe) lives_pixbuf_saturate_and_pixelate(mainw->camframe, mainw->camframe, 0.0, FALSE);
6230       lives_free(tmp); lives_free(fname);
6231       fname = NULL;
6232     }
6233     pixbuf = lives_pixbuf_scale_simple(mainw->camframe, mainw->pwidth, mainw->pheight, LIVES_INTERP_BEST);
6234     set_drawing_area_from_pixbuf(mainw->preview_image, pixbuf, mainw->pi_surface);
6235     if (pixbuf) lives_widget_object_unref(pixbuf);
6236     mainw->preview_frame = 1;
6237     lives_signal_handler_block(mainw->preview_spinbutton, mainw->preview_spin_func);
6238     lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->preview_spinbutton), 1, 1);
6239     lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->preview_spinbutton), 1);
6240     lives_signal_handler_unblock(mainw->preview_spinbutton, mainw->preview_spin_func);
6241     lives_widget_set_size_request(mainw->preview_image, mainw->pwidth, mainw->pheight);
6242     return;
6243   }
6244 
6245   if (!CURRENT_CLIP_IS_NORMAL || !CURRENT_CLIP_HAS_VIDEO) {
6246     mainw->preview_frame = 0;
6247     lives_signal_handler_block(mainw->preview_spinbutton, mainw->preview_spin_func);
6248     lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->preview_spinbutton), 0, 0);
6249     lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->preview_spinbutton), 0);
6250     lives_signal_handler_unblock(mainw->preview_spinbutton, mainw->preview_spin_func);
6251     if (mainw->imframe) {
6252       lives_widget_set_size_request(mainw->preview_image, lives_pixbuf_get_width(mainw->imframe),
6253                                     lives_pixbuf_get_height(mainw->imframe));
6254       set_drawing_area_from_pixbuf(mainw->preview_image, mainw->imframe, mainw->pi_surface);
6255     } else set_drawing_area_from_pixbuf(mainw->preview_image, NULL, mainw->pi_surface);
6256     if (!palette || !(palette->style & STYLE_LIGHT)) {
6257       lives_widget_set_opacity(mainw->preview_image, 0.8);
6258     } else {
6259       lives_widget_set_opacity(mainw->preview_image, 0.4);
6260     }
6261     return;
6262   }
6263 
6264   if (!update_always) {
6265     // set current frame from spins, set range
6266     // set mainw->preview_frame to 0 before calling to force an update (e.g after a clip switch)
6267     switch (mainw->prv_link) {
6268     case PRV_END:
6269       preview_frame = cfile->end;
6270       break;
6271     case PRV_PTR:
6272       preview_frame = calc_frame_from_time(mainw->current_file, cfile->pointer_time);
6273       break;
6274     case PRV_START:
6275       preview_frame = cfile->start;
6276       break;
6277     default:
6278       preview_frame = mainw->preview_frame > 0 ? mainw->preview_frame : 1;
6279       if (preview_frame > cfile->frames) preview_frame = cfile->frames;
6280       break;
6281     }
6282 
6283     lives_signal_handler_block(mainw->preview_spinbutton, mainw->preview_spin_func);
6284     lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->preview_spinbutton), 1, cfile->frames);
6285     lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->preview_spinbutton), preview_frame);
6286     lives_signal_handler_unblock(mainw->preview_spinbutton, mainw->preview_spin_func);
6287 
6288     mainw->preview_frame = preview_frame;
6289   }
6290 
6291   if (mainw->preview_frame < 1 || mainw->preview_frame > cfile->frames) {
6292     pixbuf = lives_pixbuf_scale_simple(mainw->imframe, cfile->hsize, cfile->vsize, LIVES_INTERP_BEST);
6293     if (!palette || !(palette->style & STYLE_LIGHT)) {
6294       lives_widget_set_opacity(mainw->preview_image, 0.4);
6295     } else {
6296       lives_widget_set_opacity(mainw->preview_image, 0.8);
6297     }
6298   } else {
6299     weed_timecode_t tc;
6300     xpf = ABS(get_indexed_frame(mainw->current_file, mainw->preview_frame));
6301 check_prcache:
6302     if (mainw->pr_fcache) {
6303       if (lives_layer_get_clip(mainw->pr_fcache) == mainw->current_file
6304           && lives_layer_get_frame(mainw->pr_fcache) == xpf) {
6305         if (is_virtual_frame(mainw->current_file, mainw->preview_frame)) layer = mainw->pr_fcache;
6306         else {
6307           if (cfile->clip_type == CLIP_TYPE_DISK && capable->has_md5sum) {
6308             char *md5sum = weed_get_string_value(mainw->pr_fcache, WEED_LEAF_MD5SUM, NULL);
6309             if (md5sum) {
6310               if (!fname) fname = make_image_file_name(cfile, mainw->preview_frame, get_image_ext_for_type(cfile->img_type));
6311               if (!xmd5sum) xmd5sum = get_md5sum(fname);
6312               if (!lives_strcmp(md5sum, xmd5sum)) layer = mainw->pr_fcache;
6313               lives_free(md5sum);
6314 	      // *INDENT-OFF*
6315 	    }}}}}
6316     // *INDENT-ON*
6317     if (!layer) {
6318       if (mainw->pr_fcache) {
6319         if (mainw->pr_fcache != mainw->st_fcache && mainw->pr_fcache != mainw->en_fcache)
6320           weed_layer_free(mainw->pr_fcache);
6321         mainw->pr_fcache = NULL;
6322       }
6323       if (tries--) {
6324         if (tries == 1) mainw->pr_fcache = mainw->st_fcache;
6325         else mainw->pr_fcache = mainw->en_fcache;
6326         goto check_prcache;
6327       }
6328     }
6329     lives_freep((void **)&fname);
6330 
6331     // if we are not playing, and it would be slow to seek to the frame, convert it to an image
6332     if (!LIVES_IS_PLAYING && !layer && cfile->clip_type == CLIP_TYPE_FILE &&
6333         is_virtual_frame(mainw->current_file, mainw->preview_frame) &&
6334         cfile->ext_src) {
6335       lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
6336       if (cdata && !(cdata->seek_flag & LIVES_SEEK_FAST)) {
6337         virtual_to_images(mainw->current_file, mainw->preview_frame, mainw->preview_frame, FALSE, &pixbuf);
6338         cache_it = FALSE;
6339       }
6340     }
6341 
6342     width = cfile->hsize;
6343     height = cfile->vsize;
6344     if (prefs->ce_maxspect && !prefs->letterbox) {
6345       width = mainw->pwidth;
6346       height = mainw->pheight;
6347     }
6348     if (prefs->letterbox) {
6349       calc_maxspect(mainw->pwidth, mainw->pheight, &width, &height);
6350     }
6351 
6352     if (!layer && !pixbuf) {
6353       layer = lives_layer_new_for_frame(mainw->current_file, mainw->preview_frame);
6354       tc = ((mainw->preview_frame - 1.)) / cfile->fps * TICKS_PER_SECOND;
6355       if (pull_frame_at_size(layer, get_image_ext_for_type(cfile->img_type), tc, width, height,
6356                              WEED_PALETTE_RGB24)) {
6357         LiVESInterpType interp = get_interp_value(prefs->pb_quality, TRUE);
6358         check_layer_ready(layer);
6359         if (!resize_layer(layer, width, height, interp, WEED_PALETTE_RGB24, 0) ||
6360             !convert_layer_palette(layer, WEED_PALETTE_RGB24, 0)) {
6361           weed_layer_free(layer);
6362           if (xmd5sum) lives_free(xmd5sum);
6363           return;
6364         }
6365       }
6366     }
6367 
6368     if (!pixbuf || lives_pixbuf_get_width(pixbuf) != mainw->pwidth
6369         || lives_pixbuf_get_height(pixbuf) != mainw->pheight) {
6370       if (!pixbuf) {
6371         if (layer) pixbuf = layer_to_pixbuf(layer, TRUE, TRUE);
6372       }
6373     }
6374 
6375     if (LIVES_IS_PIXBUF(pixbuf)) {
6376       LiVESPixbuf *pr_pixbuf = NULL;
6377       if (lives_pixbuf_get_width(pixbuf) == width && lives_pixbuf_get_height(pixbuf) == height)
6378         pr_pixbuf = pixbuf;
6379       else {
6380         pr_pixbuf = lives_pixbuf_scale_simple(pixbuf, width, height, LIVES_INTERP_BEST);
6381       }
6382       if (LIVES_IS_PIXBUF(pr_pixbuf)) {
6383         lives_widget_set_size_request(mainw->preview_image, MAX(width, mainw->sepwin_minwidth), height);
6384         set_drawing_area_from_pixbuf(mainw->preview_image, pr_pixbuf, mainw->pi_surface);
6385         if (pr_pixbuf != pixbuf) lives_widget_object_unref(pr_pixbuf);
6386         if (!layer || !cache_it || weed_layer_get_pixel_data_packed(layer) || !(pixbuf_to_layer(layer, pixbuf)))
6387           lives_widget_object_unref(pixbuf);
6388       } else cache_it = FALSE;
6389     } else cache_it = FALSE;
6390   }
6391 
6392   if (!cache_it) {
6393     weed_layer_free(layer);
6394     mainw->pr_fcache = NULL;
6395   } else {
6396     if (!mainw->pr_fcache) {
6397       mainw->pr_fcache = layer;
6398       if (!is_virtual_frame(mainw->current_file, mainw->preview_frame)) {
6399         if (cfile->clip_type == CLIP_TYPE_DISK && capable->has_md5sum) {
6400           if (!xmd5sum) {
6401             char *fname = make_image_file_name(cfile, mainw->preview_frame,
6402                                                get_image_ext_for_type(cfile->img_type));
6403             xmd5sum = get_md5sum(fname);
6404             lives_free(fname);
6405           }
6406           weed_set_string_value(layer, WEED_LEAF_MD5SUM, xmd5sum);
6407 	  // *INDENT-OFF*
6408 	}}
6409       lives_layer_set_frame(layer, xpf);
6410       lives_layer_set_clip(layer, mainw->current_file);
6411     }}
6412   // *INDENT-ON*
6413 
6414   if (update_always) {
6415     // set spins from current frame
6416     switch (mainw->prv_link) {
6417     case PRV_PTR:
6418       //cf. hrule_reset
6419       cfile->pointer_time = lives_ce_update_timeline(mainw->preview_frame, 0.);
6420       if (cfile->frames > 0) cfile->frameno = calc_frame_from_time(mainw->current_file,
6421                                                 cfile->pointer_time);
6422       if (cfile->pointer_time > 0.) {
6423         lives_widget_set_sensitive(mainw->rewind, TRUE);
6424         lives_widget_set_sensitive(mainw->trim_to_pstart, CURRENT_CLIP_HAS_AUDIO);
6425         lives_widget_set_sensitive(mainw->m_rewindbutton, TRUE);
6426         if (mainw->preview_box) {
6427           lives_widget_set_sensitive(mainw->p_rewindbutton, TRUE);
6428         }
6429       }
6430       mainw->ptrtime = cfile->pointer_time;
6431       lives_widget_queue_draw(mainw->eventbox2);
6432       break;
6433 
6434     case PRV_START:
6435       if (mainw->st_fcache && mainw->st_fcache != mainw->pr_fcache && mainw->st_fcache != mainw->en_fcache) {
6436         weed_layer_free(mainw->st_fcache);
6437       }
6438       mainw->st_fcache = mainw->pr_fcache;
6439       if (cfile->start != mainw->preview_frame) {
6440         lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), mainw->preview_frame);
6441         lives_spin_button_update(LIVES_SPIN_BUTTON(mainw->spinbutton_start));
6442         get_play_times();
6443       }
6444       break;
6445 
6446     case PRV_END:
6447       if (mainw->en_fcache && mainw->en_fcache != mainw->pr_fcache && mainw->en_fcache != mainw->st_fcache) {
6448         weed_layer_free(mainw->en_fcache);
6449       }
6450       mainw->en_fcache = mainw->pr_fcache;
6451       if (cfile->end != mainw->preview_frame) {
6452         lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), mainw->preview_frame);
6453         lives_spin_button_update(LIVES_SPIN_BUTTON(mainw->spinbutton_end));
6454         get_play_times();
6455       }
6456       break;
6457 
6458     default:
6459       lives_widget_set_sensitive(mainw->rewind, FALSE);
6460       lives_widget_set_sensitive(mainw->trim_to_pstart, FALSE);
6461       lives_widget_set_sensitive(mainw->m_rewindbutton, FALSE);
6462       if (mainw->preview_box) {
6463         lives_widget_set_sensitive(mainw->p_rewindbutton, FALSE);
6464       }
6465       break;
6466     }
6467   }
6468   if (xmd5sum) lives_free(xmd5sum);
6469 }
6470 
6471 
6472 #ifndef NO_PROG_LOAD
6473 
6474 #ifdef GUI_GTK
pbsize_set(GdkPixbufLoader * pbload,int xxwidth,int xxheight,livespointer ptr)6475 static void pbsize_set(GdkPixbufLoader * pbload, int xxwidth, int xxheight, livespointer ptr) {
6476   if (xxwidth * xxheight > 0) gdk_pixbuf_loader_set_size(pbload, xxwidth, xxheight);
6477 }
6478 #endif
6479 
6480 #endif
6481 
6482 
6483 #ifdef USE_LIBPNG
6484 #ifdef PNG_ASSEMBLER_CODE_SUPPORTED
6485 static png_uint_32 png_flags;
6486 #endif
6487 static int png_flagstate = 0;
6488 
png_init(png_structp png_ptr)6489 static void png_init(png_structp png_ptr) {
6490   png_uint_32 mask = 0;
6491 #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
6492 #ifdef PNG_SELECT_READ
6493   int selection = PNG_SELECT_READ;// | PNG_SELECT_WRITE;
6494   int mmxsupport = png_mmx_support(); // -1 = not compiled, 0 = not on machine, 1 = OK
6495   mask = png_get_asm_flagmask(selection);
6496 
6497   if (mmxsupport < 1) {
6498     int compilerID;
6499     mask &= ~(png_get_mmx_flagmask(selection, &compilerID));
6500     /* if (prefs->show_dev_opts) { */
6501     /*   g_printerr(" without MMX features (%d)\n", mmxsupport); */
6502     /* } */
6503   } else {
6504     /* if (prefs->show_dev_opts) { */
6505     /*   g_printerr(" with MMX features\n"); */
6506     /* } */
6507   }
6508 #endif
6509 #endif
6510 
6511 #if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED)	\
6512   && defined(PNG_THREAD_UNSAFE_OK)
6513   /* Disable thread-unsafe features of pnggccrd */
6514   if (png_access_version() >= 10200) {
6515     mask &= ~(PNG_ASM_FLAG_MMX_READ_COMBINE_ROW
6516               | PNG_ASM_FLAG_MMX_READ_FILTER_SUB
6517               | PNG_ASM_FLAG_MMX_READ_FILTER_AVG
6518               | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH);
6519 
6520     if (prefs->show_dev_opts) {
6521       g_printerr("Thread unsafe features of libpng disabled.\n");
6522     }
6523   }
6524 #endif
6525 
6526   if (prefs->show_dev_opts && mask != 0) {
6527     uint64_t xmask = (uint64_t)mask;
6528     g_printerr("enabling png opts %lu\n", xmask);
6529   }
6530 
6531   if (!mask) png_flagstate = -1;
6532   else {
6533 #ifdef PNG_ASSEMBLER_CODE_SUPPORTED
6534     png_flags = png_get_asm_flags(png_ptr);
6535     png_flags |= mask;
6536     png_flagstate = 1;
6537 #endif
6538   }
6539 }
6540 
6541 #define PNG_BIO
6542 #ifdef PNG_BIO
png_read_func(png_structp png_ptr,png_bytep data,png_size_t length)6543 static void png_read_func(png_structp png_ptr, png_bytep data, png_size_t length) {
6544   int fd = LIVES_POINTER_TO_INT(png_get_io_ptr(png_ptr));
6545   //lives_file_buffer_t *fbuff = find_in_file_buffers(fd);
6546   if (lives_read_buffered(fd, data, length, TRUE) < length) {
6547     png_error(png_ptr, "read_fn error");
6548   }
6549 }
6550 #endif
6551 
6552 typedef struct {
6553   weed_layer_t *layer;
6554   int width, height;
6555   LiVESInterpType interp;
6556   int pal, clamp;
6557 } resl_priv_data;
6558 
6559 
6560 #ifdef USE_RESTHREAD
res_thrdfunc(void * arg)6561 static void res_thrdfunc(void *arg) {
6562   resl_priv_data *priv = (resl_priv_data *)arg;
6563   resize_layer(priv->layer, priv->width, priv->height, priv->interp, priv->pal, priv->clamp);
6564   weed_set_voidptr_value(priv->layer, WEED_LEAF_RESIZE_THREAD, NULL);
6565   lives_free(priv);
6566 }
6567 
6568 
reslayer_thread(weed_layer_t * layer,int twidth,int theight,LiVESInterpType interp,int tpalette,int clamp,double file_gamma)6569 static void reslayer_thread(weed_layer_t *layer, int twidth, int theight, LiVESInterpType interp,
6570                             int tpalette, int clamp, double file_gamma) {
6571   resl_priv_data *priv = (resl_priv_data *)lives_malloc(sizeof(resl_priv_data));
6572   lives_proc_thread_t resthread;
6573   weed_set_double_value(layer, "file_gamma", file_gamma);
6574   priv->layer = layer;
6575   priv->width = twidth;
6576   priv->height = theight;
6577   priv->interp = interp;
6578   priv->pal = tpalette;
6579   priv->clamp = clamp;
6580   resthread = lives_proc_thread_create(LIVES_THRDATTR_NO_GUI, (lives_funcptr_t)res_thrdfunc, -1, "v", priv);
6581   weed_set_voidptr_value(layer, WEED_LEAF_RESIZE_THREAD, resthread);
6582 }
6583 #endif
6584 
6585 
layer_from_png(int fd,weed_layer_t * layer,int twidth,int theight,int tpalette,boolean prog)6586 boolean layer_from_png(int fd, weed_layer_t *layer, int twidth, int theight, int tpalette, boolean prog) {
6587   png_structp png_ptr;
6588   png_infop info_ptr;
6589   double file_gamma;
6590   int gval;
6591 #ifndef PNG_BIO
6592   FILE *fp = fdopen(fd, "rb");
6593   size_t bsize = fread(ibuff, 1, 8, fp);
6594   boolean is_png = TRUE;
6595   unsigned char ibuff[8];
6596 #endif
6597 
6598   unsigned char **row_ptrs;
6599   unsigned char *ptr;
6600 
6601   boolean is16bit = FALSE;
6602 
6603   png_uint_32 xwidth, xheight;
6604 
6605   int width, height;
6606   int color_type, bit_depth;
6607   int rowstride;
6608   int flags, privflags;
6609 
6610   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
6611 
6612   if (!png_ptr) {
6613 #ifndef PNG_BIO
6614     fclose(fp);
6615 #endif
6616     return FALSE;
6617   }
6618 
6619 #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
6620   if (!png_flagstate) png_init(png_ptr);
6621 #ifdef PNG_ASSEMBLER_CODE_SUPPORTED
6622   if (png_flagstate == 1) png_set_asm_flags(png_ptr, png_flags);
6623 #endif
6624 #endif
6625 
6626   info_ptr = png_create_info_struct(png_ptr);
6627 
6628   if (!info_ptr) {
6629     png_destroy_read_struct(&png_ptr, NULL, NULL);
6630 #ifndef PNG_BIO
6631     fclose(fp);
6632 #endif
6633     return FALSE;
6634   }
6635 
6636   if (setjmp(png_jmpbuf(png_ptr))) {
6637     // libpng will longjump to here on error
6638 #ifdef USE_RESTHREAD
6639     weed_set_int_value(layer, WEED_LEAF_PROGSCAN, 0);
6640 #endif
6641     png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
6642 #ifndef PNG_BIO
6643     fclose(fp);
6644 #endif
6645     return FALSE;
6646   }
6647 
6648 #ifdef PNG_BIO
6649   png_set_read_fn(png_ptr, LIVES_INT_TO_POINTER(fd), png_read_func);
6650 #ifndef VALGRIND_ON
6651   png_set_sig_bytes(png_ptr, 8);
6652 #else
6653   png_set_sig_bytes(png_ptr, 0);
6654 #endif
6655 #else
6656   png_init_io(png_ptr, fp);
6657   png_set_sig_bytes(png_ptr, bsize);
6658 #endif
6659 
6660   // read header info
6661   png_read_info(png_ptr, info_ptr);
6662   png_get_IHDR(png_ptr, info_ptr, &xwidth, &xheight,
6663                NULL, NULL, NULL,
6664                NULL, NULL);
6665   if (xwidth > 0 && xheight > 0) {
6666     weed_set_int_value(layer, WEED_LEAF_WIDTH, xwidth);
6667     weed_set_int_value(layer, WEED_LEAF_HEIGHT, xheight);
6668 
6669     privflags = weed_get_int_value(layer, WEED_LEAF_HOST_FLAGS, NULL);
6670     weed_set_int_value(layer, WEED_LEAF_HOST_FLAGS, privflags | LIVES_LAYER_HAS_SIZE_NOW);
6671     if (privflags == LIVES_LAYER_GET_SIZE_ONLY
6672         || (privflags == LIVES_LAYER_LOAD_IF_NEEDS_RESIZE
6673             && (int)xwidth == twidth && (int)xheight == theight)) {
6674       png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
6675 #ifndef PNG_BIO
6676       fclose(fp);
6677 #endif
6678       return TRUE;
6679     }
6680   }
6681 
6682   flags = weed_layer_get_flags(layer);
6683 
6684 #if PNG_LIBPNG_VER >= 10504
6685   if (prefs->alpha_post) {
6686     if (flags & WEED_LAYER_ALPHA_PREMULT) flags ^= WEED_LAYER_ALPHA_PREMULT;
6687     png_set_alpha_mode(png_ptr, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
6688   } else {
6689     flags |= WEED_LAYER_ALPHA_PREMULT;
6690     png_set_alpha_mode(png_ptr, PNG_ALPHA_PREMULTIPLIED, PNG_DEFAULT_sRGB);
6691   }
6692 #endif
6693 
6694   weed_set_int_value(layer, WEED_LEAF_FLAGS, flags);
6695 
6696   color_type = png_get_color_type(png_ptr, info_ptr);
6697   bit_depth = png_get_bit_depth(png_ptr, info_ptr);
6698   gval = png_get_gAMA(png_ptr, info_ptr, &file_gamma);
6699 
6700   if (!gval) {
6701     // b > a, brighter
6702     //png_set_gamma(png_ptr, 1.0, .45455); /// default, seemingly
6703     //png_set_gamma(png_ptr, 1. / .45455, 1.0); /// too bright
6704     png_set_gamma(png_ptr, 1.0, 1.0);
6705   }
6706 
6707   if (gval == PNG_INFO_gAMA) {
6708     weed_set_int_value(layer, WEED_LEAF_GAMMA_TYPE, WEED_GAMMA_LINEAR);
6709   }
6710 
6711   // want to convert everything (greyscale, RGB, RGBA64 etc.) to RGBA32 (or RGB24)
6712   if (color_type == PNG_COLOR_TYPE_PALETTE)
6713     png_set_palette_to_rgb(png_ptr);
6714 
6715   if (png_get_valid(png_ptr, info_ptr,
6716                     PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr);
6717 
6718   if (color_type == PNG_COLOR_TYPE_GRAY &&
6719       bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr);
6720 
6721   if (color_type == PNG_COLOR_TYPE_GRAY ||
6722       color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
6723     png_set_gray_to_rgb(png_ptr);
6724 
6725   if (bit_depth == 16) {
6726     // if tpalette is YUV, then recreate the pixel_data with double the width
6727     // and mark as 16bpc, then >> 8 when doing the conversion
6728 #ifdef xUSE_16BIT_PCONV
6729     /// needs testing
6730     if (weed_palette_is_yuv(tpalette)) {
6731       width *= 2;
6732       is16bit = TRUE;
6733     } else {
6734 #endif
6735 #if PNG_LIBPNG_VER >= 10504
6736       png_set_scale_16(png_ptr);
6737 #else
6738       png_set_strip_16(png_ptr);
6739 #endif
6740 #ifdef xUSE_16BIT_PCONV
6741     }
6742 #endif
6743   }
6744 
6745   if (tpalette != WEED_PALETTE_END) {
6746     if (weed_palette_has_alpha(tpalette)) {
6747       // if target has alpha, add a channel
6748       if (color_type != PNG_COLOR_TYPE_RGB_ALPHA &&
6749           color_type != PNG_COLOR_TYPE_GRAY_ALPHA) {
6750         if (tpalette == WEED_PALETTE_ARGB32)
6751           png_set_add_alpha(png_ptr, 255, PNG_FILLER_BEFORE);
6752         else
6753           png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER);
6754         color_type = PNG_COLOR_TYPE_RGB_ALPHA;
6755       } else {
6756         if (tpalette == WEED_PALETTE_ARGB32) {
6757           png_set_swap_alpha(png_ptr);
6758         }
6759       }
6760     } else {
6761       // else remove it
6762       if (color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
6763           color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
6764         png_set_strip_alpha(png_ptr);
6765         color_type = PNG_COLOR_TYPE_RGB;
6766       }
6767     }
6768     if (tpalette == WEED_PALETTE_BGR24 || tpalette == WEED_PALETTE_BGRA32) {
6769       png_set_bgr(png_ptr);
6770     }
6771   }
6772 
6773   // unnecessary for read_image or if we set npass
6774   //png_set_interlace_handling(png_ptr);
6775 
6776   // read updated info with the new palette
6777   png_read_update_info(png_ptr, info_ptr);
6778 
6779   width = png_get_image_width(png_ptr, info_ptr);
6780   height = png_get_image_height(png_ptr, info_ptr);
6781 
6782   weed_set_int_value(layer, WEED_LEAF_WIDTH, width);
6783   weed_set_int_value(layer, WEED_LEAF_HEIGHT, height);
6784 
6785   if (weed_palette_is_rgb(tpalette)) {
6786     weed_layer_set_palette(layer, tpalette);
6787   } else {
6788     if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
6789       weed_layer_set_palette(layer, WEED_PALETTE_RGBA32);
6790     } else {
6791       weed_layer_set_palette(layer, WEED_PALETTE_RGB24);
6792     }
6793   }
6794 
6795   weed_layer_pixel_data_free(layer);
6796 
6797   if (!create_empty_pixel_data(layer, FALSE, TRUE)) {
6798     create_blank_layer(layer, LIVES_FILE_EXT_PNG, 4, 4, weed_layer_get_palette(layer));
6799 #ifndef PNG_BIO
6800     fclose(fp);
6801 #endif
6802     return FALSE;
6803   }
6804 
6805   // TODO: rowstride must be at least png_get_rowbytes(png_ptr, info_ptr)
6806 
6807   rowstride = weed_layer_get_rowstride(layer);
6808   ptr = weed_layer_get_pixel_data_packed(layer);
6809 
6810   // libpng needs pointers to each row
6811   row_ptrs = (unsigned char **)lives_malloc(height * sizeof(unsigned char *));
6812   for (int j = 0; j < height; j++) {
6813     row_ptrs[j] = ptr;
6814     ptr += rowstride;
6815   }
6816 
6817 #ifdef USE_RESTHREAD
6818   if (weed_threadsafe && twidth * theight != 0 && (twidth != width || theight != height) &&
6819       !png_get_interlace_type(png_ptr, info_ptr)) {
6820     weed_set_int_value(layer, WEED_LEAF_PROGSCAN, 1);
6821     reslayer_thread(layer, twidth, theight, get_interp_value(prefs->pb_quality, TRUE),
6822                     tpalette, weed_layer_get_yuv_clamping(layer),
6823                     gval == PNG_INFO_gAMA ? file_gamma : 1.);
6824     for (int j = 0; j < height; j++) {
6825       png_read_row(png_ptr, row_ptrs[j], NULL);
6826       weed_set_int_value(layer, WEED_LEAF_PROGSCAN, j + 1);
6827     }
6828     weed_set_int_value(layer, WEED_LEAF_PROGSCAN, -1);
6829   } else
6830 #endif
6831     png_read_image(png_ptr, row_ptrs);
6832 
6833   //png_read_end(png_ptr, NULL);
6834 
6835   // end read
6836 
6837   lives_free(row_ptrs);
6838 
6839   png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
6840 
6841   /// it seems that if no gAMA is set then libpng (rather wastefully) always tries to convert to linear
6842   /// assuming a file gamma of approx. 1.2* (this is not accurate since sRGB -> linear doesnt use a power law)
6843   /// if gAMA is set, then we (correctly) need to convert to linear using the file gamma
6844   /// *I think this comes from 0.5 (approx linear to sRGB) * 2,4 (guessed display gamma)
6845 
6846   if (gval == PNG_INFO_gAMA) {
6847     /// img needs gamma converting
6848     /// TODO: can we do this using png_set_gamma ?
6849     weed_layer_set_gamma(layer, WEED_GAMMA_LINEAR);
6850   } else weed_layer_set_gamma(layer, WEED_GAMMA_SRGB);
6851 
6852   if (is16bit) {
6853 #ifdef USE_RESTHREAD
6854     lives_proc_thread_t resthread;
6855 #endif
6856     int clamping, sampling, subspace;
6857     weed_layer_get_palette_yuv(layer, &clamping, &sampling, &subspace);
6858     weed_set_int_value(layer, WEED_LEAF_PIXEL_BITS, 16);
6859     if (weed_palette_has_alpha(tpalette)) tpalette = WEED_PALETTE_YUVA4444P;
6860     else {
6861       if (tpalette != WEED_PALETTE_YUV420P) tpalette = WEED_PALETTE_YUV444P;
6862     }
6863 #ifdef USE_RESTHREAD
6864     if ((resthread = weed_get_voidptr_value(layer, WEED_LEAF_RESIZE_THREAD, NULL))) {
6865       lives_proc_thread_join(resthread);
6866       weed_set_voidptr_value(layer, WEED_LEAF_RESIZE_THREAD, NULL);
6867     }
6868 #endif
6869     // convert RGBA -> YUVA4444P or RGB -> 444P or 420
6870     // 16 bit conversion
6871     convert_layer_palette_full(layer, tpalette, clamping, sampling, subspace, WEED_GAMMA_UNKNOWN);
6872   }
6873 #ifndef PNG_BIO
6874   fclose(fp);
6875 #endif
6876   return TRUE;
6877 }
6878 
6879 
6880 // unused
save_to_png(FILE * fp,weed_layer_t * layer,int comp)6881 boolean save_to_png(FILE * fp, weed_layer_t *layer, int comp) {
6882   // comp is 0 (none) - 9 (full)
6883   png_structp png_ptr;
6884   png_infop info_ptr;
6885 
6886   unsigned char *ptr;
6887 
6888   int width, height, palette;
6889 #if PNG_LIBPNG_VER >= 10504
6890   int flags = 0;
6891 #endif
6892   int rowstride;
6893 
6894   register int i;
6895 
6896   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
6897 
6898   if (!png_ptr) {
6899     fclose(fp);
6900     return FALSE;
6901   }
6902 
6903   info_ptr = png_create_info_struct(png_ptr);
6904 
6905   if (!info_ptr) {
6906     png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
6907     fclose(fp);
6908     return FALSE;
6909   }
6910 
6911   if (setjmp(png_jmpbuf(png_ptr))) {
6912     // libpng will longjump to here on error
6913     if (info_ptr) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
6914     png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
6915     return FALSE;
6916   }
6917 
6918   png_init_io(png_ptr, fp);
6919 
6920   width = weed_layer_get_width(layer);
6921   height = weed_layer_get_height(layer);
6922   rowstride = weed_layer_get_rowstride(layer);
6923   palette = weed_layer_get_palette(layer);
6924 
6925   if (width <= 0 || height <= 0 || rowstride <= 0) {
6926     LIVES_WARN("Cannot make png with 0 width or height");
6927     return FALSE;
6928   }
6929 
6930   switch (palette) {
6931   case WEED_PALETTE_RGB24:
6932   case WEED_PALETTE_BGR24:
6933     png_set_IHDR(png_ptr, info_ptr, width, height,
6934                  8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
6935                  PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
6936     break;
6937   case WEED_PALETTE_RGBA32:
6938   case WEED_PALETTE_BGRA32:
6939     png_set_IHDR(png_ptr, info_ptr, width, height,
6940                  8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
6941                  PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
6942     break;
6943   default:
6944     LIVES_ERROR("Bad png palette !\n");
6945     break;
6946   }
6947 
6948   png_set_compression_level(png_ptr, comp);
6949 
6950   //png_set_write_status_fn(png_ptr, png_row_callback);
6951 
6952 #if PNG_LIBPNG_VER >= 10504
6953   flags = weed_layer_get_flags(layer);
6954   if (flags & WEED_LAYER_ALPHA_PREMULT) {
6955     png_set_alpha_mode(png_ptr, PNG_ALPHA_PREMULTIPLIED, PNG_DEFAULT_sRGB);
6956   } else {
6957     png_set_alpha_mode(png_ptr, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
6958   }
6959 #endif
6960 
6961   if (weed_layer_get_gamma(layer) == WEED_GAMMA_LINEAR)
6962     png_set_gAMA(png_ptr, info_ptr, 1.0);
6963   else
6964     png_set_gAMA(png_ptr, info_ptr, 0.45455);
6965 
6966   png_write_info(png_ptr, info_ptr);
6967 
6968   ptr = (unsigned char *)weed_layer_get_pixel_data_packed(layer);
6969 
6970   // Write image data
6971   for (i = 0 ; i < height ; i++) {
6972     png_write_row(png_ptr, ptr);
6973     ptr += rowstride;
6974   }
6975 
6976   // end write
6977   png_write_end(png_ptr, (png_infop)NULL);
6978 
6979   if (info_ptr) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
6980   png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
6981 
6982   fflush(fp);
6983 
6984   return TRUE;
6985 }
6986 #endif
6987 
6988 
weed_layer_create_from_file_progressive(weed_layer_t * layer,const char * fname,int width,int height,int tpalette,const char * img_ext)6989 boolean weed_layer_create_from_file_progressive(weed_layer_t *layer, const char *fname, int width,
6990     int height, int tpalette, const char *img_ext) {
6991   LiVESPixbuf *pixbuf = NULL;
6992   LiVESError *gerror = NULL;
6993   boolean ret = TRUE;
6994 #ifndef VALGRIND_ON
6995   boolean is_png = FALSE;
6996 #endif
6997   int fd = -1;
6998 
6999 #ifndef NO_PROG_LOAD
7000 #ifdef GUI_GTK
7001   GdkPixbufLoader *pbload;
7002 #endif
7003   uint8_t ibuff[IMG_BUFF_SIZE];
7004   size_t bsize;
7005 
7006 #ifndef VALGRIND_ON
7007   if (!strcmp(img_ext, LIVES_FILE_EXT_PNG)) is_png = TRUE;
7008 #endif
7009 
7010 #ifdef PNG_BIO
7011   fd = lives_open_buffered_rdonly(fname);
7012   if (fd < 0) break_me(fname);
7013   if (fd < 0) return FALSE;
7014 #ifndef VALGRIND_ON
7015   if (is_png) lives_buffered_rdonly_slurp(fd, 8);
7016   else
7017     lives_buffered_rdonly_slurp(fd, 0);
7018 #endif
7019 #else
7020   fd = lives_open2(fname, O_RDONLY);
7021 #endif
7022   if (fd < 0) return FALSE;
7023 #ifndef PNG_BIO
7024 #ifdef HAVE_POSIX_FADVISE
7025   posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
7026 #endif
7027 #endif
7028 
7029   xxwidth = width;
7030   xxheight = height;
7031 
7032   if (!strcmp(img_ext, LIVES_FILE_EXT_PNG)) {
7033 #ifdef USE_LIBPNG
7034     tpalette = weed_layer_get_palette(layer);
7035     ret = layer_from_png(fd, layer, width, height, tpalette, TRUE);
7036     goto fndone;
7037 #endif
7038 
7039 #ifdef GUI_GTK
7040     pbload = gdk_pixbuf_loader_new_with_type(LIVES_IMAGE_TYPE_PNG, &gerror);
7041 #endif
7042   }
7043 #ifdef GUI_GTK
7044   else if (!strcmp(img_ext, LIVES_FILE_EXT_JPG)) pbload = gdk_pixbuf_loader_new_with_type(LIVES_IMAGE_TYPE_JPEG, &gerror);
7045   else pbload = gdk_pixbuf_loader_new();
7046 
7047   lives_signal_connect(LIVES_WIDGET_OBJECT(pbload), LIVES_WIDGET_SIZE_PREPARED_SIGNAL,
7048                        LIVES_GUI_CALLBACK(pbsize_set), NULL);
7049 
7050   while (1) {
7051 #ifndef PNG_BIO
7052     if ((bsize = read(fd, ibuff, IMG_BUFF_SIZE)) <= 0) break;
7053 #else
7054     if ((bsize = lives_read_buffered(fd, ibuff, IMG_BUFF_SIZE, TRUE)) <= 0) break;
7055 #endif
7056     if (!gdk_pixbuf_loader_write(pbload, ibuff, bsize, &gerror)) {
7057       ret = FALSE;
7058       goto fndone;
7059     }
7060   }
7061 
7062   if (!gdk_pixbuf_loader_close(pbload, &gerror)) {
7063     ret = FALSE;
7064     goto fndone;
7065   }
7066   pixbuf = gdk_pixbuf_loader_get_pixbuf(pbload);
7067   lives_widget_object_ref(pixbuf);
7068   if (pbload) lives_widget_object_unref(pbload);
7069 
7070 #endif
7071 
7072 # else //PROG_LOAD
7073 
7074 #ifdef USE_LIBPNG
7075   {
7076 #ifdef PNG_BIO
7077     fd = lives_open_buffered_rdonly(fname);
7078 #else
7079     fd = lives_open2(fname, O_RDONLY);
7080 #endif
7081 
7082     if (fd < 0) return FALSE;
7083 
7084 #ifndef PNG_BIO
7085 #ifdef HAVE_POSIX_FADVISE
7086     posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
7087 #endif
7088 #endif
7089     tpalette = weed_layer_get_palette(layer);
7090     ret = layer_from_png(fd, layer, width, height, tpalette, FALSE);
7091     goto fndone;
7092   }
7093 #endif
7094 
7095   pixbuf = lives_pixbuf_new_from_file_at_scale(fname, width > 0 ? width : -1, height > 0 ? height : -1, FALSE, gerror);
7096 #endif
7097 
7098   if (gerror) {
7099     LIVES_ERROR(gerror->message);
7100     lives_error_free(gerror);
7101     pixbuf = NULL;
7102   }
7103 
7104   if (!pixbuf) {
7105     ret = FALSE;
7106     goto fndone;
7107   }
7108 
7109   if (lives_pixbuf_get_has_alpha(pixbuf)) {
7110     /* unfortunately gdk pixbuf loader does not preserve the original alpha channel, instead it adds its own.
7111        We need to hence reset it back to opaque */
7112     lives_pixbuf_set_opaque(pixbuf);
7113     weed_layer_set_palette(layer, WEED_PALETTE_RGBA32);
7114   } else weed_layer_set_palette(layer, WEED_PALETTE_RGB24);
7115 
7116   if (!pixbuf_to_layer(layer, pixbuf)) {
7117     lives_widget_object_unref(pixbuf);
7118   }
7119 
7120 fndone:
7121 #ifdef PNG_BIO
7122   if (fd >= 0) {
7123     lives_close_buffered(fd);
7124   }
7125 #else
7126   if (fd >= 0) close(fd);
7127 #endif
7128 
7129   return ret;
7130 }
7131 
7132 
render_subs_from_file(lives_clip_t * sfile,double xtime,weed_layer_t * layer)7133 static weed_plant_t *render_subs_from_file(lives_clip_t *sfile, double xtime, weed_layer_t *layer) {
7134   // render subtitles from whatever (.srt or .sub) file
7135   // uses default values for colours, fonts, size, etc.
7136 
7137   // TODO - allow prefs settings for colours, fonts, size, alpha (use plugin for this)
7138 
7139   //char *sfont=mainw->font_list[prefs->sub_font];
7140   const char *sfont = "Sans";
7141   lives_colRGBA64_t col_white, col_black_a;
7142 
7143   int error, size;
7144 
7145   xtime -= (double)sfile->subt->offset / sfile->fps;
7146 
7147   // round to 2 dp
7148   xtime = (double)((int)(xtime * 100. + .5)) / 100.;
7149 
7150   if (xtime < 0.) return layer;
7151 
7152   get_subt_text(sfile, xtime);
7153 
7154   if (!sfile->subt->text) return layer;
7155 
7156   size = weed_get_int_value(layer, WEED_LEAF_WIDTH, &error) / 32;
7157 
7158   col_white = lives_rgba_col_new(65535, 65535, 65535, 65535);
7159   col_black_a = lives_rgba_col_new(0, 0, 0, SUB_OPACITY);
7160 
7161   if (prefs->apply_gamma && prefs->pb_quality == PB_QUALITY_HIGH) {
7162     // make it look nicer by dimming relative to luma
7163     gamma_convert_layer(WEED_GAMMA_LINEAR, layer);
7164   }
7165 
7166   layer = render_text_to_layer(layer, sfile->subt->text, sfont, size,
7167                                LIVES_TEXT_MODE_FOREGROUND_AND_BACKGROUND, &col_white, &col_black_a, TRUE, TRUE, 0.);
7168   return layer;
7169 }
7170 
7171 
pull_frame_at_size(weed_layer_t * layer,const char * image_ext,weed_timecode_t tc,int width,int height,int target_palette)7172 boolean pull_frame_at_size(weed_layer_t *layer, const char *image_ext, weed_timecode_t tc, int width, int height,
7173                            int target_palette) {
7174   // pull a frame from an external source into a layer
7175   // the WEED_LEAF_CLIP and WEED_LEAF_FRAME leaves must be set in layer
7176   // tc is used instead of WEED_LEAF_FRAME for some sources (e.g. generator plugins)
7177   // image_ext is used if the source is an image file (eg. "jpg" or "png")
7178   // width and height are hints only, the caller should resize if necessary
7179   // target_palette is also a hint
7180 
7181   // if we pull from a decoder plugin, then we may also deinterlace
7182   weed_plant_t *vlayer;
7183   lives_clip_t *sfile = NULL;
7184   int clip = lives_layer_get_clip(layer);
7185   frames_t frame = lives_layer_get_frame(layer);
7186   int clip_type;
7187 
7188   boolean is_thread = FALSE;
7189 
7190   // the default unless overridden
7191   weed_layer_set_gamma(layer, WEED_GAMMA_SRGB);
7192 
7193   if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_PTHREAD)) is_thread = TRUE;
7194 
7195   weed_layer_pixel_data_free(layer);
7196   weed_leaf_delete(layer, WEED_LEAF_NATURAL_SIZE);
7197 
7198   mainw->osc_block = TRUE; // block OSC until we are done
7199 
7200   if (clip < 0 && frame == 0) clip_type = CLIP_TYPE_DISK;
7201   else {
7202     sfile = mainw->files[clip];
7203     if (!sfile) {
7204       mainw->osc_block = FALSE;
7205       return FALSE;
7206     }
7207     clip_type = sfile->clip_type;
7208   }
7209 
7210   switch (clip_type) {
7211   case CLIP_TYPE_NULL_VIDEO:
7212     mainw->osc_block = FALSE;
7213     create_blank_layer(layer, image_ext, width, height, target_palette);
7214     return TRUE;
7215   case CLIP_TYPE_DISK:
7216   case CLIP_TYPE_FILE:
7217     // frame number can be 0 during rendering
7218     if (frame == 0) {
7219       mainw->osc_block = FALSE;
7220       create_blank_layer(layer, image_ext, width, height, target_palette);
7221       return TRUE;
7222     } else if (clip == mainw->scrap_file) {
7223       boolean res = load_from_scrap_file(layer, frame);
7224       if (!res) {
7225         create_blank_layer(layer, image_ext, width, height, target_palette);
7226         return FALSE;
7227       }
7228       weed_leaf_delete(layer, WEED_LEAF_HOST_PIXBUF_SRC);
7229       weed_leaf_delete(layer, WEED_LEAF_HOST_SURFACE_SRC);
7230       // clip width and height may vary dynamically
7231       if (LIVES_IS_PLAYING) {
7232         sfile->hsize = weed_layer_get_width(layer);
7233         sfile->vsize = weed_layer_get_height(layer);
7234       }
7235       // realign
7236       copy_pixel_data(layer, NULL, THREADVAR(rowstride_alignment));
7237       mainw->osc_block = FALSE;
7238       return TRUE;
7239     } else {
7240       if (sfile->clip_type == CLIP_TYPE_FILE && sfile->frame_index && frame > 0 &&
7241           frame <= sfile->frames && is_virtual_frame(clip, frame)) {
7242         // pull frame from video clip
7243         ///
7244 #ifdef USE_REC_RS
7245         int nplanes;
7246 #endif
7247         void **pixel_data;
7248         boolean res = TRUE;
7249         int *rowstrides;
7250         lives_decoder_t *dplug = NULL;
7251         /// HOST_DECODER is set in mulitrack, there is 1 decoder per track since multiple tracks can have the same clip
7252         if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_DECODER)) {
7253           dplug = (lives_decoder_t *)weed_get_voidptr_value(layer, WEED_LEAF_HOST_DECODER, NULL);
7254         } else {
7255           /// experimental, multiple decoder plugins for each sfile,,,
7256           if (weed_plant_has_leaf(layer, "alt_src")) {
7257             int srcnum = weed_get_int_value(layer, "alt_src", NULL);
7258             dplug = sfile->alt_srcs[srcnum];
7259           }
7260           if (!dplug) dplug = (lives_decoder_t *)sfile->ext_src;
7261         }
7262         if (!dplug || !dplug->cdata) {
7263           create_blank_layer(layer, image_ext, width, height, target_palette);
7264           return FALSE;
7265         }
7266         if (target_palette != dplug->cdata->current_palette) {
7267           if (dplug->decoder->set_palette) {
7268             int opal = dplug->cdata->current_palette;
7269             int pal = best_palette_match(dplug->cdata->palettes, -1, target_palette);
7270             if (pal != opal) {
7271               dplug->cdata->current_palette = pal;
7272               if (!(*dplug->decoder->set_palette)(dplug->cdata)) {
7273                 dplug->cdata->current_palette = opal;
7274                 (*dplug->decoder->set_palette)(dplug->cdata);
7275               } else if (dplug->cdata->rec_rowstrides) {
7276                 lives_free(dplug->cdata->rec_rowstrides);
7277                 dplug->cdata->rec_rowstrides = NULL;
7278 		// *INDENT-OFF*
7279 	      }}}}
7280 	// *INDENT-ON*
7281 
7282         // TODO *** - check for auto-border : we might use width,height instead of frame_width,frame_height,
7283         // and handle this in the plugin
7284 
7285         if (!prefs->auto_nobord) {
7286           width = dplug->cdata->frame_width / weed_palette_get_pixels_per_macropixel(dplug->cdata->current_palette);
7287           height = dplug->cdata->frame_height;
7288         } else {
7289           width = dplug->cdata->width / weed_palette_get_pixels_per_macropixel(dplug->cdata->current_palette);
7290           height = dplug->cdata->height;
7291         }
7292 
7293         weed_layer_set_size(layer, width, height);
7294 
7295         if (weed_palette_is_yuv(dplug->cdata->current_palette))
7296           weed_layer_set_palette_yuv(layer, dplug->cdata->current_palette,
7297                                      dplug->cdata->YUV_clamping,
7298                                      dplug->cdata->YUV_sampling,
7299                                      dplug->cdata->YUV_subspace);
7300         else weed_layer_set_palette(layer, dplug->cdata->current_palette);
7301 
7302 #ifdef USE_REC_RS
7303         nplanes = weed_palette_get_nplanes(dplug->cdata->current_palette);
7304         if (!dplug->cdata->rec_rowstrides) {
7305           dplug->cdata->rec_rowstrides = lives_calloc(nplanes, sizint);
7306         } else {
7307           if (dplug->cdata->rec_rowstrides[0]) {
7308             weed_layer_set_rowstrides(layer, dplug->cdata->rec_rowstrides, nplanes);
7309             weed_leaf_set_flagbits(layer, WEED_LEAF_ROWSTRIDES, LIVES_FLAG_MAINTAIN_VALUE);
7310             lives_memset(dplug->cdata->rec_rowstrides, 0, nplanes * sizint);
7311           }
7312         }
7313 #endif
7314         if (create_empty_pixel_data(layer, TRUE, TRUE)) {
7315 #ifdef USE_REC_RS
7316           weed_leaf_clear_flagbits(layer, WEED_LEAF_ROWSTRIDES, LIVES_FLAG_MAINTAIN_VALUE);
7317 #endif
7318           pixel_data = weed_layer_get_pixel_data(layer, NULL);
7319         } else {
7320 #ifdef USE_REC_RS
7321           weed_leaf_clear_flagbits(layer, WEED_LEAF_ROWSTRIDES, LIVES_FLAG_MAINTAIN_VALUE);
7322 #endif
7323           create_blank_layer(layer, image_ext, width, height, target_palette);
7324           return FALSE;
7325         }
7326 
7327         if (!pixel_data || !pixel_data[0]) {
7328           char *msg = lives_strdup_printf("NULL pixel data for layer size %d X %d, palette %s\n", width, height,
7329                                           weed_palette_get_name_full(dplug->cdata->current_palette,
7330                                               dplug->cdata->YUV_clamping, dplug->cdata->YUV_subspace));
7331           LIVES_WARN(msg);
7332           lives_free(msg);
7333           create_blank_layer(layer, image_ext, width, height, target_palette);
7334           return FALSE;
7335         }
7336 
7337         rowstrides = weed_layer_get_rowstrides(layer, NULL);
7338 
7339         //static int last = -1;
7340         // try to pull frame from decoder plugin
7341         //if (sfile->frame_index[frame - 1] == last) break_me();
7342         //last = sfile->frame_index[frame - 1];
7343         if (!(*dplug->decoder->get_frame)(dplug->cdata, (int64_t)(sfile->frame_index[frame - 1]),
7344                                           rowstrides, sfile->vsize, pixel_data)) {
7345 
7346 #ifdef USE_REC_RS
7347           if (dplug->cdata->rec_rowstrides) lives_memset(dplug->cdata->rec_rowstrides, 0, nplanes * sizint);
7348 #endif
7349           if (prefs->show_dev_opts) g_print("Error loading frame %d (index value %d)\n", frame,
7350                                               sfile->frame_index[frame - 1]);
7351           // if get_frame fails, return a black frame
7352           if (!is_thread) {
7353             weed_layer_pixel_data_free(layer);
7354             if (!create_empty_pixel_data(layer, TRUE, TRUE)) {
7355               create_blank_layer(layer, image_ext, width, height, target_palette);
7356               return FALSE;
7357             }
7358           }
7359           res = FALSE;
7360         }
7361 
7362         lives_free(pixel_data);
7363         lives_free(rowstrides);
7364         if (res) {
7365           if (prefs->apply_gamma && prefs->pb_quality != PB_QUALITY_LOW) {
7366             if (dplug->cdata->frame_gamma != WEED_GAMMA_UNKNOWN) {
7367               weed_layer_set_gamma(layer, dplug->cdata->frame_gamma);
7368             } else if (dplug->cdata->YUV_subspace == WEED_YUV_SUBSPACE_BT709) {
7369               weed_layer_set_gamma(layer, WEED_GAMMA_BT709);
7370             }
7371           }
7372 
7373           // get_frame may now update YUV_clamping, YUV_sampling, YUV_subspace
7374           if (weed_palette_is_yuv(dplug->cdata->current_palette)) {
7375             weed_layer_set_palette_yuv(layer, dplug->cdata->current_palette,
7376                                        dplug->cdata->YUV_clamping,
7377                                        dplug->cdata->YUV_sampling,
7378                                        dplug->cdata->YUV_subspace);
7379             if (prefs->apply_gamma && prefs->pb_quality != PB_QUALITY_LOW) {
7380               if (weed_get_int_value(layer, WEED_LEAF_GAMMA_TYPE, NULL) == WEED_GAMMA_BT709) {
7381                 weed_set_int_value(layer, WEED_LEAF_YUV_SUBSPACE, WEED_YUV_SUBSPACE_BT709);
7382               }
7383               if (weed_get_int_value(layer, WEED_LEAF_YUV_SUBSPACE, NULL) == WEED_YUV_SUBSPACE_BT709) {
7384                 weed_set_int_value(layer, WEED_LEAF_GAMMA_TYPE, WEED_GAMMA_BT709);
7385               }
7386             }
7387           }
7388           // deinterlace
7389           if (sfile->deinterlace || (prefs->auto_deint && dplug->cdata->interlace != LIVES_INTERLACE_NONE)) {
7390             if (!is_thread) {
7391               deinterlace_frame(layer, tc);
7392             } else weed_set_boolean_value(layer, WEED_LEAF_HOST_DEINTERLACE, WEED_TRUE);
7393           }
7394         }
7395         mainw->osc_block = FALSE;
7396         return res;
7397       } else {
7398         // pull frame from decoded images
7399         boolean ret;
7400         char *fname = make_image_file_name(sfile, frame, image_ext);
7401 #ifdef USE_RESTHREAD
7402         lives_proc_thread_t resthread;
7403 #endif
7404         if (!*image_ext) image_ext = get_image_ext_for_type(sfile->img_type);
7405         ret = weed_layer_create_from_file_progressive(layer, fname, width, height, target_palette, image_ext);
7406 
7407 #ifdef USE_RESTHREAD
7408         if ((resthread = weed_get_voidptr_value(layer, WEED_LEAF_RESIZE_THREAD, NULL))) {
7409           lives_proc_thread_join(resthread);
7410           weed_set_voidptr_value(layer, WEED_LEAF_RESIZE_THREAD, NULL);
7411         }
7412 #endif
7413 
7414         lives_free(fname);
7415         mainw->osc_block = FALSE;
7416         if (!ret) {
7417           break_me("bad frame load from file");
7418           create_blank_layer(layer, image_ext, width, height, target_palette);
7419           return FALSE;
7420         }
7421       }
7422     }
7423     break;
7424 
7425     // handle other types of sources
7426 
7427 #ifdef HAVE_YUV4MPEG
7428   case CLIP_TYPE_YUV4MPEG:
7429     weed_layer_set_from_yuv4m(layer, sfile);
7430     if (sfile->deinterlace) {
7431       if (!is_thread) {
7432         deinterlace_frame(layer, tc);
7433       } else weed_set_boolean_value(layer, WEED_LEAF_HOST_DEINTERLACE, WEED_TRUE);
7434     }
7435     mainw->osc_block = FALSE;
7436     return TRUE;
7437 #endif
7438 #ifdef HAVE_UNICAP
7439   case CLIP_TYPE_VIDEODEV:
7440     weed_layer_set_from_lvdev(layer, sfile, 4. / cfile->pb_fps);
7441     if (sfile->deinterlace) {
7442       if (!is_thread) {
7443         deinterlace_frame(layer, tc);
7444       } else weed_set_boolean_value(layer, WEED_LEAF_HOST_DEINTERLACE, WEED_TRUE);
7445     }
7446     mainw->osc_block = FALSE;
7447     return TRUE;
7448 #endif
7449   case CLIP_TYPE_LIVES2LIVES:
7450     weed_layer_set_from_lives2lives(layer, clip, (lives_vstream_t *)sfile->ext_src);
7451     mainw->osc_block = FALSE;
7452     return TRUE;
7453   case CLIP_TYPE_GENERATOR: {
7454     // special handling for clips where host controls size
7455     // Note: vlayer is actually the out channel of the generator, so we should
7456     // never free it !
7457     weed_plant_t *inst = (weed_plant_t *)sfile->ext_src;
7458     if (inst) {
7459       int key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, NULL);
7460       while (filter_mutex_trylock(key)) {
7461         sched_yield();
7462         lives_usleep(prefs->sleep_time);
7463       }
7464       vlayer = weed_layer_create_from_generator(inst, tc, clip);
7465       weed_layer_copy(layer, vlayer); // layer is non-NULL, so copy by reference
7466       weed_layer_nullify_pixel_data(vlayer);
7467       filter_mutex_unlock(key);
7468     } else {
7469       mainw->osc_block = FALSE;
7470       create_blank_layer(layer, image_ext, width, height, target_palette);
7471     }
7472     mainw->osc_block = FALSE;
7473   }
7474   return TRUE;
7475   default:
7476     mainw->osc_block = FALSE;
7477     create_blank_layer(layer, image_ext, width, height, target_palette);
7478     return FALSE;
7479   }
7480   mainw->osc_block = FALSE;
7481 
7482   if (!is_thread) {
7483     // render subtitles from file
7484     if (prefs->show_subtitles && sfile->subt && sfile->subt->tfile > 0) {
7485       double xtime = (double)(frame - 1) / sfile->fps;
7486       layer = render_subs_from_file(sfile, xtime, layer);
7487     }
7488   }
7489 
7490   return TRUE;
7491 }
7492 
7493 
7494 /**
7495    @brief pull a frame from an external source into a layer
7496    the WEED_LEAF_CLIP and WEED_LEAF_FRAME leaves must be set in layer
7497    tc is used instead of WEED_LEAF_FRAME for some sources (e.g. generator plugins)
7498    image_ext is used if the source is an image file (eg. "jpg" or "png")
7499 */
pull_frame(weed_layer_t * layer,const char * image_ext,weed_timecode_t tc)7500 LIVES_GLOBAL_INLINE boolean pull_frame(weed_layer_t *layer, const char *image_ext, weed_timecode_t tc) {
7501   return pull_frame_at_size(layer, image_ext, tc, 0, 0, WEED_PALETTE_END);
7502 }
7503 
7504 
7505 /**
7506    @brief block until layer pixel_data is ready.
7507    This function should always be called for threaded layers, prior to freeing the layer, reading it's  properites, pixel data,
7508    resizing etc.
7509 
7510    We may also deinterlace and overlay subs here
7511    for the blend layer, we may also resize, convert palette, apply gamma in preparation for combining with the main layer
7512 
7513    if effects were applied then the frame_layer can depend on other layers, however
7514    these wil have been checked already when the effects were applied
7515 
7516    see also MACRO: is_layer_ready(layer) which can be called first to avoid the block, e.g.
7517 
7518    while (!is_layer_ready(layer)) {
7519    do_something_else();
7520    }
7521    check_layer_ready(layer); // won't block
7522 
7523    This function must be called at some point for every threaded frame, otherwise thread resources will be leaked.
7524 
7525    N.B. the name if this function is not the best, it will probably get renamed in th future to something like
7526    finish_layer.
7527 */
check_layer_ready(weed_layer_t * layer)7528 boolean check_layer_ready(weed_layer_t *layer) {
7529   int clip;
7530   boolean ready = TRUE;
7531   lives_clip_t *sfile;
7532   lives_thread_t *thrd;
7533 #ifdef USE_RESTHREAD
7534   lives_proc_thread_t resthread;
7535 #endif
7536   if (!layer) return FALSE;
7537 
7538   thrd = (lives_thread_t *)weed_get_voidptr_value(layer, WEED_LEAF_HOST_PTHREAD, NULL);
7539   if (thrd) {
7540     ready = FALSE;
7541     lives_thread_join(*thrd, NULL);
7542     weed_leaf_delete(layer, WEED_LEAF_HOST_PTHREAD);
7543     lives_free(thrd);
7544   }
7545 
7546 #ifdef USE_RESTHREAD
7547   if ((resthread = weed_get_voidptr_value(layer, WEED_LEAF_RESIZE_THREAD, NULL))) {
7548     ready = FALSE;
7549     lives_proc_thread_join(resthread);
7550     weed_set_voidptr_value(layer, WEED_LEAF_RESIZE_THREAD, NULL);
7551   }
7552 #endif
7553 
7554   if (ready) return TRUE;
7555 
7556   if (weed_get_boolean_value(layer, WEED_LEAF_HOST_DEINTERLACE, NULL) == WEED_TRUE) {
7557     weed_timecode_t tc = weed_get_int64_value(layer, WEED_LEAF_HOST_TC, NULL);
7558     deinterlace_frame(layer, tc);
7559     weed_set_boolean_value(layer, WEED_LEAF_HOST_DEINTERLACE, WEED_FALSE);
7560   }
7561 
7562   if (weed_plant_has_leaf(layer, WEED_LEAF_CLIP)) {
7563     // TODO: we should render subs before display, to avoid the text size changing
7564     clip = weed_get_int_value(layer, WEED_LEAF_CLIP, NULL);
7565     if (IS_VALID_CLIP(clip)) {
7566       sfile = mainw->files[clip];
7567       // render subtitles from file
7568       if (sfile->subt && sfile->subt->tfile >= 0 && prefs->show_subtitles) {
7569         frames_t frame = weed_get_int_value(layer, WEED_LEAF_FRAME, NULL);
7570         double xtime = (double)(frame - 1) / sfile->fps;
7571         layer = render_subs_from_file(sfile, xtime, layer);
7572 	// *INDENT-OFF*
7573       }}}
7574   // *INDENT-ON*
7575 
7576   return TRUE;
7577 }
7578 
7579 
7580 typedef struct {
7581   weed_layer_t *layer;
7582   weed_timecode_t tc;
7583   const char *img_ext;
7584   int width, height;
7585 } pft_priv_data;
7586 
7587 
pft_thread(void * in)7588 static void *pft_thread(void *in) {
7589   pft_priv_data *data = (pft_priv_data *)in;
7590   weed_layer_t *layer = data->layer;
7591   weed_timecode_t tc = data->tc;
7592   const char *img_ext = data->img_ext;
7593   int width = data->width, height = data->height;
7594   lives_free(in);
7595   /// if loading the blend frame in clip editor, then we recall the palette details and size @ injection,
7596   //and prepare it in this thread
7597   if (mainw->blend_file != -1 && mainw->blend_palette != WEED_PALETTE_END
7598       && LIVES_IS_PLAYING && !mainw->multitrack && mainw->blend_file != mainw->current_file
7599       && weed_get_int_value(layer, WEED_LEAF_CLIP, NULL) == mainw->blend_file) {
7600     int tgamma = WEED_GAMMA_UNKNOWN;
7601     short interp = get_interp_value(prefs->pb_quality, TRUE);
7602     pull_frame_at_size(layer, img_ext, tc, mainw->blend_width, mainw->blend_height, mainw->blend_palette);
7603     if (is_layer_ready(layer)) {
7604       resize_layer(layer, mainw->blend_width,
7605                    mainw->blend_height, interp, mainw->blend_palette, mainw->blend_clamping);
7606     }
7607     if (mainw->blend_palette != WEED_PALETTE_END) {
7608       if (weed_palette_is_rgb(mainw->blend_palette))
7609         tgamma = mainw->blend_gamma;
7610     }
7611     if (mainw->blend_palette != WEED_PALETTE_END) {
7612       if (is_layer_ready(layer) && weed_layer_get_width(layer) == mainw->blend_width
7613           && weed_layer_get_height(layer) == mainw->blend_height) {
7614         convert_layer_palette_full(layer, mainw->blend_palette, mainw->blend_clamping, mainw->blend_sampling,
7615                                    mainw->blend_subspace, tgamma);
7616       }
7617     }
7618     if (tgamma != WEED_GAMMA_UNKNOWN && is_layer_ready(layer)
7619         && weed_layer_get_width(layer) == mainw->blend_width
7620         && weed_layer_get_height(layer) == mainw->blend_height
7621         && weed_layer_get_palette(layer) == mainw->blend_palette)
7622       gamma_convert_layer(mainw->blend_gamma, layer);
7623   } else {
7624     pull_frame_at_size(layer, img_ext, tc, width, height, WEED_PALETTE_END);
7625   }
7626   weed_set_boolean_value(layer, WEED_LEAF_THREAD_PROCESSING, WEED_FALSE);
7627   return NULL;
7628 }
7629 
7630 
pull_frame_threaded(weed_layer_t * layer,const char * img_ext,weed_timecode_t tc,int width,int height)7631 void pull_frame_threaded(weed_layer_t *layer, const char *img_ext, weed_timecode_t tc, int width, int height) {
7632   // pull a frame from an external source into a layer
7633   // the WEED_LEAF_CLIP and WEED_LEAF_FRAME leaves must be set in layer
7634 
7635   // done in a threaded fashion
7636   // call check_layer_ready() to block until the frame thread is completed
7637 #ifdef NO_FRAME_THREAD
7638   pull_frame(layer, img_ext, tc);
7639   return;
7640 #else
7641   //#define MULT_SRC_TEST
7642 #ifdef MULT_SRC_TEST
7643   if (layer == mainw->frame_layer_preload) {
7644     int clip = mainw->pred_clip;
7645     if (IS_VALID_CLIP(clip)) {
7646       lives_clip_t *sfile = mainw->files[clip];
7647       if (sfile->clip_type == CLIP_TYPE_FILE) {
7648         if (!sfile->alt_srcs) {
7649           sfile->alt_srcs = lives_calloc(1, sizeof(void *));
7650           sfile->alt_srcs[0] = clone_decoder(clip);
7651           if (sfile->alt_srcs[0]) {
7652             weed_set_int_value(layer, "alt_src", 0);
7653             sfile->alt_src_types = lives_calloc(1, sizint);
7654             sfile->alt_src_types[0] = LIVES_EXT_SRC_DECODER;
7655 	    // *INDENT-OFF*
7656 	  }}}}}
7657 #endif
7658   // *INDENT-ON*
7659   weed_set_boolean_value(layer, WEED_LEAF_THREAD_PROCESSING, WEED_TRUE);
7660   if (1) {
7661     lives_thread_attr_t attr = LIVES_THRDATTR_PRIORITY;
7662     pft_priv_data *in = (pft_priv_data *)lives_calloc(1, sizeof(pft_priv_data));
7663     lives_thread_t *frame_thread = (lives_thread_t *)lives_calloc(1, sizeof(lives_thread_t));
7664     weed_set_int64_value(layer, WEED_LEAF_HOST_TC, tc);
7665     weed_set_boolean_value(layer, WEED_LEAF_HOST_DEINTERLACE, WEED_FALSE);
7666     weed_set_voidptr_value(layer, WEED_LEAF_HOST_PTHREAD, (void *)frame_thread);
7667     in->img_ext = img_ext;
7668     in->layer = layer;
7669     in->width = width;
7670     in->height = height;
7671     in->tc = tc;
7672     lives_thread_create(frame_thread, attr, pft_thread, (void *)in);
7673   }
7674 #endif
7675 // *INDENT-ON*
7676 }
7677 
pull_lives_pixbuf_at_size(int clip,int frame,const char * image_ext,weed_timecode_t tc,int width,int height,LiVESInterpType interp,boolean fordisp)7678 LiVESPixbuf *pull_lives_pixbuf_at_size(int clip, int frame, const char *image_ext, weed_timecode_t tc,
7679                                        int width, int height, LiVESInterpType interp, boolean fordisp) {
7680   // return a correctly sized (Gdk)Pixbuf (RGB24 for jpeg, RGB24 / RGBA32 for png) for the given clip and frame
7681   // tc is used instead of WEED_LEAF_FRAME for some sources (e.g. generator plugins)
7682   // image_ext is used if the source is an image file (eg. "jpg" or "png")
7683   // pixbuf will be sized to width x height pixels using interp
7684 
7685   LiVESPixbuf *pixbuf = NULL;
7686   weed_layer_t *layer = lives_layer_new_for_frame(clip, frame);
7687   int palette;
7688 
7689 #ifndef ALLOW_PNG24
7690   if (!strcmp(image_ext, LIVES_FILE_EXT_PNG)) palette = WEED_PALETTE_RGBA32;
7691   else palette = WEED_PALETTE_RGB24;
7692 #else
7693   if (strcmp(image_ext, LIVES_FILE_EXT_PNG)) palette = WEED_PALETTE_RGB24;
7694   else palette = WEED_PALETTE_END;
7695 #endif
7696 
7697   if (pull_frame_at_size(layer, image_ext, tc, width, height, palette)) {
7698     check_layer_ready(layer);
7699     pixbuf = layer_to_pixbuf(layer, TRUE, fordisp);
7700   }
7701   weed_layer_free(layer);
7702   if (pixbuf && ((width != 0 && lives_pixbuf_get_width(pixbuf) != width)
7703                  || (height != 0 && lives_pixbuf_get_height(pixbuf) != height))) {
7704     LiVESPixbuf *pixbuf2;
7705     // TODO - could use resize plugin here
7706     pixbuf2 = lives_pixbuf_scale_simple(pixbuf, width, height, interp);
7707     if (pixbuf) lives_widget_object_unref(pixbuf);
7708     pixbuf = pixbuf2;
7709   }
7710 
7711   return pixbuf;
7712 }
7713 
7714 
pull_lives_pixbuf(int clip,int frame,const char * image_ext,weed_timecode_t tc)7715 LIVES_GLOBAL_INLINE LiVESPixbuf *pull_lives_pixbuf(int clip, int frame, const char *image_ext, weed_timecode_t tc) {
7716   return pull_lives_pixbuf_at_size(clip, frame, image_ext, tc, 0, 0, LIVES_INTERP_NORMAL, FALSE);
7717 }
7718 
7719 
get_player_size(int * opwidth,int * opheight)7720 void get_player_size(int *opwidth, int *opheight) {
7721   // calc output size for display
7722   int rwidth, rheight;
7723 
7724   ///// external playback plugin
7725   if (mainw->ext_playback) {
7726     // playback plugin (therefore fullscreen / separate window)
7727     if (mainw->vpp->capabilities & VPP_LOCAL_DISPLAY) {
7728       if (mainw->vpp->capabilities & VPP_CAN_RESIZE) {
7729         // plugin can resize, max is the screen size
7730         get_play_screen_size(opwidth, opheight);
7731       } else {
7732         // ext plugin can't resize, use its fixed size
7733         *opwidth = mainw->vpp->fwidth;
7734         *opheight = mainw->vpp->fheight;
7735       }
7736     } else {
7737       // remote display
7738       if (!(mainw->vpp->capabilities & VPP_CAN_RESIZE)) {
7739         // cant resize, we use the width it gave us if it can't resize
7740         *opwidth = mainw->vpp->fwidth;
7741         *opheight = mainw->vpp->fheight;
7742       } else {
7743         // else the clip size
7744         *opwidth = cfile->hsize;
7745         *opheight = cfile->vsize;
7746       }
7747     }
7748     goto align;
7749   }
7750 
7751   if (mainw->play_window) {
7752     // playback in separate window
7753     // use values set in resize_play_window
7754     *opwidth = mainw->pwidth;
7755     *opheight = mainw->pheight;
7756     if (mainw->multitrack && prefs->letterbox_mt) {
7757       rwidth = *opwidth;
7758       rheight = *opheight;
7759       *opwidth = cfile->hsize;
7760       *opheight = cfile->vsize;
7761       calc_maxspect(rwidth, rheight, opwidth, opheight);
7762     }
7763     goto align;
7764   }
7765 
7766   /////////////////////////////////////////////////////////////////////////////////
7767   // multitrack: we ignore double size, and fullscreen unless playing in the separate window
7768   if (mainw->multitrack) {
7769     // frame max sizes for multitrack
7770     /* *opwidth = mainw->files[mainw->multitrack->render_file]->hsize; */
7771     /* *opheight = mainw->files[mainw->multitrack->render_file]->vsize; */
7772     /* if (!mainw->multitrack->is_rendering) { */
7773     /*   calc_maxspect(mainw->multitrack->play_width, mainw->multitrack->play_height, opwidth, opheight); */
7774     /* } */
7775     *opwidth = mainw->multitrack->play_width;
7776     *opheight = mainw->multitrack->play_height;
7777     goto align;
7778   }
7779 
7780   ////////////////////////////////////////////////////////////////////////////////////
7781   // clip edit mode
7782   if (mainw->is_rendering && !mainw->preview) {
7783     *opwidth = cfile->hsize;
7784     *opheight = cfile->vsize;
7785     goto align;
7786   }
7787 
7788   if (!mainw->fs) {
7789     // embedded player
7790     rwidth = lives_widget_get_allocation_width(mainw->play_image);// - H_RESIZE_ADJUST;
7791     rheight = lives_widget_get_allocation_height(mainw->play_image);// - V_RESIZE_ADJUST;
7792 
7793     if (0 && prefs->letterbox) {
7794       *opwidth = cfile->hsize;
7795       *opheight = cfile->vsize;
7796       calc_maxspect(rwidth, rheight, opwidth, opheight);
7797     } else {
7798       *opwidth = rwidth;
7799       *opheight = rheight;
7800     }
7801   } else {
7802     // try to get exact inner size of the main window
7803     lives_window_get_inner_size(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), opwidth, opheight);
7804     //*opheight -= 2; // necessary, or screen expands too much (!?)
7805     if (prefs->show_tool) *opheight -= lives_widget_get_allocation_height(mainw->btoolbar);
7806   }
7807 
7808 align:
7809   *opwidth = (*opwidth >> 2) << 2;
7810   *opheight = (*opheight >> 2) << 2;
7811   mainw->pwidth = *opwidth;
7812   mainw->pheight = *opheight;
7813 }
7814 
7815 
init_track_decoders(void)7816 void init_track_decoders(void) {
7817   int i;
7818   for (i = 0; i < MAX_TRACKS; i++) {
7819     mainw->track_decoders[i] = NULL;
7820     mainw->old_active_track_list[i] = mainw->active_track_list[i] = 0;
7821   }
7822   for (i = 0; i < MAX_FILES; i++) mainw->ext_src_used[i] = FALSE;
7823 }
7824 
7825 
free_track_decoders(void)7826 LIVES_GLOBAL_INLINE void free_track_decoders(void) {
7827   for (int i = 0; i < MAX_TRACKS; i++) {
7828     if (mainw->track_decoders[i] &&
7829         (mainw->active_track_list[i] <= 0 || mainw->track_decoders[i] != mainw->files[mainw->active_track_list[i]]->ext_src))
7830       close_decoder_plugin(mainw->track_decoders[i]);
7831   }
7832 }
7833 
7834 
check_for_overlay_text(weed_layer_t * layer)7835 static boolean check_for_overlay_text(weed_layer_t *layer) {
7836   if (mainw->urgency_msg && prefs->show_urgency_msgs) {
7837     ticks_t timeout = lives_alarm_check(LIVES_URGENCY_ALARM);
7838     if (!timeout) {
7839       lives_freep((void **)&mainw->urgency_msg);
7840       return FALSE;
7841     }
7842     render_text_overlay(layer, mainw->urgency_msg);
7843     return TRUE;
7844   }
7845 
7846   if ((mainw->overlay_msg && prefs->show_overlay_msgs) || mainw->lockstats) {
7847     if (mainw->lockstats) {
7848       lives_freep((void **)&mainw->overlay_msg);
7849       show_sync_callback(NULL, NULL, 0, 0, LIVES_INT_TO_POINTER(1));
7850       if (mainw->overlay_msg) {
7851         render_text_overlay(layer, mainw->overlay_msg);
7852         if (prefs->render_overlay && mainw->record && !mainw->record_paused) {
7853           weed_plant_t *event = get_last_frame_event(mainw->event_list);
7854           if (event) weed_set_string_value(event, WEED_LEAF_OVERLAY_TEXT, mainw->overlay_msg);
7855         }
7856       }
7857       return TRUE;
7858     } else {
7859       if (!mainw->preview_rendering) {
7860         ticks_t timeout = lives_alarm_check(mainw->overlay_alarm);
7861         if (timeout == 0) {
7862           lives_freep((void **)&mainw->overlay_msg);
7863           return FALSE;
7864         }
7865       }
7866       render_text_overlay(layer, mainw->overlay_msg);
7867       if (mainw->preview_rendering) lives_freep((void **)&mainw->overlay_msg);
7868       return TRUE;
7869     }
7870   }
7871   return FALSE;
7872 }
7873 
7874 
do_cleanup(weed_layer_t * layer,int success)7875 static void do_cleanup(weed_layer_t *layer, int success) {
7876   /// cleanup any resources after showing a frame. This run as a thread, so the main thread can return to the player
7877   lives_clip_t *sfile = NULL;
7878   int clip = -1;
7879   double fps = DEF_FPS;
7880   frames_t frame = 0;
7881 
7882   if (layer) {
7883     clip = lives_layer_get_clip(layer);
7884     frame = lives_layer_get_frame(layer);
7885     if (IS_VALID_CLIP(clip)) {
7886       sfile = mainw->files[clip];
7887       fps = sfile->pb_fps;
7888     }
7889   }
7890 
7891   if (success) {
7892     char *tmp;
7893     // format is now msg|timecode|fgclip|fgframe|fgfps|
7894     lives_notify(LIVES_OSC_NOTIFY_FRAME_SYNCH, (const char *)
7895                  (tmp = lives_strdup_printf("%.8f|%d|%d|%.3f|", (double)mainw->currticks / TICKS_PER_SECOND_DBL,
7896                                             clip, frame, fps)));
7897     lives_free(tmp);
7898   }
7899 
7900   if (layer) {
7901     check_layer_ready(layer);
7902     ///mainw->frame_layer_postload = mainw->frame_layer;
7903     if (layer == mainw->frame_layer) mainw->frame_layer = NULL;
7904     weed_layer_free(layer);
7905   }
7906 }
7907 
7908 
7909 //static weed_plant_t *cleaner = NULL;
7910 
7911 /* void wait_for_cleaner(void) { */
7912 /*   if (cleaner) { */
7913 /*     lives_nanosleep_until_nonzero(weed_get_boolean_value(cleaner, WEED_LEAF_DONE, NULL)); */
7914 /*     weed_plant_free(cleaner); */
7915 /*     cleaner = NULL; */
7916 /*   } */
7917 /* } */
7918 
7919 #define USEC_WAIT_FOR_SYNC 500000
7920 
avsync_check(void)7921 static boolean avsync_check(void) {
7922   register int count = USEC_WAIT_FOR_SYNC / 10, rc = 0;
7923   struct timespec ts;
7924 
7925 #ifdef VALGRIND_ON
7926   count *= 10;
7927 #endif
7928 
7929   if (mainw->foreign || !LIVES_IS_PLAYING || prefs->audio_src == AUDIO_SRC_EXT || prefs->force_system_clock
7930       || (mainw->event_list && !(mainw->record || mainw->record_paused)) || prefs->audio_player == AUD_PLAYER_NONE
7931       || !is_realtime_aplayer(prefs->audio_player)) {
7932     mainw->video_seek_ready = mainw->audio_seek_ready = TRUE;
7933     return TRUE;
7934   }
7935 
7936   if (!mainw->video_seek_ready) {
7937 #ifdef ENABLE_JACK
7938     if (!mainw->foreign && mainw->jackd && prefs->audio_player == AUD_PLAYER_JACK) {
7939       /// try to improve sync by delaying audio pb start
7940       if (LIVES_UNLIKELY(mainw->event_list && LIVES_IS_PLAYING && !mainw->record
7941                          && !mainw->record_paused && mainw->jackd->is_paused)) {
7942         mainw->video_seek_ready = TRUE;
7943         if (!mainw->switch_during_pb) mainw->force_show = TRUE;
7944         return TRUE;
7945       }
7946     }
7947 #endif
7948 #ifdef HAVE_PULSE_AUDIO
7949     if (!mainw->foreign && mainw->pulsed && prefs->audio_player == AUD_PLAYER_PULSE) {
7950       /// try to improve sync by delaying audio pb start
7951       if (LIVES_UNLIKELY(mainw->event_list && LIVES_IS_PLAYING && !mainw->record
7952                          && !mainw->record_paused && mainw->pulsed->is_paused)) {
7953         mainw->video_seek_ready = TRUE;
7954         if (!mainw->switch_during_pb) mainw->force_show = TRUE;
7955         return TRUE;
7956       }
7957     }
7958 #endif
7959   }
7960 
7961   clock_gettime(CLOCK_REALTIME, &ts);
7962   pthread_mutex_lock(&mainw->avseek_mutex);
7963   mainw->video_seek_ready = TRUE;
7964   while (!mainw->audio_seek_ready && --count) {
7965     ts.tv_nsec += 10000;   // def. 10 usec (* 50000 = 0.5 sec)
7966     if (ts.tv_nsec >= ONE_BILLION) {
7967       ts.tv_sec++;
7968       ts.tv_nsec -= ONE_BILLION;
7969     }
7970     sched_yield();
7971     rc = pthread_cond_timedwait(&mainw->avseek_cond, &mainw->avseek_mutex, &ts);
7972     mainw->video_seek_ready = TRUE;
7973   }
7974   if (!mainw->audio_seek_ready && rc == ETIMEDOUT) {
7975     pthread_mutex_unlock(&mainw->avseek_mutex);
7976     mainw->cancelled = handle_audio_timeout();
7977     return FALSE;
7978   }
7979   pthread_mutex_unlock(&mainw->avseek_mutex);
7980   return TRUE;
7981 }
7982 
7983 
load_frame_image(int frame)7984 void load_frame_image(int frame) {
7985   // this is where we do the actual load/record of a playback frame
7986   // it is called every 1/fps from do_progress_dialog() via process_one() in dialogs.c
7987 
7988   // for the multitrack window we set mainw->frame_image; this is used to display the
7989   // preview image
7990 
7991   // NOTE: we should be careful if load_frame_image() is called from anywhere inside load_frame_image()
7992   // e.g. by calling g_main_context_iteration() --> user presses sepwin button --> load_frame_image() is called
7993   // this is because mainw->frame_layer is global and gets freed() before exit from load_frame_image()
7994 
7995   void **pd_array, **retdata = NULL;
7996   LiVESPixbuf *pixbuf = NULL;
7997 
7998   char *framecount = NULL, *tmp;
7999   char *fname_next = NULL, *info_file = NULL;
8000   const char *img_ext = NULL;
8001 
8002   LiVESInterpType interp;
8003   double scrap_file_size = -1;
8004 
8005   ticks_t audio_timed_out = 1;
8006 
8007   boolean was_preview = FALSE;
8008   boolean rec_after_pb = FALSE;
8009   boolean success = FALSE;
8010   boolean size_ok = TRUE;
8011   boolean player_v2 = FALSE;
8012 
8013   int retval;
8014   int layer_palette, cpal;
8015 
8016   static int old_pwidth = 0, old_pheight = 0;
8017   int opwidth = 0, opheight = 0;
8018   int pwidth, pheight;
8019   int lb_width = 0, lb_height = 0;
8020   int bad_frame_count = 0;
8021   int fg_file = mainw->current_file;
8022   int tgamma = WEED_GAMMA_UNKNOWN;
8023   boolean was_letterboxed = FALSE;
8024 
8025 #if defined ENABLE_JACK || defined HAVE_PULSE_AUDIO
8026   lives_alarm_t alarm_handle;
8027 #endif
8028 
8029 #define BFC_LIMIT 1000
8030   if (LIVES_UNLIKELY(cfile->frames == 0 && !mainw->foreign && !mainw->is_rendering)) {
8031     if (mainw->record && !mainw->record_paused) {
8032       // add blank frame
8033       weed_plant_t *event = get_last_event(mainw->event_list);
8034       weed_plant_t *event_list = insert_blank_frame_event_at(mainw->event_list, lives_get_relative_ticks(mainw->origsecs,
8035                                  mainw->orignsecs),
8036                                  &event);
8037       if (!mainw->event_list) mainw->event_list = event_list;
8038       if (mainw->rec_aclip != -1 && (prefs->rec_opts & REC_AUDIO) && !mainw->record_starting) {
8039         // we are recording, and the audio clip changed; add audio
8040         if (mainw->rec_aclip == mainw->ascrap_file) {
8041           mainw->rec_aseek = (double)mainw->files[mainw->ascrap_file]->aseek_pos /
8042                              (double)(mainw->files[mainw->ascrap_file]->arps * mainw->files[mainw->ascrap_file]->achans *
8043                                       mainw->files[mainw->ascrap_file]->asampsize >> 3);
8044           mainw->rec_avel = 1.;
8045         }
8046         if (!mainw->mute) {
8047           insert_audio_event_at(event, -1, mainw->rec_aclip, mainw->rec_aseek, mainw->rec_avel);
8048           mainw->rec_aclip = -1;
8049         }
8050       }
8051     }
8052     if (!mainw->fs && !mainw->faded) get_play_times();
8053 
8054     return;
8055   }
8056 
8057   if (!mainw->foreign) {
8058     mainw->actual_frame = frame;
8059     if (!mainw->preview_rendering && (!((was_preview = mainw->preview) || mainw->is_rendering))) {
8060       /////////////////////////////////////////////////////////
8061 
8062       // normal play
8063 
8064       if (LIVES_UNLIKELY(mainw->nervous) && clip_can_reverse(mainw->playing_file)) {
8065         // nervous mode
8066         if ((mainw->actual_frame += (-10 + (int)(21.*rand() / (RAND_MAX + 1.0)))) > cfile->frames ||
8067             mainw->actual_frame < 1) mainw->actual_frame = frame;
8068         else resync_audio(mainw->actual_frame);
8069       }
8070 
8071       if (mainw->opening_loc || !CURRENT_CLIP_IS_NORMAL) {
8072         framecount = lives_strdup_printf("%9d", mainw->actual_frame);
8073       } else {
8074         framecount = lives_strdup_printf("%9d / %d", mainw->actual_frame, cfile->frames);
8075       }
8076 
8077       /////////////////////////////////////////////////
8078 
8079       // record performance
8080       if ((mainw->record && !mainw->record_paused) || mainw->record_starting) {
8081         ticks_t actual_ticks;
8082         int fg_frame = mainw->record_frame;
8083         int bg_file = IS_VALID_CLIP(mainw->blend_file) && mainw->blend_file != mainw->current_file
8084                       ? mainw->blend_file : -1;
8085         int bg_frame = bg_file > 0 && bg_file != mainw->current_file ? mainw->files[bg_file]->frameno : 0;
8086         int numframes;
8087         int *clips;
8088         int64_t *frames;
8089         weed_plant_t *event_list;
8090 
8091         // should we record the output from the playback plugin ?
8092         if (mainw->record && (prefs->rec_opts & REC_AFTER_PB) && mainw->ext_playback &&
8093             (mainw->vpp->capabilities & VPP_CAN_RETURN)) {
8094           rec_after_pb = TRUE;
8095         }
8096 
8097         if (rec_after_pb || !CURRENT_CLIP_IS_NORMAL ||
8098             (prefs->rec_opts & REC_EFFECTS && bg_file != -1 && !IS_NORMAL_CLIP(bg_file))) {
8099           // TODO - handle non-opening of scrap_file
8100           if (mainw->scrap_file == -1) open_scrap_file();
8101           fg_file = mainw->scrap_file;
8102           fg_frame = mainw->files[mainw->scrap_file]->frames + 1;
8103           scrap_file_size = mainw->files[mainw->scrap_file]->f_size;
8104           bg_file = -1;
8105           bg_frame = 0;
8106         }
8107 
8108         //actual_ticks = mainw->clock_ticks;//mainw->currticks;
8109         actual_ticks = mainw->startticks; ///< use the "thoretical" time
8110 
8111         if (mainw->record_starting) {
8112           if (!mainw->event_list) {
8113             mainw->event_list = lives_event_list_new(NULL, NULL);
8114           }
8115 
8116           // mark record start
8117           mainw->event_list = append_marker_event(mainw->event_list, actual_ticks, EVENT_MARKER_RECORD_START);
8118 
8119           if (prefs->rec_opts & REC_EFFECTS) {
8120             // add init events and pchanges for all active fx
8121             add_filter_init_events(mainw->event_list, actual_ticks);
8122           }
8123 
8124 #ifdef ENABLE_JACK
8125           if (prefs->audio_player == AUD_PLAYER_JACK && mainw->jackd &&
8126               (prefs->rec_opts & REC_AUDIO) && prefs->audio_src == AUDIO_SRC_INT && mainw->rec_aclip != mainw->ascrap_file) {
8127             // get current seek postion
8128             alarm_handle = lives_alarm_set(LIVES_SHORT_TIMEOUT);
8129 
8130             while ((audio_timed_out = lives_alarm_check(alarm_handle)) > 0 && jack_get_msgq(mainw->jackd) != NULL) {
8131               // wait for audio player message queue clearing
8132               sched_yield();
8133               lives_usleep(prefs->sleep_time);
8134             }
8135             lives_alarm_clear(alarm_handle);
8136             if (audio_timed_out == 0) {
8137               mainw->cancelled = handle_audio_timeout();
8138               goto lfi_done;
8139             }
8140             jack_get_rec_avals(mainw->jackd);
8141           }
8142 #endif
8143 #ifdef HAVE_PULSE_AUDIO
8144           if (prefs->audio_player == AUD_PLAYER_PULSE && mainw->pulsed &&
8145               (prefs->rec_opts & REC_AUDIO) && prefs->audio_src == AUDIO_SRC_INT && mainw->rec_aclip != mainw->ascrap_file) {
8146             // get current seek postion
8147             alarm_handle = lives_alarm_set(LIVES_SHORT_TIMEOUT);
8148             while ((audio_timed_out = lives_alarm_check(alarm_handle)) > 0 && pulse_get_msgq(mainw->pulsed) != NULL) {
8149               // wait for audio player message queue clearing
8150               sched_yield();
8151               lives_usleep(prefs->sleep_time);
8152             }
8153             lives_alarm_clear(alarm_handle);
8154             pulse_get_rec_avals(mainw->pulsed);
8155           }
8156 #endif
8157           mainw->record_starting = FALSE;
8158           if (audio_timed_out == 0) {
8159             mainw->cancelled = handle_audio_timeout();
8160             goto lfi_done;
8161           }
8162           mainw->record = TRUE;
8163           mainw->record_paused = FALSE;
8164         }
8165 
8166         numframes = (bg_file == -1) ? 1 : 2;
8167         clips = (int *)lives_malloc(numframes * sizint);
8168         frames = (int64_t *)lives_malloc(numframes * 8);
8169 
8170         clips[0] = fg_file;
8171         frames[0] = (int64_t)fg_frame;
8172         if (numframes == 2) {
8173           clips[1] = bg_file;
8174           frames[1] = (int64_t)bg_frame;
8175         }
8176         if (framecount) lives_free(framecount);
8177         pthread_mutex_lock(&mainw->event_list_mutex);
8178 
8179         /// usual function to record a frame event
8180         if ((event_list = append_frame_event(mainw->event_list, actual_ticks, numframes, clips, frames)) != NULL) {
8181           if (!mainw->event_list) mainw->event_list = event_list;
8182 
8183           // TODO ***: do we need to perform more checks here ???
8184           if (scrap_file_size != -1 || (mainw->rec_aclip != -1 && (prefs->rec_opts & REC_AUDIO))) {
8185             weed_plant_t *event = get_last_frame_event(mainw->event_list);
8186 
8187             if (scrap_file_size != -1) weed_set_int64_value(event, WEED_LEAF_HOST_SCRAP_FILE_OFFSET, scrap_file_size);
8188 
8189             if (mainw->rec_aclip != -1) {
8190               if (mainw->rec_aclip == mainw->ascrap_file) {
8191                 mainw->rec_aseek = (double)mainw->files[mainw->ascrap_file]->aseek_pos /
8192                                    (double)(mainw->files[mainw->ascrap_file]->arps * mainw->files[mainw->ascrap_file]->achans *
8193                                             mainw->files[mainw->ascrap_file]->asampsize >> 3);
8194                 mainw->rec_avel = 1.;
8195 
8196               }
8197               if (!mainw->mute) {
8198                 weed_event_t *xevent = get_prev_frame_event(event);
8199                 if (!xevent) xevent = event;
8200                 insert_audio_event_at(xevent, -1, mainw->rec_aclip, mainw->rec_aseek, mainw->rec_avel);
8201               }
8202               mainw->rec_aclip = -1;
8203             }
8204           }
8205           pthread_mutex_unlock(&mainw->event_list_mutex);
8206 
8207           /* TRANSLATORS: rec(ord) */
8208           framecount = lives_strdup_printf((tmp = _("rec %9d / %d")), mainw->actual_frame,
8209                                            cfile->frames > mainw->actual_frame ? cfile->frames : mainw->actual_frame);
8210         } else {
8211           pthread_mutex_unlock(&mainw->event_list_mutex);
8212           /* TRANSLATORS: out of memory (rec(ord)) */
8213           framecount = lives_strdup_printf((tmp = _("!rec %9d / %d")), mainw->actual_frame, cfile->frames);
8214         }
8215         lives_free(tmp);
8216         lives_free(clips);
8217         lives_free(frames);
8218       } else {
8219         if (mainw->toy_type != LIVES_TOY_NONE) {
8220           if (mainw->toy_type == LIVES_TOY_MAD_FRAMES && !mainw->fs && CURRENT_CLIP_IS_NORMAL) {
8221             int current_file = mainw->current_file;
8222             if (mainw->toy_go_wild) {
8223               int i, other_file;
8224               for (i = 0; i < 11; i++) {
8225                 other_file = (1 + (int)((double)(mainw->clips_available) * rand() / (RAND_MAX + 1.0)));
8226                 other_file = LIVES_POINTER_TO_INT(lives_list_nth_data(mainw->cliplist, other_file));
8227                 if (mainw->files[other_file]) {
8228                   // steal a frame from another clip
8229                   mainw->current_file = other_file;
8230                 }
8231               }
8232             }
8233             load_end_image(1 + (int)((double)cfile->frames * rand() / (RAND_MAX + 1.0)));
8234             load_start_image(1 + (int)((double)cfile->frames * rand() / (RAND_MAX + 1.0)));
8235             mainw->current_file = current_file;
8236           }
8237         }
8238       }
8239 
8240       if ((!mainw->fs || (prefs->play_monitor != widget_opts.monitor && capable->nmonitors > 1) ||
8241            (mainw->ext_playback && !(mainw->vpp->capabilities & VPP_LOCAL_DISPLAY)))
8242           && !prefs->hide_framebar) {
8243         lives_entry_set_text(LIVES_ENTRY(mainw->framecounter), framecount);
8244         //lives_widget_queue_draw(mainw->framecounter);
8245       }
8246       lives_freep((void **)&framecount);
8247     }
8248 
8249     if (was_preview) {
8250       // preview
8251       if (mainw->proc_ptr && mainw->proc_ptr->frames_done > 0 &&
8252           frame >= (mainw->proc_ptr->frames_done - cfile->progress_start + cfile->start)) {
8253         if (cfile->opening) {
8254           mainw->proc_ptr->frames_done = cfile->opening_frames = get_frame_count(mainw->current_file, cfile->opening_frames);
8255         }
8256       }
8257       if (mainw->proc_ptr && mainw->proc_ptr->frames_done > 0 &&
8258           frame >= (mainw->proc_ptr->frames_done - cfile->progress_start + cfile->start)) {
8259         mainw->cancelled = CANCEL_PREVIEW_FINISHED;
8260         goto lfi_done;
8261       }
8262 
8263       // play preview
8264       if (cfile->opening || (cfile->next_event && !mainw->proc_ptr)) {
8265         fname_next = make_image_file_name(cfile, frame + 1, get_image_ext_for_type(cfile->img_type));
8266         if (!mainw->fs && !prefs->hide_framebar && !mainw->is_rendering) {
8267           lives_freep((void **)&framecount);
8268           if (CURRENT_CLIP_HAS_VIDEO && cfile->frames != 123456789) {
8269             framecount = lives_strdup_printf("%9d / %d", frame, cfile->frames);
8270           } else {
8271             framecount = lives_strdup_printf("%9d", frame);
8272           }
8273           lives_entry_set_text(LIVES_ENTRY(mainw->framecounter), framecount);
8274           lives_widget_queue_draw(mainw->framecounter);
8275           lives_freep((void **)&framecount);
8276         }
8277         if (mainw->toy_type != LIVES_TOY_NONE) {
8278           // TODO - move into toys.c
8279           if (mainw->toy_type == LIVES_TOY_MAD_FRAMES && !mainw->fs) {
8280             if (cfile->opening_only_audio) {
8281               load_end_image(1 + (int)((double)cfile->frames * rand() / (RAND_MAX + 1.0)));
8282               load_start_image(1 + (int)((double)cfile->frames * rand() / (RAND_MAX + 1.0)));
8283             } else {
8284               load_end_image(1 + (int)((double)frame * rand() / (RAND_MAX + 1.0)));
8285               load_start_image(1 + (int)((double)frame * rand() / (RAND_MAX + 1.0)));
8286             }
8287           }
8288         }
8289       } else {
8290         if (mainw->is_rendering || mainw->is_generating) {
8291           fname_next = make_image_file_name(cfile, frame + 1, get_image_ext_for_type(cfile->img_type));
8292         } else {
8293           if (!mainw->keep_pre) {
8294             img_ext = LIVES_FILE_EXT_MGK;
8295           } else {
8296             img_ext = LIVES_FILE_EXT_PRE;
8297           }
8298           fname_next = make_image_file_name(cfile, frame + 1, img_ext);
8299         }
8300       }
8301       mainw->actual_frame = frame;
8302 
8303       // maybe the performance finished and we weren't looping
8304       if ((mainw->actual_frame < 1 || mainw->actual_frame > cfile->frames) &&
8305           CURRENT_CLIP_IS_NORMAL && (!mainw->is_rendering || mainw->preview)) {
8306         goto lfi_done;
8307         return;
8308       }
8309     }
8310 
8311     // limit max frame size unless we are saving to disk or rendering
8312     // frame_layer will in any case be equal to or smaller than this depending on maximum source frame size
8313 
8314     if (!(mainw->record && !mainw->record_paused && (prefs->rec_opts & REC_EFFECTS) &&
8315           (!CURRENT_CLIP_IS_NORMAL || (IS_VALID_CLIP(mainw->blend_file) && !IS_NORMAL_CLIP(mainw->blend_file))))) {
8316       get_player_size(&opwidth, &opheight);
8317     }
8318 
8319     ////////////////////////////////////////////////////////////
8320     // load a frame from disk buffer
8321 
8322     if (mainw->preview && !mainw->frame_layer && (!mainw->event_list || cfile->opening)) {
8323       info_file = lives_build_filename(prefs->workdir, cfile->handle, LIVES_STATUS_FILE_NAME, NULL);
8324     }
8325 
8326     do {
8327       //wait_for_cleaner();
8328       if (mainw->frame_layer) {
8329         // free the old mainw->frame_layer
8330         check_layer_ready(mainw->frame_layer); // ensure all threads are complete
8331         weed_layer_free(mainw->frame_layer);
8332         mainw->frame_layer = NULL;
8333       }
8334 
8335       if (mainw->is_rendering && !(mainw->proc_ptr && mainw->preview)) {
8336         // here if we are rendering from multitrack, previewing a recording, or applying realtime effects to a selection
8337         weed_timecode_t tc = mainw->cevent_tc;
8338         if (mainw->scrap_file != -1 && mainw->clip_index[0] == mainw->scrap_file && mainw->num_tracks == 1) {
8339           // do not apply fx, just pull frame
8340           mainw->frame_layer = lives_layer_new_for_frame(mainw->clip_index[0], mainw->frame_index[0]);
8341           pull_frame_threaded(mainw->frame_layer, NULL, (weed_timecode_t)mainw->currticks, 0, 0);
8342           /* if (!pull_frame(mainw->frame_layer, get_image_ext_for_type(cfile->img_type), tc)) { */
8343           /*   weed_plant_free(mainw->frame_layer); */
8344           /*   mainw->frame_layer = NULL; */
8345           /*   if (mainw->preview_rendering) { */
8346           /*     mainw->cancelled = CANCEL_NO_MORE_PREVIEW; */
8347           /*     goto lfi_done; */
8348           /*   } */
8349           /* } */
8350         } else {
8351           int oclip, nclip;
8352           register int i;
8353           weed_plant_t **layers = (weed_plant_t **)lives_calloc((mainw->num_tracks + 1), sizeof(weed_plant_t *));
8354           // get list of active tracks from mainw->filter map
8355           get_active_track_list(mainw->clip_index, mainw->num_tracks, mainw->filter_map);
8356           for (i = 0; i < mainw->num_tracks; i++) {
8357             oclip = mainw->old_active_track_list[i];
8358             mainw->ext_src_used[oclip] = FALSE;
8359             if (oclip > 0 && oclip == (nclip = mainw->active_track_list[i])) {
8360               // check if ext_src survives old->new
8361               if (mainw->track_decoders[i] == mainw->files[oclip]->ext_src) mainw->ext_src_used[oclip] = TRUE;
8362             }
8363           }
8364 
8365           for (i = 0; i < mainw->num_tracks; i++) {
8366             layers[i] = lives_layer_new_for_frame(mainw->clip_index[i], mainw->frame_index[i]);
8367             weed_set_int_value(layers[i], WEED_LEAF_CURRENT_PALETTE, (mainw->clip_index[i] == -1 ||
8368                                mainw->files[mainw->clip_index[i]]->img_type ==
8369                                IMG_TYPE_JPEG) ? WEED_PALETTE_RGB24 : WEED_PALETTE_RGBA32);
8370             if ((oclip = mainw->old_active_track_list[i]) != (nclip = mainw->active_track_list[i])) {
8371               // now using threading, we want to start pulling all pixel_data for all active layers here
8372               // however, we may have more than one copy of the same clip -
8373               // in this case we want to create clones of the decoder plugin
8374               // this is to prevent constant seeking between different frames in the clip
8375               if (oclip > 0) {
8376                 if (mainw->files[oclip]->clip_type == CLIP_TYPE_FILE) {
8377                   if (mainw->track_decoders[i] != (lives_decoder_t *)mainw->files[oclip]->ext_src) {
8378                     // remove the clone for oclip
8379                     close_decoder_plugin(mainw->track_decoders[i]);
8380                   }
8381                   mainw->track_decoders[i] = NULL;
8382                 }
8383               }
8384 
8385               if (nclip > 0) {
8386                 if (mainw->files[nclip]->clip_type == CLIP_TYPE_FILE) {
8387                   if (!mainw->ext_src_used[nclip]) {
8388                     mainw->track_decoders[i] = (lives_decoder_t *)mainw->files[nclip]->ext_src;
8389                     mainw->ext_src_used[nclip] = TRUE;
8390                   } else {
8391                     // add new clone for nclip
8392                     mainw->track_decoders[i] = clone_decoder(nclip);
8393 		    // *INDENT-OFF*
8394 		  }}}}
8395 	    // *INDENT-ON*
8396 
8397             mainw->old_active_track_list[i] = mainw->active_track_list[i];
8398 
8399             if (nclip > 0) {
8400               img_ext = get_image_ext_for_type(mainw->files[nclip]->img_type);
8401               // set alt src in layer
8402               weed_set_voidptr_value(layers[i], WEED_LEAF_HOST_DECODER, (void *)mainw->track_decoders[i]);
8403               pull_frame_threaded(layers[i], img_ext, (weed_timecode_t)mainw->currticks, 0, 0);
8404             } else {
8405               weed_layer_pixel_data_free(layers[i]);
8406             }
8407           }
8408           layers[i] = NULL;
8409 
8410           mainw->frame_layer = weed_apply_effects(layers, mainw->filter_map, tc, opwidth, opheight, mainw->pchains);
8411 
8412           for (i = 0; layers[i]; i++) {
8413             if (layers[i] != mainw->frame_layer) {
8414               check_layer_ready(layers[i]);
8415               weed_layer_free(layers[i]);
8416             }
8417           }
8418           lives_free(layers);
8419 
8420           if (mainw->internal_messaging) {
8421             // this happens if we are calling from multitrack, or apply rte.  We get our mainw->frame_layer and exit.
8422             // DO NOT goto lfi_done, as that will free mainw->frame_layer.
8423             lives_freep((void **)&framecount);
8424             lives_freep((void **)&info_file);
8425             return;
8426           }
8427         }
8428       } else {
8429         if (prefs->dev_show_timing)
8430           g_printerr("pull_frame @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8431         // normal playback in the clip editor, or applying a non-realtime effect
8432         if (cfile->clip_type != CLIP_TYPE_DISK
8433             || !mainw->preview || lives_file_test(fname_next, LIVES_FILE_TEST_EXISTS)) {
8434           mainw->frame_layer = lives_layer_new_for_frame(mainw->current_file, mainw->actual_frame);
8435           if (!img_ext) img_ext = get_image_ext_for_type(cfile->img_type);
8436           if (mainw->preview && !mainw->frame_layer
8437               && (!mainw->event_list || cfile->opening)) {
8438             if (!pull_frame_at_size(mainw->frame_layer, img_ext, (weed_timecode_t)mainw->currticks,
8439                                     cfile->hsize, cfile->vsize, WEED_PALETTE_END)) {
8440               if (mainw->frame_layer) {
8441                 weed_layer_free(mainw->frame_layer);
8442                 mainw->frame_layer = NULL;
8443               }
8444 
8445               if (cfile->clip_type == CLIP_TYPE_DISK &&
8446                   cfile->opening && cfile->img_type == IMG_TYPE_PNG
8447                   && sget_file_size(fname_next) <= 0) {
8448                 if (++bad_frame_count > BFC_LIMIT) {
8449                   mainw->cancelled = check_for_bad_ffmpeg();
8450                   bad_frame_count = 0;
8451                 } else lives_usleep(prefs->sleep_time);
8452               }
8453             }
8454           } else {
8455             boolean got_preload = FALSE;
8456             if (mainw->frame_layer_preload && mainw->pred_clip == mainw->playing_file
8457                 && mainw->pred_frame != 0 && is_layer_ready(mainw->frame_layer_preload)) {
8458               frames_t delta = (labs(mainw->pred_frame) - mainw->actual_frame) * sig(cfile->pb_fps);
8459               /* g_print("THANKS for %p,! %d %ld should be %d, right  --  %d",
8460                 // mainw->frame_layer_preload, mainw->pred_clip, */
8461               /*         mainw->pred_frame, mainw->actual_frame, delta); */
8462               if (delta <= 0 || (mainw->pred_frame < 0 && delta > 0)) {
8463                 check_layer_ready(mainw->frame_layer_preload);
8464                 if (weed_layer_get_pixel_data_packed(mainw->frame_layer_preload) != NULL) {
8465                   //g_print("YAH !\n");
8466                   got_preload = TRUE;
8467                   if (mainw->pred_frame < 0) {
8468                     if (mainw->frame_layer) weed_layer_free(mainw->frame_layer);
8469                     mainw->frame_layer = weed_layer_copy(NULL, mainw->frame_layer_preload);
8470                   } else {
8471                     weed_layer_copy(mainw->frame_layer, mainw->frame_layer_preload);
8472                     weed_layer_nullify_pixel_data(mainw->frame_layer_preload);
8473                   }
8474                 }
8475               }
8476               if (prefs->show_dev_opts) {
8477                 if (delta < 0) g_printerr("cached frame    TOO LATE, got %ld, wanted %d !!!\n",
8478                                             labs(mainw->pred_frame), mainw->actual_frame);
8479               }
8480               //if (delta > 0) g_print("    waiting...\n");
8481             }
8482             if (!got_preload) {
8483               pull_frame_threaded(mainw->frame_layer, img_ext, (weed_timecode_t)mainw->currticks, 0, 0);
8484               //pull_frame(mainw->frame_layer, img_ext, (weed_timecode_t)mainw->currticks);
8485             }
8486             if ((mainw->rte != 0 || (mainw->is_rendering && !mainw->event_list))
8487                 && (mainw->current_file != mainw->scrap_file || mainw->multitrack)) {
8488               /// will set mainw->blend_layer
8489               get_blend_layer((weed_timecode_t)mainw->currticks);
8490             }
8491           }
8492         }
8493 
8494         if (prefs->dev_show_timing)
8495           g_printerr("pull_frame done @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8496         if ((!cfile->next_event && mainw->is_rendering && !mainw->switch_during_pb &&
8497              (!mainw->multitrack || (!mainw->multitrack->is_rendering && !mainw->is_generating))) ||
8498             ((!mainw->multitrack || (mainw->multitrack && mainw->multitrack->is_rendering)) &&
8499              mainw->preview && !mainw->frame_layer)) {
8500           // preview ended
8501           if (!cfile->opening) mainw->cancelled = CANCEL_NO_MORE_PREVIEW;
8502           if (mainw->cancelled) {
8503             lives_free(fname_next);
8504             lives_freep((void **)&info_file);
8505             goto lfi_done;
8506           }
8507           // ???
8508           mainw->currticks = lives_get_current_playback_ticks(mainw->origsecs, mainw->orignsecs, NULL);
8509         }
8510 
8511         img_ext = NULL;
8512 
8513         if (mainw->internal_messaging) {
8514           // here we are rendering to an effect or timeline, need to keep mainw->frame_layer and return
8515           lives_freep((void **)&framecount);
8516           lives_freep((void **)&info_file);
8517           check_layer_ready(mainw->frame_layer);
8518           return;
8519         }
8520 
8521         if (!mainw->frame_layer && (!mainw->preview || (mainw->multitrack && !cfile->opening))) {
8522           lives_freep((void **)&info_file);
8523           goto lfi_done;
8524         }
8525 
8526         if (mainw->preview && !mainw->frame_layer && (!mainw->event_list || cfile->opening)) {
8527           FILE *fp;
8528           // non-realtime effect preview
8529           // check effect to see if it finished yet
8530           if ((fp = fopen(info_file, "r"))) {
8531             clear_mainw_msg();
8532             do {
8533               retval = 0;
8534               lives_fgets(mainw->msg, MAINW_MSG_SIZE, fp);
8535               if (THREADVAR(read_failed) && THREADVAR(read_failed) == fileno(fp) + 1) {
8536                 THREADVAR(read_failed) = 0;
8537                 retval = do_read_failed_error_s_with_retry(info_file, NULL);
8538               }
8539             } while (retval == LIVES_RESPONSE_RETRY);
8540             fclose(fp);
8541             if (!lives_strncmp(mainw->msg, "completed", 9) || !strncmp(mainw->msg, "error", 5)) {
8542               // effect completed whilst we were busy playing a preview
8543               if (mainw->preview_box) lives_widget_set_tooltip_text(mainw->p_playbutton, _("Play"));
8544               lives_widget_set_tooltip_text(mainw->m_playbutton, _("Play"));
8545               if (cfile->opening && !cfile->is_loaded) {
8546                 if (mainw->toy_type == LIVES_TOY_TV) {
8547                   on_toy_activate(NULL, LIVES_INT_TO_POINTER(LIVES_TOY_NONE));
8548                 }
8549               }
8550               mainw->preview = FALSE;
8551             } else {
8552               lives_usleep(prefs->sleep_time);
8553             }
8554           } else {
8555             lives_usleep(prefs->sleep_time);
8556           }
8557 
8558           // or we reached the end of the preview
8559           if ((!cfile->opening && frame >= (mainw->proc_ptr->frames_done - cfile->progress_start + cfile->start)) ||
8560               (cfile->opening && (mainw->toy_type == LIVES_TOY_TV || !mainw->preview || mainw->effects_paused))) {
8561             if (mainw->toy_type == LIVES_TOY_TV) {
8562               // force a loop (set mainw->cancelled to CANCEL_KEEP_LOOPING to play selection again)
8563               mainw->cancelled = CANCEL_KEEP_LOOPING;
8564             } else mainw->cancelled = CANCEL_NO_MORE_PREVIEW;
8565             lives_free(fname_next);
8566             // end of playback, so this is no longer needed
8567             lives_freep((void **)&info_file);
8568             goto lfi_done;
8569           } else if (mainw->preview || cfile->opening) lives_widget_context_update();
8570         }
8571       }
8572     } while (!mainw->frame_layer && mainw->cancelled == CANCEL_NONE && cfile->clip_type == CLIP_TYPE_DISK);
8573 
8574     lives_freep((void **)&info_file);
8575 
8576     if (LIVES_UNLIKELY((!mainw->frame_layer) || mainw->cancelled > 0)) {
8577       // NULL frame or user cancelled
8578       if (mainw->frame_layer) {
8579         check_layer_ready(mainw->frame_layer);
8580         weed_layer_free(mainw->frame_layer);
8581         mainw->frame_layer = NULL;
8582       }
8583       goto lfi_done;
8584     }
8585 
8586     if (was_preview) {
8587       lives_free(fname_next);
8588     }
8589 
8590     // OK. Here is the deal now. We have a layer from the current file, current frame.
8591     // (or at least we sent out a thread to fetch it).
8592     // We will pass this into the effects, and we will get back a layer.
8593     // The palette of the effected layer could be any Weed palette.
8594     // We will pass the layer to all playback plugins.
8595     // Finally we may want to end up with a GkdPixbuf (unless the playback plugin is VPP_DISPLAY_LOCAL
8596     // and we are in full screen mode).
8597 
8598     if (!prefs->vj_mode && (mainw->current_file != mainw->scrap_file || mainw->multitrack)
8599         && mainw->pwidth > 0 && mainw->pheight > 0
8600         && !(mainw->is_rendering && !(mainw->proc_ptr && mainw->preview))
8601         && !cfile->opening && !mainw->resizing && CURRENT_CLIP_IS_NORMAL
8602         && !is_virtual_frame(mainw->current_file, mainw->actual_frame)
8603         && is_layer_ready(mainw->frame_layer)) {
8604       // if we are pulling the frame from an image and playing back normally, check the size is what it should be
8605       // this used to cause problems with some effects, but that may no longer be the case with the layers model
8606       int wl = weed_layer_get_width(mainw->frame_layer) *
8607                weed_palette_get_pixels_per_macropixel(weed_layer_get_palette(mainw->frame_layer));
8608       int hl = weed_layer_get_height(mainw->frame_layer);
8609       if ((wl != cfile->hsize && wl != mainw->pwidth)
8610           || (hl != cfile->vsize && hl != mainw->pheight)) {
8611         break_me("bad frame size");
8612         mainw->size_warn = mainw->current_file;
8613         size_ok = FALSE;
8614       }
8615     }
8616 
8617     if (size_ok) {
8618       // if frame size is OK we apply real time effects
8619       if ((mainw->rte != 0 || (mainw->is_rendering && !mainw->event_list))
8620           && (mainw->current_file != mainw->scrap_file || mainw->multitrack)) {
8621         if (prefs->dev_show_timing)
8622           g_printerr("rte start @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8623         mainw->frame_layer = on_rte_apply(mainw->frame_layer, lb_width, lb_height, (weed_timecode_t)mainw->currticks);
8624       }
8625     }
8626 
8627     if (prefs->dev_show_timing)
8628       g_printerr("rte done @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8629 
8630     ////////////////////////
8631 
8632     // save to scrap_file now if we have to
8633     if (mainw->record && !mainw->record_paused && mainw->scrap_file != -1 && fg_file == mainw->scrap_file) {
8634       if (!rec_after_pb) {
8635         check_layer_ready(mainw->frame_layer);
8636         save_to_scrap_file(mainw->frame_layer);
8637       }
8638       get_player_size(&opwidth, &opheight);
8639     }
8640 
8641     if (mainw->ext_playback && (mainw->vpp->capabilities & VPP_CAN_RESIZE)
8642         && ((((!prefs->letterbox && !mainw->multitrack) || (mainw->multitrack && !prefs->letterbox_mt)))
8643             || (mainw->vpp->capabilities & VPP_CAN_LETTERBOX))) {
8644       // here we are outputing video through a video playback plugin which can resize: thus we just send whatever we have
8645       // we need only to convert the palette to whatever was agreed with the plugin when we called set_palette()
8646       // in plugins.c
8647       //
8648       // if we want letterboxing we do this ourselves, later in the code
8649 
8650       weed_plant_t *frame_layer = NULL;
8651       weed_plant_t *return_layer = NULL;
8652       int lwidth, lheight;
8653       int ovpppalette = mainw->vpp->palette;
8654 
8655       /// check if function exists - it accepts rowstrides
8656       if (mainw->vpp->play_frame) player_v2 = TRUE;
8657 
8658       //g_print("clr1 start  @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8659       check_layer_ready(mainw->frame_layer);
8660       mainw->video_seek_ready = TRUE;
8661       //g_print("clr1 done  @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8662 
8663       layer_palette = weed_layer_get_palette(mainw->frame_layer);
8664       if (!weed_palette_is_valid(layer_palette)) {
8665         goto lfi_done;
8666       }
8667 
8668       if ((mainw->vpp->capabilities & VPP_CAN_CHANGE_PALETTE)
8669           && mainw->vpp->palette != layer_palette) vpp_try_match_palette(mainw->vpp, mainw->frame_layer);
8670 
8671       if (!(mainw->vpp->capabilities & VPP_LOCAL_DISPLAY) &&
8672           ((weed_palette_is_rgb(layer_palette) &&
8673             !(weed_palette_is_rgb(mainw->vpp->palette))) ||
8674            (weed_palette_is_lower_quality(mainw->vpp->palette, layer_palette)))) {
8675         // mainw->frame_layer is RGB and so is our screen, but plugin is YUV
8676         // so copy layer and convert, retaining original
8677         if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8678         frame_layer = weed_layer_copy(NULL, mainw->frame_layer);
8679       } else frame_layer = mainw->frame_layer;
8680 
8681       if (mainw->vpp->capabilities & VPP_LOCAL_DISPLAY) {
8682         if (!check_for_overlay_text(frame_layer)) {
8683           if (mainw->multitrack && mainw->multitrack->opts.overlay_timecode) {
8684             frame_layer = render_text_overlay(frame_layer, mainw->multitrack->timestring);
8685           }
8686         }
8687       }
8688 
8689       if (prefs->apply_gamma) {
8690         // gamma correction
8691         if (weed_palette_is_rgb(mainw->vpp->palette)) {
8692           if (mainw->vpp->capabilities & VPP_LINEAR_GAMMA)
8693             tgamma = WEED_GAMMA_LINEAR;
8694           else {
8695             tgamma = WEED_GAMMA_SRGB;
8696           }
8697         }
8698       }
8699 
8700       if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8701       if (!convert_layer_palette_full(frame_layer, mainw->vpp->palette, mainw->vpp->YUV_clamping,
8702                                       mainw->vpp->YUV_sampling, mainw->vpp->YUV_subspace, tgamma)) {
8703         goto lfi_done;
8704       }
8705       if (prefs->dev_show_timing)
8706         g_print("cl palette done %d to %d @ %f\n", weed_layer_get_palette(frame_layer), mainw->vpp->palette,
8707                 lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8708 
8709       if (!player_v2) {
8710         // vid plugin expects compacted rowstrides (i.e. no padding/alignment after pixel row)
8711         if (!compact_rowstrides(frame_layer)) {
8712           goto lfi_done;
8713         }
8714       }
8715       if (prefs->dev_show_timing)
8716         g_print("comp rs done @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8717       if (mainw->stream_ticks == -1) mainw->stream_ticks = mainw->currticks;
8718 
8719       if (rec_after_pb) {
8720         // record output from playback plugin
8721 
8722         int retwidth = mainw->pwidth / weed_palette_get_pixels_per_macropixel(mainw->vpp->palette);
8723         int retheight = mainw->pheight;
8724 
8725         return_layer = weed_layer_create(retwidth, retheight, NULL, ovpppalette);
8726 
8727         if (weed_palette_is_yuv(ovpppalette)) {
8728           weed_set_int_value(return_layer, WEED_LEAF_YUV_CLAMPING, mainw->vpp->YUV_clamping);
8729           weed_set_int_value(return_layer, WEED_LEAF_YUV_SUBSPACE, mainw->vpp->YUV_subspace);
8730           weed_set_int_value(return_layer, WEED_LEAF_YUV_SAMPLING, mainw->vpp->YUV_sampling);
8731         }
8732 
8733         // vid plugin expects compacted rowstrides (i.e. no padding/alignment after pixel row)
8734         if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8735         if (create_empty_pixel_data(return_layer, FALSE, TRUE))
8736           retdata = weed_layer_get_pixel_data(return_layer, NULL);
8737         else return_layer = NULL;
8738       }
8739 
8740       // chain any data to the playback plugin
8741       if (!(mainw->preview || mainw->is_rendering)) {
8742         // chain any data pipelines
8743         if (mainw->pconx) {
8744           pconx_chain_data(FX_DATA_KEY_PLAYBACK_PLUGIN, 0, FALSE);
8745         }
8746         if (mainw->cconx) cconx_chain_data(FX_DATA_KEY_PLAYBACK_PLUGIN, 0);
8747       }
8748 
8749       if (prefs->apply_gamma) {
8750         // gamma correction
8751         gamma_convert_layer(tgamma, frame_layer);
8752       }
8753       if (prefs->dev_show_timing)
8754         g_print("gamma conv done @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8755 
8756       if (return_layer) weed_leaf_dup(return_layer, frame_layer, WEED_LEAF_GAMMA_TYPE);
8757       pd_array = weed_layer_get_pixel_data(frame_layer, NULL);
8758       lb_width = lwidth = weed_layer_get_width_pixels(frame_layer);
8759       lb_height = lheight = weed_layer_get_height(frame_layer);
8760       pwidth = mainw->pwidth;
8761       pheight = mainw->pheight;
8762       if (player_v2) {
8763         if ((!mainw->multitrack && prefs->letterbox) || (mainw->multitrack && prefs->letterbox_mt)) {
8764           // pretend it cant resize, just to get the offsets
8765           get_letterbox_sizes(&pwidth, &pheight, &lb_width, &lb_height, FALSE);
8766           weed_set_double_value(frame_layer, "x_range", (double)lb_width / (double)pwidth);
8767           weed_set_double_value(frame_layer, "y_range", (double)lb_height / (double)pheight);
8768         } else {
8769           weed_set_double_value(frame_layer, "x_range", 1.0);
8770           weed_set_double_value(frame_layer, "y_range", 1.0);
8771         }
8772       }
8773 
8774       if (!avsync_check()) goto lfi_done;
8775 
8776       lwidth = weed_layer_get_width(frame_layer);
8777       if (tgamma == WEED_GAMMA_SRGB && prefs->use_screen_gamma) {
8778         // TODO - do conversion before letterboxing
8779         gamma_convert_layer(WEED_GAMMA_MONITOR, frame_layer);
8780       }
8781       if ((player_v2 && !(*mainw->vpp->play_frame)(frame_layer, mainw->currticks - mainw->stream_ticks, return_layer))
8782           || (!player_v2 && !(*mainw->vpp->render_frame)(lwidth, weed_layer_get_height(frame_layer),
8783               mainw->currticks - mainw->stream_ticks, pd_array, retdata, mainw->vpp->play_params))) {
8784         //vid_playback_plugin_exit();
8785         if (return_layer) {
8786           weed_layer_free(return_layer);
8787           lives_free(retdata);
8788           return_layer = NULL;
8789         }
8790       } else success = TRUE;
8791       if (prefs->dev_show_timing)
8792         g_printerr("rend fr done @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8793       lives_free(pd_array);
8794       if (frame_layer != mainw->frame_layer) {
8795         weed_layer_free(frame_layer);
8796       }
8797 
8798       if (return_layer) {
8799         int width = MIN(weed_layer_get_width(mainw->frame_layer)
8800                         / weed_palette_get_pixels_per_macropixel(weed_layer_get_palette(mainw->frame_layer)),
8801                         weed_layer_get_width(return_layer)
8802                         / weed_palette_get_pixels_per_macropixel(weed_layer_get_palette(return_layer)));
8803         int height = MIN(weed_layer_get_height(mainw->frame_layer), weed_layer_get_height(return_layer));
8804         if (!resize_layer(return_layer, width, height, LIVES_INTERP_FAST, WEED_PALETTE_END, 0)) {
8805           if (tgamma == WEED_GAMMA_SRGB && prefs->use_screen_gamma) {
8806             /// TODO - save w. screen_gamma
8807             gamma_convert_layer(WEED_GAMMA_SRGB, return_layer);
8808           }
8809           save_to_scrap_file(return_layer);
8810         }
8811         weed_layer_free(return_layer);
8812         lives_free(retdata);
8813         return_layer = NULL;
8814       }
8815 
8816       if (mainw->vpp->capabilities & VPP_LOCAL_DISPLAY) goto lfi_done;
8817     }
8818 
8819     get_player_size(&mainw->pwidth, &mainw->pheight);
8820     if (prefs->dev_show_timing)
8821       g_printerr("ext start  @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8822 
8823     if (mainw->ext_playback && (!(mainw->vpp->capabilities & VPP_CAN_RESIZE)
8824                                 || (((!mainw->multitrack && prefs->letterbox) || (mainw->multitrack && prefs->letterbox_mt))
8825                                     & !(mainw->vpp->capabilities & VPP_CAN_LETTERBOX)))) {
8826       // here we are either: playing through an external video playback plugin which cannot resize
8827       // - we must resize to whatever width and height we set when we called init_screen() in the plugin
8828       // i.e. mainw->vpp->fwidth, mainw->vpp fheight
8829 
8830       // both dimensions are in RGB(A) pixels, so we must adjust here and send the correct
8831       // macropixel size in the plugin's render_frame() (in case of exotic palettes)
8832 
8833       // - this is also used if we are letterboxing with an external plugin
8834 
8835       weed_plant_t *frame_layer = NULL;
8836       weed_plant_t *return_layer = NULL;
8837       int ovpppalette = mainw->vpp->palette;
8838       boolean needs_lb = FALSE;
8839 
8840       /// check if function exists - it accepts rowstrides
8841       if (mainw->vpp->play_frame) player_v2 = TRUE;
8842 
8843       check_layer_ready(mainw->frame_layer);
8844       mainw->video_seek_ready = TRUE;
8845       if (prefs->dev_show_timing)
8846         g_printerr("clr2  @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8847 
8848       layer_palette = weed_layer_get_palette(mainw->frame_layer);
8849       if (!weed_palette_is_valid(layer_palette)) goto lfi_done;
8850 
8851       if ((mainw->vpp->capabilities & VPP_CAN_CHANGE_PALETTE)
8852           && mainw->vpp->palette != layer_palette) vpp_try_match_palette(mainw->vpp, mainw->frame_layer);
8853       interp = get_interp_value(prefs->pb_quality, TRUE);
8854 
8855       if (mainw->fs && (mainw->vpp->capabilities & VPP_LOCAL_DISPLAY)) {
8856         mainw->vpp->fwidth = mainw->pwidth;
8857         mainw->vpp->fheight = mainw->pheight;
8858       }
8859 
8860       if (!(mainw->vpp->capabilities & VPP_LOCAL_DISPLAY) && !(mainw->vpp->capabilities & VPP_CAN_RESIZE) &&
8861           ((mainw->vpp->fwidth  < mainw->pwidth || mainw->vpp->fheight < mainw->pheight))) {
8862         // mainw->frame_layer will be downsized for the plugin but upsized for screen
8863         // so copy layer and convert, retaining original
8864         if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8865         frame_layer = weed_layer_copy(NULL, mainw->frame_layer);
8866       } else frame_layer = mainw->frame_layer;
8867 
8868       if (frame_layer == mainw->frame_layer && !(mainw->vpp->capabilities & VPP_LOCAL_DISPLAY) &&
8869           ((weed_palette_is_rgb(layer_palette) &&
8870             !(weed_palette_is_rgb(mainw->vpp->palette))) ||
8871            (weed_palette_is_lower_quality(mainw->vpp->palette, layer_palette)))) {
8872         // mainw->frame_layer is RGB and so is our screen, but plugin is YUV
8873         // so copy layer and convert, retaining original
8874         if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8875         frame_layer = weed_layer_copy(NULL, mainw->frame_layer);
8876       }
8877       if (prefs->dev_show_timing)
8878         g_printerr("copied  @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8879 
8880       pwidth = mainw->vpp->fwidth;
8881       pheight = mainw->vpp->fheight;
8882 
8883       if ((mainw->multitrack && prefs->letterbox_mt) || (!mainw->multitrack && prefs->letterbox)) {
8884         /// letterbox external
8885         lb_width = weed_layer_get_width_pixels(mainw->frame_layer);
8886         lb_height = weed_layer_get_height(mainw->frame_layer);
8887         get_letterbox_sizes(&pwidth, &pheight, &lb_width, &lb_height, (mainw->vpp->capabilities & VPP_CAN_RESIZE) != 0);
8888         if (pwidth != lb_width || pheight != lb_height) {
8889           needs_lb = TRUE;
8890           if (!(mainw->vpp->capabilities & VPP_CAN_LETTERBOX)) {
8891             if (frame_layer == mainw->frame_layer) {
8892               if (layer_palette != mainw->vpp->palette && (pwidth > lb_width || pheight > lb_height)) {
8893                 frame_layer = weed_layer_copy(NULL, mainw->frame_layer);
8894                 if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8895                 if (!convert_layer_palette_full(frame_layer, mainw->vpp->palette, mainw->vpp->YUV_clamping,
8896                                                 mainw->vpp->YUV_sampling, mainw->vpp->YUV_subspace, tgamma)) {
8897                   goto lfi_done;
8898                 }
8899               } else {
8900                 frame_layer = weed_layer_new(WEED_LAYER_TYPE_VIDEO);
8901                 weed_layer_copy(frame_layer, mainw->frame_layer);
8902               }
8903             }
8904             if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8905             if (!letterbox_layer(frame_layer, pwidth, pheight, lb_width, lb_height, interp,
8906                                  mainw->vpp->palette, mainw->vpp->YUV_clamping)) goto lfi_done;
8907             was_letterboxed = TRUE;
8908 	    // *INDENT-OFF*
8909 	  } else {
8910 	    weed_set_double_value(frame_layer, "x_range", (double)lb_width / (double)pwidth);
8911 	    weed_set_double_value(frame_layer, "y_range", (double)lb_height / (double)pheight);
8912 	  }
8913 	}
8914       }
8915       // *INDENT-ON*
8916 
8917       if (prefs->dev_show_timing)
8918         g_printerr("lbb  @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8919       layer_palette = weed_layer_get_palette(frame_layer);
8920 
8921       if (((weed_layer_get_width_pixels(frame_layer) ^ pwidth) >> 2) ||
8922           ((weed_layer_get_height(frame_layer) ^ pheight) >> 1)) {
8923         if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8924         if (!needs_lb  || was_letterboxed) {
8925           lb_width = pwidth;
8926           lb_height = pheight;
8927         }
8928         if (!resize_layer(frame_layer, lb_width, lb_height, interp,
8929                           mainw->vpp->palette, mainw->vpp->YUV_clamping)) goto lfi_done;
8930       }
8931       if (prefs->dev_show_timing)
8932         g_printerr("resize done  @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8933 
8934       // resize_layer can change palette
8935 
8936       if (frame_layer == mainw->frame_layer && !(mainw->vpp->capabilities & VPP_LOCAL_DISPLAY) &&
8937           ((weed_palette_is_rgb(layer_palette) &&
8938             !(weed_palette_is_rgb(mainw->vpp->palette))) ||
8939            (weed_palette_is_lower_quality(mainw->vpp->palette, layer_palette)))) {
8940         // mainw->frame_layer is RGB and so is our screen, but plugin is YUV
8941         // so copy layer and convert, retaining original
8942         if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8943         frame_layer = weed_layer_copy(NULL, mainw->frame_layer);
8944       }
8945 
8946       layer_palette = weed_layer_get_palette(frame_layer);
8947 
8948       pwidth = weed_layer_get_width(frame_layer) * weed_palette_get_pixels_per_macropixel(layer_palette);
8949       pheight = weed_layer_get_height(frame_layer);
8950 
8951       if (mainw->vpp->capabilities & VPP_LOCAL_DISPLAY) {
8952         if (!check_for_overlay_text(frame_layer)) {
8953           if (mainw->multitrack && mainw->multitrack->opts.overlay_timecode) {
8954             frame_layer = render_text_overlay(frame_layer, mainw->multitrack->timestring);
8955           }
8956         }
8957       }
8958 
8959       if (prefs->apply_gamma) {
8960         // gamma correction
8961         if (weed_palette_is_rgb(mainw->vpp->palette)) {
8962           if (mainw->vpp->capabilities & VPP_LINEAR_GAMMA)
8963             tgamma = WEED_GAMMA_LINEAR;
8964           else {
8965             tgamma = WEED_GAMMA_SRGB;
8966           }
8967         }
8968       }
8969       //g_print("clp start %d %d   %d %d @\n", weed_layer_get_palette(frame_layer),
8970       //mainw->vpp->palette, weed_layer_get_gamma(frame_layer), tgamma);
8971       if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8972       if (!convert_layer_palette_full(frame_layer, mainw->vpp->palette, mainw->vpp->YUV_clamping,
8973                                       mainw->vpp->YUV_sampling, mainw->vpp->YUV_subspace, tgamma)) {
8974         goto lfi_done;
8975       }
8976 
8977       if (prefs->dev_show_timing)
8978         g_printerr("clp done  @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8979 
8980       if (mainw->stream_ticks == -1) mainw->stream_ticks = mainw->currticks;
8981 
8982       if (!player_v2) {
8983         // vid plugin expects compacted rowstrides (i.e. no padding/alignment after pixel row)
8984         if (!compact_rowstrides(frame_layer)) goto lfi_done;
8985         if (prefs->dev_show_timing)
8986           g_printerr("c rows done  @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
8987       }
8988       if (rec_after_pb) {
8989         // record output from playback plugin
8990         int retwidth = mainw->vpp->fwidth;
8991         int retheight = mainw->vpp->fheight;
8992 
8993         if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1;
8994         return_layer = weed_layer_create(retwidth, retheight, NULL, ovpppalette);
8995 
8996         if (weed_palette_is_yuv(mainw->vpp->palette)) {
8997           weed_layer_set_yuv_clamping(return_layer, mainw->vpp->YUV_clamping);
8998           weed_layer_set_yuv_sampling(return_layer, mainw->vpp->YUV_sampling);
8999           weed_layer_set_yuv_subspace(return_layer, mainw->vpp->YUV_subspace);
9000         }
9001 
9002         if (!player_v2) THREADVAR(rowstride_alignment_hint) = -1 ; /// special value to compact the rowstrides
9003         if (create_empty_pixel_data(return_layer, FALSE, TRUE)) {
9004           retdata = weed_layer_get_pixel_data(return_layer, NULL);
9005         } else return_layer = NULL;
9006       }
9007 
9008       // chain any data to the playback plugin
9009       if (!(mainw->preview || mainw->is_rendering)) {
9010         // chain any data pipelines
9011         if (mainw->pconx) {
9012           pconx_chain_data(-2, 0, FALSE);
9013         }
9014         if (mainw->cconx) cconx_chain_data(-2, 0);
9015       }
9016 
9017       if (tgamma != WEED_GAMMA_UNKNOWN) {
9018         if (!was_letterboxed) {
9019           gamma_convert_layer(tgamma, frame_layer);
9020         } else {
9021           gamma_convert_sub_layer(tgamma, 1.0, frame_layer, (pwidth - lb_width) / 2, (pheight - lb_height) / 2,
9022                                   lb_width, lb_height, TRUE);
9023         }
9024       }
9025 
9026       if (return_layer) weed_layer_set_gamma(return_layer, weed_layer_get_gamma(frame_layer));
9027 
9028       if (!avsync_check()) goto lfi_done;
9029 
9030       pd_array = weed_layer_get_pixel_data(frame_layer, NULL);
9031 
9032       if (player_v2) {
9033         weed_set_double_value(frame_layer, "x_range", 1.0);
9034         weed_set_double_value(frame_layer, "y_range", 1.0);
9035       }
9036 
9037       if (tgamma == WEED_GAMMA_SRGB && prefs->use_screen_gamma) {
9038         // TODO - do conversion before letterboxing
9039         gamma_convert_layer(WEED_GAMMA_MONITOR, frame_layer);
9040       }
9041 
9042       if ((player_v2 && !(*mainw->vpp->play_frame)(frame_layer,
9043            mainw->currticks - mainw->stream_ticks, return_layer))
9044           || (!player_v2 && !(*mainw->vpp->render_frame)(weed_layer_get_width(frame_layer),
9045               weed_layer_get_height(frame_layer),
9046               mainw->currticks - mainw->stream_ticks, pd_array, retdata,
9047               mainw->vpp->play_params))) {
9048         //vid_playback_plugin_exit();
9049         if (return_layer) {
9050           weed_layer_free(return_layer);
9051           lives_free(retdata);
9052           return_layer = NULL;
9053         }
9054         goto lfi_done;
9055       } else success = TRUE;
9056       lives_free(pd_array);
9057       if (prefs->dev_show_timing)
9058         g_printerr("rend done  @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
9059 
9060       if (return_layer) {
9061         int width = MIN(weed_layer_get_width(mainw->frame_layer)
9062                         * weed_palette_get_pixels_per_macropixel(weed_layer_get_palette(mainw->frame_layer)),
9063                         weed_layer_get_width(return_layer)
9064                         * weed_palette_get_pixels_per_macropixel(weed_layer_get_palette(return_layer)));
9065         int height = MIN(weed_layer_get_height(mainw->frame_layer), weed_layer_get_height(return_layer));
9066         if (resize_layer(return_layer, width, height, LIVES_INTERP_FAST, WEED_PALETTE_END, 0)) {
9067           if (tgamma == WEED_GAMMA_SRGB && prefs->use_screen_gamma) {
9068             // TODO - save w. screen_gamma
9069             gamma_convert_layer(WEED_GAMMA_SRGB, frame_layer);
9070           }
9071           save_to_scrap_file(return_layer);
9072         }
9073         weed_layer_free(return_layer);
9074         lives_free(retdata);
9075         return_layer = NULL;
9076       }
9077 
9078       if (frame_layer != mainw->frame_layer) {
9079         weed_layer_free(frame_layer);
9080       }
9081 
9082       // frame display was handled by a playback plugin, skip the rest
9083       if (mainw->vpp->capabilities & VPP_LOCAL_DISPLAY) goto lfi_done;
9084     }
9085 
9086     ////////////////////////////////////////////////////////
9087     // local display - either we are playing with no playback plugin, or else the playback plugin has no
9088     // local display of its own
9089     if (prefs->dev_show_timing)
9090       g_printerr("clr @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
9091     check_layer_ready(mainw->frame_layer); // wait for all threads to complete
9092     mainw->video_seek_ready = TRUE;
9093     if (prefs->dev_show_timing)
9094       g_printerr("clr end @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
9095     if (weed_layer_get_width(mainw->frame_layer) == 0) return;
9096     if ((mainw->sep_win && !prefs->show_playwin) || (!mainw->sep_win && !prefs->show_gui)) {
9097       // no display to output, skip the rest
9098       success = TRUE;
9099       goto lfi_done;
9100     }
9101 
9102     if (mainw->ext_playback && !player_v2) THREADVAR(rowstride_alignment_hint) = -1 ; /// special value to compact the rowstrides
9103     layer_palette = weed_layer_get_palette(mainw->frame_layer);
9104     if (!weed_palette_is_valid(layer_palette) || !CURRENT_CLIP_IS_VALID) goto lfi_done;
9105 
9106     if (cfile->img_type == IMG_TYPE_JPEG || !weed_palette_has_alpha(layer_palette)) cpal = WEED_PALETTE_RGB24;
9107     else {
9108       cpal = WEED_PALETTE_RGBA32;
9109     }
9110     if (mainw->fs && !mainw->ext_playback && (!mainw->multitrack || mainw->sep_win)) {
9111       // set again, in case vpp was turned off because of preview conditions
9112       get_player_size(&mainw->pwidth, &mainw->pheight);
9113     }
9114 
9115     interp = get_interp_value(prefs->pb_quality, TRUE);
9116 
9117     pwidth = opwidth;
9118     pheight = opheight;
9119 
9120     if (prefs->dev_show_timing)
9121       g_printerr("res start @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
9122 
9123     lb_width = weed_layer_get_width_pixels(mainw->frame_layer);
9124     lb_height = weed_layer_get_height(mainw->frame_layer);
9125 
9126     if ((lb_width != pwidth || lb_height != pheight)
9127         || weed_get_boolean_value(mainw->frame_layer, "letterboxed", NULL) == WEED_FALSE) {
9128       if ((!mainw->multitrack && prefs->letterbox) || (mainw->multitrack && prefs->letterbox_mt)) {
9129         /// letterbox internal
9130         get_letterbox_sizes(&pwidth, &pheight, &lb_width, &lb_height, FALSE);
9131         if (!letterbox_layer(mainw->frame_layer, pwidth, pheight, lb_width, lb_height, interp, cpal, 0)) goto lfi_done;
9132         was_letterboxed = TRUE;
9133         weed_set_boolean_value(mainw->frame_layer, "letterboxed", WEED_TRUE);
9134         lb_width = pwidth;
9135         lb_height = pheight;
9136       }
9137     }
9138 
9139     if (lb_width != pwidth || lb_height != pheight ||
9140         weed_get_boolean_value(mainw->frame_layer, "letterboxed", NULL) == WEED_FALSE) {
9141       if (weed_layer_get_width_pixels(mainw->frame_layer) != pwidth ||
9142           weed_layer_get_height(mainw->frame_layer) != pheight) {
9143         if (!resize_layer(mainw->frame_layer, pwidth, pheight, interp, cpal, 0)) goto lfi_done;
9144       }
9145     }
9146     if (prefs->dev_show_timing)
9147       g_printerr("res end @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
9148 
9149     if (!convert_layer_palette_full(mainw->frame_layer, cpal, 0, 0, 0, WEED_GAMMA_SRGB)) goto lfi_done;
9150 
9151     if (prefs->dev_show_timing)
9152       g_printerr("clp end @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
9153     if (LIVES_IS_PLAYING) {
9154       if (!check_for_overlay_text(mainw->frame_layer)) {
9155         if (mainw->multitrack && mainw->multitrack->opts.overlay_timecode) {
9156           mainw->frame_layer = render_text_overlay(mainw->frame_layer, mainw->multitrack->timestring);
9157         }
9158       }
9159     }
9160 
9161     /* if (1 || !was_letterboxed) { */
9162     /*   if (!prefs->gamma_srgb) */
9163     /*     gamma_convert_layer(WEED_GAMMA_MONITOR, mainw->frame_layer); */
9164     /*   else */
9165     /*     gamma_convert_layer(WEED_GAMMA_SRGB, mainw->frame_layer); */
9166     /* } else { */
9167     /*   if (!prefs->gamma_srgb) */
9168     /*     gamma_convert_sub_layer(WEED_GAMMA_MONITOR, mainw->frame_layer, (pwidth - lb_width) / 2, (pheight - lb_height / 2), */
9169     /*                             lb_width, lb_height); */
9170     /*   else */
9171     /*     gamma_convert_sub_layer(WEED_GAMMA_SRGB, mainw->frame_layer, (pwidth - lb_width) / 2, (pheight - lb_height / 2), */
9172     /*                             lb_width, lb_height); */
9173     /* } */
9174 
9175     if (prefs->dev_show_timing)
9176       g_printerr("l2p start @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
9177 
9178     pixbuf = layer_to_pixbuf(mainw->frame_layer, TRUE, TRUE);
9179 
9180     if (prefs->dev_show_timing)
9181       g_printerr("l2p @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
9182 
9183     if (!avsync_check()) goto lfi_done;
9184 
9185     // internal player, double size or fullscreen, or multitrack
9186 
9187     if (mainw->play_window && LIVES_IS_XWINDOW(lives_widget_get_xwindow(mainw->play_window))) {
9188       set_drawing_area_from_pixbuf(mainw->preview_image, pixbuf, mainw->pi_surface);
9189       lives_widget_queue_draw(mainw->preview_image);
9190     } else {
9191       pwidth = lives_widget_get_allocation_width(mainw->play_image);
9192       pheight = lives_widget_get_allocation_height(mainw->play_image);
9193       if (pwidth < old_pwidth || pheight < old_pheight)
9194         clear_widget_bg(mainw->play_image, mainw->play_surface);
9195       old_pwidth = pwidth;
9196       old_pheight = pheight;
9197       set_drawing_area_from_pixbuf(mainw->play_image, pixbuf, mainw->play_surface);
9198       lives_widget_queue_draw(mainw->play_image);
9199     }
9200 
9201     if (pixbuf) lives_widget_object_unref(pixbuf);
9202     success = TRUE;
9203     if (prefs->dev_show_timing)
9204       g_print("paint @ %f\n\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
9205     goto lfi_done;
9206   }
9207 
9208   // record external window
9209   if (mainw->record_foreign) {
9210     char fname[PATH_MAX];
9211     int xwidth, xheight;
9212     LiVESError *gerror = NULL;
9213     lives_painter_t *cr = lives_painter_create_from_surface(mainw->play_surface);
9214 
9215     if (!cr) return;
9216 
9217     if (mainw->rec_vid_frames == -1) {
9218       lives_entry_set_text(LIVES_ENTRY(mainw->framecounter), (tmp = lives_strdup_printf("%9d", frame)));
9219       lives_widget_queue_draw(mainw->framecounter);
9220     } else {
9221       if (frame > mainw->rec_vid_frames) {
9222         mainw->cancelled = CANCEL_KEEP;
9223         if (CURRENT_CLIP_HAS_VIDEO) cfile->frames = mainw->rec_vid_frames;
9224         return;
9225       }
9226 
9227       lives_entry_set_text(LIVES_ENTRY(mainw->framecounter), (tmp = lives_strdup_printf("%9d / %9d",
9228                            frame, mainw->rec_vid_frames)));
9229       lives_widget_queue_draw(mainw->framecounter);
9230       lives_free(tmp);
9231     }
9232 
9233 #ifdef GUI_GTK
9234 #if GTK_CHECK_VERSION(3, 0, 0)
9235     xwidth = gdk_window_get_width(mainw->foreign_window);
9236     xheight = gdk_window_get_height(mainw->foreign_window);
9237     if ((pixbuf = gdk_pixbuf_get_from_window(mainw->foreign_window, 0, 0, xwidth, xheight))) {
9238 #else
9239     gdk_window_get_size(mainw->foreign_window, &xwidth, &xheight);
9240     if ((pixbuf = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE(mainw->foreign_window),
9241                   mainw->foreign_cmap, 0, 0, 0, 0, xwidth, xheight))) {
9242 #endif
9243 #endif
9244       tmp = make_image_file_name(cfile, frame, get_image_ext_for_type(cfile->img_type));
9245       lives_snprintf(fname, PATH_MAX, "%s", tmp);
9246       lives_free(tmp);
9247 
9248       do {
9249         // TODO ***: add a timeout here
9250         if (gerror) lives_error_free(gerror);
9251         lives_pixbuf_save(pixbuf, fname, cfile->img_type, 100, cfile->hsize, cfile->vsize, &gerror);
9252       } while (gerror);
9253 
9254       lives_painter_set_source_pixbuf(cr, pixbuf, 0, 0);
9255       lives_painter_paint(cr);
9256       lives_painter_destroy(cr);
9257 
9258       if (pixbuf) lives_widget_object_unref(pixbuf);
9259       cfile->frames = frame;
9260     } else {
9261       widget_opts.non_modal = TRUE;
9262       do_error_dialog(_("LiVES was unable to capture this image\n\n"));
9263       widget_opts.non_modal = FALSE;
9264       mainw->cancelled = CANCEL_CAPTURE_ERROR;
9265     }
9266     if (frame > mainw->rec_vid_frames && mainw->rec_vid_frames > -1)
9267       mainw->cancelled = CANCEL_KEEP;
9268     lives_freep((void **)&framecount);
9269     return;
9270   }
9271 
9272 lfi_done:
9273   // here is where we free the mainw->frame_layer (the output video "frame" we just worked with)
9274   // we also animate the timeline and frame counters
9275   // if success is TRUE we may send an OSC FRAME_SYNCH notification
9276 
9277   /* if (cleaner) { */
9278   /* 	lives_nanosleep_until_nonzero(weed_get_boolean_value(cleaner, WEED_LEAF_DONE, NULL)); */
9279   /* 	weed_plant_free(cleaner); */
9280   /* 	cleaner = NULL; */
9281   /* } */
9282 
9283   do_cleanup(mainw->frame_layer, success);
9284   mainw->frame_layer = NULL;
9285   THREADVAR(rowstride_alignment_hint) = 0;
9286   lives_freep((void **)&framecount);
9287   if (success) {
9288     if (!mainw->multitrack &&
9289         !mainw->faded && (!mainw->fs || (prefs->gui_monitor != prefs->play_monitor
9290                                          && prefs->play_monitor != 0 && capable->nmonitors > 1))
9291         && mainw->current_file != mainw->scrap_file) {
9292       double ptrtime = ((double)mainw->actual_frame - 1.) / cfile->fps;
9293       mainw->ptrtime = ptrtime;
9294       lives_widget_queue_draw(mainw->eventbox2);
9295     }
9296     if (mainw->multitrack && !cfile->opening) animate_multitrack(mainw->multitrack);
9297   }
9298 }
9299 
9300 
9301 /**
9302    @brief Save a pixbuf to a file using the specified imgtype and the specified quality/compression value
9303 */
9304 boolean lives_pixbuf_save(LiVESPixbuf * pixbuf, char *fname, lives_img_type_t imgtype, int quality, int width, int height,
9305                           LiVESError **gerrorptr) {
9306   ticks_t timeout;
9307   lives_alarm_t alarm_handle;
9308   boolean retval = TRUE;
9309   int fd;
9310 
9311   // CALLER should check for errors
9312   // fname should be in local charset
9313 
9314   if (!LIVES_IS_PIXBUF(pixbuf)) {
9315     /// invalid pixbuf, we will save a blank image
9316     const char *img_ext = get_image_ext_for_type(imgtype);
9317     weed_layer_t  *layer = create_blank_layer(NULL, img_ext, width, height, WEED_PALETTE_END);
9318     pixbuf = layer_to_pixbuf(layer, TRUE, FALSE);
9319     weed_layer_free(layer);
9320     retval = FALSE;
9321   }
9322 
9323   fd = lives_open3(fname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
9324   alarm_handle = lives_alarm_set(LIVES_SHORTEST_TIMEOUT);
9325   while (flock(fd, LOCK_EX) && (timeout = lives_alarm_check(alarm_handle)) > 0) {
9326     lives_nanosleep(1000);
9327   }
9328   lives_alarm_clear(alarm_handle);
9329   if (timeout == 0) return FALSE;
9330 
9331   if (imgtype == IMG_TYPE_JPEG) {
9332     char *qstr = lives_strdup_printf("%d", quality);
9333 #ifdef GUI_GTK
9334     gdk_pixbuf_save(pixbuf, fname, LIVES_IMAGE_TYPE_JPEG, gerrorptr, "quality", qstr, NULL);
9335 #endif
9336 #ifdef GUI_QT
9337     qt_jpeg_save(pixbuf, fname, gerrorptr, quality);
9338 #endif
9339     lives_free(qstr);
9340   } else if (imgtype == IMG_TYPE_PNG) {
9341     char *cstr = lives_strdup_printf("%d", (int)((100. - (double)quality + 5.) / 10.));
9342     if (LIVES_IS_PIXBUF(pixbuf)) {
9343 #ifdef GUI_GTK
9344       gdk_pixbuf_save(pixbuf, fname, LIVES_IMAGE_TYPE_PNG, gerrorptr, "compression", cstr, NULL);
9345 #endif
9346 #ifdef GUI_QT
9347       qt_png_save(pixbuf, fname, gerrorptr, (int)((100. - (double)quality + 5.) / 10.));
9348 #endif
9349     } else retval = FALSE;
9350     lives_free(cstr);
9351   } else {
9352     //gdk_pixbuf_save_to_callback(...);
9353   }
9354 
9355   close(fd);
9356   if (*gerrorptr) return FALSE;
9357   return retval;
9358 }
9359 
9360 /**
9361    @brief save frame to pixbuf in a thread.
9362    The renderer uses this now so that it can be saving the current output frame
9363    at the same time as it prepares the following frame
9364 */
9365 void  *lives_pixbuf_save_threaded(void *args) {
9366   savethread_priv_t *saveargs = (savethread_priv_t *)args;
9367   lives_pixbuf_save(saveargs->pixbuf, saveargs->fname, saveargs->img_type, saveargs->compression, saveargs->width,
9368                     saveargs->height, &saveargs->error);
9369   return saveargs;
9370 }
9371 
9372 
9373 void close_current_file(int file_to_switch_to) {
9374   // close the current file, and free the file struct and all sub storage
9375   LiVESList *list_index;
9376   char *com;
9377   boolean need_new_blend_file = FALSE;
9378   int index = -1;
9379   int old_file = mainw->current_file;
9380 
9381   //update the bar text
9382   if (CURRENT_CLIP_IS_VALID) {
9383     int i;
9384     if (cfile->clip_type == CLIP_TYPE_TEMP) {
9385       close_temp_handle(file_to_switch_to);
9386       return;
9387     }
9388     if (cfile->clip_type != CLIP_TYPE_GENERATOR && mainw->current_file != mainw->scrap_file &&
9389         mainw->current_file != mainw->ascrap_file && mainw->current_file != 0 &&
9390         (!mainw->multitrack || mainw->current_file != mainw->multitrack->render_file)) {
9391       d_print(_("Closed clip %s\n"), cfile->file_name);
9392       lives_notify(LIVES_OSC_NOTIFY_CLIP_CLOSED, "");
9393     }
9394 
9395     cfile->hsize = mainw->def_width;
9396     cfile->vsize = mainw->def_height;
9397 
9398     if (cfile->laudio_drawable) {
9399       if (mainw->laudio_drawable == cfile->laudio_drawable
9400           || mainw->drawsrc == mainw->current_file) mainw->laudio_drawable = NULL;
9401       if (!mainw->multitrack) {
9402         if (cairo_surface_get_reference_count(cfile->laudio_drawable))
9403           lives_painter_surface_destroy(cfile->laudio_drawable);
9404       }
9405       cfile->laudio_drawable = NULL;
9406     }
9407     if (cfile->raudio_drawable) {
9408       if (mainw->raudio_drawable == cfile->raudio_drawable
9409           || mainw->drawsrc == mainw->current_file) mainw->raudio_drawable = NULL;
9410       if (!mainw->multitrack) {
9411         if (cairo_surface_get_reference_count(cfile->raudio_drawable))
9412           lives_painter_surface_destroy(cfile->raudio_drawable);
9413       }
9414       cfile->raudio_drawable = NULL;
9415     }
9416     if (mainw->drawsrc == mainw->current_file) mainw->drawsrc = -1;
9417 
9418     if (mainw->st_fcache) {
9419       if (mainw->en_fcache == mainw->st_fcache) mainw->en_fcache = NULL;
9420       if (mainw->pr_fcache == mainw->st_fcache) mainw->pr_fcache = NULL;
9421       weed_layer_free(mainw->st_fcache);
9422       mainw->st_fcache = NULL;
9423     }
9424     if (mainw->en_fcache) {
9425       if (mainw->pr_fcache == mainw->en_fcache) mainw->pr_fcache = NULL;
9426       weed_layer_free(mainw->en_fcache);
9427       mainw->en_fcache = NULL;
9428     }
9429     if (mainw->pr_fcache) {
9430       weed_layer_free(mainw->pr_fcache);
9431       mainw->pr_fcache = NULL;
9432     }
9433 
9434     for (i = 0; i < FN_KEYS - 1; i++) {
9435       if (mainw->clipstore[i][0] == mainw->current_file) mainw->clipstore[i][0] = -1;
9436     }
9437 
9438     // this must all be done last...
9439     if (cfile->menuentry) {
9440       // c.f. on_prevclip_activate
9441       list_index = lives_list_find(mainw->cliplist, LIVES_INT_TO_POINTER(mainw->current_file));
9442       do {
9443         if (!(list_index = lives_list_previous(list_index))) list_index = lives_list_last(mainw->cliplist);
9444         index = LIVES_POINTER_TO_INT(lives_list_nth_data(list_index, 0));
9445       } while ((mainw->files[index] || mainw->files[index]->opening || mainw->files[index]->restoring ||
9446                 (index == mainw->scrap_file && index > -1) || (index == mainw->ascrap_file && index > -1)
9447                 || (mainw->files[index]->frames == 0 &&
9448                     LIVES_IS_PLAYING)) &&
9449                index != mainw->current_file);
9450       if (index == mainw->current_file) index = -1;
9451       if (mainw->current_file != mainw->scrap_file && mainw->current_file != mainw->ascrap_file) remove_from_clipmenu();
9452     }
9453 
9454     if (CURRENT_CLIP_IS_NORMAL && cfile->ext_src) {
9455       if (cfile->ext_src_type == LIVES_EXT_SRC_DECODER) {
9456         close_clip_decoder(mainw->current_file);
9457       }
9458     }
9459     free_thumb_cache(mainw->current_file, 0);
9460     lives_freep((void **)&cfile->frame_index);
9461     lives_freep((void **)&cfile->frame_index_back);
9462 
9463     if (cfile->clip_type != CLIP_TYPE_GENERATOR && !mainw->close_keep_frames) {
9464       char *clipd = lives_build_path(prefs->workdir, cfile->handle, NULL);
9465       if (lives_file_test(clipd, LIVES_FILE_TEST_EXISTS)) {
9466         // as a safety feature we create a special file which allows the back end to delete the directory
9467         char *permitname = lives_build_filename(clipd, TEMPFILE_MARKER "." LIVES_FILE_EXT_TMP, NULL);
9468         lives_touch(permitname);
9469         lives_free(permitname);
9470 
9471         com = lives_strdup_printf("%s close \"%s\"", prefs->backend_sync, cfile->handle);
9472         lives_system(com, TRUE);
9473         lives_free(com);
9474       }
9475       lives_free(clipd);
9476       if (cfile->event_list_back) event_list_free(cfile->event_list_back);
9477       if (cfile->event_list) event_list_free(cfile->event_list);
9478 
9479       lives_list_free_all(&cfile->layout_map);
9480     }
9481 
9482     if (cfile->subt) subtitles_free(cfile);
9483 
9484     if (cfile->clip_type == CLIP_TYPE_YUV4MPEG) {
9485 #ifdef HAVE_YUV4MPEG
9486       lives_yuv_stream_stop_read((lives_yuv4m_t *)cfile->ext_src);
9487       lives_free(cfile->ext_src);
9488 #endif
9489     }
9490 
9491     if (cfile->clip_type == CLIP_TYPE_VIDEODEV) {
9492 #ifdef HAVE_UNICAP
9493       lives_vdev_free((lives_vdev_t *)cfile->ext_src);
9494       lives_free(cfile->ext_src);
9495 #endif
9496     }
9497 
9498     if (cfile->audio_waveform) {
9499       for (i = 0; i < cfile->achans; i++) lives_freep((void **)&cfile->audio_waveform[i]);
9500       lives_freep((void **)&cfile->audio_waveform);
9501       lives_free(cfile->aw_sizes);
9502     }
9503 
9504     lives_freep((void **)&cfile);
9505 
9506     if (mainw->multitrack && mainw->current_file != mainw->multitrack->render_file) {
9507       mt_delete_clips(mainw->multitrack, mainw->current_file);
9508     }
9509 
9510     if (mainw->first_free_file == ALL_USED || mainw->first_free_file > mainw->current_file)
9511       mainw->first_free_file = mainw->current_file;
9512 
9513     if (!mainw->only_close) {
9514       if (IS_VALID_CLIP(file_to_switch_to) && file_to_switch_to > 0) {
9515         if (!mainw->multitrack) {
9516           if (!LIVES_IS_PLAYING) {
9517             mainw->current_file = file_to_switch_to;
9518             switch_clip(1, file_to_switch_to, TRUE);
9519             d_print("");
9520           } else {
9521             if (file_to_switch_to != mainw->playing_file) mainw->new_clip = file_to_switch_to;
9522           }
9523         } else if (old_file != mainw->multitrack->render_file) {
9524           mt_clip_select(mainw->multitrack, TRUE);
9525         }
9526         return;
9527       }
9528     }
9529     // file we were asked to switch to is invalid, thus we must find one
9530 
9531     if (mainw->current_file == mainw->blend_file) {
9532       need_new_blend_file = TRUE;
9533       // set blend_file to -1. This in case the file is a generator - we need to distinguish between the cases where
9534       // the generator is the blend file and we switch because it was deinited, and when we switch fg <-> bg
9535       // in the former case the generator is killed off, in the latter it survives
9536       mainw->blend_file = -1;
9537     }
9538 
9539     mainw->preview_frame = 0;
9540 
9541     if (!mainw->only_close) {
9542       // find another clip to switch to
9543       if (index > -1) {
9544         if (!mainw->multitrack) {
9545           if (!LIVES_IS_PLAYING) {
9546             switch_clip(1, index, TRUE);
9547             d_print("");
9548           } else mainw->new_clip = index;
9549           if (need_new_blend_file) mainw->blend_file = mainw->current_file;
9550         } else {
9551           mainw->multitrack->clip_selected = -mainw->multitrack->clip_selected;
9552           mt_clip_select(mainw->multitrack, TRUE);
9553         }
9554         return;
9555       }
9556       if (mainw->clips_available > 0) {
9557         for (i = mainw->current_file - 1; i > 0; i--) {
9558           if (mainw->files[i]) {
9559             if (!mainw->multitrack) {
9560               if (!LIVES_IS_PLAYING) {
9561                 switch_clip(1, i, TRUE);
9562                 d_print("");
9563               } else mainw->new_clip = index;
9564               if (need_new_blend_file) mainw->blend_file = mainw->current_file;
9565             } else {
9566               mainw->multitrack->clip_selected = -mainw->multitrack->clip_selected;
9567               mt_clip_select(mainw->multitrack, TRUE);
9568             }
9569             return;
9570           }
9571         }
9572         for (i = 1; i < MAX_FILES; i++) {
9573           if (mainw->files[i]) {
9574             if (!mainw->multitrack) {
9575               if (!LIVES_IS_PLAYING) {
9576                 switch_clip(1, i, TRUE);
9577                 d_print("");
9578               } else mainw->new_clip = index;
9579               if (need_new_blend_file) mainw->blend_file = mainw->current_file;
9580             } else {
9581               mainw->multitrack->clip_selected = -mainw->multitrack->clip_selected;
9582               mt_clip_select(mainw->multitrack, TRUE);
9583             }
9584             return;
9585 	      // *INDENT-OFF*
9586 	    }}}}}
9587     // *INDENT-ON*
9588 
9589   // no other clips
9590   mainw->current_file = mainw->blend_file = -1;
9591   set_main_title(NULL, 0);
9592 
9593   lives_widget_set_sensitive(mainw->vj_save_set, FALSE);
9594   lives_widget_set_sensitive(mainw->vj_load_set, TRUE);
9595   lives_widget_set_sensitive(mainw->export_proj, FALSE);
9596   lives_widget_set_sensitive(mainw->import_proj, FALSE);
9597 
9598   if (mainw->multitrack) lives_widget_set_sensitive(mainw->multitrack->load_set, TRUE);
9599 
9600   // can't use set_undoable, as we don't have a cfile
9601   lives_menu_item_set_text(mainw->undo, _("_Undo"), TRUE);
9602   lives_menu_item_set_text(mainw->redo, _("_Redo"), TRUE);
9603   lives_widget_hide(mainw->redo);
9604   lives_widget_show(mainw->undo);
9605   lives_widget_set_sensitive(mainw->undo, FALSE);
9606 
9607   if (!mainw->is_ready || mainw->recovering_files) return;
9608 
9609   if (LIVES_IS_PLAYING) mainw->cancelled = CANCEL_GENERATOR_END;
9610 
9611   if (!mainw->multitrack) {
9612     //resize(1);
9613     lives_widget_set_opacity(mainw->playframe, 0.);
9614     //lives_widget_hide(mainw->playframe);
9615     load_start_image(0);
9616     load_end_image(0);
9617     if (prefs->show_msg_area && !mainw->only_close) {
9618       if (mainw->idlemax == 0) {
9619         lives_idle_add_simple(resize_message_area, NULL);
9620       }
9621       mainw->idlemax = DEF_IDLE_MAX;
9622     }
9623   }
9624 
9625   set_sel_label(mainw->sel_label);
9626 
9627   zero_spinbuttons();
9628   show_playbar_labels(-1);
9629 
9630   if (!mainw->only_close) {
9631     lives_widget_queue_draw(LIVES_MAIN_WINDOW_WIDGET);
9632     if (!LIVES_IS_PLAYING) d_print("");
9633 
9634     if (mainw->multitrack) {
9635       mainw->multitrack->clip_selected = -mainw->multitrack->clip_selected;
9636       mt_clip_select(mainw->multitrack, TRUE);
9637     }
9638   }
9639   if (!LIVES_IS_PLAYING && !mainw->is_processing && !mainw->preview) {
9640     if (mainw->multitrack) mt_sensitise(mainw->multitrack);
9641     else sensitize();
9642   }
9643 }
9644 
9645 
9646 void switch_to_file(int old_file, int new_file) {
9647   // this function is used for full clip switching (during non-playback or non fs)
9648 
9649   // calling this function directly is now deprecated in favour of switch_clip()
9650 
9651   int orig_file = mainw->current_file;
9652 
9653   // should use close_current_file
9654   if (!IS_VALID_CLIP(new_file)) {
9655     char *msg = lives_strdup_printf("attempt to switch to invalid clip %d", new_file);
9656     LIVES_WARN(msg);
9657     lives_free(msg);
9658     return;
9659   }
9660 
9661   if (mainw->multitrack) return;
9662 
9663   if (LIVES_IS_PLAYING) {
9664     mainw->new_clip = new_file;
9665     return;
9666   }
9667 
9668   mainw->current_file = new_file;
9669 
9670   if (old_file != new_file) {
9671     if (CURRENT_CLIP_IS_VALID) {
9672       mainw->laudio_drawable = cfile->laudio_drawable;
9673       mainw->raudio_drawable = cfile->raudio_drawable;
9674       mainw->drawsrc = mainw->current_file;
9675     }
9676     if (old_file != 0 && new_file != 0) mainw->preview_frame = 0;
9677     if (1) {
9678       // TODO - indicate "opening" in clipmenu
9679 
9680       //      if (old_file>0&&mainw->files[old_file]!=NULL&&mainw->files[old_file]->menuentry!=NULL&&
9681       //  (mainw->files[old_file]->clip_type==CLIP_TYPE_DISK||mainw->files[old_file]->clip_type==CLIP_TYPE_FILE)) {
9682       //char menutext[32768];
9683       //get_menu_text_long(mainw->files[old_file]->menuentry,menutext);
9684 
9685       //lives_menu_item_set_text(mainw->files[old_file]->menuentry,menutext,FALSE);
9686       //}
9687       lives_widget_set_sensitive(mainw->select_new, (cfile->insert_start > 0));
9688       lives_widget_set_sensitive(mainw->select_last, (cfile->undo_start > 0));
9689       if ((cfile->start == 1 || cfile->end == cfile->frames) && !(cfile->start == 1 && cfile->end == cfile->frames)) {
9690         lives_widget_set_sensitive(mainw->select_invert, TRUE);
9691       } else {
9692         lives_widget_set_sensitive(mainw->select_invert, FALSE);
9693       }
9694       if (IS_VALID_CLIP(old_file) && mainw->files[old_file]->opening) {
9695         // switch while opening - come out of processing dialog
9696         if (mainw->proc_ptr) {
9697           lives_widget_destroy(mainw->proc_ptr->processing);
9698           lives_freep((void **)&mainw->proc_ptr);
9699 	    // *INDENT-OFF*
9700 	  }}}}
9701     // *INDENT-ON*
9702 
9703   if (mainw->play_window && cfile->is_loaded && orig_file != new_file) {
9704     resize_play_window();
9705 
9706     // if the clip is loaded
9707     if (!mainw->preview_box) {
9708       // create the preview box that shows frames...
9709       make_preview_box();
9710     }
9711     // add it the play window...
9712     if (!lives_widget_get_parent(mainw->preview_box)) {
9713       lives_widget_queue_draw(mainw->play_window);
9714       lives_container_add(LIVES_CONTAINER(mainw->play_window), mainw->preview_box);
9715     }
9716 
9717     lives_widget_set_no_show_all(mainw->preview_controls, FALSE);
9718     lives_widget_show_all(mainw->preview_box);
9719     lives_widget_show_now(mainw->preview_box);
9720     lives_widget_set_no_show_all(mainw->preview_controls, TRUE);
9721 
9722     // and resize it
9723     lives_widget_grab_focus(mainw->preview_spinbutton);
9724     load_preview_image(FALSE);
9725   }
9726 
9727   if (!mainw->go_away && !LIVES_IS_PLAYING && CURRENT_CLIP_IS_NORMAL) {
9728     mainw->no_context_update = TRUE;
9729     reget_afilesize(mainw->current_file);
9730     mainw->no_context_update = FALSE;
9731   }
9732 
9733   if (!CURRENT_CLIP_IS_VALID) return;
9734   //chill_decoder_plugin(mainw->current_file);
9735 
9736   if (!CURRENT_CLIP_IS_NORMAL || cfile->opening) {
9737     lives_widget_set_sensitive(mainw->rename, FALSE);
9738   }
9739 
9740   if (cfile->menuentry) {
9741     reset_clipmenu();
9742   }
9743 
9744   if (!mainw->switch_during_pb && !cfile->opening) sensitize();
9745 
9746   lives_menu_item_set_text(mainw->undo, cfile->undo_text, TRUE);
9747   lives_menu_item_set_text(mainw->redo, cfile->redo_text, TRUE);
9748 
9749   set_sel_label(mainw->sel_label);
9750 
9751   if (mainw->eventbox5) lives_widget_show(mainw->eventbox5);
9752   lives_widget_show(mainw->hruler);
9753   lives_widget_show(mainw->vidbar);
9754   lives_widget_show(mainw->laudbar);
9755 
9756   if (cfile->achans < 2) {
9757     lives_widget_hide(mainw->raudbar);
9758   } else {
9759     lives_widget_show(mainw->raudbar);
9760   }
9761 
9762   if (cfile->redoable) {
9763     lives_widget_show(mainw->redo);
9764     lives_widget_hide(mainw->undo);
9765   } else {
9766     lives_widget_hide(mainw->redo);
9767     lives_widget_show(mainw->undo);
9768   }
9769 
9770   if (new_file > 0) {
9771     if (cfile->menuentry) {
9772       set_main_title(cfile->name, 0);
9773     } else set_main_title(cfile->file_name, 0);
9774   }
9775 
9776   if (cfile->frames == 0) {
9777     zero_spinbuttons();
9778   }
9779 
9780   resize(1);
9781   if (!mainw->go_away) {
9782     get_play_times();
9783   }
9784 
9785   // if the file was opening, continue...
9786   if (cfile->opening) {
9787     open_file(cfile->file_name);
9788   } else {
9789     showclipimgs();
9790     redraw_timeline(mainw->current_file);
9791     lives_ce_update_timeline(0, cfile->pointer_time);
9792     mainw->ptrtime = cfile->pointer_time;
9793     lives_widget_queue_draw(mainw->eventbox2);
9794   }
9795 
9796   if (!mainw->multitrack && !mainw->reconfig) {
9797     if (prefs->show_msg_area && !mainw->only_close) {
9798       reset_message_area(); // necessary
9799       if (mainw->idlemax == 0) {
9800         lives_idle_add_simple(resize_message_area, NULL);
9801       }
9802       mainw->idlemax = DEF_IDLE_MAX;
9803     }
9804   }
9805 }
9806 
9807 
9808 boolean  switch_audio_clip(int new_file, boolean activate) {
9809   ticks_t timeout;
9810   lives_alarm_t alarm_handle;
9811 
9812   if (prefs->audio_player == AUD_PLAYER_JACK) {
9813 #ifdef ENABLE_JACK
9814     if (mainw->jackd) {
9815       if (mainw->jackd->playing_file == new_file ||
9816           (IS_VALID_CLIP(mainw->playing_file) && mainw->files[mainw->playing_file]->achans > 0
9817            && mainw->jackd->playing_file != mainw->playing_file)) return FALSE;
9818 
9819       if (mainw->scratch == SCRATCH_JUMP) {
9820         mainw->files[new_file]->aseek_pos =
9821           (off_t)((double)mainw->files[new_file]->frameno / mainw->files[new_file]->fps * mainw->files[new_file]->arate)
9822           * mainw->files[new_file]->achans * mainw->files[new_file]->asampsize / 8;
9823       }
9824 
9825       if (!activate) mainw->jackd->in_use = FALSE;
9826 
9827       alarm_handle = lives_alarm_set(LIVES_DEFAULT_TIMEOUT);
9828       while ((timeout = lives_alarm_check(alarm_handle)) > 0 && jack_get_msgq(mainw->jackd) != NULL) {
9829         // wait for seek
9830         lives_nanosleep(1000);
9831       }
9832       lives_alarm_clear(alarm_handle);
9833       if (timeout == 0) {
9834         mainw->cancelled = handle_audio_timeout();
9835         return FALSE;
9836       }
9837 
9838       if (mainw->jackd->playing_file > 0) {
9839         if (!CLIP_HAS_AUDIO(new_file)) {
9840           jack_get_rec_avals(mainw->jackd);
9841           mainw->rec_avel = 0.;
9842         }
9843         jack_message.command = ASERVER_CMD_FILE_CLOSE;
9844         jack_message.data = NULL;
9845         jack_message.next = NULL;
9846         mainw->jackd->msgq = &jack_message;
9847 
9848         alarm_handle = lives_alarm_set(LIVES_DEFAULT_TIMEOUT);
9849         while ((timeout = lives_alarm_check(alarm_handle)) > 0 && jack_get_msgq(mainw->jackd) != NULL) {
9850           // wait for seek
9851           lives_nanosleep(1000);
9852         }
9853         lives_alarm_clear(alarm_handle);
9854         if (timeout == 0)  {
9855           mainw->cancelled = handle_audio_timeout();
9856           return FALSE;
9857         }
9858       }
9859     }
9860     if (!IS_VALID_CLIP(new_file)) {
9861       mainw->jackd->in_use = FALSE;
9862       return FALSE;
9863     }
9864 
9865     if (CLIP_HAS_AUDIO(new_file)) {
9866       int asigned = !(mainw->files[new_file]->signed_endian & AFORM_UNSIGNED);
9867       int aendian = !(mainw->files[new_file]->signed_endian & AFORM_BIG_ENDIAN);
9868       mainw->jackd->num_input_channels = mainw->files[new_file]->achans;
9869       mainw->jackd->bytes_per_channel = mainw->files[new_file]->asampsize / 8;
9870       if (activate && (prefs->audio_opts & AUDIO_OPTS_FOLLOW_FPS)) {
9871         if (!mainw->files[new_file]->play_paused)
9872           mainw->jackd->sample_in_rate = mainw->files[new_file]->arate * mainw->files[new_file]->pb_fps /
9873                                          mainw->files[new_file]->fps;
9874         else mainw->jackd->sample_in_rate = mainw->files[new_file]->arate * mainw->files[new_file]->freeze_fps /
9875                                               mainw->files[new_file]->fps;
9876       } else mainw->jackd->sample_in_rate = mainw->files[new_file]->arate;
9877       if (mainw->files[new_file]->adirection == LIVES_DIRECTION_REVERSE)
9878         mainw->jackd->sample_in_rate = -abs(mainw->jackd->sample_in_rate);
9879       else
9880         mainw->jackd->sample_in_rate = abs(mainw->jackd->sample_in_rate);
9881       mainw->jackd->usigned = !asigned;
9882       mainw->jackd->seek_end = mainw->files[new_file]->afilesize;
9883 
9884       if ((aendian && (capable->byte_order == LIVES_BIG_ENDIAN)) ||
9885           (!aendian && (capable->byte_order == LIVES_LITTLE_ENDIAN)))
9886         mainw->jackd->reverse_endian = TRUE;
9887       else mainw->jackd->reverse_endian = FALSE;
9888 
9889       if (mainw->ping_pong) mainw->jackd->loop = AUDIO_LOOP_PINGPONG;
9890       else mainw->jackd->loop = AUDIO_LOOP_FORWARD;
9891 
9892       avsync_force();
9893 
9894       // tell jack server to open audio file and start playing it
9895 
9896       jack_message.command = ASERVER_CMD_FILE_OPEN;
9897 
9898       jack_message.data = lives_strdup_printf("%d", new_file);
9899 
9900       jack_message2.command = ASERVER_CMD_FILE_SEEK;
9901       jack_message.next = &jack_message2;
9902       jack_message2.data = lives_strdup_printf("%"PRId64, mainw->files[new_file]->aseek_pos);
9903       if (LIVES_IS_PLAYING && !mainw->preview) jack_message2.tc = lives_get_current_ticks();
9904       jack_message2.next = NULL;
9905 
9906       mainw->jackd->msgq = &jack_message;
9907       mainw->jackd->in_use = TRUE;
9908 
9909       mainw->jackd->is_paused = mainw->files[new_file]->play_paused;
9910       mainw->jackd->is_silent = FALSE;
9911       mainw->rec_aclip = new_file;
9912       mainw->rec_avel = (double)mainw->jackd->sample_in_rate / (double)mainw->files[new_file]->arps;
9913       mainw->rec_aseek = fabs((double)(mainw->files[new_file]->aseek_pos
9914                                        / (mainw->files[new_file]->achans * mainw->files[new_file]->asampsize / 8))
9915                               / (double)mainw->files[new_file]->arps);
9916     } else {
9917       mainw->video_seek_ready = mainw->audio_seek_ready = TRUE;
9918     }
9919     /* event = get_last_frame_event(mainw->event_list); */
9920     /* insert_audio_event_at(event, -1, mainw->rec_aclip, mainw->rec_aseek, mainw->rec_avel); */
9921     /* mainw->rec_aclip = -1; */
9922 #endif
9923   }
9924 
9925   if (prefs->audio_player == AUD_PLAYER_PULSE) {
9926 #ifdef HAVE_PULSE_AUDIO
9927     if (mainw->pulsed) {
9928       if (mainw->pulsed->playing_file == new_file ||
9929           (IS_VALID_CLIP(mainw->playing_file) && mainw->files[mainw->playing_file]->achans > 0
9930            && mainw->pulsed->playing_file != mainw->playing_file)) return FALSE;
9931 
9932       if (mainw->scratch == SCRATCH_JUMP) {
9933         mainw->files[new_file]->aseek_pos =
9934           (off_t)((double)mainw->files[new_file]->frameno / mainw->files[new_file]->fps * mainw->files[new_file]->arate)
9935           * mainw->files[new_file]->achans * mainw->files[new_file]->asampsize / 8;
9936       }
9937 
9938       if (!activate) mainw->pulsed->in_use = FALSE;
9939 
9940       alarm_handle = lives_alarm_set(LIVES_DEFAULT_TIMEOUT);
9941       while ((timeout = lives_alarm_check(alarm_handle)) > 0 && pulse_get_msgq(mainw->pulsed)) {
9942         // wait for seek
9943         lives_nanosleep(1000);
9944       }
9945       lives_alarm_clear(alarm_handle);
9946       if (timeout == 0)  {
9947         mainw->cancelled = handle_audio_timeout();
9948         return FALSE;
9949       }
9950 
9951       if (mainw->pulsed->fd > 0) {
9952         if (!CLIP_HAS_AUDIO(new_file)) {
9953           pulse_get_rec_avals(mainw->pulsed);
9954           mainw->rec_avel = 0.;
9955         }
9956         pulse_message.command = ASERVER_CMD_FILE_CLOSE;
9957         pulse_message.data = NULL;
9958         pulse_message.next = NULL;
9959         mainw->pulsed->msgq = &pulse_message;
9960 
9961         alarm_handle = lives_alarm_set(LIVES_DEFAULT_TIMEOUT);
9962         while ((timeout = lives_alarm_check(alarm_handle)) > 0 && pulse_get_msgq(mainw->pulsed) != NULL) {
9963           // wait for seek
9964           lives_nanosleep(1000);
9965         }
9966         lives_alarm_clear(alarm_handle);
9967         if (timeout == 0)  {
9968           mainw->cancelled = handle_audio_timeout();
9969           return FALSE;
9970         }
9971       }
9972 
9973       if (!IS_VALID_CLIP(new_file)) {
9974         mainw->pulsed->in_use = FALSE;
9975         return FALSE;
9976       }
9977 
9978       mainw->pulsed->in_use = TRUE;
9979 
9980       if (CLIP_HAS_AUDIO(new_file)) {
9981         int asigned = !(mainw->files[new_file]->signed_endian & AFORM_UNSIGNED);
9982         int aendian = !(mainw->files[new_file]->signed_endian & AFORM_BIG_ENDIAN);
9983         mainw->pulsed->in_achans = mainw->files[new_file]->achans;
9984         mainw->pulsed->in_asamps = mainw->files[new_file]->asampsize;
9985         if (activate && (prefs->audio_opts & AUDIO_OPTS_FOLLOW_FPS)) {
9986           if (!mainw->files[new_file]->play_paused)
9987             mainw->pulsed->in_arate = mainw->files[new_file]->arate
9988                                       * mainw->files[new_file]->pb_fps /
9989                                       mainw->files[new_file]->fps;
9990           else mainw->pulsed->in_arate = mainw->files[new_file]->arate
9991                                            * mainw->files[new_file]->freeze_fps /
9992                                            mainw->files[new_file]->fps;
9993         } else mainw->pulsed->in_arate = mainw->files[new_file]->arate;
9994         if (mainw->files[new_file]->adirection == LIVES_DIRECTION_REVERSE)
9995           mainw->pulsed->in_arate = -abs(mainw->pulsed->in_arate);
9996         else
9997           mainw->pulsed->in_arate = abs(mainw->pulsed->in_arate);
9998         mainw->pulsed->usigned = !asigned;
9999         mainw->pulsed->seek_end = mainw->files[new_file]->afilesize;
10000 
10001         if ((aendian && (capable->byte_order == LIVES_BIG_ENDIAN)) ||
10002             (!aendian && (capable->byte_order == LIVES_LITTLE_ENDIAN)))
10003           mainw->pulsed->reverse_endian = TRUE;
10004         else mainw->pulsed->reverse_endian = FALSE;
10005 
10006         if (mainw->ping_pong) mainw->pulsed->loop = AUDIO_LOOP_PINGPONG;
10007         else mainw->pulsed->loop = AUDIO_LOOP_FORWARD;
10008 
10009         avsync_force();
10010 
10011         // tell pulse server to open audio file and start playing it
10012 
10013         pulse_message.command = ASERVER_CMD_FILE_OPEN;
10014         pulse_message.data = lives_strdup_printf("%d", new_file);
10015 
10016         pulse_message2.command = ASERVER_CMD_FILE_SEEK;
10017         if (LIVES_IS_PLAYING && !mainw->preview) pulse_message2.tc = lives_get_current_ticks();
10018         pulse_message.next = &pulse_message2;
10019         pulse_message2.data = lives_strdup_printf("%"PRId64, mainw->files[new_file]->aseek_pos);
10020         pulse_message2.next = NULL;
10021         mainw->pulsed->msgq = &pulse_message;
10022         mainw->pulsed->in_use = TRUE;
10023 
10024         mainw->pulsed->is_paused = mainw->files[new_file]->play_paused;
10025         mainw->rec_aclip = new_file;
10026         mainw->rec_avel = (double)mainw->pulsed->in_arate / (double)mainw->files[new_file]->arps;
10027         mainw->rec_aseek = fabs((double)(mainw->files[new_file]->aseek_pos
10028                                          / (mainw->files[new_file]->achans * mainw->files[new_file]->asampsize / 8))
10029                                 / (double)mainw->files[new_file]->arps);
10030       } else {
10031         mainw->video_seek_ready = mainw->audio_seek_ready = TRUE;
10032       }
10033     }
10034 #endif
10035   }
10036 
10037 #if 0
10038   if (prefs->audio_player == AUD_PLAYER_NONE) {
10039     if (!IS_VALID_CLIP(new_file)) {
10040       mainw->nullaudio_playing_file = -1;
10041       return FALSE;
10042     }
10043     if (mainw->nullaudio->playing_file == new_file) return FALSE;
10044     nullaudio_clip_set(new_file);
10045     if (activate && (prefs->audio_opts & AUDIO_OPTS_FOLLOW_FPS)) {
10046       if (!mainw->files[new_file]->play_paused)
10047         nullaudio_arate_set(mainw->files[new_file]->arate * mainw->files[new_file]->pb_fps /
10048                             mainw->files[new_file]->fps);
10049       else nullaudio_arate_set(mainw->files[new_file]->arate
10050                                  * mainw->files[new_file]->freeze_fps /
10051                                  mainw->files[new_file]->fps);
10052     } else nullaudio_arate_set(mainw->files[new_file]->arate);
10053     nullaudio_seek_set(mainw->files[new_file]->aseek_pos);
10054     if (CLIP_HAS_AUDIO(new_file)) {
10055       nullaudio_get_rec_avals();
10056     } else {
10057       nullaudio_get_rec_avals();
10058       mainw->rec_avel = 0.;
10059     }
10060   }
10061 #endif
10062   return TRUE;
10063 }
10064 
10065 
10066 void do_quick_switch(int new_file) {
10067   // handle clip switching during playback
10068   // calling this function directly is now deprecated in favour of switch_clip()
10069   boolean osc_block;
10070   int old_file = mainw->current_file;// area = 0;
10071 
10072   if (mainw->current_file < 1 || !mainw->files[new_file]) return;
10073 
10074   if (mainw->multitrack
10075       || (mainw->record && !mainw->record_paused && !(prefs->rec_opts & REC_CLIPS)) ||
10076       mainw->foreign || (mainw->preview && !mainw->is_rendering)) return;
10077 
10078   if (!LIVES_IS_PLAYING) {
10079     switch_to_file(mainw->current_file, new_file);
10080     return;
10081   }
10082 
10083   if (mainw->noswitch) {
10084     mainw->new_clip = new_file;
10085     return;
10086   }
10087 
10088   mainw->blend_palette = WEED_PALETTE_END;
10089 
10090   if (CURRENT_CLIP_IS_VALID && new_file != mainw->current_file && mainw->current_file != mainw->blend_file
10091       && !mainw->is_rendering) {
10092     if (cfile->clip_type == CLIP_TYPE_GENERATOR && cfile->ext_src) {
10093       if (new_file != mainw->blend_file) {
10094         // switched from generator to another clip, end the generator
10095         weed_plant_t *inst = (weed_plant_t *)cfile->ext_src;
10096         mainw->gen_started_play = FALSE;
10097         mainw->whentostop = NEVER_STOP;
10098         weed_generator_end(inst);
10099       } else {
10100         rte_swap_fg_bg();
10101       }
10102     }
10103     if (new_file == mainw->blend_file && mainw->files[mainw->blend_file]->clip_type == CLIP_TYPE_GENERATOR
10104         && mainw->files[mainw->blend_file]->ext_src) {
10105       rte_swap_fg_bg();
10106     }
10107   }
10108 
10109   osc_block = mainw->osc_block;
10110   mainw->osc_block = TRUE;
10111 
10112   if (mainw->loop_locked) {
10113     unlock_loop_lock();
10114   }
10115 
10116   mainw->whentostop = NEVER_STOP;
10117 
10118   // TODO - can these be combined ?
10119   mainw->switch_during_pb = TRUE;
10120   mainw->clip_switched = TRUE;
10121 
10122   if (CURRENT_CLIP_IS_NORMAL) cfile->last_play_sequence = mainw->play_sequence;
10123 
10124   mainw->current_file = new_file;
10125 
10126   mainw->drawsrc = mainw->current_file;
10127   mainw->laudio_drawable = cfile->laudio_drawable;
10128   mainw->raudio_drawable = cfile->raudio_drawable;
10129 
10130   if (!mainw->fs && !mainw->faded) {
10131     redraw_timeline(mainw->current_file);
10132     show_playbar_labels(mainw->current_file);
10133   }
10134 
10135   lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), mainw->files[new_file]->pb_fps);
10136   changed_fps_during_pb(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), LIVES_INT_TO_POINTER(1));
10137 
10138   // switch audio clip
10139   if (is_realtime_aplayer(prefs->audio_player) && (prefs->audio_opts & AUDIO_OPTS_FOLLOW_CLIPS)
10140       && !mainw->is_rendering && (mainw->preview || !(mainw->agen_key != 0 || mainw->agen_needs_reinit
10141                                   || prefs->audio_src == AUDIO_SRC_EXT))) {
10142     switch_audio_clip(new_file, TRUE);
10143   }
10144 
10145   mainw->deltaticks = 0;
10146 
10147   set_main_title(cfile->name, 0);
10148 
10149   if (mainw->ce_thumbs && mainw->active_sa_clips == SCREEN_AREA_FOREGROUND) ce_thumbs_highlight_current_clip();
10150 
10151   if (CURRENT_CLIP_IS_NORMAL) {
10152     char *tmp;
10153     tmp = lives_build_filename(prefs->workdir, cfile->handle, LIVES_STATUS_FILE_NAME, NULL);
10154     lives_snprintf(cfile->info_file, PATH_MAX, "%s", tmp);
10155     lives_free(tmp);
10156   }
10157 
10158   if (!CURRENT_CLIP_IS_NORMAL || (mainw->event_list && !mainw->record))
10159     mainw->play_end = INT_MAX;
10160 
10161   // act like we are not playing a selection (but we will try to keep to
10162   // selection bounds)
10163   mainw->playing_sel = FALSE;
10164 
10165   if (!cfile->frameno && cfile->frames) cfile->frameno = calc_frame_from_time(mainw->current_file, cfile->pointer_time);
10166   cfile->last_frameno = cfile->frameno;
10167 
10168   mainw->playing_file = new_file;
10169 
10170   cfile->next_event = NULL;
10171 
10172 #if GTK_CHECK_VERSION(3, 0, 0)
10173   if (LIVES_IS_PLAYING && !mainw->play_window && (!IS_VALID_CLIP(old_file)
10174       || !CURRENT_CLIP_IS_VALID || cfile->hsize != mainw->files[old_file]->hsize
10175       || cfile->vsize != mainw->files[old_file]->vsize)) {
10176     clear_widget_bg(mainw->play_image, mainw->play_surface);
10177   }
10178 #endif
10179 
10180   if (CURRENT_CLIP_HAS_VIDEO) {
10181     if (!mainw->fs && !mainw->faded) {
10182       lives_signal_handler_block(mainw->spinbutton_end, mainw->spin_end_func);
10183       lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_end), 1, cfile->frames);
10184       lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->end);
10185       lives_signal_handler_unblock(mainw->spinbutton_end, mainw->spin_end_func);
10186 
10187       lives_signal_handler_block(mainw->spinbutton_start, mainw->spin_start_func);
10188       lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_start), 1, cfile->frames);
10189       lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->start);
10190       lives_signal_handler_unblock(mainw->spinbutton_start, mainw->spin_start_func);
10191 
10192       if (!mainw->play_window && mainw->double_size) {
10193         //frame_size_update();
10194         resize(2.);
10195       } else resize(1);
10196     }
10197   } else resize(1);
10198 
10199   if (!mainw->fs && !mainw->faded) {
10200     showclipimgs();
10201   }
10202 
10203   if (new_file == mainw->blend_file) {
10204     check_layer_ready(mainw->blend_layer);
10205     mainw->blend_file = old_file;
10206   }
10207 
10208   // force loading of a frame from the new clip
10209   mainw->force_show = TRUE;
10210 
10211   mainw->fps_mini_measure = 1.;
10212   mainw->fps_mini_ticks = mainw->currticks;
10213 
10214   if (mainw->play_window && prefs->show_playwin) {
10215     lives_window_present(LIVES_WINDOW(mainw->play_window));
10216     lives_xwindow_raise(lives_widget_get_xwindow(mainw->play_window));
10217   }
10218 
10219   //mainw->switch_during_pb = FALSE;
10220   mainw->osc_block = osc_block;
10221   lives_ruler_set_upper(LIVES_RULER(mainw->hruler), CURRENT_CLIP_TOTAL_TIME);
10222 
10223   if (!mainw->fs && !mainw->faded) {
10224     redraw_timeline(mainw->current_file);
10225     set_sel_label(mainw->sel_label);
10226   }
10227 }
10228 
10229 
10230 void resize(double scale) {
10231   // resize the frame widgets
10232   // set scale < 0. to _force_ the playback frame to expand (for external capture)
10233   LiVESXWindow *xwin;
10234   double oscale = scale;
10235 
10236   int xsize, vspace;
10237   int bx, by;
10238 
10239   // height of the separator imeage
10240 
10241   // maximum values
10242   int hsize, vsize;
10243   int w, h;
10244   int scr_width = GUI_SCREEN_WIDTH;
10245   int scr_height = GUI_SCREEN_HEIGHT;
10246 
10247   if (!prefs->show_gui || mainw->multitrack) return;
10248   vspace = get_vspace();
10249 
10250   get_border_size(LIVES_MAIN_WINDOW_WIDGET, &bx, &by);
10251   bx *= 2;
10252 
10253   if (prefs->open_maximised && by > MENU_HIDE_LIM)
10254     lives_window_set_hide_titlebar_when_maximized(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), TRUE);
10255 
10256   w = lives_widget_get_allocation_width(LIVES_MAIN_WINDOW_WIDGET);
10257   h = lives_widget_get_allocation_height(LIVES_MAIN_WINDOW_WIDGET);
10258 
10259   // resize the main window so it fits the gui monitor
10260   if (prefs->open_maximised)
10261     lives_window_maximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
10262   else if (w > scr_width - bx || h > scr_height - by) {
10263     w = scr_width - bx;
10264     h = scr_height - by - mainw->mbar_res;
10265     lives_window_unmaximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
10266     lives_window_resize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), w, h);
10267   }
10268 
10269   //if (mainw->play_window) return;
10270 
10271   hsize = (scr_width - (H_RESIZE_ADJUST * 3 + bx)) / 3;
10272   vsize = scr_height - (CE_TIMELINE_VSPACE * 1.01 / sqrt(widget_opts.scale) + vspace + by
10273                         + (prefs->show_msg_area ? mainw->mbar_res : 0)
10274                         + widget_opts.border_width * 2);
10275 
10276   if (scale < 0.) {
10277     // foreign capture
10278     scale = -scale;
10279     hsize = (scr_width - H_RESIZE_ADJUST - bx) / scale;
10280     vsize = (scr_height - V_RESIZE_ADJUST - by) / scale;
10281   }
10282 
10283   mainw->ce_frame_width = hsize;
10284   mainw->ce_frame_height = vsize;
10285 
10286   if (oscale == 2.) {
10287     if (hsize * 2 > scr_width - SCR_WIDTH_SAFETY) {
10288       scale = 1.;
10289     }
10290   }
10291 
10292   if (oscale > 0.) {
10293     if (scale > 1.) {
10294       // this is the size for the start and end frames
10295       // they shrink when scale is 2.0
10296       mainw->ce_frame_width = hsize / scale;
10297       mainw->ce_frame_height = vsize / scale + V_RESIZE_ADJUST;
10298 
10299       lives_widget_set_margin_left(mainw->playframe, widget_opts.packing_width);
10300       lives_widget_set_margin_right(mainw->playframe, widget_opts.packing_width);
10301     }
10302 
10303     if (CURRENT_CLIP_IS_VALID) {
10304       if (cfile->clip_type == CLIP_TYPE_YUV4MPEG || cfile->clip_type == CLIP_TYPE_VIDEODEV) {
10305         if (!mainw->camframe) {
10306           LiVESError *error = NULL;
10307           char *fname = lives_strdup_printf("%s.%s", THEME_FRAME_IMG_LITERAL, LIVES_FILE_EXT_JPG);
10308           char *tmp = lives_build_filename(prefs->prefix_dir, THEME_DIR, LIVES_THEME_CAMERA, fname, NULL);
10309           mainw->camframe = lives_pixbuf_new_from_file(tmp, &error);
10310           if (mainw->camframe) lives_pixbuf_saturate_and_pixelate(mainw->camframe, mainw->camframe, 0.0, FALSE);
10311           lives_free(tmp); lives_free(fname);
10312         }
10313       }
10314     }
10315 
10316     // THE SIZES OF THE FRAME CONTAINERS
10317     lives_widget_set_size_request(mainw->frame1, mainw->ce_frame_width, mainw->ce_frame_height);
10318     lives_widget_set_size_request(mainw->eventbox3, mainw->ce_frame_width, mainw->ce_frame_height);
10319     lives_widget_set_size_request(mainw->frame2, mainw->ce_frame_width, mainw->ce_frame_height);
10320     lives_widget_set_size_request(mainw->eventbox4, mainw->ce_frame_width, mainw->ce_frame_height);
10321 
10322     lives_widget_set_size_request(mainw->start_image, mainw->ce_frame_width, mainw->ce_frame_height);
10323     lives_widget_set_size_request(mainw->end_image, mainw->ce_frame_width, mainw->ce_frame_height);
10324 
10325     // use unscaled size in dblsize
10326     if (scale > 1.) {
10327       hsize *= scale;
10328       vsize *= scale;
10329     }
10330     lives_widget_set_size_request(mainw->playframe, hsize, vsize);
10331     lives_widget_set_size_request(mainw->pl_eventbox, hsize, vsize);
10332     lives_widget_set_size_request(mainw->playarea, hsize, vsize);
10333 
10334     // IMPORTANT (or the entire image will not be shown)
10335     lives_widget_set_size_request(mainw->play_image, hsize, vsize);
10336     xwin = lives_widget_get_xwindow(mainw->play_image);
10337     if (LIVES_IS_XWINDOW(xwin)) {
10338       if (mainw->play_surface) lives_painter_surface_destroy(mainw->play_surface);
10339       mainw->play_surface =
10340         lives_xwindow_create_similar_surface(xwin, LIVES_PAINTER_CONTENT_COLOR,
10341                                              hsize, vsize);
10342       clear_widget_bg(mainw->play_image, mainw->play_surface);
10343     }
10344   } else {
10345     // capture window size
10346     xsize = (scr_width - hsize * -oscale - H_RESIZE_ADJUST) / 2;
10347     if (xsize > 0) {
10348       lives_widget_set_size_request(mainw->frame1, xsize / scale, vsize + V_RESIZE_ADJUST);
10349       lives_widget_set_size_request(mainw->eventbox3, xsize / scale, vsize + V_RESIZE_ADJUST);
10350       lives_widget_set_size_request(mainw->frame2, xsize / scale, vsize + V_RESIZE_ADJUST);
10351       lives_widget_set_size_request(mainw->eventbox4, xsize / scale, vsize + V_RESIZE_ADJUST);
10352       mainw->ce_frame_width = xsize / scale;
10353       mainw->ce_frame_height = vsize + V_RESIZE_ADJUST;
10354     } else {
10355       lives_widget_hide(mainw->frame1);
10356       lives_widget_hide(mainw->frame2);
10357       lives_widget_hide(mainw->eventbox3);
10358       lives_widget_hide(mainw->eventbox4);
10359     }
10360   }
10361 
10362   if (!mainw->foreign && mainw->current_file == -1) {
10363     lives_table_set_column_homogeneous(LIVES_TABLE(mainw->pf_grid), TRUE);
10364     load_start_image(0);
10365     load_end_image(0);
10366   }
10367 
10368   update_sel_menu();
10369 
10370   if (scale != oscale) {
10371     lives_widget_context_update();
10372     if (prefs->open_maximised)
10373       lives_window_maximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
10374     else if (w > scr_width - bx || h > scr_height - by) {
10375       w = scr_width - bx;
10376       h = scr_height - by;
10377       lives_window_unmaximize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET));
10378       lives_window_resize(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET), w, h);
10379     }
10380   }
10381 }
10382