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