1 // startup.c
2 // LiVES
3 // (c) G. Finch 2010 - 2020 <salsaman+lives@gmail.com>
4 // released under the GNU GPL 3 or later
5 // see file ../COPYING for licensing details
6 
7 // functions for first time startup
8 
9 #include "main.h"
10 #include "interface.h"
11 #include "rte_window.h"
12 #include "startup.h"
13 
14 static boolean allpassed;
15 
16 LiVESWidget *assist;
17 
18 static uint64_t oldver = 0;
19 
migrate_config(const char * old_vhash,const char * newconfigfile)20 boolean migrate_config(const char *old_vhash, const char *newconfigfile) {
21   // on a fresh install, we check if there is an older config file, and if so, migrate it
22   oldver = atoll(old_vhash);
23   /// $HOME/.lives.* files -> $HOME/.local/config/lives/settings.*
24   /// then if $HOME/.lives-dir exists, move contents to $HOME/.local/share/lives
25   if (oldver > 0 && oldver < 3200000) {
26     char *ocfdir = lives_build_path(capable->home_dir, LIVES_DEF_CONFIG_DATADIR_OLD, NULL);
27     lives_cp(prefs->configfile, newconfigfile);
28     if (lives_file_test(ocfdir, LIVES_FILE_TEST_IS_DIR)) {
29       char *fname, *fname2;
30       lives_cp_recursive(ocfdir, prefs->config_datadir, FALSE);
31       lives_free(ocfdir);
32       fname = lives_build_filename(prefs->config_datadir, DEF_KEYMAP_FILE_OLD, NULL);
33       if (lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) {
34         lives_rm(fname);
35       }
36       lives_free(fname);
37       fname = lives_build_filename(prefs->config_datadir, DEF_KEYMAP_FILE2_OLD, NULL); // perkey defs
38       if (lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) {
39         fname2 = lives_build_filename(prefs->config_datadir, DEF_KEYMAP_FILE2, NULL); // perkey defs
40         lives_mv(fname, fname2);
41         lives_free(fname2);
42       }
43       lives_free(fname);
44       fname = lives_build_filename(prefs->config_datadir, DEF_KEYMAP_FILE3_OLD, NULL); // data connections
45       if (lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) {
46         fname2 = lives_build_filename(prefs->config_datadir, DEF_KEYMAP_FILE3, NULL); // data connections
47         lives_mv(fname, fname2);
48         lives_free(fname2);
49       }
50       lives_free(fname);
51     }
52     return TRUE;
53   }
54   return FALSE;
55 }
56 
57 
cleanup_old_config(void)58 void cleanup_old_config(void) {
59   if (oldver > 0 && oldver < 3200000) {
60     char *oldconfig = lives_build_filename(capable->home_dir, LIVES_DEF_CONFIG_FILE_OLD, NULL);
61     char *oldconfigdir = lives_build_path(capable->home_dir, LIVES_DEF_CONFIG_DATADIR_OLD, NULL);
62     if (do_yesno_dialogf(_("The locations of LiVES configuration files have changed.\n"
63                            "%s is now %s\nand %s is now %s\nThe files have been copied to the new locations.\n"
64                            "\nWould you like me to remove the old files ?\n"),
65                          oldconfig, prefs->configfile, oldconfigdir, prefs->config_datadir)) {
66       lives_rm(oldconfig);
67       lives_free(oldconfig);
68       oldconfig = lives_build_filename(capable->home_dir, LIVES_DEF_CONFIG_FILE_OLD ".", NULL);
69       lives_rmglob(oldconfig);
70       lives_free(oldconfig);
71       oldconfig = lives_build_filename(capable->home_dir, LIVES_DEF_CONFIG_FILE_OLD "~", NULL);
72       lives_rm(oldconfig);
73       if (lives_file_test(oldconfigdir, LIVES_FILE_TEST_IS_DIR)) {
74         lives_rmdir(oldconfigdir, TRUE);
75       }
76     }
77     lives_free(oldconfig);
78     lives_free(oldconfigdir);
79   }
80 }
81 
82 
build_init_config(const char * config_datadir,boolean prompt)83 boolean build_init_config(const char *config_datadir, boolean prompt) {
84   /// startup phase 3
85   boolean create = TRUE;
86   if (prompt) {
87     if (!do_yesno_dialogf(_("Should I create default items in\n%s ?"), config_datadir)) create = FALSE;
88   }
89   if (create) {
90     LiVESResponseType retval;
91     char *keymap_file, *stock_icons_dir, *devmapdir;
92 
93     if (!lives_file_test(config_datadir, LIVES_FILE_TEST_IS_DIR)) {
94       if (mainw && mainw->splash_window) lives_widget_hide(mainw->splash_window);
95       while (1) {
96         if (!lives_make_writeable_dir(config_datadir)) {
97           do_dir_perm_error(config_datadir, FALSE);
98           continue;
99         }
100         break;
101 	  // *INDENT-OFF*
102       }}
103     // *INDENT-ON*
104 
105     /// default keymap
106     keymap_file = lives_build_filename(config_datadir, DEF_KEYMAP_FILE2, NULL);
107     if (!lives_file_test(keymap_file, LIVES_FILE_TEST_EXISTS)) {
108       char *tmp, *keymap_template = lives_build_filename(prefs->prefix_dir, DATA_DIR, DEF_KEYMAP_FILE2, NULL);
109       if (mainw && mainw->splash_window) lives_widget_hide(mainw->splash_window);
110       do {
111         retval = LIVES_RESPONSE_NONE;
112         if (!lives_file_test(keymap_template, LIVES_FILE_TEST_EXISTS)) {
113           retval = do_file_notfound_dialog(_("LiVES was unable to find the default keymap file"),
114                                            keymap_template);
115           if (retval == LIVES_RESPONSE_BROWSE) {
116             char *dirx = lives_build_path(prefs->prefix_dir, DATA_DIR, NULL);
117             char *xkeymap_template = choose_file(dirx, DEF_KEYMAP_FILE2, NULL,
118                                                  LIVES_FILE_CHOOSER_ACTION_SELECT_FILE, NULL, NULL);
119             if (xkeymap_template && *xkeymap_template) {
120               lives_free(keymap_template);
121               keymap_template = xkeymap_template;
122             }
123             continue;
124           }
125         }
126       } while (retval == LIVES_RESPONSE_RETRY);
127 
128       if (retval != LIVES_RESPONSE_CANCEL) {
129         do {
130           retval = LIVES_RESPONSE_NONE;
131           lives_cp(keymap_template, keymap_file);
132           if (!lives_file_test(keymap_file, LIVES_FILE_TEST_EXISTS)) {
133             // give up
134             d_print((tmp = lives_strdup_printf
135                            (_("Unable to create default keymap file: %s\nPlease make sure the directory\n%s\nis writable.\n"),
136                             keymap_file, config_datadir)));
137 
138             retval = do_abort_cancel_retry_dialog(tmp);
139           }
140         } while (retval == LIVES_RESPONSE_RETRY);
141         lives_free(keymap_template);
142       }
143     }
144     lives_free(keymap_file);
145 
146     /// default keymap
147     keymap_file = lives_build_filename(config_datadir, DEF_KEYMAP_FILE3, NULL);
148     if (!lives_file_test(keymap_file, LIVES_FILE_TEST_EXISTS)) {
149       char *keymap_template = lives_build_filename(prefs->prefix_dir, DATA_DIR, DEF_KEYMAP_FILE3, NULL);
150       retval = LIVES_RESPONSE_NONE;
151       if (lives_file_test(keymap_template, LIVES_FILE_TEST_EXISTS)) {
152         lives_cp(keymap_template, keymap_file);
153       }
154     }
155     lives_free(keymap_file);
156 
157     devmapdir = lives_build_path(config_datadir, LIVES_DEVICEMAP_DIR, NULL);
158     if (1 || !lives_file_test(devmapdir, LIVES_FILE_TEST_IS_DIR)) {
159 #ifdef ENABLE_OSC
160       char *sys_devmap_dir = lives_build_path(prefs->prefix_dir, DATA_DIR, LIVES_DEVICEMAP_DIR, NULL);
161       if (mainw && mainw->splash_window) lives_widget_hide(mainw->splash_window);
162       do {
163         retval = LIVES_RESPONSE_NONE;
164         if (!lives_file_test(sys_devmap_dir, LIVES_FILE_TEST_IS_DIR)) {
165           retval = do_dir_notfound_dialog(_("LiVES was unable to find its default device maps in\n"),
166                                           sys_devmap_dir);
167           if (retval == LIVES_RESPONSE_BROWSE) {
168             char *xsys_devmap_dir = choose_file(sys_devmap_dir, NULL, NULL,
169                                                 LIVES_FILE_CHOOSER_ACTION_SELECT_FOLDER, NULL, NULL);
170             if (xsys_devmap_dir && *xsys_devmap_dir) {
171               lives_free(sys_devmap_dir);
172               sys_devmap_dir = xsys_devmap_dir;
173             }
174             continue;
175           }
176         }
177       } while (retval == LIVES_RESPONSE_RETRY);
178 
179       if (retval != LIVES_RESPONSE_CANCEL) {
180         do {
181           retval = LIVES_RESPONSE_NONE;
182           if (!lives_make_writeable_dir(devmapdir))
183             retval = do_dir_perm_error(devmapdir, TRUE);
184         } while (retval == LIVES_RESPONSE_RETRY);
185 
186         if (retval != LIVES_RESPONSE_CANCEL) {
187           lives_cp_recursive(sys_devmap_dir, config_datadir, TRUE);
188         }
189       }
190       lives_free(sys_devmap_dir);
191 #endif
192     }
193     lives_free(devmapdir);
194 
195 #ifdef GUI_GTK
196     /// stock_icons
197     stock_icons_dir = lives_build_path(config_datadir, STOCK_ICONS_DIR, NULL);
198     if (!lives_file_test(stock_icons_dir, LIVES_FILE_TEST_IS_DIR)) {
199       char *sys_stock_icons_dir = lives_build_path(prefs->prefix_dir, DATA_DIR, STOCK_ICONS_DIR, NULL);
200       if (mainw && mainw->splash_window) {
201         lives_widget_hide(mainw->splash_window);
202         lives_widget_context_update();
203       }
204       do {
205         retval = LIVES_RESPONSE_NONE;
206         if (!lives_file_test(sys_stock_icons_dir, LIVES_FILE_TEST_IS_DIR)) {
207           retval = do_dir_notfound_dialog(_("LiVES was unable to find its default icons in\n"),
208                                           sys_stock_icons_dir);
209           if (retval == LIVES_RESPONSE_BROWSE) {
210             char *xsys_stock_icons_dir = choose_file(sys_stock_icons_dir, NULL, NULL,
211                                          LIVES_FILE_CHOOSER_ACTION_SELECT_FOLDER, NULL, NULL);
212             if (xsys_stock_icons_dir && *xsys_stock_icons_dir) {
213               lives_free(sys_stock_icons_dir);
214               sys_stock_icons_dir = xsys_stock_icons_dir;
215             }
216             continue;
217           }
218         }
219       } while (retval == LIVES_RESPONSE_RETRY);
220 
221       if (retval != LIVES_RESPONSE_CANCEL) {
222         do {
223           retval = LIVES_RESPONSE_NONE;
224           if (!lives_make_writeable_dir(stock_icons_dir))
225             retval = do_dir_perm_error(stock_icons_dir, TRUE);
226         } while (retval == LIVES_RESPONSE_RETRY);
227 
228         if (retval != LIVES_RESPONSE_CANCEL) {
229           lives_cp_recursive(sys_stock_icons_dir, config_datadir, TRUE);
230         }
231       }
232       lives_free(sys_stock_icons_dir);
233     }
234     lives_free(stock_icons_dir);
235 #endif
236     if (mainw && mainw->splash_window) lives_widget_show(mainw->splash_window);
237 
238     return TRUE;
239   }
240   return FALSE;
241 }
242 
243 
prompt_existing_dir(const char * dirname,uint64_t freespace,boolean wrtable)244 static LiVESResponseType prompt_existing_dir(const char *dirname, uint64_t freespace, boolean wrtable) {
245   // can return LIVES_RESPONSE_OK, LIVES_RESPONSE_CANCEL or LIVES_RESPONSE_RETRY
246   char *msg;
247   if (wrtable) {
248     if (dirs_equal(dirname, capable->home_dir)) {
249       if (!do_yesno_dialog(
250             _("You have chosen to use your home directory as the LiVES working directory.\n"
251               "This is NOT recommended as it will possibly result in the loss of unrelated files.\n"
252               "Click Yes if you REALLY want to continue, or No to create or select another directory.\n")))
253         return LIVES_RESPONSE_CANCEL;
254     } else {
255       msg = lives_format_storage_space_string(freespace);
256       boolean res = do_yesno_dialogf(
257                       _("A directory named\n%s\nalready exists. Do you wish to use this directory ?\n\n(Free space = %s)\n"),
258                       dirname, msg);
259       lives_free(msg);
260       if (!res) return LIVES_RESPONSE_CANCEL;
261       return LIVES_RESPONSE_OK;
262     }
263   } else {
264     msg = lives_strdup_printf(_("A directory named\n%s\nalready exists.\nHowever, LiVES could not write to this directory "
265                                 "or read its free space.\nClick Abort to exit from LiVES, or Retry to select another "
266                                 "location.\n"), dirname);
267 
268     do_abort_retry_dialog(msg);
269     lives_free(msg);
270     return LIVES_RESPONSE_RETRY;
271   }
272   return LIVES_RESPONSE_OK;
273 }
274 
275 
prompt_new_dir(char * dirname,uint64_t freespace,boolean wrtable)276 static boolean prompt_new_dir(char *dirname, uint64_t freespace, boolean wrtable) {
277   boolean res;
278   if (wrtable) {
279     char *fspstr = lives_format_storage_space_string(freespace);
280     res = do_warning_dialogf(_("\nCreate the directory\n%s\n?\n\n(Free space = %s)"), dirname, fspstr);
281     lives_free(fspstr);
282   } else {
283     res = do_error_dialogf(_("\nLiVES could not write to the directory\n%s\n"
284                              "Please try again and choose a different location.\n"),
285                            dirname);
286   }
287   return res;
288 }
289 
290 
filename_toolong_error(const char * fname,const char * ftype,size_t max,boolean can_retry)291 void filename_toolong_error(const char *fname, const char *ftype, size_t max, boolean can_retry) {
292   char *rstr, *msg;
293   if (can_retry) rstr = _("\nPlease click Retry to select an alternative directory, or Abort to exit immediately"
294                             "from LiVES\n");
295   else rstr = lives_strdup("");
296 
297   msg = lives_strdup_printf(_("The name of the %s provided\n(%s)\nis too long (maximum is %d characters)\n%s"),
298                             ftype, fname, max, rstr);
299   if (can_retry) do_abort_retry_dialog(msg);
300   else startup_message_fatal(msg);
301   lives_free(msg); lives_free(rstr);
302 }
303 
dir_toolong_error(const char * dirname,const char * dirtype,size_t max,boolean can_retry)304 void dir_toolong_error(const char *dirname, const char *dirtype, size_t max, boolean can_retry) {
305   char *rstr, *msg;
306   if (can_retry) rstr = _("\nPlease click Retry to select an alternative directory, or Abort to exit immediately"
307                             "from LiVES\n");
308   else rstr = lives_strdup("");
309   msg = lives_strdup_printf(_("The name of the %s provided\n(%s)\nis too long (maximum is %d characters)\n%s"),
310                             dirtype, dirname, max, rstr);
311   if (can_retry) do_abort_retry_dialog(msg);
312   else startup_message_fatal(msg);
313   lives_free(msg); lives_free(rstr);
314 }
315 
316 
close_file(int current_file,boolean tshoot)317 void close_file(int current_file, boolean tshoot) {
318   if (tshoot) close_current_file(current_file);
319   else {
320 #ifdef IS_MINGW
321     // kill any active processes: for other OSes the backend does this
322     lives_kill_subprocesses(cfile->handle, TRUE);
323 #endif
324     close_temp_handle(current_file);
325   }
326 }
327 
328 
check_workdir_valid(char ** pdirname,LiVESDialog * dialog,boolean fullcheck)329 LiVESResponseType check_workdir_valid(char **pdirname, LiVESDialog * dialog, boolean fullcheck) {
330   // returns LIVES_RESPONSE_RETRY or LIVES_RESPONSE_OK
331   char cdir[PATH_MAX];
332   uint64_t freesp;
333   size_t chklen = strlen(LIVES_DEF_WORK_NAME) + strlen(LIVES_DIR_SEP) * 2;
334   char *tmp;
335 
336   if (!pdirname || !*pdirname) return LIVES_RESPONSE_RETRY;
337 
338   if (lives_strlen(*pdirname) > (PATH_MAX - MAX_SET_NAME_LEN * 2)) {
339     do_error_dialog(_("Directory name is too long !"));
340     return LIVES_RESPONSE_RETRY;
341   }
342 
343   // append a dirsep to the end if there isnt one
344   lives_snprintf(cdir, PATH_MAX, "%s", *pdirname);
345   ensure_isdir(cdir);
346 
347   *pdirname = lives_strdup(cdir);
348 
349   if (strlen(*pdirname) > (PATH_MAX - MAX_SET_NAME_LEN * 2)) {
350     do_error_dialog(_("Directory name is too long !"));
351     return LIVES_RESPONSE_RETRY;
352   }
353 
354   if (fullcheck) {
355     // if it's an existing dir, append "livesprojects" to the end unless it is already
356     if (lives_file_test(*pdirname, LIVES_FILE_TEST_EXISTS) &&
357         (strlen(*pdirname) < chklen || strncmp(*pdirname + strlen(*pdirname) - chklen,
358             LIVES_DIR_SEP LIVES_DEF_WORK_NAME LIVES_DIR_SEP, chklen))) {
359       tmp = lives_build_path(*pdirname, LIVES_DEF_WORK_NAME, NULL);
360       lives_free(*pdirname);
361       *pdirname = tmp;
362     }
363 
364     if (lives_strlen(*pdirname) > (PATH_MAX - MAX_SET_NAME_LEN * 2)) {
365       do_error_dialog(_("Directory name is too long !"));
366       return LIVES_RESPONSE_RETRY;
367     }
368   }
369 
370   if (!check_dir_access(*pdirname, FALSE)) {
371     do_dir_perm_error(*pdirname, FALSE);
372     return LIVES_RESPONSE_RETRY;
373   }
374 
375   if (fullcheck) {
376     if (lives_file_test(*pdirname, LIVES_FILE_TEST_IS_DIR)) {
377       if (is_writeable_dir(*pdirname)) {
378         freesp = get_ds_free(*pdirname);
379         widget_opts.transient = LIVES_WINDOW(dialog);
380         if (!prompt_existing_dir(*pdirname, freesp, TRUE)) {
381           widget_opts.transient = NULL;
382           return LIVES_RESPONSE_RETRY;
383         }
384         widget_opts.transient = NULL;
385       } else {
386         if (!prompt_existing_dir(*pdirname, 0, FALSE)) {
387           return LIVES_RESPONSE_RETRY;
388         }
389       }
390     } else {
391       if (is_writeable_dir(*pdirname)) {
392         freesp = get_ds_free(*pdirname);
393         if (!prompt_new_dir(*pdirname, freesp, TRUE)) {
394           lives_rmdir(*pdirname, FALSE);
395           return LIVES_RESPONSE_RETRY;
396         }
397       } else {
398         if (!prompt_new_dir(*pdirname, 0, FALSE)) {
399           lives_rmdir(*pdirname, FALSE);
400           return LIVES_RESPONSE_RETRY;
401 	  // *INDENT-OFF*
402         }}}}
403   // *INDENT-ON*
404 
405   if (!lives_make_writeable_dir(*pdirname)) {
406     return do_dir_perm_error(*pdirname, FALSE);
407   }
408 
409   return LIVES_RESPONSE_OK;
410 }
411 
412 
do_workdir_query(void)413 boolean do_workdir_query(void) {
414   LiVESWidget *dirbutton;
415   LiVESResponseType response;
416   char *dirname = NULL, *mp;
417   _entryw *wizard = create_rename_dialog(6);
418 
419   /// override FILESEL_TYPE_KEY, in case it was set to WORKDIR; we will do our own checking here
420   dirbutton = lives_label_get_mnemonic_widget(LIVES_LABEL(widget_opts.last_label));
421   lives_widget_object_set_data(LIVES_WIDGET_OBJECT(dirbutton), FILESEL_TYPE_KEY,
422                                LIVES_INT_TO_POINTER(LIVES_DIR_SELECTION_CREATE_FOLDER));
423 
424   if (mainw->splash_window) {
425     char *wid;
426     lives_widget_hide(mainw->splash_window);
427     lives_widget_show_all(wizard->dialog);
428     lives_widget_show_now(wizard->dialog);
429     gtk_window_set_urgency_hint(LIVES_WINDOW(wizard->dialog), TRUE); // dont know if this actually does anything...
430     wid = lives_strdup_printf("0x%08lx", (uint64_t)LIVES_XWINDOW_XID(lives_widget_get_xwindow(wizard->dialog)));
431     if (!wid || !activate_x11_window(wid)) lives_window_set_keep_above(LIVES_WINDOW(wizard->dialog), TRUE);
432   }
433 
434   do {
435     lives_freep((void **)&dirname);
436     response = lives_dialog_run(LIVES_DIALOG(wizard->dialog));
437     if (response == LIVES_RESPONSE_CANCEL) return FALSE;
438 
439     // TODO: should we convert to locale encoding ??
440     dirname = lives_strdup(lives_entry_get_text(LIVES_ENTRY(wizard->entry)));
441   } while (lives_strcmp(dirname, prefs->workdir) &&
442            check_workdir_valid(&dirname, LIVES_DIALOG(wizard->dialog), TRUE) == LIVES_RESPONSE_RETRY);
443 
444   mp = get_mountpoint_for(dirname);
445   if (lives_strcmp(mp, capable->mountpoint) || !strcmp(mp, "??????")) {
446     capable->ds_free = capable->ds_used = capable->ds_tot = -1;
447     mainw->dsu_valid = FALSE;
448     mainw->ds_status = LIVES_STORAGE_STATUS_UNKNOWN;
449     if (capable->mountpoint) lives_free(capable->mountpoint);
450     capable->mountpoint = mp;
451   }
452 
453   lives_widget_destroy(wizard->dialog);
454   lives_freep((void **)&wizard);
455 
456   if (mainw->splash_window) lives_widget_show(mainw->splash_window);
457 
458   if (mainw->is_ready) {
459     lives_snprintf(future_prefs->workdir, PATH_MAX, "%s", dirname);
460     return TRUE;
461   }
462 
463   lives_snprintf(prefs->workdir, PATH_MAX, "%s", dirname);
464   lives_snprintf(prefs->backend, PATH_MAX * 4, "%s -s \"%s\" -WORKDIR=\"%s\" -CONFIGFILE=\"%s\" --", EXEC_PERL,
465                  capable->backend_path, prefs->workdir, prefs->configfile);
466   lives_snprintf(prefs->backend_sync, PATH_MAX * 4, "%s", prefs->backend);
467 
468   set_string_pref_priority(PREF_WORKING_DIR, prefs->workdir);
469   set_string_pref(PREF_WORKING_DIR_OLD, prefs->workdir);
470 
471   mainw->has_session_workdir = FALSE;
472 
473   lives_free(dirname);
474 
475   return TRUE;
476 }
477 
478 
on_init_aplayer_toggled(LiVESToggleButton * tbutton,livespointer user_data)479 static void on_init_aplayer_toggled(LiVESToggleButton * tbutton, livespointer user_data) {
480   int audp = LIVES_POINTER_TO_INT(user_data);
481 
482   if (!lives_toggle_button_get_active(tbutton)) return;
483 
484   prefs->audio_player = audp;
485 
486   switch (audp) {
487   case AUD_PLAYER_PULSE:
488     set_string_pref(PREF_AUDIO_PLAYER, AUDIO_PLAYER_PULSE);
489     break;
490   case AUD_PLAYER_JACK:
491     set_string_pref(PREF_AUDIO_PLAYER, AUDIO_PLAYER_JACK);
492     break;
493   case AUD_PLAYER_SOX:
494     set_string_pref(PREF_AUDIO_PLAYER, AUDIO_PLAYER_SOX);
495     break;
496   }
497 }
498 
499 
do_audio_choice_dialog(short startup_phase)500 boolean do_audio_choice_dialog(short startup_phase) {
501   LiVESWidget *dialog, *dialog_vbox, *radiobutton2 = NULL, *label;
502   LiVESWidget *okbutton, *cancelbutton;
503   LiVESWidget *hbox;
504 
505 #ifdef HAVE_PULSE_AUDIO
506   LiVESWidget *radiobutton0;
507 #endif
508 
509 #ifdef ENABLE_JACK
510   LiVESWidget *radiobutton1;
511 #endif
512 
513   LiVESAccelGroup *accel_group;
514 
515   LiVESSList *radiobutton_group = NULL;
516 
517   char *txt0, *txt1, *txt2, *txt3, *txt4, *txt5, *txt6, *msg, *wid;
518 
519   LiVESResponseType response;
520 
521   if (startup_phase == 2) {
522     txt0 = (_("LiVES FAILED TO START YOUR SELECTED AUDIO PLAYER !\n\n"));
523   } else {
524     prefs->audio_player = -1;
525     txt0 = lives_strdup("");
526   }
527 
528   txt1 = lives_strdup(
529            _("Before starting LiVES, you need to choose an audio player.\n\nPULSE AUDIO is recommended for most users"));
530 
531 #ifndef HAVE_PULSE_AUDIO
532   txt2 = (_(", but this version of LiVES was not compiled with pulse audio support.\n\n"));
533 #else
534   if (!capable->has_pulse_audio) {
535     txt2 = lives_strdup(
536              _(", but you do not have pulseaudio installed on your system.\n "
537                "You are advised to install pulseaudio first before running LiVES.\n\n"));
538   } else txt2 = lives_strdup(".\n\n");
539 #endif
540 
541   txt3 = (_("JACK audio is recommended for pro users"));
542 
543 #ifndef ENABLE_JACK
544   txt4 = (_(", but this version of LiVES was not compiled with jack audio support.\n\n"));
545 #else
546   if (!capable->has_jackd) {
547     txt4 = (_(", but you do not have jackd installed. You may wish to install jackd first before running LiVES.\n\n"));
548   } else {
549     txt4 = lives_strdup(
550              _(", but may prevent LiVES from starting on some systems.\nIf LiVES will not start with jack,"
551                "you can restart and try with another audio player instead.\n\n"));
552   }
553 #endif
554 
555   txt5 = (_("SOX may be used if neither of the preceding players work, "));
556 
557   if (capable->has_sox_play) {
558     txt6 = (_("but many audio features will be disabled.\n\n"));
559   } else {
560     txt6 = (_("but you do not have sox installed.\nYou are advised to install it before running LiVES.\n\n"));
561   }
562 
563   msg = lives_strdup_printf("%s%s%s%s%s%s%s", txt0, txt1, txt2, txt3, txt4, txt5, txt6);
564 
565   lives_free(txt0); lives_free(txt1); lives_free(txt2);
566   lives_free(txt3); lives_free(txt4); lives_free(txt5);
567   lives_free(txt6);
568 
569   dialog = lives_standard_dialog_new(_("Choose an audio player"), FALSE, -1, -1);
570 
571   accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
572   lives_window_add_accel_group(LIVES_WINDOW(dialog), accel_group);
573 
574   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
575 
576   // TODO: add_param_label_to_box()
577   label = lives_standard_label_new(msg);
578   lives_container_add(LIVES_CONTAINER(dialog_vbox), label);
579   lives_free(msg);
580 
581 #ifdef HAVE_PULSE_AUDIO
582   hbox = lives_hbox_new(FALSE, 0);
583   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
584   radiobutton0 = lives_standard_radio_button_new(_("Use _pulseaudio player"), &radiobutton_group, LIVES_BOX(hbox), NULL);
585   if (prefs->audio_player == -1) prefs->audio_player = AUD_PLAYER_PULSE;
586 #endif
587 
588 #ifdef ENABLE_JACK
589   hbox = lives_hbox_new(FALSE, 0);
590   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
591   radiobutton1 = lives_standard_radio_button_new(_("Use _jack audio player"), &radiobutton_group, LIVES_BOX(hbox), NULL);
592 #endif
593 
594   if (capable->has_sox_play) {
595     hbox = lives_hbox_new(FALSE, 0);
596     lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
597     radiobutton2 = lives_standard_radio_button_new(_("Use _sox audio player"), &radiobutton_group, LIVES_BOX(hbox), NULL);
598     if (prefs->audio_player == -1) prefs->audio_player = AUD_PLAYER_SOX;
599   }
600 
601 #ifdef HAVE_PULSE_AUDIO
602   if (prefs->audio_player == AUD_PLAYER_PULSE || (!capable->has_pulse_audio && prefs->audio_player == -1)) {
603     prefs->audio_player = AUD_PLAYER_PULSE;
604     lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(radiobutton0), TRUE);
605     set_string_pref(PREF_AUDIO_PLAYER, AUDIO_PLAYER_PULSE);
606   }
607 #endif
608 #ifdef ENABLE_JACK
609   if (prefs->audio_player == AUD_PLAYER_JACK || !capable->has_pulse_audio || prefs->audio_player == -1) {
610     prefs->audio_player = AUD_PLAYER_JACK;
611     lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(radiobutton1), TRUE);
612     set_string_pref(PREF_AUDIO_PLAYER, AUDIO_PLAYER_JACK);
613   }
614 #endif
615   if (capable->has_sox_play) {
616     if (prefs->audio_player == AUD_PLAYER_SOX) {
617       lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(radiobutton2), TRUE);
618       set_string_pref(PREF_AUDIO_PLAYER, AUDIO_PLAYER_SOX);
619     }
620   }
621 
622 #ifdef HAVE_PULSE_AUDIO
623   lives_signal_sync_connect(LIVES_GUI_OBJECT(radiobutton0), LIVES_WIDGET_TOGGLED_SIGNAL,
624                             LIVES_GUI_CALLBACK(on_init_aplayer_toggled),
625                             LIVES_INT_TO_POINTER(AUD_PLAYER_PULSE));
626 #endif
627 
628 #ifdef ENABLE_JACK
629   lives_signal_sync_connect(LIVES_GUI_OBJECT(radiobutton1), LIVES_WIDGET_TOGGLED_SIGNAL,
630                             LIVES_GUI_CALLBACK(on_init_aplayer_toggled),
631                             LIVES_INT_TO_POINTER(AUD_PLAYER_JACK));
632 #endif
633 
634   if (capable->has_sox_play) {
635     lives_signal_sync_connect(LIVES_GUI_OBJECT(radiobutton2), LIVES_WIDGET_TOGGLED_SIGNAL,
636                               LIVES_GUI_CALLBACK(on_init_aplayer_toggled),
637                               LIVES_INT_TO_POINTER(AUD_PLAYER_SOX));
638   }
639   cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_CANCEL, NULL,
640                  LIVES_RESPONSE_CANCEL);
641 
642   lives_widget_add_accelerator(cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
643                                LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
644 
645   okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_GO_FORWARD, _("_Next"),
646              LIVES_RESPONSE_OK);
647 
648   lives_widget_show_all(dialog);
649   lives_button_grab_default_special(okbutton);
650 
651   lives_widget_show_now(dialog);
652   lives_widget_grab_focus(okbutton);
653 
654   if (prefs->audio_player == -1) {
655     do_no_mplayer_sox_error();
656     return LIVES_RESPONSE_CANCEL;
657   }
658 
659   if (mainw->splash_window) {
660     lives_widget_hide(mainw->splash_window);
661   }
662 
663   wid = lives_strdup_printf("0x%08lx", (uint64_t)LIVES_XWINDOW_XID(lives_widget_get_xwindow(dialog)));
664   if (!wid || !activate_x11_window(wid)) lives_window_set_keep_above(LIVES_WINDOW(dialog), TRUE);
665 
666   response = lives_dialog_run(LIVES_DIALOG(dialog));
667 
668   lives_widget_destroy(dialog);
669 
670   if (mainw->splash_window) {
671     lives_widget_show(mainw->splash_window);
672   }
673 
674   if (!is_realtime_aplayer(prefs->audio_player)) {
675     lives_widget_hide(mainw->vol_toolitem);
676     if (mainw->vol_label) lives_widget_hide(mainw->vol_label);
677     lives_widget_hide(mainw->recaudio_submenu);
678   }
679 
680   return (response == LIVES_RESPONSE_OK);
681 }
682 
683 
add_test(LiVESWidget * table,int row,char * ttext,boolean noskip)684 static void add_test(LiVESWidget * table, int row, char *ttext, boolean noskip) {
685   LiVESWidget *label = lives_standard_label_new(ttext);
686 
687   lives_table_attach(LIVES_TABLE(table), label, 0, 1, row, row + 1, (LiVESAttachOptions)0, (LiVESAttachOptions)0, 10, 10);
688   lives_widget_show(label);
689 
690   if (!noskip) {
691     LiVESWidget *image = lives_image_new_from_stock(LIVES_STOCK_REMOVE, LIVES_ICON_SIZE_LARGE_TOOLBAR);
692     // TRANSLATORS - as in "skipped test"
693     label = lives_standard_label_new(_("Skipped"));
694 
695     lives_table_attach(LIVES_TABLE(table), label, 1, 2, row, row + 1, (LiVESAttachOptions)0, (LiVESAttachOptions)0, 10, 10);
696     lives_widget_show(label);
697 
698     lives_table_attach(LIVES_TABLE(table), image, 2, 3, row, row + 1, (LiVESAttachOptions)0, (LiVESAttachOptions)0, 0, 10);
699     lives_widget_show(image);
700   }
701 
702   lives_widget_context_update();
703 }
704 
705 
pass_test(LiVESWidget * table,int row)706 static boolean pass_test(LiVESWidget * table, int row) {
707   // TRANSLATORS - as in "passed test"
708   LiVESWidget *label = lives_standard_label_new(_("Passed"));
709 
710 #if GTK_CHECK_VERSION(3, 10, 0)
711   LiVESWidget *image = lives_image_new_from_stock(LIVES_STOCK_ADD, LIVES_ICON_SIZE_LARGE_TOOLBAR);
712 #else
713   LiVESWidget *image = lives_image_new_from_stock(LIVES_STOCK_APPLY, LIVES_ICON_SIZE_LARGE_TOOLBAR);
714 #endif
715 
716   lives_table_attach(LIVES_TABLE(table), label, 1, 2, row, row + 1, (LiVESAttachOptions)0, (LiVESAttachOptions)0, 10, 10);
717   lives_widget_show(label);
718 
719   lives_table_attach(LIVES_TABLE(table), image, 2, 3, row, row + 1, (LiVESAttachOptions)0, (LiVESAttachOptions)0, 0, 10);
720   lives_widget_show(image);
721 
722   lives_widget_context_update();
723   return TRUE;
724 }
725 
726 
_fail_test(LiVESWidget * table,int row,char * ftext,const char * type)727 static boolean _fail_test(LiVESWidget * table, int row, char *ftext, const char *type) {
728   LiVESWidget *label;
729 #if GTK_CHECK_VERSION(3, 10, 0)
730   LiVESWidget *image = lives_image_new_from_stock(LIVES_STOCK_REMOVE, LIVES_ICON_SIZE_LARGE_TOOLBAR);
731 #else
732   LiVESWidget *image = lives_image_new_from_stock(LIVES_STOCK_CANCEL, LIVES_ICON_SIZE_LARGE_TOOLBAR);
733 #endif
734 
735   label = lives_standard_label_new(ftext);
736 
737   lives_table_attach(LIVES_TABLE(table), label, 3, 4, row, row + 1, (LiVESAttachOptions)0, (LiVESAttachOptions)0, 10, 10);
738   lives_widget_show(label);
739 
740   // TRANSLATORS - as in "failed test"
741   label = lives_standard_label_new(type);
742 
743   lives_table_attach(LIVES_TABLE(table), label, 1, 2, row, row + 1, (LiVESAttachOptions)0, (LiVESAttachOptions)0, 10, 10);
744   lives_widget_show(label);
745 
746   lives_table_attach(LIVES_TABLE(table), image, 2, 3, row, row + 1, (LiVESAttachOptions)0, (LiVESAttachOptions)0, 0, 10);
747   lives_widget_show(image);
748 
749   lives_widget_context_update();
750   return FALSE;
751 }
752 
fail_test(LiVESWidget * table,int row,char * ftext)753 LIVES_LOCAL_INLINE boolean fail_test(LiVESWidget * table, int row, char *ftext) {
754   allpassed = FALSE;
755   return _fail_test(table, row, ftext, _("Failed"));
756 }
757 
skip_test(LiVESWidget * table,int row,char * ftext)758 LIVES_LOCAL_INLINE boolean skip_test(LiVESWidget * table, int row, char *ftext) {
759   return _fail_test(table, row, ftext, _("Skipped"));
760 }
761 
get_resource(char * fname)762 LIVES_LOCAL_INLINE char *get_resource(char *fname) {
763   return lives_build_filename(prefs->prefix_dir, DATA_DIR, LIVES_RESOURCES_DIR, fname, NULL);
764 }
765 
766 
do_startup_tests(boolean tshoot)767 boolean do_startup_tests(boolean tshoot) {
768   LiVESWidget *dialog;
769   LiVESWidget *dialog_vbox;
770 
771   LiVESWidget *label;
772   LiVESWidget *table;
773   LiVESWidget *okbutton;
774   LiVESWidget *cancelbutton;
775 
776   LiVESAccelGroup *accel_group;
777 
778   char mppath[PATH_MAX];
779 
780   char *com, *rname, *afile, *tmp;
781   char *image_ext = lives_strdup(prefs->image_ext);
782   char *title, *msg;
783 
784   const char *mp_cmd;
785   const char *lookfor;
786 
787   uint8_t *abuff;
788 
789   off_t fsize;
790 
791   boolean success, success2, success3, success4;
792   boolean imgext_switched = FALSE;
793 
794   LiVESResponseType response;
795   int res;
796   int current_file = mainw->current_file;
797 
798   int out_fd, info_fd, testcase = 0;
799 
800   allpassed = TRUE;
801 
802   mainw->suppress_dprint = TRUE;
803   mainw->cancelled = CANCEL_NONE;
804 
805   if (mainw->multitrack) {
806     if (mainw->multitrack->idlefunc > 0) {
807       lives_source_remove(mainw->multitrack->idlefunc);
808       mainw->multitrack->idlefunc = 0;
809     }
810     mt_desensitise(mainw->multitrack);
811   }
812 
813   if (!tshoot) {
814     title = (_("Testing Configuration"));
815   } else {
816     title = (_("Troubleshoot"));
817   }
818 
819   dialog = lives_standard_dialog_new(title, FALSE, -1, -1);
820 
821   accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
822   lives_window_add_accel_group(LIVES_WINDOW(dialog), accel_group);
823 
824   lives_free(title);
825 
826   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
827 
828   label = lives_standard_label_new(_("LiVES will now run some basic configuration tests\n"));
829   lives_container_add(LIVES_CONTAINER(dialog_vbox), label);
830 
831   cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_CANCEL, NULL,
832                  LIVES_RESPONSE_CANCEL);
833 
834   lives_widget_add_accelerator(cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
835                                LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
836 
837   if (!tshoot) {
838     okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_GO_FORWARD, _("_Next"),
839                LIVES_RESPONSE_OK);
840   } else okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_OK, NULL,
841                       LIVES_RESPONSE_OK);
842 
843   lives_button_grab_default_special(okbutton);
844   lives_widget_grab_focus(okbutton);
845 
846   lives_widget_set_sensitive(okbutton, FALSE);
847 
848   table = lives_table_new(10, 4, FALSE);
849   lives_container_add(LIVES_CONTAINER(dialog_vbox), table);
850 
851   if (!tshoot) {
852     char *wid;
853     if (mainw->splash_window) {
854       lives_widget_hide(mainw->splash_window);
855     }
856     gtk_window_set_urgency_hint(LIVES_WINDOW(dialog), TRUE);
857     lives_widget_show_all(dialog);
858     lives_widget_show_now(dialog);
859     lives_widget_context_update();
860 
861     gtk_window_set_urgency_hint(LIVES_WINDOW(dialog), TRUE); // dont know if this actually does anything...
862     wid = lives_strdup_printf("0x%08lx", (uint64_t)LIVES_XWINDOW_XID(lives_widget_get_xwindow(dialog)));
863     if (!wid || !activate_x11_window(wid)) lives_window_set_keep_above(LIVES_WINDOW(dialog), TRUE);
864   }
865 
866   lives_widget_context_update();
867 
868   // check for sox presence
869 
870   add_test(table, testcase, _("Checking for \"sox\" presence"), TRUE);
871 
872   if (!capable->has_sox_sox) {
873     success = fail_test(table, testcase, _("You should install sox to be able to use all the audio features in LiVES"));
874     lives_widget_grab_focus(cancelbutton);
875   } else {
876     success = pass_test(table, testcase);
877   }
878 
879   // test if sox can convert raw 44100 -> wav 22050
880   add_test(table, ++testcase, _("Checking if sox can convert audio"), success);
881 
882   if (!tshoot) set_string_pref(PREF_DEFAULT_IMAGE_TYPE, LIVES_IMAGE_TYPE_PNG);
883   lives_snprintf(prefs->image_ext, 16, "%s", LIVES_FILE_EXT_PNG);
884   lives_snprintf(prefs->image_type, 16, "%s", LIVES_IMAGE_TYPE_PNG);
885 
886   get_temp_handle(-1);
887 
888   if (success) {
889     info_fd = -1;
890 
891     lives_rm(cfile->info_file);
892 
893     // write 1 second of silence
894     afile = lives_get_audio_file_name(mainw->current_file);
895     out_fd = lives_open3(afile, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
896 
897     if (out_fd < 0) THREADVAR(write_failed) = TRUE;
898     else THREADVAR(write_failed) = FALSE;
899 
900     if (!THREADVAR(write_failed)) {
901       int bytes = 44100 * 4;
902       abuff = (uint8_t *)lives_calloc(44100, 4);
903       if (!abuff) {
904         tmp = lives_strdup_printf(_("Unable to allocate %d bytes memory."), bytes);
905         fail_test(table, testcase, tmp);
906         lives_free(tmp);
907       } else {
908         lives_write(out_fd, abuff, bytes, TRUE);
909         close(out_fd);
910         lives_free(abuff);
911       }
912     }
913 
914     if (THREADVAR(write_failed)) {
915       tmp = lives_strdup_printf(_("Unable to write to: %s"), afile);
916       fail_test(table, testcase, tmp);
917       lives_free(tmp);
918     }
919 
920     lives_free(afile);
921 
922     if (!THREADVAR(write_failed)) {
923       afile = lives_build_filename(prefs->workdir, cfile->handle, "testout.wav", NULL);
924 
925       com = lives_strdup_printf("%s export_audio \"%s\" 0. 0. 44100 2 16 1 22050 \"%s\"", prefs->backend_sync,
926                                 cfile->handle, afile);
927       lives_system(com, TRUE);
928       if (THREADVAR(com_failed)) {
929         THREADVAR(com_failed) = FALSE;
930         tmp = lives_strdup_printf(_("Command failed: %s"), com);
931         fail_test(table, testcase, tmp);
932         lives_free(tmp);
933       }
934 
935       lives_free(com);
936 
937       while (mainw->cancelled == CANCEL_NONE && (info_fd = open(cfile->info_file, O_RDONLY)) == -1) {
938         lives_usleep(prefs->sleep_time);
939         lives_widget_context_update();
940       }
941 
942       if (info_fd != -1) {
943         close(info_fd);
944 
945         lives_sync(1);
946 
947         fsize = sget_file_size(afile);
948         lives_rm(afile);
949         lives_free(afile);
950 
951         if (fsize <= 0)
952           fail_test(table, testcase, _("You should install sox_fmt_all or similar"));
953         else pass_test(table, testcase);
954       }
955     }
956   }
957 
958   if (tshoot) {
959     lives_snprintf(prefs->image_ext, 16, "%s", image_ext);
960     lives_snprintf(prefs->image_type, 16, "%s", image_ext_to_lives_image_type(prefs->image_ext));
961   }
962 
963   if (mainw->cancelled != CANCEL_NONE) {
964     mainw->cancelled = CANCEL_NONE;
965     close_file(current_file, tshoot);
966     lives_widget_destroy(dialog);
967     mainw->suppress_dprint = FALSE;
968 
969     if (!mainw->multitrack) {
970       mt_sensitise(mainw->multitrack);
971       mainw->multitrack->idlefunc = mt_idle_add(mainw->multitrack);
972     }
973 
974     return FALSE;
975   }
976 
977   // check for mplayer presence
978   success2 = TRUE;
979 
980   add_test(table, ++testcase, _("Checking for \"mplayer\", \"mplayer2\" or \"mpv\" presence"), TRUE);
981 
982   if (!capable->has_mplayer && !capable->has_mplayer2 && !capable->has_mpv) {
983     success2 = fail_test(table, testcase,
984                          _("You should install mplayer, mplayer2 or mpv to be able to use all the decoding features in LiVES"));
985   }
986 
987   if (!success && !capable->has_mplayer2 && !capable->has_mplayer) {
988     success2 = FALSE;
989   }
990 
991   if (!success2) {
992     if (!success) {
993       lives_widget_destroy(dialog);
994       lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
995 
996       do_no_mplayer_sox_error();
997       close_file(current_file, tshoot);
998       mainw->suppress_dprint = FALSE;
999 
1000       if (mainw->multitrack) {
1001         mt_sensitise(mainw->multitrack);
1002         mainw->multitrack->idlefunc = mt_idle_add(mainw->multitrack);
1003       }
1004 
1005       return FALSE;
1006     }
1007   } else {
1008     success2 = pass_test(table, testcase);
1009   }
1010 
1011   // if present
1012 
1013   // check if mplayer can decode audio
1014 
1015   if (capable->has_mplayer) mp_cmd = EXEC_MPLAYER;
1016   else if (capable->has_mplayer2) mp_cmd = EXEC_MPLAYER2;
1017   else mp_cmd = EXEC_MPV;
1018 
1019   get_location(mp_cmd, mppath, PATH_MAX);
1020   lives_snprintf(prefs->video_open_command, PATH_MAX + 2, "\"%s\"", mppath);
1021   set_string_pref(PREF_VIDEO_OPEN_COMMAND, prefs->video_open_command);
1022 
1023   msg = lives_strdup_printf(_("Checking if %s can convert audio"), mp_cmd);
1024   add_test(table, ++testcase, msg, success2);
1025   lives_free(msg);
1026 
1027   res = 1;
1028 
1029   if (success2) {
1030     // TODO - add a timeout
1031 #ifndef IS_MINGW
1032     com = lives_strdup_printf("LANG=en LANGUAGE=en %s -ao help | %s pcm >/dev/null 2>&1", prefs->video_open_command,
1033                               capable->grep_cmd);
1034     res = lives_system(com, TRUE);
1035     lives_free(com);
1036 #else
1037     com = lives_strdup_printf("%s -ao help | %s pcm >NUL 2>&1", prefs->video_open_command, capable->grep_cmd);
1038     res = lives_system(com, TRUE);
1039     lives_free(com);
1040 #endif
1041   }
1042 
1043   if (res == 0) {
1044     pass_test(table, testcase);
1045   } else {
1046     fail_test(table, testcase, _("You should install mplayer,mplayer2 or mpv with pcm/wav support"));
1047   }
1048 
1049   // check if mplayer can decode to png/(alpha)
1050 
1051   rname = get_resource("");
1052   /// ensure that the resources dir is there
1053   if (!lives_file_test(rname, LIVES_FILE_TEST_IS_DIR)) {
1054     /// oops, no resources dir
1055     success4 = FALSE;
1056   } else success4 = TRUE;
1057 
1058 #ifdef ALLOW_PNG24
1059   msg = lives_strdup_printf(_("Checking if %s can decode to png"), mp_cmd);
1060 #else
1061   msg = lives_strdup_printf(_("Checking if %s can decode to png/alpha"), mp_cmd);
1062 #endif
1063   add_test(table, ++testcase, msg, success2);
1064   lives_free(msg);
1065 
1066   success3 = FALSE;
1067 
1068   if (success2 && !success4) {
1069     tmp = lives_strdup_printf(_("Resource directory %s not found !"), rname);
1070     skip_test(table, testcase, tmp);
1071     lives_free(tmp);
1072 
1073     msg = lives_strdup_printf(_("Checking less rigorously"), mp_cmd);
1074     add_test(table, ++testcase, msg, TRUE);
1075     lives_free(msg);
1076 
1077     res = 1;
1078 
1079     if (!strcmp(mp_cmd, "mpv")) lookfor = "image";
1080     else lookfor = "png file";
1081 
1082 #ifndef IS_MINGW
1083     com = lives_strdup_printf("LANG=en LANGUAGE=en %s -vo help | %s -i \"%s\" >/dev/null 2>&1",
1084                               prefs->video_open_command, capable->grep_cmd, lookfor);
1085 #else
1086     com = lives_strdup_printf("%s -vo help | %s -i \"%s\" >NUL 2>&1", prefs->video_open_command,
1087                               capable->grep_cmd, lookfor);
1088 #endif
1089     res = lives_system(com, TRUE);
1090     lives_free(com);
1091 
1092     if (!res) {
1093       pass_test(table, testcase);
1094       success3 = TRUE;
1095     }
1096   }
1097 
1098   lives_free(rname);
1099 
1100   // try to open resource vidtest.avi
1101   if (!success3 && success2 && success4) {
1102     info_fd = -1;
1103 
1104     lives_rm(cfile->info_file);
1105 
1106     rname = get_resource(LIVES_TEST_VIDEO_NAME);
1107 
1108     com = lives_strdup_printf("%s open_test \"%s\" %s \"%s\" 0 png", prefs->backend_sync, cfile->handle,
1109                               prefs->video_open_command,
1110                               (tmp = lives_filename_from_utf8(rname, -1, NULL, NULL, NULL)));
1111     lives_free(tmp);
1112     lives_free(rname);
1113 
1114     lives_system(com, TRUE);
1115     if (THREADVAR(com_failed)) {
1116       THREADVAR(com_failed) = FALSE;
1117       tmp = lives_strdup_printf(_("Command failed: %s"), com);
1118       fail_test(table, testcase, tmp);
1119       lives_free(tmp);
1120     }
1121 
1122     lives_free(com);
1123 
1124     while (mainw->cancelled == CANCEL_NONE && (info_fd = open(cfile->info_file, O_RDONLY)) == -1) {
1125       lives_usleep(prefs->sleep_time);
1126     }
1127 
1128     if (info_fd != -1) {
1129       close(info_fd);
1130 
1131       lives_sync(1);
1132 
1133       cfile->img_type = IMG_TYPE_PNG;
1134       cfile->frames = get_frame_count(mainw->current_file, 1);
1135 
1136       if (cfile->frames <= 0) {
1137         msg = lives_strdup_printf(_("You may wish to upgrade %s to a newer version"), mp_cmd);
1138         fail_test(table, testcase, msg);
1139         lives_free(msg);
1140       }
1141 
1142       else {
1143         pass_test(table, testcase);
1144         success3 = TRUE;
1145       }
1146     }
1147   }
1148 
1149   if (mainw->cancelled != CANCEL_NONE) {
1150     mainw->cancelled = CANCEL_NONE;
1151     close_file(current_file, tshoot);
1152     lives_widget_destroy(dialog);
1153     mainw->suppress_dprint = FALSE;
1154 
1155     if (mainw->multitrack) {
1156       mt_sensitise(mainw->multitrack);
1157       mainw->multitrack->idlefunc = mt_idle_add(mainw->multitrack);
1158     }
1159 
1160     return FALSE;
1161   }
1162 
1163   // check if mplayer can decode to jpeg
1164 
1165   msg = lives_strdup_printf(_("Checking if %s can decode to jpeg"), mp_cmd);
1166   add_test(table, ++testcase, msg, success2);
1167   lives_free(msg);
1168   res = 1;
1169 
1170   if (!strcmp(mp_cmd, "mpv")) {
1171     if (success2 && success3 && !success4) {
1172       tmp = (_("Already checked"));
1173       skip_test(table, testcase - 1, tmp);
1174       lives_free(tmp);
1175       goto jpgdone;
1176     }
1177     lookfor = "image";
1178   } else lookfor = "jpeg file";
1179 
1180   if (success2) {
1181 #ifndef IS_MINGW
1182     com = lives_strdup_printf("LANG=en LANGUAGE=en %s -vo help | %s -i \"%s\" >/dev/null 2>&1",
1183                               prefs->video_open_command, capable->grep_cmd, lookfor);
1184     res = lives_system(com, TRUE);
1185     lives_free(com);
1186 #else
1187     com = lives_strdup_printf("%s -vo help | %s -i \"%s\" >NUL 2>&1", prefs->video_open_command,
1188                               capable->grep_cmd, lookfor);
1189     res = lives_system(com, TRUE);
1190     lives_free(com);
1191 #endif
1192   }
1193 
1194   if (res == 0) {
1195     pass_test(table, testcase);
1196     if (!success3) {
1197       if (!strcmp(prefs->image_ext, LIVES_FILE_EXT_PNG)) imgext_switched = TRUE;
1198       set_string_pref(PREF_DEFAULT_IMAGE_TYPE, LIVES_IMAGE_TYPE_JPEG);
1199       lives_snprintf(prefs->image_ext, 16, "%s", LIVES_FILE_EXT_JPG);
1200       lives_snprintf(prefs->image_type, 16, "%s", LIVES_IMAGE_TYPE_JPEG);
1201     }
1202   } else {
1203     if (!success3) {
1204 #ifdef ALLOW_PNG24
1205       msg = lives_strdup_printf(_("You should install %s with either png or jpeg support"), mp_cmd);
1206 #else
1207       msg = lives_strdup_printf(_("You should install %s with either png/alpha or jpeg support"), mp_cmd);
1208 #endif
1209       fail_test(table, testcase, msg);
1210       lives_free(msg);
1211     } else {
1212       msg = lives_strdup_printf(_("You may wish to add jpeg output support to %s"), mp_cmd);
1213       fail_test(table, testcase, msg);
1214       lives_free(msg);
1215     }
1216   }
1217 
1218   // TODO - check each enabled decoder plugin in turn
1219 
1220 jpgdone:
1221   // check for convert
1222 
1223   add_test(table, ++testcase, _("Checking for \"convert\" presence"), TRUE);
1224 
1225   if (!capable->has_convert) {
1226     success = fail_test(table, testcase, _("Install imageMagick to be able to use all of the rendered effects"));
1227   } else {
1228     success = pass_test(table, testcase);
1229   }
1230 
1231   close_file(current_file, tshoot);
1232   mainw->current_file = current_file;
1233 
1234   lives_widget_set_sensitive(okbutton, TRUE);
1235   lives_widget_grab_focus(okbutton);
1236   /* if (!tshoot) { */
1237   /*   if (allpassed) { */
1238   /*   } else { */
1239   /*     lives_widget_grab_focus(cancelbutton); */
1240   /*   } */
1241   /* } */
1242 
1243   if (tshoot) {
1244     lives_widget_hide(cancelbutton);
1245     if (imgext_switched) {
1246       label = lives_standard_label_new(
1247                 _("\n\n\tImage decoding type has been switched to jpeg. You can revert this in Preferences/Decoding.\t\n"));
1248       lives_container_add(LIVES_CONTAINER(dialog_vbox), label);
1249     }
1250     lives_widget_show(label);
1251   } else {
1252     label = lives_standard_label_new(
1253               _("\n\n\tClick Cancel to exit and install any missing components, or Next to continue\t\n"));
1254     lives_container_add(LIVES_CONTAINER(dialog_vbox), label);
1255     lives_widget_show(label);
1256   }
1257 
1258   response = lives_dialog_run(LIVES_DIALOG(dialog));
1259 
1260   lives_widget_destroy(dialog);
1261   mainw->suppress_dprint = FALSE;
1262 
1263   if (mainw->splash_window) {
1264     lives_widget_show(mainw->splash_window);
1265   }
1266 
1267   if (mainw->multitrack) {
1268     mt_sensitise(mainw->multitrack);
1269     mainw->multitrack->idlefunc = mt_idle_add(mainw->multitrack);
1270   }
1271 
1272   return (response == LIVES_RESPONSE_OK);
1273 }
1274 
1275 
do_startup_interface_query(void)1276 void do_startup_interface_query(void) {
1277   // prompt for startup ce or startup mt
1278   LiVESWidget *dialog, *dialog_vbox, *radiobutton, *label;
1279   /* LiVESWidget *okbutton; */
1280   /* LiVESWidget *quotabutton; */
1281   LiVESWidget *hbox;
1282   LiVESSList *radiobutton_group = NULL;
1283   LiVESResponseType resp;
1284   char *txt1, *txt2, *txt3, *msg, *wid;
1285 
1286   txt1 = (_("\n\nFinally, you can choose the default startup interface for LiVES.\n"));
1287   txt2 = (_("\n\nLiVES has two main interfaces and you can start up with either of them.\n"));
1288   txt3 = (_("\n\nThe default can always be changed later from Preferences.\n"));
1289 
1290   msg = lives_strdup_printf("%s%s%s", txt1, txt2, txt3);
1291 
1292   lives_free(txt1); lives_free(txt2); lives_free(txt3);
1293 
1294   dialog = lives_standard_dialog_new(_("Choose the Startup Interface"), FALSE, -1, -1);
1295   //if (transient) lives_window_set_transient_for(LIVES_WINDOW(dialog), NULL);
1296 
1297   dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
1298 
1299   label = lives_standard_label_new(msg);
1300   lives_container_add(LIVES_CONTAINER(dialog_vbox), label);
1301   lives_free(msg);
1302 
1303   hbox = lives_hbox_new(FALSE, 0);
1304   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
1305   lives_standard_radio_button_new(_("Start in _Clip Edit mode"), &radiobutton_group, LIVES_BOX(hbox), NULL);
1306 
1307   label = lives_standard_label_new(_("This is the best choice for simple editing tasks and for VJs\n"));
1308 
1309   lives_box_pack_start(LIVES_BOX(dialog_vbox), label, FALSE, FALSE, widget_opts.packing_height);
1310 
1311   hbox = lives_hbox_new(FALSE, 0);
1312   lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
1313   radiobutton = lives_standard_radio_button_new(_("Start in _Multitrack mode"), &radiobutton_group, LIVES_BOX(hbox), NULL);
1314 
1315   label = lives_standard_label_new(_("This is a better choice for complex editing tasks involving multiple clips.\n"));
1316 
1317   lives_box_pack_start(LIVES_BOX(dialog_vbox), label, FALSE, FALSE, widget_opts.packing_height);
1318 
1319   if (prefs->startup_interface == STARTUP_MT) {
1320     lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(radiobutton), TRUE);
1321   }
1322 
1323   add_fill_to_box(LIVES_BOX(dialog_vbox));
1324 
1325   widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH | LIVES_EXPAND_DEFAULT_HEIGHT;
1326   lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), NULL,
1327                                      _("Set Quota Limits (Optional)"), LIVES_RESPONSE_SHOW_DETAILS);
1328   widget_opts.expand = LIVES_EXPAND_DEFAULT;
1329 
1330   lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_GO_FORWARD,
1331                                      _("Finish"), LIVES_RESPONSE_OK);
1332 
1333   /* lives_button_grab_default_special(okbutton); */
1334   /* lives_widget_grab_focus(okbutton); */
1335 
1336   lives_widget_hide(LIVES_MAIN_WINDOW_WIDGET);
1337   lives_widget_show_now(dialog);
1338 
1339   wid = lives_strdup_printf("0x%08lx", (uint64_t)LIVES_XWINDOW_XID(lives_widget_get_xwindow(dialog)));
1340   if (!wid || !activate_x11_window(wid)) lives_window_set_keep_above(LIVES_WINDOW(dialog), TRUE);
1341 
1342   if (mainw->splash_window) {
1343     lives_widget_hide(mainw->splash_window);
1344   }
1345 
1346   resp = lives_dialog_run(LIVES_DIALOG(dialog));
1347   if (resp == LIVES_RESPONSE_SHOW_DETAILS) prefs->show_disk_quota = TRUE;
1348   else prefs->show_disk_quota = FALSE;
1349 
1350   if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(radiobutton)))
1351     future_prefs->startup_interface = prefs->startup_interface = STARTUP_MT;
1352 
1353   set_int_pref(PREF_STARTUP_INTERFACE, prefs->startup_interface);
1354 
1355   lives_widget_destroy(dialog);
1356   if (mainw->splash_window) {
1357     lives_widget_show(mainw->splash_window);
1358   }
1359 }
1360 
1361 
on_troubleshoot_activate(LiVESMenuItem * menuitem,livespointer user_data)1362 void on_troubleshoot_activate(LiVESMenuItem * menuitem, livespointer user_data) {do_startup_tests(TRUE);}
1363 
1364 
explain_missing(const char * exe)1365 static char *explain_missing(const char *exe) {
1366   char *pt2, *pt1 = lives_strdup_printf(_("\t'%s' was not found on your system.\n"
1367                                           "Installation is recommended as it provides the following features\n\t- "), exe);
1368   if (!lives_strcmp(exe, EXEC_FILE)) pt2 = (_("Enables easier identification of file types,\n\n"));
1369   else if (!lives_strcmp(exe, EXEC_GZIP)) pt2 = (_("Enables reduction in file size for some files,\n\n"));
1370   else if (!lives_strcmp(exe, EXEC_DU)) pt2 = (_("Enables measuring of disk space used,\n\n"));
1371   else if (!lives_strcmp(exe, EXEC_FFPROBE)) pt2 = (_("Assists in the identification of video clips\n\n"));
1372   else if (!lives_strcmp(exe, EXEC_IDENTIFY)) pt2 = (_("Assists in the identification of image files\n\n"));
1373   else if (!lives_strcmp(exe, EXEC_CONVERT)) pt2 = (_("Required for many rendered effects in the clip editor.\n\n"));
1374   else if (!lives_strcmp(exe, EXEC_COMPOSITE)) pt2 = (_("Enables clip merging in the clip editor.\n\n"));
1375   else if (!lives_strcmp(exe, EXEC_PYTHON)) pt2 = (_("Allows use of some additional encoder plugins\n\n"));
1376   else if (!lives_strcmp(exe, EXEC_MD5SUM)) pt2 = (_("Allows checking for file changes, "
1377         "enabling additional files to be cached in memory.\n\n"));
1378   else if (!lives_strcmp(exe, EXEC_YOUTUBE_DL)) pt2 = (_("Enables download and import of files from "
1379         "Youtube and other sites.\n\n"));
1380   else if (!lives_strcmp(exe, EXEC_XWININFO)) pt2 = (_("Enables identification of external windows "
1381         "so that they can be recorded.\n\n"));
1382   else {
1383     lives_free(pt1);
1384     pt1 = lives_strdup_printf(_("\t'%s' was not found on your system.\n"
1385                                 "Installation is optional, but may enable additional features\n\t- "), exe);
1386     if (!lives_strcmp(exe, EXEC_XDOTOOL)) pt2 = (_("Enables adjustment of windows within the desktop,\n\n"));
1387     else return lives_strdup_free(pt1, "");
1388   }
1389   return lives_concat(pt1, pt2);
1390 }
1391 
1392 
1393 #define ADD_TO_TEXT(what, exec)   if (!capable->has_##what) {	\
1394     text = lives_concat(text, explain_missing(exec)) ;\
1395 }
1396 
explain_missing_activate(LiVESMenuItem * menuitem,livespointer user_data)1397 void explain_missing_activate(LiVESMenuItem * menuitem, livespointer user_data) {
1398   char *title = (_("What is missing ?")), *text = lives_strdup("");
1399 
1400   check_for_executable(&capable->has_file, EXEC_FILE);
1401 
1402   ADD_TO_TEXT(file, EXEC_FILE);
1403   ADD_TO_TEXT(du,  EXEC_DU);
1404   ADD_TO_TEXT(identify, EXEC_IDENTIFY);
1405   ADD_TO_TEXT(md5sum, EXEC_MD5SUM);
1406   ADD_TO_TEXT(ffprobe, EXEC_FFPROBE);
1407   ADD_TO_TEXT(convert, EXEC_CONVERT);
1408   ADD_TO_TEXT(composite, EXEC_COMPOSITE);
1409   ADD_TO_TEXT(python, EXEC_PYTHON);
1410   ADD_TO_TEXT(gzip, EXEC_GZIP);
1411   ADD_TO_TEXT(youtube_dl, EXEC_YOUTUBE_DL);
1412   ADD_TO_TEXT(xwininfo, EXEC_XWININFO);
1413   if (!(*text)) {
1414     lives_free(title); lives_free(text);
1415     do_info_dialog(_("All optional components located\n"));
1416     return;
1417   }
1418   text = lives_concat(text, (_("\n\nIf you DO have any of these missing components, please ensure they are "
1419                                "located in your $PATH before restarting LiVES")));
1420   widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH | LIVES_EXPAND_DEFAULT_HEIGHT;
1421   create_text_window(title, text, NULL, TRUE);
1422   widget_opts.expand = LIVES_EXPAND_DEFAULT;;
1423   lives_free(title);
1424   lives_free(text);
1425 }
1426 #undef ADD_TO_TEXT
1427 
1428