1
2 // callbacks.c
3 // LiVES
4 // (c) G. Finch 2003 - 2020 <salsaman+lives@gmail.com>
5 // released under the GNU GPL 3 or later
6 // see file ../COPYING for licensing details
7
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <sys/stat.h>
14 #include <dlfcn.h>
15
16 #include "main.h"
17 #include "callbacks.h"
18 #include "interface.h"
19 #include "effects.h"
20 #include "resample.h"
21 #include "rte_window.h"
22 #include "events.h"
23 #include "audio.h"
24 #include "cvirtual.h"
25 #include "paramwindow.h"
26 #include "ce_thumbs.h"
27 #include "startup.h"
28 #include "diagnostics.h"
29
30 #ifdef LIBAV_TRANSCODE
31 #include "transcode.h"
32 #endif
33
34 #ifdef HAVE_YUV4MPEG
35 #include "lives-yuv4mpeg.h"
36 #endif
37
38 #ifdef HAVE_UNICAP
39 #include "videodev.h"
40 #endif
41
42 #ifdef ENABLE_OSC
43 #include "osc.h"
44 #endif
45
46 static char file_name[PATH_MAX];
47
48
lives_notify(int msgnumber,const char * msgstring)49 void lives_notify(int msgnumber, const char *msgstring) {
50 #ifdef IS_LIBLIVES
51 binding_cb(msgnumber, msgstring, mainw->id);
52 #endif
53 #ifdef ENABLE_OSC
54 lives_osc_notify(msgnumber, msgstring);
55 #endif
56
57 #ifdef TEST_NOTIFY
58 if (msgnumber == LIVES_OSC_NOTIFY_CLIPSET_OPENED) {
59 char *details = lives_strdup_printf(_("'LiVES opened the clip set' '%s'"), msgstring);
60 char *tmp = lives_strdup_printf("notify-send %s", details);
61 lives_system(tmp, TRUE);
62 lives_free(tmp);
63 lives_free(details);
64 }
65
66 if (msgnumber == LIVES_OSC_NOTIFY_CLIPSET_SAVED) {
67 char *details = lives_strdup_printf(_("'LiVES saved the clip set' '%s'"), msgstring);
68 char *tmp = lives_strdup_printf("notify-send %s", details);
69 lives_system(tmp, TRUE);
70 lives_free(tmp);
71 lives_free(details);
72 }
73 #endif
74 }
75
76
lives_notify_int(int msgnumber,int msgint)77 LIVES_GLOBAL_INLINE void lives_notify_int(int msgnumber, int msgint) {
78 char *tmp = lives_strdup_printf("%d", msgint);
79 lives_notify(msgnumber, tmp);
80 lives_free(tmp);
81 }
82
83
on_LiVES_delete_event(LiVESWidget * widget,LiVESXEventDelete * event,livespointer user_data)84 boolean on_LiVES_delete_event(LiVESWidget *widget, LiVESXEventDelete *event, livespointer user_data) {
85 if (!LIVES_IS_INTERACTIVE) return TRUE;
86 on_quit_activate(NULL, NULL);
87 return TRUE;
88 }
89
90
cleanup_set_dir(const char * set_name)91 static void cleanup_set_dir(const char *set_name) {
92 // this function is called:
93 // - when a set is saved and merged with an existing one
94 // - when a set is deleted
95 // - when the last clip in a set is closed
96
97 char *lfiles, *ofile, *sdir;
98
99 sdir = lives_build_path(prefs->workdir, set_name, LAYOUTS_DIRNAME, NULL);
100 if (lives_file_test(sdir, LIVES_FILE_TEST_IS_DIR))
101 lives_rmdir(sdir, FALSE);
102 lives_free(sdir);
103
104 sdir = lives_build_filename(prefs->workdir, set_name, CLIPS_DIRNAME, NULL);
105 if (lives_file_test(sdir, LIVES_FILE_TEST_IS_DIR))
106 lives_rmdir(sdir, FALSE);
107 lives_free(sdir);
108
109 // remove any stale lockfiles
110 lfiles = SET_LOCK_FILES(set_name);
111 lives_rmglob(lfiles);
112 lives_free(lfiles);
113
114 ofile = lives_build_filename(prefs->workdir, set_name, CLIP_ORDER_FILENAME, NULL);
115 lives_rm(ofile);
116 lives_free(ofile);
117
118 ofile = lives_build_filename(prefs->workdir, set_name,
119 CLIP_ORDER_FILENAME "." LIVES_FILE_EXT_NEW, NULL);
120 lives_rm(ofile);
121 lives_free(ofile);
122
123 lives_sync(1);
124
125 sdir = lives_build_path(prefs->workdir, set_name, NULL);
126 lives_rmdir(sdir, FALSE); // set to FALSE in case the user placed extra files there
127 lives_free(sdir);
128
129 if (prefs->ar_clipset && !strcmp(prefs->ar_clipset_name, set_name)) {
130 prefs->ar_clipset = FALSE;
131 lives_memset(prefs->ar_clipset_name, 0, 1);
132 set_string_pref(PREF_AR_CLIPSET, "");
133 }
134 mainw->set_list = lives_list_delete_string(mainw->set_list, set_name);
135 }
136
137
138 #ifndef VALGRIND_ON
139 #ifdef _lives_free
140 #undef lives_free
141 #define lives_free(a) (mainw->is_exiting ? a : _lives_free(a))
142 #endif
143 #endif
144
lives_exit(int signum)145 void lives_exit(int signum) {
146 char *tmp, *com;
147 int i;
148
149 if (!mainw) _exit(0);
150
151 if (!mainw->only_close) {
152 mainw->is_exiting = TRUE;
153
154 // unlock all mutexes to prevent deadlocks
155 #ifdef HAVE_PULSE_AUDIO
156 /* if (mainw->pulsed || mainw->pulsed_read) */
157 /* pa_mloop_unlock(); */
158 #endif
159
160 // recursive
161 while (!pthread_mutex_unlock(&mainw->instance_ref_mutex));
162 while (!pthread_mutex_unlock(&mainw->abuf_mutex));
163
164 // non-recursive
165 pthread_mutex_trylock(&mainw->abuf_frame_mutex);
166 pthread_mutex_unlock(&mainw->abuf_frame_mutex);
167 pthread_mutex_trylock(&mainw->fxd_active_mutex);
168 pthread_mutex_unlock(&mainw->fxd_active_mutex);
169 pthread_mutex_trylock(&mainw->event_list_mutex);
170 pthread_mutex_unlock(&mainw->event_list_mutex);
171 pthread_mutex_trylock(&mainw->clip_list_mutex);
172 pthread_mutex_unlock(&mainw->clip_list_mutex);
173 pthread_mutex_trylock(&mainw->vpp_stream_mutex);
174 pthread_mutex_unlock(&mainw->vpp_stream_mutex);
175 pthread_mutex_trylock(&mainw->cache_buffer_mutex);
176 pthread_mutex_unlock(&mainw->cache_buffer_mutex);
177 pthread_mutex_trylock(&mainw->audio_filewriteend_mutex);
178 pthread_mutex_unlock(&mainw->audio_filewriteend_mutex);
179 pthread_mutex_trylock(&mainw->fbuffer_mutex);
180 pthread_mutex_unlock(&mainw->fbuffer_mutex);
181 pthread_mutex_trylock(&mainw->alarmlist_mutex);
182 pthread_mutex_unlock(&mainw->alarmlist_mutex);
183 // filter mutexes are unlocked in weed_unload_all
184
185 if (pthread_mutex_trylock(&mainw->exit_mutex)) pthread_exit(NULL);
186
187 if (mainw->memok && prefs->crash_recovery && mainw->record) {
188 backup_recording(NULL, NULL);
189 }
190
191 //lives_threadpool_finish();
192 //show_weed_stats();
193 }
194
195 if (mainw->is_ready) {
196 if (mainw->multitrack && mainw->multitrack->idlefunc > 0) {
197 //lives_source_remove(mainw->multitrack->idlefunc);
198 mainw->multitrack->idlefunc = 0;
199 }
200
201 threaded_dialog_spin(0.);
202
203 if (mainw->toy_type != LIVES_TOY_NONE) {
204 on_toy_activate(NULL, LIVES_INT_TO_POINTER(LIVES_TOY_NONE));
205 }
206
207 if (mainw->alives_pgid > 0) {
208 autolives_toggle(NULL, NULL);
209 }
210
211 #ifdef VALGRIND_ON
212 if (mainw->stored_event_list || mainw->sl_undo_mem) {
213 stored_event_list_free_all(FALSE);
214 }
215
216 if (mainw->multitrack && !mainw->only_close) {
217 lives_freep((void **)&mainw->multitrack->undo_mem);
218 }
219
220 if (mainw->multi_opts.set && !mainw->only_close && mainw->multi_opts.aparam_view_list) {
221 lives_list_free(mainw->multi_opts.aparam_view_list);
222 }
223 #endif
224
225 #ifdef VALGRIND_ON
226 if (LIVES_IS_PLAYING) {
227 lives_grab_remove(LIVES_MAIN_WINDOW_WIDGET);
228 if (mainw->ext_playback) {
229 pthread_mutex_lock(&mainw->vpp_stream_mutex);
230 mainw->ext_audio = FALSE;
231 pthread_mutex_unlock(&mainw->vpp_stream_mutex);
232 if (mainw->vpp->exit_screen)(*mainw->vpp->exit_screen)(mainw->ptr_x, mainw->ptr_y);
233 stop_audio_stream();
234 mainw->stream_ticks = -1;
235 }
236
237 // tell non-realtime audio players (sox or mplayer) to stop
238 if (!is_realtime_aplayer(prefs->audio_player) && mainw->aud_file_to_kill > -1 &&
239 mainw->files[mainw->aud_file_to_kill]) {
240 char *lsname = lives_build_filename(prefs->workdir, mainw->files[mainw->aud_file_to_kill]->handle, NULL);
241 lives_touch(lsname);
242 lives_free(lsname);
243 com = lives_strdup_printf("%s stop_audio \"%s\"", prefs->backend, mainw->files[mainw->aud_file_to_kill]->handle);
244 lives_system(com, TRUE);
245 lives_free(com);
246 }
247 }
248 #endif
249 // stop any background processing for the current clip
250 if (CURRENT_CLIP_IS_VALID) {
251 if (cfile->handle && CURRENT_CLIP_IS_NORMAL) {
252 lives_kill_subprocesses(cfile->handle, TRUE);
253 }
254 }
255
256 // prevent crash in "threaded" dialog
257 mainw->current_file = -1;
258
259 if (!mainw->only_close) {
260 // shut down audio players
261 #ifdef HAVE_PULSE_AUDIO
262 if (mainw->pulsed) pulse_close_client(mainw->pulsed);
263 if (mainw->pulsed_read) pulse_close_client(mainw->pulsed_read);
264 pulse_shutdown();
265 #endif
266 #ifdef ENABLE_JACK
267 lives_jack_end();
268 if (mainw->jackd) {
269 jack_close_device(mainw->jackd);
270 }
271 if (mainw->jackd_read) {
272 jack_close_device(mainw->jackd_read);
273 }
274 #endif
275 }
276
277 if (mainw->vpp && !mainw->only_close) {
278 if (mainw->memok) {
279 if (mainw->write_vpp_file) {
280 // save video playback plugin parameters
281 char *vpp_file = lives_build_filename(prefs->config_datadir, VPP_DEFS_FILE, NULL);
282 save_vpp_defaults(mainw->vpp, vpp_file);
283 }
284 }
285 close_vid_playback_plugin(mainw->vpp);
286 }
287
288 if (mainw->memok) {
289 if (!mainw->leave_recovery) {
290 lives_rm(mainw->recovery_file);
291 // hide the main window
292 threaded_dialog_spin(0.);
293 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
294 threaded_dialog_spin(0.);
295 }
296
297 if (*(future_prefs->workdir) && lives_strcmp(future_prefs->workdir, prefs->workdir)) {
298 // if we changed the workdir, remove everything but sets from the old dir
299 // create the new directory, and then move any sets over
300 end_threaded_dialog();
301 if (do_move_workdir_dialog()) {
302 do_do_not_close_d();
303 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
304
305 // TODO *** - check for namespace collisions between sets in old dir and sets in new dir
306
307 // use backend to move the sets
308 com = lives_strdup_printf("%s move_workdir \"%s\"", prefs->backend_sync,
309 future_prefs->workdir);
310 lives_system(com, FALSE);
311 lives_free(com);
312 }
313 lives_snprintf(prefs->workdir, PATH_MAX, "%s", future_prefs->workdir);
314 }
315
316 if (mainw->leave_files && !mainw->fatal) {
317 d_print(_("Saving as set %s..."), mainw->set_name);
318 mainw->suppress_dprint = TRUE;
319 }
320
321 for (i = 1; i <= MAX_FILES; i++) {
322 if (mainw->files[i]) {
323 mainw->current_file = i;
324 threaded_dialog_spin(0.);
325 if (cfile->event_list_back) event_list_free(cfile->event_list_back);
326 if (cfile->event_list) event_list_free(cfile->event_list);
327
328 cfile->event_list = cfile->event_list_back = NULL;
329
330 lives_list_free_all(&cfile->layout_map);
331
332 if (cfile->laudio_drawable) {
333 if (mainw->laudio_drawable == cfile->laudio_drawable) mainw->laudio_drawable = NULL;
334 lives_painter_surface_destroy(cfile->laudio_drawable);
335 cfile->laudio_drawable = NULL;
336 }
337
338 if (cfile->raudio_drawable) {
339 if (mainw->raudio_drawable == cfile->raudio_drawable) mainw->raudio_drawable = NULL;
340 lives_painter_surface_destroy(cfile->raudio_drawable);
341 cfile->raudio_drawable = NULL;
342 }
343 if (mainw->drawsrc == mainw->current_file) mainw->drawsrc = -1;
344
345 if (IS_NORMAL_CLIP(i) && mainw->files[i]->ext_src && mainw->files[i]->ext_src_type == LIVES_EXT_SRC_DECODER) {
346 // must do this before we move it
347 close_clip_decoder(i);
348 threaded_dialog_spin(0.);
349 }
350 lives_freep((void **)&mainw->files[i]->frame_index);
351 cfile->layout_map = NULL;
352 }
353
354 if (mainw->files[i]) {
355 /// physically remove:
356 /// - "device" clips, generators, etc.
357 /// - scrap files, if we are not closing or crash recovery is disabled
358 /// - "normal" clips, unless crash recovery is in effect, or
359 /// - we are no exiting and it's the clipboard, or the mt render file
360 if (!IS_NORMAL_CLIP(i) || (i == 0 && !mainw->only_close)
361 || (!mainw->leave_files && !mainw->leave_recovery)
362 || (i == mainw->scrap_file && (mainw->only_close ||
363 !mainw->leave_recovery || !prefs->rr_crash))
364 || (i == mainw->ascrap_file && (mainw->only_close ||
365 !mainw->leave_recovery || !prefs->rr_crash))
366 || (i > 0 && !mainw->only_close && mainw->multitrack
367 && i == mainw->multitrack->render_file && !CLIP_HAS_VIDEO(i)
368 && !CLIP_HAS_AUDIO(i))) {
369 if (mainw->only_close || !IS_NORMAL_CLIP(i)) {
370 int current_file = mainw->current_file;
371 mainw->current_file = i;
372 close_current_file(current_file);
373 } else {
374 char *permitname;
375 threaded_dialog_spin(0.);
376 lives_kill_subprocesses(mainw->files[i]->handle, TRUE);
377 permitname = lives_build_filename(prefs->workdir, mainw->files[i]->handle,
378 TEMPFILE_MARKER "." LIVES_FILE_EXT_TMP, NULL);
379 lives_touch(permitname);
380 lives_free(permitname);
381 com = lives_strdup_printf("%s close \"%s\"", prefs->backend, mainw->files[i]->handle);
382 lives_system(com, FALSE);
383 lives_free(com);
384 threaded_dialog_spin(0.);
385 }
386 } else {
387 threaded_dialog_spin(0.);
388 // or just clean them up -
389 // remove the following: "*.mgk *.bak *.pre *.tmp pause audio.* audiodump* audioclip";
390 if (!prefs->vj_mode) {
391 if (prefs->autoclean) {
392 com = lives_strdup_printf("%s clear_tmp_files \"%s\"",
393 prefs->backend_sync, mainw->files[i]->handle);
394 lives_system(com, FALSE);
395 threaded_dialog_spin(0.);
396 lives_free(com);
397 }
398 if (IS_NORMAL_CLIP(i)) {
399 char *fname = lives_build_filename(prefs->workdir, mainw->files[i]->handle,
400 TOTALSAVE_NAME, NULL);
401 int fd = lives_create_buffered(fname, DEF_FILE_PERMS);
402 lives_write_buffered(fd, (const char *)mainw->files[i], sizeof(lives_clip_t), TRUE);
403 lives_close_buffered(fd);
404 }
405 }
406 if (mainw->files[i]->frameno != mainw->files[i]->saved_frameno) {
407 save_clip_value(i, CLIP_DETAILS_PB_FRAMENO, &mainw->files[i]->frameno);
408 // *INDENT-OFF*
409 }}}}
410 // *INDENT-ON*
411 if (prefs->autoclean) {
412 com = lives_strdup_printf("%s empty_trash . general", prefs->backend);
413 lives_system(com, FALSE);
414 lives_free(com);
415 }
416
417 if (*mainw->set_name) {
418 /// if a set was loaded:
419 /// - if we are only closing them in the app, leave the frames on disk
420 if (mainw->only_close) {
421 mainw->suppress_dprint = TRUE;
422 mainw->close_keep_frames = TRUE;
423 mainw->is_processing = TRUE; ///< stop multitrack from sensitizing too soon
424 for (i = 1; i <= MAX_FILES; i++) {
425 if (IS_NORMAL_CLIP(i) && (!mainw->multitrack || i != mainw->multitrack->render_file)) {
426 mainw->current_file = i;
427 close_current_file(0);
428 threaded_dialog_spin(0.);
429 }
430 }
431 mainw->close_keep_frames = FALSE;
432 }
433
434 if (*mainw->set_name) {
435 if (!mainw->leave_files && !mainw->leave_recovery) {
436 // delete the current set (this is for DELETE_SET)
437 cleanup_set_dir(mainw->set_name);
438 lives_memset(mainw->set_name, 0, 1);
439 mainw->was_set = FALSE;
440 lives_widget_set_sensitive(mainw->vj_load_set, TRUE);
441 } else {
442 unlock_set_file(mainw->set_name);
443 }
444 }
445 }
446
447 if (mainw->only_close) {
448 mainw->suppress_dprint = FALSE;
449 if (!mainw->multitrack) resize(1);
450 mainw->was_set = FALSE;
451 lives_memset(mainw->set_name, 0, 1);
452 mainw->only_close = FALSE;
453 prefs->crash_recovery = TRUE;
454
455 threaded_dialog_spin(0.);
456 if (mainw->current_file > -1) sensitize();
457 lives_widget_queue_draw(LIVES_MAIN_WINDOW_WIDGET);
458 d_print_done();
459 end_threaded_dialog();
460
461 if (mainw->multitrack) {
462 mainw->current_file = mainw->multitrack->render_file;
463 mainw->multitrack->file_selected = -1;
464 polymorph(mainw->multitrack, POLY_NONE);
465 polymorph(mainw->multitrack, POLY_CLIPS);
466 mt_sensitise(mainw->multitrack);
467 } else {
468 if (prefs->show_msg_area) {
469 reset_message_area();
470 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
471 if (mainw->idlemax == 0) {
472 lives_idle_add_simple(resize_message_area, NULL);
473 }
474 mainw->idlemax = DEF_IDLE_MAX;
475 }
476 }
477 mainw->is_processing = FALSE; ///< mt may now sensitize...
478 return;
479 }
480 save_future_prefs();
481 }
482
483 // stop valgrind from complaining
484 #ifdef VALGRIND_ON
485 if (mainw->frame_layer) {
486 check_layer_ready(mainw->frame_layer);
487 weed_layer_free(mainw->frame_layer);
488 mainw->frame_layer = NULL;
489 }
490 #endif
491 if (mainw->sep_win && (LIVES_IS_PLAYING || prefs->sepwin_type == SEPWIN_TYPE_STICKY)) {
492 threaded_dialog_spin(0.);
493 kill_play_window();
494 threaded_dialog_spin(0.);
495 }
496
497 weed_unload_all();
498
499 #ifdef VALGRIND_ON
500 lives_list_free_all(&mainw->current_layouts_map);
501
502 if (capable->has_encoder_plugins) {
503 LiVESList *dummy_list = plugin_request("encoders", prefs->encoder.name, "finalise");
504 lives_list_free_all(&dummy_list);
505 }
506 threaded_dialog_spin(0.);
507 rfx_free_all();
508 threaded_dialog_spin(0.);
509 #endif
510
511 #ifdef ENABLE_OSC
512 if (prefs->osc_udp_started) lives_osc_end();
513 #endif
514 mainw->is_ready = FALSE;
515
516 #ifdef VALGRIND_ON
517 pconx_delete_all();
518 cconx_delete_all();
519
520 mainw->msg_adj = NULL;
521 free_n_msgs(mainw->n_messages);
522
523 if (mainw->multitrack) {
524 event_list_free_undos(mainw->multitrack);
525
526 if (mainw->multitrack->event_list) {
527 event_list_free(mainw->multitrack->event_list);
528 mainw->multitrack->event_list = NULL;
529 }
530 }
531
532 lives_freep((void **)&prefs->fxdefsfile);
533 lives_freep((void **)&prefs->fxsizesfile);
534 lives_freep((void **)&capable->wm_name);
535 lives_freep((void **)&mainw->recovery_file);
536
537 for (i = 0; i < NUM_LIVES_STRING_CONSTANTS; i++) lives_freep((void **)&mainw->string_constants[i]);
538 for (i = 0; i < mainw->n_screen_areas; i++) lives_freep((void **)&mainw->screen_areas[i].name);
539
540 lives_freep((void **)&mainw->foreign_visual);
541 lives_freep((void **)&THREADVAR(read_failed_file));
542 lives_freep((void **)&THREADVAR(write_failed_file));
543 lives_freep((void **)&THREADVAR(bad_aud_file));
544
545 lives_freep((void **)&mainw->old_vhash);
546 lives_freep((void **)&mainw->version_hash);
547 lives_freep((void **)&mainw->multitrack);
548 lives_freep((void **)&mainw->mgeom);
549 lives_list_free_all(&prefs->disabled_decoders);
550 if (mainw->fonts_array) lives_strfreev(mainw->fonts_array);
551 #ifdef ENABLE_NLS
552 //lives_freep((void **)&trString);
553 #endif
554 #endif
555 unload_decoder_plugins();
556 }
557 tmp = lives_strdup_printf("signal: %d", signum);
558 lives_notify(LIVES_OSC_NOTIFY_QUIT, tmp);
559 lives_free(tmp);
560
561 exit(0);
562 }
563
564
565 #ifndef VALGRIND_ON
566 #ifdef _lives_free
567 #undef lives_free
568 #define lives_free _lives_free
569 #endif
570 #endif
571
572
open_sel_range_activate(int frames,double fps)573 static void open_sel_range_activate(int frames, double fps) {
574 // open selection range dialog
575 LiVESWidget *opensel_dialog;
576 mainw->fc_buttonresponse = LIVES_RESPONSE_NONE; // reset button state
577 mainw->fx1_val = 0.;
578 mainw->fx2_val = frames > 1000. ? 1000. : (double)frames;
579 opensel_dialog = create_opensel_dialog(frames, fps);
580 lives_widget_show_all(opensel_dialog);
581 }
582
583
read_file_details_generic(const char * fname)584 static boolean read_file_details_generic(const char *fname) {
585 /// make a tmpdir in case we need to open images for example
586 char *tmpdir, *dirname, *com;
587 const char *prefix = "_fsp";
588 dirname = get_worktmp(prefix);
589 if (dirname) tmpdir = lives_build_path(prefs->workdir, dirname, NULL);
590 else {
591 dirname = lives_strdup_printf("%s%lu", prefix, gen_unique_id());
592 tmpdir = lives_build_path(prefs->workdir, dirname, NULL);
593 if (!lives_make_writeable_dir(tmpdir)) {
594 workdir_warning();
595 lives_free(tmpdir); lives_free(dirname);
596 end_fs_preview();
597 return FALSE;
598 }
599 }
600
601 // check details
602 com = lives_strdup_printf("%s get_details %s \"%s\" \"%s\" %d", prefs->backend_sync,
603 dirname, fname, prefs->image_ext, 0);
604 lives_popen(com, FALSE, mainw->msg, MAINW_MSG_SIZE);
605 lives_free(com); lives_free(dirname);
606
607 lives_rmdir(tmpdir, TRUE);
608 lives_free(tmpdir);
609
610 if (THREADVAR(com_failed)) {
611 THREADVAR(com_failed) = FALSE;
612 end_fs_preview();
613 return FALSE;
614 }
615 return TRUE;
616 }
617
618
on_open_sel_activate(LiVESMenuItem * menuitem,livespointer user_data)619 void on_open_sel_activate(LiVESMenuItem * menuitem, livespointer user_data) {
620 // OPEN A FILE
621 LiVESWidget *chooser;
622 char **array;
623 char *fname, *tmp;
624 double fps;
625 int resp, npieces, frames;
626 mainw->mt_needs_idlefunc = FALSE;
627
628 if (mainw->multitrack) {
629 if (mainw->multitrack->idlefunc > 0) {
630 lives_source_remove(mainw->multitrack->idlefunc);
631 mainw->multitrack->idlefunc = 0;
632 mainw->mt_needs_idlefunc = TRUE;
633 }
634 mt_desensitise(mainw->multitrack);
635 lives_widget_set_sensitive(mainw->multitrack->playall, TRUE);
636 lives_widget_set_sensitive(mainw->m_playbutton, TRUE);
637 }
638
639 while (1) {
640 chooser = choose_file_with_preview((*mainw->vid_load_dir) ? mainw->vid_load_dir : NULL, NULL, NULL,
641 LIVES_FILE_SELECTION_VIDEO_AUDIO);
642 resp = lives_dialog_run(LIVES_DIALOG(chooser));
643
644 end_fs_preview();
645
646 if (resp != LIVES_RESPONSE_ACCEPT) {
647 on_filechooser_cancel_clicked(chooser);
648 if (mainw->multitrack) {
649 mt_sensitise(mainw->multitrack);
650 maybe_add_mt_idlefunc();
651 }
652 return;
653 }
654
655 fname = lives_file_chooser_get_filename(LIVES_FILE_CHOOSER(chooser));
656
657 if (!fname) {
658 if (mainw->multitrack) {
659 mt_sensitise(mainw->multitrack);
660 maybe_add_mt_idlefunc();
661 }
662 return;
663 }
664
665 lives_snprintf(file_name, PATH_MAX, "%s", (tmp = lives_filename_to_utf8(fname, -1, NULL, NULL, NULL)));
666 lives_free(tmp);
667
668 lives_widget_destroy(LIVES_WIDGET(chooser));
669
670 lives_snprintf(mainw->vid_load_dir, PATH_MAX, "%s", file_name);
671 get_dirname(mainw->vid_load_dir);
672
673 lives_widget_queue_draw_and_update(LIVES_MAIN_WINDOW_WIDGET);
674
675 if (prefs->save_directories) {
676 set_utf8_pref(PREF_VID_LOAD_DIR, mainw->vid_load_dir);
677 }
678
679 if (!read_file_details_generic(fname)) {
680 lives_free(fname);
681 if (mainw->multitrack) {
682 mt_sensitise(mainw->multitrack);
683 maybe_add_mt_idlefunc();
684 }
685 return;
686 }
687 lives_free(fname);
688
689 npieces = get_token_count(mainw->msg, '|');
690 if (npieces < 8) {
691 end_fs_preview();
692 if (mainw->multitrack) {
693 mt_sensitise(mainw->multitrack);
694 maybe_add_mt_idlefunc();
695 }
696 return;
697 }
698
699 array = lives_strsplit(mainw->msg, "|", npieces);
700 frames = atoi(array[2]);
701 fps = lives_strtod(array[7], NULL);
702 lives_strfreev(array);
703
704 if (frames == 0) {
705 do_error_dialog("LiVES could not extract any video frames from this file.\nSorry.\n");
706 end_fs_preview();
707 if (mainw->multitrack) {
708 mt_sensitise(mainw->multitrack);
709 maybe_add_mt_idlefunc();
710 }
711 continue;
712 }
713 break;
714 }
715
716 open_sel_range_activate(frames, fps);
717 }
718
719
on_open_vcd_activate(LiVESMenuItem * menuitem,livespointer device_type)720 void on_open_vcd_activate(LiVESMenuItem * menuitem, livespointer device_type) {
721 LiVESWidget *vcdtrack_dialog;
722 int type = LIVES_POINTER_TO_INT(device_type);
723 mainw->mt_needs_idlefunc = FALSE;
724
725 if (mainw->multitrack) {
726 if (mainw->multitrack->idlefunc > 0) {
727 lives_source_remove(mainw->multitrack->idlefunc);
728 mainw->multitrack->idlefunc = 0;
729 mainw->mt_needs_idlefunc = TRUE;
730 }
731 mt_desensitise(mainw->multitrack);
732 lives_widget_set_sensitive(mainw->multitrack->playall, TRUE);
733 lives_widget_set_sensitive(mainw->m_playbutton, TRUE);
734 }
735
736 mainw->fx1_val = 1;
737 mainw->fx2_val = 1;
738 mainw->fx3_val = DVD_AUDIO_CHAN_DEFAULT;
739
740 vcdtrack_dialog = create_cdtrack_dialog(type, NULL);
741 lives_widget_show_all(vcdtrack_dialog);
742 }
743
744
on_open_loc_activate(LiVESMenuItem * menuitem,livespointer user_data)745 void on_open_loc_activate(LiVESMenuItem * menuitem, livespointer user_data) {
746 // need non-instant opening (for now)
747 mainw->mt_needs_idlefunc = FALSE;
748
749 if (!HAS_EXTERNAL_PLAYER) {
750 do_need_mplayer_mpv_dialog();
751 return;
752 }
753
754 if (mainw->multitrack) {
755 if (mainw->multitrack->idlefunc > 0) {
756 lives_source_remove(mainw->multitrack->idlefunc);
757 mainw->multitrack->idlefunc = 0;
758 mainw->mt_needs_idlefunc = TRUE;
759 }
760 mt_desensitise(mainw->multitrack);
761 lives_widget_set_sensitive(mainw->multitrack->playall, TRUE);
762 lives_widget_set_sensitive(mainw->m_playbutton, TRUE);
763 }
764
765 locw = create_location_dialog();
766 lives_widget_show_all(locw->dialog);
767 }
768
769
on_open_utube_activate(LiVESMenuItem * menuitem,livespointer user_data)770 void on_open_utube_activate(LiVESMenuItem * menuitem, livespointer user_data) {
771 /// get a system tmpdir
772
773 lives_remote_clip_request_t *req = NULL, *req2;
774 char *tmpdir;
775 if (!check_for_executable(&capable->has_mktemp, EXEC_MKTEMP)) {
776 do_program_not_found_error(EXEC_MKTEMP);
777 return;
778 }
779 tmpdir = get_systmp("ytdl", TRUE);
780 if (!tmpdir) return;
781
782 mainw->mt_needs_idlefunc = FALSE;
783
784 if (mainw->multitrack) {
785 if (mainw->multitrack->idlefunc > 0) {
786 lives_source_remove(mainw->multitrack->idlefunc);
787 mainw->multitrack->idlefunc = 0;
788 mainw->mt_needs_idlefunc = TRUE;
789 }
790 mt_desensitise(mainw->multitrack);
791 lives_widget_set_sensitive(mainw->multitrack->playall, TRUE);
792 lives_widget_set_sensitive(mainw->m_playbutton, TRUE);
793 }
794
795 do {
796 mainw->cancelled = CANCEL_NONE;
797 req = run_youtube_dialog(req);
798 if (!req) {
799 if (mainw->multitrack) {
800 mt_sensitise(mainw->multitrack);
801 maybe_add_mt_idlefunc();
802 }
803 goto final123;
804 }
805 req2 = on_utube_select(req, tmpdir);
806 #ifndef ALLOW_NONFREE_CODECS
807 req2 = NULL;
808 #endif
809 if (req2 && mainw->cancelled == CANCEL_RETRY) req = req2;
810 else {
811 lives_free(req);
812 req = NULL;
813 }
814 } while (mainw->cancelled == CANCEL_RETRY);
815
816 final123:
817 if (mainw->permmgr) {
818 lives_freep((void **)&mainw->permmgr->key);
819 lives_free(mainw->permmgr);
820 mainw->permmgr = NULL;
821 }
822 if (tmpdir) {
823 if (lives_file_test(tmpdir, LIVES_FILE_TEST_EXISTS)) {
824 lives_rmdir(tmpdir, TRUE);
825 }
826 lives_free(tmpdir);
827 }
828
829 if (!mainw->multitrack) sensitize();
830 }
831
832
on_recent_activate(LiVESMenuItem * menuitem,livespointer user_data)833 void on_recent_activate(LiVESMenuItem * menuitem, livespointer user_data) {
834 char file[PATH_MAX];
835 double start = 0.;
836 int end = 0, pno;
837 char *pref;
838 mainw->mt_needs_idlefunc = FALSE;
839
840 pno = LIVES_POINTER_TO_INT(user_data);
841
842 if (mainw->multitrack) {
843 if (mainw->multitrack->idlefunc > 0) {
844 lives_source_remove(mainw->multitrack->idlefunc);
845 mainw->multitrack->idlefunc = 0;
846 mainw->mt_needs_idlefunc = TRUE;
847 }
848 mt_desensitise(mainw->multitrack);
849 }
850
851 //lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
852
853 pref = lives_strdup_printf("%s%d", PREF_RECENT, pno);
854
855 get_utf8_pref(pref, file, PATH_MAX);
856
857 lives_free(pref);
858
859 if (get_token_count(file, '\n') > 1) {
860 char **array = lives_strsplit(file, "\n", 2);
861 lives_snprintf(file, PATH_MAX, "%s", array[0]);
862 lives_freep((void **)&mainw->file_open_params);
863 mainw->file_open_params = lives_strdup(array[1]);
864 lives_strfreev(array);
865 }
866
867 if (get_token_count(file, '|') > 2) {
868 char **array = lives_strsplit(file, "|", 3);
869 lives_snprintf(file, PATH_MAX, "%s", array[0]);
870 start = lives_strtod(array[1], NULL);
871 end = atoi(array[2]);
872 lives_strfreev(array);
873 }
874 deduce_file(file, start, end);
875
876 if (mainw->multitrack) {
877 polymorph(mainw->multitrack, POLY_NONE);
878 polymorph(mainw->multitrack, POLY_CLIPS);
879 mt_sensitise(mainw->multitrack);
880 maybe_add_mt_idlefunc();
881 }
882 }
883
884
on_location_select(LiVESButton * button,livespointer user_data)885 void on_location_select(LiVESButton * button, livespointer user_data) {
886 lives_snprintf(file_name, PATH_MAX, "%s", lives_entry_get_text(LIVES_ENTRY(locw->entry)));
887 lives_widget_destroy(locw->dialog);
888 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
889 lives_free(locw);
890
891 mainw->opening_loc = TRUE;
892 lives_freep((void **)&mainw->file_open_params);
893 if (prefs->no_bandwidth) {
894 mainw->file_open_params = lives_strdup("nobandwidth");
895 } else mainw->file_open_params = lives_strdup("sendbandwidth");
896 mainw->img_concat_clip = -1;
897 open_file(file_name);
898
899 if (mainw->multitrack) {
900 polymorph(mainw->multitrack, POLY_NONE);
901 polymorph(mainw->multitrack, POLY_CLIPS);
902 mt_sensitise(mainw->multitrack);
903 maybe_add_mt_idlefunc();
904 }
905 }
906
907 #define USE_YTDL
908
909 //ret updated req if fmt sel. needs change
on_utube_select(lives_remote_clip_request_t * req,const char * tmpdir)910 lives_remote_clip_request_t *on_utube_select(lives_remote_clip_request_t *req, const char *tmpdir) {
911 char *com, *full_dfile = NULL, *tmp, *ddir, *dest = NULL;
912 char *overrdkey = NULL;
913 char *mpf = NULL, *mpt = NULL;
914 lives_remote_clip_request_t *reqout = NULL;
915 boolean hasnone = FALSE, hasalts = FALSE;
916 boolean keep_old_dir = FALSE;
917 boolean forcecheck = FALSE;
918 boolean bres;
919 boolean badfile = FALSE;
920 int keep_frags = 0;
921 int manage_ds = 0;
922 int current_file = mainw->current_file;
923 int audchoice = 0;
924
925 mainw->no_switch_dprint = TRUE;
926
927 // if possible, download to a temp dir first, that way we can cleanly delete leftover fragments, etc.
928 if (tmpdir) {
929 ddir = lives_build_path(tmpdir, req->fname, NULL);
930 keep_frags = 1;
931 if (lives_file_test(ddir, LIVES_FILE_TEST_IS_DIR)) {
932 if (check_dir_access(ddir, FALSE)) {
933 keep_old_dir = TRUE;
934 }
935 }
936 if (!keep_old_dir) {
937 LiVESResponseType resp;
938 char *xdir = lives_build_path(tmpdir, "*", NULL);
939 lives_rmdir(xdir, TRUE);
940 lives_free(xdir);
941 do {
942 resp = LIVES_RESPONSE_NONE;
943 if (!lives_make_writeable_dir(ddir)) {
944 resp = do_dir_perm_error(ddir, TRUE);
945 if (resp == LIVES_RESPONSE_CANCEL) goto cleanup_ut;
946 }
947 } while (resp == LIVES_RESPONSE_RETRY);
948 }
949 } else ddir = req->save_dir;
950
951 if (capable->mountpoint && *capable->mountpoint) {
952 /// if tempdir is on same volume as workdir, or if not using tmpdir and final is on same
953 // then we monitor continuously
954 mpf = get_mountpoint_for(ddir);
955 if (mpf && *mpf && !lives_strcmp(mpf, capable->mountpoint)) {
956 manage_ds = 1;
957 }
958 }
959 if (!manage_ds && ddir != req->save_dir) {
960 mpt = get_mountpoint_for(req->save_dir);
961 if (mpf && *mpf && mpt && *mpt) {
962 if (lives_strcmp(mpf, mpt)) {
963 /// in this case tmpdir is on another volume, but final dest. is on our volume
964 /// or a different one
965 /// we will only check before moving the file
966 if (capable->mountpoint && *capable->mountpoint && !lives_strcmp(mpt, capable->mountpoint)) {
967 // final dest is ours, we will check warn, crit and overflow
968 manage_ds = 2;
969 } else {
970 // final dest is not ours, we will only check overflow
971 manage_ds = 3;
972 // *INDENT-OFF*
973 }}}}
974 // *INDENT-ON*
975
976 lives_freep((void **)&mpf);
977
978 if (prefs->ds_warn_level && !prefs->ds_crit_level) {
979 /// if the user disabled disk_quota, disk_warn, AND disk_crit, then we just let the disk fill up
980 /// the only thing we will care about is if there is insufficient space to move the file
981 if (manage_ds == 2) manage_ds = 3;
982 else manage_ds = 0;
983 }
984
985 mainw->error = FALSE;
986
987 // do minimal ds checking until we hit full download
988 forcecheck = FALSE;
989
990 if (!get_temp_handle(-1)) {
991 // we failed because we ran out of file handles; this hsould almost never happen
992 d_print_failed();
993 goto cleanup_ut;
994 }
995
996 while (1) {
997 retry:
998 lives_rm(cfile->info_file);
999 if (req->do_update) {
1000 if (!check_for_executable(&capable->has_pip, EXEC_PIP)) {
1001 /// check we can update locally
1002 do_please_install(EXEC_PIP, 0);
1003 capable->has_pip = UNCHECKED;
1004 d_print_failed();
1005 goto cleanup_ut;
1006 } else {
1007 #ifdef YTDL_URL
1008 /// if youtube-dl has a fixed download location, we can let the backend install it for us
1009 /// TODO: pass URL as argv[15]
1010 if (mainw->permmgr && mainw->permmgr->key && req->do_update) {
1011 /// force fresh install of local youtube-dl
1012 overrdkey = mainw->permmgr->key;
1013 }
1014 #else
1015 /// else copy system binary to $HOME/.local/bin
1016 if (capable->has_youtube_dl != LOCAL) {
1017 char *todir = lives_build_path(capable->home_dir, LOCAL_HOME_DIR, "bin", NULL);
1018 char *to = lives_build_filename(todir, EXEC_YOUTUBE_DL, NULL);
1019 if (!lives_file_test(to, LIVES_FILE_TEST_IS_EXECUTABLE)) {
1020 char from[PATH_MAX];
1021 if (check_for_executable(&capable->has_youtube_dlc, EXEC_YOUTUBE_DLC))
1022 get_location(EXEC_YOUTUBE_DLC, from, PATH_MAX);
1023 else
1024 get_location(EXEC_YOUTUBE_DL, from, PATH_MAX);
1025 if (lives_strlen(from) > 10) {
1026 if (check_dir_access(todir, TRUE)) {
1027 lives_cp(from, to);
1028 }
1029 }
1030 }
1031 lives_free(todir); lives_free(to);
1032 check_for_executable(&capable->has_youtube_dl, EXEC_YOUTUBE_DL);
1033 }
1034 }
1035 }
1036 #endif
1037
1038 // get format list
1039
1040 // for now, we dont't pass req->desired_fps or req->audchoice
1041 // also we could send req->sub_lang...
1042
1043 if (!mainw->save_with_sound) audchoice = -1;
1044
1045 com = lives_strdup_printf("%s download_clip \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" %d %d %d \"%s\" %d "
1046 "%d %d %d %s", prefs->backend, cfile->handle, req->URI, ddir,
1047 req->fname, req->format, req->desired_width, req->desired_height,
1048 req->matchsize, req->vidchoice, audchoice, keep_frags,
1049 req->do_update, req->debug,
1050 overrdkey ? (tmp = lives_strdup_printf(" %s", overrdkey))
1051 : (tmp = lives_strdup("")));
1052 lives_free(tmp);
1053
1054 if (mainw->permmgr) {
1055 lives_freep((void **)&mainw->permmgr->key);
1056 lives_free(mainw->permmgr);
1057 overrdkey = NULL;
1058 mainw->permmgr = NULL;
1059 }
1060
1061 mainw->error = FALSE;
1062 lives_system(com, FALSE);
1063 lives_free(com);
1064
1065 if (THREADVAR(com_failed)) {
1066 d_print_failed();
1067 mainw->error = FALSE;
1068 req->allownf = TRUE;
1069 reqout = req;
1070 reqout->do_update = TRUE;
1071 mainw->cancelled = CANCEL_RETRY;
1072 goto cleanup_ut;
1073 }
1074
1075 #ifndef USE_YTDL
1076 break;
1077 #endif
1078
1079 // we expect to get back a list of available formats
1080 // or the selected format
1081 if (*(req->vidchoice)) break;
1082
1083 if (!do_auto_dialog(_("Getting format list"), 2)) {
1084 /// we can get CANCEL_ERROR: - error was detected but user gave permission to fix it
1085 /// or CANCEL_USER: - error was detected and user declined auto fix
1086 if (mainw->cancelled == CANCEL_ERROR) {
1087 mainw->cancelled = CANCEL_NONE;
1088 mainw->error = TRUE;
1089 }
1090 if (mainw->cancelled) d_print_cancelled();
1091 else if (mainw->error) {
1092 d_print_failed();
1093 if (mainw->permmgr) {
1094 if (mainw->cancelled == CANCEL_NONE &&
1095 mainw->permmgr->key && *mainw->permmgr->key) {
1096 req->do_update = TRUE;
1097 mainw->error = FALSE;
1098 goto retry;
1099 } else {
1100 req->do_update = FALSE;
1101 lives_free(mainw->permmgr);
1102 mainw->permmgr = NULL;
1103 }
1104 } else {
1105 do_error_dialogf(_("Unable to download media from the requested URL:\n%s\n\n"
1106 "NB: Obtaining the address by right clicking on the target itself "
1107 "can sometimes work better\n\n\nAlso, please note that downloading of 'Private' videos "
1108 "from Youtube is not possible,\nthey need to be changed to 'Unlisted' "
1109 "in order for the download to succeed.\n"), req->URI);
1110 }
1111 if (reqout) reqout->do_update = TRUE;
1112 }
1113 mainw->error = FALSE;
1114 mainw->cancelled = CANCEL_RETRY;
1115 reqout = req;
1116 goto cleanup_ut;
1117 }
1118
1119 if (!(*mainw->msg)) {
1120 hasnone = TRUE;
1121 }
1122 #ifdef ALLOW_NONFREE_CODECS
1123 else if (!lives_strncmp(mainw->msg, "completed|altfmts", 17)) {
1124 hasalts = TRUE;
1125 }
1126 #endif
1127
1128 if (hasnone || hasalts) {
1129 d_print_failed();
1130 if (hasnone) {
1131 do_error_dialog(
1132 _("\nLiVES was unable to download the clip.\nPlease check the clip URL and make sure you have \n"
1133 "the latest youtube-dl installed.\n"));
1134 } else {
1135 #ifdef ALLOW_NONFREE_CODECS
1136 if (do_yesno_dialog(
1137 _("\nLiVES was unable to download the clip in the desired format\nWould you like to try using an alternate "
1138 "format selection ?"))) {
1139 mainw->error = FALSE;
1140 mainw->cancelled = CANCEL_RETRY;
1141 req->allownf = TRUE;
1142 reqout = req;
1143 #endif
1144 }
1145 }
1146 goto cleanup_ut;
1147 }
1148
1149 if (req->matchsize == LIVES_MATCH_CHOICE && !*req->vidchoice) {
1150 // show a list of the video formats and let the user pick one
1151 if (!youtube_select_format(req)) {
1152 goto cleanup_ut;
1153 }
1154 // we try again, this time with req->vidchoice set
1155 req->matchsize = LIVES_MATCH_SPECIFIED;
1156 } else {
1157 // returned completed|vidchoice|audchoice
1158 char **array = lives_strsplit(mainw->msg, "|", 3);
1159 lives_snprintf(req->vidchoice, 512, "%s", array[1]);
1160 lives_snprintf(req->audchoice, 512, "%s", array[2]);
1161 lives_strfreev(array);
1162 }
1163 }
1164
1165 // backend should now be downloading the clip
1166
1167 // do more intensive diskspace checking
1168 forcecheck = TRUE;
1169
1170 if (manage_ds == 1) {
1171 /// type 1, we do continuous monitoring
1172 // we will only monitor for CRIT, other statuses will be checked at the end
1173 mainw->ds_mon = CHECK_CRIT;
1174 }
1175
1176 cfile->nopreview = TRUE;
1177 cfile->no_proc_sys_errors = TRUE; ///< do not show processing error dialogs, we will show our own msg
1178
1179 //// TODO - allow downloading in bg while user does something else
1180 /// **ADD TASK CALLBACK
1181
1182 lives_snprintf(req->ext, 16, "%s", req->format);
1183
1184 full_dfile = lives_strdup_printf("%s.%s", req->fname, req->ext);
1185
1186 bres = do_progress_dialog(TRUE, TRUE, _("Downloading clip"));
1187 cfile->no_proc_sys_errors = FALSE;
1188 if (!bres || mainw->error) badfile = TRUE;
1189 else {
1190 dest = lives_build_filename(req->save_dir, full_dfile, NULL);
1191 if (ddir != req->save_dir) {
1192 lives_storage_status_t dstate;
1193 char *from = lives_build_filename(ddir, full_dfile, NULL);
1194 off_t clipsize;
1195 if (!lives_file_test(from, LIVES_FILE_TEST_EXISTS) || (clipsize = sget_file_size(from)) <= 0) {
1196 badfile = TRUE;
1197 } else {
1198 if (manage_ds == 2 || manage_ds == 3) {
1199 LiVESResponseType resp;
1200 do {
1201 char *msg = NULL;
1202 int64_t dsu = -1;
1203 resp = LIVES_RESPONSE_OK;
1204 dstate = get_storage_status(req->save_dir, mainw->next_ds_warn_level, &dsu, clipsize);
1205 if (dstate == LIVES_STORAGE_STATUS_OVERFLOW) {
1206 msg =
1207 lives_strdup_printf(_("There is insufficient disk space in %s to move the downloaded clip.\n"), mpt);
1208 } else if (manage_ds != 3) {
1209 if (dstate == LIVES_STORAGE_STATUS_CRITICAL || dstate == LIVES_STORAGE_STATUS_WARNING) {
1210 msg = lives_strdup_printf(_("Moving the downloaded clip to\n%s\nwill bring free disk space in %s\n"
1211 "below the %s level of %s\n"), mpt);
1212 }
1213 }
1214
1215 if (msg) {
1216 char *cs = lives_format_storage_space_string(clipsize);
1217 char *vs = lives_format_storage_space_string(dsu);
1218 char *xmsg = lives_strdup_printf("%s\n(Free space in volume = %s, clip size = %s)\n"
1219 "You can either try deleting some files from %s and clicking on Retry\n"
1220 "or else click Cancel to cancel the download.\n", msg, vs, cs, mpt);
1221 resp = do_retry_cancel_dialog(xmsg);
1222 lives_free(xmsg); lives_free(msg);
1223 lives_free(cs); lives_free(vs);
1224 }
1225 } while (resp == LIVES_RESPONSE_RETRY);
1226 if (resp == LIVES_RESPONSE_CANCEL) {
1227 badfile = TRUE;
1228 }
1229 }
1230 }
1231 if (!badfile) {
1232 /// move file to its final destination
1233 LiVESResponseType resp;
1234 req->do_update = FALSE;
1235 if (tmpdir) {
1236 if (lives_mv(from, dest)) {
1237 lives_free(from);
1238 lives_free(dest);
1239 badfile = TRUE;
1240 goto cleanup_ut;
1241 }
1242 }
1243 do {
1244 resp = LIVES_RESPONSE_NONE;
1245 if (!lives_file_test(dest, LIVES_FILE_TEST_EXISTS)) {
1246 char *errtxt = lives_strdup_printf(_("Failed to move %s to %s\n"), from, dest);
1247 resp = do_write_failed_error_s_with_retry(dest, errtxt);
1248 lives_free(errtxt);
1249 }
1250 } while (resp == LIVES_RESPONSE_RETRY);
1251 if (resp == LIVES_RESPONSE_CANCEL) {
1252 badfile = TRUE;
1253 }
1254 }
1255 lives_free(from);
1256 }
1257 }
1258
1259 if (badfile) {
1260 lives_kill_subprocesses(cfile->handle, TRUE);
1261 if (mainw->error) {
1262 d_print_failed();
1263 do_error_dialog(
1264 _("\nLiVES was unable to download the clip.\nPlease check the clip URL and make sure you have \n"
1265 "the latest youtube-dl installed.\n(Note: try right-clicking on the clip itself to copy its address)\n"));
1266 mainw->error = FALSE;
1267 }
1268 }
1269
1270 cleanup_ut:
1271 close_temp_handle(current_file);
1272 lives_freep((void **)&mpt);
1273
1274 if (manage_ds) {
1275 lives_storage_status_t dstat;
1276 boolean recheck = FALSE;
1277 boolean tempdir_removed = FALSE;
1278 int64_t dsu = -1;
1279 if (prefs->disk_quota) {
1280 size_t wdlen = lives_strlen(prefs->workdir);
1281 size_t tlen = lives_strlen(req->save_dir);
1282 if (tlen >= wdlen && lives_strncmp(req->save_dir, prefs->workdir, wdlen)) {
1283 dsu = capable->ds_used = get_dir_size(prefs->workdir);
1284 }
1285 }
1286 dstat = mainw->ds_status = get_storage_status(prefs->workdir, mainw->next_ds_warn_level, &dsu, 0);
1287 capable->ds_free = dsu;
1288 THREADVAR(com_failed) = FALSE;
1289 if (dstat != LIVES_STORAGE_STATUS_NORMAL) {
1290 // Houston, we hava problem !
1291 if (!forcecheck) recheck = TRUE;
1292 if (tmpdir) {
1293 /// remove tmpdir and re-check
1294 lives_freep((void **)&mpt);
1295 mpt = get_mountpoint_for(tmpdir);
1296 if (!lives_strcmp(mpt, capable->mountpoint)) {
1297 tempdir_removed = TRUE;
1298 lives_rmdir(tmpdir, TRUE);
1299 if (!THREADVAR(com_failed)) {
1300 recheck = TRUE;
1301 // *INDENT-OFF*
1302 }}}}
1303 // *INDENT-ON*
1304
1305 if (recheck) {
1306 if (prefs->disk_quota) {
1307 mainw->dsu_valid = TRUE;
1308 dsu = capable->ds_used = get_dir_size(prefs->workdir);
1309 }
1310 dstat = mainw->ds_status = get_storage_status(prefs->workdir, mainw->next_ds_warn_level, &dsu, 0);
1311 capable->ds_free = dsu;
1312 }
1313 if (dstat != LIVES_STORAGE_STATUS_NORMAL) {
1314 if (!tempdir_removed) {
1315 if (tmpdir) {
1316 /// remove tmpdir and re-check
1317 lives_freep((void **)&mpt);
1318 mpt = get_mountpoint_for(tmpdir);
1319 if (!lives_strcmp(mpt, capable->mountpoint)) {
1320 lives_rmdir(tmpdir, TRUE);
1321 if (!THREADVAR(com_failed)) {
1322 if (prefs->disk_quota) {
1323 dsu = capable->ds_used = get_dir_size(prefs->workdir);
1324 }
1325 dstat = mainw->ds_status = get_storage_status(prefs->workdir, mainw->next_ds_warn_level, &dsu, 0);
1326 capable->ds_free = dsu;
1327 // *INDENT-OFF*
1328 }}}}}
1329 // *INDENT-ON*
1330 if (dstat != LIVES_STORAGE_STATUS_NORMAL) {
1331 /// iff critical, delete file
1332 // we should probably offer if warn or quota too
1333 if (mainw->ds_status == LIVES_STORAGE_STATUS_CRITICAL && dest) {
1334 lives_rm(dest);
1335 badfile = TRUE;
1336 }
1337 if (!check_storage_space(-1, FALSE)) {
1338 badfile = TRUE;
1339 }
1340 }
1341 }
1342
1343 mainw->img_concat_clip = -1;
1344 mainw->no_switch_dprint = FALSE;
1345
1346 if (dest) {
1347 if (!badfile) {
1348 open_file(dest);
1349 if (mainw->multitrack) {
1350 polymorph(mainw->multitrack, POLY_NONE);
1351 polymorph(mainw->multitrack, POLY_CLIPS);
1352 mt_sensitise(mainw->multitrack);
1353 }
1354 }
1355 lives_free(dest);
1356 }
1357 if (mainw->multitrack) {
1358 maybe_add_mt_idlefunc();
1359 }
1360 return reqout;
1361 }
1362
1363
1364 void on_stop_clicked(LiVESMenuItem * menuitem, livespointer user_data) {
1365 // 'enough' button for open, open location, and record audio
1366
1367 #ifdef ENABLE_JACK
1368 if (mainw->jackd && mainw->jackd_read && mainw->jackd_read->in_use) {
1369 mainw->cancelled = CANCEL_KEEP;
1370 return;
1371 }
1372 #endif
1373 #ifdef HAVE_PULSE_AUDIO
1374 if (mainw->pulsed && mainw->pulsed_read && mainw->pulsed_read->in_use) {
1375 mainw->cancelled = CANCEL_KEEP;
1376 return;
1377 }
1378 #endif
1379
1380 if (CURRENT_CLIP_IS_VALID) {
1381 lives_kill_subprocesses(cfile->handle, FALSE);
1382 if (mainw->proc_ptr) {
1383 if (mainw->proc_ptr->stop_button)
1384 lives_widget_set_sensitive(mainw->proc_ptr->stop_button, FALSE);
1385 lives_widget_set_sensitive(mainw->proc_ptr->pause_button, FALSE);
1386 lives_widget_set_sensitive(mainw->proc_ptr->preview_button, FALSE);
1387 lives_widget_set_sensitive(mainw->proc_ptr->cancel_button, FALSE);
1388 }
1389 }
1390
1391 // resume to allow return
1392 if (mainw->effects_paused && CURRENT_CLIP_IS_VALID) {
1393 lives_suspend_resume_process(cfile->handle, FALSE);
1394 }
1395 }
1396
1397
1398 void on_save_as_activate(LiVESMenuItem * menuitem, livespointer user_data) {
1399 if (cfile->frames == 0) {
1400 on_export_audio_activate(NULL, NULL);
1401 return;
1402 }
1403 save_file(mainw->current_file, cfile->start, cfile->end, NULL);
1404 }
1405
1406
1407 #ifdef LIBAV_TRANSCODE
1408 void on_transcode_activate(LiVESMenuItem * menuitem, livespointer user_data) {
1409 if (!CURRENT_CLIP_IS_VALID) return;
1410 transcode_clip(cfile->start, cfile->end, FALSE, NULL);
1411 }
1412 #endif
1413
1414
1415 void on_save_selection_activate(LiVESMenuItem * menuitem, livespointer user_data) {
1416 if (!CURRENT_CLIP_IS_VALID) return;
1417 save_file(mainw->current_file, cfile->start, cfile->end, NULL);
1418 }
1419
1420
1421 static void check_remove_layout_files(void) {
1422 if (prompt_remove_layout_files()) {
1423 // delete layout directory
1424 char *laydir = lives_build_filename(prefs->workdir, mainw->set_name, LAYOUTS_DIRNAME, NULL);
1425 lives_rmdir(laydir, TRUE);
1426 lives_free(laydir);
1427 d_print(_("Layouts were removed for set %s.\n"), mainw->set_name);
1428 }
1429 }
1430
1431
1432 void on_close_activate(LiVESMenuItem * menuitem, livespointer user_data) {
1433 char *warn, *extra;
1434 boolean lmap_errors = FALSE, acurrent = FALSE, only_current = FALSE;
1435 mainw->mt_needs_idlefunc = FALSE;
1436
1437 if (mainw->multitrack) {
1438 if (mainw->multitrack->idlefunc > 0) {
1439 lives_source_remove(mainw->multitrack->idlefunc);
1440 mainw->multitrack->idlefunc = 0;
1441 mainw->mt_needs_idlefunc = TRUE;
1442 }
1443 mt_desensitise(mainw->multitrack);
1444 mainw->current_file = mainw->multitrack->file_selected;
1445 } else desensitize();
1446
1447 if (!(prefs->warning_mask & WARN_MASK_LAYOUT_CLOSE_FILE)) {
1448 mainw->xlays = layout_frame_is_affected(mainw->current_file, 1, 0, mainw->xlays);
1449 mainw->xlays = layout_audio_is_affected(mainw->current_file, 0., 0., mainw->xlays);
1450
1451 acurrent = used_in_current_layout(mainw->multitrack, mainw->current_file);
1452 if (acurrent) {
1453 if (!mainw->xlays) only_current = TRUE;
1454 mainw->xlays = lives_list_append_unique(mainw->xlays, mainw->string_constants[LIVES_STRING_CONSTANT_CL]);
1455 }
1456
1457 if (mainw->xlays) {
1458 char *title = get_menu_name(cfile, FALSE);
1459 if (strlen(title) > 128) {
1460 lives_free(title);
1461 title = (_("This file"));
1462 }
1463 if (acurrent) extra = (_(",\n - including the current layout - "));
1464 else extra = lives_strdup("");
1465 if (!only_current) warn = lives_strdup_printf(_("\n%s\nis used in some multitrack layouts%s.\n\nReally close it ?"),
1466 title, extra);
1467 else warn = lives_strdup_printf(_("\n%s\nis used in the current layout.\n\nReally close it ?"), title);
1468 lives_free(title);
1469 lives_free(extra);
1470 if (!do_warning_dialog(warn)) {
1471 lives_free(warn);
1472 lives_list_free_all(&mainw->xlays);
1473 goto close_done;
1474 }
1475 lives_free(warn);
1476 add_lmap_error(LMAP_ERROR_CLOSE_FILE, cfile->name, cfile->layout_map, 0, 1, 0., acurrent);
1477 lmap_errors = TRUE;
1478 lives_list_free_all(&mainw->xlays);
1479 }
1480 }
1481 if (!lmap_errors) {
1482 if (cfile->changed) {
1483 if (!do_close_changed_warn()) {
1484 goto close_done;
1485 }
1486 }
1487 }
1488
1489 if (mainw->sl_undo_mem && (cfile->stored_layout_frame != 0 || cfile->stored_layout_audio != 0.)) {
1490 // need to invalidate undo/redo stack, in case file was used in some layout undo
1491 stored_event_list_free_undos();
1492 }
1493
1494 if (mainw->multitrack) {
1495 event_list_free_undos(mainw->multitrack);
1496 }
1497
1498 close_current_file(0);
1499
1500 if (mainw->multitrack) {
1501 mainw->current_file = mainw->multitrack->render_file;
1502 polymorph(mainw->multitrack, POLY_NONE);
1503 polymorph(mainw->multitrack, POLY_CLIPS);
1504 if (mainw->multitrack->event_list) only_current = FALSE;
1505 }
1506
1507 if (lmap_errors && !only_current && mainw->cliplist) popup_lmap_errors(NULL, NULL);
1508
1509 if (!mainw->cliplist && *mainw->set_name) {
1510 boolean has_layout_map = FALSE;
1511
1512 // check for layout maps
1513 if (mainw->current_layouts_map) {
1514 has_layout_map = TRUE;
1515 }
1516
1517 if (has_layout_map) {
1518 check_remove_layout_files();
1519 recover_layout_cancelled(FALSE);
1520 }
1521 // the user closed the last clip in the set, we should remove the set
1522 d_print(_("Removing set %s since it is now empty..."));
1523 cleanup_set_dir(mainw->set_name);
1524 lives_memset(mainw->set_name, 0, 1);
1525 mainw->was_set = FALSE;
1526 lives_widget_set_sensitive(mainw->vj_load_set, TRUE);
1527 d_print_done();
1528 }
1529
1530 close_done:
1531 if (mainw->multitrack) {
1532 mt_sensitise(mainw->multitrack);
1533 maybe_add_mt_idlefunc();
1534 } else sensitize();
1535 }
1536
1537
1538 void on_import_proj_activate(LiVESMenuItem * menuitem, livespointer user_data) {
1539 char *com;
1540 char *filt[] = {"*."LIVES_FILE_EXT_PROJECT, NULL};
1541 char *proj_file = choose_file(NULL, NULL, filt, LIVES_FILE_CHOOSER_ACTION_OPEN, NULL, NULL);
1542 char *new_set;
1543 char *set_dir;
1544 char *msg;
1545
1546 int current_file = mainw->current_file;
1547
1548 if (!proj_file) return;
1549 com = lives_strdup_printf("%s get_proj_set \"%s\"", prefs->backend_sync, proj_file);
1550 lives_popen(com, FALSE, mainw->msg, MAINW_MSG_SIZE);
1551 lives_free(com);
1552
1553 if (THREADVAR(com_failed)) {
1554 THREADVAR(com_failed) = FALSE;
1555 lives_free(proj_file);
1556 return;
1557 }
1558
1559 if (!(*mainw->msg)) {
1560 lives_free(proj_file);
1561 widget_opts.non_modal = TRUE;
1562 do_error_dialog(_("\nInvalid project file.\n"));
1563 widget_opts.non_modal = FALSE;
1564 return;
1565 }
1566
1567 if (!is_legal_set_name(mainw->msg, TRUE, FALSE)) return;
1568
1569 new_set = lives_strdup(mainw->msg);
1570 set_dir = lives_build_filename(prefs->workdir, new_set, NULL);
1571
1572 if (lives_file_test(set_dir, LIVES_FILE_TEST_IS_DIR)) {
1573 msg = lives_strdup_printf(
1574 _("\nA set called %s already exists.\nIn order to import this project, you must rename or delete the existing set.\n"
1575 "You can do this by File|Reload Set, and giving the set name\n%s\n"
1576 "then File|Close/Save all Clips and provide a new set name or discard it.\n"
1577 "Once you have done this, you will be able to import the new project.\n"),
1578 new_set, new_set);
1579 do_error_dialog(msg);
1580 lives_free(msg);
1581 lives_free(proj_file);
1582 lives_free(set_dir);
1583 lives_free(new_set);
1584 return;
1585 }
1586
1587 lives_free(set_dir);
1588
1589 d_print(_("Importing the project %s as set %s..."), proj_file, new_set);
1590
1591 if (!get_temp_handle(-1)) {
1592 lives_free(proj_file);
1593 lives_free(new_set);
1594 d_print_failed();
1595 return;
1596 }
1597
1598 com = lives_strdup_printf("%s import_project \"%s\" \"%s\"", prefs->backend, cfile->handle, proj_file);
1599 lives_system(com, FALSE);
1600 lives_free(com);
1601 lives_free(proj_file);
1602
1603 if (THREADVAR(com_failed)) {
1604 mainw->current_file = close_temp_handle(current_file);
1605 lives_free(new_set);
1606 d_print_failed();
1607 return;
1608 }
1609
1610 do_progress_dialog(TRUE, FALSE, _("Importing project"));
1611
1612 mainw->current_file = close_temp_handle(current_file);
1613 sensitize();
1614
1615 if (mainw->error) {
1616 lives_free(new_set);
1617 d_print_failed();
1618 return;
1619 }
1620
1621 d_print_done();
1622
1623 reload_set(new_set);
1624 lives_free(new_set);
1625 }
1626
1627
1628 void on_export_proj_activate(LiVESMenuItem * menuitem, livespointer user_data) {
1629 char *filt[] = {"*."LIVES_FILE_EXT_PROJECT, NULL};
1630 char *def_file;
1631 char *proj_file;
1632 char *com, *tmp;
1633
1634 if (!*mainw->set_name) {
1635 int response;
1636 char new_set_name[MAX_SET_NAME_LEN];
1637 do {
1638 // prompt for a set name, advise user to save set
1639 renamew = create_rename_dialog(5);
1640 lives_widget_show_all(renamew->dialog);
1641 response = lives_dialog_run(LIVES_DIALOG(renamew->dialog));
1642 if (response == LIVES_RESPONSE_CANCEL) {
1643 mainw->cancelled = CANCEL_USER;
1644 return;
1645 }
1646 lives_snprintf(new_set_name, MAX_SET_NAME_LEN, "%s", (tmp = U82F(lives_entry_get_text(LIVES_ENTRY(renamew->entry)))));
1647 lives_widget_destroy(renamew->dialog);
1648 lives_freep((void **)&renamew);
1649 lives_free(tmp);
1650 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
1651
1652 } while (!is_legal_set_name(new_set_name, FALSE, FALSE));
1653 lives_snprintf(mainw->set_name, MAX_SET_NAME_LEN, "%s", new_set_name);
1654 }
1655
1656 if (mainw->stored_event_list && mainw->stored_event_list_changed) {
1657 if (!check_for_layout_del(NULL, FALSE)) return;
1658 }
1659
1660 if (mainw->sl_undo_mem) stored_event_list_free_undos();
1661
1662 if (!mainw->was_set) {
1663 mainw->no_exit = TRUE;
1664 if (!on_save_set_activate(NULL, NULL)) return;
1665 mainw->no_exit = FALSE;
1666 mainw->was_set = TRUE;
1667 if (mainw->multitrack && !mainw->multitrack->changed) recover_layout_cancelled(FALSE);
1668 }
1669
1670 def_file = lives_strdup_printf("%s.%s", mainw->set_name, LIVES_FILE_EXT_PROJECT);
1671 proj_file = choose_file(NULL, def_file, filt, LIVES_FILE_CHOOSER_ACTION_SAVE, NULL, NULL);
1672 lives_free(def_file);
1673
1674 if (!proj_file) return;
1675
1676 lives_rm((tmp = lives_filename_from_utf8(proj_file, -1, NULL, NULL, NULL)));
1677 lives_free(tmp);
1678
1679 d_print(_("Exporting project %s..."), proj_file);
1680
1681 com = lives_strdup_printf("%s export_project \"%s\" \"%s\" \"%s\"", prefs->backend, cfile->handle, mainw->set_name, proj_file);
1682 lives_system(com, FALSE);
1683 lives_free(com);
1684
1685 if (THREADVAR(com_failed)) {
1686 lives_free(proj_file);
1687 d_print_failed();
1688 return;
1689 }
1690
1691 do_progress_dialog(TRUE, FALSE, _("Exporting project"));
1692
1693 if (mainw->error) d_print_failed();
1694 else d_print_done();
1695
1696 lives_free(proj_file);
1697 }
1698
1699
1700 void on_export_theme_activate(LiVESMenuItem * menuitem, livespointer user_data) {
1701 lives_colRGBA64_t lcol;
1702
1703 char *filt[] = {"*."LIVES_FILE_EXT_TAR_GZ, NULL};
1704
1705 char theme_name[128];
1706
1707 char *file_name, *tmp, *tmp2, *com, *fname;
1708 char *sepimg_ext, *frameimg_ext, *sepimg, *frameimg;
1709 char *themedir, *thfile, *themefile;
1710 char *pstyle;
1711
1712 int response;
1713
1714 desensitize();
1715
1716 do {
1717 // prompt for a set name, advise user to save set
1718 renamew = create_rename_dialog(8);
1719 lives_widget_show_all(renamew->dialog);
1720 response = lives_dialog_run(LIVES_DIALOG(renamew->dialog));
1721 if (response == LIVES_RESPONSE_CANCEL) return;
1722 lives_snprintf(theme_name, 128, "%s", (tmp = U82F(lives_entry_get_text(LIVES_ENTRY(renamew->entry)))));
1723 lives_widget_destroy(renamew->dialog);
1724 lives_freep((void **)&renamew);
1725 lives_free(tmp);
1726 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
1727
1728 } while (!do_std_checks(U82F(theme_name), _("Theme"), 64, NULL));
1729
1730 fname = lives_strdup_printf("%s.%s", theme_name, LIVES_FILE_EXT_TAR_GZ);
1731
1732 file_name = choose_file(capable->home_dir, fname, filt,
1733 LIVES_FILE_CHOOSER_ACTION_SAVE, _("Choose a directory to export to"), NULL);
1734
1735 lives_free(fname);
1736
1737 if (!file_name) {
1738 return;
1739 }
1740
1741 lives_set_cursor_style(LIVES_CURSOR_BUSY, NULL);
1742 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
1743
1744 // create a header.theme file in tmp, then zip it up with the images
1745
1746 sepimg_ext = get_extension(mainw->sepimg_path);
1747 frameimg_ext = get_extension(mainw->frameblank_path);
1748
1749 thfile = lives_strdup_printf("%s%d", THEME_LITERAL, capable->mainpid);
1750 themedir = lives_build_filename(prefs->workdir, thfile, NULL);
1751 themefile = lives_build_filename(themedir, THEME_HEADER, NULL);
1752 #ifdef GUI_GTK
1753 #if !GTK_CHECK_VERSION(3, 0, 0)
1754 lives_free(themefile);
1755 themefile = lives_build_filename(themedir, THEME_HEADER_2, NULL);
1756 #endif
1757 #endif
1758 lives_free(thfile);
1759
1760 thfile = lives_strdup_printf("%s.%s", THEME_SEP_IMG_LITERAL, sepimg_ext);
1761 sepimg = lives_build_filename(themedir, thfile, NULL);
1762 lives_free(thfile);
1763
1764 thfile = lives_strdup_printf("%s.%s", THEME_FRAME_IMG_LITERAL, frameimg_ext);
1765 frameimg = lives_build_filename(themedir, thfile, NULL);
1766
1767 lives_free(sepimg_ext);
1768 lives_free(frameimg_ext);
1769
1770 lives_mkdir_with_parents(themedir, capable->umask);
1771
1772 set_theme_pref(themefile, THEME_DETAIL_NAME, theme_name);
1773
1774 pstyle = lives_strdup_printf("%d", palette->style);
1775 set_theme_pref(themefile, THEME_DETAIL_STYLE, pstyle);
1776 lives_free(pstyle);
1777
1778 widget_color_to_lives_rgba(&lcol, &palette->normal_fore);
1779 set_theme_colour_pref(themefile, THEME_DETAIL_NORMAL_FORE, &lcol);
1780
1781 widget_color_to_lives_rgba(&lcol, &palette->normal_back);
1782 set_theme_colour_pref(themefile, THEME_DETAIL_NORMAL_BACK, &lcol);
1783
1784 widget_color_to_lives_rgba(&lcol, &palette->menu_and_bars_fore);
1785 set_theme_colour_pref(themefile, THEME_DETAIL_ALT_FORE, &lcol);
1786
1787 widget_color_to_lives_rgba(&lcol, &palette->menu_and_bars);
1788 set_theme_colour_pref(themefile, THEME_DETAIL_ALT_BACK, &lcol);
1789
1790 widget_color_to_lives_rgba(&lcol, &palette->info_text);
1791 set_theme_colour_pref(themefile, THEME_DETAIL_INFO_TEXT, &lcol);
1792
1793 widget_color_to_lives_rgba(&lcol, &palette->info_base);
1794 set_theme_colour_pref(themefile, THEME_DETAIL_INFO_BASE, &lcol);
1795
1796 if (mainw->fx1_bool) {
1797 widget_color_to_lives_rgba(&lcol, &palette->mt_timecode_fg);
1798 set_theme_colour_pref(themefile, THEME_DETAIL_MT_TCFG, &lcol);
1799
1800 widget_color_to_lives_rgba(&lcol, &palette->mt_timecode_bg);
1801 set_theme_colour_pref(themefile, THEME_DETAIL_MT_TCBG, &lcol);
1802
1803 set_theme_colour_pref(themefile, THEME_DETAIL_AUDCOL, &palette->audcol);
1804 set_theme_colour_pref(themefile, THEME_DETAIL_VIDCOL, &palette->vidcol);
1805 set_theme_colour_pref(themefile, THEME_DETAIL_FXCOL, &palette->fxcol);
1806
1807 set_theme_colour_pref(themefile, THEME_DETAIL_MT_TLREG, &palette->mt_timeline_reg);
1808 set_theme_colour_pref(themefile, THEME_DETAIL_MT_MARK, &palette->mt_mark);
1809 set_theme_colour_pref(themefile, THEME_DETAIL_MT_EVBOX, &palette->mt_evbox);
1810
1811 set_theme_colour_pref(themefile, THEME_DETAIL_FRAME_SURROUND, &palette->frame_surround);
1812
1813 set_theme_colour_pref(themefile, THEME_DETAIL_CE_SEL, &palette->ce_sel);
1814 set_theme_colour_pref(themefile, THEME_DETAIL_CE_UNSEL, &palette->ce_unsel);
1815 }
1816
1817 lives_free(themefile);
1818
1819 d_print(_("Exporting theme as %s..."), file_name);
1820
1821 // copy images for packaging
1822 lives_cp(mainw->sepimg_path, sepimg);
1823 lives_free(sepimg);
1824
1825 if (THREADVAR(com_failed)) {
1826 lives_rmdir(themedir, TRUE);
1827 lives_free(frameimg);
1828 lives_free(file_name);
1829 lives_free(themedir);
1830 d_print_failed();
1831 sensitize();
1832 return;
1833 }
1834
1835 lives_cp(mainw->frameblank_path, frameimg);
1836 lives_free(frameimg);
1837
1838 if (THREADVAR(com_failed)) {
1839 lives_rmdir(themedir, TRUE);
1840 lives_free(file_name);
1841 lives_free(themedir);
1842 d_print_failed();
1843 sensitize();
1844 return;
1845 }
1846
1847 com = lives_strdup_printf("%s create_package \"%s\" \"%s\"", prefs->backend_sync,
1848 (tmp = lives_filename_from_utf8(file_name, -1, NULL, NULL, NULL)),
1849 (tmp2 = lives_filename_from_utf8(themedir, -1, NULL, NULL, NULL)));
1850
1851 lives_free(tmp);
1852 lives_free(tmp2);
1853 lives_free(file_name);
1854
1855 lives_system(com, TRUE);
1856 lives_free(com);
1857
1858 lives_rmdir(themedir, TRUE);
1859 lives_free(themedir);
1860
1861 if (THREADVAR(com_failed)) {
1862 d_print_failed();
1863 sensitize();
1864 return;
1865 }
1866
1867 d_print_done();
1868 sensitize();
1869 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
1870 }
1871
1872
1873 void on_import_theme_activate(LiVESMenuItem * menuitem, livespointer user_data) {
1874 char *filt[] = {"*."LIVES_FILE_EXT_TAR_GZ, NULL};
1875 char tname[128];
1876
1877 char *importcheckdir, *themeheader, *themedir;
1878 char *com;
1879 char *theme_file;
1880
1881 desensitize();
1882
1883 theme_file = choose_file(NULL, NULL, filt, LIVES_FILE_CHOOSER_ACTION_OPEN, NULL, NULL);
1884
1885 if (!theme_file) {
1886 sensitize();
1887 return;
1888 }
1889 lives_set_cursor_style(LIVES_CURSOR_BUSY, NULL);
1890 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
1891
1892
1893 importcheckdir = lives_build_filename(prefs->workdir, IMPORTS_DIRNAME, NULL);
1894 lives_rmdir(importcheckdir, TRUE);
1895
1896 // unpackage file to get the theme name
1897 com = lives_strdup_printf("%s import_package \"%s\" \"%s\"", prefs->backend_sync, U82F(theme_file), importcheckdir);
1898 lives_system(com, FALSE);
1899 lives_free(com);
1900
1901 if (THREADVAR(com_failed)) {
1902 lives_rmdir(importcheckdir, TRUE);
1903 lives_free(importcheckdir);
1904 lives_free(theme_file);
1905 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
1906 sensitize();
1907 return;
1908 }
1909
1910 themeheader = lives_build_filename(prefs->workdir, IMPORTS_DIRNAME, THEME_HEADER, NULL);
1911
1912 if (get_pref_from_file(themeheader, THEME_DETAIL_NAME, tname, 128) == LIVES_RESPONSE_NO) {
1913 // failed to get name
1914 lives_rmdir(importcheckdir, TRUE);
1915 lives_free(importcheckdir);
1916 lives_free(themeheader);
1917 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
1918 do_bad_theme_import_error(theme_file);
1919 lives_free(theme_file);
1920 sensitize();
1921 return;
1922 }
1923
1924 lives_rmdir(importcheckdir, TRUE);
1925 lives_free(importcheckdir);
1926 lives_free(themeheader);
1927
1928 d_print(_("Importing theme \"%s\" from %s..."), tname, theme_file);
1929
1930 if (!do_std_checks(U82F(tname), _("Theme"), 64, NULL)) {
1931 lives_free(theme_file);
1932 d_print_failed();
1933 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
1934 return;
1935 }
1936
1937 // check for existing dupes
1938
1939 themedir = lives_build_filename(prefs->config_datadir, PLUGIN_THEMES, tname, NULL);
1940
1941 if (lives_file_test(themedir, LIVES_FILE_TEST_IS_DIR)) {
1942 if (!do_theme_exists_warn(tname)) {
1943 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
1944 lives_free(themedir);
1945 lives_free(theme_file);
1946 d_print_failed();
1947 sensitize();
1948 return;
1949 }
1950 lives_rmdir(themedir, TRUE);
1951 }
1952
1953 // name was OK, unpack into custom dir
1954 com = lives_strdup_printf("%s import_package \"%s\" \"%s\"", prefs->backend_sync, U82F(theme_file), themedir);
1955 lives_system(com, FALSE);
1956 lives_free(com);
1957
1958 lives_free(theme_file);
1959
1960 if (THREADVAR(com_failed)) {
1961 lives_rmdir(themedir, TRUE);
1962 lives_free(themedir);
1963 d_print_failed();
1964 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
1965 sensitize();
1966 return;
1967 }
1968
1969 lives_free(themedir);
1970
1971 lives_snprintf(prefs->theme, 64, "%s", tname);
1972
1973 // try to set theme colours
1974 if (!set_palette_colours(TRUE)) {
1975 lives_snprintf(prefs->theme, 64, "%s", future_prefs->theme);
1976 d_print_failed();
1977 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
1978 sensitize();
1979 return;
1980 }
1981
1982 lives_snprintf(future_prefs->theme, 64, "%s", prefs->theme);
1983 set_string_pref(PREF_GUI_THEME, prefs->theme);
1984
1985 load_theme_images();
1986 pref_change_images();
1987 pref_change_colours();
1988 pref_change_xcolours();
1989
1990 d_print_done();
1991 sensitize();
1992 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
1993 }
1994
1995
1996 void on_backup_activate(LiVESMenuItem * menuitem, livespointer user_data) {
1997 char *filt[] = {"*."LIVES_FILE_EXT_BACKUP, NULL};
1998 char *file_name;
1999 char *defname, *text;
2000
2001 defname = lives_strdup_printf("%s.%s", cfile->name, LIVES_FILE_EXT_BACKUP);
2002
2003 text = lives_strdup_printf(_("Backup as %s File"), LIVES_FILE_EXT_BACKUP);
2004
2005 file_name = choose_file((*mainw->proj_save_dir) ? mainw->proj_save_dir : NULL, defname, filt,
2006 LIVES_FILE_CHOOSER_ACTION_SAVE, text, NULL);
2007
2008 lives_free(text);
2009 lives_free(defname);
2010
2011 if (!file_name) return;
2012
2013 backup_file(mainw->current_file, 1, cfile->frames, file_name);
2014
2015 lives_snprintf(mainw->proj_save_dir, PATH_MAX, "%s", file_name);
2016 get_dirname(mainw->proj_save_dir);
2017 lives_free(file_name);
2018 }
2019
2020
2021 void on_restore_activate(LiVESMenuItem * menuitem, livespointer user_data) {
2022 char *filt[] = {"*."LIVES_FILE_EXT_BACKUP, NULL};
2023 char *file_name, *text;
2024
2025 text = lives_strdup_printf(_("Restore %s File"), LIVES_FILE_EXT_BACKUP);
2026
2027 file_name = choose_file((*mainw->proj_load_dir) ? mainw->proj_load_dir : NULL, text, filt,
2028 LIVES_FILE_CHOOSER_ACTION_OPEN, text, NULL);
2029
2030 lives_free(text);
2031
2032 if (!file_name) return;
2033
2034 restore_file(file_name);
2035
2036 lives_snprintf(mainw->proj_load_dir, PATH_MAX, "%s", file_name);
2037 get_dirname(mainw->proj_load_dir);
2038 lives_free(file_name);
2039 check_storage_space(-1, FALSE);
2040 }
2041
2042
2043 void mt_memory_free(void) {
2044 int i;
2045
2046 threaded_dialog_spin(0.);
2047
2048 mainw->multitrack->no_expose = TRUE;
2049
2050 if (CURRENT_CLIP_HAS_AUDIO) {
2051 delete_audio_tracks(mainw->multitrack, mainw->multitrack->audio_draws, FALSE);
2052 if (mainw->multitrack->audio_vols) lives_list_free(mainw->multitrack->audio_vols);
2053 }
2054
2055 if (mainw->multitrack->video_draws) {
2056 for (i = 0; i < mainw->multitrack->num_video_tracks; i++) {
2057 delete_video_track(mainw->multitrack, i, FALSE);
2058 }
2059 lives_list_free(mainw->multitrack->video_draws);
2060 }
2061
2062 lives_widget_object_unref(mainw->multitrack->clip_scroll);
2063 lives_widget_object_unref(mainw->multitrack->in_out_box);
2064
2065 lives_list_free(mainw->multitrack->tl_marks);
2066
2067 if (mainw->multitrack->event_list) event_list_free(mainw->multitrack->event_list);
2068 mainw->multitrack->event_list = NULL;
2069
2070 if (mainw->multitrack->undo_mem) event_list_free_undos(mainw->multitrack);
2071
2072 recover_layout_cancelled(FALSE);
2073
2074 threaded_dialog_spin(0.);
2075 }
2076
2077
2078 void del_current_set(boolean exit_after) {
2079 char *msg;
2080 boolean moc = mainw->only_close, crec;
2081 mainw->only_close = !exit_after;
2082 set_string_pref(PREF_AR_CLIPSET, "");
2083 prefs->ar_clipset = FALSE;
2084
2085 if (mainw->multitrack) {
2086 event_list_free_undos(mainw->multitrack);
2087
2088 if (mainw->multitrack->event_list) {
2089 event_list_free(mainw->multitrack->event_list);
2090 mainw->multitrack->event_list = NULL;
2091 }
2092 }
2093
2094 // check for layout maps
2095 if (mainw->current_layouts_map) {
2096 check_remove_layout_files();
2097 }
2098
2099 if (mainw->multitrack && !mainw->only_close) mt_memory_free();
2100 else if (mainw->multitrack) wipe_layout(mainw->multitrack);
2101
2102 mainw->was_set = mainw->leave_files = mainw->leave_recovery = FALSE;
2103
2104 recover_layout_cancelled(FALSE);
2105
2106 if (mainw->clips_available) {
2107 if (*mainw->set_name)
2108 msg = lives_strdup_printf(_("Deleting set %s..."), mainw->set_name);
2109 else
2110 msg = lives_strdup(_("Deleting set..."));
2111 d_print(msg);
2112 lives_free(msg);
2113
2114 do_threaded_dialog(_("Deleting set"), FALSE);
2115 }
2116
2117 crec = prefs->crash_recovery;
2118 prefs->crash_recovery = FALSE;
2119
2120 // do a lot of cleanup, delete files
2121 lives_exit(0);
2122 prefs->crash_recovery = crec;
2123
2124 if (*mainw->set_name) {
2125 d_print(_("Set %s was permanently deleted from the disk.\n"), mainw->set_name);
2126 lives_memset(mainw->set_name, 0, 1);
2127 }
2128 mainw->only_close = moc;
2129 end_threaded_dialog();
2130 }
2131
2132
2133 void on_quit_activate(LiVESMenuItem * menuitem, livespointer user_data) {
2134 char *tmp;
2135 boolean legal_set_name;
2136
2137 mainw->mt_needs_idlefunc = FALSE;
2138
2139 if (user_data && LIVES_POINTER_TO_INT(user_data) == 1) {
2140 mainw->no_exit = TRUE;
2141 mainw->only_close = TRUE;
2142 } else {
2143 mainw->no_exit = FALSE;
2144 mainw->only_close = FALSE;
2145 }
2146
2147 // stop if playing
2148 if (LIVES_IS_PLAYING) {
2149 mainw->cancelled = CANCEL_APP_QUIT;
2150 mainw->only_close = mainw->is_exiting = FALSE;
2151 return;
2152 }
2153
2154 if (mainw->multitrack) {
2155 if (mainw->multitrack->idlefunc > 0) {
2156 lives_source_remove(mainw->multitrack->idlefunc);
2157 mainw->multitrack->idlefunc = 0;
2158 mainw->mt_needs_idlefunc = TRUE;
2159 }
2160 mt_desensitise(mainw->multitrack);
2161 }
2162
2163 if (mainw->multitrack && mainw->multitrack->event_list) {
2164 if (mainw->only_close) {
2165 if (!check_for_layout_del(mainw->multitrack, FALSE)) {
2166 if (mainw->multitrack) {
2167 mt_sensitise(mainw->multitrack);
2168 maybe_add_mt_idlefunc();
2169 }
2170 return;
2171 // *INDENT-OFF*
2172 }}}
2173 // *INDENT-ON*
2174
2175 if (mainw->stored_event_list && mainw->stored_event_list_changed) {
2176 if (!check_for_layout_del(NULL, FALSE)) {
2177 mainw->only_close = mainw->is_exiting = FALSE;
2178 return;
2179 }
2180 } else if (mainw->stored_layout_undos) {
2181 stored_event_list_free_undos();
2182 }
2183
2184 /// do not popup warning if set name is changed
2185 mainw->suppress_layout_warnings = TRUE;
2186
2187 if (!mainw->clips_available || (future_prefs->vj_mode && !mainw->no_exit)) {
2188 lives_exit(0);
2189 } else {
2190 char *set_name;
2191 _entryw *cdsw = create_cds_dialog(1);
2192 LiVESResponseType resp;
2193 do {
2194 legal_set_name = TRUE;
2195 lives_widget_show_all(cdsw->dialog);
2196 resp = lives_dialog_run(LIVES_DIALOG(cdsw->dialog));
2197
2198 if (resp == LIVES_RESPONSE_RETRY) continue;
2199
2200 if (resp == LIVES_RESPONSE_CANCEL) {
2201 lives_widget_destroy(cdsw->dialog);
2202 lives_free(cdsw);
2203 mainw->only_close = mainw->is_exiting = FALSE;
2204 if (mainw->multitrack) {
2205 mt_sensitise(mainw->multitrack);
2206 maybe_add_mt_idlefunc();
2207 }
2208 mainw->only_close = mainw->is_exiting = FALSE;
2209 return;
2210 }
2211 if (resp == LIVES_RESPONSE_ACCEPT) {
2212 // save set
2213 if ((legal_set_name = is_legal_set_name((set_name = U82F(lives_entry_get_text(LIVES_ENTRY(cdsw->entry)))),
2214 TRUE, FALSE))) {
2215 lives_widget_destroy(cdsw->dialog);
2216 lives_free(cdsw);
2217
2218 if (prefs->ar_clipset) set_string_pref(PREF_AR_CLIPSET, set_name);
2219 else set_string_pref(PREF_AR_CLIPSET, "");
2220
2221 mainw->leave_recovery = FALSE;
2222
2223 on_save_set_activate(NULL, (tmp = U82F(set_name)));
2224 lives_free(tmp);
2225 lives_free(set_name);
2226
2227 if (!mainw->no_exit) lives_exit(0);
2228
2229 if (mainw->multitrack) {
2230 mt_sensitise(mainw->multitrack);
2231 maybe_add_mt_idlefunc();
2232 }
2233 mainw->only_close = mainw->is_exiting = FALSE;
2234 if (mainw->cs_manage) lives_idle_add_simple(run_diskspace_dialog_idle, NULL);
2235 end_threaded_dialog();
2236 return;
2237 }
2238 resp = LIVES_RESPONSE_RETRY;
2239 lives_widget_hide(cdsw->dialog);
2240 lives_free(set_name);
2241 }
2242 if (resp == LIVES_RESPONSE_RESET) {
2243 char *what, *expl;
2244 // TODO
2245 //if (check_for_executable(&capable->has_gio, EXEC_GIO)) mainw->add_trash_rb = TRUE;
2246 if (mainw->was_set) {
2247 what = lives_strdup_printf(_("Set '%s'"), mainw->set_name);
2248 expl = lives_strdup("");
2249 } else {
2250 what = (_("All currently open clips"));
2251 expl = (_("<b>(Note: original source material will NOT be affected !)</b>"));
2252 widget_opts.use_markup = TRUE;
2253 }
2254 if (!do_warning_dialogf(_("\n\n%s will be permanently deleted from the disk.\nAre you sure ?\n\n%s"), what, expl)) {
2255 resp = LIVES_RESPONSE_ABORT;
2256 }
2257 widget_opts.use_markup = FALSE;
2258 lives_free(what); lives_free(expl);
2259 //mainw->add_trash_rb = FALSE;
2260 }
2261 } while (resp == LIVES_RESPONSE_ABORT || resp == LIVES_RESPONSE_RETRY);
2262
2263 lives_widget_destroy(cdsw->dialog);
2264 lives_free(cdsw);
2265
2266 // discard clipset
2267 del_current_set(!mainw->only_close);
2268 }
2269
2270 mainw->leave_recovery = TRUE;
2271 }
2272
2273
2274 // TODO - split into undo.c
2275 void on_undo_activate(LiVESWidget * menuitem, livespointer user_data) {
2276 char *com, *tmp;
2277
2278 boolean bad_header = FALSE;
2279 boolean retvalb;
2280
2281 int ostart = cfile->start;
2282 int oend = cfile->end;
2283 int current_file = mainw->current_file;
2284 int switch_file = current_file;
2285 int asigned, aendian;
2286 int i;
2287
2288 if (mainw->multitrack) return;
2289
2290 lives_widget_set_sensitive(mainw->undo, FALSE);
2291 lives_widget_set_sensitive(mainw->redo, TRUE);
2292 cfile->undoable = FALSE;
2293 cfile->redoable = TRUE;
2294 lives_widget_hide(mainw->undo);
2295 lives_widget_show(mainw->redo);
2296
2297 mainw->osc_block = TRUE;
2298
2299 d_print("");
2300
2301 if (menuitem) {
2302 mainw->no_switch_dprint = TRUE;
2303 d_print("%s...", lives_menu_item_get_text(LIVES_WIDGET(menuitem)));
2304 mainw->no_switch_dprint = FALSE;
2305 }
2306
2307 if (cfile->undo_action == UNDO_INSERT_SILENCE) {
2308 double start = cfile->undo1_dbl;
2309 // if old audio end < start then we want to delete from oae to end
2310 if (cfile->old_laudio_time < start) cfile->undo1_dbl = cfile->old_laudio_time;
2311 on_del_audio_activate(NULL, NULL);
2312 cfile->undo_action = UNDO_INSERT_SILENCE;
2313 set_redoable(_("Insert Silence"), TRUE);
2314 cfile->undo1_dbl = start;
2315 }
2316
2317 if (cfile->undo_action == UNDO_CUT || cfile->undo_action == UNDO_DELETE || cfile->undo_action == UNDO_DELETE_AUDIO) {
2318 int reset_achans = 0;
2319 lives_rm(cfile->info_file);
2320 if (cfile->achans != cfile->undo_achans) {
2321 if (cfile->audio_waveform) {
2322 for (i = 0; i < cfile->achans; lives_freep((void **)&cfile->audio_waveform[i++]));
2323 lives_freep((void **)&cfile->audio_waveform);
2324 lives_freep((void **)&cfile->aw_sizes);
2325 }
2326 }
2327
2328 cfile->arate = cfile->undo_arate;
2329 cfile->signed_endian = cfile->undo_signed_endian;
2330 cfile->achans = cfile->undo_achans;
2331 cfile->asampsize = cfile->undo_asampsize;
2332 cfile->arps = cfile->undo_arps;
2333
2334 if (cfile->frames == 0) {
2335 cfile->hsize = cfile->ohsize;
2336 cfile->vsize = cfile->ovsize;
2337 }
2338
2339 if (cfile->undo_action == UNDO_DELETE_AUDIO) {
2340 if (cfile->undo1_dbl == cfile->undo2_dbl && cfile->undo1_dbl == 0.) {
2341 // undo delete_all_audio
2342 reset_achans = cfile->undo_achans;
2343 com = lives_strdup_printf("%s undo_audio \"%s\"", prefs->backend_sync, cfile->handle);
2344 }
2345 // undo delete selected audio
2346 // (set with with_audio==2 [audio only],therfore start,end,where are in secs.; times==-1)
2347 else com = lives_strdup_printf("%s insert \"%s\" \"%s\" %.8f 0. %.8f \"%s\" 2 0 0 0 0 %d %d %d %d %d -1",
2348 prefs->backend,
2349 cfile->handle, get_image_ext_for_type(cfile->img_type), cfile->undo1_dbl,
2350 cfile->undo2_dbl - cfile->undo1_dbl, cfile->handle, cfile->arps, cfile->achans,
2351 cfile->asampsize, !(cfile->signed_endian & AFORM_UNSIGNED),
2352 !(cfile->signed_endian & AFORM_BIG_ENDIAN));
2353 } else {
2354 // undo cut or delete (times to insert is -1)
2355 // start,end, where are in frames
2356 cfile->undo1_boolean &= mainw->ccpd_with_sound;
2357 com = lives_strdup_printf("%s insert \"%s\" \"%s\" %d %d %d \"%s\" %d %d 0 0 %.3f %d %d %d %d %d -1",
2358 prefs->backend, cfile->handle,
2359 get_image_ext_for_type(cfile->img_type), cfile->undo_start - 1, cfile->undo_start,
2360 cfile->undo_end, cfile->handle, cfile->undo1_boolean, cfile->frames, cfile->fps,
2361 cfile->arps, cfile->achans, cfile->asampsize, !(cfile->signed_endian & AFORM_UNSIGNED),
2362 !(cfile->signed_endian & AFORM_BIG_ENDIAN));
2363
2364 }
2365
2366 lives_system(com, FALSE);
2367 lives_free(com);
2368
2369 if (THREADVAR(com_failed)) return;
2370
2371 // show a progress dialog, not cancellable
2372 do_progress_dialog(TRUE, FALSE, _("Undoing"));
2373
2374 if (mainw->error) {
2375 d_print_failed();
2376 //cfile->may_be_damaged=TRUE;
2377 return;
2378 }
2379
2380 if (cfile->undo_action != UNDO_DELETE_AUDIO) {
2381 cfile->insert_start = cfile->undo_start;
2382 cfile->insert_end = cfile->undo_end;
2383
2384 if (cfile->start >= cfile->undo_start) {
2385 cfile->start += cfile->undo_end - cfile->undo_start + 1;
2386 }
2387 if (cfile->end >= cfile->undo_start) {
2388 cfile->end += cfile->undo_end - cfile->undo_start + 1;
2389 }
2390
2391 cfile->frames += cfile->undo_end - cfile->undo_start + 1;
2392 if (cfile->frames > 0) {
2393 if (cfile->start == 0) {
2394 cfile->start = 1;
2395 }
2396 if (cfile->end == 0) {
2397 cfile->end = cfile->frames;
2398 }
2399 }
2400 if (cfile->frame_index_back) {
2401 restore_frame_index_back(mainw->current_file);
2402 }
2403 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_FRAMES, &cfile->frames)) bad_header = TRUE;
2404 showclipimgs();
2405 }
2406 if (reset_achans > 0) {
2407 if (cfile->audio_waveform) {
2408 for (i = 0; i < cfile->achans; lives_freep((void **)&cfile->audio_waveform[i++]));
2409 lives_freep((void **)&cfile->audio_waveform);
2410 lives_freep((void **)&cfile->aw_sizes);
2411 }
2412 asigned = !(cfile->signed_endian & AFORM_UNSIGNED);
2413 aendian = cfile->signed_endian & AFORM_BIG_ENDIAN;
2414 cfile->achans = reset_achans;
2415 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ACHANS, &cfile->achans)) bad_header = TRUE;
2416 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ARATE, &cfile->arps)) bad_header = TRUE;
2417 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_PB_ARATE, &cfile->arate)) bad_header = TRUE;
2418 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ASAMPS, &cfile->asampsize)) bad_header = TRUE;
2419 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_AENDIAN, &aendian)) bad_header = TRUE;
2420 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ASIGNED, &asigned)) bad_header = TRUE;
2421 }
2422
2423 showclipimgs();
2424
2425 if (bad_header) do_header_write_error(mainw->current_file);
2426 }
2427
2428 if (cfile->undo_action == UNDO_RESIZABLE || cfile->undo_action == UNDO_RENDER || cfile->undo_action == UNDO_EFFECT ||
2429 cfile->undo_action == UNDO_MERGE || (cfile->undo_action == UNDO_ATOMIC_RESAMPLE_RESIZE &&
2430 (cfile->frames != cfile->old_frames || cfile->hsize != cfile->ohsize ||
2431 cfile->vsize != cfile->ovsize || cfile->fps != cfile->undo1_dbl))) {
2432 char *audfile;
2433
2434 com = lives_strdup_printf("%s undo \"%s\" %d %d \"%s\"", prefs->backend, cfile->handle, cfile->undo_start, cfile->undo_end,
2435 get_image_ext_for_type(cfile->img_type));
2436 lives_rm(cfile->info_file);
2437 lives_system(com, FALSE);
2438 lives_free(com);
2439
2440 if (THREADVAR(com_failed)) return;
2441
2442 mainw->cancelled = CANCEL_NONE;
2443 mainw->error = FALSE;
2444
2445 // show a progress dialog, not cancellable
2446 cfile->progress_start = cfile->undo_start;
2447 cfile->progress_end = cfile->undo_end;
2448 do_progress_dialog(TRUE, FALSE, _("Undoing"));
2449
2450 if (cfile->undo_action == UNDO_RENDER || cfile->undo_action == UNDO_MERGE) {
2451 audfile = lives_get_audio_file_name(mainw->current_file);
2452 tmp = lives_strdup_printf("%s.%s", audfile, LIVES_FILE_EXT_BAK);
2453 lives_free(audfile);
2454 audfile = tmp;
2455 if (lives_file_test(audfile, LIVES_FILE_TEST_EXISTS)) {
2456 // restore overwritten audio
2457 com = lives_strdup_printf("%s undo_audio \"%s\"", prefs->backend_sync, cfile->handle);
2458 lives_rm(cfile->info_file);
2459 lives_system(com, FALSE);
2460 lives_free(com);
2461 if (THREADVAR(com_failed)) {
2462 lives_free(audfile);
2463 return;
2464 }
2465 retvalb = do_auto_dialog(_("Restoring audio"), 0);
2466 if (!retvalb) {
2467 d_print_failed();
2468 //cfile->may_be_damaged=TRUE;
2469 return;
2470 }
2471 }
2472 lives_free(audfile);
2473 }
2474
2475 if (cfile->frame_index_back) {
2476 int *tmpindex = cfile->frame_index;
2477 cfile->clip_type = CLIP_TYPE_FILE;
2478 cfile->frame_index = cfile->frame_index_back;
2479 if (cfile->undo_action == UNDO_RENDER) {
2480 do_threaded_dialog(_("Clearing frame images"), FALSE);
2481 clean_images_from_virtual(cfile, cfile->undo_start, cfile->undo_end);
2482 save_frame_index(mainw->current_file);
2483 cfile->frame_index_back = NULL;
2484 end_threaded_dialog();
2485 } else {
2486 save_frame_index(mainw->current_file);
2487 cfile->frame_index_back = tmpindex;
2488 }
2489 }
2490 }
2491
2492 if (cfile->undo_action == UNDO_ATOMIC_RESAMPLE_RESIZE && (cfile->frames != cfile->old_frames ||
2493 cfile->hsize != cfile->ohsize || cfile->vsize != cfile->ovsize)) {
2494
2495 if (cfile->frames > cfile->old_frames) {
2496 com = lives_strdup_printf("%s cut \"%s\" %d %d %d %d \"%s\" %.3f %d %d %d",
2497 prefs->backend, cfile->handle, cfile->old_frames + 1,
2498 cfile->frames, FALSE, cfile->frames, get_image_ext_for_type(cfile->img_type),
2499 cfile->fps, cfile->arate, cfile->achans, cfile->asampsize);
2500
2501 cfile->progress_start = cfile->old_frames + 1;
2502 cfile->progress_end = cfile->frames;
2503
2504 lives_rm(cfile->info_file);
2505 lives_system(com, FALSE);
2506 lives_free(com);
2507
2508 if (THREADVAR(com_failed)) return;
2509
2510 // show a progress dialog, not cancellable
2511 do_progress_dialog(TRUE, FALSE, _("Deleting excess frames"));
2512
2513 if (cfile->clip_type == CLIP_TYPE_FILE) {
2514 delete_frames_from_virtual(mainw->current_file, cfile->old_frames + 1, cfile->frames);
2515 }
2516 }
2517
2518 cfile->frames = cfile->old_frames;
2519 cfile->hsize = cfile->ohsize;
2520 cfile->vsize = cfile->ovsize;
2521 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_WIDTH, &cfile->hsize)) bad_header = TRUE;
2522 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_HEIGHT, &cfile->vsize)) bad_header = TRUE;
2523 cfile->fps = cfile->undo1_dbl;
2524 if (cfile->clip_type == CLIP_TYPE_FILE && cfile->ext_src) {
2525 lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
2526 double dfps = (double)cdata->fps;
2527 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_FPS, &dfps)) bad_header = TRUE;
2528 } else {
2529 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_FPS, &cfile->fps)) bad_header = TRUE;
2530 }
2531 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_PB_FPS, &cfile->fps)) bad_header = TRUE;
2532 cfile->redoable = FALSE;
2533 // force a resize in switch_to_file
2534 switch_file = 0;
2535
2536 if (bad_header) do_header_write_error(mainw->current_file);
2537 }
2538
2539 if (cfile->undo_action == UNDO_RENDER) {
2540 cfile->frames = cfile->old_frames;
2541 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_FRAMES, &cfile->frames)) bad_header = TRUE;
2542 showclipimgs();
2543 if (bad_header) do_header_write_error(mainw->current_file);
2544 }
2545
2546 if (cfile->undo_action == UNDO_INSERT || cfile->undo_action == UNDO_MERGE
2547 || cfile->undo_action == UNDO_INSERT_WITH_AUDIO) {
2548 boolean ccpd_with_sound = mainw->ccpd_with_sound;
2549 if (!(cfile->undo_action == UNDO_MERGE && cfile->insert_start == cfile->undo_start && cfile->insert_end == cfile->undo_end)) {
2550 if (cfile->undo_action == UNDO_MERGE) {
2551 if (cfile->insert_start == cfile->undo_start) {
2552 cfile->insert_start = cfile->undo_end + 1;
2553 }
2554 if (cfile->insert_end == cfile->undo_end) {
2555 cfile->insert_end = cfile->undo_start - 1;
2556 }
2557 }
2558 cfile->start = cfile->insert_start;
2559 cfile->end = cfile->insert_end;
2560
2561 if (cfile->undo_action == UNDO_INSERT_WITH_AUDIO) mainw->ccpd_with_sound = TRUE;
2562 else mainw->ccpd_with_sound = FALSE;
2563 on_delete_activate(NULL, NULL);
2564
2565 cfile->start = ostart;
2566 if (ostart >= cfile->insert_start) {
2567 cfile->start -= cfile->insert_end - cfile->insert_start + 1;
2568 if (cfile->start < cfile->insert_start - 1) {
2569 cfile->start = cfile->insert_start - 1;
2570 }
2571 }
2572 cfile->end = oend;
2573 if (oend >= cfile->insert_start) {
2574 cfile->end -= cfile->insert_end - cfile->insert_start + 1;
2575 if (cfile->end < cfile->insert_start - 1) {
2576 cfile->end = cfile->insert_start - 1;
2577 }
2578 }
2579 // TODO - use lives_clip_start macro
2580 if (cfile->start < 1) cfile->start = cfile->frames > 0 ? 1 : 0;
2581 if (cfile->end < 1) cfile->end = cfile->frames > 0 ? 1 : 0;
2582
2583 cfile->insert_start = cfile->insert_end = 0;
2584 }
2585 mainw->ccpd_with_sound = ccpd_with_sound;
2586 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_FRAMES, &cfile->frames)) bad_header = TRUE;
2587 showclipimgs();
2588 if (bad_header) do_header_write_error(mainw->current_file);
2589 }
2590
2591 if (cfile->undo_action == UNDO_REC_AUDIO) {
2592 mainw->fx1_val = cfile->arate;
2593 mainw->fx2_val = cfile->achans;
2594 mainw->fx3_val = cfile->asampsize;
2595 mainw->fx4_val = cfile->signed_endian;
2596 mainw->fx5_val = cfile->arps;
2597 }
2598
2599 if (cfile->undo_action == UNDO_AUDIO_RESAMPLE || cfile->undo_action == UNDO_REC_AUDIO ||
2600 cfile->undo_action == UNDO_FADE_AUDIO || cfile->undo_action == UNDO_AUDIO_VOL ||
2601 cfile->undo_action == UNDO_TRIM_AUDIO || cfile->undo_action == UNDO_APPEND_AUDIO ||
2602 (cfile->undo_action == UNDO_ATOMIC_RESAMPLE_RESIZE && cfile->arate != cfile->undo1_int)) {
2603 com = lives_strdup_printf("%s undo_audio \"%s\"", prefs->backend_sync, cfile->handle);
2604 mainw->cancelled = CANCEL_NONE;
2605 mainw->error = FALSE;
2606 lives_system(com, FALSE);
2607 lives_free(com);
2608
2609 if (THREADVAR(com_failed)) {
2610 reget_afilesize(mainw->current_file);
2611 d_print_failed();
2612 return;
2613 }
2614 if (!do_auto_dialog(_("Undoing"), 0)) {
2615 reget_afilesize(mainw->current_file);
2616 d_print_failed();
2617 return;
2618 }
2619 }
2620
2621 if ((cfile->undo_action == UNDO_AUDIO_RESAMPLE) || (cfile->undo_action == UNDO_ATOMIC_RESAMPLE_RESIZE &&
2622 cfile->arate != cfile->undo1_int)) {
2623 cfile->arate += cfile->undo1_int;
2624 cfile->undo1_int = cfile->arate - cfile->undo1_int;
2625 cfile->arate -= cfile->undo1_int;
2626
2627 cfile->achans += cfile->undo2_int;
2628 cfile->undo2_int = cfile->achans - cfile->undo2_int;
2629 cfile->achans -= cfile->undo2_int;
2630
2631 cfile->asampsize += cfile->undo3_int;
2632 cfile->undo3_int = cfile->asampsize - cfile->undo3_int;
2633 cfile->asampsize -= cfile->undo3_int;
2634
2635 cfile->arps += cfile->undo4_int;
2636 cfile->undo4_int = cfile->arps - cfile->undo4_int;
2637 cfile->arps -= cfile->undo4_int;
2638
2639 cfile->signed_endian += cfile->undo1_uint;
2640 cfile->undo1_uint = cfile->signed_endian - cfile->undo1_uint;
2641 cfile->signed_endian -= cfile->undo1_uint;
2642
2643 asigned = !(cfile->signed_endian & AFORM_UNSIGNED);
2644 aendian = cfile->signed_endian & AFORM_BIG_ENDIAN;
2645
2646 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ARATE, &cfile->arps)) bad_header = TRUE;
2647 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_PB_ARATE, &cfile->arate)) bad_header = TRUE;
2648 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ACHANS, &cfile->achans)) bad_header = TRUE;
2649 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ASAMPS, &cfile->asampsize)) bad_header = TRUE;
2650 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_AENDIAN, &aendian)) bad_header = TRUE;
2651 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ASIGNED, &asigned)) bad_header = TRUE;
2652
2653 if (bad_header) do_header_write_error(mainw->current_file);
2654 }
2655
2656 if (cfile->undo_action == UNDO_NEW_AUDIO) {
2657 lives_rm(cfile->info_file);
2658 com = lives_strdup_printf("%s undo_audio \"%s\"", prefs->backend_sync, cfile->handle);
2659 lives_system(com, FALSE);
2660 lives_free(com);
2661
2662 if (THREADVAR(com_failed)) return;
2663
2664 mainw->cancelled = CANCEL_NONE;
2665 mainw->error = FALSE;
2666
2667 if (!do_auto_dialog(_("Restoring audio"), 0)) {
2668 d_print_failed();
2669 return;
2670 }
2671
2672 if (cfile->achans != cfile->undo_achans) {
2673 if (cfile->audio_waveform) {
2674 for (i = 0; i < cfile->achans; lives_freep((void **)&cfile->audio_waveform[i++]));
2675 lives_freep((void **)&cfile->audio_waveform);
2676 lives_freep((void **)&cfile->aw_sizes);
2677 }
2678 }
2679
2680 cfile->achans = cfile->undo_achans;
2681 cfile->arate = cfile->undo_arate;
2682 cfile->arps = cfile->undo_arps;
2683 cfile->asampsize = cfile->undo_asampsize;
2684 cfile->signed_endian = cfile->undo_signed_endian;
2685
2686 asigned = !(cfile->signed_endian & AFORM_UNSIGNED);
2687 aendian = cfile->signed_endian & AFORM_BIG_ENDIAN;
2688
2689 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ARATE, &cfile->arps)) bad_header = TRUE;
2690 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_PB_ARATE, &cfile->arate)) bad_header = TRUE;
2691 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ACHANS, &cfile->achans)) bad_header = TRUE;
2692 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ASAMPS, &cfile->asampsize)) bad_header = TRUE;
2693 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_AENDIAN, &aendian)) bad_header = TRUE;
2694 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ASIGNED, &asigned)) bad_header = TRUE;
2695
2696 if (bad_header) do_header_write_error(mainw->current_file);
2697 }
2698
2699 if (cfile->undo_action == UNDO_CHANGE_SPEED) {
2700 cfile->fps += cfile->undo1_dbl;
2701 cfile->undo1_dbl = cfile->fps - cfile->undo1_dbl;
2702 cfile->fps -= cfile->undo1_dbl;
2703
2704 cfile->arate += cfile->undo1_int;
2705 cfile->undo1_int = cfile->arate - cfile->undo1_int;
2706 cfile->arate -= cfile->undo1_int;
2707 /// DON'T ! we only save the pb_fps now, since otherwise we may lose the orig. clip fps
2708 /* save_clip_value(mainw->current_file, CLIP_DETAILS_FPS, &cfile->fps); */
2709 if (cfile->clip_type == CLIP_TYPE_FILE && cfile->ext_src) {
2710 lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
2711 double dfps = (double)cdata->fps;
2712 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_FPS, &dfps)) bad_header = TRUE;
2713 } else {
2714 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_FPS, &cfile->fps)) bad_header = TRUE;
2715 }
2716 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_PB_FPS, &cfile->fps)) bad_header = TRUE;
2717 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_PB_ARATE, &cfile->arate)) bad_header = TRUE;
2718
2719 if (bad_header) do_header_write_error(mainw->current_file);
2720 }
2721
2722 if (cfile->undo_action == UNDO_INSERT || cfile->undo_action == UNDO_INSERT_WITH_AUDIO || cfile->undo_action == UNDO_MERGE ||
2723 cfile->undo_action == UNDO_NEW_AUDIO) {
2724 cfile->redoable = FALSE;
2725 }
2726
2727 if (menuitem) {
2728 mainw->no_switch_dprint = TRUE;
2729 d_print_done();
2730 mainw->no_switch_dprint = FALSE;
2731 }
2732
2733 if (cfile->undo_action == UNDO_RESAMPLE) {
2734 cfile->start = (int)((cfile->start - 1) / cfile->fps * cfile->undo1_dbl + 1.);
2735 if ((cfile->end = (int)(cfile->end / cfile->fps * cfile->undo1_dbl + .49999)) < 1) cfile->end = 1;
2736 cfile->fps += cfile->undo1_dbl;
2737 cfile->undo1_dbl = cfile->fps - cfile->undo1_dbl;
2738 cfile->fps -= cfile->undo1_dbl;
2739
2740 // deorder the frames
2741 cfile->frames = deorder_frames(cfile->old_frames, mainw->current_file == 0 && !prefs->conserve_space);
2742
2743 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_FRAMES, &cfile->frames)) bad_header = TRUE;
2744 if (cfile->clip_type == CLIP_TYPE_FILE && cfile->ext_src) {
2745 lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
2746 double dfps = (double)cdata->fps;
2747 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_FPS, &dfps)) bad_header = TRUE;
2748 } else {
2749 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_FPS, &cfile->fps)) bad_header = TRUE;
2750 }
2751 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_PB_FPS, &cfile->fps)) bad_header = TRUE;
2752
2753 if (bad_header) do_header_write_error(mainw->current_file);
2754
2755 if (mainw->current_file > 0) {
2756 com = lives_strdup_printf(_("Length of video is now %d frames at %.3f frames per second.\n"), cfile->frames, cfile->fps);
2757 } else {
2758 mainw->no_switch_dprint = TRUE;
2759 com = lives_strdup_printf(_("Clipboard was resampled to %d frames.\n"), cfile->frames);
2760 }
2761 d_print(com);
2762 lives_free(com);
2763 mainw->no_switch_dprint = FALSE;
2764 showclipimgs();
2765 }
2766
2767 if (cfile->end > cfile->frames) {
2768 cfile->end = cfile->frames;
2769 }
2770
2771 if (cfile->undo_action == UNDO_RESIZABLE) {
2772 cfile->vsize += cfile->ovsize;
2773 cfile->ovsize = cfile->vsize - cfile->ovsize;
2774 cfile->vsize -= cfile->ovsize;
2775 cfile->hsize += cfile->ohsize;
2776 cfile->ohsize = cfile->hsize - cfile->ohsize;
2777 cfile->hsize -= cfile->ohsize;
2778 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_WIDTH, &cfile->hsize)) bad_header = TRUE;
2779 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_HEIGHT, &cfile->vsize)) bad_header = TRUE;
2780
2781 // force a resize in switch_to_file
2782 switch_file = 0;
2783
2784 if (bad_header) do_header_write_error(mainw->current_file);
2785 }
2786
2787 if (current_file > 0) {
2788 switch_to_file((mainw->current_file = switch_file), current_file);
2789 }
2790
2791 if (cfile->undo_action == UNDO_RENDER) {
2792 if (mainw->event_list) event_list_free(mainw->event_list);
2793 mainw->event_list = cfile->event_list_back;
2794 cfile->event_list_back = NULL;
2795 deal_with_render_choice(FALSE);
2796 }
2797 mainw->osc_block = FALSE;
2798
2799 if (!mainw->multitrack) {
2800 reget_afilesize(mainw->current_file);
2801 if (CURRENT_CLIP_HAS_AUDIO) redraw_timeline(mainw->current_file);
2802 }
2803 }
2804
2805
2806 void on_redo_activate(LiVESWidget * menuitem, livespointer user_data) {
2807 char *com;
2808
2809 int ostart = cfile->start;
2810 int oend = cfile->end;
2811 int current_file = mainw->current_file;
2812 int i;
2813
2814 mainw->osc_block = TRUE;
2815
2816 cfile->undoable = TRUE;
2817 cfile->redoable = FALSE;
2818 lives_widget_hide(mainw->redo);
2819 lives_widget_show(mainw->undo);
2820 lives_widget_set_sensitive(mainw->undo, TRUE);
2821 lives_widget_set_sensitive(mainw->redo, FALSE);
2822
2823 d_print("");
2824
2825 if (menuitem) {
2826 mainw->no_switch_dprint = TRUE;
2827 d_print("%s...", lives_menu_item_get_text(menuitem));
2828 mainw->no_switch_dprint = FALSE;
2829 }
2830
2831 if (cfile->undo_action == UNDO_INSERT_SILENCE) {
2832 on_ins_silence_activate(NULL, NULL);
2833 mainw->osc_block = FALSE;
2834 mainw->no_switch_dprint = TRUE;
2835 d_print_done();
2836 mainw->no_switch_dprint = FALSE;
2837 sensitize();
2838 return;
2839 }
2840 if (cfile->undo_action == UNDO_CHANGE_SPEED) {
2841 on_change_speed_ok_clicked(NULL, NULL);
2842 mainw->osc_block = FALSE;
2843 d_print_done();
2844 return;
2845 }
2846 if (cfile->undo_action == UNDO_RESAMPLE) {
2847 on_resample_vid_ok(NULL, NULL);
2848 mainw->osc_block = FALSE;
2849 return;
2850 }
2851 if (cfile->undo_action == UNDO_AUDIO_RESAMPLE) {
2852 on_resaudio_ok_clicked(NULL, NULL);
2853 mainw->osc_block = FALSE;
2854 d_print_done();
2855 return;
2856 }
2857 if (cfile->undo_action == UNDO_CUT || cfile->undo_action == UNDO_DELETE) {
2858 cfile->start = cfile->undo_start;
2859 cfile->end = cfile->undo_end;
2860 mainw->osc_block = FALSE;
2861 }
2862 if (cfile->undo_action == UNDO_CUT) {
2863 on_cut_activate(NULL, NULL);
2864 mainw->osc_block = FALSE;
2865 }
2866 if (cfile->undo_action == UNDO_DELETE) {
2867 on_delete_activate(NULL, NULL);
2868 mainw->osc_block = FALSE;
2869 }
2870 if (cfile->undo_action == UNDO_DELETE_AUDIO) {
2871 on_del_audio_activate(NULL, NULL);
2872 mainw->osc_block = FALSE;
2873 d_print_done();
2874 return;
2875 }
2876 if (cfile->undo_action == UNDO_CUT || cfile->undo_action == UNDO_DELETE) {
2877 cfile->start = ostart;
2878 cfile->end = oend;
2879 if (mainw->current_file == current_file) {
2880 if (cfile->start >= cfile->undo_start) {
2881 cfile->start -= cfile->undo_end - cfile->undo_start + 1;
2882 if (cfile->start < cfile->undo_start - 1) {
2883 cfile->start = cfile->undo_start - 1;
2884 }
2885 }
2886 if (cfile->end >= cfile->undo_start) {
2887 cfile->end -= cfile->undo_end - cfile->undo_start + 1;
2888 if (cfile->end < cfile->undo_start - 1) {
2889 cfile->end = cfile->undo_start - 1;
2890 }
2891 }
2892 switch_to_file(mainw->current_file, mainw->current_file);
2893 }
2894 mainw->osc_block = FALSE;
2895 return;
2896 }
2897
2898 if (cfile->undo_action == UNDO_REC_AUDIO) {
2899 if (cfile->audio_waveform) {
2900 for (i = 0; i < cfile->achans; lives_freep((void **)&cfile->audio_waveform[i++]));
2901 lives_freep((void **)&cfile->audio_waveform);
2902 lives_freep((void **)&cfile->aw_sizes);
2903 }
2904 cfile->arate = mainw->fx1_val;
2905 cfile->achans = mainw->fx2_val;
2906 cfile->asampsize = mainw->fx3_val;
2907 cfile->signed_endian = mainw->fx4_val;
2908 cfile->arps = mainw->fx5_val;
2909 save_clip_values(mainw->current_file);
2910 }
2911
2912 if (cfile->undo_action == UNDO_REC_AUDIO || cfile->undo_action == UNDO_FADE_AUDIO
2913 || cfile->undo_action == UNDO_TRIM_AUDIO || cfile->undo_action == UNDO_AUDIO_VOL ||
2914 cfile->undo_action == UNDO_APPEND_AUDIO) {
2915 com = lives_strdup_printf("%s undo_audio \"%s\"", prefs->backend_sync, cfile->handle);
2916 lives_rm(cfile->info_file);
2917 lives_system(com, FALSE);
2918 lives_free(com);
2919
2920 if (THREADVAR(com_failed)) {
2921 reget_afilesize(mainw->current_file);
2922 d_print_failed();
2923 return;
2924 }
2925
2926 // show a progress dialog, not cancellable
2927 do_progress_dialog(TRUE, FALSE, _("Redoing"));
2928
2929 if (mainw->error) {
2930 reget_afilesize(mainw->current_file);
2931 d_print_failed();
2932 return;
2933 }
2934
2935 d_print_done();
2936 switch_to_file(mainw->current_file, mainw->current_file);
2937 mainw->osc_block = FALSE;
2938 return;
2939 }
2940
2941 com = lives_strdup_printf("%s redo \"%s\" %d %d \"%s\"", prefs->backend, cfile->handle, cfile->undo_start, cfile->undo_end,
2942 get_image_ext_for_type(cfile->img_type));
2943 lives_rm(cfile->info_file);
2944 lives_system(com, FALSE);
2945 lives_free(com);
2946
2947 if (THREADVAR(com_failed)) {
2948 d_print_failed();
2949 return;
2950 }
2951
2952 cfile->progress_start = cfile->undo_start;
2953 cfile->progress_end = cfile->undo_end;
2954
2955 // show a progress dialog, not cancellable
2956 do_progress_dialog(TRUE, FALSE, _("Redoing"));
2957 reget_afilesize(mainw->current_file);
2958
2959 if (mainw->error) {
2960 d_print_failed();
2961 return;
2962 }
2963
2964 if (cfile->clip_type == CLIP_TYPE_FILE && (cfile->undo_action == UNDO_EFFECT || cfile->undo_action == UNDO_RESIZABLE)) {
2965 int *tmpindex = cfile->frame_index;
2966 cfile->frame_index = cfile->frame_index_back;
2967 cfile->frame_index_back = tmpindex;
2968 cfile->clip_type = CLIP_TYPE_FILE;
2969 if (!check_if_non_virtual(mainw->current_file, 1, cfile->frames)) save_frame_index(mainw->current_file);
2970 }
2971
2972 if (cfile->undo_action == UNDO_RESIZABLE) {
2973 cfile->vsize += cfile->ovsize;
2974 cfile->ovsize = cfile->vsize - cfile->ovsize;
2975 cfile->vsize -= cfile->ovsize;
2976 cfile->hsize += cfile->ohsize;
2977 cfile->ohsize = cfile->hsize - cfile->ohsize;
2978 cfile->hsize -= cfile->ohsize;
2979 switch_to_file((mainw->current_file = 0), current_file);
2980 } else {
2981 if (cfile->end <= cfile->undo_end) load_end_image(cfile->end);
2982 if (cfile->start >= cfile->undo_start) load_start_image(cfile->start);
2983 }
2984
2985 d_print_done();
2986 mainw->osc_block = FALSE;
2987 }
2988
2989
2990 //////////////////////////////////////////////////
2991
2992 void on_copy_activate(LiVESMenuItem * menuitem, livespointer user_data) {
2993 char *com;
2994
2995 int current_file = mainw->current_file;
2996 int start, end;
2997 int i;
2998
2999 desensitize();
3000
3001 d_print(""); // force switchtext
3002
3003 if (mainw->ccpd_with_sound && cfile->achans > 0)
3004 d_print(_("Copying frames %d to %d (with sound) to the clipboard..."), cfile->start, cfile->end);
3005 else
3006 d_print(lives_strdup_printf(_("Copying frames %d to %d to the clipboard..."), cfile->start, cfile->end));
3007
3008 init_clipboard();
3009
3010 lives_rm(cfile->info_file);
3011 mainw->last_transition_loops = 1;
3012
3013 start = cfile->start;
3014 end = cfile->end;
3015
3016 if (cfile->clip_type == CLIP_TYPE_FILE) {
3017 // for virtual frames, we copy only the frame_index
3018 clipboard->clip_type = CLIP_TYPE_FILE;
3019 clipboard->interlace = cfile->interlace;
3020 clipboard->deinterlace = cfile->deinterlace;
3021 clipboard->frame_index = frame_index_copy(cfile->frame_index, end - start + 1, start - 1);
3022 clipboard->frames = end - start + 1;
3023 check_if_non_virtual(0, 1, clipboard->frames);
3024 if (clipboard->clip_type == CLIP_TYPE_FILE) {
3025 clipboard->ext_src = clone_decoder(mainw->current_file);
3026 clipboard->ext_src_type = LIVES_EXT_SRC_DECODER;
3027 end = -end; // allow missing frames
3028 lives_snprintf(clipboard->file_name, PATH_MAX, "%s", cfile->file_name);
3029 }
3030 }
3031
3032 mainw->fx1_val = 1;
3033 mainw->fx1_bool = FALSE;
3034
3035 clipboard->img_type = cfile->img_type;
3036
3037 // copy audio and frames
3038 com = lives_strdup_printf("%s insert \"%s\" \"%s\" 0 %d %d \"%s\" %d 0 0 0 %.3f %d %d %d %d %d", prefs->backend,
3039 clipboard->handle, get_image_ext_for_type(clipboard->img_type),
3040 start, end, cfile->handle, mainw->ccpd_with_sound, cfile->fps, cfile->arate,
3041 cfile->achans, cfile->asampsize, !(cfile->signed_endian & AFORM_UNSIGNED),
3042 !(cfile->signed_endian & AFORM_BIG_ENDIAN));
3043
3044 if (clipboard->clip_type == CLIP_TYPE_FILE) end = -end;
3045
3046 lives_system(com, FALSE);
3047 lives_free(com);
3048
3049 if (THREADVAR(com_failed)) {
3050 d_print_failed();
3051 sensitize();
3052 return;
3053 }
3054
3055 // we need to set this to look at the right info_file
3056 mainw->current_file = 0;
3057 cfile->progress_start = clipboard->start = 1;
3058 cfile->progress_end = clipboard->end = end - start + 1;
3059
3060 // stop the 'preview' and 'pause' buttons from appearing
3061 cfile->nopreview = TRUE;
3062 if (!do_progress_dialog(TRUE, TRUE, _("Copying to the clipboard"))) {
3063 #ifdef IS_MINGW
3064 // kill any active processes: for other OSes the backend does this
3065 lives_kill_subprocesses(cfile->handle, TRUE);
3066 #endif
3067
3068 // close clipboard, it is invalid
3069 mainw->current_file = CLIPBOARD_FILE;
3070 close_temp_handle(current_file);
3071
3072 sensitize();
3073 mainw->cancelled = CANCEL_USER;
3074 return;
3075 }
3076
3077 cfile->nopreview = FALSE;
3078 mainw->current_file = current_file;
3079
3080 //set all clipboard details
3081 clipboard->frames = clipboard->old_frames = clipboard->end;
3082 clipboard->hsize = cfile->hsize;
3083 clipboard->vsize = cfile->vsize;
3084 clipboard->bpp = cfile->bpp;
3085 clipboard->gamma_type = cfile->gamma_type;
3086 clipboard->undo1_dbl = clipboard->fps = cfile->fps;
3087 clipboard->ratio_fps = cfile->ratio_fps;
3088 clipboard->is_loaded = TRUE;
3089 lives_snprintf(clipboard->type, 40, "Frames");
3090
3091 clipboard->asampsize = clipboard->arate = clipboard->achans = 0;
3092 clipboard->afilesize = 0l;
3093
3094 if (mainw->ccpd_with_sound) {
3095 if (clipboard->audio_waveform) {
3096 for (i = 0; i < clipboard->achans; lives_freep((void **)&clipboard->audio_waveform[i++]));
3097 lives_freep((void **)&clipboard->audio_waveform);
3098 lives_freep((void **)&clipboard->aw_sizes);
3099 }
3100 clipboard->achans = cfile->achans;
3101 clipboard->asampsize = cfile->asampsize;
3102
3103 clipboard->arate = cfile->arate;
3104 clipboard->arps = cfile->arps;
3105 clipboard->signed_endian = cfile->signed_endian;
3106
3107 reget_afilesize(0);
3108 }
3109
3110 clipboard->start = 1;
3111 clipboard->end = clipboard->frames;
3112
3113 get_total_time(clipboard);
3114
3115 sensitize();
3116 d_print_done();
3117 }
3118
3119
3120 void on_cut_activate(LiVESMenuItem * menuitem, livespointer user_data) {
3121 uint32_t chk_mask = 0;
3122 int current_file = mainw->current_file;
3123
3124 if (menuitem) {
3125 char *tmp = (_("Cutting"));
3126 chk_mask = WARN_MASK_LAYOUT_DELETE_FRAMES | WARN_MASK_LAYOUT_SHIFT_FRAMES | WARN_MASK_LAYOUT_ALTER_FRAMES;
3127 if (mainw->ccpd_with_sound) chk_mask |= WARN_MASK_LAYOUT_DELETE_AUDIO | WARN_MASK_LAYOUT_SHIFT_AUDIO |
3128 WARN_MASK_LAYOUT_ALTER_AUDIO;
3129 if (!check_for_layout_errors(tmp, mainw->current_file, cfile->start, cfile->end, &chk_mask)) {
3130 lives_free(tmp);
3131 return;
3132 }
3133 lives_free(tmp);
3134 }
3135
3136 on_copy_activate(menuitem, user_data);
3137 if (mainw->cancelled) {
3138 unbuffer_lmap_errors(FALSE);
3139 return;
3140 }
3141
3142 on_delete_activate(NULL, user_data);
3143 if (mainw->current_file == current_file) {
3144 set_undoable(_("Cut"), TRUE);
3145 cfile->undo_action = UNDO_CUT;
3146 }
3147
3148 if (chk_mask != 0) popup_lmap_errors(NULL, LIVES_INT_TO_POINTER(chk_mask));
3149 }
3150
3151
3152 void on_paste_as_new_activate(LiVESMenuItem * menuitem, livespointer user_data) {
3153 #define VIRT_PASTE
3154 #ifndef VIRT_PASTE
3155 char *msg;
3156 #endif
3157 char *com;
3158 int old_file = mainw->current_file;
3159 frames_t cbframes, lframe;
3160
3161 if (!clipboard) return;
3162
3163 mainw->current_file = mainw->first_free_file;
3164
3165 if (!get_new_handle(mainw->current_file, NULL)) {
3166 mainw->current_file = old_file;
3167 return;
3168 }
3169
3170 lframe = cbframes = clipboard->frames;
3171
3172 //set file details
3173 cfile->hsize = clipboard->hsize;
3174 cfile->vsize = clipboard->vsize;
3175 cfile->pb_fps = cfile->fps = clipboard->fps;
3176 cfile->ratio_fps = clipboard->ratio_fps;
3177 cfile->changed = TRUE;
3178 cfile->is_loaded = TRUE;
3179 cfile->img_type = clipboard->img_type;
3180 cfile->gamma_type = clipboard->gamma_type;
3181
3182 set_default_comment(cfile, NULL);
3183
3184 #ifndef VIRT_PASTE
3185 msg = (_("Pulling frames from clipboard..."));
3186
3187 if ((lframe = realize_all_frames(0, msg, TRUE)) < cbframes) {
3188 if (!paste_enough_dlg(lframe - 1)) {
3189 lives_free(msg);
3190 close_current_file(old_file);
3191 sensitize();
3192 return;
3193 }
3194 lframe--;
3195 }
3196 lives_free(msg);
3197 #else
3198 /// copy the frame_index, and do an insert, skipping missing frames
3199 lframe = -lframe;
3200 #endif
3201
3202 cfile->progress_start = cfile->start = cbframes > 0 ? 1 : 0;
3203 cfile->progress_end = cfile->end = cfile->frames = cbframes;
3204
3205 mainw->no_switch_dprint = TRUE;
3206 d_print(_("Pasting %d frames to new clip %s..."), lframe, cfile->name);
3207 mainw->no_switch_dprint = FALSE;
3208
3209 if (clipboard->achans > 0 && clipboard->arate > 0) {
3210 com = lives_strdup_printf("%s insert \"%s\" \"%s\" 0 1 %d \"%s\" %d 0 0 0 %.3f %d %d %d %d %d",
3211 prefs->backend, cfile->handle,
3212 get_image_ext_for_type(cfile->img_type), lframe, clipboard->handle,
3213 mainw->ccpd_with_sound, clipboard->fps, clipboard->arate, clipboard->achans,
3214 clipboard->asampsize, !(cfile->signed_endian & AFORM_UNSIGNED),
3215 !(cfile->signed_endian & AFORM_BIG_ENDIAN));
3216 } else {
3217 com = lives_strdup_printf("%s insert \"%s\" \"%s\" 0 1 %d \"%s\" %d 0 0 0 %.3f 0 0 0 0 0",
3218 prefs->backend, cfile->handle,
3219 get_image_ext_for_type(cfile->img_type), lframe, clipboard->handle,
3220 FALSE, clipboard->fps);
3221
3222 if (clipboard->achans > 0 && clipboard->arate < 0) {
3223 int zero = 0;
3224 double chvols = 1.;
3225 double avels = -1.;
3226 double aseeks = (double)clipboard->afilesize / (double)(-clipboard->arate * clipboard->asampsize / 8 * clipboard->achans);
3227 ticks_t tc = (ticks_t)(aseeks * TICKS_PER_SECOND_DBL);
3228 cfile->arate = clipboard->arate = -clipboard->arate;
3229 cfile->arps = clipboard->arps;
3230 cfile->achans = clipboard->achans;
3231 cfile->asampsize = clipboard->asampsize;
3232 cfile->afilesize = clipboard->afilesize;
3233 cfile->signed_endian = clipboard->signed_endian;
3234 render_audio_segment(1, &zero, mainw->current_file, &avels, &aseeks, 0, tc, &chvols, 1., 1., NULL);
3235 }
3236 }
3237
3238 lives_system(com, FALSE);
3239 lives_free(com);
3240
3241 if (THREADVAR(com_failed)) {
3242 d_print_failed();
3243 close_current_file(old_file);
3244 return;
3245 }
3246
3247 cfile->nopreview = TRUE;
3248
3249 mainw->disk_mon = MONITOR_QUOTA;
3250
3251 // show a progress dialog, not cancellable
3252 if (!do_progress_dialog(TRUE, TRUE, _("Pasting"))) {
3253 mainw->disk_mon = 0;
3254 if (mainw->error) d_print_failed();
3255 close_current_file(old_file);
3256 return;
3257 }
3258 cfile->nopreview = FALSE;
3259 mainw->disk_mon = 0;
3260
3261 if (mainw->ccpd_with_sound) {
3262 if (cfile->audio_waveform) {
3263 for (int i = 0; i < cfile->achans; lives_freep((void **)&cfile->audio_waveform[i++]));
3264 lives_freep((void **)&cfile->audio_waveform);
3265 lives_freep((void **)&cfile->aw_sizes);
3266 }
3267 cfile->arate = clipboard->arate;
3268 cfile->arps = clipboard->arps;
3269 cfile->achans = clipboard->achans;
3270 cfile->asampsize = clipboard->asampsize;
3271 cfile->afilesize = clipboard->afilesize;
3272 cfile->signed_endian = clipboard->signed_endian;
3273 if (cfile->afilesize > 0) d_print(_("...added audio..."));
3274 }
3275
3276 #ifdef VIRT_PASTE
3277 if (clipboard->frame_index) {
3278 cfile->frame_index = frame_index_copy(clipboard->frame_index, cbframes, 0);
3279 }
3280
3281 cfile->clip_type = clipboard->clip_type;
3282
3283 if (cfile->clip_type == CLIP_TYPE_FILE) {
3284 cfile->ext_src = clone_decoder(CLIPBOARD_FILE);
3285 lives_snprintf(cfile->file_name, PATH_MAX, "%s", clipboard->file_name);
3286 }
3287 #endif
3288
3289 if (cfile->frame_index) save_frame_index(mainw->current_file);
3290
3291 // add entry to window menu
3292 add_to_clipmenu();
3293 if (!save_clip_values(mainw->current_file)) {
3294 close_current_file(old_file);
3295 return;
3296 }
3297
3298 if (prefs->crash_recovery) add_to_recovery_file(cfile->handle);
3299
3300 switch_clip(1, mainw->current_file, TRUE);
3301 d_print_done();
3302
3303 mainw->last_dprint_file = old_file;
3304 d_print(""); // force switchtext
3305
3306 lives_notify(LIVES_OSC_NOTIFY_CLIP_OPENED, "");
3307 check_storage_space(-1, FALSE);
3308 }
3309
3310
3311 void on_insert_pre_activate(LiVESMenuItem * menuitem, livespointer user_data) {
3312 insertw = create_insert_dialog();
3313
3314 lives_widget_show_all(insertw->insert_dialog);
3315 mainw->fx1_bool = FALSE;
3316 mainw->fx1_val = 1;
3317
3318 mainw->fx2_bool = lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(insertw->with_sound));
3319 }
3320
3321
3322 void on_insert_activate(LiVESButton * button, livespointer user_data) {
3323 double times_to_insert;
3324 double audio_stretch;
3325
3326 char *com;
3327
3328 boolean with_sound = mainw->fx2_bool;
3329 boolean bad_header = FALSE;
3330 boolean insert_silence = FALSE;
3331
3332 // have we resampled ?
3333 boolean cb_audio_change = FALSE;
3334 boolean cb_video_change = FALSE;
3335
3336 boolean virtual_ins = FALSE;
3337 boolean all_virtual = FALSE;
3338
3339 uint32_t chk_mask = 0;
3340
3341 int where = cfile->start - 1;
3342 int start = cfile->start, ostart = start;
3343 int end = cfile->end, oend = end;
3344
3345 int hsize = cfile->hsize;
3346 int vsize = cfile->vsize;
3347
3348 int cfile_signed = 0, cfile_endian = 0, clipboard_signed = 0, clipboard_endian = 0;
3349 int current_file = mainw->current_file;
3350
3351 int orig_frames = cfile->frames;
3352 int ocarps = clipboard->arps;
3353 int leave_backup = 1;
3354 int remainder_frames;
3355 int insert_start;
3356 int cb_start = 1, cb_end = clipboard->frames;
3357 int i;
3358
3359 // if it is an insert into the original file, and we can do fast seek, we can insert virtual frames
3360 if (button && mainw->current_file == clipboard->cb_src && !check_if_non_virtual(0, 1, clipboard->frames)) {
3361 lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
3362 if (cdata->seek_flag & LIVES_SEEK_FAST) {
3363 virtual_ins = TRUE;
3364 if (count_virtual_frames(clipboard->frame_index, 1, clipboard->frames) == clipboard->frames) all_virtual = TRUE;
3365 }
3366 }
3367
3368 // don't ask smogrify to resize if frames are the same size and type
3369 if (all_virtual || (((cfile->hsize == clipboard->hsize && cfile->vsize == clipboard->vsize) || orig_frames == 0) &&
3370 (cfile->img_type == clipboard->img_type))) hsize = vsize = 0;
3371 else {
3372 if (!capable->has_convert) {
3373 widget_opts.non_modal = TRUE;
3374 do_error_dialog(
3375 _("This operation requires resizing or converting of frames.\n"
3376 "Please install 'convert' from the Image-magick package, and then restart LiVES.\n"));
3377 widget_opts.non_modal = FALSE;
3378 mainw->error = TRUE;
3379 if (button) {
3380 lives_widget_destroy(insertw->insert_dialog);
3381 lives_free(insertw);
3382 }
3383 return;
3384 }
3385 }
3386
3387 if (button) {
3388 lives_widget_destroy(insertw->insert_dialog);
3389 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
3390 // call to update fx1_val, in case activates_default was called from spin entry
3391 lives_free(insertw);
3392 }
3393
3394 times_to_insert = mainw->fx1_val;
3395
3396 // fit video to audio if requested
3397 if (mainw->fx1_bool && (cfile->asampsize * cfile->arate * cfile->achans != 0)) {
3398 // "insert to fit audio" : number of inserts is (audio_time - sel_end_time) / clipboard_time
3399 times_to_insert = (cfile->laudio_time - (cfile->frames > 0 ? (double)cfile->end / cfile->fps : 0.)) / ((
3400 double)clipboard->frames / clipboard->fps);
3401 }
3402
3403 if (times_to_insert < 0. && (mainw->fx1_bool)) {
3404 widget_opts.non_modal = TRUE;
3405 do_error_dialog(
3406 _("\n\nVideo is longer than audio.\nTry selecting all frames, and then using \n"
3407 "the 'Trim Audio' function from the Audio menu."));
3408 mainw->error = TRUE;
3409 widget_opts.non_modal = FALSE;
3410 return;
3411 }
3412
3413 if (with_sound) {
3414 cfile_signed = !(cfile->signed_endian & AFORM_UNSIGNED);
3415 cfile_endian = !(cfile->signed_endian & AFORM_BIG_ENDIAN);
3416
3417 clipboard_signed = !(clipboard->signed_endian & AFORM_UNSIGNED);
3418 clipboard_endian = !(clipboard->signed_endian & AFORM_BIG_ENDIAN);
3419
3420 if ((cfile->achans * cfile->arps * cfile->asampsize > 0) && (cfile->achans != clipboard->achans ||
3421 (cfile->arps != clipboard->arps && clipboard->achans > 0) ||
3422 cfile->asampsize != clipboard->asampsize ||
3423 cfile_signed != clipboard_signed || cfile_endian != clipboard_endian ||
3424 cfile->arate != clipboard->arate)) {
3425 if (!(capable->has_sox_sox)) {
3426 if (cfile->arps != clipboard->arps) {
3427 widget_opts.non_modal = TRUE;
3428 do_error_dialog(_("LiVES cannot insert because the audio rates do not match.\n"
3429 "Please install 'sox', and try again."));
3430 mainw->error = TRUE;
3431 widget_opts.non_modal = FALSE;
3432 return;
3433 // *INDENT-OFF*
3434 }}}}
3435 // *INDENT-ON*
3436
3437 if (mainw->insert_after) insert_start = cfile->end + 1;
3438 else insert_start = cfile->start;
3439
3440 if (button) {
3441 char *tmp = (_("Insertion"));
3442 chk_mask = WARN_MASK_LAYOUT_SHIFT_FRAMES | WARN_MASK_LAYOUT_ALTER_FRAMES;
3443 if (with_sound) chk_mask |= WARN_MASK_LAYOUT_SHIFT_AUDIO | WARN_MASK_LAYOUT_ALTER_AUDIO;
3444 if (!check_for_layout_errors(tmp, mainw->current_file, insert_start, 0, &chk_mask)) {
3445 lives_free(tmp);
3446 return;
3447 }
3448 lives_free(tmp);
3449 }
3450
3451 if (button) {
3452 if ((cfile->fps != clipboard->fps && orig_frames > 0) || (cfile->arps != clipboard->arps && clipboard->achans > 0 &&
3453 with_sound)) {
3454 if (!do_clipboard_fps_warning()) {
3455 unbuffer_lmap_errors(FALSE);
3456 mainw->error = TRUE;
3457 return;
3458 }
3459 }
3460 if (prefs->ins_resample && clipboard->fps != cfile->fps && orig_frames != 0) {
3461 cb_end = count_resampled_frames(clipboard->frames, clipboard->fps, cfile->fps);
3462 }
3463 } else {
3464 // called from on_merge_activate()
3465 cb_start = mainw->fx1_start;
3466 cb_end = mainw->fx2_start;
3467
3468 // we will use leave_backup as this will leave our
3469 // merge backup in place
3470 leave_backup = -1;
3471 }
3472
3473 cfile->insert_start = insert_start;
3474 cfile->insert_end = cfile->insert_start - 1;
3475
3476 if (mainw->insert_after) where = cfile->end;
3477
3478 // at least we should try to convert the audio to match...
3479 // if with_sound is TRUE, and clipboard has no audio, we will insert silence (unless target
3480 // also has no audio
3481 if (with_sound) {
3482 if (clipboard->achans == 0) {
3483 if (cfile->achans > 0) insert_silence = TRUE;
3484 with_sound = FALSE;
3485 } else {
3486 if ((cfile->achans * cfile->arps * cfile->asampsize > 0)
3487 && clipboard->achans > 0 && (cfile->achans != clipboard->achans ||
3488 cfile->arps != clipboard->arps || clipboard->vol != 1. || cfile->vol != 1. ||
3489 cfile->asampsize != clipboard->asampsize ||
3490 cfile_signed != clipboard_signed ||
3491 cfile_endian != clipboard_endian || cfile->arate != clipboard->arate)) {
3492
3493 cb_audio_change = TRUE;
3494
3495 if (clipboard->arps != clipboard->arps || cfile->arate != clipboard->arate) {
3496 // pb rate != real rate - stretch to pb rate and resample
3497 if ((audio_stretch = (double)clipboard->arps / (double)clipboard->arate *
3498 (double)cfile->arate / (double)cfile->arps) != 1.) {
3499 if (audio_stretch < 0.) {
3500 // clipboard audio should be reversed
3501 // we will create a temp handle, copy the audio, and then render it back reversed
3502 if (!get_temp_handle(-1)) {
3503 d_print_failed();
3504 return;
3505 } else {
3506 char *fnameto = lives_get_audio_file_name(mainw->current_file);
3507 char *fnamefrom = lives_get_audio_file_name(0);
3508 int zero = 0;
3509 float volx = 1.;
3510 double chvols = 1.;
3511 double avels = -1.;
3512 double aseeks = (double)clipboard->afilesize / (double)(-clipboard->arate
3513 * clipboard->asampsize / 8 * clipboard->achans);
3514 ticks_t tc = (ticks_t)(aseeks * TICKS_PER_SECOND_DBL);
3515 if (cfile->vol > 0.001) volx = clipboard->vol / cfile->vol;
3516 render_audio_segment(1, &zero, mainw->current_file, &avels, &aseeks, 0, tc, &chvols, volx, volx, NULL);
3517 reget_afilesize(0);
3518 reget_afilesize(mainw->current_file);
3519 if (cfile->afilesize == clipboard->afilesize) {
3520 lives_mv(fnameto, fnamefrom);
3521 }
3522 close_temp_handle(current_file);
3523 clipboard->arate = -clipboard->arate;
3524 lives_free(fnamefrom);
3525 lives_free(fnameto);
3526 }
3527 } else {
3528 lives_rm(clipboard->info_file);
3529 com = lives_strdup_printf("%s resample_audio \"%s\" %d %d %d %d %d %d %d %d %d %d %.4f",
3530 prefs->backend,
3531 clipboard->handle, clipboard->arps, clipboard->achans, clipboard->asampsize,
3532 clipboard_signed, clipboard_endian, cfile->arps, clipboard->achans,
3533 clipboard->asampsize, clipboard_signed, clipboard_endian, audio_stretch);
3534 lives_system(com, FALSE);
3535 lives_free(com);
3536
3537 if (THREADVAR(com_failed)) {
3538 unbuffer_lmap_errors(FALSE);
3539 return;
3540 }
3541
3542 mainw->current_file = 0;
3543 mainw->error = FALSE;
3544 do_progress_dialog(TRUE, FALSE, _("Resampling clipboard audio"));
3545 mainw->current_file = current_file;
3546 if (mainw->error) {
3547 d_print_failed();
3548 unbuffer_lmap_errors(FALSE);
3549 return;
3550 }
3551
3552 // not really, but we pretend...
3553 clipboard->arps = cfile->arps;
3554 }
3555 }
3556 }
3557
3558 if (clipboard->achans > 0 && (cfile->achans != clipboard->achans || cfile->arps != clipboard->arps ||
3559 cfile->asampsize != clipboard->asampsize || cfile_signed != clipboard_signed ||
3560 cfile_endian != clipboard_endian)) {
3561 lives_rm(clipboard->info_file);
3562 com = lives_strdup_printf("%s resample_audio \"%s\" %d %d %d %d %d %d %d %d %d %d",
3563 prefs->backend, clipboard->handle,
3564 clipboard->arps, clipboard->achans, clipboard->asampsize, clipboard_signed,
3565 clipboard_endian, cfile->arps, cfile->achans, cfile->asampsize, cfile_signed, cfile_endian);
3566 lives_system(com, FALSE);
3567 lives_free(com);
3568
3569 if (THREADVAR(com_failed)) {
3570 unbuffer_lmap_errors(FALSE);
3571 return;
3572 }
3573
3574 mainw->current_file = 0;
3575 do_progress_dialog(TRUE, FALSE, _("Resampling clipboard audio"));
3576 mainw->current_file = current_file;
3577
3578 if (mainw->error) {
3579 d_print_failed();
3580 unbuffer_lmap_errors(FALSE);
3581 return;
3582 }
3583 }
3584
3585 if (clipboard->achans > 0 && clipboard->afilesize == 0l) {
3586 if (prefs->conserve_space) {
3587 // oops...
3588 if (clipboard->audio_waveform) {
3589 for (i = 0; i < clipboard->achans; lives_freep((void **)&clipboard->audio_waveform[i++]));
3590 lives_freep((void **)&clipboard->audio_waveform);
3591 lives_freep((void **)&clipboard->aw_sizes);
3592 }
3593 clipboard->achans = clipboard->arate = clipboard->asampsize = 0;
3594 with_sound = FALSE;
3595 widget_opts.non_modal = TRUE;
3596 do_error_dialog
3597 (_("\n\nLiVES was unable to resample the clipboard audio. \nClipboard audio has been erased.\n"));
3598 widget_opts.non_modal = FALSE;
3599 } else {
3600 lives_rm(clipboard->info_file);
3601 mainw->current_file = 0;
3602 com = lives_strdup_printf("%s undo_audio \"%s\"", prefs->backend_sync, clipboard->handle);
3603 lives_system(com, FALSE);
3604 lives_free(com);
3605 mainw->current_file = current_file;
3606
3607 clipboard->arps = ocarps;
3608 reget_afilesize(0);
3609
3610 if (!do_yesno_dialog
3611 (_("\n\nLiVES was unable to resample the clipboard audio.\n"
3612 "Do you wish to continue with the insert \nusing unchanged audio ?\n"))) {
3613 mainw->error = TRUE;
3614 unbuffer_lmap_errors(FALSE);
3615 return;
3616 // *INDENT-OFF*
3617 }}}}}}
3618 // *INDENT-ON*
3619
3620 if (!virtual_ins) {
3621 char *msg = (_("Pulling frames from clipboard..."));
3622 if (realize_all_frames(0, msg, FALSE) <= 0) {
3623 lives_free(msg);
3624 sensitize();
3625 unbuffer_lmap_errors(FALSE);
3626 return;
3627 }
3628 lives_free(msg);
3629 }
3630
3631 d_print(""); // force switchtext
3632
3633 // if pref is set, resample clipboard video
3634 if (prefs->ins_resample && cfile->fps != clipboard->fps && orig_frames > 0) {
3635 if (!resample_clipboard(cfile->fps)) {
3636 unbuffer_lmap_errors(FALSE);
3637 return;
3638 }
3639 cb_video_change = TRUE;
3640 }
3641
3642 if (mainw->fx1_bool && (cfile->asampsize * cfile->arate * cfile->achans != 0)) {
3643 // in theory this should not change after resampling, but we will recalculate anyway
3644
3645 // "insert to fit audio" : number of inserts is (audio_time - video_time) / clipboard_time
3646 times_to_insert = (cfile->laudio_time - cfile->frames > 0 ? (double)cfile->frames / cfile->fps : 0.) / ((
3647 double)clipboard->frames / clipboard->fps);
3648 }
3649
3650 switch_clip(1, current_file, TRUE);
3651
3652 if (cb_end > clipboard->frames) {
3653 cb_end = clipboard->frames;
3654 }
3655
3656 if (with_sound && cfile->achans == 0) {
3657 int asigned = !(clipboard->signed_endian & AFORM_UNSIGNED);
3658 int endian = clipboard->signed_endian & AFORM_BIG_ENDIAN;
3659
3660 cfile->achans = clipboard->achans;
3661 cfile->asampsize = clipboard->asampsize;
3662 cfile->arps = cfile->arate = clipboard->arate;
3663 cfile->signed_endian = clipboard->signed_endian;
3664
3665 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ARATE, &cfile->arps)) bad_header = TRUE;
3666 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_PB_ARATE, &cfile->arate)) bad_header = TRUE;
3667 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ACHANS, &cfile->achans)) bad_header = TRUE;
3668 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ASIGNED, &asigned)) bad_header = TRUE;
3669 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_AENDIAN, &endian)) bad_header = TRUE;
3670 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ASAMPS, &cfile->asampsize)) bad_header = TRUE;
3671
3672 if (bad_header) do_header_write_error(mainw->current_file);
3673 }
3674
3675 // first remainder frames
3676 remainder_frames = (int)(times_to_insert - (double)(int)times_to_insert) * clipboard->frames;
3677
3678 end = clipboard->frames;
3679 if (virtual_ins) end = -end;
3680
3681 if (!mainw->insert_after && remainder_frames > 0) {
3682 d_print(_("Inserting %d%s frames from the clipboard..."), remainder_frames,
3683 times_to_insert > 1. ? " remainder" : "");
3684
3685 com = lives_strdup_printf("%s insert \"%s\" \"%s\" %d %d %d \"%s\" %d %d %d %d %.3f %d %d %d %d %d",
3686 prefs->backend, cfile->handle,
3687 get_image_ext_for_type(cfile->img_type), where, clipboard->frames - remainder_frames + 1,
3688 end, clipboard->handle, with_sound, cfile->frames, hsize, vsize, cfile->fps,
3689 cfile->arate, cfile->achans, cfile->asampsize, !(cfile->signed_endian & AFORM_UNSIGNED),
3690 !(cfile->signed_endian & AFORM_BIG_ENDIAN));
3691
3692 lives_rm(cfile->info_file);
3693 lives_system(com, FALSE);
3694 lives_free(com);
3695
3696 if (THREADVAR(com_failed)) {
3697 d_print_failed();
3698 unbuffer_lmap_errors(FALSE);
3699 return;
3700 }
3701
3702 cfile->progress_start = 1;
3703 cfile->progress_end = remainder_frames;
3704
3705 mainw->disk_mon = MONITOR_QUOTA;
3706 do_progress_dialog(TRUE, FALSE, _("Inserting"));
3707 mainw->disk_mon = 0;
3708
3709 if (mainw->error) {
3710 d_print_failed();
3711 unbuffer_lmap_errors(FALSE);
3712 check_storage_space(-1, FALSE);
3713 return;
3714 }
3715
3716 if (cfile->clip_type == CLIP_TYPE_FILE || virtual_ins) {
3717 insert_images_in_virtual(mainw->current_file, where, remainder_frames, clipboard->frame_index,
3718 clipboard->frames - remainder_frames + 1);
3719 }
3720
3721 cfile->frames += remainder_frames;
3722 where += remainder_frames;
3723
3724 cfile->insert_end += remainder_frames;
3725
3726 if (!mainw->insert_after) {
3727 cfile->start += remainder_frames;
3728 cfile->end += remainder_frames;
3729 }
3730
3731 if (with_sound) {
3732 reget_afilesize(mainw->current_file);
3733 } else get_play_times();
3734 d_print_done();
3735 }
3736
3737 // inserts of whole clipboard
3738 if ((int)times_to_insert > 1) {
3739 d_print("");
3740 d_print(_("Inserting %d times from the clipboard%s..."), (int)times_to_insert, with_sound ?
3741 " (with sound)" : "");
3742 } else if ((int)times_to_insert > 0) {
3743 d_print("");
3744 d_print(_("Inserting %d frames from the clipboard%s..."), cb_end - cb_start + 1, with_sound ?
3745 " (with sound)" : "");
3746 }
3747
3748 if (virtual_ins) cb_end = -cb_end;
3749
3750 // for an insert after a merge we set our start posn. -ve
3751 // this should indicate to the back end to leave our
3752 // backup frames alone
3753
3754 com = lives_strdup_printf("%s insert \"%s\" \"%s\" %d %d %d \"%s\" %d %d %d %d %.3f %d %d %d %d %d %d",
3755 prefs->backend, cfile->handle,
3756 get_image_ext_for_type(cfile->img_type), where, cb_start * leave_backup, cb_end,
3757 clipboard->handle, with_sound, cfile->frames, hsize, vsize, cfile->fps, cfile->arate,
3758 cfile->achans, cfile->asampsize, !(cfile->signed_endian & AFORM_UNSIGNED),
3759 !(cfile->signed_endian & AFORM_BIG_ENDIAN), (int)times_to_insert);
3760
3761 if (virtual_ins) cb_end = -cb_end;
3762
3763 cfile->progress_start = 1;
3764 cfile->progress_end = (cb_end - cb_start + 1) * (int)times_to_insert + cfile->frames - where;
3765 lives_rm(cfile->info_file);
3766 lives_system(com, FALSE);
3767 lives_free(com);
3768
3769 if (THREADVAR(com_failed)) {
3770 d_print_failed();
3771 unbuffer_lmap_errors(FALSE);
3772 return;
3773 }
3774
3775 // show a progress dialog
3776 cfile->nopreview = TRUE;
3777 mainw->disk_mon = MONITOR_QUOTA;
3778 if (!do_progress_dialog(TRUE, TRUE, _("Inserting"))) {
3779 // cancelled
3780 cfile->nopreview = FALSE;
3781 mainw->disk_mon = 0;
3782
3783 if (mainw->error) {
3784 d_print_failed();
3785 unbuffer_lmap_errors(FALSE);
3786 return;
3787 }
3788
3789 // clean up moved/inserted frames
3790 com = lives_strdup_printf("%s undo_insert \"%s\" %d %d %d \"%s\"",
3791 prefs->backend, cfile->handle, where + 1,
3792 where + (cb_end - cb_start + 1) * (int)times_to_insert, cfile->frames,
3793 get_image_ext_for_type(cfile->img_type));
3794 lives_system(com, FALSE);
3795 lives_free(com);
3796
3797 do_progress_dialog(TRUE, FALSE, _("Cancelling"));
3798
3799 cfile->start = ostart;
3800 cfile->end = oend;
3801
3802 if (with_sound) {
3803 // desample clipboard audio
3804 if (cb_audio_change && !prefs->conserve_space) {
3805 lives_rm(clipboard->info_file);
3806 com = lives_strdup_printf("%s undo_audio \"%s\"", prefs->backend_sync, clipboard->handle);
3807 mainw->current_file = 0;
3808 lives_system(com, FALSE);
3809 lives_free(com);
3810 mainw->current_file = current_file;
3811 clipboard->arps = ocarps;
3812 reget_afilesize(0);
3813 }
3814 }
3815
3816 if (cb_video_change) {
3817 // desample clipboard video
3818 mainw->current_file = 0;
3819 mainw->no_switch_dprint = TRUE;
3820 on_undo_activate(NULL, NULL);
3821 mainw->no_switch_dprint = FALSE;
3822 mainw->current_file = current_file;
3823 }
3824
3825 switch_clip(1, current_file, TRUE);
3826 set_undoable(NULL, FALSE);
3827 mainw->cancelled = CANCEL_USER;
3828 unbuffer_lmap_errors(FALSE);
3829 return;
3830 }
3831 mainw->disk_mon = 0;
3832
3833 mainw->cancelled = CANCEL_NONE;
3834 cfile->nopreview = FALSE;
3835
3836 if (cfile->clip_type == CLIP_TYPE_FILE || virtual_ins) {
3837 insert_images_in_virtual(mainw->current_file, where, (cb_end - cb_start + 1) * (int)times_to_insert, clipboard->frame_index,
3838 cb_start * leave_backup);
3839 }
3840
3841 cfile->frames += (cb_end - cb_start + 1) * (int)times_to_insert;
3842 where += (cb_end - cb_start + 1) * (int)times_to_insert;
3843 cfile->insert_end += (cb_end - cb_start + 1) * (int)times_to_insert;
3844
3845 if (!mainw->insert_after) {
3846 cfile->start += (cb_end - cb_start + 1) * (int)times_to_insert;
3847 cfile->end += (cb_end - cb_start + 1) * (int)times_to_insert;
3848 }
3849
3850 if (with_sound == 1) {
3851 reget_afilesize(mainw->current_file);
3852 } else get_play_times();
3853 d_print_done();
3854
3855 // last remainder frames
3856
3857 if (mainw->insert_after && remainder_frames > 0) {
3858 d_print(_("Inserting %d%s frames from the clipboard..."), remainder_frames,
3859 times_to_insert > 1. ? " remainder" : "");
3860
3861 if (virtual_ins) remainder_frames = -remainder_frames;
3862
3863 com = lives_strdup_printf("%s insert \"%s\" \"%s\" %d %d %d \"%s\" %d %d %d %d %3f %d %d %d %d %d",
3864 prefs->backend, cfile->handle,
3865 get_image_ext_for_type(cfile->img_type), where, 1, remainder_frames, clipboard->handle,
3866 with_sound, cfile->frames, hsize, vsize, cfile->fps, cfile->arate, cfile->achans,
3867 cfile->asampsize, !(cfile->signed_endian & AFORM_UNSIGNED),
3868 !(cfile->signed_endian & AFORM_BIG_ENDIAN));
3869
3870 lives_rm(cfile->info_file);
3871 lives_system(com, FALSE);
3872
3873 if (THREADVAR(com_failed)) {
3874 unbuffer_lmap_errors(TRUE);
3875 d_print_failed();
3876 return;
3877 }
3878
3879 if (virtual_ins) remainder_frames = -remainder_frames;
3880
3881 cfile->progress_start = 1;
3882 cfile->progress_end = remainder_frames;
3883
3884 mainw->disk_mon = MONITOR_QUOTA;
3885 do_progress_dialog(TRUE, FALSE, _("Inserting"));
3886 mainw->disk_mon = 0;
3887
3888 if (mainw->error) {
3889 d_print_failed();
3890 unbuffer_lmap_errors(TRUE);
3891 return;
3892 }
3893
3894 if (cfile->clip_type == CLIP_TYPE_FILE || virtual_ins) {
3895 insert_images_in_virtual(mainw->current_file, where, remainder_frames, clipboard->frame_index, 1);
3896 }
3897
3898 cfile->frames += remainder_frames;
3899 cfile->insert_end += remainder_frames;
3900 lives_free(com);
3901
3902 if (!mainw->insert_after) {
3903 cfile->start += remainder_frames;
3904 cfile->end += remainder_frames;
3905 }
3906 get_play_times();
3907
3908 d_print_done();
3909 }
3910
3911 // if we had deferred audio, we insert silence in selection
3912 if (insert_silence) {
3913 cfile->undo1_dbl = calc_time_from_frame(mainw->current_file, cfile->insert_start);
3914 cfile->undo2_dbl = calc_time_from_frame(mainw->current_file, cfile->insert_end + 1);
3915 cfile->undo_arate = cfile->arate;
3916 cfile->undo_signed_endian = cfile->signed_endian;
3917 cfile->undo_achans = cfile->achans;
3918 cfile->undo_asampsize = cfile->asampsize;
3919 cfile->undo_arps = cfile->arps;
3920
3921 on_ins_silence_activate(NULL, NULL);
3922
3923 with_sound = TRUE;
3924 }
3925
3926 // insert done
3927
3928 // start or end can be zero if we inserted into pure audio
3929 if (cfile->start == 0 && cfile->frames > 0) cfile->start = 1;
3930 if (cfile->end == 0) cfile->end = cfile->frames;
3931
3932 if (cfile->frames > 0 && orig_frames == 0) {
3933 lives_snprintf(cfile->type, 40, "Frames");
3934 cfile->orig_file_name = FALSE;
3935 cfile->hsize = clipboard->hsize;
3936 cfile->vsize = clipboard->vsize;
3937 cfile->bpp = clipboard->bpp;
3938 cfile->fps = cfile->pb_fps = clipboard->fps;
3939 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_WIDTH, &cfile->hsize)) bad_header = TRUE;
3940 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_HEIGHT, &cfile->vsize)) bad_header = TRUE;
3941 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_BPP, &cfile->bpp)) bad_header = TRUE;
3942 if (cfile->clip_type == CLIP_TYPE_FILE && cfile->ext_src) {
3943 lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
3944 double dfps = (double)cdata->fps;
3945 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_FPS, &dfps)) bad_header = TRUE;
3946 } else {
3947 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_FPS, &cfile->fps)) bad_header = TRUE;
3948 }
3949 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_PB_FPS, &cfile->fps)) bad_header = TRUE;
3950
3951 if (bad_header) do_header_write_error(mainw->current_file);
3952 }
3953
3954 lives_signal_handler_block(mainw->spinbutton_end, mainw->spin_end_func);
3955 lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->frames == 0 ? 0 : 1, cfile->frames);
3956 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->end);
3957 lives_signal_handler_unblock(mainw->spinbutton_end, mainw->spin_end_func);
3958
3959 lives_signal_handler_block(mainw->spinbutton_start, mainw->spin_start_func);
3960 lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->frames == 0 ? 0 : 1, cfile->frames);
3961 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->start);
3962 lives_signal_handler_unblock(mainw->spinbutton_start, mainw->spin_start_func);
3963
3964 set_undoable(_("Insert"), TRUE);
3965 cfile->undo1_boolean = with_sound;
3966 lives_widget_set_sensitive(mainw->select_new, TRUE);
3967
3968 // mark new file size as 'Unknown'
3969 cfile->f_size = 0l;
3970 cfile->changed = TRUE;
3971
3972 if (with_sound) {
3973 cfile->undo_action = UNDO_INSERT_WITH_AUDIO;
3974 if (cb_audio_change && !prefs->conserve_space && clipboard->achans > 0) {
3975 lives_rm(clipboard->info_file);
3976 mainw->current_file = 0;
3977 com = lives_strdup_printf("%s undo_audio \"%s\"", prefs->backend_sync, clipboard->handle);
3978 lives_system(com, FALSE);
3979 lives_free(com);
3980 mainw->current_file = current_file;
3981 clipboard->arps = ocarps;
3982 reget_afilesize(0);
3983 }
3984 } else cfile->undo_action = UNDO_INSERT;
3985
3986 if (cb_video_change) {
3987 mainw->current_file = 0;
3988 mainw->no_switch_dprint = TRUE;
3989 on_undo_activate(NULL, NULL);
3990 mainw->no_switch_dprint = FALSE;
3991 mainw->current_file = current_file;
3992 }
3993
3994 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_FRAMES, &cfile->frames)) bad_header = TRUE;
3995
3996 if (bad_header) do_header_write_error(mainw->current_file);
3997 switch_clip(1, current_file, TRUE);
3998 mainw->error = FALSE;
3999
4000 check_storage_space(-1, FALSE);
4001
4002 if (mainw->sl_undo_mem && (cfile->stored_layout_frame != 0 || (with_sound && cfile->stored_layout_audio != 0.))) {
4003 // need to invalidate undo/redo stack, in case file was used in some layout undo
4004 stored_event_list_free_undos();
4005 }
4006
4007 if (chk_mask != 0) popup_lmap_errors(NULL, LIVES_INT_TO_POINTER(chk_mask));
4008 }
4009
4010 /**
4011 @brief check for layout errors, using in_mask as a guide
4012 (mask values are taken from prefs->warn_mask, but with opposite sense)
4013
4014 This function should ALWAYS be called before any operations are performed which may do any of the following:
4015 - delete frames, shift frames, alter frames (e.g. insert, delete, resample, apply rendered effects).
4016 - delete audio, shift audio, alter audio (e.g. insert / delete with audio, resample, adjust the volume)
4017 - (deletion includes closing the clip)
4018
4019 - some operations are exempt (i.e resizing frames, converting the frame / sample format, appending after the end, temporary
4020 changes which affect only playback such as applying real time effects, letterboxing, altering the playback rate)
4021
4022 -- changing clip audio volume is somewhat undefined as this is a new feature and can be both a playback change and / or
4023 permanent change. However fade in / out and insert silence are more permanent and should call this function.
4024
4025 - the order of priority for both frames and audio is always: delete > shift > alter
4026 the default settings are to warn on delete / shift and not to warn on alter; however the user preferences may override this
4027
4028 start and end represent frame values for the affected region.
4029 For audio, the values should approximate the start and end points,
4030 (though normally they would be the correct points) and end may extend beyond the actual frame count.
4031
4032 After checking, in_mask is set (reduced) to to any 'trangressions' found - this will be the intersection (AND) of the check_mask,
4033 AND detected transgressions AND the conjunction of non-disabled warnings.
4034
4035 if the resulting set is non-empty, then prior to returning, a warning dialog is displayed.
4036 'operation' is a descriptive word / phrase for what the operation intends to be doing, e.g "deletion", "cutting", "pasting" which
4037 used in the dialog message.
4038
4039 if the user cancels, FALSE is returned. and the caller should abort whatever operation.
4040
4041 if the user chooses to continue, warnings are added to the layout errors buffer am TRUE is returned.
4042 (within the buffer, errors of the same type are collated and organised by priority,
4043 so there is no harm in calling this function multiple times).
4044
4045 If no warnings are shown (either because there were no conflicts, or because the user disabled the warnings) then TRUE is also
4046 returned, and in this case chk_mask will be 0.
4047
4048 After return from this function, if the return value is TRUE the operation may proceed, but the following must be observed:
4049
4050 - If the operation fails or is cancelled. any buffered warnings should be cleared by calling: unbuffer_lmap_errors(FALSE);
4051 (this function may always be called, even if chk_mask was returned as 0)
4052
4053 Otherwise, after the operation completes something like the following must be done:
4054
4055 if (chk_mask != 0) popup_lmap_errors(NULL, LIVES_INT_TO_POINTER(chk_mask));
4056
4057 this latter function must be called if and only if chk_mask was returned with a non-zero value.
4058 */
4059 boolean check_for_layout_errors(const char *operation, int fileno, int start, int end, uint32_t *in_mask) {
4060 lives_clip_t *sfile;
4061 LiVESList *xlays = NULL;
4062 uint32_t ret_mask = 0, mask = *in_mask;
4063 boolean cancelled = FALSE;
4064
4065 if (!IS_VALID_CLIP(fileno)) return 0;
4066 sfile = mainw->files[fileno];
4067 if (start < 1) start = 1;
4068
4069 if (mask & WARN_MASK_LAYOUT_DELETE_FRAMES) {
4070 if ((xlays = layout_frame_is_affected(fileno, start, end, NULL)) != NULL) {
4071 if (sfile->tcache_dubious_from > 0) free_thumb_cache(fileno, sfile->tcache_dubious_from);
4072 sfile->tcache_dubious_from = start;
4073 ret_mask |= WARN_MASK_LAYOUT_DELETE_FRAMES | (mask & WARN_MASK_LAYOUT_SHIFT_FRAMES)
4074 | (mask & WARN_MASK_LAYOUT_ALTER_FRAMES);
4075 if ((prefs->warning_mask & WARN_MASK_LAYOUT_DELETE_FRAMES) == 0) {
4076 mainw->xlays = xlays;
4077 if (!do_warning_dialogf
4078 (_("%s will cause missing frames in some multitrack layouts.\nAre you sure you wish to continue ?\n"), operation)) {
4079 cancelled = TRUE;
4080 }
4081 }
4082
4083 if (!cancelled) {
4084 buffer_lmap_error(LMAP_ERROR_DELETE_FRAMES, sfile->name, (livespointer)sfile->layout_map, fileno,
4085 start, 0., count_resampled_frames(sfile->stored_layout_frame,
4086 sfile->stored_layout_fps, sfile->fps) >= start);
4087 }
4088 lives_list_free_all(&xlays);
4089 }
4090 }
4091
4092 if (mask & WARN_MASK_LAYOUT_DELETE_AUDIO) {
4093 if ((xlays = layout_audio_is_affected(fileno, (start - 1.) / sfile->fps, (end - 1.) / sfile->fps, NULL)) != NULL) {
4094 ret_mask |= WARN_MASK_LAYOUT_DELETE_AUDIO | (mask & WARN_MASK_LAYOUT_SHIFT_AUDIO)
4095 | (mask & WARN_MASK_LAYOUT_ALTER_AUDIO);
4096 if (!cancelled) {
4097 if ((prefs->warning_mask & WARN_MASK_LAYOUT_DELETE_AUDIO) == 0) {
4098 mainw->xlays = xlays;
4099 if (!do_warning_dialogf
4100 (_("%s will cause missing audio in some multitrack layouts.\nAre you sure you wish to continue ?\n"), operation)) {
4101 cancelled = TRUE;
4102 }
4103 }
4104 if (!cancelled) {
4105 buffer_lmap_error(LMAP_ERROR_DELETE_AUDIO, sfile->name, (livespointer)sfile->layout_map, fileno, 0,
4106 (start - 1.) / sfile->fps, (start - 1.) / sfile->fps < sfile->stored_layout_audio);
4107 }
4108 }
4109 }
4110 lives_list_free_all(&xlays);
4111 }
4112
4113 if ((ret_mask & WARN_MASK_LAYOUT_DELETE_FRAMES) == 0) {
4114 if (mask & WARN_MASK_LAYOUT_SHIFT_FRAMES) {
4115 if ((xlays = layout_frame_is_affected(fileno, start, 0, NULL)) != NULL) {
4116 if (sfile->tcache_dubious_from > 0) free_thumb_cache(fileno, sfile->tcache_dubious_from);
4117 sfile->tcache_dubious_from = start;
4118 ret_mask |= WARN_MASK_LAYOUT_SHIFT_FRAMES | (mask & WARN_MASK_LAYOUT_ALTER_FRAMES);
4119 if ((prefs->warning_mask & WARN_MASK_LAYOUT_SHIFT_FRAMES) == 0) {
4120 mainw->xlays = xlays;
4121 if (!do_warning_dialogf
4122 (_("%s will cause frames to shift in some multitrack layouts.\nAre you sure you wish to continue ?\n"),
4123 operation)) {
4124 cancelled = TRUE;
4125 }
4126 }
4127 if (!cancelled) {
4128 buffer_lmap_error(LMAP_ERROR_SHIFT_FRAMES, sfile->name, (livespointer)sfile->layout_map, fileno,
4129 start, 0., start <= count_resampled_frames(sfile->stored_layout_frame,
4130 sfile->stored_layout_fps, sfile->fps));
4131 }
4132 }
4133 lives_list_free_all(&xlays);
4134 }
4135 }
4136
4137 if ((ret_mask & WARN_MASK_LAYOUT_DELETE_AUDIO) == 0) {
4138 if (mask & WARN_MASK_LAYOUT_SHIFT_AUDIO) {
4139 if ((xlays = layout_audio_is_affected(fileno, (start - 1.) / sfile->fps, 0., NULL)) != NULL) {
4140 ret_mask |= WARN_MASK_LAYOUT_SHIFT_AUDIO | (mask & WARN_MASK_LAYOUT_ALTER_AUDIO);
4141 if (!cancelled) {
4142 if ((prefs->warning_mask & WARN_MASK_LAYOUT_SHIFT_AUDIO)) {
4143 mainw->xlays = xlays;
4144 if (!do_warning_dialogf
4145 (_("%s will cause audio to shift in some multitrack layouts.\nAre you sure you wish to continue ?\n"),
4146 operation)) {
4147 cancelled = TRUE;
4148 }
4149 }
4150 if (!cancelled) {
4151 buffer_lmap_error(LMAP_ERROR_SHIFT_AUDIO, sfile->name, (livespointer)sfile->layout_map, fileno, 0,
4152 (start - 1.) / sfile->fps, (start - 1.) / sfile->fps <= sfile->stored_layout_audio);
4153 }
4154 }
4155 lives_list_free_all(&xlays);
4156 }
4157 }
4158 }
4159
4160 if ((ret_mask & (WARN_MASK_LAYOUT_DELETE_FRAMES | WARN_MASK_LAYOUT_SHIFT_FRAMES)) == 0) {
4161 if (mask & WARN_MASK_LAYOUT_ALTER_FRAMES) {
4162 if ((xlays = layout_frame_is_affected(fileno, start, end, NULL)) != NULL) {
4163 if (sfile->tcache_dubious_from > 0) free_thumb_cache(fileno, sfile->tcache_dubious_from);
4164 sfile->tcache_dubious_from = start;
4165 ret_mask |= WARN_MASK_LAYOUT_ALTER_FRAMES;
4166 if ((prefs->warning_mask & WARN_MASK_LAYOUT_ALTER_FRAMES) == 0) {
4167 mainw->xlays = xlays;
4168 if (!do_layout_alter_frames_warning()) {
4169 cancelled = TRUE;
4170 }
4171 }
4172 if (!cancelled) {
4173 buffer_lmap_error(LMAP_ERROR_ALTER_FRAMES, sfile->name, (livespointer)sfile->layout_map, fileno, 0, 0.,
4174 sfile->stored_layout_frame > 0);
4175 }
4176 lives_list_free_all(&xlays);
4177 }
4178 }
4179 }
4180
4181 if ((ret_mask & (WARN_MASK_LAYOUT_DELETE_AUDIO | WARN_MASK_LAYOUT_SHIFT_AUDIO)) == 0) {
4182 if (mask & WARN_MASK_LAYOUT_ALTER_AUDIO) {
4183 if ((xlays = layout_audio_is_affected(fileno, 0., 0., NULL)) != NULL) {
4184 ret_mask |= WARN_MASK_LAYOUT_ALTER_AUDIO;
4185 if (!cancelled) {
4186 if ((prefs->warning_mask & WARN_MASK_LAYOUT_ALTER_AUDIO) == 0) {
4187 mainw->xlays = xlays;
4188 if (!do_layout_alter_audio_warning()) {
4189 cancelled = TRUE;
4190 }
4191 }
4192 }
4193 if (!cancelled) {
4194 buffer_lmap_error(LMAP_ERROR_ALTER_AUDIO, sfile->name, (livespointer)sfile->layout_map, fileno, 0, 0.,
4195 sfile->stored_layout_audio > 0.);
4196 }
4197 lives_list_free_all(&xlays);
4198 }
4199 }
4200 }
4201
4202 mainw->xlays = NULL;
4203 *in_mask = ret_mask;
4204 return !cancelled;
4205 }
4206
4207
4208 void on_delete_activate(LiVESMenuItem * menuitem, livespointer user_data) {
4209 char *com;
4210
4211 boolean bad_header = FALSE;
4212
4213 uint32_t chk_mask = 0;
4214
4215 int frames_cut = cfile->end - cfile->start + 1;
4216 int start = cfile->start;
4217 int end = cfile->end;
4218
4219 // occasionally we get a keyboard misread, so this should prevent that
4220 if (LIVES_IS_PLAYING) return;
4221
4222 if (cfile->start <= 1 && cfile->end == cfile->frames) {
4223 if (!mainw->osc_auto && menuitem != LIVES_MENU_ITEM(mainw->cut) && (cfile->achans == 0 ||
4224 ((cfile->end - 1.) / cfile->fps >= cfile->laudio_time &&
4225 mainw->ccpd_with_sound))) {
4226 if (do_warning_dialog
4227 (_("\nDeleting all frames will close this file.\nAre you sure ?"))) close_current_file(0);
4228 return;
4229 }
4230 }
4231
4232 if (menuitem) {
4233 char *tmp = (_("Deletion"));
4234 chk_mask = WARN_MASK_LAYOUT_DELETE_FRAMES | WARN_MASK_LAYOUT_SHIFT_FRAMES | WARN_MASK_LAYOUT_ALTER_FRAMES;
4235 if (mainw->ccpd_with_sound) chk_mask |= WARN_MASK_LAYOUT_DELETE_AUDIO | WARN_MASK_LAYOUT_SHIFT_AUDIO |
4236 WARN_MASK_LAYOUT_ALTER_AUDIO;
4237 if (!check_for_layout_errors(tmp, mainw->current_file, cfile->start, cfile->end, &chk_mask)) {
4238 lives_free(tmp);
4239 return;
4240 }
4241 lives_free(tmp);
4242 }
4243
4244 if (cfile->start <= 1 && cfile->end == cfile->frames) {
4245 cfile->ohsize = cfile->hsize;
4246 cfile->ovsize = cfile->vsize;
4247 }
4248
4249 cfile->undo_start = cfile->start;
4250 cfile->undo_end = cfile->end;
4251 cfile->undo1_boolean = mainw->ccpd_with_sound;
4252
4253 if (menuitem || mainw->osc_auto) {
4254 d_print(""); // force switchtext
4255 d_print(_("Deleting frames %d to %d%s..."), cfile->start, cfile->end,
4256 mainw->ccpd_with_sound && cfile->achans > 0 ? " (with sound)" : "");
4257 }
4258
4259 com = lives_strdup_printf("%s cut \"%s\" %d %d %d %d \"%s\" %.3f %d %d %d",
4260 prefs->backend, cfile->handle, cfile->start, cfile->end,
4261 mainw->ccpd_with_sound, cfile->frames, get_image_ext_for_type(cfile->img_type),
4262 cfile->fps, cfile->arate, cfile->achans, cfile->asampsize);
4263 lives_rm(cfile->info_file);
4264 lives_system(com, FALSE);
4265 lives_free(com);
4266
4267 if (THREADVAR(com_failed)) {
4268 unbuffer_lmap_errors(FALSE);
4269 d_print_failed();
4270 return;
4271 }
4272
4273 cfile->progress_start = cfile->start;
4274 cfile->progress_end = cfile->frames;
4275
4276 // show a progress dialog, not cancellable
4277 do_progress_dialog(TRUE, FALSE, _("Deleting"));
4278
4279 if (cfile->clip_type == CLIP_TYPE_FILE) {
4280 delete_frames_from_virtual(mainw->current_file, cfile->start, cfile->end);
4281 }
4282
4283 cfile->frames -= frames_cut;
4284
4285 cfile->undo_arate = cfile->arate;
4286 cfile->undo_signed_endian = cfile->signed_endian;
4287 cfile->undo_achans = cfile->achans;
4288 cfile->undo_asampsize = cfile->asampsize;
4289 cfile->undo_arps = cfile->arps;
4290
4291 if (mainw->ccpd_with_sound) {
4292 reget_afilesize(mainw->current_file);
4293 } else get_play_times();
4294
4295 if (cfile->frames == 0) {
4296 if (cfile->afilesize == 0l) {
4297 close_current_file(0);
4298 return;
4299 }
4300 lives_snprintf(cfile->type, 40, "Audio");
4301 cfile->hsize = cfile->vsize = 0;
4302 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_WIDTH, &cfile->hsize)) bad_header = TRUE;
4303 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_HEIGHT, &cfile->vsize)) bad_header = TRUE;
4304
4305 if (bad_header) do_header_write_error(mainw->current_file);
4306 cfile->orig_file_name = FALSE;
4307 desensitize();
4308 sensitize();
4309 }
4310
4311 if (!mainw->selwidth_locked || cfile->start > cfile->frames) {
4312 if (--start == 0 && cfile->frames > 0) {
4313 start = 1;
4314 }
4315 }
4316
4317 cfile->start = start;
4318
4319 if (!mainw->selwidth_locked) {
4320 cfile->end = start;
4321 } else {
4322 cfile->end = end;
4323 if (cfile->end > cfile->frames) {
4324 cfile->end = cfile->frames;
4325 }
4326 }
4327
4328 lives_signal_handler_block(mainw->spinbutton_end, mainw->spin_end_func);
4329 lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->frames == 0 ? 0 : 1, cfile->frames);
4330 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->end);
4331 lives_signal_handler_unblock(mainw->spinbutton_end, mainw->spin_end_func);
4332
4333 lives_signal_handler_block(mainw->spinbutton_start, mainw->spin_start_func);
4334 lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->frames == 0 ? 0 : 1, cfile->frames);
4335 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->start);
4336 lives_signal_handler_unblock(mainw->spinbutton_start, mainw->spin_start_func);
4337
4338 // menuitem is NULL if we came here from undo_insert
4339 if (!menuitem && !mainw->osc_auto) return;
4340
4341 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_FRAMES, &cfile->frames)) bad_header = TRUE;
4342
4343 showclipimgs();
4344
4345 get_play_times();
4346
4347 if (bad_header) do_header_write_error(mainw->current_file);
4348
4349 // mark new file size as 'Unknown'
4350 cfile->f_size = 0l;
4351 cfile->changed = TRUE;
4352
4353 set_undoable(_("Delete"), TRUE);
4354 cfile->undo_action = UNDO_DELETE;
4355 d_print_done();
4356
4357 if (mainw->sl_undo_mem && (cfile->stored_layout_frame != 0 || (mainw->ccpd_with_sound &&
4358 cfile->stored_layout_audio != 0.))) {
4359 // need to invalidate undo/redo stack, in case file was used in some layout undo
4360 stored_event_list_free_undos();
4361 }
4362
4363 if (chk_mask != 0) popup_lmap_errors(NULL, LIVES_INT_TO_POINTER(chk_mask));
4364 }
4365
4366
4367 void on_select_all_activate(LiVESWidget * widget, livespointer user_data) {
4368 if (!CURRENT_CLIP_IS_VALID) return;
4369
4370 if (mainw->selwidth_locked) {
4371 widget_opts.non_modal = TRUE;
4372 if (widget) do_error_dialog(_("\n\nSelection is locked.\n"));
4373 widget_opts.non_modal = FALSE;
4374 return;
4375 }
4376
4377 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), 1);
4378 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->frames);
4379
4380 cfile->start = cfile->frames > 0 ? 1 : 0;
4381 cfile->end = cfile->frames;
4382
4383 get_play_times();
4384
4385 showclipimgs();
4386 }
4387
4388
4389 void on_select_start_only_activate(LiVESMenuItem * menuitem, livespointer user_data) {
4390 if (mainw->current_file == -1) return;
4391 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->start);
4392 }
4393
4394
4395 void on_select_end_only_activate(LiVESMenuItem * menuitem, livespointer user_data) {
4396 if (mainw->current_file == -1) return;
4397 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->end);
4398 }
4399
4400
4401 void on_select_invert_activate(LiVESMenuItem * menuitem, livespointer user_data) {
4402 if (cfile->start == 1) {
4403 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->end + 1);
4404 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->frames);
4405 } else {
4406 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->start - 1);
4407 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), 1);
4408 }
4409
4410 get_play_times();
4411
4412 showclipimgs();
4413 }
4414
4415
4416 void on_select_last_activate(LiVESMenuItem * menuitem, livespointer user_data) {
4417 if (cfile->undo_start > cfile->frames) cfile->undo_start = cfile->frames;
4418 if (cfile->undo_end > cfile->frames) cfile->undo_end = cfile->frames;
4419
4420 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->undo_start);
4421 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->undo_end);
4422
4423 cfile->start = cfile->undo_start;
4424 cfile->end = cfile->undo_end;
4425
4426 get_play_times();
4427
4428 showclipimgs();
4429 }
4430
4431
4432 void on_select_new_activate(LiVESMenuItem * menuitem, livespointer user_data) {
4433 if (cfile->insert_start > cfile->frames) cfile->insert_start = cfile->frames;
4434 if (cfile->insert_end > cfile->frames) cfile->insert_end = cfile->frames;
4435
4436 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->insert_start);
4437 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->insert_end);
4438
4439 cfile->start = cfile->insert_start;
4440 cfile->end = cfile->insert_end;
4441
4442 get_play_times();
4443
4444 showclipimgs();
4445 }
4446
4447
4448 void on_select_to_end_activate(LiVESMenuItem * menuitem, livespointer user_data) {
4449 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->frames);
4450 cfile->end = cfile->frames;
4451 get_play_times();
4452 load_end_image(cfile->end);
4453 }
4454
4455
4456 void on_select_to_aend_activate(LiVESMenuItem * menuitem, livespointer user_data) {
4457 int end = calc_frame_from_time4(mainw->current_file, cfile->laudio_time);
4458 if (end > cfile->frames) end = cfile->frames;
4459 if (end < cfile->start) end = cfile->start;
4460 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), end);
4461 cfile->end = end;
4462 get_play_times();
4463 load_end_image(cfile->end);
4464 }
4465
4466
4467 void on_select_from_start_activate(LiVESMenuItem * menuitem, livespointer user_data) {
4468 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), 1);
4469 cfile->start = cfile->frames > 0 ? 1 : 0;
4470 get_play_times();
4471 load_start_image(cfile->start);
4472 }
4473
4474
4475 void on_lock_selwidth_activate(LiVESMenuItem * menuitem, livespointer user_data) {
4476 mainw->selwidth_locked = !mainw->selwidth_locked;
4477 lives_widget_set_sensitive(mainw->select_submenu, !mainw->selwidth_locked);
4478 update_sel_menu();
4479 }
4480
4481
4482 void play_all(boolean from_menu) {
4483 if (!CURRENT_CLIP_IS_VALID || CURRENT_CLIP_IS_CLIPBOARD) return;
4484
4485 if (mainw->multitrack) {
4486 if (!LIVES_IS_PLAYING) {
4487 if (!mainw->multitrack->playing_sel) multitrack_playall(mainw->multitrack);
4488 else multitrack_play_sel(NULL, mainw->multitrack);
4489 } else on_pause_clicked();
4490 return;
4491 }
4492
4493 if (!LIVES_IS_PLAYING) {
4494 if (mainw->proc_ptr && from_menu) {
4495 on_preview_clicked(LIVES_BUTTON(mainw->proc_ptr->preview_button), NULL);
4496 return;
4497 }
4498
4499 if (!mainw->osc_auto) {
4500 if (cfile->frames > 0) {
4501 mainw->play_start = calc_frame_from_time(mainw->current_file,
4502 cfile->pointer_time);
4503 } else {
4504 mainw->play_start = calc_frame_from_time4(mainw->current_file,
4505 cfile->pointer_time); // real_pointer_time ???
4506 }
4507 mainw->play_end = cfile->frames;
4508 }
4509
4510 mainw->playing_sel = FALSE;
4511 if (CURRENT_CLIP_IS_NORMAL) lives_rm(cfile->info_file);
4512
4513 play_file();
4514
4515 /* if (CURRENT_CLIP_IS_VALID) { */
4516 /* if (1 || !cfile->play_paused) { */
4517 /* //cfile->pointer_time = (cfile->last_frameno - 1.) / cfile->fps; */
4518 /* lives_ce_update_timeline(0, cfile->real_pointer_time); */
4519 /* } else { */
4520 /* lives_ce_update_timeline(cfile->frameno, 0); */
4521 /* //cfile->pointer_time = (cfile->last_frameno - 1.) / cfile->fps; */
4522 /* //cfile->play_paused = TRUE; */
4523 /* mainw->cancelled = CANCEL_USER; */
4524 /* } */
4525 //}
4526 }
4527 }
4528
4529
4530 void on_playall_activate(LiVESMenuItem * menuitem, livespointer user_data) {
4531 if (menuitem && mainw->go_away) return;
4532 start_playback(menuitem ? 8 : 0);
4533 }
4534
4535
4536 void play_sel(void) {
4537 if (!mainw->is_rendering) {
4538 mainw->play_start = cfile->start;
4539 mainw->play_end = cfile->end;
4540 mainw->clip_switched = FALSE;
4541 }
4542
4543 if (!mainw->preview) {
4544 int orig_play_frame = calc_frame_from_time(mainw->current_file, cfile->pointer_time);
4545 if (orig_play_frame > mainw->play_start && orig_play_frame < mainw->play_end) {
4546 mainw->play_start = orig_play_frame;
4547 }
4548 }
4549
4550 mainw->playing_sel = TRUE;
4551
4552 play_file();
4553
4554 mainw->playing_sel = FALSE;
4555 lives_ce_update_timeline(0, cfile->real_pointer_time);
4556
4557 // in case we are rendering and previewing, in case we now have audio
4558 if (mainw->preview && mainw->is_rendering && mainw->is_processing) reget_afilesize(mainw->current_file);
4559 if (mainw->cancelled == CANCEL_AUDIO_ERROR) {
4560 handle_audio_timeout();
4561 mainw->cancelled = CANCEL_ERROR;
4562 }
4563 }
4564
4565
4566 void on_playsel_activate(LiVESMenuItem * menuitem, livespointer user_data) {
4567 // play part of a clip (in clip editor)
4568 if (!CURRENT_CLIP_IS_VALID || CURRENT_CLIP_IS_CLIPBOARD) return;
4569
4570 if (mainw->proc_ptr && menuitem) {
4571 on_preview_clicked(LIVES_BUTTON(mainw->proc_ptr->preview_button), NULL);
4572 return;
4573 }
4574 if (LIVES_POINTER_TO_INT(user_data)) play_file();
4575 else start_playback(1);
4576 }
4577
4578
4579 void on_playclip_activate(LiVESMenuItem * menuitem, livespointer user_data) {
4580 // play the clipboard
4581 int current_file;
4582 if (mainw->multitrack) return;
4583
4584 current_file = mainw->pre_play_file = mainw->current_file;
4585 mainw-> oloop = mainw->loop;
4586 mainw->oloop_cont = mainw->loop_cont;
4587
4588 // switch to the clipboard
4589 switch_to_file(current_file, 0);
4590 lives_widget_set_sensitive(mainw->loop_video, FALSE);
4591 lives_widget_set_sensitive(mainw->loop_continue, FALSE);
4592 mainw->loop = mainw->loop_cont = FALSE;
4593
4594 mainw->play_start = 1;
4595 mainw->play_end = clipboard->frames;
4596 mainw->playing_sel = FALSE;
4597 mainw->loop = FALSE;
4598
4599 lives_rm(cfile->info_file);
4600
4601 start_playback(5);
4602 }
4603
4604
4605 void on_record_perf_activate(LiVESMenuItem * menuitem, livespointer user_data) {
4606 // real time recording
4607
4608 if (mainw->multitrack) return;
4609
4610 if (LIVES_IS_PLAYING) {
4611 // we are playing a clip
4612 if (!mainw->record || mainw->record_paused) {
4613 // recording is starting
4614 mainw->record_starting = TRUE;
4615
4616 toggle_record();
4617
4618 if ((prefs->rec_opts & REC_AUDIO) && (mainw->agen_key != 0 || mainw->agen_needs_reinit
4619 || prefs->audio_src == AUDIO_SRC_EXT) &&
4620 (prefs->audio_player == AUD_PLAYER_JACK || prefs->audio_player == AUD_PLAYER_PULSE)) {
4621 if (mainw->ascrap_file == -1) {
4622 open_ascrap_file();
4623 }
4624 if (mainw->ascrap_file != -1) {
4625 mainw->rec_samples = -1; // record unlimited
4626 mainw->rec_aclip = mainw->ascrap_file;
4627 mainw->rec_avel = 1.;
4628 mainw->rec_aseek = (double)mainw->files[mainw->ascrap_file]->aseek_pos /
4629 (double)(mainw->files[mainw->ascrap_file]->arps * mainw->files[mainw->ascrap_file]->achans *
4630 mainw->files[mainw->ascrap_file]->asampsize >> 3);
4631
4632 #ifdef ENABLE_JACK
4633 if (prefs->audio_player == AUD_PLAYER_JACK) {
4634 char *lives_header = lives_build_filename(prefs->workdir, mainw->files[mainw->ascrap_file]->handle,
4635 LIVES_CLIP_HEADER, NULL);
4636 mainw->clip_header = fopen(lives_header, "w"); // speed up clip header writes
4637 lives_free(lives_header);
4638
4639 if (mainw->agen_key == 0 && !mainw->agen_needs_reinit) {
4640 jack_rec_audio_to_clip(mainw->ascrap_file, -1, RECA_EXTERNAL);
4641 mainw->jackd_read->is_paused = FALSE;
4642 mainw->jackd_read->in_use = TRUE;
4643 } else {
4644 if (mainw->jackd) {
4645 jack_rec_audio_to_clip(mainw->ascrap_file, -1, RECA_GENERATED);
4646 }
4647 }
4648 if (mainw->clip_header) fclose(mainw->clip_header);
4649 mainw->clip_header = NULL;
4650 }
4651
4652 #endif
4653 #ifdef HAVE_PULSE_AUDIO
4654 if (prefs->audio_player == AUD_PLAYER_PULSE) {
4655 char *lives_header = lives_build_filename(prefs->workdir, mainw->files[mainw->ascrap_file]->handle,
4656 LIVES_CLIP_HEADER, NULL);
4657 mainw->clip_header = fopen(lives_header, "w"); // speed up clip header writes
4658 lives_free(lives_header);
4659
4660 if (mainw->agen_key == 0 && !mainw->agen_needs_reinit) {
4661 pulse_rec_audio_to_clip(mainw->ascrap_file, -1, RECA_EXTERNAL);
4662 mainw->pulsed_read->is_paused = FALSE;
4663 mainw->pulsed_read->in_use = TRUE;
4664 } else {
4665 if (mainw->pulsed) {
4666 pulse_rec_audio_to_clip(mainw->ascrap_file, -1, RECA_GENERATED);
4667 }
4668 }
4669 if (mainw->clip_header) fclose(mainw->clip_header);
4670 mainw->clip_header = NULL;
4671 }
4672 #endif
4673 }
4674 return;
4675 }
4676
4677 if (prefs->rec_opts & REC_AUDIO) {
4678 // recording INTERNAL audio
4679 #ifdef ENABLE_JACK
4680 if (prefs->audio_player == AUD_PLAYER_JACK && mainw->jackd) {
4681 jack_get_rec_avals(mainw->jackd);
4682 }
4683 #endif
4684 #ifdef HAVE_PULSE_AUDIO
4685 if (prefs->audio_player == AUD_PLAYER_PULSE && mainw->pulsed) {
4686 pulse_get_rec_avals(mainw->pulsed);
4687 }
4688 #endif
4689 }
4690 return;
4691 }
4692
4693 // end record during playback
4694 event_list_add_end_events(mainw->event_list, FALSE);
4695 mainw->record_paused = TRUE; // pause recording of further events
4696 enable_record();
4697 return;
4698 }
4699
4700 // out of playback
4701
4702 // record performance
4703 if (!mainw->record) {
4704 // TODO - change message depending on rec_opts
4705 d_print(_("Ready to record. Use 'control' and cursor keys during playback to record your performance.\n"
4706 "(To cancel, press 'r' or click on Play|Record Performance again before you play.)\n"));
4707 mainw->record = TRUE;
4708 toggle_record();
4709 get_play_times();
4710 } else {
4711 d_print(_("Record cancelled.\n"));
4712 enable_record();
4713 mainw->record = FALSE;
4714 }
4715 }
4716
4717
4718 boolean record_toggle_callback(LiVESAccelGroup * group, LiVESWidgetObject * obj, uint32_t keyval, LiVESXModifierType mod,
4719 livespointer user_data) {
4720 // from osc
4721 boolean start = (boolean)LIVES_POINTER_TO_INT(user_data);
4722
4723 if ((start && (!mainw->record || mainw->record_paused)) || (!start && (mainw->record && !mainw->record_paused)))
4724 on_record_perf_activate(NULL, NULL);
4725
4726 return TRUE;
4727 }
4728
4729
4730 void on_rewind_activate(LiVESMenuItem * menuitem, livespointer user_data) {
4731 if (LIVES_IS_PLAYING) return;
4732
4733 if (mainw->multitrack) {
4734 mt_tl_move(mainw->multitrack, 0.);
4735 return;
4736 }
4737
4738 cfile->pointer_time = lives_ce_update_timeline(0, 0.);
4739 lives_widget_queue_draw_if_visible(mainw->hruler);
4740 mainw->ptrtime = cfile->pointer_time;
4741 lives_widget_queue_draw(mainw->eventbox2);
4742 lives_widget_set_sensitive(mainw->rewind, FALSE);
4743 lives_widget_set_sensitive(mainw->m_rewindbutton, FALSE);
4744 lives_widget_set_sensitive(mainw->trim_to_pstart, FALSE);
4745 }
4746
4747
4748 void on_stop_activate(LiVESMenuItem * menuitem, livespointer user_data) {
4749 // stop during playback
4750
4751 if (mainw->multitrack && mainw->multitrack->is_paused && !LIVES_IS_PLAYING) {
4752 mainw->multitrack->is_paused = FALSE;
4753 mainw->multitrack->playing_sel = FALSE;
4754 mt_tl_move(mainw->multitrack, mainw->multitrack->pb_unpaused_start_time);
4755 lives_widget_set_sensitive(mainw->stop, FALSE);
4756 lives_widget_set_sensitive(mainw->m_stopbutton, FALSE);
4757 return;
4758 }
4759
4760 mainw->cancelled = CANCEL_USER;
4761 }
4762
4763
4764 boolean on_stop_activate_by_del(LiVESWidget * widget, LiVESXEventDelete * event, livespointer user_data) {
4765 // called if the user closes the separate play window
4766 if (prefs->sepwin_type == SEPWIN_TYPE_STICKY) {
4767 on_sepwin_pressed(NULL, NULL);
4768 }
4769 return TRUE;
4770 }
4771
4772
4773 void on_pause_clicked(void) {
4774 mainw->jack_can_stop = FALSE;
4775 mainw->cancelled = CANCEL_USER_PAUSED;
4776 }
4777
4778
4779 void on_encoder_entry_changed(LiVESCombo * combo, livespointer ptr) {
4780 LiVESList *encoder_capabilities = NULL;
4781 LiVESList *ofmt_all = NULL;
4782 LiVESList *ofmt = NULL;
4783
4784 const char *new_encoder_name = lives_combo_get_active_text(combo);
4785 char *msg;
4786 char **array;
4787 int i;
4788 render_details *rdet = (render_details *)ptr;
4789 LiVESList *dummy_list;
4790
4791 if (!strlen(new_encoder_name)) return;
4792
4793 if (!strcmp(new_encoder_name, mainw->string_constants[LIVES_STRING_CONSTANT_ANY])) {
4794 LiVESList *ofmt = NULL;
4795 ofmt = lives_list_append(ofmt, lives_strdup(mainw->string_constants[LIVES_STRING_CONSTANT_ANY]));
4796
4797 lives_signal_handler_block(rdet->encoder_combo, rdet->encoder_name_fn);
4798 // ---
4799 lives_combo_set_active_string(LIVES_COMBO(rdet->encoder_combo), mainw->string_constants[LIVES_STRING_CONSTANT_ANY]);
4800 // ---
4801 lives_signal_handler_unblock(rdet->encoder_combo, rdet->encoder_name_fn);
4802
4803 lives_combo_populate(LIVES_COMBO(rdet->ofmt_combo), ofmt);
4804 lives_signal_handler_block(rdet->ofmt_combo, rdet->encoder_ofmt_fn);
4805 lives_combo_set_active_string(LIVES_COMBO(rdet->ofmt_combo), mainw->string_constants[LIVES_STRING_CONSTANT_ANY]);
4806 lives_signal_handler_unblock(rdet->ofmt_combo, rdet->encoder_ofmt_fn);
4807
4808 lives_list_free(ofmt);
4809 if (prefs->acodec_list) {
4810 lives_list_free_all(&prefs->acodec_list);
4811 }
4812 prefs->acodec_list = lives_list_append(prefs->acodec_list, lives_strdup(mainw->string_constants[LIVES_STRING_CONSTANT_ANY]));
4813
4814 lives_combo_populate(LIVES_COMBO(rdet->acodec_combo), prefs->acodec_list);
4815
4816 lives_combo_set_active_string(LIVES_COMBO(rdet->acodec_combo), mainw->string_constants[LIVES_STRING_CONSTANT_ANY]);
4817
4818 rdet->enc_changed = FALSE;
4819
4820 return;
4821 }
4822
4823 // finalise old plugin
4824 plugin_request(PLUGIN_ENCODERS, prefs->encoder.name, "finalise");
4825
4826 clear_mainw_msg();
4827 // initialise new plugin
4828 if ((dummy_list = plugin_request(PLUGIN_ENCODERS, new_encoder_name, "init")) == NULL) {
4829 if (*mainw->msg) {
4830 msg = lives_strdup_printf(_("\n\nThe '%s' plugin reports:\n%s\n"), new_encoder_name, mainw->msg);
4831 } else {
4832 msg = lives_strdup_printf
4833 (_("\n\nUnable to find the 'init' method in the %s plugin.\nThe plugin may be broken or not installed correctly."),
4834 new_encoder_name);
4835 }
4836
4837 if (mainw->is_ready) {
4838 do_error_dialog_with_check(msg, 0);
4839 }
4840
4841 lives_free(msg);
4842
4843 if (prefsw) {
4844 lives_signal_handler_block(prefsw->encoder_combo, prefsw->encoder_name_fn);
4845 // ---
4846 lives_combo_set_active_string(LIVES_COMBO(prefsw->encoder_combo), prefs->encoder.name);
4847 // ---
4848 lives_signal_handler_unblock(prefsw->encoder_combo, prefsw->encoder_name_fn);
4849 }
4850
4851 if (rdet) {
4852 lives_signal_handler_block(rdet->encoder_combo, rdet->encoder_name_fn);
4853 // ---
4854 lives_combo_set_active_string(LIVES_COMBO(rdet->encoder_combo), rdet->encoder_name);
4855 // ---
4856 lives_signal_handler_unblock(rdet->encoder_combo, rdet->encoder_name_fn);
4857 }
4858
4859 dummy_list = plugin_request(PLUGIN_ENCODERS, prefs->encoder.name, "init");
4860 lives_list_free_all(&dummy_list);
4861 return;
4862 }
4863 lives_list_free_all(&dummy_list);
4864
4865 lives_snprintf(future_prefs->encoder.name, 64, "%s", new_encoder_name);
4866
4867 if ((encoder_capabilities = plugin_request(PLUGIN_ENCODERS, future_prefs->encoder.name, "get_capabilities")) == NULL) {
4868 do_plugin_encoder_error(future_prefs->encoder.name);
4869
4870 if (prefsw) {
4871 lives_signal_handler_block(prefsw->encoder_combo, prefsw->encoder_name_fn);
4872 // ---
4873 lives_combo_set_active_string(LIVES_COMBO(prefsw->encoder_combo), prefs->encoder.name);
4874 // ---
4875 lives_signal_handler_unblock(prefsw->encoder_combo, prefsw->encoder_name_fn);
4876 }
4877
4878 if (rdet) {
4879 lives_signal_handler_block(rdet->encoder_combo, rdet->encoder_name_fn);
4880 // ---
4881 lives_combo_set_active_string(LIVES_COMBO(rdet->encoder_combo), rdet->encoder_name);
4882 // ---
4883 lives_signal_handler_unblock(rdet->encoder_combo, rdet->encoder_name_fn);
4884 }
4885
4886 plugin_request(PLUGIN_ENCODERS, prefs->encoder.name, "init");
4887 lives_snprintf(future_prefs->encoder.name, 64, "%s", prefs->encoder.name);
4888 return;
4889 }
4890 prefs->encoder.capabilities = atoi((char *)lives_list_nth_data(encoder_capabilities, 0));
4891 lives_list_free_all(&encoder_capabilities);
4892
4893 // fill list with new formats
4894 if ((ofmt_all = plugin_request_by_line(PLUGIN_ENCODERS, future_prefs->encoder.name, "get_formats"))) {
4895 for (i = 0; i < lives_list_length(ofmt_all); i++) {
4896 if (get_token_count((char *)lives_list_nth_data(ofmt_all, i), '|') > 2) {
4897 array = lives_strsplit((char *)lives_list_nth_data(ofmt_all, i), "|", -1);
4898 ofmt = lives_list_append(ofmt, lives_strdup(array[1]));
4899 lives_strfreev(array);
4900 }
4901 }
4902
4903 if (prefsw) {
4904 // we have to block here, otherwise on_ofmt_changed gets called for every added entry !
4905 lives_signal_handler_block(prefsw->ofmt_combo, prefsw->encoder_ofmt_fn);
4906
4907 lives_combo_populate(LIVES_COMBO(prefsw->ofmt_combo), ofmt);
4908
4909 lives_signal_handler_unblock(prefsw->ofmt_combo, prefsw->encoder_ofmt_fn);
4910 }
4911
4912 if (rdet) {
4913 // we have to block here, otherwise on_ofmt_changed gets called for every added entry !
4914 lives_signal_handler_block(rdet->ofmt_combo, rdet->encoder_ofmt_fn);
4915
4916 lives_combo_populate(LIVES_COMBO(rdet->ofmt_combo), ofmt);
4917
4918 lives_signal_handler_unblock(rdet->ofmt_combo, rdet->encoder_ofmt_fn);
4919 }
4920
4921 lives_list_free(ofmt);
4922
4923 // set default (first) output type
4924 array = lives_strsplit((char *)lives_list_nth_data(ofmt_all, 0), "|", -1);
4925
4926 if (rdet) {
4927 lives_combo_set_active_string(LIVES_COMBO(rdet->ofmt_combo), array[1]);
4928
4929 if (!prefsw && strcmp(prefs->encoder.name, future_prefs->encoder.name)) {
4930 lives_snprintf(prefs->encoder.name, 64, "%s", future_prefs->encoder.name);
4931 set_string_pref(PREF_ENCODER, prefs->encoder.name);
4932 lives_snprintf(prefs->encoder.of_restrict, 1024, "%s", future_prefs->encoder.of_restrict);
4933 prefs->encoder.of_allowed_acodecs = future_prefs->encoder.of_allowed_acodecs;
4934 }
4935 rdet->enc_changed = TRUE;
4936 rdet->encoder_name = lives_strdup(prefs->encoder.name);
4937 lives_widget_set_sensitive(rdet->okbutton, TRUE);
4938 }
4939
4940 if (prefsw) {
4941 lives_combo_set_active_string(LIVES_COMBO(prefsw->ofmt_combo), array[1]);
4942 }
4943 on_encoder_ofmt_changed(NULL, rdet);
4944 lives_strfreev(array);
4945 if (ofmt_all) {
4946 lives_list_free_all(&ofmt_all);
4947 }
4948 }
4949 }
4950
4951
4952 void on_insertwsound_toggled(LiVESToggleButton * togglebutton, livespointer user_data) {
4953 if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(togglebutton))) {
4954 lives_widget_set_sensitive(insertw->fit_checkbutton, FALSE);
4955 } else {
4956 lives_widget_set_sensitive(insertw->fit_checkbutton, CURRENT_CLIP_HAS_AUDIO);
4957 }
4958 mainw->fx2_bool = !mainw->fx2_bool;
4959 }
4960
4961
4962 /// stored values for loop locking
4963 static int loop_lock_frame = -1;
4964 static lives_direction_t ofwd;
4965
4966 void unlock_loop_lock(void) {
4967 mainw->loop = mainw->oloop;
4968 mainw->loop_cont = mainw->oloop_cont;
4969 mainw->ping_pong = mainw->oping_pong;
4970 mainw->loop_locked = FALSE;
4971 if (CURRENT_CLIP_IS_NORMAL) {
4972 mainw->play_start = cfile->start;
4973 mainw->play_end = cfile->end;
4974 }
4975 loop_lock_frame = -1;
4976 mainw->clip_switched = TRUE;
4977 }
4978
4979
4980 boolean clip_can_reverse(int clipno) {
4981 if (!LIVES_IS_PLAYING || mainw->internal_messaging || mainw->is_rendering || mainw->is_processing
4982 || !IS_VALID_CLIP(clipno) || mainw->preview) return FALSE;
4983 else {
4984 lives_clip_t *sfile = mainw->files[clipno];
4985 if (sfile->clip_type == CLIP_TYPE_DISK) return TRUE;
4986 if (sfile->next_event) return FALSE;
4987 if (sfile->clip_type == CLIP_TYPE_FILE) {
4988 lives_clip_data_t *cdata = ((lives_decoder_t *)sfile->ext_src)->cdata;
4989 if (!cdata || !(cdata->seek_flag & LIVES_SEEK_FAST_REV)) return FALSE;
4990 }
4991 }
4992 return TRUE;
4993 }
4994
4995
4996 boolean dirchange_callback(LiVESAccelGroup * group, LiVESWidgetObject * obj, uint32_t keyval, LiVESXModifierType mod,
4997 livespointer area_enum) {
4998 int area = LIVES_POINTER_TO_INT(area_enum);
4999
5000 if (!(mod & LIVES_ALT_MASK) && (mod & LIVES_CONTROL_MASK) && mainw->loop_locked) {
5001 boolean do_ret = FALSE;
5002 if (!clip_can_reverse(mainw->current_file) || !mainw->ping_pong || ((cfile->pb_fps >= 0. && ofwd == LIVES_DIRECTION_FORWARD)
5003 || (cfile->pb_fps < 0. && ofwd == LIVES_DIRECTION_BACKWARD))) do_ret = TRUE;
5004 unlock_loop_lock();
5005 if (do_ret) return TRUE;
5006 }
5007
5008 if (area == SCREEN_AREA_FOREGROUND) {
5009 if (!CURRENT_CLIP_IS_NORMAL
5010 || (!clip_can_reverse(mainw->current_file) && cfile->pb_fps > 0.)) return TRUE;
5011 // change play direction
5012 if (cfile->play_paused) {
5013 if (!clip_can_reverse(mainw->current_file) && cfile->freeze_fps > 0.) return TRUE;
5014 cfile->freeze_fps = -cfile->freeze_fps;
5015 return TRUE;
5016 }
5017
5018 /// set this so we invalid preload cache
5019 if (mainw->scratch == SCRATCH_NONE) mainw->scratch = SCRATCH_REV;
5020
5021 lives_signal_handler_block(mainw->spinbutton_pb_fps, mainw->pb_fps_func);
5022 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), -cfile->pb_fps);
5023 lives_signal_handler_unblock(mainw->spinbutton_pb_fps, mainw->pb_fps_func);
5024
5025 // make sure this is called, sometimes we switch clips too soon...
5026 changed_fps_during_pb(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), NULL);
5027 } else if (area == SCREEN_AREA_BACKGROUND) {
5028 if (!IS_NORMAL_CLIP(mainw->blend_file)
5029 || (!clip_can_reverse(mainw->blend_file) && mainw->files[mainw->blend_file]->pb_fps >= 0.)) return TRUE;
5030 mainw->files[mainw->blend_file]->pb_fps = -mainw->files[mainw->blend_file]->pb_fps;
5031 }
5032 return TRUE;
5033 }
5034
5035
5036 /**
5037 @brief set in / out points for video looping
5038 during free playback, it is possible to set in / out points for video looping
5039 after setting both points, the video becomes "loop locked", i.e when one point
5040 is reached, it will jump to the other point (if the clip can reversee the it will instead
5041 ping-pong between the 2 points, ie. when one end point is reached,, the playdirection will flip)
5042
5043 loop lock can be disabled by any of the following:
5044 switching to another clip
5045 chaging clip direction manually
5046 triggering a bookmark
5047 ending playback
5048 when loop lock is released, the original play direction from before entering the lock is
5049 applied, if the lock was ended by triggering a direction change then the actual
5050 direction change is ignored
5051
5052 If both are already set, then triggering this again will reduce the loop length
5053 */
5054 boolean dirchange_lock_callback(LiVESAccelGroup * group, LiVESWidgetObject * obj, uint32_t keyval, LiVESXModifierType mod,
5055 livespointer area_enum) {
5056
5057 //if (!clip_can_reverse(mainw->current_file)) return TRUE;
5058
5059 if (!mainw->loop_locked && loop_lock_frame == -1) loop_lock_frame = mainw->actual_frame;
5060 else {
5061 // temporary loop_cont / ping-pong
5062 mainw->clip_switched = FALSE;
5063 if ((!mainw->loop_locked && mainw->actual_frame < loop_lock_frame) || (mainw->loop_locked && cfile->pb_fps < 0)) {
5064 if (!mainw->loop_locked || mainw->play_end - mainw->actual_frame > LOOP_LOCK_MIN_FRAMES)
5065 mainw->play_start = mainw->actual_frame;
5066 if (!mainw->loop_locked) mainw->play_end = loop_lock_frame;
5067 } else {
5068 if (!mainw->loop_locked) mainw->play_start = loop_lock_frame;
5069 if (!mainw->loop_locked || mainw->actual_frame - mainw->play_start > LOOP_LOCK_MIN_FRAMES)
5070 mainw->play_end = mainw->actual_frame;
5071 }
5072 if (!mainw->loop_locked) {
5073 mainw->oloop = mainw->loop;
5074 mainw->oloop_cont = mainw->loop_cont;
5075 mainw->oping_pong = mainw->ping_pong;
5076 /// store original direction so when we unlock loop lock we come out with original
5077 /// this is reversed because we already had one reversal
5078 ofwd = cfile->pb_fps < 0. ? LIVES_DIRECTION_FORWARD : LIVES_DIRECTION_BACKWARD;
5079 }
5080 mainw->loop_cont = TRUE;
5081 if (clip_can_reverse(mainw->current_file))
5082 mainw->ping_pong = TRUE;
5083 mainw->loop = FALSE;
5084 mainw->loop_locked = TRUE;
5085 loop_lock_frame = -1;
5086 }
5087 if (clip_can_reverse(mainw->current_file))
5088 return dirchange_callback(group, obj, keyval, mod, area_enum);
5089 return TRUE;
5090 }
5091
5092
5093 void on_volch_pressed(LiVESButton * button, livespointer user_data) {
5094 lives_direction_t dirn = LIVES_POINTER_TO_INT(user_data);
5095 if (!CURRENT_CLIP_IS_VALID || mainw->preview || (mainw->is_processing && cfile->is_loaded) || !mainw->cliplist) return;
5096 if (dirn == LIVES_DIRECTION_UP) cfile->vol += .01;
5097 else cfile->vol -= .01;
5098 if (cfile->vol > 2.) cfile->vol = 2.;
5099 if (cfile->vol < 0.) cfile->vol = 0.;
5100 if (prefs->show_overlay_msgs && !(mainw->urgency_msg && prefs->show_urgency_msgs))
5101 d_print_overlay(.5, _("Clip volume: %.2f"), cfile->vol);
5102 }
5103
5104
5105 boolean fps_reset_callback(LiVESAccelGroup * group, LiVESWidgetObject * obj, uint32_t keyval, LiVESXModifierType mod,
5106 livespointer area_enum) {
5107 // reset playback fps (cfile->pb_fps) to normal fps (cfile->fps)
5108 // also resync the audio
5109 int area;
5110 if (!LIVES_IS_PLAYING || mainw->multitrack) return TRUE;
5111
5112 area = LIVES_POINTER_TO_INT(area_enum);
5113 if (area == SCREEN_AREA_BACKGROUND) {
5114 if (!IS_NORMAL_CLIP(mainw->blend_file)) return TRUE;
5115 mainw->files[mainw->blend_file]->pb_fps = mainw->files[mainw->blend_file]->fps;
5116 return TRUE;
5117 }
5118
5119 mainw->scratch = SCRATCH_JUMP_NORESYNC;
5120
5121 if (mainw->loop_locked) {
5122 dirchange_callback(group, obj, keyval, LIVES_CONTROL_MASK, SCREEN_AREA_FOREGROUND);
5123 }
5124
5125 if (prefs->audio_opts & AUDIO_OPTS_FOLLOW_FPS) {
5126 resync_audio(((double)cfile->frameno));
5127 /* + (double)(lives_get_current_playback_ticks(mainw->origsecs, mainw->orignsecs, NULL) */
5128 /* - mainw->startticks) / TICKS_PER_SECOND_DBL * cfile->pb_fps); */
5129 }
5130
5131 // change play direction
5132 if (cfile->play_paused) {
5133 if (cfile->freeze_fps < 0.) cfile->freeze_fps = -cfile->fps;
5134 else cfile->freeze_fps = cfile->fps;
5135 return TRUE;
5136 }
5137
5138 lives_signal_handler_block(mainw->spinbutton_pb_fps, mainw->pb_fps_func);
5139 if (cfile->pb_fps > 0.) lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), cfile->fps);
5140 else lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), -cfile->fps);
5141 lives_signal_handler_unblock(mainw->spinbutton_pb_fps, mainw->pb_fps_func);
5142
5143 // make sure this is called, sometimes we switch clips too soon...
5144 changed_fps_during_pb(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), NULL);
5145
5146 return TRUE;
5147 }
5148
5149
5150 boolean prevclip_callback(LiVESAccelGroup * group, LiVESWidgetObject * obj, uint32_t keyval, LiVESXModifierType mod,
5151 livespointer user_data) {
5152 LiVESList *list_index;
5153 int i = 0;
5154 int num_tried = 0, num_clips;
5155 int type = 0;
5156
5157 // prev clip
5158 // type = 0 : if the effect is a transition, this will change the background clip
5159 // type = 1 fg only
5160 // type = 2 bg only
5161
5162 if (!LIVES_IS_INTERACTIVE) return TRUE;
5163 if (mainw->go_away) return TRUE;
5164
5165 if (!CURRENT_CLIP_IS_VALID || mainw->preview || (mainw->is_processing && cfile->is_loaded) ||
5166 !mainw->cliplist) return TRUE;
5167
5168 if (user_data) type = LIVES_POINTER_TO_INT(user_data);
5169
5170 if (type == 1 && mainw->new_clip != -1) return TRUE;
5171
5172 if (type == 2 || (mainw->active_sa_clips == SCREEN_AREA_BACKGROUND && mainw->playing_file > 0 && type != 1
5173 && !(type == 0 && !IS_NORMAL_CLIP(mainw->blend_file)))) {
5174 if (!IS_VALID_CLIP(mainw->blend_file)) return TRUE;
5175 list_index = lives_list_find(mainw->cliplist, LIVES_INT_TO_POINTER(mainw->blend_file));
5176 } else {
5177 list_index = lives_list_find(mainw->cliplist,
5178 LIVES_INT_TO_POINTER(mainw->swapped_clip == -1 ? mainw->current_file : mainw->swapped_clip));
5179 }
5180 mainw->swapped_clip = -1;
5181
5182 num_clips = lives_list_length(mainw->cliplist);
5183
5184 do {
5185 if (num_tried++ == num_clips) return TRUE; // we might have only audio clips, and then we will block here
5186 if (!list_index || ((list_index = list_index->prev) == NULL)) list_index = lives_list_last(mainw->cliplist);
5187 i = LIVES_POINTER_TO_INT(list_index->data);
5188 } while ((!mainw->files[i] || mainw->files[i]->opening || mainw->files[i]->restoring || i == mainw->scrap_file ||
5189 i == mainw->ascrap_file || (!mainw->files[i]->frames && LIVES_IS_PLAYING)) &&
5190 i != ((type == 2 || (mainw->playing_file > 0 && mainw->active_sa_clips == SCREEN_AREA_BACKGROUND && type != 1)) ?
5191 mainw->blend_file : mainw->current_file));
5192
5193 switch_clip(type, i, FALSE);
5194
5195 return TRUE;
5196 }
5197
5198
5199 boolean nextclip_callback(LiVESAccelGroup * group, LiVESWidgetObject * obj, uint32_t keyval, LiVESXModifierType mod,
5200 livespointer user_data) {
5201 LiVESList *list_index;
5202 int i;
5203 int num_tried = 0, num_clips;
5204
5205 int type = 0; ///< auto (switch bg if a transition is active, otherwise foreground)
5206
5207 if (!LIVES_IS_INTERACTIVE) return TRUE;
5208 if (mainw->go_away) return TRUE;
5209 // next clip
5210 // if the effect is a transition, this will change the background clip
5211 if (!CURRENT_CLIP_IS_VALID || mainw->preview || (mainw->is_processing && cfile->is_loaded) ||
5212 !mainw->cliplist) return TRUE;
5213
5214 if (user_data) type = LIVES_POINTER_TO_INT(user_data);
5215
5216 if (type == 1 && mainw->new_clip != -1) return TRUE;
5217
5218 if (type == 2 || (mainw->active_sa_clips == SCREEN_AREA_BACKGROUND && mainw->playing_file > 0 && type != 1
5219 && !(type == 0 && !IS_NORMAL_CLIP(mainw->blend_file)))) {
5220 if (!IS_VALID_CLIP(mainw->blend_file)) return TRUE;
5221 list_index = lives_list_find(mainw->cliplist, LIVES_INT_TO_POINTER(mainw->blend_file));
5222 } else {
5223 list_index = lives_list_find(mainw->cliplist,
5224 LIVES_INT_TO_POINTER(mainw->swapped_clip == -1 ? mainw->current_file : mainw->swapped_clip));
5225 }
5226 mainw->swapped_clip = -1;
5227
5228 num_clips = lives_list_length(mainw->cliplist);
5229
5230 do {
5231 if (num_tried++ == num_clips) return TRUE; // we might have only audio clips, and then we will block here
5232 if (!list_index || ((list_index = list_index->next) == NULL)) list_index = mainw->cliplist;
5233 i = LIVES_POINTER_TO_INT(list_index->data);
5234 } while ((!mainw->files[i] || mainw->files[i]->opening || mainw->files[i]->restoring || i == mainw->scrap_file ||
5235 i == mainw->ascrap_file || (!mainw->files[i]->frames && LIVES_IS_PLAYING)) &&
5236 i != ((type == 2 || (mainw->playing_file > 0 && mainw->active_sa_clips == SCREEN_AREA_BACKGROUND && type != 1)) ?
5237 mainw->blend_file : mainw->current_file));
5238
5239 switch_clip(type, i, FALSE);
5240
5241 return TRUE;
5242 }
5243
5244
5245 static LiVESResponseType rewrite_orderfile(boolean is_append, boolean add, boolean * got_new_handle) {
5246 char *ordfile = lives_build_filename(prefs->workdir, mainw->set_name, CLIP_ORDER_FILENAME, NULL);
5247 char *ordfile_new = lives_build_filename(prefs->workdir, mainw->set_name, CLIP_ORDER_FILENAME "." LIVES_FILE_EXT_NEW, NULL);
5248 char *cwd = lives_get_current_dir();
5249 char *new_dir;
5250 char *dfile, *ord_entry;
5251 char buff[PATH_MAX] = {0};
5252 char new_handle[256] = {0};
5253 LiVESResponseType retval;
5254 LiVESList *cliplist;
5255 int ord_fd, i;
5256
5257 do {
5258 // create the orderfile which lists all the clips in order
5259 retval = LIVES_RESPONSE_NONE;
5260 if (!is_append) ord_fd = creat(ordfile_new, DEF_FILE_PERMS);
5261 else {
5262 lives_cp(ordfile, ordfile_new);
5263 ord_fd = open(ordfile_new, O_CREAT | O_WRONLY | O_APPEND, DEF_FILE_PERMS);
5264 }
5265
5266 if (ord_fd < 0) {
5267 retval = do_write_failed_error_s_with_retry(ordfile, lives_strerror(errno));
5268 if (retval == LIVES_RESPONSE_CANCEL) {
5269 lives_free(ordfile);
5270 lives_free(ordfile_new);
5271 lives_chdir(cwd, FALSE);
5272 lives_free(cwd);
5273 return retval;
5274 }
5275 }
5276
5277 else {
5278 char *oldval, *newval;
5279
5280 for (cliplist = mainw->cliplist; cliplist; cliplist = cliplist->next) {
5281 if (THREADVAR(write_failed)) break;
5282 threaded_dialog_spin(0.);
5283 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
5284
5285 i = LIVES_POINTER_TO_INT(cliplist->data);
5286 if (IS_NORMAL_CLIP(i) && i != mainw->scrap_file && i != mainw->ascrap_file) {
5287 lives_snprintf(buff, PATH_MAX, "%s", mainw->files[i]->handle);
5288 get_basename(buff);
5289 if (*buff) {
5290 lives_snprintf(new_handle, 256, "%s/%s/%s", mainw->set_name, CLIPS_DIRNAME, buff);
5291 } else {
5292 lives_snprintf(new_handle, 256, "%s/%s/%s", mainw->set_name, CLIPS_DIRNAME, mainw->files[i]->handle);
5293 }
5294
5295 if (strcmp(new_handle, mainw->files[i]->handle)) {
5296 if (!add) continue;
5297
5298 new_dir = lives_build_path(prefs->workdir, new_handle, NULL);
5299 if (lives_file_test(new_dir, LIVES_FILE_TEST_IS_DIR)) {
5300 // get a new unique handle
5301 get_temp_handle(i);
5302 lives_snprintf(new_handle, 256, "%s/%s/%s", mainw->set_name, CLIPS_DIRNAME, mainw->files[i]->handle);
5303 }
5304 lives_free(new_dir);
5305
5306 // move the files
5307 oldval = lives_build_path(prefs->workdir, mainw->files[i]->handle, NULL);
5308 newval = lives_build_path(prefs->workdir, new_handle, NULL);
5309
5310 lives_mv(oldval, newval);
5311 lives_free(oldval);
5312 lives_free(newval);
5313
5314 if (THREADVAR(com_failed)) {
5315 close(ord_fd);
5316 end_threaded_dialog();
5317 lives_free(ordfile);
5318 lives_free(ordfile_new);
5319 lives_chdir(cwd, FALSE);
5320 lives_free(cwd);
5321 return FALSE;
5322 }
5323
5324 *got_new_handle = TRUE;
5325
5326 lives_snprintf(mainw->files[i]->handle, 256, "%s", new_handle);
5327 dfile = lives_build_filename(prefs->workdir, mainw->files[i]->handle, LIVES_STATUS_FILE_NAME, NULL);
5328 lives_snprintf(mainw->files[i]->info_file, PATH_MAX, "%s", dfile);
5329 lives_free(dfile);
5330 }
5331
5332 ord_entry = lives_strdup_printf("%s\n", mainw->files[i]->handle);
5333 lives_write(ord_fd, ord_entry, strlen(ord_entry), FALSE);
5334 lives_free(ord_entry);
5335 }
5336 }
5337
5338 if (THREADVAR(write_failed) == ord_fd) {
5339 THREADVAR(write_failed) = 0;
5340 retval = do_write_failed_error_s_with_retry(ordfile, NULL);
5341 }
5342 }
5343 } while (retval == LIVES_RESPONSE_RETRY);
5344
5345 close(ord_fd);
5346
5347 if (retval == LIVES_RESPONSE_CANCEL) lives_rm(ordfile_new);
5348 else lives_cp(ordfile_new, ordfile);
5349
5350 lives_free(ordfile);
5351 lives_free(ordfile_new);
5352
5353 lives_chdir(cwd, FALSE);
5354 lives_free(cwd);
5355 return retval;
5356 }
5357
5358
5359 boolean on_save_set_activate(LiVESWidget * widget, livespointer user_data) {
5360 // here is where we save clipsets
5361 // SAVE CLIPSET FUNCTION
5362 // also handles migration and merging of sets
5363 // new_set_name can be passed in userdata, it should be in filename encoding
5364 // TODO - caller to do end_threaded_dialog()
5365
5366 /////////////////
5367 /// IMPORTANT !!! mainw->no_exit must be set. otherwise the app will exit
5368 ////////////
5369
5370 char new_set_name[MAX_SET_NAME_LEN] = {0};
5371
5372 char *old_set = lives_strdup(mainw->set_name);
5373 char *layout_map_file, *layout_map_dir, *new_clips_dir, *current_clips_dir;
5374 //char *tmp;
5375 char *text;
5376
5377 char *tmp;
5378 char *osetn, *nsetn, *dfile;
5379
5380 boolean is_append = FALSE; // we will overwrite the target layout.map file
5381 boolean response;
5382 boolean got_new_handle = FALSE;
5383
5384 int retval;
5385
5386 if (!mainw->cliplist) return FALSE;
5387
5388 // warn the user what will happen
5389 if (!user_data && !do_save_clipset_warn()) return FALSE;
5390
5391 if (mainw->stored_event_list && mainw->stored_event_list_changed) {
5392 // if we have a current layout, give the user the chance to change their mind
5393 if (!check_for_layout_del(NULL, FALSE)) return FALSE;
5394 }
5395
5396 if (!user_data) {
5397 // this was called from the GUI
5398 do {
5399 // prompt for a set name, advise user to save set
5400 renamew = create_rename_dialog(2);
5401 response = lives_dialog_run(LIVES_DIALOG(renamew->dialog));
5402 if (response == LIVES_RESPONSE_CANCEL) return FALSE;
5403 lives_snprintf(new_set_name, MAX_SET_NAME_LEN, "%s",
5404 (tmp = U82F(lives_entry_get_text(LIVES_ENTRY(renamew->entry)))));
5405 lives_free(tmp);
5406 lives_widget_destroy(renamew->dialog);
5407 lives_free(renamew);
5408 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
5409 } while (!is_legal_set_name(new_set_name, TRUE, FALSE));
5410 } else lives_snprintf(new_set_name, MAX_SET_NAME_LEN, "%s", (char *)user_data);
5411
5412 lives_widget_queue_draw_and_update(LIVES_MAIN_WINDOW_WIDGET);
5413
5414 lives_snprintf(mainw->set_name, MAX_SET_NAME_LEN, "%s", new_set_name);
5415
5416 if (lives_strcmp(mainw->set_name, old_set)) {
5417 // The user CHANGED the set name
5418 // we must migrate all physical files for the set, and possibly merge with another set
5419
5420 new_clips_dir = CLIPS_DIR(mainw->set_name);
5421 // check if target clips dir exists, ask if user wants to append files
5422 if (lives_file_test(new_clips_dir, LIVES_FILE_TEST_IS_DIR)) {
5423 lives_free(new_clips_dir);
5424 if (mainw->osc_auto == 0) {
5425 if (!do_set_duplicate_warning(mainw->set_name)) {
5426 lives_snprintf(mainw->set_name, MAX_SET_NAME_LEN, "%s", old_set);
5427 return FALSE;
5428 }
5429 } else if (mainw->osc_auto == 1) return FALSE;
5430
5431 is_append = TRUE;
5432 } else {
5433 lives_free(new_clips_dir);
5434 layout_map_file = lives_build_filename(prefs->workdir, mainw->set_name, LAYOUTS_DIRNAME,
5435 LAYOUT_MAP_FILENAME, NULL);
5436 // if target has layouts dir but no clips, it means we have old layouts !
5437 if (lives_file_test(layout_map_file, LIVES_FILE_TEST_EXISTS)) {
5438 if (do_set_rename_old_layouts_warning(mainw->set_name)) {
5439 // user answered "yes" - delete
5440 // clear _old_layout maps
5441 char *dfile = lives_build_filename(prefs->workdir, mainw->set_name, LAYOUTS_DIRNAME, NULL);
5442 lives_rm(dfile);
5443 //lives_free(dfile);
5444 }
5445 }
5446 lives_free(layout_map_file);
5447 }
5448 }
5449
5450 text = lives_strdup_printf(_("Saving set %s"), mainw->set_name);
5451 do_threaded_dialog(text, FALSE);
5452 lives_free(text);
5453
5454 /////////////////////////////////////////////////////////////
5455
5456 THREADVAR(com_failed) = FALSE;
5457
5458 current_clips_dir = lives_build_filename(prefs->workdir, old_set, CLIPS_DIRNAME "/", NULL);
5459 if (*old_set && strcmp(mainw->set_name, old_set)
5460 && lives_file_test(current_clips_dir, LIVES_FILE_TEST_IS_DIR)) {
5461 // set name was changed for an existing set
5462 if (!is_append) {
5463 // create new dir, in case it doesn't already exist
5464 dfile = lives_build_filename(prefs->workdir, mainw->set_name, CLIPS_DIRNAME, NULL);
5465 if (!lives_make_writeable_dir(dfile)) {
5466 // abort if we cannot create the new subdir
5467 LIVES_ERROR("Could not create directory");
5468 LIVES_ERROR(dfile);
5469 d_print_file_error_failed();
5470 lives_snprintf(mainw->set_name, MAX_SET_NAME_LEN, "%s", old_set);
5471 lives_free(dfile);
5472 end_threaded_dialog();
5473 return FALSE;
5474 }
5475 lives_free(dfile);
5476 }
5477 } else {
5478 // saving as same name (or as new set)
5479 dfile = lives_build_filename(prefs->workdir, mainw->set_name, CLIPS_DIRNAME, NULL);
5480 if (!lives_make_writeable_dir(dfile)) {
5481 // abort if we cannot create the new subdir
5482 LIVES_ERROR("Could not create directory");
5483 LIVES_ERROR(dfile);
5484 d_print_file_error_failed();
5485 lives_snprintf(mainw->set_name, MAX_SET_NAME_LEN, "%s", old_set);
5486 lives_free(dfile);
5487 end_threaded_dialog();
5488 return FALSE;
5489 }
5490 lives_free(dfile);
5491 }
5492 lives_free(current_clips_dir);
5493
5494 if (mainw->scrap_file > -1) close_scrap_file(TRUE);
5495 if (mainw->ascrap_file > -1) close_ascrap_file(TRUE);
5496
5497 retval = rewrite_orderfile(is_append, TRUE, &got_new_handle);
5498
5499 if (retval == LIVES_RESPONSE_CANCEL) {
5500 end_threaded_dialog();
5501 return FALSE;
5502 }
5503
5504 if (mainw->num_sets > -1) mainw->num_sets++;
5505 if (!*old_set) mainw->set_list = lives_list_prepend(mainw->set_list, mainw->set_name);
5506
5507 if (got_new_handle && !*old_set) migrate_layouts(NULL, mainw->set_name);
5508
5509 if (*old_set && lives_strcmp(old_set, mainw->set_name)) {
5510 layout_map_dir = lives_build_path(prefs->workdir, old_set, LAYOUTS_DIRNAME, NULL);
5511 layout_map_file = lives_build_filename(layout_map_dir, LAYOUT_MAP_FILENAME, NULL);
5512 // update details for layouts - needs_set, current_layout_map and affected_layout_map
5513 if (lives_file_test(layout_map_file, LIVES_FILE_TEST_EXISTS)) {
5514 migrate_layouts(old_set, mainw->set_name);
5515 // save updated layout.map (with new handles), we will move it below
5516
5517 save_layout_map(NULL, NULL, NULL, layout_map_dir);
5518
5519 got_new_handle = FALSE;
5520 }
5521 lives_free(layout_map_file);
5522 lives_free(layout_map_dir);
5523
5524 if (is_append) {
5525 osetn = lives_build_filename(prefs->workdir, old_set, LAYOUTS_DIRNAME, LAYOUT_MAP_FILENAME, NULL);
5526 nsetn = lives_build_filename(prefs->workdir, mainw->set_name, LAYOUTS_DIRNAME, LAYOUT_MAP_FILENAME, NULL);
5527
5528 if (lives_file_test(osetn, LIVES_FILE_TEST_EXISTS)) {
5529 //append current layout.map to target one
5530 lives_cat(osetn, nsetn, TRUE); /// command may not fail, so we check first
5531 lives_rm(osetn);
5532 }
5533 lives_free(osetn);
5534 lives_free(nsetn);
5535 }
5536
5537 osetn = lives_build_path(prefs->workdir, old_set, LAYOUTS_DIRNAME, NULL);
5538
5539 if (lives_file_test(osetn, LIVES_FILE_TEST_IS_DIR)) {
5540 nsetn = lives_build_filename(prefs->workdir, mainw->set_name, NULL);
5541
5542 // move any layouts from old set to new (including layout.map)
5543 lives_cp_keep_perms(osetn, nsetn);
5544
5545 lives_free(nsetn);
5546 }
5547
5548 lives_free(osetn);
5549
5550 // remove the old set (should be empty now)
5551 cleanup_set_dir(old_set);
5552 }
5553
5554 if (!mainw->was_set && !strcmp(old_set, mainw->set_name)) {
5555 // set name was set by export or save layout, now we need to update our layout map
5556 layout_map_dir = lives_build_filename(prefs->workdir, old_set, LAYOUTS_DIRNAME, NULL);
5557 layout_map_file = lives_build_filename(layout_map_dir, LAYOUT_MAP_FILENAME, NULL);
5558 if (lives_file_test(layout_map_file, LIVES_FILE_TEST_EXISTS)) save_layout_map(NULL, NULL, NULL, layout_map_dir);
5559 mainw->was_set = TRUE;
5560 got_new_handle = FALSE;
5561 lives_free(layout_map_dir);
5562 lives_free(layout_map_file);
5563 if (mainw->multitrack && !mainw->multitrack->changed) recover_layout_cancelled(FALSE);
5564 }
5565
5566 if (mainw->current_layouts_map && strcmp(old_set, mainw->set_name) && !mainw->suppress_layout_warnings) {
5567 // warn the user about layouts if the set name changed
5568 // but, don't bother the user with errors if we are exiting
5569 add_lmap_error(LMAP_INFO_SETNAME_CHANGED, old_set, mainw->set_name, 0, 0, 0., FALSE);
5570 popup_lmap_errors(NULL, NULL);
5571 }
5572
5573 lives_notify(LIVES_OSC_NOTIFY_CLIPSET_SAVED, old_set);
5574
5575 lives_free(old_set);
5576 mainw->leave_files = TRUE;
5577 if (mainw->multitrack && !mainw->only_close) mt_memory_free();
5578 else if (mainw->multitrack) wipe_layout(mainw->multitrack);
5579
5580 // do a lot of cleanup here, but leave files
5581 lives_exit(0);
5582 mainw->leave_files = FALSE;
5583 //end_threaded_dialog();
5584
5585 lives_widget_set_sensitive(mainw->vj_load_set, TRUE);
5586 return TRUE;
5587 }
5588
5589
5590 char *on_load_set_activate(LiVESMenuItem * menuitem, livespointer user_data) {
5591 // get set name (use a modified rename window)
5592 char *set_name = NULL;
5593 LiVESResponseType resp;
5594 mainw->mt_needs_idlefunc = FALSE;
5595
5596 if (mainw->multitrack) {
5597 if (mainw->multitrack->idlefunc > 0) {
5598 lives_source_remove(mainw->multitrack->idlefunc);
5599 mainw->multitrack->idlefunc = 0;
5600 mainw->mt_needs_idlefunc = TRUE;
5601 }
5602 mt_desensitise(mainw->multitrack);
5603 }
5604
5605 renamew = create_rename_dialog(3);
5606 if (!renamew) return NULL; ///< no sets available
5607
5608 resp = lives_dialog_run(LIVES_DIALOG(renamew->dialog));
5609
5610 if (resp == LIVES_RESPONSE_OK) {
5611 set_name = U82F(lives_entry_get_text(LIVES_ENTRY(renamew->entry)));
5612 }
5613
5614 // need to clean up renamew
5615 lives_widget_destroy(renamew->dialog);
5616 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
5617 lives_freep((void **)&renamew);
5618
5619 if (resp == LIVES_RESPONSE_OK) {
5620 if (!is_legal_set_name(set_name, TRUE, TRUE)) {
5621 lives_freep((void **)&set_name);
5622 } else {
5623 if (!user_data) {
5624 if (mainw->cliplist)
5625 if (!do_reload_set_query()) return NULL;
5626 reload_set(set_name);
5627 lives_free(set_name);
5628 if (mainw->num_sets > -1) mainw->num_sets--;
5629 return NULL;
5630 }
5631 }
5632 }
5633
5634 return set_name;
5635 }
5636
5637
5638 void lock_set_file(const char *set_name) {
5639 // function is called when a set is opened, to prevent multiple acces to the same set
5640 char *setdir = lives_build_path(prefs->workdir, set_name, NULL);
5641 if (lives_file_test(setdir, LIVES_FILE_TEST_IS_DIR)) {
5642 char *set_lock_file = lives_strdup_printf("%s.%d", SET_LOCK_FILENAME, capable->mainpid);
5643 char *set_locker = SET_LOCK_FILE(set_name, set_lock_file);
5644 lives_touch(set_locker);
5645 lives_free(set_locker);
5646 lives_free(set_lock_file);
5647 }
5648 lives_free(setdir);
5649 }
5650
5651
5652 void unlock_set_file(const char *set_name) {
5653 char *set_lock_file = lives_strdup_printf("%s.%d", SET_LOCK_FILENAME, capable->mainpid);
5654 char *set_locker = SET_LOCK_FILE(set_name, set_lock_file);
5655 lives_rm(set_locker);
5656 lives_free(set_lock_file);
5657 lives_free(set_locker);
5658 }
5659
5660
5661 boolean reload_set(const char *set_name) {
5662 // this is the main clip set loader
5663
5664 // CLIP SET LOADER
5665
5666 // setname should be in filesystem encoding
5667
5668 FILE *orderfile;
5669 lives_clip_t *sfile;
5670
5671 char *msg, *com, *ordfile, *cwd, *clipdir, *handle = NULL;
5672
5673 boolean added_recovery = FALSE;
5674 boolean keep_threaded_dialog = FALSE;
5675 boolean hadbad = FALSE;
5676
5677 int last_file = -1, new_file = -1;
5678 int current_file = mainw->current_file;
5679 int clipnum = 0;
5680 int maxframe;
5681 mainw->mt_needs_idlefunc = FALSE;
5682
5683 if (mainw->multitrack) {
5684 if (mainw->multitrack->idlefunc > 0) {
5685 lives_source_remove(mainw->multitrack->idlefunc);
5686 mainw->multitrack->idlefunc = 0;
5687 mainw->mt_needs_idlefunc = TRUE;
5688 }
5689 }
5690 lives_memset(mainw->set_name, 0, 1);
5691
5692 // check if set is locked
5693 if (!check_for_lock_file(set_name, 0)) {
5694 if (!mainw->recovering_files) {
5695 d_print_cancelled();
5696 if (mainw->multitrack) {
5697 mainw->current_file = mainw->multitrack->render_file;
5698 mt_sensitise(mainw->multitrack);
5699 maybe_add_mt_idlefunc();
5700 }
5701 }
5702 return FALSE;
5703 }
5704
5705 lives_snprintf(mainw->msg, MAINW_MSG_SIZE, "none");
5706
5707 // check if we already have a threaded dialog running (i.e. we are called from startup)
5708 if (mainw->threaded_dialog) keep_threaded_dialog = TRUE;
5709
5710 if (prefs->show_gui && !keep_threaded_dialog) {
5711 char *tmp;
5712 msg = lives_strdup_printf(_("Loading clips from set %s"), (tmp = F2U8(set_name)));
5713 do_threaded_dialog(msg, FALSE);
5714 lives_free(msg);
5715 lives_free(tmp);
5716 }
5717
5718 ordfile = lives_build_filename(prefs->workdir, set_name, CLIP_ORDER_FILENAME, NULL);
5719
5720 orderfile = fopen(ordfile, "r"); // no we can't assert this, because older sets did not have this file
5721 lives_free(ordfile);
5722
5723 mainw->suppress_dprint = TRUE;
5724 THREADVAR(read_failed) = FALSE;
5725
5726 // lock the set
5727 lock_set_file(set_name);
5728
5729 cwd = lives_get_current_dir();
5730
5731 while (1) {
5732 if (prefs->show_gui) threaded_dialog_spin(0.);
5733
5734 if (mainw->hdrs_cache) cached_list_free(&mainw->hdrs_cache);
5735
5736 if (!orderfile) {
5737 // old style (pre 0.9.6)
5738 com = lives_strdup_printf("%s get_next_in_set \"%s\" \"%s\" %d", prefs->backend_sync, mainw->msg,
5739 set_name, capable->mainpid);
5740 lives_system(com, FALSE);
5741 lives_free(com);
5742 } else {
5743 if (!lives_fgets(mainw->msg, MAINW_MSG_SIZE, orderfile)) clear_mainw_msg();
5744 else lives_memset(mainw->msg + lives_strlen(mainw->msg) - 1, 0, 1);
5745 }
5746
5747 if (!(*mainw->msg) || (!strncmp(mainw->msg, "none", 4))) {
5748 if (!mainw->recovering_files) mainw->suppress_dprint = FALSE;
5749 if (!keep_threaded_dialog) end_threaded_dialog();
5750
5751 if (orderfile) fclose(orderfile);
5752
5753 //mainw->current_file = current_file;
5754
5755 if (!mainw->multitrack) {
5756 if (last_file > 0) {
5757 threaded_dialog_spin(0.);
5758 switch_to_file(current_file, last_file);
5759 threaded_dialog_spin(0.);
5760 }
5761 }
5762
5763 if (clipnum == 0) {
5764 do_set_noclips_error(set_name);
5765 } else {
5766 char *tmp;
5767 reset_clipmenu();
5768 lives_widget_set_sensitive(mainw->vj_load_set, FALSE);
5769
5770 // MUST set set_name before calling this
5771 recover_layout_map(MAX_FILES);
5772
5773 // TODO - check for missing frames and audio in layouts
5774
5775 if (hadbad) rewrite_orderfile(FALSE, FALSE, NULL);
5776
5777 d_print(_("%d clips and %d layouts were recovered from set (%s).\n"),
5778 clipnum, lives_list_length(mainw->current_layouts_map), (tmp = F2U8(set_name)));
5779 lives_free(tmp);
5780 lives_snprintf(mainw->set_name, MAX_SET_NAME_LEN, "%s", set_name);
5781 lives_notify(LIVES_OSC_NOTIFY_CLIPSET_OPENED, mainw->set_name);
5782 }
5783
5784 threaded_dialog_spin(0.);
5785 if (!mainw->multitrack) {
5786 if (mainw->is_ready) {
5787 if (clipnum > 0 && CURRENT_CLIP_IS_VALID) {
5788 showclipimgs();
5789 }
5790 // force a redraw
5791 update_play_times();
5792 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
5793 }
5794 } else {
5795 mainw->current_file = mainw->multitrack->render_file;
5796 polymorph(mainw->multitrack, POLY_NONE);
5797 polymorph(mainw->multitrack, POLY_CLIPS);
5798 mt_sensitise(mainw->multitrack);
5799 maybe_add_mt_idlefunc();
5800 }
5801 if (!keep_threaded_dialog) end_threaded_dialog();
5802 lives_chdir(cwd, FALSE);
5803 lives_free(cwd);
5804 if (mainw->multitrack)
5805 mt_clip_select(mainw->multitrack, TRUE); // scroll clip on screen
5806 sensitize();
5807 return TRUE;
5808 }
5809
5810 if (clipnum > 0)
5811 mainw->was_set = TRUE;
5812
5813 if (prefs->crash_recovery && !added_recovery) {
5814 char *recovery_entry = lives_build_filename(set_name, "*", NULL);
5815 add_to_recovery_file(recovery_entry);
5816 lives_free(recovery_entry);
5817 added_recovery = TRUE;
5818 }
5819
5820 clipdir = lives_build_filename(prefs->workdir, mainw->msg, NULL);
5821 if (orderfile) {
5822 // newer style (0.9.6+)
5823
5824 if (!lives_file_test(clipdir, LIVES_FILE_TEST_IS_DIR)) {
5825 lives_free(clipdir);
5826 continue;
5827 }
5828 threaded_dialog_spin(0.);
5829
5830 //create a new cfile and fill in the details
5831 handle = lives_strndup(mainw->msg, 256);
5832 }
5833
5834 // changes mainw->current_file on success
5835 sfile = create_cfile(-1, handle, FALSE);
5836 if (handle) lives_free(handle);
5837 handle = NULL;
5838 threaded_dialog_spin(0.);
5839
5840 if (!sfile) {
5841 lives_free(clipdir);
5842 mainw->suppress_dprint = FALSE;
5843
5844 if (!keep_threaded_dialog) end_threaded_dialog();
5845
5846 if (mainw->multitrack) {
5847 mainw->current_file = mainw->multitrack->render_file;
5848 polymorph(mainw->multitrack, POLY_NONE);
5849 polymorph(mainw->multitrack, POLY_CLIPS);
5850 mt_sensitise(mainw->multitrack);
5851 maybe_add_mt_idlefunc();
5852 }
5853
5854 recover_layout_map(MAX_FILES);
5855 lives_chdir(cwd, FALSE);
5856 lives_free(cwd);
5857 fclose(orderfile);
5858 return FALSE;
5859 }
5860
5861 // get file details
5862 if (!read_headers(mainw->current_file, clipdir, NULL)) {
5863 /// set clip failed to load, we need to do something with it
5864 /// else it will keep trying to reload each time.
5865 /// for now we shall just move it out of the set
5866 /// this is fine as the user can try to recover it at a later time
5867 lives_free(clipdir);
5868 lives_free(mainw->files[mainw->current_file]);
5869 mainw->files[mainw->current_file] = NULL;
5870 if (mainw->first_free_file > mainw->current_file) mainw->first_free_file = mainw->current_file;
5871 if (mainw->hdrs_cache) cached_list_free(&mainw->hdrs_cache);
5872 hadbad = TRUE;
5873 continue;
5874 }
5875 lives_free(clipdir);
5876
5877 threaded_dialog_spin(0.);
5878
5879 /** read_headers() will have read the clip metadata file, so we 'know' how many frames there ought to be.
5880 however this could be wrong if the file was damaged for some reason. So the first step is to read the file_index if any.
5881 - if present we assume we are dealing with CLIP_TYPE_FILE (original clip + decoded frames).
5882 -- If it contains more frames then we will increase cfile->frames.
5883 - If it is not present then we assume are dealing with CLIP_TYPE_DISK (all frames decoded to images).
5884
5885 we want to do as little checking here as possible, since it can slow down the startup, but if we detect a problem then we'll
5886 do increasingly more checking.
5887 */
5888
5889 if ((maxframe = load_frame_index(mainw->current_file)) > 0) {
5890 // CLIP_TYPE_FILE
5891 /** here we attempt to reload the clip. First we load the frame_index if any, If it contains more frames than the metadata says, then
5892 we trust the frame_index for now, since the metadata may have been corrupted.
5893 If it contains fewer frames, then we will warn the user, but we cannot know whether the metadata is correct or not,
5894 and in any case we cannot reconstruct the frame_index, so we have to use what it tells us.
5895 If file_index is absent then we assume we are dealing with CLIP_TYPE_DISK (below).
5896
5897 Next we attempt to reload the original clip using the same decoder plugin as last time if possible.
5898 The decoder may return fewer frames from the original clip than the size of frame_index,
5899 This is OK provided the final frames are decoded frames.
5900 We then check backwards from the end of file_index to find the final decoded frame.
5901 If this is the frame we expected then we assume all is OK */
5902
5903 if (!reload_clip(mainw->current_file, maxframe)) {
5904 if (mainw->hdrs_cache) cached_list_free(&mainw->hdrs_cache);
5905 continue;
5906 }
5907 if (cfile->clip_type == CLIP_TYPE_FILE && cfile->header_version >= 102) cfile->fps = cfile->pb_fps;
5908
5909 /** if the image type is still unkown it means either there were no decoded frames, or the final decoded frame was absent
5910 so we count the virtual frames. If all are virtual then we set img_type to prefs->img_type and assume all is OK
5911 (or at least we recovered as many frames as we could using frame_index),
5912 and we'll accept whatever the decoder returns if there is a divergence with the clip metadata */
5913
5914 if (!cfile->checked && cfile->img_type == IMG_TYPE_UNKNOWN) {
5915 lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
5916 int fvirt = count_virtual_frames(cfile->frame_index, 1, cfile->frames);
5917 /** if there are some decoded frames then we have a problem.
5918 Since the img type was not found it means that the final decoded
5919 frame was missing. So we check backwards to find where the last actual decoded frame is and the frame count is set to
5920 final decoded frame + any virtual frames immediately following, and warn the user.
5921 If other frames are missing then the clip is corrupt, but we'll continue as best we can. */
5922 if (fvirt < cfile->frames) check_clip_integrity(mainw->current_file, cdata, cfile->frames);
5923 }
5924 cfile->checked = TRUE;
5925 } else {
5926 /// CLIP_TYPE_DISK
5927 /** in this case we find the last decoded frame and check the frame size and get the image_type.
5928 If there is a discrepancy with the metadata then we trust the empirical evidence.
5929 If the final frame is absent then we find the real final frame, warn the user, and adjust frame count.
5930 */
5931 boolean isok = TRUE;
5932 if (!cfile->checked) isok = check_clip_integrity(mainw->current_file, NULL, cfile->frames);
5933 cfile->checked = TRUE;
5934 /** here we do a simple check: make sure the final frame is present and frame + 1 isn't
5935 if either check fails then we count all the frames (since we don't have a frame_index to guide us),
5936 - this can be pretty slow so we wan't to avoid it unless we detected a problem. */
5937 if (!check_frame_count(mainw->current_file, isok)) {
5938 cfile->frames = get_frame_count(mainw->current_file, 1);
5939 if (cfile->frames == -1) {
5940 close_current_file(0);
5941 if (mainw->hdrs_cache) cached_list_free(&mainw->hdrs_cache);
5942 continue;
5943 }
5944 cfile->needs_update = TRUE;
5945 }
5946 }
5947
5948 if (!prefs->vj_mode) {
5949 if (cfile->achans > 0 && cfile->afilesize == 0) {
5950 reget_afilesize_inner(mainw->current_file);
5951 }
5952 }
5953
5954 last_file = new_file;
5955
5956 if (++clipnum == 1) {
5957 /** we need to set the set_name before calling add_to_clipmenu(), so that the clip gets the name of the set in
5958 its menuentry, and also prior to loading any layouts since they specirfy the clipset they need */
5959 lives_snprintf(mainw->set_name, MAX_SET_NAME_LEN, "%s", set_name);
5960 }
5961
5962 /// read the playback fps, play frame, and name
5963 open_set_file(clipnum); ///< must do before calling save_clip_values()
5964 if (cfile->clip_type == CLIP_TYPE_FILE && cfile->header_version >= 102) cfile->fps = cfile->pb_fps;
5965
5966 /// if this is set then it means we are auto reloading the clipset from the previous session, so restore full details
5967 if (future_prefs->ar_clipset) restore_clip_binfmt(mainw->current_file);
5968
5969 threaded_dialog_spin(0.);
5970 cfile->was_in_set = TRUE;
5971
5972 if (cfile->frameno > cfile->frames) cfile->frameno = cfile->last_frameno = 1;
5973
5974 if (cfile->needs_update || cfile->needs_silent_update) {
5975 if (cfile->needs_update) do_clip_divergence_error(mainw->current_file);
5976 save_clip_values(mainw->current_file);
5977 cfile->needs_silent_update = cfile->needs_update = FALSE;
5978 }
5979
5980 if (mainw->hdrs_cache) cached_list_free(&mainw->hdrs_cache);
5981
5982 if (prefs->autoload_subs) {
5983 reload_subs(mainw->current_file);
5984 threaded_dialog_spin(0.);
5985 }
5986
5987 get_total_time(cfile);
5988
5989 cfile->saved_frameno = cfile->frameno;
5990 if (cfile->frameno > cfile->frames && cfile->frameno > 1) cfile->frameno = cfile->frames;
5991 cfile->last_frameno = cfile->frameno;
5992
5993 cfile->pointer_time = cfile->real_pointer_time = calc_time_from_frame(mainw->current_file, cfile->frameno);
5994 if (cfile->real_pointer_time > CLIP_TOTAL_TIME(mainw->current_file))
5995 cfile->real_pointer_time = CLIP_TOTAL_TIME(mainw->current_file);
5996 if (cfile->pointer_time > cfile->video_time) cfile->pointer_time = 0.;
5997
5998 if (cfile->achans) {
5999 cfile->aseek_pos = (off64_t)((double)(cfile->real_pointer_time * cfile->arate) * cfile->achans *
6000 (cfile->asampsize / 8));
6001 if (cfile->aseek_pos > cfile->afilesize) cfile->aseek_pos = 0.;
6002 }
6003
6004 // add to clip menu
6005 threaded_dialog_spin(0.);
6006 add_to_clipmenu();
6007 cfile->start = cfile->frames > 0 ? 1 : 0;
6008 cfile->end = cfile->frames;
6009 cfile->is_loaded = TRUE;
6010 cfile->changed = TRUE;
6011 lives_rm(cfile->info_file);
6012 set_main_title(cfile->name, 0);
6013 restore_clip_binfmt(mainw->current_file);
6014
6015 if (!mainw->multitrack) {
6016 resize(1);
6017 }
6018
6019 if (mainw->multitrack && mainw->multitrack->is_ready) {
6020 new_file = mainw->current_file;
6021 mainw->current_file = mainw->multitrack->render_file;
6022 mt_init_clips(mainw->multitrack, new_file, TRUE);
6023 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
6024 mt_clip_select(mainw->multitrack, TRUE);
6025 }
6026
6027 lives_notify(LIVES_OSC_NOTIFY_CLIP_OPENED, "");
6028 }
6029
6030 // should never reach here
6031 lives_chdir(cwd, FALSE);
6032 lives_free(cwd);
6033 return TRUE;
6034 }
6035
6036
6037 static void recover_lost_clips(LiVESList * reclist) {
6038 if (!do_foundclips_query()) return;
6039
6040 //d_print_cancelled();
6041
6042 // save set
6043 if (!CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID) {
6044 on_quit_activate(NULL, LIVES_INT_TO_POINTER(1));
6045 if (mainw->clips_available) return;
6046 }
6047
6048 // recover files
6049 mainw->recovery_list = reclist;
6050 recover_files(NULL, TRUE);
6051
6052 if (prefs->crash_recovery) rewrite_recovery_file();
6053
6054 if (!CURRENT_CLIP_IS_VALID) {
6055 int start_file;
6056 for (start_file = MAX_FILES; start_file > 0; start_file--) {
6057 if (IS_VALID_CLIP(start_file)
6058 && (mainw->files[start_file]->frames > 0 || mainw->files[start_file]->afilesize > 0)) break;
6059 }
6060 switch_to_file(-1, start_file);
6061 }
6062 do_info_dialogf(P_("$d clip was recovered", "%d clips were recovered\n",
6063 mainw->clips_available), mainw->clips_available);
6064 }
6065
6066
6067 static boolean handle_remnants(LiVESList * recnlist, const char *trashremdir, LiVESList **rem_list) {
6068 LiVESResponseType resp;
6069 LiVESList *list = recnlist;
6070 char *unrecdir = lives_build_path(prefs->workdir, UNREC_CLIPS_DIR, NULL);
6071 char *text = lives_strdup_printf(_("Some clips could not be recovered.\n"
6072 "These items can be deleted or moved to the directory\n%s\n"
6073 "What would you like to do with them ?"), unrecdir);
6074 LiVESWidget *dialog = create_question_dialog(_("Unrecoverable Clips"), text), *bbox, *cancelbutton;
6075
6076 lives_free(text);
6077
6078 cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_CANCEL, _("Ignore"),
6079 LIVES_RESPONSE_CANCEL);
6080
6081 lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_DELETE, _("Delete them"),
6082 LIVES_RESPONSE_NO);
6083
6084 lives_dialog_add_button_from_stock(LIVES_DIALOG(dialog), LIVES_STOCK_SAVE, _("Move them"),
6085 LIVES_RESPONSE_OK);
6086
6087 bbox = lives_dialog_get_action_area(LIVES_DIALOG(dialog));
6088 trash_rb(LIVES_BUTTON_BOX(bbox));
6089 lives_dialog_add_escape(LIVES_DIALOG(dialog), cancelbutton);
6090
6091 resp = lives_dialog_run(LIVES_DIALOG(dialog));
6092 lives_widget_destroy(dialog);
6093 lives_widget_context_update();
6094 THREADVAR(com_failed) = FALSE;
6095
6096 if (resp == LIVES_RESPONSE_CANCEL) return FALSE;
6097
6098 if (resp == LIVES_RESPONSE_OK) {
6099 // move from workdir to workdir/unrec
6100 char *from, *to, *norem;
6101 char *ucdir = lives_build_path(prefs->workdir, UNREC_CLIPS_DIR, NULL);
6102 lives_mkdir_with_parents(ucdir, capable->umask);
6103 if (!lives_file_test(ucdir, LIVES_FILE_TEST_IS_DIR)) return FALSE;
6104 norem = lives_build_filename(ucdir, LIVES_FILENAME_NOREMOVE, NULL);
6105 lives_touch(norem);
6106 lives_free(norem);
6107 for (; list; list = list->next) {
6108 from = lives_build_path(prefs->workdir, (char *)list->data, NULL);
6109 to = lives_build_path(ucdir, (char *)list->data, NULL);
6110 lives_mv(from, to);
6111 lives_free(from); lives_free(to);
6112 if (THREADVAR(com_failed)) {
6113 THREADVAR(com_failed) = FALSE;
6114 return FALSE;
6115 }
6116 }
6117 lives_free(ucdir);
6118 } else {
6119 char *tfile;
6120 lives_file_dets_t *fdets;
6121 // touch files in remdir, also prepend to remdir so we dont skip removal
6122 for (; list; list = list->next) {
6123 tfile = lives_build_filename(trashremdir, (char *)list->data, NULL);
6124 lives_touch(tfile);
6125 lives_free(tfile);
6126 if (THREADVAR(com_failed)) {
6127 THREADVAR(com_failed) = FALSE;
6128 return FALSE;
6129 }
6130 fdets = (lives_file_dets_t *)struct_from_template(LIVES_STRUCT_FILE_DETS_T);
6131 fdets->name = lives_strdup((char *)list->data);
6132 *rem_list = lives_list_prepend(*rem_list, fdets);
6133 }
6134 }
6135 return TRUE;
6136 }
6137
6138
6139 void on_cleardisk_activate(LiVESWidget * widget, livespointer user_data) {
6140 // recover disk space
6141 lives_file_dets_t *filedets;
6142 lives_proc_thread_t tinfo;
6143 LiVESTextBuffer *tbuff;
6144 LiVESWidget *top_vbox;
6145
6146 LiVESList *lists[3];
6147 LiVESList **left_list, **rec_list, **rem_list;
6148 LiVESList *list;
6149
6150 int64_t bytes = 0, fspace = -1;
6151 int64_t ds_warn_level = mainw->next_ds_warn_level;
6152
6153 uint64_t ukey;
6154
6155 char *uidgid;
6156 char *trashdir = NULL, *full_trashdir = NULL;
6157
6158 char *markerfile, *filedir;
6159 char *com, *msg, *tmp;
6160 char *extra = lives_strdup("");
6161
6162 LiVESResponseType retval = LIVES_RESPONSE_NONE, resp;
6163
6164 boolean gotsize = FALSE;
6165
6166 int current_file = mainw->current_file;
6167 int marker_fd;
6168 int i, ntok, nitems = 0;
6169
6170 mainw->mt_needs_idlefunc = FALSE;
6171
6172 mainw->next_ds_warn_level = 0; /// < avoid nested warnings
6173
6174 if (user_data) lives_widget_hide(lives_widget_get_toplevel(LIVES_WIDGET(user_data)));
6175
6176 rec_list = &lists[0];
6177 rem_list = &lists[1];
6178 left_list = &lists[2];
6179
6180 *rec_list = *rem_list = *left_list = NULL;
6181
6182 mainw->tried_ds_recover = TRUE; ///< indicates we tried ds recovery already
6183 mainw->add_clear_ds_adv = TRUE; ///< auto reset by do_warning_dialog()
6184 if (!(prefs->clear_disk_opts & LIVES_CDISK_REMOVE_ORPHAN_CLIPS)) {
6185 lives_free(extra);
6186 extra = (_("\n\nIf potential missing clips are detected, you will be provided "
6187 "the option to try to recover them\n"
6188 "before they are removed permanently from the disk.\n\n"
6189 "<b>You will also have an opportunity to view and revise the list of items to be removed "
6190 "before continuing.</b>\n"));
6191 }
6192 widget_opts.use_markup = TRUE;
6193 if (!do_warning_dialogf(
6194 _("LiVES will attempt to recover some disk space.\n"
6195 "Unnecessary files will be removed from %s\n"
6196 "You should <b>ONLY</b> run this if you have no other copies of LiVES running on this machine.\n"
6197 "%s\nClick OK to proceed.\n"), tmp = lives_markup_escape_text(prefs->workdir, -1), extra)) {
6198 widget_opts.use_markup = FALSE;
6199 lives_free(tmp);
6200 lives_free(extra);
6201 mainw->next_ds_warn_level = ds_warn_level;
6202 goto end;
6203 }
6204 widget_opts.use_markup = FALSE;
6205 lives_free(extra);
6206
6207 if (CURRENT_CLIP_IS_VALID) cfile->cb_src = current_file;
6208
6209 lives_set_cursor_style(LIVES_CURSOR_BUSY, NULL);
6210
6211 d_print(_("Cleaning up disk space..."));
6212 // get a temporary clip for receiving data from backend
6213 if (!get_temp_handle(-1)) {
6214 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
6215 d_print_failed();
6216 mainw->next_ds_warn_level = ds_warn_level;
6217 return;
6218 }
6219
6220 if (mainw->multitrack) {
6221 if (mainw->multitrack->idlefunc > 0) {
6222 lives_source_remove(mainw->multitrack->idlefunc);
6223 mainw->multitrack->idlefunc = 0;
6224 mainw->mt_needs_idlefunc = TRUE;
6225 }
6226 mt_desensitise(mainw->multitrack);
6227 }
6228
6229 ukey = gen_unique_id();
6230 uidgid = lives_strdup_printf("-%d-%d", lives_getuid(), lives_getgid());
6231 trashdir = lives_strdup_printf("%s%lu%s", TRASH_NAME, ukey, uidgid);
6232
6233 for (i = 0; i < MAX_FILES; i++) {
6234 // mark all free-floating files (directories) which we do not want to remove
6235 // we do error checking here
6236 if (mainw->files[i] && *mainw->files[i]->handle) {
6237 filedir = lives_build_path(prefs->workdir, mainw->files[i]->handle, NULL);
6238 if (lives_file_test(filedir, LIVES_FILE_TEST_IS_DIR)) {
6239 markerfile = lives_build_filename(filedir, LIVES_FILENAME_INUSE, NULL);
6240 lives_echo(trashdir, markerfile, FALSE);
6241 lives_free(markerfile);
6242 if (mainw->files[i]->undo_action != UNDO_NONE) {
6243 markerfile = lives_build_filename(filedir, LIVES_FILENAME_NOCLEAN, NULL);
6244 do {
6245 retval = LIVES_RESPONSE_NONE;
6246 marker_fd = creat(markerfile, S_IRUSR | S_IWUSR);
6247 if (marker_fd < 0) {
6248 retval = do_write_failed_error_s_with_retry(markerfile, lives_strerror(errno));
6249 }
6250 } while (retval == LIVES_RESPONSE_RETRY);
6251 if (marker_fd >= 0) close(marker_fd);
6252 lives_free(markerfile);
6253 if (retval == LIVES_RESPONSE_CANCEL) goto cleanup;
6254 // *INDENT-OFF*
6255 }}}}
6256 // *INDENT-ON*
6257
6258 full_trashdir = lives_build_path(prefs->workdir, trashdir, NULL);
6259
6260 do {
6261 resp = LIVES_RESPONSE_NONE;
6262 if (!lives_make_writeable_dir(full_trashdir) || !check_dir_access(full_trashdir, TRUE)) {
6263 resp = do_dir_perm_error(full_trashdir, TRUE);
6264 if (resp == LIVES_RESPONSE_CANCEL) goto cleanup;
6265 }
6266 } while (resp == LIVES_RESPONSE_RETRY);
6267
6268 // get space before
6269 fspace = get_ds_free(prefs->workdir);
6270
6271 //if (prefs->autoclean) {
6272 // clearup old
6273 mainw->cancelled = CANCEL_NONE;
6274
6275 com = lives_strdup_printf("%s empty_trash %s general %s", prefs->backend, cfile->handle,
6276 TRASH_NAME);
6277 lives_rm(cfile->info_file);
6278 lives_system(com, FALSE);
6279 lives_free(com);
6280 do_auto_dialog(_("Removing general trash"), 0);
6281
6282 THREADVAR(com_failed) = FALSE;
6283
6284 if (CURRENT_CLIP_IS_VALID) lives_rm(cfile->info_file);
6285
6286 tinfo = lives_proc_thread_create(LIVES_THRDATTR_NONE, (lives_funcptr_t)do_auto_dialog, -1,
6287 "si", _("Analysing Disk"), 0);
6288 tbuff = lives_text_buffer_new();
6289 com = lives_strdup_printf("%s disk_check %s %u %s", prefs->backend, cfile->handle,
6290 prefs->clear_disk_opts, trashdir);
6291 lives_free(uidgid);
6292 lives_popen(com, TRUE, (char *)tbuff, 0);
6293 lives_free(com);
6294
6295 lives_proc_thread_join(tinfo);
6296
6297 if (*mainw->msg && (ntok = get_token_count(mainw->msg, '|')) > 1) {
6298 char **array = lives_strsplit(mainw->msg, "|", 2);
6299 if (!strcmp(array[0], "completed")) {
6300 nitems = atoi(array[1]);
6301 }
6302 lives_strfreev(array);
6303 }
6304
6305 // remove the protective markers
6306 for (i = 0; i < MAX_FILES; i++) {
6307 if (mainw->files[i] && *mainw->files[i]->handle) {
6308 filedir = lives_build_path(prefs->workdir, mainw->files[i]->handle, NULL);
6309 if (lives_file_test(filedir, LIVES_FILE_TEST_IS_DIR)) {
6310 markerfile = lives_build_filename(prefs->workdir, mainw->files[i]->handle,
6311 LIVES_FILENAME_INUSE, NULL);
6312 lives_rm(markerfile);
6313 lives_free(markerfile);
6314 if (mainw->files[i]->undo_action != UNDO_NONE) {
6315 markerfile = lives_build_filename(prefs->workdir, mainw->files[i]->handle,
6316 LIVES_FILENAME_NOCLEAN, NULL);
6317 lives_rm(markerfile);
6318 lives_free(markerfile);
6319 // *INDENT-OFF*
6320 }}}}
6321 // *INDENT-ON*
6322
6323 if (THREADVAR(com_failed)) {
6324 THREADVAR(com_failed) = FALSE;
6325 } else {
6326 LiVESAccelGroup *accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
6327 LiVESWidget *button, *accb, *hbox, *label;
6328 lives_proc_thread_t recinfo, reminfo, leaveinfo;
6329 char *remtrashdir, *op, *from, *to;
6330 int orig;
6331
6332 if (nitems) {
6333 char *dirname = lives_build_path(full_trashdir, TRASH_RECOVER, NULL);
6334 recinfo =
6335 dir_to_file_details(rec_list, dirname, prefs->workdir,
6336 EXTRA_DETAILS_CLIPHDR);
6337 lives_free(dirname);
6338
6339 dirname = lives_build_path(full_trashdir, TRASH_REMOVE, NULL);
6340 reminfo =
6341 dir_to_file_details(rem_list, dirname, prefs->workdir,
6342 EXTRA_DETAILS_EMPTY_DIRS | EXTRA_DETAILS_DIRSIZE);
6343 lives_free(dirname);
6344
6345 dirname = lives_build_path(full_trashdir, TRASH_LEAVE, NULL);
6346 leaveinfo =
6347 dir_to_file_details(left_list, dirname, prefs->workdir,
6348 EXTRA_DETAILS_EMPTY_DIRS | EXTRA_DETAILS_DIRSIZE);
6349 lives_free(dirname);
6350 } else {
6351 *rec_list = lives_list_append(*rec_list, NULL);
6352 *rem_list = lives_list_append(*rem_list, NULL);
6353 *left_list = lives_list_append(*left_list, NULL);
6354 }
6355
6356 widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH;
6357 textwindow = create_text_window(_("Disk Analysis Log"), NULL, tbuff, FALSE);
6358 widget_opts.expand = LIVES_EXPAND_DEFAULT;;
6359
6360 lives_window_add_accel_group(LIVES_WINDOW(textwindow->dialog), accel_group);
6361
6362 top_vbox = lives_dialog_get_content_area(LIVES_DIALOG(textwindow->dialog));
6363
6364 hbox = lives_hbox_new(FALSE, 0);
6365 lives_box_pack_start(LIVES_BOX(top_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
6366 msg = lives_strdup_printf(_("\nAnalysis of directory %s complete.\n\n"), prefs->workdir);
6367 label = lives_standard_label_new(msg);
6368 lives_free(msg);
6369
6370 lives_box_pack_start(LIVES_BOX(hbox), label, TRUE, TRUE, 0);
6371 lives_widget_set_halign(label, LIVES_ALIGN_CENTER);
6372
6373 if (!nitems) {
6374 hbox = lives_hbox_new(FALSE, 0);
6375 lives_box_pack_start(LIVES_BOX(top_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
6376 msg = _("No items to be removed or recovered were detected.\n");
6377 label = lives_standard_label_new(msg);
6378 lives_free(msg);
6379
6380 lives_box_pack_start(LIVES_BOX(hbox), label, TRUE, TRUE, 0);
6381 lives_widget_set_halign(label, LIVES_ALIGN_CENTER);
6382 }
6383
6384 lives_widget_object_ref(textwindow->vbox);
6385 lives_widget_unparent(textwindow->vbox);
6386
6387 widget_opts.justify = LIVES_JUSTIFY_CENTER;
6388 lives_standard_expander_new(_("Show _Log"), LIVES_BOX(top_vbox),
6389 textwindow->vbox);
6390 widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
6391 lives_widget_object_unref(textwindow->vbox);
6392
6393 add_fill_to_box(LIVES_BOX(top_vbox));
6394
6395 button =
6396 lives_dialog_add_button_from_stock(LIVES_DIALOG(textwindow->dialog),
6397 LIVES_STOCK_CANCEL, nitems ? NULL :
6398 LIVES_STOCK_LABEL_CLOSE_WINDOW, LIVES_RESPONSE_CANCEL);
6399
6400 lives_widget_add_accelerator(button, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
6401 LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
6402
6403 widget_opts.expand = LIVES_EXPAND_DEFAULT_HEIGHT | LIVES_EXPAND_EXTRA_WIDTH;
6404 accb = lives_dialog_add_button_from_stock(LIVES_DIALOG(textwindow->dialog),
6405 LIVES_STOCK_EDIT, nitems ? _("_Check and Filter Results")
6406 : _("Show Results"), LIVES_RESPONSE_BROWSE);
6407
6408 widget_opts.expand = LIVES_EXPAND_DEFAULT;
6409 lives_button_grab_default_special(accb);
6410
6411 if (nitems) {
6412 LiVESWidget *bbox = lives_dialog_get_action_area(LIVES_DIALOG(textwindow->dialog));
6413 lives_button_box_set_child_non_homogeneous(LIVES_BUTTON_BOX(bbox), button, TRUE);
6414 lives_button_box_set_layout(LIVES_BUTTON_BOX(bbox), LIVES_BUTTONBOX_START);
6415 }
6416
6417 retval = lives_dialog_run(LIVES_DIALOG(textwindow->dialog));
6418 lives_widget_destroy(textwindow->dialog);
6419 lives_free(textwindow);
6420
6421 if (retval != LIVES_RESPONSE_CANCEL) {
6422 retval = filter_cleanup(full_trashdir, rec_list, rem_list, left_list);
6423 }
6424
6425 if (!nitems) {
6426 gotsize = TRUE;
6427 goto cleanup;
6428 }
6429
6430 lives_proc_thread_cancel(recinfo);
6431 lives_proc_thread_cancel(reminfo);
6432 lives_proc_thread_cancel(leaveinfo);
6433
6434 if (retval == LIVES_RESPONSE_CANCEL) {
6435 com = lives_strdup_printf("%s restore_trash %s", prefs->backend, trashdir);
6436 lives_system(com, FALSE);
6437 lives_free(com);
6438 goto cleanup;
6439 }
6440
6441 /// user accepted
6442
6443 // first we need to move some entries at the list starts
6444 // type now indicates the origin list, since moved entries were prepended
6445 // we can stop when orig == current list
6446
6447 THREADVAR(com_failed) = FALSE;
6448
6449 for (list = *rem_list; list && list->data; list = list->next) {
6450 filedets = (lives_file_dets_t *)list->data;
6451 orig = filedets->type & ~LIVES_FILE_TYPE_FLAG_SPECIAL;
6452 if (orig == 1) break;
6453 to = lives_build_path(full_trashdir, TRASH_REMOVE, filedets->name, NULL);
6454 if (!orig) {
6455 // moved from rec_list to rem_list
6456 from = lives_build_path(full_trashdir, TRASH_RECOVER, filedets->name, NULL);
6457 } else {
6458 // moved from left_list to rem_list
6459 from = lives_build_path(full_trashdir, TRASH_LEAVE, filedets->name, NULL);
6460 }
6461 lives_mv(from, to);
6462 lives_free(from);
6463 lives_free(to);
6464 if (THREADVAR(com_failed)) {
6465 THREADVAR(com_failed) = FALSE;
6466 goto cleanup;
6467 }
6468 }
6469
6470 for (list = *left_list; list && list->data; list = list->next) {
6471 filedets = (lives_file_dets_t *)list->data;
6472 orig = filedets->type;
6473 if (orig == 2) break;
6474 to = lives_build_path(full_trashdir, TRASH_LEAVE, filedets->name, NULL);
6475 if (!orig) {
6476 // moved from rec_list to left_list
6477 from = lives_build_path(full_trashdir, TRASH_RECOVER, filedets->name, NULL);
6478 } else {
6479 // moved from rem_list to left_list
6480 from = lives_build_path(full_trashdir, TRASH_REMOVE, filedets->name, NULL);
6481 }
6482 lives_mv(from, to);
6483 lives_free(from);
6484 lives_free(to);
6485 if (THREADVAR(com_failed)) {
6486 THREADVAR(com_failed) = FALSE;
6487 goto cleanup;
6488 }
6489 }
6490
6491 list = *rec_list;
6492
6493 if (list && list->data) {
6494 /// try to recover lost files first
6495 // create a list with just the names
6496 LiVESList *recnlist = NULL;
6497
6498 for (; list && list->data; list = list->next) {
6499 filedets = (lives_file_dets_t *)list->data;
6500 if (*filedets->name)
6501 recnlist = lives_list_prepend(recnlist, lives_strdup(filedets->name));
6502 }
6503 recnlist = lives_list_reverse(recnlist);
6504
6505 // close the temporary clip
6506 close_temp_handle(current_file);
6507
6508 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
6509 recover_lost_clips(recnlist);
6510 lives_set_cursor_style(LIVES_CURSOR_BUSY, NULL);
6511
6512 /// handle any remnants. Remove any entries from recnlist which are now loaded
6513 /// the remainder will be deleted or moved to "unrecoverable_clips"
6514
6515 for (list = mainw->cliplist; list; list = list->next) {
6516 int clipno = LIVES_POINTER_TO_INT(list->data);
6517 LiVESList *list2 = recnlist;
6518 for (; list2; list2 = list2->next) {
6519 if (!strcmp(mainw->files[clipno]->handle, (char *)list2->data)) {
6520 if (list2->prev) list2->prev->next = list2->next;
6521 if (list2->next) list2->next->prev = list2->prev;
6522 if (recnlist == list2) recnlist = list2->next;
6523 list2->next = list2->prev = NULL;
6524 lives_list_free(list2);
6525 break;
6526 }
6527 }
6528 }
6529
6530 current_file = mainw->current_file;
6531
6532 // get a temporary clip for receiving data from backend
6533 if (!get_temp_handle(-1)) {
6534 lives_list_free_all(&recnlist);
6535 mainw->next_ds_warn_level = ds_warn_level;
6536 goto cleanup;
6537 }
6538
6539 if (recnlist) {
6540 boolean bresp;
6541 remtrashdir = lives_build_path(full_trashdir, TRASH_REMOVE, NULL);
6542
6543 /// handle unrecovered items
6544 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
6545 bresp = handle_remnants(recnlist, remtrashdir, rem_list);
6546 lives_set_cursor_style(LIVES_CURSOR_BUSY, NULL);
6547 if (!bresp) {
6548 // if failed / cancelled, add to left_list
6549 lives_file_dets_t *fdets;
6550 for (list = recnlist; list; list = list->next) {
6551 fdets = (lives_file_dets_t *)struct_from_template(LIVES_STRUCT_FILE_DETS_T);
6552 fdets->name = lives_strdup((char *)list->data);
6553 *left_list = lives_list_prepend(*left_list, fdets);
6554 }
6555 }
6556 lives_list_free_all(&recnlist);
6557 lives_free(remtrashdir);
6558 }
6559 }
6560 // now finally we remove all in rem_list, this is done in the backend
6561 list = *rem_list;
6562 if (list && list->data) {
6563 if (prefs->pref_trash) op = lives_strdup("giotrash");
6564 else op = lives_strdup("delete");
6565
6566 remtrashdir = lives_build_path(trashdir, TRASH_REMOVE, NULL);
6567
6568 if (CURRENT_CLIP_IS_VALID) lives_rm(cfile->info_file);
6569
6570 tinfo = lives_proc_thread_create(LIVES_THRDATTR_NONE, (lives_funcptr_t)do_auto_dialog, -1,
6571 "si", _("Clearing Disk"), 0);
6572 tbuff = lives_text_buffer_new();
6573
6574 com = lives_strdup_printf("%s empty_trash \"%s\" %s \"%s\"",
6575 prefs->backend, cfile->handle, op, remtrashdir);
6576 lives_free(op);
6577 lives_free(remtrashdir);
6578
6579 lives_popen(com, TRUE, (char *)tbuff, 0);
6580 lives_free(com);
6581 lives_proc_thread_join(tinfo);
6582
6583 lives_rm(cfile->info_file);
6584 }
6585
6586 if (THREADVAR(com_failed)) {
6587 THREADVAR(com_failed) = FALSE;
6588 goto cleanup;
6589 }
6590
6591 bytes = get_ds_free(prefs->workdir) - fspace;
6592 gotsize = TRUE;
6593 }
6594
6595 cleanup:
6596
6597 if (trashdir) lives_free(trashdir);
6598
6599 if (full_trashdir) {
6600 lives_rmdir(full_trashdir, TRUE);
6601 lives_free(full_trashdir);
6602 }
6603
6604 if (*rec_list) free_fdets_list(rec_list);
6605
6606 // close the temporary clip
6607 close_temp_handle(current_file);
6608
6609 if (bytes < 0) bytes = 0;
6610 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
6611
6612 if (gotsize && retval != LIVES_RESPONSE_CANCEL && !THREADVAR(com_failed) && fspace > -1) {
6613 LiVESWidget *dialog, *tview;
6614
6615 d_print_done();
6616
6617 msg = lives_strdup_printf(_("%s of disk space was recovered.\n"),
6618 lives_format_storage_space_string((uint64_t)bytes));
6619
6620 dialog = create_message_dialog(LIVES_DIALOG_INFO, msg, 0);
6621 lives_free(msg);
6622
6623 list = *rem_list;
6624 top_vbox = lives_dialog_get_content_area(LIVES_DIALOG(dialog));
6625
6626 if (list && list->data) {
6627 lives_label_chomp(LIVES_LABEL(widget_opts.last_label));
6628 widget_opts.expand = LIVES_EXPAND_DEFAULT_WIDTH;
6629 tview = scrolled_textview(NULL, tbuff, RFX_WINSIZE_H * 2, NULL);
6630 widget_opts.expand = LIVES_EXPAND_DEFAULT;
6631 widget_opts.justify = LIVES_JUSTIFY_CENTER;
6632 lives_standard_expander_new(_("Show _Log"), LIVES_BOX(top_vbox), tview);
6633 widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
6634 }
6635
6636 list = *left_list;
6637
6638 if (list && list->data) {
6639 char *text = NULL, *item;
6640 LiVESWidget *label = lives_standard_label_new(_("Some files and directories may be removed manually "
6641 "if desired.\nClick for details:\n"));
6642 LiVESWidget *hbox = lives_hbox_new(FALSE, 0);
6643
6644 lives_box_pack_start(LIVES_BOX(top_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
6645 lives_box_pack_start(LIVES_BOX(hbox), label, TRUE, TRUE, 0);
6646 lives_widget_set_halign(label, LIVES_ALIGN_CENTER);
6647
6648 for (; list && list->data; list = list->next) {
6649 filedets = (lives_file_dets_t *)list->data;
6650 item = lives_build_path(prefs->workdir, filedets->name, NULL);
6651 text = lives_concat_sep(text, "\n", item);
6652 }
6653
6654 widget_opts.expand = LIVES_EXPAND_DEFAULT_WIDTH;
6655 tview = scrolled_textview(text, NULL, RFX_WINSIZE_H * 2, NULL);
6656 widget_opts.expand = LIVES_EXPAND_DEFAULT;
6657 lives_free(text);
6658
6659 widget_opts.justify = LIVES_JUSTIFY_CENTER;
6660 lives_standard_expander_new(_("Show _Remaining Items"),
6661 LIVES_BOX(top_vbox), tview);
6662 widget_opts.justify = LIVES_JUSTIFY_DEFAULT;
6663 }
6664
6665 lives_dialog_run(LIVES_DIALOG(dialog));
6666 } else {
6667 if (retval != LIVES_RESPONSE_CANCEL) d_print_failed();
6668 else d_print_cancelled();
6669 }
6670
6671 if (*rem_list) free_fdets_list(rem_list);
6672 if (*left_list) free_fdets_list(left_list);
6673
6674 mainw->next_ds_warn_level = ds_warn_level;
6675
6676 if (user_data) {
6677 mainw->dsu_valid = FALSE;
6678 if (!disk_monitor_running(prefs->workdir)) {
6679 mainw->dsu_valid = TRUE;
6680 lives_idle_add_simple(update_dsu, NULL);
6681 }
6682 lives_widget_show(lives_widget_get_toplevel(LIVES_WIDGET(user_data)));
6683 } else {
6684 if (!mainw->multitrack && !mainw->is_processing && !LIVES_IS_PLAYING) {
6685 sensitize();
6686 }
6687
6688
6689 end:
6690 if (mainw->multitrack) {
6691 if (!mainw->is_processing && !LIVES_IS_PLAYING) {
6692 mt_sensitise(mainw->multitrack);
6693 maybe_add_mt_idlefunc();
6694 // *INDENT-OFF*
6695 }}}
6696 // *INDENT-ON*
6697 }
6698
6699
6700 void on_cleardisk_advanced_clicked(LiVESWidget * widget, livespointer user_data) {
6701 // make cleardisk adv window
6702
6703 // show various options and OK/Cancel button
6704
6705 // on OK set clear_disk opts
6706 int response;
6707 LiVESWidget *dialog;
6708 do {
6709 dialog = create_cleardisk_advanced_dialog();
6710 lives_widget_show_all(dialog);
6711 response = lives_dialog_run(LIVES_DIALOG(dialog));
6712 lives_widget_destroy(dialog);
6713 if (response == LIVES_RESPONSE_RETRY) prefs->clear_disk_opts = 0;
6714 } while (response == LIVES_RESPONSE_RETRY);
6715
6716 set_int_pref(PREF_CLEAR_DISK_OPTS, prefs->clear_disk_opts);
6717 }
6718
6719
6720 void on_show_keys_activate(LiVESMenuItem * menuitem, livespointer user_data) {do_keys_window();}
6721
6722
6723 void on_vj_realize_activate(LiVESMenuItem * menuitem, livespointer user_data) {
6724 frames_t ret;
6725 char *msg = (_("Pre-decoding all frames in this clip..."));
6726 d_print(msg);
6727
6728 desensitize();
6729
6730 ret = realize_all_frames(mainw->current_file, msg, TRUE);
6731 lives_free(msg);
6732 if (ret <= 0) d_print_failed();
6733 else if (ret < cfile->frames) d_print_enough(ret);
6734 else d_print_done();
6735
6736 sensitize();
6737 }
6738
6739
6740 void on_vj_reset_activate(LiVESMenuItem * menuitem, livespointer user_data) {
6741 LiVESList *clip_list = mainw->cliplist;
6742
6743 boolean bad_header = FALSE;
6744
6745 int i;
6746
6747 //mainw->soft_debug=TRUE;
6748
6749 do_threaded_dialog(_("Resetting frame rates and frame values..."), FALSE);
6750
6751 while (clip_list) {
6752 i = LIVES_POINTER_TO_INT(clip_list->data);
6753 mainw->files[i]->pb_fps = mainw->files[i]->fps;
6754 mainw->files[i]->frameno = 1;
6755 mainw->files[i]->aseek_pos = 0;
6756
6757 if (!save_clip_value(i, CLIP_DETAILS_PB_FPS, &mainw->files[i]->fps)) bad_header = TRUE;
6758 if (!save_clip_value(i, CLIP_DETAILS_PB_FRAMENO, &mainw->files[i]->frameno)) bad_header = TRUE;
6759
6760 threaded_dialog_spin((double)i / (double)mainw->clips_available);
6761
6762 if (bad_header) {
6763 if (!do_header_write_error(i)) break;
6764 } else clip_list = clip_list->next;
6765 }
6766
6767 end_threaded_dialog();
6768 }
6769
6770
6771 void on_show_messages_activate(LiVESMenuItem * menuitem, livespointer user_data) {
6772 do_messages_window(FALSE);
6773 }
6774
6775
6776 void on_show_file_info_activate(LiVESMenuItem * menuitem, livespointer user_data) {
6777 char buff[512];
6778 lives_clipinfo_t *filew;
6779
6780 char *sigs, *ends, *tmp;
6781
6782 if (!CURRENT_CLIP_IS_VALID) return;
6783
6784 filew = create_clip_info_window(cfile->achans, FALSE);
6785
6786 if (cfile->frames > 0) {
6787 // type
6788 lives_snprintf(buff, 512, _("External: %s\nInternal: %s (%d bpp) / %s"), cfile->type,
6789 (tmp = lives_strdup((cfile->clip_type == CLIP_TYPE_YUV4MPEG ||
6790 cfile->clip_type == CLIP_TYPE_VIDEODEV) ? (_("buffered")) :
6791 (cfile->img_type == IMG_TYPE_JPEG ? LIVES_IMAGE_TYPE_JPEG : LIVES_IMAGE_TYPE_PNG))),
6792 cfile->bpp, LIVES_AUDIO_TYPE_PCM);
6793 lives_free(tmp);
6794
6795 if (cfile->clip_type == CLIP_TYPE_FILE) {
6796 lives_decoder_t *dplug = (lives_decoder_t *)cfile->ext_src;
6797 lives_decoder_sys_t *dpsys = (lives_decoder_sys_t *)dplug->decoder;
6798 const char *decname = dpsys->name;
6799 lives_strappendf(buff, 512, _("\ndecoder: %s"), decname);
6800 }
6801 lives_text_view_set_text(LIVES_TEXT_VIEW(filew->textview_type), buff, -1);
6802 // fps
6803 lives_snprintf(buff, 512, " %.3f%s", cfile->fps, cfile->ratio_fps ? "..." : "");
6804
6805 lives_text_view_set_text(LIVES_TEXT_VIEW(filew->textview_fps), buff, -1);
6806 // image size
6807 lives_snprintf(buff, 512, " %dx%d", cfile->hsize, cfile->vsize);
6808 lives_text_view_set_text(LIVES_TEXT_VIEW(filew->textview_size), buff, -1);
6809 // frames
6810 if ((cfile->opening && !cfile->opening_audio && cfile->frames == 0) || cfile->frames == 123456789) {
6811 lives_snprintf(buff, 512, "%s", _(" Opening..."));
6812 } else {
6813 lives_snprintf(buff, 512, " %d", cfile->frames);
6814
6815 if (cfile->frame_index) {
6816 int fvirt = count_virtual_frames(cfile->frame_index, 1, cfile->frames);
6817 char *tmp = lives_strdup_printf(_("\n(%d virtual)"), fvirt);
6818 lives_strappend(buff, 512, tmp);
6819 lives_free(tmp);
6820 tmp = lives_strdup_printf(_("\n(%d decoded)"), cfile->frames - fvirt);
6821 lives_strappend(buff, 512, tmp);
6822 lives_free(tmp);
6823 }
6824
6825 }
6826 lives_text_view_set_text(LIVES_TEXT_VIEW(filew->textview_frames), buff, -1);
6827 // video time
6828 if ((cfile->opening && !cfile->opening_audio && cfile->frames == 0) || cfile->frames == 123456789) {
6829 lives_snprintf(buff, 512, "%s", _(" Opening..."));
6830 } else {
6831 lives_snprintf(buff, 512, _(" %.2f sec."), cfile->video_time);
6832 }
6833 lives_text_view_set_text(LIVES_TEXT_VIEW(filew->textview_vtime), buff, -1);
6834 // file size
6835 if (cfile->f_size > 0l) {
6836 char *file_ds = lives_format_storage_space_string((uint64_t)cfile->f_size);
6837 lives_snprintf(buff, 512, " %s", file_ds);
6838 lives_free(file_ds);
6839 } else lives_snprintf(buff, 512, "%s", _(" Unknown"));
6840 lives_text_view_set_text(LIVES_TEXT_VIEW(filew->textview_fsize), buff, -1);
6841 }
6842
6843 if (cfile->achans > 0) {
6844 if (cfile->opening) {
6845 lives_snprintf(buff, 512, "%s", _(" Opening..."));
6846 } else {
6847 lives_snprintf(buff, 512, _(" %.2f sec."), cfile->laudio_time);
6848 }
6849 lives_text_view_set_text(LIVES_TEXT_VIEW(filew->textview_ltime), buff, -1);
6850
6851 if (cfile->signed_endian & AFORM_UNSIGNED) sigs = (_("unsigned"));
6852 else sigs = (_("signed"));
6853
6854 if (cfile->signed_endian & AFORM_BIG_ENDIAN) ends = (_("big-endian"));
6855 else ends = (_("little-endian"));
6856
6857 lives_snprintf(buff, 512, _(" %d Hz %d bit\n%s %s"), cfile->arate, cfile->asampsize, sigs, ends);
6858 lives_text_view_set_text(LIVES_TEXT_VIEW(filew->textview_lrate), buff, -1);
6859
6860 lives_free(sigs);
6861 lives_free(ends);
6862 }
6863
6864 if (cfile->achans > 1) {
6865 if (cfile->signed_endian & AFORM_UNSIGNED) sigs = (_("unsigned"));
6866 else sigs = (_("signed"));
6867
6868 if (cfile->signed_endian & AFORM_BIG_ENDIAN) ends = (_("big-endian"));
6869 else ends = (_("little-endian"));
6870
6871 lives_snprintf(buff, 512, _(" %d Hz %d bit\n%s %s"), cfile->arate, cfile->asampsize, sigs, ends);
6872 lives_text_view_set_text(LIVES_TEXT_VIEW(filew->textview_rrate), buff, -1);
6873
6874 lives_free(sigs);
6875 lives_free(ends);
6876
6877 if (cfile->opening) {
6878 lives_snprintf(buff, 512, "%s", _(" Opening..."));
6879 } else {
6880 lives_snprintf(buff, 512, _(" %.2f sec."), cfile->raudio_time);
6881 }
6882 lives_text_view_set_text(LIVES_TEXT_VIEW(filew->textview_rtime), buff, -1);
6883 }
6884 }
6885
6886
6887 void on_show_file_comments_activate(LiVESMenuItem * menuitem, livespointer user_data) {
6888 do_comments_dialog(mainw->current_file, NULL);
6889 }
6890
6891
6892 void on_show_clipboard_info_activate(LiVESMenuItem * menuitem, livespointer user_data) {
6893 int current_file = mainw->current_file;
6894 mainw->current_file = 0;
6895 on_show_file_info_activate(menuitem, user_data);
6896 mainw->current_file = current_file;
6897 }
6898
6899
6900 void switch_clip(int type, int newclip, boolean force) {
6901 // generic switch clip callback
6902
6903 // This is the new single entry function for switching clips.
6904 // It should eventually replace switch_to_file() and do_quick_switch()
6905
6906 // type = 0 : if we are playing and a transition is active, this will change the background clip
6907 // type = 1 fg only
6908 // type = 2 bg only
6909
6910 if (mainw->current_file < 1 || mainw->multitrack || mainw->preview || mainw->internal_messaging ||
6911 (mainw->is_processing && cfile && cfile->is_loaded) || !mainw->cliplist) return;
6912
6913 mainw->blend_palette = WEED_PALETTE_END;
6914
6915 if (type == 2 || (mainw->active_sa_clips == SCREEN_AREA_BACKGROUND && mainw->playing_file > 0 && type != 1
6916 && !(mainw->blend_file != -1 && !IS_NORMAL_CLIP(mainw->blend_file) && mainw->blend_file != mainw->playing_file))) {
6917 if (mainw->num_tr_applied < 1 || newclip == mainw->blend_file) return;
6918
6919 // switch bg clip
6920 if (IS_VALID_CLIP(mainw->blend_file) && mainw->blend_file != mainw->playing_file
6921 && mainw->files[mainw->blend_file]->clip_type == CLIP_TYPE_GENERATOR) {
6922 if (mainw->blend_layer) check_layer_ready(mainw->blend_layer);
6923 weed_plant_t *inst = mainw->files[mainw->blend_file]->ext_src;
6924 if (inst) {
6925 mainw->osc_block = TRUE;
6926 if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_KEY)) {
6927 int key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, NULL);
6928 rte_key_on_off(key + 1, FALSE);
6929 }
6930 mainw->osc_block = FALSE;
6931 }
6932 }
6933
6934 //chill_decoder_plugin(mainw->blend_file);
6935 mainw->blend_file = newclip;
6936 mainw->whentostop = NEVER_STOP;
6937 if (mainw->ce_thumbs && mainw->active_sa_clips == SCREEN_AREA_BACKGROUND) {
6938 ce_thumbs_highlight_current_clip();
6939 }
6940 mainw->blend_palette = WEED_PALETTE_END;
6941 return;
6942 }
6943
6944 // switch fg clip
6945
6946 if (!force && (newclip == mainw->current_file && (!LIVES_IS_PLAYING || mainw->playing_file == newclip))) return;
6947 if (cfile && !cfile->is_loaded) mainw->cancelled = CANCEL_NO_PROPOGATE;
6948
6949 if (LIVES_IS_PLAYING) {
6950 mainw->new_clip = newclip;
6951 mainw->blend_palette = WEED_PALETTE_END;
6952 } else {
6953 if (!cfile || (force && newclip == mainw->current_file)) mainw->current_file = -1;
6954 switch_to_file(mainw->current_file, newclip);
6955 }
6956 }
6957
6958
6959 void switch_clip_activate(LiVESMenuItem * menuitem, livespointer user_data) {
6960 // switch clips from the clips menu
6961
6962 register int i;
6963 if (mainw->current_file < 1 || mainw->preview || (mainw->is_processing && cfile->is_loaded) || !mainw->cliplist) return;
6964
6965 for (i = 1; i < MAX_FILES; i++) {
6966 if (mainw->files[i]) {
6967 if (LIVES_MENU_ITEM(menuitem) == LIVES_MENU_ITEM(mainw->files[i]->menuentry) &&
6968 lives_check_menu_item_get_active(LIVES_CHECK_MENU_ITEM(mainw->files[i]->menuentry))) {
6969 switch_clip(0, i, FALSE);
6970 return;
6971 // *INDENT-OFF*
6972 }}}
6973 // *INDENT-ON*
6974 }
6975
6976
6977 void on_about_activate(LiVESMenuItem * menuitem, livespointer user_data) {
6978
6979 #ifdef GUI_GTK
6980 #if GTK_CHECK_VERSION(2, 14, 0)
6981 char *license = (_(
6982 "This program is free software; you can redistribute it and/or modify\n"
6983 "it under the terms of the GNU General Public License as published by\n"
6984 "the Free Software Foundation; either version 3 of the License, or\n"
6985 "(at your option) any later version.\n"
6986 "\n"
6987 "This program is distributed in the hope that it will be useful,\n"
6988 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
6989 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
6990 "GNU General Public License for more details.\n"
6991 "\n"
6992 "You should have received a copy of the GNU General Public License\n"
6993 "along with this program; if not, write to the Free Software\n"
6994 "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA.\n"));
6995
6996 char *comments = (_("A video editor and VJ program."));
6997 char *title = (_("About LiVES"));
6998
6999 char *translator_credits = (_("translator_credits"));
7000
7001 #if GTK_CHECK_VERSION(3, 0, 0)
7002 char *authors[2] = {LIVES_AUTHOR_EMAIL, NULL};
7003 #else
7004 gtk_about_dialog_set_url_hook(activate_url, NULL, NULL);
7005 gtk_about_dialog_set_email_hook(activate_url, NULL, NULL);
7006 #endif
7007
7008 gtk_show_about_dialog(LIVES_WINDOW(LIVES_MAIN_WINDOW_WIDGET),
7009 "logo", NULL,
7010 "name", PACKAGE_NAME,
7011 "version", LiVES_VERSION,
7012 "comments", comments,
7013 "copyright", "(C) "LIVES_COPYRIGHT_YEARS" salsaman <"LIVES_AUTHOR_EMAIL"> and others",
7014 "website", LIVES_WEBSITE,
7015 "license", license,
7016 "title", title,
7017 "translator_credits", translator_credits,
7018 #if GTK_CHECK_VERSION(3, 0, 0)
7019 "authors", authors,
7020 "license-type", GTK_LICENSE_GPL_3_0,
7021 #endif
7022 NULL);
7023
7024 lives_free(translator_credits);
7025 lives_free(comments);
7026 lives_free(title);
7027 lives_free(license);
7028 return;
7029 #endif
7030 #endif
7031 widget_opts.non_modal = TRUE;
7032 do_error_dialogf(_("LiVES Version %s\n"
7033 "(c) G. Finch (salsaman) %s\n\n"
7034 "Released under the GPL 3 or later (http://www.gnu.org/licenses/gpl.txt)\n"
7035 "LiVES is distributed WITHOUT WARRANTY\n\n"
7036 "Contact the author at:\n%s\n"
7037 "Homepage: %s"),
7038 LiVES_VERSION, LIVES_COPYRIGHT_YEARS, LIVES_AUTHOR_EMAIL, LIVES_WEBSITE);
7039 widget_opts.non_modal = FALSE;
7040 }
7041
7042
7043 void show_manual_activate(LiVESMenuItem * menuitem, livespointer user_data) {
7044 show_manual_section(NULL, NULL);
7045 }
7046
7047
7048 void email_author_activate(LiVESMenuItem * menuitem, livespointer user_data) {
7049 activate_url_inner("mailto:"LIVES_AUTHOR_EMAIL);
7050 }
7051
7052
7053 void report_bug_activate(LiVESMenuItem * menuitem, livespointer user_data) {
7054 activate_url_inner(LIVES_BUG_URL);
7055 }
7056
7057
7058 void suggest_feature_activate(LiVESMenuItem * menuitem, livespointer user_data) {
7059 activate_url_inner(LIVES_FEATURE_URL);
7060 }
7061
7062
7063 void help_translate_activate(LiVESMenuItem * menuitem, livespointer user_data) {
7064 activate_url_inner(LIVES_TRANSLATE_URL);
7065 }
7066
7067
7068 void donate_activate(LiVESMenuItem * menuitem, livespointer user_data) {
7069 const char *link = lives_strdup_printf("%s%s", LIVES_DONATE_URL, !user_data ? "" : (char *)user_data);
7070 activate_url_inner(link);
7071 }
7072
7073
7074 static char *fsp_ltext;
7075 static char *fsp_info_file;
7076 static char *file_open_params;
7077
7078 static boolean fs_preview_idle(void *data) {
7079 LiVESWidget *widget = (LiVESWidget *)data;
7080 FILE *ifile;
7081
7082 if (!(ifile = fopen(fsp_info_file, "r")) && mainw->in_fs_preview && mainw->fc_buttonresponse
7083 == LIVES_RESPONSE_NONE) {
7084 return TRUE;
7085 }
7086
7087 widget_opts.expand = LIVES_EXPAND_NONE;
7088
7089 if (LIVES_IS_BUTTON(widget))
7090 lives_button_set_label(LIVES_BUTTON(widget), fsp_ltext);
7091 widget_opts.expand = LIVES_EXPAND_DEFAULT;
7092 lives_free(fsp_ltext);
7093
7094 if (ifile) {
7095 fclose(ifile);
7096 }
7097
7098 end_fs_preview();
7099 lives_free(fsp_info_file);
7100
7101 lives_freep((void **)&file_open_params);
7102 if (LIVES_IS_WIDGET(widget))
7103 lives_widget_set_sensitive(widget, TRUE);
7104 return FALSE;
7105 }
7106
7107
7108 void on_fs_preview_clicked(LiVESWidget * widget, livespointer user_data) {
7109 // file selector preview
7110 double start_time = 0.;
7111
7112 uint64_t xwin = 0;
7113
7114 char **array;
7115
7116 int preview_frames = 0;
7117 int preview_type = LIVES_POINTER_TO_INT(user_data);
7118 int height = 0, width = 0;
7119 int fwidth = -1, fheight = -1;
7120 int owidth, oheight, npieces, border = 0;
7121 boolean with_audio = mainw->save_with_sound;
7122
7123 char *thm_dir = NULL;
7124 char *tmp, *tmp2;
7125 char *com;
7126 char *type;
7127
7128 file_open_params = NULL;
7129
7130 if (mainw->in_fs_preview) {
7131 end_fs_preview();
7132 return;
7133 }
7134 fsp_ltext = NULL;
7135
7136 if (!check_for_executable(&capable->has_mktemp, EXEC_MKTEMP)) {
7137 do_program_not_found_error(EXEC_MKTEMP);
7138 lives_widget_set_sensitive(widget, TRUE);
7139 return;
7140 }
7141
7142 if (preview_type == LIVES_PREVIEW_TYPE_RANGE) {
7143 // open selection
7144 start_time = mainw->fx1_val;
7145 preview_frames = (int)mainw->fx2_val;
7146 } else {
7147 // open file
7148 lives_snprintf(file_name, PATH_MAX, "%s",
7149 (tmp = lives_filename_to_utf8((tmp2
7150 = lives_file_chooser_get_filename(LIVES_FILE_CHOOSER(lives_widget_get_toplevel(widget)))),
7151 -1, NULL, NULL, NULL)));
7152 lives_free(tmp);
7153 lives_free(tmp2);
7154 }
7155
7156 // get file detaisl
7157 if (!read_file_details_generic(file_name)) return;
7158
7159 npieces = get_token_count(mainw->msg, '|');
7160 if (npieces < 4) {
7161 end_fs_preview();
7162 return;
7163 }
7164 array = lives_strsplit(mainw->msg, "|", npieces);
7165 type = lives_strdup(array[3]);
7166
7167 if (npieces > 5) {
7168 width = atoi(array[4]);
7169 height = atoi(array[5]);
7170 }
7171 lives_strfreev(array);
7172
7173 if (!strcmp(type, "image") || !strcmp(type, prefs->image_type)) {
7174 if (preview_type == LIVES_PREVIEW_TYPE_VIDEO_AUDIO || preview_type == LIVES_PREVIEW_TYPE_IMAGE_ONLY) {
7175 clear_mainw_msg();
7176
7177 thm_dir = get_worktmp("_thm");
7178
7179 if (thm_dir && capable->has_identify) {
7180 mainw->error = FALSE;
7181
7182 fwidth = lives_widget_get_allocation_width(mainw->fs_playalign) - 20;
7183 fheight = lives_widget_get_allocation_height(mainw->fs_playalign) - 20;
7184
7185 // make thumb from any image file
7186
7187 com = lives_strdup_printf("%s make_thumb %s %d %d \"%s\" \"%s\"", prefs->backend_sync, thm_dir, fwidth,
7188 fheight, prefs->image_ext, (tmp = lives_filename_from_utf8(file_name, -1, NULL, NULL, NULL)));
7189 lives_free(tmp);
7190
7191 lives_popen(com, TRUE, mainw->msg, MAINW_MSG_SIZE);
7192 lives_free(com);
7193
7194 npieces = get_token_count(mainw->msg, '|');
7195 if (npieces < 3) {
7196 THREADVAR(com_failed) = FALSE;
7197 end_fs_preview();
7198 return;
7199 }
7200 if (!THREADVAR(com_failed)) {
7201 array = lives_strsplit(mainw->msg, "|", 3);
7202 width = atoi(array[1]);
7203 height = atoi(array[2]);
7204 lives_strfreev(array);
7205 } else height = width = 0;
7206 THREADVAR(com_failed) = FALSE;
7207 } else {
7208 height = width = 0;
7209 }
7210
7211 if (height > 0 && width > 0) {
7212 // draw image
7213 LiVESXWindow *xwin;
7214 LiVESError *error = NULL;
7215 char *thumbfile = lives_strdup_printf("%08d.%s", 1, prefs->image_ext);
7216 char *thumb = lives_build_filename(prefs->workdir, thm_dir, thumbfile, NULL);
7217 LiVESPixbuf *pixbuf = lives_pixbuf_new_from_file((tmp = lives_filename_from_utf8(thumb, -1, NULL, NULL, NULL)), &error);
7218 lives_free(thumbfile);
7219 lives_free(thumb);
7220 lives_free(tmp);
7221 if (!error) {
7222 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(mainw->fs_playimg), "pixbuf", pixbuf);
7223 owidth = width;
7224 oheight = height;
7225
7226 calc_maxspect(fwidth, fheight, &width, &height);
7227
7228 width = (width >> 1) << 1;
7229 height = (height >> 1) << 1;
7230
7231 if (width > owidth || height > oheight) {
7232 width = owidth;
7233 height = oheight;
7234 }
7235
7236 if (width < 4 || height < 4) {
7237 end_fs_preview();
7238 lives_widget_set_sensitive(widget, TRUE);
7239 return;
7240 }
7241 lives_widget_set_size_request(mainw->fs_playarea, width, height);
7242 lives_alignment_set(mainw->fs_playalign, 0.5, 0.5, (float)width / (float)fwidth,
7243 (float)height / (float)fheight);
7244 border = MIN(fwidth - width, fheight - height);
7245 lives_container_set_border_width(LIVES_CONTAINER(mainw->fs_playarea), border >> 1);
7246 lives_widget_show(mainw->fs_playimg);
7247 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
7248 xwin = lives_widget_get_xwindow(mainw->fs_playimg);
7249 if (LIVES_IS_XWINDOW(xwin)) {
7250 if (mainw->fsp_surface) lives_painter_surface_destroy(mainw->fsp_surface);
7251 mainw->fsp_surface =
7252 lives_xwindow_create_similar_surface(xwin, LIVES_PAINTER_CONTENT_COLOR,
7253 width, height);
7254 if (mainw->fsp_func == 0)
7255 mainw->fsp_func = lives_signal_sync_connect(LIVES_GUI_OBJECT(mainw->fs_playimg), LIVES_WIDGET_EXPOSE_EVENT,
7256 LIVES_GUI_CALLBACK(all_expose), &mainw->fsp_surface);
7257 }
7258 set_drawing_area_from_pixbuf(mainw->fs_playimg, pixbuf, mainw->fsp_surface);
7259 } else {
7260 lives_error_free(error);
7261 }
7262 }
7263
7264 if (thm_dir) {
7265 lives_rmdir(thm_dir, TRUE);
7266 lives_free(thm_dir);
7267 }
7268 if (height > 0 || width > 0 || preview_type == LIVES_PREVIEW_TYPE_IMAGE_ONLY) {
7269 lives_widget_set_sensitive(widget, TRUE);
7270 return;
7271 }
7272 }
7273 return;
7274 }
7275
7276 check_for_executable(&capable->has_mplayer, EXEC_MPLAYER);
7277 check_for_executable(&capable->has_mplayer2, EXEC_MPLAYER2);
7278 check_for_executable(&capable->has_mpv, EXEC_MPV);
7279
7280 if (!HAS_EXTERNAL_PLAYER) {
7281 char *msg;
7282 if (!check_for_executable(&capable->has_identify, EXEC_IDENTIFY)) {
7283 msg = (_("\n\nYou need to install mplayer, mplayer2 or mpv to be able to preview this file.\n"));
7284 } else {
7285 msg = (_("\n\nYou need to install mplayer, mplayer2, mpv or imageMagick to be able to preview this file.\n"));
7286 }
7287 do_error_dialog(msg);
7288 lives_free(msg);
7289 lives_widget_set_sensitive(widget, TRUE);
7290 return;
7291 }
7292
7293 mainw->fsp_tmpdir = get_worktmp("_fsp");
7294
7295 if (!mainw->fsp_tmpdir) {
7296 workdir_warning();
7297 lives_widget_set_sensitive(widget, TRUE);
7298 return;
7299 }
7300
7301 fsp_info_file = lives_build_filename(mainw->fsp_tmpdir, LIVES_STATUS_FILE_NAME, NULL);
7302
7303 mainw->in_fs_preview = TRUE;
7304
7305 if (preview_type != LIVES_PREVIEW_TYPE_AUDIO_ONLY) {
7306 if (!strcmp(type, "Audio")) {
7307 preview_frames = -1;
7308 } else {
7309 if (height == 0 || width == 0) {
7310 width = DEF_FRAME_HSIZE / 2;
7311 height = DEF_FRAME_VSIZE / 2;
7312 }
7313
7314 owidth = width;
7315 oheight = height;
7316
7317 fwidth = lives_widget_get_allocation_width(mainw->fs_playframe) - 20;
7318 fheight = lives_widget_get_allocation_height(mainw->fs_playframe) - 20;
7319
7320 calc_maxspect(fwidth, fheight, &width, &height);
7321
7322 width = (width >> 1) << 1;
7323 height = (height >> 1) << 1;
7324
7325 if (width > owidth || height > oheight) {
7326 width = owidth;
7327 height = oheight;
7328 }
7329
7330 if (width < 4 || height < 4) {
7331 end_fs_preview();
7332 lives_widget_set_sensitive(widget, TRUE);
7333 return;
7334 }
7335 lives_widget_set_bg_color(mainw->fs_playframe, LIVES_WIDGET_STATE_NORMAL, &palette->black);
7336 lives_widget_set_size_request(mainw->fs_playarea, width, height);
7337 lives_alignment_set(mainw->fs_playalign, 0.5, 0.5, (float)width / (float)fwidth,
7338 (float)height / (float)fheight);
7339 border = MIN(fwidth - width, fheight - height);
7340 lives_container_set_border_width(LIVES_CONTAINER(mainw->fs_playarea), border >> 1);
7341 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
7342 }
7343 } else preview_frames = -1;
7344
7345 if (!USE_MPV) {
7346 if (with_audio && prefs->audio_player == AUD_PLAYER_JACK) {
7347 file_open_params = lives_strdup_printf("%s %s -ao jack", mainw->file_open_params != NULL ?
7348 mainw->file_open_params : "", get_deinterlace_string());
7349 } else if (with_audio && prefs->audio_player == AUD_PLAYER_PULSE) {
7350 file_open_params = lives_strdup_printf("%s %s -ao pulse", mainw->file_open_params != NULL ?
7351 mainw->file_open_params : "", get_deinterlace_string());
7352 } else {
7353 file_open_params = lives_strdup_printf("%s %s -ao null", mainw->file_open_params != NULL ?
7354 mainw->file_open_params : "", get_deinterlace_string());
7355 }
7356 } else {
7357 if (with_audio && prefs->audio_player == AUD_PLAYER_JACK) {
7358 file_open_params = lives_strdup_printf("%s %s --ao=jack", mainw->file_open_params != NULL ?
7359 mainw->file_open_params : "", get_deinterlace_string());
7360 } else if (with_audio && prefs->audio_player == AUD_PLAYER_PULSE) {
7361 file_open_params = lives_strdup_printf("%s %s --ao=pulse", mainw->file_open_params != NULL ?
7362 mainw->file_open_params : "", get_deinterlace_string());
7363 } else {
7364 file_open_params = lives_strdup_printf("%s %s --ao=null", mainw->file_open_params != NULL ?
7365 mainw->file_open_params : "", get_deinterlace_string());
7366 }
7367 }
7368
7369 if (preview_type == LIVES_PREVIEW_TYPE_VIDEO_AUDIO || preview_type == LIVES_PREVIEW_TYPE_RANGE) {
7370 xwin = lives_widget_get_xwinid(mainw->fs_playarea, "Unsupported display type for preview.");
7371 if (xwin == -1) {
7372 end_fs_preview();
7373 lives_free(fsp_info_file);
7374 lives_widget_set_sensitive(widget, TRUE);
7375 return;
7376 }
7377 }
7378
7379 if (file_open_params) {
7380 com = lives_strdup_printf("%s fs_preview %s %"PRIu64" %d %d %.2f %d %d \"%s\" \"%s\"", prefs->backend, mainw->fsp_tmpdir,
7381 xwin, width, height, start_time, preview_frames, (int)(prefs->volume * 100.),
7382 (tmp = lives_filename_from_utf8(file_name, -1, NULL, NULL, NULL)), file_open_params);
7383
7384 } else {
7385 com = lives_strdup_printf("%s fs_preview %s %"PRIu64" %d %d %.2f %d %d \"%s\"", prefs->backend, mainw->fsp_tmpdir,
7386 xwin, width, height, start_time, preview_frames, (int)(prefs->volume * 100.),
7387 (tmp = lives_filename_from_utf8(file_name, -1, NULL, NULL, NULL)));
7388 }
7389
7390 lives_free(tmp);
7391 mainw->in_fs_preview = TRUE;
7392 lives_rm(fsp_info_file);
7393 lives_system(com, FALSE);
7394 lives_free(com);
7395
7396 if (THREADVAR(com_failed)) {
7397 THREADVAR(com_failed) = FALSE;
7398 end_fs_preview();
7399 lives_free(fsp_info_file);
7400 lives_widget_set_sensitive(widget, TRUE);
7401 return;
7402 }
7403
7404 tmp = (_("\nStop Preview\n"));
7405 fsp_ltext = lives_strdup(lives_button_get_label(LIVES_BUTTON(widget)));
7406 widget_opts.expand = LIVES_EXPAND_NONE;
7407 lives_button_set_label(LIVES_BUTTON(widget), tmp);
7408 if (preview_type == LIVES_PREVIEW_TYPE_RANGE) {
7409 widget_opts.expand = LIVES_EXPAND_DEFAULT;
7410 }
7411 lives_free(tmp);
7412
7413 // loop here until preview has finished, or the user presses OK or Cancel
7414 lives_idle_add_simple(fs_preview_idle, (livespointer)widget);
7415 }
7416
7417
7418 void on_open_activate(LiVESMenuItem * menuitem, livespointer user_data) {
7419 // OPEN A FILE (single or multiple)
7420 LiVESWidget *chooser;
7421 LiVESResponseType resp;
7422 mainw->mt_needs_idlefunc = FALSE;
7423
7424 if (mainw->multitrack) {
7425 if (mainw->multitrack->idlefunc > 0) {
7426 lives_source_remove(mainw->multitrack->idlefunc);
7427 mainw->multitrack->idlefunc = 0;
7428 mainw->mt_needs_idlefunc = TRUE;
7429 }
7430 mt_desensitise(mainw->multitrack);
7431 lives_widget_set_sensitive(mainw->multitrack->playall, TRUE);
7432 lives_widget_set_sensitive(mainw->m_playbutton, TRUE);
7433 }
7434
7435 chooser = choose_file_with_preview((*mainw->vid_load_dir) ? mainw->vid_load_dir : NULL, NULL, NULL,
7436 LIVES_FILE_SELECTION_VIDEO_AUDIO_MULTI);
7437
7438 resp = lives_dialog_run(LIVES_DIALOG(chooser));
7439
7440 end_fs_preview();
7441
7442 if (resp == LIVES_RESPONSE_ACCEPT) on_ok_file_open_clicked(LIVES_FILE_CHOOSER(chooser), NULL);
7443 else on_filechooser_cancel_clicked(chooser);
7444 }
7445
7446
7447 void on_ok_file_open_clicked(LiVESFileChooser * chooser, LiVESSList * fnames) {
7448 // this is also called from drag target
7449
7450 LiVESSList *ofnames;
7451
7452 if (chooser) {
7453 fnames = lives_file_chooser_get_filenames(chooser);
7454
7455 lives_widget_destroy(LIVES_WIDGET(chooser));
7456
7457 if (!fnames) return;
7458
7459 if (!fnames->data) {
7460 lives_list_free_all((LiVESList **)&fnames);
7461 return;
7462 }
7463
7464 lives_snprintf(mainw->vid_load_dir, PATH_MAX, "%s", (char *)fnames->data);
7465 get_dirname(mainw->vid_load_dir);
7466
7467 lives_widget_queue_draw_and_update(LIVES_MAIN_WINDOW_WIDGET);
7468
7469 if (prefs->save_directories) {
7470 set_utf8_pref(PREF_VID_LOAD_DIR, mainw->vid_load_dir);
7471 }
7472
7473 mainw->cancelled = CANCEL_NONE;
7474 }
7475
7476 ofnames = fnames;
7477 mainw->img_concat_clip = -1;
7478
7479 while (fnames && mainw->cancelled == CANCEL_NONE) {
7480 lives_snprintf(file_name, PATH_MAX, "%s", (char *)fnames->data);
7481 lives_free((livespointer)fnames->data);
7482 open_file(file_name);
7483 fnames = fnames->next;
7484 }
7485
7486 lives_slist_free(ofnames);
7487
7488 mainw->opening_multi = FALSE;
7489 mainw->img_concat_clip = -1;
7490
7491 if (mainw->multitrack) {
7492 polymorph(mainw->multitrack, POLY_NONE);
7493 polymorph(mainw->multitrack, POLY_CLIPS);
7494 mt_sensitise(mainw->multitrack);
7495 maybe_add_mt_idlefunc();
7496 }
7497 }
7498
7499
7500 #ifdef GUI_GTK
7501 // TODO
7502 // files dragged onto target from outside - try to open them
7503 void drag_from_outside(LiVESWidget * widget, GdkDragContext * dcon, int x, int y,
7504 GtkSelectionData * data, uint32_t info, uint32_t time, livespointer user_data) {
7505 GSList *fnames = NULL;
7506 #if GTK_CHECK_VERSION(3, 0, 0)
7507 char *filelist = (char *)gtk_selection_data_get_data(data);
7508 #else
7509 char *filelist = (char *)data->data;
7510 #endif
7511 char *nfilelist, **array;
7512 int nfiles, i;
7513
7514 if (!filelist) {
7515 gtk_drag_finish(dcon, FALSE, FALSE, time);
7516 return;
7517 }
7518
7519 if ((mainw->multitrack && !lives_widget_is_sensitive(mainw->multitrack->open_menu)) ||
7520 (!mainw->multitrack && !lives_widget_is_sensitive(mainw->open))) {
7521 gtk_drag_finish(dcon, FALSE, FALSE, time);
7522 return;
7523 }
7524
7525 nfilelist = subst(filelist, "file://", "");
7526
7527 nfiles = get_token_count(nfilelist, '\n');
7528 array = lives_strsplit(nfilelist, "\n", nfiles);
7529 lives_free(nfilelist);
7530
7531 for (i = 0; i < nfiles; i++) {
7532 fnames = lives_slist_append(fnames, array[i]);
7533 }
7534
7535 on_ok_file_open_clicked(NULL, fnames);
7536
7537 // fn will free array elements and fnames
7538
7539 lives_free(array);
7540
7541 gtk_drag_finish(dcon, TRUE, FALSE, time);
7542 }
7543 #endif
7544
7545
7546 void on_opensel_range_ok_clicked(LiVESButton * button, livespointer user_data) {
7547 // open file selection
7548 boolean needs_idlefunc;
7549
7550 end_fs_preview();
7551
7552 needs_idlefunc = mainw->mt_needs_idlefunc;
7553 mainw->mt_needs_idlefunc = FALSE;
7554 lives_general_button_clicked(button, NULL);
7555 mainw->mt_needs_idlefunc = needs_idlefunc;
7556
7557 mainw->img_concat_clip = -1;
7558 open_file_sel(file_name, mainw->fx1_val, (int)mainw->fx2_val);
7559
7560 if (mainw->multitrack) {
7561 polymorph(mainw->multitrack, POLY_NONE);
7562 polymorph(mainw->multitrack, POLY_CLIPS);
7563 mt_sensitise(mainw->multitrack);
7564 maybe_add_mt_idlefunc();
7565 }
7566 }
7567
7568
7569 void end_fs_preview(void) {
7570 // clean up if we were playing a preview - should be called from all callbacks
7571 // where there is a possibility of fs preview still playing
7572 static boolean singleton = FALSE;
7573 char *com;
7574
7575 if (singleton) return;
7576 singleton = TRUE;
7577
7578 lives_widget_set_bg_color(mainw->fs_playframe, LIVES_WIDGET_STATE_NORMAL, &palette->normal_back);
7579
7580 if (mainw->fs_playarea) {
7581 LiVESPixbuf *pixbuf = NULL;
7582 pixbuf = (LiVESPixbuf *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(mainw->fs_playarea), "pixbuf");
7583 if (pixbuf) lives_widget_object_unref(pixbuf);
7584 lives_widget_object_set_data(LIVES_WIDGET_OBJECT(mainw->fs_playarea), "pixbuf", NULL);
7585 if (mainw->fsp_func != 0) {
7586 lives_signal_handler_disconnect(mainw->fs_playimg, mainw->fsp_func);
7587 mainw->fsp_func = 0;
7588 }
7589 if (mainw->fsp_surface) {
7590 lives_painter_surface_destroy(mainw->fsp_surface);
7591 mainw->fsp_surface = NULL;
7592 }
7593 lives_widget_hide(mainw->fs_playimg);
7594 }
7595
7596 if (mainw->in_fs_preview) {
7597 if (mainw->fsp_tmpdir) {
7598 char *permitname = lives_build_filename(prefs->workdir, mainw->fsp_tmpdir,
7599 TEMPFILE_MARKER "." LIVES_FILE_EXT_TMP, NULL);
7600 lives_kill_subprocesses(mainw->fsp_tmpdir, TRUE);
7601 lives_touch(permitname);
7602 lives_free(permitname);
7603 com = lives_strdup_printf("%s close \"%s\"", prefs->backend, mainw->fsp_tmpdir);
7604 lives_freep((void **)&mainw->fsp_tmpdir);
7605 lives_system(com, TRUE);
7606 lives_free(com);
7607 }
7608 mainw->in_fs_preview = FALSE;
7609 }
7610 if (mainw->fs_playframe) lives_widget_queue_draw(mainw->fs_playframe);
7611 singleton = FALSE;
7612 }
7613
7614
7615 void on_save_textview_clicked(LiVESButton * button, livespointer user_data) {
7616 LiVESTextView *textview = (LiVESTextView *)user_data;
7617 char *filt[] = {"*." LIVES_FILE_EXT_TEXT, NULL};
7618 int fd;
7619 char *btext;
7620 char *save_file;
7621 boolean needs_idlefunc;
7622
7623 lives_widget_hide(lives_widget_get_toplevel(LIVES_WIDGET(button)));
7624 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
7625
7626 save_file = choose_file(NULL, NULL, filt, LIVES_FILE_CHOOSER_ACTION_SAVE, NULL, NULL);
7627
7628 if (!save_file) {
7629 lives_widget_show(lives_widget_get_toplevel(LIVES_WIDGET(button)));
7630 return;
7631 }
7632
7633 #ifndef IS_MINGW
7634 if ((fd = creat(save_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) == -1) {
7635 #else
7636 if ((fd = creat(save_file, S_IRUSR | S_IWUSR)) == -1) {
7637 #endif
7638 lives_widget_show(lives_widget_get_toplevel(LIVES_WIDGET(button)));
7639 do_write_failed_error_s(save_file, lives_strerror(errno));
7640 lives_free(save_file);
7641 return;
7642 }
7643
7644 btext = lives_text_view_get_text(textview);
7645
7646 needs_idlefunc = mainw->mt_needs_idlefunc;
7647 mainw->mt_needs_idlefunc = FALSE;
7648 lives_general_button_clicked(button, NULL);
7649 mainw->mt_needs_idlefunc = needs_idlefunc;
7650
7651 THREADVAR(write_failed) = FALSE;
7652 lives_write(fd, btext, strlen(btext), FALSE);
7653 lives_free(btext);
7654
7655 close(fd);
7656
7657 if (THREADVAR(write_failed)) {
7658 do_write_failed_error_s(save_file, lives_strerror(errno));
7659 } else {
7660 char *msg = lives_strdup_printf(_("Text was saved as\n%s\n"), save_file);
7661 do_error_dialog(msg);
7662 lives_free(msg);
7663 }
7664
7665 lives_free(save_file);
7666 #if 0
7667 }
7668 #endif
7669 }
7670
7671
7672 void on_filechooser_cancel_clicked(LiVESWidget * widget) {
7673 lives_widget_destroy(widget);
7674
7675 if (mainw->multitrack) {
7676 mt_sensitise(mainw->multitrack);
7677 maybe_add_mt_idlefunc();
7678 } else if (!CURRENT_CLIP_IS_CLIPBOARD && CURRENT_CLIP_IS_VALID && !cfile->opening) {
7679 get_play_times();
7680 }
7681 }
7682
7683
7684 void on_cancel_opensel_clicked(LiVESButton * button, livespointer user_data) {
7685 boolean needs_idlefunc;
7686
7687 end_fs_preview();
7688 needs_idlefunc = mainw->mt_needs_idlefunc;
7689 mainw->mt_needs_idlefunc = FALSE;
7690 lives_general_button_clicked(button, NULL);
7691 mainw->mt_needs_idlefunc = needs_idlefunc;
7692
7693 if (mainw->multitrack) {
7694 mt_sensitise(mainw->multitrack);
7695 maybe_add_mt_idlefunc();
7696 }
7697 lives_menu_item_activate(LIVES_MENU_ITEM(mainw->open_sel)); // returm to the fileselector
7698 }
7699
7700
7701 void on_cancel_keep_button_clicked(LiVESButton * button, livespointer user_data) {
7702 // Cancel/Keep from progress dialog
7703 char *com = NULL;
7704
7705 uint32_t keep_frames = 0;
7706
7707 boolean killprocs = FALSE;
7708
7709 if (CURRENT_CLIP_IS_VALID && cfile->opening && mainw->effects_paused) {
7710 on_stop_clicked(NULL, NULL);
7711 return;
7712 }
7713
7714 clear_mainw_msg();
7715
7716 if (CURRENT_CLIP_IS_VALID && mainw->proc_ptr) {
7717 lives_widget_set_sensitive(mainw->proc_ptr->cancel_button, FALSE);
7718 lives_widget_set_sensitive(mainw->proc_ptr->pause_button, FALSE);
7719 if (mainw->proc_ptr->stop_button)
7720 lives_widget_set_sensitive(mainw->proc_ptr->stop_button, FALSE);
7721 lives_widget_set_sensitive(mainw->proc_ptr->preview_button, FALSE);
7722 }
7723 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
7724
7725 if ((!mainw->effects_paused || cfile->nokeep) && (!mainw->multitrack ||
7726 (mainw->multitrack && (!mainw->multitrack->is_rendering ||
7727 !mainw->preview)))) {
7728 // Cancel
7729 if (mainw->cancel_type == CANCEL_SOFT) {
7730 // cancel in record audio
7731 mainw->cancelled = CANCEL_USER;
7732 d_print_cancelled();
7733 return;
7734 } else if (mainw->cancel_type == CANCEL_KILL) {
7735 // kill processes and subprocesses working on cfile
7736 killprocs = TRUE;
7737 }
7738
7739 if (CURRENT_CLIP_IS_VALID && !cfile->opening && !mainw->internal_messaging) {
7740 // if we are opening, this is 'stop' in the preview, so don't cancel
7741 // otherwise, come here
7742
7743 // kill off the background process
7744 if (killprocs) {
7745 lives_kill_subprocesses(cfile->handle, TRUE);
7746 }
7747
7748 // resume for next time
7749 if (mainw->effects_paused) {
7750 lives_freep((void **)&com);
7751 com = lives_strdup_printf("%s resume \"%s\"", prefs->backend_sync, cfile->handle);
7752 lives_system(com, FALSE);
7753 }
7754 }
7755
7756 mainw->cancelled = CANCEL_USER;
7757
7758 if (mainw->is_rendering) {
7759 if (CURRENT_CLIP_IS_VALID) cfile->frames = 0;
7760 d_print_cancelled();
7761 } else {
7762 // see if there was a message from backend
7763
7764 if (mainw->cancel_type != CANCEL_SOFT) {
7765 lives_fread_string(mainw->msg, MAINW_MSG_SIZE, cfile->info_file);
7766 if (lives_strncmp(mainw->msg, "completed", 9)) {
7767 d_print_cancelled();
7768 } else {
7769 // processing finished before we could cancel
7770 mainw->cancelled = CANCEL_NONE;
7771 }
7772 } else d_print_cancelled();
7773 }
7774 } else {
7775 // Keep
7776 if (mainw->cancel_type == CANCEL_SOFT) {
7777 mainw->cancelled = CANCEL_KEEP;
7778 return;
7779 }
7780 if (!mainw->is_rendering) {
7781 keep_frames = mainw->proc_ptr->frames_done - cfile->progress_start
7782 + cfile->start - 1 + mainw->internal_messaging * 2;
7783 if (mainw->internal_messaging && atoi(mainw->msg) > mainw->proc_ptr->frames_done)
7784 keep_frames = atoi(mainw->msg) - cfile->progress_start + cfile->start - 1 + 2;
7785 } else keep_frames = cfile->frames + 1;
7786 if (keep_frames > mainw->internal_messaging) {
7787 d_print_enough(keep_frames - cfile->start);
7788 lives_set_cursor_style(LIVES_CURSOR_BUSY, NULL);
7789 if (!mainw->internal_messaging) {
7790 lives_kill_subprocesses(cfile->handle, TRUE);
7791 com = lives_strdup_printf("%s resume \"%s\"", prefs->backend_sync, cfile->handle);
7792 lives_system(com, FALSE);
7793 lives_free(com);
7794 if (!mainw->keep_pre) com = lives_strdup_printf("%s mv_mgk \"%s\" %d %d \"%s\"", prefs->backend, cfile->handle,
7795 cfile->start, keep_frames - 1, get_image_ext_for_type(cfile->img_type));
7796 else {
7797 com = lives_strdup_printf("%s mv_pre \"%s\" %d %d \"%s\" &", prefs->backend_sync, cfile->handle,
7798 cfile->start, keep_frames - 1, get_image_ext_for_type(cfile->img_type));
7799 mainw->keep_pre = FALSE;
7800 }
7801 } else {
7802 mainw->internal_messaging = FALSE;
7803 if (!mainw->keep_pre) com = lives_strdup_printf("%s mv_mgk \"%s\" %d %d \"%s\"", prefs->backend, cfile->handle,
7804 cfile->start, keep_frames - 1, get_image_ext_for_type(cfile->img_type));
7805 else {
7806 com = lives_strdup_printf("%s mv_pre \"%s\" %d %d \"%s\" &", prefs->backend_sync, cfile->handle,
7807 cfile->start, keep_frames - 1, get_image_ext_for_type(cfile->img_type));
7808 mainw->keep_pre = FALSE;
7809 }
7810 }
7811 if (!mainw->is_rendering || mainw->multitrack) {
7812 lives_rm(cfile->info_file);
7813 lives_system(com, FALSE);
7814 cfile->undo_end = keep_frames - 1;
7815 } else mainw->cancelled = CANCEL_KEEP;
7816 lives_set_cursor_style(LIVES_CURSOR_NORMAL, NULL);
7817 } else {
7818 // no frames there, nothing to keep
7819 d_print_cancelled();
7820
7821 if (!mainw->internal_messaging && !mainw->is_rendering) {
7822 lives_kill_subprocesses(cfile->handle, TRUE);
7823 com = lives_strdup_printf("%s resume \"%s\"", prefs->backend_sync, cfile->handle);
7824 lives_system(com, FALSE);
7825 }
7826 mainw->cancelled = CANCEL_USER;
7827 }
7828 }
7829
7830 lives_freep((void **)&com);
7831 }
7832
7833
7834 void on_details_button_clicked(void) {
7835 text_window *textwindow;
7836 widget_opts.expand = LIVES_EXPAND_EXTRA;
7837 textwindow = create_text_window(_("Encoder Debug Output"),
7838 lives_text_view_get_text(mainw->optextview), NULL, TRUE);
7839 widget_opts.expand = LIVES_EXPAND_DEFAULT;
7840 lives_widget_show_all(textwindow->dialog);
7841 }
7842
7843
7844 void on_full_screen_pressed(LiVESButton * button, livespointer user_data) {
7845 // toolbar button (full screen)
7846 // ignore if audio only clip
7847 if (CURRENT_CLIP_IS_VALID && !CURRENT_CLIP_HAS_VIDEO && !mainw->multitrack) return;
7848 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->full_screen), !mainw->fs);
7849 }
7850
7851
7852 static void _on_full_screen_activate(LiVESMenuItem * menuitem, livespointer user_data) {
7853
7854 // ignore if audio only clip
7855 if (CURRENT_CLIP_IS_VALID && !CURRENT_CLIP_HAS_VIDEO && LIVES_IS_PLAYING && !mainw->multitrack) return;
7856
7857 if (!user_data) {
7858 // toggle can be overridden by setting user_data non-NULL
7859 mainw->fs = !mainw->fs;
7860 }
7861 mainw->blend_palette = WEED_PALETTE_END;
7862
7863 if (!mainw->fs) {
7864 lives_widget_set_tooltip_text(mainw->t_fullscreen, _("Fullscreen playback (f)"));
7865 lives_widget_set_opacity(mainw->t_fullscreen, .75);
7866 } else {
7867 lives_widget_set_tooltip_text(mainw->t_fullscreen, _("Fullscreen playback off (f)"));
7868 lives_widget_set_opacity(mainw->t_fullscreen, 1.);
7869 }
7870
7871 if (LIVES_IS_PLAYING) {
7872 if (mainw->fs) {
7873 // switch TO full screen during pb
7874 if (!mainw->multitrack && !mainw->sep_win) {
7875 fade_background();
7876 fullscreen_internal();
7877 }
7878 if (mainw->sep_win) {
7879 resize_play_window();
7880 lives_window_set_decorated(LIVES_WINDOW(mainw->play_window), FALSE);
7881 }
7882 if (cfile->frames == 1 || cfile->play_paused) {
7883 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
7884 }
7885
7886 if (mainw->ext_playback && mainw->vpp->fheight > -1 && mainw->vpp->fwidth > -1) {
7887 // fixed o/p size for stream
7888 if (mainw->vpp->fwidth == 0 || mainw->vpp->fheight == 0) {
7889 mainw->vpp->fwidth = cfile->hsize;
7890 mainw->vpp->fheight = cfile->vsize;
7891 }
7892 mainw->pwidth = mainw->vpp->fwidth;
7893 mainw->pheight = mainw->vpp->fheight;
7894 }
7895 } else {
7896 // switch from fullscreen during pb
7897 if (mainw->sep_win) {
7898 // separate window
7899 mainw->ignore_screen_size = TRUE;
7900 if (prefs->show_desktop_panel && (capable->wm_caps.pan_annoy & ANNOY_DISPLAY)
7901 && (capable->wm_caps.pan_annoy & ANNOY_FS) && (capable->wm_caps.pan_res & RES_HIDE) &&
7902 capable->wm_caps.pan_res & RESTYPE_ACTION) {
7903 show_desktop_panel();
7904 }
7905 if (mainw->ext_playback) {
7906 #ifndef IS_MINGW
7907 vid_playback_plugin_exit();
7908 lives_window_unfullscreen(LIVES_WINDOW(mainw->play_window));
7909 #else
7910 lives_window_unfullscreen(LIVES_WINDOW(mainw->play_window));
7911 vid_playback_plugin_exit();
7912 #endif
7913 } else {
7914 // multi monitors don't like this it seems, breaks the window
7915 lives_window_unfullscreen(LIVES_WINDOW(mainw->play_window));
7916 }
7917
7918 if (!mainw->faded) unfade_background();
7919 resize_play_window();
7920
7921 if (!mainw->multitrack && mainw->opwx > -1) {
7922 //opwx and opwy were stored when we first switched to full screen
7923 lives_window_move(LIVES_WINDOW(mainw->play_window), mainw->opwx, mainw->opwy);
7924 mainw->opwx = mainw->opwy = -1;
7925 } else {
7926 if (mainw->play_window) {
7927 lives_window_center(LIVES_WINDOW(mainw->play_window));
7928 hide_cursor(lives_widget_get_xwindow(mainw->play_window));
7929 lives_widget_set_app_paintable(mainw->play_window, TRUE);
7930 }
7931 }
7932 if (!mainw->multitrack) {
7933 lives_window_set_decorated(LIVES_WINDOW(mainw->play_window), TRUE);
7934 if (cfile->frames == 1 || cfile->play_paused) {
7935 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
7936 }
7937 }
7938 } else {
7939 // switch FROM fullscreen during pb
7940 // in frame window
7941 if (!mainw->multitrack) {
7942 if (!mainw->faded) {
7943 if (mainw->double_size) {
7944 lives_table_set_column_homogeneous(LIVES_TABLE(mainw->pf_grid), FALSE);
7945 lives_widget_hide(mainw->sep_image);
7946 if (prefs->show_msg_area) lives_widget_hide(mainw->message_box);
7947 } else lives_table_set_column_homogeneous(LIVES_TABLE(mainw->pf_grid), TRUE);
7948 unfade_background();
7949 } else {
7950 lives_widget_hide(mainw->frame1);
7951 lives_widget_hide(mainw->frame2);
7952 lives_widget_show(mainw->eventbox3);
7953 lives_widget_show(mainw->eventbox4);
7954 fade_background();
7955 if (mainw->double_size) {
7956 lives_table_set_column_homogeneous(LIVES_TABLE(mainw->pf_grid), FALSE);
7957 resize(2.);
7958 } else {
7959 lives_table_set_column_homogeneous(LIVES_TABLE(mainw->pf_grid), TRUE);
7960 resize(1.);
7961 }
7962 }
7963
7964 lives_widget_set_sensitive(mainw->fade, TRUE);
7965 lives_widget_set_sensitive(mainw->dsize, TRUE);
7966 // *INDENT-OFF*
7967 }}
7968 if (!mainw->multitrack && !mainw->faded) {
7969 if (CURRENT_CLIP_IS_VALID) {
7970 redraw_timeline(mainw->current_file);
7971 show_playbar_labels(mainw->current_file);
7972 }}}
7973 // *INDENT-ON*
7974 mainw->force_show = TRUE;
7975 } else {
7976 // not playing
7977 if (!mainw->multitrack) {
7978 if (mainw->fs) {
7979 lives_widget_set_sensitive(mainw->fade, FALSE);
7980 lives_widget_set_sensitive(mainw->dsize, FALSE);
7981 } else {
7982 lives_widget_set_sensitive(mainw->fade, TRUE);
7983 lives_widget_set_sensitive(mainw->dsize, TRUE);
7984 // *INDENT-OFF*
7985 }}}
7986 // *INDENT-ON*
7987 }
7988
7989
7990 void on_full_screen_activate(LiVESMenuItem * menuitem, livespointer user_data) {
7991 main_thread_execute((lives_funcptr_t)_on_full_screen_activate, 0, NULL, "vv", menuitem, user_data);
7992 }
7993
7994 void on_double_size_pressed(LiVESButton * button, livespointer user_data) {
7995 // toolbar button (separate window)
7996 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->dsize), !mainw->double_size);
7997 }
7998
7999
8000 void on_double_size_activate(LiVESMenuItem * menuitem, livespointer user_data) {
8001
8002 if (mainw->multitrack || (CURRENT_CLIP_IS_VALID && !CURRENT_CLIP_HAS_VIDEO && !user_data)) return;
8003
8004 if (!user_data) {
8005 mainw->double_size = !mainw->double_size;
8006 }
8007
8008 if (!CURRENT_CLIP_IS_VALID) return;
8009 mainw->blend_palette = WEED_PALETTE_END;
8010
8011 mainw->opwx = mainw->opwy = -1;
8012
8013 if ((LIVES_IS_PLAYING && !mainw->fs) || (!LIVES_IS_PLAYING && mainw->play_window)) {
8014 if (mainw->play_window) {
8015 resize_play_window();
8016 sched_yield();
8017 if (!mainw->double_size) lives_window_center(LIVES_WINDOW(mainw->play_window));
8018 } else {
8019 // in-frame
8020 if (mainw->double_size) {
8021 if (!mainw->faded) {
8022 if (palette->style & STYLE_1) {
8023 lives_widget_hide(mainw->sep_image);
8024 }
8025 if (prefs->show_msg_area) lives_widget_hide(mainw->message_box);
8026 }
8027 lives_table_set_column_homogeneous(LIVES_TABLE(mainw->pf_grid), FALSE);
8028 resize(2.);
8029 } else {
8030 lives_table_set_column_homogeneous(LIVES_TABLE(mainw->pf_grid), TRUE);
8031 resize(1.);
8032 if (!mainw->faded) {
8033 if (palette->style & STYLE_1) {
8034 lives_widget_show_all(mainw->sep_image);
8035 }
8036 if (prefs->show_msg_area) lives_widget_show_all(mainw->message_box);
8037 // *INDENT-OFF*
8038 }}}}
8039 // *INDENT-ON*
8040 if (LIVES_IS_PLAYING && !mainw->fs) mainw->force_show = TRUE;
8041 }
8042
8043
8044 void on_sepwin_pressed(LiVESButton * button, livespointer user_data) {
8045 if (mainw->go_away) return;
8046
8047 // toolbar button (separate window)
8048 if (mainw->multitrack) {
8049 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->multitrack->sepwin), !mainw->sep_win);
8050 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->sepwin), mainw->sep_win);
8051 } else lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->sepwin), !mainw->sep_win);
8052 }
8053
8054
8055 void on_sepwin_activate(LiVESMenuItem * menuitem, livespointer user_data) {
8056
8057 if (mainw->go_away) return;
8058
8059 mainw->sep_win = !mainw->sep_win;
8060 mainw->blend_palette = WEED_PALETTE_END;
8061
8062 if (mainw->multitrack) {
8063 if (!LIVES_IS_PLAYING) return;
8064 unpaint_lines(mainw->multitrack);
8065 mainw->multitrack->redraw_block = TRUE; // stop pb cursor from updating
8066 mt_show_current_frame(mainw->multitrack, FALSE);
8067 mainw->multitrack->redraw_block = FALSE;
8068 }
8069
8070 if (mainw->sep_win) {
8071 lives_widget_set_tooltip_text(mainw->m_sepwinbutton, _("Hide the play window (s)"));
8072 lives_widget_set_tooltip_text(mainw->t_sepwin, _("Hide the play window (s)"));
8073 lives_widget_set_opacity(mainw->m_sepwinbutton, 1.);
8074 lives_widget_set_opacity(mainw->t_sepwin, 1.);
8075 } else {
8076 lives_widget_set_tooltip_text(mainw->m_sepwinbutton, _("Show the play window (s)"));
8077 lives_widget_set_tooltip_text(mainw->t_sepwin, _("Play in separate window (s)"));
8078 lives_widget_set_opacity(mainw->m_sepwinbutton, .75);
8079 lives_widget_set_opacity(mainw->t_sepwin, .75);
8080 }
8081
8082 if (prefs->sepwin_type == SEPWIN_TYPE_STICKY && !LIVES_IS_PLAYING) {
8083 if (mainw->sep_win) make_play_window();
8084 else kill_play_window();
8085 /* if (mainw->multitrack && !LIVES_IS_PLAYING) { */
8086 /* activate_mt_preview(mainw->multitrack); // show frame preview */
8087 /* } */
8088 } else {
8089 if (LIVES_IS_PLAYING) {
8090 if (mainw->sep_win) {
8091 // switch to separate window during pb
8092 if (!mainw->multitrack) {
8093 lives_widget_set_opacity(mainw->playframe, 0.);
8094 if (!prefs->hide_framebar && !mainw->faded && ((!mainw->preview && (CURRENT_CLIP_HAS_VIDEO || mainw->foreign)) ||
8095 (CURRENT_CLIP_IS_VALID &&
8096 cfile->opening))) {
8097 lives_widget_show(mainw->framebar);
8098 }
8099 if ((!mainw->faded && mainw->fs && ((prefs->play_monitor != widget_opts.monitor && prefs->play_monitor > 0 &&
8100 capable->nmonitors > 1))) ||
8101 (mainw->fs && mainw->vpp &&
8102 !(mainw->vpp->capabilities & VPP_LOCAL_DISPLAY))) {
8103 unfade_background();
8104 showclipimgs();
8105 }
8106 if (mainw->fs && !mainw->faded) {
8107 lives_table_set_column_homogeneous(LIVES_TABLE(mainw->pf_grid), TRUE);
8108 resize(1.);
8109 } else {
8110 if (mainw->faded) {
8111 lives_widget_set_opacity(mainw->playframe, 0.);
8112 //lives_widget_hide(mainw->playframe);
8113 lives_widget_hide(mainw->frame1);
8114 lives_widget_hide(mainw->frame2);
8115 lives_widget_show(mainw->eventbox3);
8116 lives_widget_show(mainw->eventbox4);
8117 } else {
8118 if (mainw->double_size) {
8119 // switch back to single size as we are scooping the player out
8120 lives_table_set_column_homogeneous(LIVES_TABLE(mainw->pf_grid), TRUE);
8121 resize(1.);
8122 if (!mainw->faded) {
8123 if (palette->style & STYLE_1) {
8124 lives_widget_show(mainw->sep_image);
8125 }
8126 if (prefs->show_msg_area) lives_widget_show_all(mainw->message_box);
8127 // *INDENT-OFF*
8128 }}}}}
8129 // *INDENT-ON*
8130 else {
8131 set_drawing_area_from_pixbuf(mainw->play_image, NULL, mainw->play_surface);
8132 }
8133 make_play_window();
8134
8135 mainw->pw_scroll_func = lives_signal_connect(LIVES_GUI_OBJECT(mainw->play_window), LIVES_WIDGET_SCROLL_EVENT,
8136 LIVES_GUI_CALLBACK(on_mouse_scroll), NULL);
8137
8138 if (mainw->ext_playback && mainw->vpp->fheight > -1 && mainw->vpp->fwidth > -1) {
8139 // fixed o/p size for stream
8140 if ((mainw->vpp->fwidth == 0 || mainw->vpp->fheight == 0) && CURRENT_CLIP_IS_VALID) {
8141 mainw->vpp->fwidth = cfile->hsize;
8142 mainw->vpp->fheight = cfile->vsize;
8143 }
8144 mainw->pwidth = mainw->vpp->fwidth;
8145 mainw->pheight = mainw->vpp->fheight;
8146
8147 if (!(mainw->vpp->capabilities & VPP_LOCAL_DISPLAY)) {
8148 unfade_background();
8149 }
8150 resize(1.);
8151 resize_play_window();
8152 }
8153
8154 if (mainw->play_window && LIVES_IS_XWINDOW(lives_widget_get_xwindow(mainw->play_window))) {
8155 hide_cursor(lives_widget_get_xwindow(mainw->play_window));
8156 lives_widget_set_app_paintable(mainw->play_window, TRUE);
8157 }
8158 } else {
8159 // switch from separate window during playback
8160 if (mainw->ext_playback) {
8161 #ifndef IS_MINGW
8162 vid_playback_plugin_exit();
8163 lives_window_unfullscreen(LIVES_WINDOW(mainw->play_window));
8164 #else
8165 lives_window_unfullscreen(LIVES_WINDOW(mainw->play_window));
8166 vid_playback_plugin_exit();
8167 #endif
8168 }
8169 if (mainw->fs) {
8170 mainw->ignore_screen_size = TRUE;
8171 if (prefs->show_desktop_panel) {
8172 show_desktop_panel();
8173 }
8174 }
8175
8176 kill_play_window();
8177
8178 if (!mainw->multitrack) {
8179 lives_widget_show_all(mainw->playframe);
8180 if (!mainw->fs) {
8181 if (!mainw->double_size) {
8182 lives_table_set_column_homogeneous(LIVES_TABLE(mainw->pf_grid), TRUE);
8183 resize(1.);
8184 } else {
8185 if (palette->style & STYLE_1) {
8186 lives_widget_hide(mainw->sep_image);
8187 }
8188 if (prefs->show_msg_area) lives_widget_hide(mainw->message_box);
8189 lives_table_set_column_homogeneous(LIVES_TABLE(mainw->pf_grid), FALSE);
8190 resize(2.);
8191 }
8192 } else {
8193 // fullscreen
8194 if (!mainw->multitrack && CURRENT_CLIP_HAS_VIDEO) {
8195 lives_table_set_column_homogeneous(LIVES_TABLE(mainw->pf_grid), FALSE);
8196 fade_background();
8197 fullscreen_internal();
8198 // *INDENT-OFF*
8199 }}
8200 lives_widget_set_opacity(mainw->playframe, 1.);
8201 hide_cursor(lives_widget_get_xwindow(mainw->playarea));
8202 }}}}
8203 // *INDENT-ON*
8204 if (LIVES_IS_PLAYING) mainw->force_show = TRUE;
8205 }
8206
8207
8208 void on_showfct_activate(LiVESMenuItem * menuitem, livespointer user_data) {
8209 prefs->hide_framebar = !prefs->hide_framebar;
8210 if (!mainw->fs || (prefs->play_monitor != widget_opts.monitor && mainw->play_window && capable->nmonitors > 1)) {
8211 if (!prefs->hide_framebar) {
8212 lives_widget_show(mainw->framebar);
8213 } else {
8214 if (prefs->hide_framebar) {
8215 lives_widget_hide(mainw->framebar);
8216 // *INDENT-OFF*
8217 }}}
8218 // *INDENT-ON*
8219 }
8220
8221
8222 void on_sticky_activate(LiVESMenuItem * menuitem, livespointer user_data) {
8223 // type is SEPWIN_TYPE_STICKY (shown even when not playing)
8224 // or SEPWIN_TYPE_NON_STICKY (shown only when playing)
8225 boolean make_perm = (prefs->sepwin_type == future_prefs->sepwin_type);
8226 if (prefs->sepwin_type == SEPWIN_TYPE_NON_STICKY) {
8227 pref_factory_int(PREF_SEPWIN_TYPE, SEPWIN_TYPE_STICKY, make_perm);
8228 } else {
8229 pref_factory_int(PREF_SEPWIN_TYPE, SEPWIN_TYPE_NON_STICKY, make_perm);
8230 }
8231 }
8232
8233
8234 void on_fade_pressed(LiVESButton * button, livespointer user_data) {
8235 // toolbar button (unblank background)
8236 if (mainw->fs && (!mainw->play_window || (prefs->play_monitor == widget_opts.monitor || capable->nmonitors == 1)))
8237 return;
8238 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->fade), !mainw->faded);
8239 }
8240
8241
8242 void on_fade_activate(LiVESMenuItem * menuitem, livespointer user_data) {
8243 mainw->faded = !mainw->faded;
8244 if (LIVES_IS_PLAYING && (!mainw->fs || (prefs->play_monitor != widget_opts.monitor && mainw->play_window &&
8245 capable->nmonitors > 1))) {
8246 if (mainw->faded) {
8247 lives_widget_hide(mainw->framebar);
8248 fade_background();
8249 } else {
8250 unfade_background();
8251 lives_widget_show(mainw->frame1);
8252 lives_widget_show(mainw->frame2);
8253 lives_widget_show(mainw->eventbox3);
8254 lives_widget_show(mainw->eventbox4);
8255 if (!prefs->hide_framebar && !(prefs->hfbwnp && !LIVES_IS_PLAYING)) {
8256 lives_widget_show(mainw->framebar);
8257 }
8258 if (!mainw->multitrack && CURRENT_CLIP_IS_VALID) {
8259 redraw_timeline(mainw->current_file);
8260 show_playbar_labels(mainw->current_file);
8261 // *INDENT-OFF*
8262 }}}
8263 // *INDENT-ON*
8264 }
8265
8266
8267 void on_showsubs_toggled(LiVESWidgetObject * obj, livespointer user_data) {
8268 prefs->show_subtitles = !prefs->show_subtitles;
8269 if (mainw->current_file > 0 && !mainw->multitrack) {
8270 if (mainw->play_window) {
8271 load_preview_image(FALSE);
8272 }
8273 showclipimgs();
8274 }
8275 }
8276
8277
8278 void on_boolean_toggled(LiVESWidgetObject * obj, livespointer user_data) {
8279 boolean *ppref = (boolean *)user_data;
8280 *ppref = !(*ppref);
8281 }
8282
8283
8284 void on_audio_toggled(LiVESWidget * tbutton, LiVESWidget * label) {
8285 boolean state;
8286 if (!LIVES_IS_INTERACTIVE) return;
8287
8288 state = lives_toggle_tool_button_get_active(LIVES_TOGGLE_TOOL_BUTTON(tbutton));
8289 lives_widget_set_sensitive(tbutton, !state);
8290
8291 if (tbutton == mainw->ext_audio_checkbutton) {
8292 pref_factory_bool(PREF_REC_EXT_AUDIO, state, TRUE);
8293 } else {
8294 pref_factory_bool(PREF_REC_EXT_AUDIO, !state, TRUE);
8295 }
8296 }
8297
8298 void on_loop_video_activate(LiVESMenuItem * menuitem, livespointer user_data) {
8299 if (mainw->current_file == 0) return;
8300 mainw->loop = !mainw->loop;
8301 lives_widget_set_sensitive(mainw->playclip, !LIVES_IS_PLAYING && clipboard);
8302 if (mainw->current_file > -1) find_when_to_stop();
8303 }
8304
8305
8306 void on_loop_button_activate(LiVESMenuItem * menuitem, livespointer user_data) {
8307 if (mainw->multitrack) {
8308 lives_signal_handler_block(mainw->multitrack->loop_continue, mainw->multitrack->loop_cont_func);
8309 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->multitrack->loop_continue), !mainw->loop_cont);
8310 lives_signal_handler_unblock(mainw->multitrack->loop_continue, mainw->multitrack->loop_cont_func);
8311 }
8312 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->loop_continue), !mainw->loop_cont);
8313 }
8314
8315
8316 void on_loop_cont_activate(LiVESMenuItem * menuitem, livespointer user_data) {
8317
8318 mainw->loop_cont = !mainw->loop_cont;
8319
8320 if (mainw->loop_cont) {
8321 lives_widget_set_tooltip_text(mainw->m_loopbutton, _("Switch continuous looping off (o)"));
8322 lives_widget_set_opacity(mainw->m_loopbutton, 1.);
8323 } else {
8324 lives_widget_set_tooltip_text(mainw->m_loopbutton, _("Switch continuous looping on (o)"));
8325 lives_widget_set_opacity(mainw->m_loopbutton, .75);
8326 }
8327
8328 lives_widget_set_sensitive(mainw->playclip, clipboard != NULL);
8329 if (mainw->current_file > -1) find_when_to_stop();
8330 else mainw->whentostop = NEVER_STOP;
8331
8332 if (mainw->preview_box) {
8333 if (mainw->loop_cont)
8334 lives_widget_set_opacity(mainw->p_loopbutton, 1.);
8335 else
8336 lives_widget_set_opacity(mainw->p_loopbutton, .75);
8337 }
8338
8339 #ifdef ENABLE_JACK
8340 if (prefs->audio_player == AUD_PLAYER_JACK) {
8341 if (mainw->jackd && (mainw->loop_cont || mainw->whentostop == NEVER_STOP)) {
8342 if (mainw->ping_pong && prefs->audio_opts & AUDIO_OPTS_FOLLOW_FPS)
8343 mainw->jackd->loop = AUDIO_LOOP_PINGPONG;
8344 else mainw->jackd->loop = AUDIO_LOOP_FORWARD;
8345 } else if (mainw->jackd) mainw->jackd->loop = AUDIO_LOOP_NONE;
8346 }
8347 #endif
8348 #ifdef HAVE_PULSE_AUDIO
8349 if (prefs->audio_player == AUD_PLAYER_PULSE) {
8350 if (mainw->pulsed && (mainw->loop_cont || mainw->whentostop == NEVER_STOP)) {
8351 if (mainw->ping_pong && prefs->audio_opts & AUDIO_OPTS_FOLLOW_FPS)
8352 mainw->pulsed->loop = AUDIO_LOOP_PINGPONG;
8353 else mainw->pulsed->loop = AUDIO_LOOP_FORWARD;
8354 } else if (mainw->pulsed) mainw->pulsed->loop = AUDIO_LOOP_NONE;
8355 }
8356 #endif
8357 }
8358
8359
8360 void on_ping_pong_activate(LiVESMenuItem * menuitem, livespointer user_data) {
8361 mainw->ping_pong = !mainw->ping_pong;
8362 #ifdef ENABLE_JACK
8363 if (prefs->audio_player == AUD_PLAYER_JACK && mainw->jackd && mainw->jackd->loop != AUDIO_LOOP_NONE) {
8364 if (mainw->ping_pong && prefs->audio_opts & AUDIO_OPTS_FOLLOW_FPS) mainw->jackd->loop = AUDIO_LOOP_PINGPONG;
8365 else mainw->jackd->loop = AUDIO_LOOP_FORWARD;
8366 }
8367 #endif
8368 #ifdef HAVE_PULSE_AUDIO
8369 if (prefs->audio_player == AUD_PLAYER_PULSE && mainw->pulsed && mainw->pulsed->loop != AUDIO_LOOP_NONE) {
8370 if (mainw->ping_pong && prefs->audio_opts & AUDIO_OPTS_FOLLOW_FPS) mainw->pulsed->loop = AUDIO_LOOP_PINGPONG;
8371 else mainw->pulsed->loop = AUDIO_LOOP_FORWARD;
8372 }
8373 #endif
8374 }
8375
8376
8377 void on_volume_slider_value_changed(LiVESScaleButton * sbutton, livespointer user_data) {
8378 pref_factory_float(PREF_MASTER_VOLUME, lives_scale_button_get_value(sbutton), TRUE);
8379 }
8380
8381
8382 void on_mute_button_activate(LiVESMenuItem * menuitem, livespointer user_data) {
8383 if (mainw->multitrack) {
8384 lives_signal_handler_block(mainw->multitrack->mute_audio, mainw->multitrack->mute_audio_func);
8385 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->multitrack->mute_audio), !mainw->mute);
8386 lives_signal_handler_unblock(mainw->multitrack->mute_audio, mainw->multitrack->mute_audio_func);
8387 }
8388 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->mute_audio), !mainw->mute);
8389 }
8390
8391
8392 boolean mute_audio_callback(LiVESAccelGroup * group, LiVESWidgetObject * obj, uint32_t keyval, LiVESXModifierType mod,
8393 livespointer user_data) {
8394 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->mute_audio), !mainw->mute);
8395 return TRUE;
8396 }
8397
8398
8399 void on_mute_activate(LiVESMenuItem * menuitem, livespointer user_data) {
8400
8401 mainw->mute = !mainw->mute;
8402
8403 // change the mute icon
8404
8405 if (mainw->mute) {
8406 lives_widget_set_opacity(mainw->m_mutebutton, 1.);
8407 if (mainw->preview_box) {
8408 lives_widget_set_opacity(mainw->p_mutebutton, 1.);
8409 }
8410 #ifdef ENABLE_JACK
8411 if (mainw->jackd && prefs->audio_player == AUD_PLAYER_JACK) {
8412 if (LIVES_IS_PLAYING) {
8413 if (mainw->record && !mainw->record_paused && (prefs->rec_opts & REC_AUDIO)) {
8414 weed_plant_t *event = get_last_frame_event(mainw->event_list);
8415 insert_audio_event_at(event, -1, mainw->jackd->playing_file, 0., 0.); // audio switch off
8416 }
8417 mainw->jackd->mute = TRUE;
8418 mainw->jackd->in_use = TRUE;
8419 }
8420 }
8421 #endif
8422 #ifdef HAVE_PULSE_AUDIO
8423 if (mainw->pulsed && prefs->audio_player == AUD_PLAYER_PULSE) {
8424 if (LIVES_IS_PLAYING) {
8425 if (mainw->record && !mainw->record_paused && (prefs->rec_opts & REC_AUDIO)) {
8426 weed_plant_t *event = get_last_frame_event(mainw->event_list);
8427 insert_audio_event_at(event, -1, mainw->pulsed->playing_file, 0., 0.); // audio switch off
8428 }
8429 mainw->pulsed->mute = TRUE;
8430 mainw->pulsed->in_use = TRUE;
8431 }
8432 }
8433 #endif
8434 lives_widget_set_tooltip_text(mainw->m_mutebutton, _("Unmute the audio (z)"));
8435 if (mainw->preview_box) lives_widget_set_tooltip_text(mainw->p_mutebutton, _("Unmute the audio (z)"));
8436 } else {
8437 #ifdef ENABLE_JACK
8438 if (mainw->jackd && prefs->audio_player == AUD_PLAYER_JACK) {
8439 if (LIVES_IS_PLAYING) {
8440 if (mainw->record && !mainw->record_paused && (prefs->rec_opts & REC_AUDIO)) {
8441 jack_get_rec_avals(mainw->jackd);
8442 }
8443 mainw->jackd->mute = FALSE;
8444 mainw->jackd->in_use = TRUE;
8445 }
8446 }
8447 #endif
8448 #ifdef HAVE_PULSE_AUDIO
8449 if (mainw->pulsed && prefs->audio_player == AUD_PLAYER_PULSE) {
8450 if (LIVES_IS_PLAYING) {
8451 if (mainw->record && !mainw->record_paused && (prefs->rec_opts & REC_AUDIO)) {
8452 pulse_get_rec_avals(mainw->pulsed);
8453 }
8454 mainw->pulsed->mute = FALSE;
8455 mainw->pulsed->in_use = TRUE;
8456 }
8457 }
8458 #endif
8459 lives_widget_set_opacity(mainw->m_mutebutton, .75);
8460 if (mainw->preview_box) {
8461 lives_widget_set_opacity(mainw->p_mutebutton, .75);
8462 }
8463
8464 lives_widget_set_tooltip_text(mainw->m_mutebutton, _("Mute the audio (z)"));
8465 if (mainw->preview_box) lives_widget_set_tooltip_text(mainw->p_mutebutton, _("Mute the audio (z)"));
8466
8467 #ifdef ENABLE_JACK
8468 if (prefs->audio_player == AUD_PLAYER_JACK && LIVES_IS_PLAYING && mainw->jackd) {
8469 mainw->jackd->mute = mainw->mute;
8470 }
8471 #endif
8472 #ifdef HAVE_PULSE_AUDIO
8473 if (prefs->audio_player == AUD_PLAYER_PULSE && LIVES_IS_PLAYING && mainw->pulsed) {
8474 mainw->pulsed->mute = mainw->mute;
8475 }
8476 #endif
8477 }
8478 }
8479
8480 #define GEN_SPB_LINK(n, bit) case n: mainw->fx##n##_##bit = \
8481 lives_spin_button_get_value(LIVES_SPIN_BUTTON(spinbutton)); break
8482 #define GEN_SPB_LINK_I(n, bit) case n: mainw->fx##n##_##bit = \
8483 lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton)); break
8484
8485 void on_spin_value_changed(LiVESSpinButton * spinbutton, livespointer user_data) {
8486 // TODO - use array
8487 switch (LIVES_POINTER_TO_INT(user_data)) {
8488 GEN_SPB_LINK(1, val); GEN_SPB_LINK(2, val);
8489 GEN_SPB_LINK(3, val); GEN_SPB_LINK(4, val);
8490 default: break;
8491 }
8492 }
8493
8494
8495 void on_spin_start_value_changed(LiVESSpinButton * spinbutton, livespointer user_data) {
8496 // generic
8497 // TODO - use array
8498 switch (LIVES_POINTER_TO_INT(user_data)) {
8499 GEN_SPB_LINK_I(1, start); GEN_SPB_LINK_I(2, start);
8500 GEN_SPB_LINK_I(3, start); GEN_SPB_LINK_I(4, start);
8501 default: break;
8502 }
8503 }
8504
8505
8506 void on_spin_step_value_changed(LiVESSpinButton * spinbutton, livespointer user_data) {
8507 // generic
8508 // TODO - use array
8509 switch (LIVES_POINTER_TO_INT(user_data)) {
8510 GEN_SPB_LINK_I(1, step); GEN_SPB_LINK_I(2, step);
8511 GEN_SPB_LINK_I(3, step); GEN_SPB_LINK_I(4, step);
8512 default: break;
8513 }
8514 }
8515
8516
8517 void on_spin_end_value_changed(LiVESSpinButton * spinbutton, livespointer user_data) {
8518 // generic
8519 // TODO - use array
8520 switch (LIVES_POINTER_TO_INT(user_data)) {
8521 GEN_SPB_LINK_I(1, end); GEN_SPB_LINK_I(2, end);
8522 GEN_SPB_LINK_I(3, end); GEN_SPB_LINK_I(4, end);
8523 default: break;
8524 }
8525 }
8526
8527
8528 void on_rev_clipboard_activate(LiVESMenuItem * menuitem, livespointer user_data) {
8529 // reverse the clipboard
8530 char *com;
8531 int current_file = mainw->current_file;
8532 mainw->current_file = 0;
8533
8534 if (!check_if_non_virtual(0, 1, cfile->frames)) {
8535 lives_clip_data_t *cdata = ((lives_decoder_t *)cfile->ext_src)->cdata;
8536 char *msg = (_("Pulling frames from clipboard..."));
8537 if (!(cdata->seek_flag & LIVES_SEEK_FAST)) {
8538 if (realize_all_frames(0, msg, FALSE) <= 0) {
8539 mainw->current_file = current_file;
8540 lives_free(msg);
8541 sensitize();
8542 return;
8543 }
8544 lives_free(msg);
8545 }
8546 }
8547
8548 d_print(_("Reversing clipboard..."));
8549 com = lives_strdup_printf("%s reverse \"%s\" %d %d \"%s\"", prefs->backend, clipboard->handle, 1, clipboard->frames,
8550 get_image_ext_for_type(cfile->img_type));
8551
8552 lives_rm(cfile->info_file);
8553 lives_system(com, FALSE);
8554 lives_free(com);
8555
8556 if (!THREADVAR(com_failed)) {
8557 cfile->progress_start = 1;
8558 cfile->progress_end = cfile->frames;
8559
8560 // show a progress dialog, not cancellable
8561 do_progress_dialog(TRUE, FALSE, _("Reversing clipboard"));
8562 }
8563
8564 if (THREADVAR(com_failed) || mainw->error) d_print_failed();
8565 else {
8566 if (clipboard->frame_index) reverse_frame_index(0);
8567 d_print_done();
8568 }
8569 clipboard->arate = -clipboard->arate;
8570 clipboard->aseek_pos = clipboard->afilesize;
8571 mainw->current_file = current_file;
8572 sensitize();
8573 }
8574
8575
8576 void on_load_subs_activate(LiVESMenuItem * menuitem, livespointer user_data) {
8577 char *subfile;
8578 char *filt[] = LIVES_SUBS_FILTER;
8579 char filename[512];
8580 char *subfname, *isubfname;
8581 lives_subtitle_type_t subtype = SUBTITLE_TYPE_NONE;
8582 char *lfile_name;
8583 char *ttl;
8584
8585 if (!CURRENT_CLIP_IS_VALID) return;
8586
8587 if (cfile->subt) if (!do_existing_subs_warning()) return;
8588
8589 // try to repaint the screen, as it may take a few seconds to get a directory listing
8590 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
8591
8592 ttl = (_("Load Subtitles"));
8593
8594 if (*mainw->vid_load_dir) {
8595 subfile = choose_file(mainw->vid_load_dir, NULL, filt, LIVES_FILE_CHOOSER_ACTION_OPEN, ttl, NULL);
8596 } else subfile = choose_file(NULL, NULL, filt, LIVES_FILE_CHOOSER_ACTION_OPEN, ttl, NULL);
8597 lives_free(ttl);
8598
8599 if (!subfile) return; // cancelled
8600
8601 lives_snprintf(filename, 512, "%s", subfile);
8602 lives_free(subfile);
8603
8604 get_filename(filename, FALSE); // strip extension
8605 isubfname = lives_strdup_printf("%s.%s", filename, LIVES_FILE_EXT_SRT);
8606 lfile_name = lives_filename_from_utf8(isubfname, -1, NULL, NULL, NULL);
8607
8608 if (lives_file_test(lfile_name, LIVES_FILE_TEST_EXISTS)) {
8609 subfname = lives_build_filename(prefs->workdir, cfile->handle, SUBS_FILENAME "." LIVES_FILE_EXT_SRT, NULL);
8610 subtype = SUBTITLE_TYPE_SRT;
8611 } else {
8612 lives_free(isubfname);
8613 lives_free(lfile_name);
8614 isubfname = lives_strdup_printf("%s.%s", filename, LIVES_FILE_EXT_SUB);
8615 lfile_name = lives_filename_from_utf8(isubfname, -1, NULL, NULL, NULL);
8616
8617 if (lives_file_test(isubfname, LIVES_FILE_TEST_EXISTS)) {
8618 subfname = lives_build_filename(prefs->workdir, cfile->handle, SUBS_FILENAME "." LIVES_FILE_EXT_SUB, NULL);
8619 subtype = SUBTITLE_TYPE_SUB;
8620 } else {
8621 lives_free(isubfname);
8622 do_invalid_subs_error();
8623 lives_free(lfile_name);
8624 return;
8625 }
8626 }
8627
8628 if (cfile->subt) {
8629 // erase any existing subs
8630 on_erase_subs_activate(NULL, NULL);
8631 subtitles_free(cfile);
8632 }
8633
8634 lives_cp(lfile_name, subfname);
8635
8636 if (THREADVAR(com_failed)) {
8637 lives_free(subfname);
8638 lives_free(isubfname);
8639 lives_free(lfile_name);
8640 return;
8641 }
8642
8643 subtitles_init(cfile, subfname, subtype);
8644 lives_free(subfname);
8645
8646 if (!mainw->multitrack) {
8647 // force update
8648 switch_to_file(0, mainw->current_file);
8649 }
8650
8651 d_print(_("Loaded subtitle file: %s\n"), isubfname);
8652
8653 lives_free(isubfname);
8654 lives_free(lfile_name);
8655 }
8656
8657
8658 void on_save_subs_activate(LiVESMenuItem * menuitem, livespointer user_data) {
8659 char *subfile;
8660 char xfname[512];
8661 char xfname2[512];
8662
8663 // try to repaint the screen, as it may take a few seconds to get a directory listing
8664 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
8665
8666 lives_snprintf(xfname, 512, "%s", mainw->subt_save_file);
8667 get_dirname(xfname);
8668
8669 lives_snprintf(xfname2, 512, "%s", mainw->subt_save_file);
8670 get_basename(xfname2);
8671
8672 subfile = choose_file(xfname, xfname2, NULL, LIVES_FILE_CHOOSER_ACTION_SAVE, NULL, NULL);
8673
8674 if (!subfile) return; // cancelled
8675
8676 lives_free(subfile);
8677 }
8678
8679
8680 void on_erase_subs_activate(LiVESMenuItem * menuitem, livespointer user_data) {
8681 char *sfname;
8682
8683 if (!CURRENT_CLIP_IS_VALID || !cfile->subt) return;
8684
8685 if (menuitem)
8686 if (!do_erase_subs_warning()) return;
8687
8688 switch (cfile->subt->type) {
8689 case SUBTITLE_TYPE_SRT:
8690 sfname = lives_build_filename(prefs->workdir, cfile->handle, SUBS_FILENAME "." LIVES_FILE_EXT_SRT, NULL);
8691 break;
8692
8693 case SUBTITLE_TYPE_SUB:
8694 sfname = lives_build_filename(prefs->workdir, cfile->handle, SUBS_FILENAME "." LIVES_FILE_EXT_SUB, NULL);
8695 break;
8696
8697 default:
8698 return;
8699 }
8700
8701 subtitles_free(cfile);
8702
8703 lives_rm(sfname);
8704 lives_free(sfname);
8705
8706 if (menuitem) {
8707 // force update
8708 if (!mainw->multitrack) {
8709 switch_to_file(0, mainw->current_file);
8710 }
8711 d_print(_("Subtitles were erased.\n"));
8712 }
8713 }
8714
8715
8716 void on_load_audio_activate(LiVESMenuItem * menuitem, livespointer user_data) {
8717 LiVESWidget *chooser;
8718 char *filt[] = LIVES_AUDIO_LOAD_FILTER;
8719 LiVESResponseType resp;
8720 mainw->mt_needs_idlefunc = FALSE;
8721
8722 if (mainw->multitrack) {
8723 if (mainw->multitrack->idlefunc > 0) {
8724 lives_source_remove(mainw->multitrack->idlefunc);
8725 mainw->multitrack->idlefunc = 0;
8726 mainw->mt_needs_idlefunc = TRUE;
8727 }
8728 mt_desensitise(mainw->multitrack);
8729 lives_widget_set_sensitive(mainw->multitrack->playall, TRUE);
8730 lives_widget_set_sensitive(mainw->m_playbutton, TRUE);
8731 }
8732
8733 chooser = choose_file_with_preview((*mainw->audio_dir) ? mainw->audio_dir : NULL, _("Select Audio File"), filt,
8734 LIVES_FILE_SELECTION_AUDIO_ONLY);
8735
8736 resp = lives_dialog_run(LIVES_DIALOG(chooser));
8737
8738 end_fs_preview();
8739
8740 if (resp != LIVES_RESPONSE_ACCEPT) on_filechooser_cancel_clicked(chooser);
8741 else on_open_new_audio_clicked(LIVES_FILE_CHOOSER(chooser), NULL);
8742 }
8743
8744
8745 void on_open_new_audio_clicked(LiVESFileChooser * chooser, livespointer user_data) {
8746 // open audio file
8747 // also called from osc.c
8748
8749 char *a_type;
8750 char *com, *tmp;
8751 char **array;
8752
8753 uint32_t chk_mask = 0;
8754
8755 int oundo_start;
8756 int oundo_end;
8757 int israw = 1;
8758 int asigned, aendian;
8759
8760 boolean bad_header = FALSE;
8761 boolean preparse = FALSE;
8762 boolean gotit = FALSE;
8763
8764 register int i;
8765
8766 if (!CURRENT_CLIP_IS_VALID) return;
8767
8768 tmp = (_("Loading new audio"));
8769 chk_mask = WARN_MASK_LAYOUT_DELETE_AUDIO | WARN_MASK_LAYOUT_ALTER_AUDIO;
8770 if (!check_for_layout_errors(tmp, mainw->current_file, 1, 0, &chk_mask)) {
8771 lives_free(tmp);
8772 if (mainw->multitrack) {
8773 mt_sensitise(mainw->multitrack);
8774 maybe_add_mt_idlefunc();
8775 }
8776 return;
8777 }
8778
8779 cfile->undo_arate = cfile->arate;
8780 cfile->undo_achans = cfile->achans;
8781 cfile->undo_asampsize = cfile->asampsize;
8782 cfile->undo_signed_endian = cfile->signed_endian;
8783 cfile->undo_arps = cfile->arps;
8784
8785 oundo_start = cfile->undo_start;
8786 oundo_end = cfile->undo_end;
8787
8788 if (!user_data) {
8789 char *filename = lives_file_chooser_get_filename(chooser);
8790 lives_snprintf(file_name, PATH_MAX, "%s", (tmp = lives_filename_to_utf8(filename, -1, NULL, NULL, NULL)));
8791 lives_free(filename);
8792 lives_free(tmp);
8793 } else lives_snprintf(file_name, PATH_MAX, "%s", (char *)user_data);
8794
8795 lives_snprintf(mainw->audio_dir, PATH_MAX, "%s", file_name);
8796 get_dirname(mainw->audio_dir);
8797 end_fs_preview();
8798 lives_widget_destroy(LIVES_WIDGET(chooser));
8799 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
8800
8801 a_type = get_extension(file_name);
8802
8803 if (strlen(a_type)) {
8804 char *filt[] = LIVES_AUDIO_LOAD_FILTER;
8805 for (i = 0; filt[i]; i++) {
8806 if (!lives_ascii_strcasecmp(a_type, filt[i] + 2)) gotit = TRUE; // skip past "*." in filt
8807 }
8808 }
8809
8810 if (gotit) {
8811 com = lives_strdup_printf("%s audioopen \"%s\" \"%s\"", prefs->backend, cfile->handle,
8812 (tmp = lives_filename_from_utf8(file_name, -1, NULL, NULL, NULL)));
8813 lives_free(tmp);
8814 } else {
8815 lives_free(a_type);
8816 do_audio_import_error();
8817
8818 if (mainw->multitrack) {
8819 mt_sensitise(mainw->multitrack);
8820 maybe_add_mt_idlefunc();
8821 }
8822 unbuffer_lmap_errors(FALSE);
8823 return;
8824 }
8825
8826 if (!lives_ascii_strncasecmp(a_type, LIVES_FILE_EXT_WAV, 3)) israw = 0;
8827
8828 if (HAS_EXTERNAL_PLAYER) {
8829 if (read_file_details(file_name, TRUE, FALSE)) {
8830 if (get_token_count(mainw->msg, '|') >= 14) {
8831 array = lives_strsplit(mainw->msg, "|", -1);
8832 cfile->arate = atoi(array[9]);
8833 cfile->achans = atoi(array[10]);
8834 cfile->asampsize = atoi(array[11]);
8835 cfile->signed_endian = get_signed_endian(atoi(array[12]), atoi(array[13]));
8836 lives_strfreev(array);
8837 preparse = TRUE;
8838 }
8839 }
8840 }
8841
8842 if (!preparse) {
8843 // TODO !!! - need some way to identify audio without invoking mplayer
8844 cfile->arate = cfile->arps = DEFAULT_AUDIO_RATE;
8845 cfile->achans = DEFAULT_AUDIO_CHANS;
8846 cfile->asampsize = DEFAULT_AUDIO_SAMPS;
8847 cfile->signed_endian = mainw->endian;
8848 }
8849
8850 if (cfile->undo_arate > 0) cfile->arps = cfile->undo_arps / cfile->undo_arate * cfile->arate;
8851 else cfile->arps = cfile->arate;
8852
8853 d_print(""); // force switchtext
8854 d_print(_("Opening audio %s, type %s..."), file_name, a_type);
8855 lives_free(a_type);
8856
8857 lives_rm(cfile->info_file);
8858 lives_system(com, FALSE);
8859 lives_free(com);
8860
8861 if (THREADVAR(com_failed)) {
8862 cfile->arate = cfile->undo_arate;
8863 cfile->achans = cfile->undo_achans;
8864 cfile->asampsize = cfile->undo_asampsize;
8865 cfile->signed_endian = cfile->undo_signed_endian;
8866 cfile->arps = cfile->undo_arps;
8867 cfile->undo_start = oundo_start;
8868 cfile->undo_end = oundo_end;
8869 sensitize();
8870 if (mainw->multitrack) {
8871 mt_sensitise(mainw->multitrack);
8872 maybe_add_mt_idlefunc();
8873 }
8874 reget_afilesize(mainw->current_file);
8875 unbuffer_lmap_errors(FALSE);
8876 return;
8877 }
8878
8879 cfile->opening = cfile->opening_audio = cfile->opening_only_audio = TRUE;
8880
8881 cfile->undo_start = 1;
8882 cfile->undo_end = cfile->frames;
8883
8884 // show audio [opening...] in main window
8885 get_play_times();
8886
8887 if (!(do_progress_dialog(TRUE, TRUE, _("Opening audio")))) {
8888 lives_widget_queue_draw_and_update(LIVES_MAIN_WINDOW_WIDGET);
8889
8890 mainw->cancelled = CANCEL_NONE;
8891 mainw->error = FALSE;
8892 lives_rm(cfile->info_file);
8893 com = lives_strdup_printf("%s cancel_audio \"%s\"", prefs->backend, cfile->handle);
8894 lives_system(com, FALSE);
8895 do_auto_dialog(_("Cancelling"), 0);
8896 lives_free(com);
8897 cfile->opening_audio = cfile->opening = cfile->opening_only_audio = FALSE;
8898 cfile->arate = cfile->undo_arate;
8899 cfile->achans = cfile->undo_achans;
8900 cfile->asampsize = cfile->undo_asampsize;
8901 cfile->signed_endian = cfile->undo_signed_endian;
8902 cfile->arps = cfile->undo_arps;
8903 cfile->undo_start = oundo_start;
8904 cfile->undo_end = oundo_end;
8905 sensitize();
8906 if (mainw->multitrack) {
8907 mt_sensitise(mainw->multitrack);
8908 maybe_add_mt_idlefunc();
8909 }
8910 reget_afilesize(mainw->current_file);
8911 if (mainw->error) d_print_failed();
8912 unbuffer_lmap_errors(FALSE);
8913 return;
8914 }
8915
8916 cfile->opening_audio = cfile->opening = cfile->opening_only_audio = FALSE;
8917
8918 cfile->afilesize = 0;
8919
8920 if (get_token_count(mainw->msg, '|') > 6) {
8921 array = lives_strsplit(mainw->msg, "|", 7);
8922 cfile->arate = atoi(array[1]);
8923 cfile->achans = atoi(array[2]);
8924 cfile->asampsize = atoi(array[3]);
8925 cfile->signed_endian = get_signed_endian(atoi(array[4]), atoi(array[5]));
8926 cfile->afilesize = atol(array[6]);
8927 lives_strfreev(array);
8928
8929 if (cfile->undo_arate > 0) cfile->arps = cfile->undo_arps / cfile->undo_arate * cfile->arate;
8930 else cfile->arps = cfile->arate;
8931 }
8932
8933 /// not sure why, but this messes up mainw->msg...
8934 lives_widget_queue_draw_and_update(LIVES_MAIN_WINDOW_WIDGET);
8935
8936 if (cfile->afilesize == 0) {
8937 d_print_failed();
8938
8939 mainw->cancelled = CANCEL_NONE;
8940 mainw->error = FALSE;
8941 lives_rm(cfile->info_file);
8942
8943 com = lives_strdup_printf("%s cancel_audio \"%s\"", prefs->backend, cfile->handle);
8944
8945 lives_system(com, FALSE);
8946 lives_free(com);
8947
8948 if (!THREADVAR(com_failed)) do_auto_dialog(_("Cancelling"), 0);
8949
8950 cfile->arate = cfile->undo_arate;
8951 cfile->achans = cfile->undo_achans;
8952 cfile->asampsize = cfile->undo_asampsize;
8953 cfile->signed_endian = cfile->undo_signed_endian;
8954 cfile->arps = cfile->undo_arps;
8955 cfile->undo_start = oundo_start;
8956 cfile->undo_end = oundo_end;
8957 sensitize();
8958 if (mainw->multitrack) {
8959 mt_sensitise(mainw->multitrack);
8960 maybe_add_mt_idlefunc();
8961 }
8962 reget_afilesize(mainw->current_file);
8963 unbuffer_lmap_errors(FALSE);
8964 return;
8965 }
8966
8967 cfile->changed = TRUE;
8968 d_print_done();
8969
8970 d_print(P_("New audio: %d Hz %d channel %d bps\n", "New audio: %d Hz %d channels %d bps\n",
8971 cfile->achans),
8972 cfile->arate, cfile->achans, cfile->asampsize);
8973
8974 mainw->cancelled = CANCEL_NONE;
8975 mainw->error = FALSE;
8976 lives_rm(cfile->info_file);
8977
8978 com = lives_strdup_printf("%s commit_audio \"%s\" %d", prefs->backend, cfile->handle, israw);
8979 lives_system(com, FALSE);
8980 lives_free(com);
8981
8982 if (THREADVAR(com_failed)) {
8983 cfile->arate = cfile->undo_arate;
8984 cfile->achans = cfile->undo_achans;
8985 cfile->asampsize = cfile->undo_asampsize;
8986 cfile->signed_endian = cfile->undo_signed_endian;
8987 cfile->arps = cfile->undo_arps;
8988 cfile->undo_start = oundo_start;
8989 cfile->undo_end = oundo_end;
8990 sensitize();
8991 if (mainw->multitrack) {
8992 mt_sensitise(mainw->multitrack);
8993 maybe_add_mt_idlefunc();
8994 }
8995 reget_afilesize(mainw->current_file);
8996 unbuffer_lmap_errors(FALSE);
8997 return;
8998 }
8999
9000 if (!do_auto_dialog(_("Committing audio"), 0)) {
9001 //cfile->may_be_damaged=TRUE;
9002 d_print_failed();
9003 if (mainw->multitrack) {
9004 mt_sensitise(mainw->multitrack);
9005 maybe_add_mt_idlefunc();
9006 }
9007 unbuffer_lmap_errors(FALSE);
9008 return;
9009 }
9010
9011 if (prefs->save_directories) {
9012 set_utf8_pref(PREF_AUDIO_DIR, mainw->audio_dir);
9013 }
9014 if (!prefs->conserve_space) {
9015 cfile->undo_action = UNDO_NEW_AUDIO;
9016 set_undoable(_("New Audio"), TRUE);
9017 }
9018
9019 asigned = !(cfile->signed_endian & AFORM_UNSIGNED);
9020 aendian = cfile->signed_endian & AFORM_BIG_ENDIAN;
9021
9022 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ARATE, &cfile->arps)) bad_header = TRUE;
9023 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_PB_ARATE, &cfile->arate)) bad_header = TRUE;
9024 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ACHANS, &cfile->achans)) bad_header = TRUE;
9025 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ASAMPS, &cfile->asampsize)) bad_header = TRUE;
9026 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_AENDIAN, &aendian)) bad_header = TRUE;
9027 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ASIGNED, &asigned)) bad_header = TRUE;
9028
9029 if (bad_header) do_header_write_error(mainw->current_file);
9030
9031 if (!mainw->multitrack) {
9032 switch_to_file(mainw->current_file, mainw->current_file);
9033 }
9034
9035 if (chk_mask != 0) popup_lmap_errors(NULL, LIVES_INT_TO_POINTER(chk_mask));
9036
9037 if (mainw->multitrack) {
9038 mt_sensitise(mainw->multitrack);
9039 maybe_add_mt_idlefunc();
9040 }
9041 }
9042
9043
9044 void on_load_cdtrack_activate(LiVESMenuItem * menuitem, livespointer user_data) {
9045 LiVESWidget *cdtrack_dialog;
9046
9047 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
9048
9049 if (!strlen(prefs->cdplay_device)) {
9050 do_cd_error_dialog();
9051 return;
9052 }
9053
9054 mainw->fx1_val = 1;
9055 cdtrack_dialog = create_cdtrack_dialog(LIVES_DEVICE_CD, NULL);
9056 lives_widget_show_all(cdtrack_dialog);
9057 }
9058
9059
9060 void on_eject_cd_activate(LiVESMenuItem * menuitem, livespointer user_data) {
9061 char *com;
9062
9063 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
9064
9065 if (!strlen(prefs->cdplay_device)) {
9066 do_cd_error_dialog();
9067 return;
9068 }
9069
9070 if (strlen(capable->eject_cmd)) {
9071 com = lives_strdup_printf("%s \"%s\"", capable->eject_cmd, prefs->cdplay_device);
9072
9073 lives_system(com, TRUE);
9074 lives_free(com);
9075 }
9076 }
9077
9078
9079 void on_load_cdtrack_ok_clicked(LiVESButton * button, livespointer user_data) {
9080 char *com;
9081 char **array;
9082
9083 boolean was_new = FALSE;
9084
9085 uint32_t chk_mask = 0;
9086
9087 int new_file = mainw->first_free_file;
9088 int asigned, endian;
9089
9090 boolean bad_header = FALSE;
9091 boolean needs_idlefunc = mainw->mt_needs_idlefunc;
9092 mainw->mt_needs_idlefunc = FALSE;
9093 lives_general_button_clicked(button, NULL);
9094 mainw->mt_needs_idlefunc = needs_idlefunc;
9095
9096 if (CURRENT_CLIP_IS_VALID) {
9097 char *tmp = (_("Loading new audio"));
9098 chk_mask = WARN_MASK_LAYOUT_DELETE_AUDIO | WARN_MASK_LAYOUT_ALTER_AUDIO;
9099 if (!check_for_layout_errors(tmp, mainw->current_file, 1, 0, &chk_mask)) {
9100 lives_free(tmp);
9101 return;
9102 }
9103 lives_free(tmp);
9104 }
9105
9106 d_print(_("Opening CD track %d from %s..."), (int)mainw->fx1_val, prefs->cdplay_device);
9107
9108 if (!CURRENT_CLIP_IS_VALID) {
9109 if (!get_new_handle(new_file, lives_strdup_printf(_("CD track %d"), (int)mainw->fx1_val))) {
9110 unbuffer_lmap_errors(FALSE);
9111 return;
9112 }
9113
9114 mainw->current_file = new_file;
9115 lives_snprintf(cfile->type, 40, "CD track %d on %s", (int)mainw->fx1_val, prefs->cdplay_device);
9116 update_play_times();
9117 add_to_clipmenu();
9118 was_new = TRUE;
9119 cfile->opening = cfile->opening_audio = cfile->opening_only_audio = TRUE;
9120 cfile->hsize = DEF_FRAME_HSIZE;
9121 cfile->vsize = DEF_FRAME_VSIZE;
9122 } else {
9123 cfile->undo_arate = cfile->arate;
9124 cfile->undo_achans = cfile->achans;
9125 cfile->undo_asampsize = cfile->asampsize;
9126 cfile->undo_signed_endian = cfile->signed_endian;
9127 cfile->undo_arps = cfile->arps;
9128 }
9129
9130 com = lives_strdup_printf("%s cdopen \"%s\" %d", prefs->backend, cfile->handle, (int)mainw->fx1_val);
9131
9132 lives_rm(cfile->info_file);
9133 lives_system(com, FALSE);
9134 lives_free(com);
9135
9136 if (THREADVAR(com_failed)) {
9137 cfile->arate = cfile->undo_arate;
9138 cfile->achans = cfile->undo_achans;
9139 cfile->asampsize = cfile->undo_asampsize;
9140 cfile->signed_endian = cfile->undo_signed_endian;
9141 cfile->arps = cfile->undo_arps;
9142
9143 sensitize();
9144 reget_afilesize(mainw->current_file);
9145 if (was_new) close_current_file(0);
9146 unbuffer_lmap_errors(FALSE);
9147 return;
9148 }
9149
9150 if (!(do_progress_dialog(TRUE, TRUE, _("Opening CD track...")))) {
9151 lives_widget_queue_draw_and_update(LIVES_MAIN_WINDOW_WIDGET);
9152
9153 if (!was_new) {
9154 mainw->cancelled = CANCEL_NONE;
9155 mainw->error = FALSE;
9156 lives_rm(cfile->info_file);
9157
9158 com = lives_strdup_printf("%s cancel_audio \"%s\"", prefs->backend, cfile->handle);
9159 lives_system(com, FALSE);
9160 lives_free(com);
9161
9162 if (!THREADVAR(com_failed)) do_auto_dialog(_("Cancelling"), 0);
9163
9164 cfile->arate = cfile->undo_arate;
9165 cfile->achans = cfile->undo_achans;
9166 cfile->asampsize = cfile->undo_asampsize;
9167 cfile->signed_endian = cfile->undo_signed_endian;
9168 cfile->arps = cfile->undo_arps;
9169
9170 sensitize();
9171 reget_afilesize(mainw->current_file);
9172 }
9173
9174 if (was_new) close_current_file(0);
9175
9176 if (mainw->error) {
9177 d_print_failed();
9178 }
9179
9180 unbuffer_lmap_errors(FALSE);
9181 return;
9182 }
9183
9184 lives_widget_queue_draw_and_update(LIVES_MAIN_WINDOW_WIDGET);
9185
9186 if (mainw->error) {
9187 d_print(_("Error loading CD track\n"));
9188
9189 lives_widget_queue_draw_and_update(LIVES_MAIN_WINDOW_WIDGET);
9190
9191 if (!was_new) {
9192 com = lives_strdup_printf("%s cancel_audio \"%s\"", prefs->backend, cfile->handle);
9193 mainw->cancelled = CANCEL_NONE;
9194 mainw->error = FALSE;
9195 lives_rm(cfile->info_file);
9196 lives_system(com, FALSE);
9197 lives_free(com);
9198
9199 if (!THREADVAR(com_failed)) do_auto_dialog(_("Cancelling"), 0);
9200
9201 cfile->arate = cfile->undo_arate;
9202 cfile->achans = cfile->undo_achans;
9203 cfile->asampsize = cfile->undo_asampsize;
9204 cfile->signed_endian = cfile->undo_signed_endian;
9205 cfile->arps = cfile->undo_arps;
9206
9207 sensitize();
9208 reget_afilesize(mainw->current_file);
9209 }
9210
9211 if (was_new) close_current_file(0);
9212 unbuffer_lmap_errors(FALSE);
9213 return;
9214 }
9215
9216 array = lives_strsplit(mainw->msg, "|", 5);
9217 cfile->arate = atoi(array[1]);
9218 cfile->achans = atoi(array[2]);
9219 cfile->asampsize = atoi(array[3]);
9220 cfile->afilesize = strtol(array[4], NULL, 10);
9221 lives_strfreev(array);
9222
9223 if (!was_new && cfile->undo_arate > 0) cfile->arps = cfile->undo_arps / cfile->undo_arate * cfile->arate;
9224 else cfile->arps = cfile->arate;
9225
9226 asigned = !(cfile->signed_endian & AFORM_UNSIGNED);
9227 endian = cfile->signed_endian & AFORM_BIG_ENDIAN;
9228
9229 if (cfile->afilesize == 0l) {
9230 d_print(_("Error loading CD track\n"));
9231
9232 if (!was_new) {
9233 com = lives_strdup_printf("%s cancel_audio \"%s\"", prefs->backend, cfile->handle);
9234 mainw->cancelled = CANCEL_NONE;
9235 mainw->error = FALSE;
9236 lives_rm(cfile->info_file);
9237 lives_system(com, FALSE);
9238 lives_free(com);
9239
9240 if (!THREADVAR(com_failed)) do_auto_dialog(_("Cancelling"), 0);
9241
9242 cfile->achans = cfile->undo_achans;
9243 cfile->arate = cfile->undo_arate;
9244 cfile->arps = cfile->undo_arps;
9245 cfile->asampsize = cfile->undo_asampsize;
9246 cfile->signed_endian = cfile->undo_signed_endian;
9247
9248 reget_afilesize(mainw->current_file);
9249 }
9250
9251 if (was_new) close_current_file(0);
9252 unbuffer_lmap_errors(FALSE);
9253 return;
9254 }
9255
9256 cfile->opening = cfile->opening_audio = cfile->opening_only_audio = FALSE;
9257
9258 mainw->cancelled = CANCEL_NONE;
9259 mainw->error = FALSE;
9260 lives_rm(cfile->info_file);
9261
9262 com = lives_strdup_printf("%s commit_audio \"%s\"", prefs->backend, cfile->handle);
9263 lives_system(com, FALSE);
9264 lives_free(com);
9265
9266 if (THREADVAR(com_failed)) {
9267 d_print_failed();
9268 cfile->achans = cfile->undo_achans;
9269 cfile->arate = cfile->undo_arate;
9270 cfile->arps = cfile->undo_arps;
9271 cfile->asampsize = cfile->undo_asampsize;
9272 cfile->signed_endian = cfile->undo_signed_endian;
9273
9274 reget_afilesize(mainw->current_file);
9275
9276 if (was_new) close_current_file(0);
9277 unbuffer_lmap_errors(FALSE);
9278 return;
9279 }
9280
9281 if (!do_auto_dialog(_("Committing audio"), 0)) {
9282 d_print_failed();
9283 unbuffer_lmap_errors(FALSE);
9284 return;
9285 }
9286
9287 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ARATE, &cfile->arps)) bad_header = TRUE;
9288 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_PB_ARATE, &cfile->arate)) bad_header = TRUE;
9289 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ACHANS, &cfile->achans)) bad_header = TRUE;
9290 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ASIGNED, &asigned)) bad_header = TRUE;
9291 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_AENDIAN, &endian)) bad_header = TRUE;
9292 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ASAMPS, &cfile->asampsize)) bad_header = TRUE;
9293
9294 if (bad_header) do_header_write_error(mainw->current_file);
9295
9296 reget_afilesize(mainw->current_file);
9297 cfile->changed = TRUE;
9298 d_print_done();
9299 d_print(P_("New audio: %d Hz %d channel %d bps\n", "New audio: %d Hz %d channels %d bps\n", cfile->achans),
9300 cfile->arate, cfile->achans, cfile->asampsize);
9301
9302 if (!was_new) {
9303 if (!prefs->conserve_space) {
9304 cfile->undo_action = UNDO_NEW_AUDIO;
9305 set_undoable(_("New Audio"), TRUE);
9306 }
9307 }
9308
9309 lives_widget_set_sensitive(mainw->loop_video, TRUE);
9310
9311 lives_notify(LIVES_OSC_NOTIFY_CLIP_OPENED, "");
9312
9313 if (chk_mask != 0) popup_lmap_errors(NULL, LIVES_INT_TO_POINTER(chk_mask));
9314 }
9315
9316
9317 void on_load_vcd_ok_clicked(LiVESButton * button, livespointer user_data) {
9318 boolean needs_idlefunc = mainw->mt_needs_idlefunc;
9319 mainw->mt_needs_idlefunc = FALSE;
9320 lives_general_button_clicked(button, NULL);
9321 mainw->mt_needs_idlefunc = needs_idlefunc;
9322
9323 if (LIVES_POINTER_TO_INT(user_data) == LIVES_DEVICE_DVD) {
9324 lives_snprintf(file_name, PATH_MAX, "dvd://%d", (int)mainw->fx1_val);
9325 lives_freep((void **)&mainw->file_open_params);
9326 if (USE_MPV) mainw->file_open_params = lives_strdup_printf("--chapter=%d --aid=%d", (int)mainw->fx2_val, (int)mainw->fx3_val);
9327 else mainw->file_open_params = lives_strdup_printf("-chapter %d -aid %d", (int)mainw->fx2_val, (int)mainw->fx3_val);
9328 } else {
9329 lives_snprintf(file_name, PATH_MAX, "vcd://%d", (int)mainw->fx1_val);
9330 }
9331 open_sel_range_activate(0, 0.);
9332 }
9333
9334
9335 void popup_lmap_errors(LiVESMenuItem * menuitem, livespointer user_data) {
9336 // popup layout map errors dialog
9337 LiVESWidget *vbox;
9338 LiVESWidget *button;
9339 text_window *textwindow;
9340
9341 uint32_t chk_mask = 0;
9342
9343 unbuffer_lmap_errors(TRUE);
9344
9345 if (!menuitem && user_data) {
9346 if (prefs->warning_mask & WARN_MASK_LAYOUT_POPUP) return;
9347 chk_mask = (uint32_t)LIVES_POINTER_TO_INT(user_data);
9348 if (((chk_mask ^ prefs->warning_mask) & chk_mask) == 0) return;
9349 }
9350
9351 widget_opts.expand = LIVES_EXPAND_EXTRA_WIDTH | LIVES_EXPAND_DEFAULT_HEIGHT;
9352 textwindow = create_text_window(_("Layout Errors"), NULL, mainw->layout_textbuffer, FALSE);
9353 widget_opts.expand = LIVES_EXPAND_DEFAULT;
9354
9355 vbox = lives_dialog_get_content_area(LIVES_DIALOG(textwindow->dialog));
9356
9357 add_warn_check(LIVES_BOX(vbox), WARN_MASK_LAYOUT_POPUP);
9358
9359 button = lives_dialog_add_button_from_stock(LIVES_DIALOG(textwindow->dialog), LIVES_STOCK_CLOSE, _("_Close Window"),
9360 LIVES_RESPONSE_OK);
9361
9362 lives_signal_sync_connect(LIVES_GUI_OBJECT(button), LIVES_WIDGET_CLICKED_SIGNAL,
9363 LIVES_GUI_CALLBACK(lives_general_button_clicked),
9364 textwindow);
9365
9366 lives_container_set_border_width(LIVES_CONTAINER(button), widget_opts.border_width);
9367
9368 textwindow->clear_button = lives_dialog_add_button_from_stock(LIVES_DIALOG(textwindow->dialog), LIVES_STOCK_CLEAR,
9369 _("Clear _Errors"),
9370 LIVES_RESPONSE_CANCEL);
9371
9372 lives_signal_sync_connect(LIVES_GUI_OBJECT(textwindow->clear_button), LIVES_WIDGET_CLICKED_SIGNAL,
9373 LIVES_GUI_CALLBACK(on_lerrors_clear_clicked),
9374 LIVES_INT_TO_POINTER(FALSE));
9375
9376 lives_container_set_border_width(LIVES_CONTAINER(textwindow->clear_button), widget_opts.border_width);
9377
9378 textwindow->delete_button = lives_dialog_add_button_from_stock(LIVES_DIALOG(textwindow->dialog), LIVES_STOCK_DELETE,
9379 _("_Delete affected layouts"), LIVES_RESPONSE_CANCEL);
9380
9381 lives_button_box_set_layout(LIVES_BUTTON_BOX(lives_widget_get_parent(textwindow->delete_button)), LIVES_BUTTONBOX_SPREAD);
9382
9383 lives_container_set_border_width(LIVES_CONTAINER(textwindow->delete_button), widget_opts.border_width);
9384
9385 lives_signal_sync_connect(LIVES_GUI_OBJECT(textwindow->delete_button), LIVES_WIDGET_CLICKED_SIGNAL,
9386 LIVES_GUI_CALLBACK(on_lerrors_delete_clicked), NULL);
9387
9388 lives_widget_show_all(textwindow->dialog);
9389 }
9390
9391
9392 void on_rename_activate(LiVESMenuItem * menuitem, livespointer user_data) {
9393 renamew = create_rename_dialog(1);
9394 lives_widget_show_all(renamew->dialog);
9395 }
9396
9397
9398 void autolives_toggle(LiVESMenuItem * menuitem, livespointer user_data) {
9399 // TODO: allow mapping of change types to random ranges in the backend
9400 // TODO: allow user selection of all ports
9401 #ifdef ENABLE_OSC
9402 autolives_window *alwindow = NULL;
9403 int trigtime;
9404 char *apb;
9405 char *mute;
9406 char *trigopt;
9407 char *debug;
9408 char string[PATH_MAX];
9409 char *com = NULL;
9410 boolean cancelled = FALSE;
9411
9412 if (mainw->alives_pgid > 0) {
9413 // already running, kill the old process
9414 lives_killpg(mainw->alives_pgid, LIVES_SIGHUP);
9415 mainw->alives_pgid = 0;
9416
9417 // restore pre-playback rte state
9418 rte_keymodes_restore(prefs->rte_keys_virtual);
9419 goto autolives_fail;
9420 }
9421
9422 if (!lives_check_menu_item_get_active(LIVES_CHECK_MENU_ITEM(mainw->autolives))) return;
9423
9424 if (!CURRENT_CLIP_IS_VALID) {
9425 do_autolives_needs_clips_error();
9426 goto autolives_fail;
9427 }
9428
9429 if (cfile->event_list || cfile->opening || mainw->multitrack || mainw->is_processing || mainw->preview) {
9430 // ignore if doing something more important
9431 goto autolives_fail;
9432 }
9433
9434 // search for autolives.pl
9435 if (!capable->has_autolives) {
9436 get_location(EXEC_AUTOLIVES_PL, string, PATH_MAX);
9437 if (strlen(string)) capable->has_autolives = TRUE;
9438 else {
9439 do_no_autolives_error();
9440 goto autolives_fail;
9441 }
9442 }
9443
9444 alwindow = autolives_pre_dialog();
9445 if (!alwindow) {
9446 goto autolives_fail;
9447 }
9448 if (lives_dialog_run(LIVES_DIALOG(alwindow->dialog)) == LIVES_RESPONSE_CANCEL) {
9449 // user cancelled
9450 cancelled = TRUE;
9451 goto autolives_fail;
9452 }
9453
9454 // check if osc is started; if not ask permission
9455 if (!prefs->osc_udp_started) {
9456 char typep[32];
9457 char *inst = (char *)typep;
9458 lives_snprintf(typep, 32, "%d", LIVES_PERM_OSC_PORTS);
9459 if (!lives_ask_permission((char **)&inst, 1, 0)) {
9460 // permission not given
9461 goto autolives_fail;
9462 }
9463
9464 // try: start up osc
9465 prefs->osc_udp_started = lives_osc_init(prefs->osc_udp_port);
9466 if (!prefs->osc_udp_started) {
9467 goto autolives_fail;
9468 }
9469 }
9470
9471 // build the command to run
9472 trigtime = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(alwindow->atrigger_spin));
9473 if (!lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(alwindow->apb_button))) apb = lives_strdup(" -waitforplay");
9474 else apb = lives_strdup("");
9475 if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(alwindow->mute_button))) mute = lives_strdup(" -mute");
9476 else mute = lives_strdup("");
9477 if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(alwindow->atrigger_button))) {
9478 // timed
9479 trigopt = lives_strdup_printf(" -time %d", trigtime);
9480 } else {
9481 // omc
9482 trigopt = lives_strdup_printf(" -omc %d", prefs->osc_udp_port - 2);
9483 }
9484 if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(alwindow->debug_button))) {
9485 debug = lives_strdup(" -debug");
9486 } else {
9487 debug = lives_strdup("");
9488 }
9489 lives_widget_destroy(alwindow->dialog);
9490 lives_free(alwindow);
9491
9492 // store the current key/mode state
9493 rte_keymodes_backup(prefs->rte_keys_virtual);
9494
9495 com = lives_strdup_printf("/usr/bin/%s localhost %d %d%s%s%s%s", EXEC_AUTOLIVES_PL, prefs->osc_udp_port,
9496 prefs->osc_udp_port - 1, apb,
9497 trigopt, mute,
9498 debug);
9499
9500 mainw->alives_pgid = lives_fork(com);
9501
9502 lives_free(debug);
9503 lives_free(trigopt);
9504 lives_free(apb);
9505 lives_free(mute);
9506 if (com) lives_free(com);
9507 return;
9508
9509 autolives_fail:
9510 if (alwindow) {
9511 if (!cancelled) lives_widget_destroy(alwindow->dialog);
9512 lives_free(alwindow);
9513 }
9514
9515 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->autolives), FALSE);
9516
9517 #endif
9518 }
9519
9520
9521 void on_rename_clip_name(LiVESButton * button, livespointer user_data) {
9522 char title[256];
9523 boolean bad_header = FALSE;
9524
9525 if (!user_data) {
9526 lives_snprintf(title, 256, "%s", lives_entry_get_text(LIVES_ENTRY(renamew->entry)));
9527 lives_widget_destroy(renamew->dialog);
9528 lives_free(renamew);
9529 } else lives_snprintf(title, 256, "%s", (char *)user_data);
9530
9531 if (!(strlen(title))) return;
9532
9533 if (!user_data) {
9534 set_main_title(title, 0);
9535 }
9536
9537 if (CURRENT_CLIP_IS_VALID) {
9538 lives_menu_item_set_text(cfile->menuentry, title, FALSE);
9539
9540 lives_snprintf(cfile->name, 256, "%s", title);
9541
9542 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_CLIPNAME, cfile->name)) bad_header = TRUE;
9543
9544 if (bad_header) do_header_write_error(mainw->current_file);
9545 cfile->was_renamed = TRUE;
9546 }
9547 }
9548
9549
9550 void on_toy_activate(LiVESMenuItem * menuitem, livespointer user_data) {
9551 if (menuitem && mainw->toy_type == LIVES_POINTER_TO_INT(user_data)) {
9552 // switch is off
9553 user_data = LIVES_INT_TO_POINTER(LIVES_TOY_NONE);
9554 }
9555
9556 switch (mainw->toy_type) {
9557 // old status
9558 case LIVES_TOY_MAD_FRAMES:
9559 lives_signal_handler_block(mainw->toy_random_frames, mainw->toy_func_random_frames);
9560 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->toy_random_frames), FALSE);
9561 lives_signal_handler_unblock(mainw->toy_random_frames, mainw->toy_func_random_frames);
9562 if (LIVES_IS_PLAYING) {
9563 if (mainw->faded) {
9564 lives_widget_hide(mainw->start_image);
9565 lives_widget_hide(mainw->end_image);
9566 }
9567 if (CURRENT_CLIP_IS_VALID) {
9568 showclipimgs();
9569 }
9570 }
9571 break;
9572 case LIVES_TOY_TV:
9573 lives_signal_handler_block(mainw->toy_tv, mainw->toy_func_lives_tv);
9574 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->toy_tv), FALSE);
9575 lives_signal_handler_unblock(mainw->toy_tv, mainw->toy_func_lives_tv);
9576 break;
9577 default:
9578 lives_signal_handler_block(mainw->toy_none, mainw->toy_func_none);
9579 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->toy_none), FALSE);
9580 lives_signal_handler_unblock(mainw->toy_none, mainw->toy_func_none);
9581 break;
9582 }
9583
9584 mainw->toy_type = (lives_toy_t)LIVES_POINTER_TO_INT(user_data);
9585
9586 switch (mainw->toy_type) {
9587 case LIVES_TOY_NONE:
9588 lives_signal_handler_block(mainw->toy_none, mainw->toy_func_none);
9589 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->toy_none), TRUE);
9590 lives_signal_handler_unblock(mainw->toy_none, mainw->toy_func_none);
9591 return;
9592 case LIVES_TOY_MAD_FRAMES:
9593 break;
9594 case LIVES_TOY_TV:
9595 // load in the lives TV clip
9596 deduce_file(LIVES_TV_CHANNEL1, 0., 0);
9597
9598 // if we choose to discard it, discard it....otherwise keep it
9599 if (prefs->discard_tv) {
9600 close_current_file(0);
9601 } else {
9602 // keep it
9603 int current_file = mainw->current_file;
9604 char *com = lives_strdup_printf("%s commit_audio \"%s\"", prefs->backend, cfile->handle);
9605 cfile->start = 1;
9606 cfile->frames = get_frame_count(mainw->current_file, 1);
9607 cfile->end = cfile->frames;
9608 cfile->opening = cfile->opening_loc = cfile->opening_audio = cfile->opening_only_audio = FALSE;
9609 cfile->is_loaded = TRUE;
9610 lives_system(com, FALSE);
9611 save_clip_values(current_file);
9612 if (prefs->crash_recovery) add_to_recovery_file(cfile->handle);
9613 if (!mainw->multitrack) {
9614 switch_to_file((mainw->current_file = 0), current_file);
9615 sensitize();
9616 }
9617 }
9618 break;
9619 default:
9620 if (mainw->faded && !mainw->foreign) {
9621 lives_widget_show(mainw->start_image);
9622 lives_widget_show(mainw->end_image);
9623 }
9624 }
9625 }
9626
9627
9628 void on_preview_spinbutton_changed(LiVESSpinButton * spinbutton, livespointer user_data) {
9629 // update the play window preview
9630 int preview_frame;
9631 static volatile boolean updated = FALSE;
9632
9633 if (updated) return;
9634
9635 if (CURRENT_CLIP_IS_CLIPBOARD || !CURRENT_CLIP_IS_VALID) {
9636 return;
9637 }
9638 if ((preview_frame = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton))) == mainw->preview_frame) {
9639 return;
9640 }
9641 // prevent multiple updates from interfering
9642 updated = TRUE;
9643 lives_signal_handler_block(mainw->preview_spinbutton, mainw->preview_spin_func);
9644 //lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
9645 mainw->preview_frame = preview_frame;
9646 load_preview_image(TRUE);
9647 lives_signal_handler_unblock(mainw->preview_spinbutton, mainw->preview_spin_func);
9648 updated = FALSE;
9649 }
9650
9651
9652 void on_prv_link_toggled(LiVESToggleButton * togglebutton, livespointer user_data) {
9653 if (!lives_toggle_button_get_active(togglebutton)) return;
9654 mainw->prv_link = LIVES_POINTER_TO_INT(user_data);
9655 if (mainw->is_processing && (mainw->prv_link == PRV_START || mainw->prv_link == PRV_END)) {
9656 // block spinbutton in play window
9657 lives_widget_set_sensitive(mainw->preview_spinbutton, FALSE);
9658 } else {
9659 lives_widget_set_sensitive(mainw->preview_spinbutton, TRUE);
9660 }
9661 load_preview_image(FALSE);
9662 lives_widget_grab_focus(mainw->preview_spinbutton);
9663 }
9664
9665
9666 void update_sel_menu(void) {
9667 if (mainw->multitrack || mainw->selwidth_locked) return;
9668
9669 if (!CURRENT_CLIP_HAS_VIDEO || LIVES_IS_PLAYING || CURRENT_CLIP_IS_CLIPBOARD || mainw->is_processing) {
9670 lives_widget_set_sensitive(mainw->select_invert, FALSE);
9671 lives_widget_set_sensitive(mainw->select_all, FALSE);
9672 lives_widget_set_sensitive(mainw->sa_button, FALSE);
9673 lives_widget_set_sensitive(mainw->select_start_only, FALSE);
9674 lives_widget_set_sensitive(mainw->select_end_only, FALSE);
9675 lives_widget_set_sensitive(mainw->select_from_start, FALSE);
9676 lives_widget_set_sensitive(mainw->select_to_end, FALSE);
9677 lives_widget_set_sensitive(mainw->select_to_aend, FALSE);
9678 return;
9679 }
9680
9681 lives_widget_set_sensitive(mainw->select_new, cfile->insert_start > 0);
9682 lives_widget_set_sensitive(mainw->select_last, cfile->undo_start > 0);
9683
9684 if (cfile->end > cfile->start) {
9685 lives_widget_set_sensitive(mainw->select_start_only, TRUE);
9686 lives_widget_set_sensitive(mainw->select_end_only, TRUE);
9687 } else {
9688 lives_widget_set_sensitive(mainw->select_start_only, FALSE);
9689 lives_widget_set_sensitive(mainw->select_end_only, FALSE);
9690 }
9691 if (cfile->start == 1 && cfile->end == cfile->frames) {
9692 lives_widget_set_sensitive(mainw->select_invert, FALSE);
9693 lives_widget_set_sensitive(mainw->select_all, FALSE);
9694 lives_widget_set_sensitive(mainw->sa_button, FALSE);
9695 } else {
9696 if (cfile->start == 1 || cfile->end == cfile->frames)
9697 lives_widget_set_sensitive(mainw->select_invert, TRUE);
9698 else
9699 lives_widget_set_sensitive(mainw->select_invert, FALSE);
9700
9701 lives_widget_set_sensitive(mainw->select_all, TRUE);
9702 lives_widget_set_sensitive(mainw->sa_button, TRUE);
9703 }
9704
9705 if (cfile->start == 1) lives_widget_set_sensitive(mainw->select_from_start, FALSE);
9706 else lives_widget_set_sensitive(mainw->select_from_start, TRUE);
9707
9708 if (cfile->end < cfile->frames) {
9709 lives_widget_set_sensitive(mainw->select_to_end, TRUE);
9710 } else {
9711 lives_widget_set_sensitive(mainw->select_to_end, FALSE);
9712 lives_widget_set_sensitive(mainw->select_to_aend, FALSE);
9713 }
9714 if (cfile->achans > 0) {
9715 int audframe = calc_frame_from_time4(mainw->current_file, cfile->laudio_time);
9716 if (audframe <= cfile->frames && audframe >= cfile->start && audframe != cfile->end)
9717 lives_widget_set_sensitive(mainw->select_to_aend, TRUE);
9718 else lives_widget_set_sensitive(mainw->select_to_aend, FALSE);
9719 } else lives_widget_set_sensitive(mainw->select_to_aend, FALSE);
9720 }
9721
9722
9723 void on_spinbutton_start_value_changed(LiVESSpinButton * spinbutton, livespointer user_data) {
9724 int start, ostart;
9725 boolean rdrw_bars = TRUE;
9726 static volatile boolean updated = FALSE;
9727
9728 if (updated) return;
9729
9730 if (CURRENT_CLIP_IS_CLIPBOARD || !CURRENT_CLIP_IS_VALID) {
9731 return;
9732 }
9733 if ((start = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton))) == cfile->start) {
9734 return;
9735 }
9736
9737 // prevent multiple updates from interfering
9738 updated = TRUE;
9739 lives_signal_handler_block(mainw->spinbutton_start, mainw->spin_start_func);
9740 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
9741
9742 ostart = cfile->start;
9743 cfile->start = start;
9744
9745 if (mainw->selwidth_locked) {
9746 /// must not update cfile->end directly, otherwise the selection colour won'r be updates
9747 int new_end = cfile->end + cfile->start - ostart;
9748 mainw->selwidth_locked = FALSE;
9749 if (new_end > cfile->frames) {
9750 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->start - cfile->end + cfile->frames);
9751 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->frames);
9752 lives_spin_button_update(LIVES_SPIN_BUTTON(mainw->spinbutton_end));
9753 } else {
9754 if (cfile->start < ostart && cfile->fps > 0.) {
9755 redraw_timer_bars((double)(cfile->start - 1.) / cfile->fps, (double)ostart / cfile->fps, 0);
9756 rdrw_bars = FALSE;
9757 }
9758 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), new_end);
9759 lives_spin_button_update(LIVES_SPIN_BUTTON(mainw->spinbutton_end));
9760 }
9761 mainw->selwidth_locked = TRUE;
9762 }
9763 update_sel_menu();
9764
9765 if (!LIVES_IS_PLAYING && mainw->play_window && cfile->is_loaded) {
9766 /// load this first in case of caching - it is likely to be larger and higher quality
9767 if (mainw->prv_link == PRV_START && mainw->preview_frame != cfile->start)
9768 load_preview_image(FALSE);
9769 }
9770
9771 if (!LIVES_IS_PLAYING) load_start_image(cfile->start);
9772
9773 if (cfile->start > cfile->end) {
9774 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->start);
9775 }
9776 set_sel_label(mainw->sel_label);
9777 if (rdrw_bars && cfile->fps > 0.) {
9778 if (cfile->start < ostart)
9779 redraw_timer_bars((double)(cfile->start - 1.) / cfile->fps, (double)ostart / cfile->fps, 0);
9780 else
9781 redraw_timer_bars((double)(ostart - 1.) / cfile->fps, (double)cfile->start / cfile->fps, 0);
9782 }
9783
9784 lives_signal_handler_unblock(mainw->spinbutton_start, mainw->spin_start_func);
9785 updated = FALSE;
9786 }
9787
9788
9789 void on_spinbutton_end_value_changed(LiVESSpinButton * spinbutton, livespointer user_data) {
9790 int end, oend;
9791 boolean rdrw_bars = TRUE;
9792 static volatile boolean updated = FALSE;
9793
9794 if (updated) return;
9795
9796 if (CURRENT_CLIP_IS_CLIPBOARD || !CURRENT_CLIP_IS_VALID) {
9797 return;
9798 }
9799 if ((end = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton))) == cfile->end) {
9800 return;
9801 }
9802
9803 // prevent multiple updates from interfering
9804 updated = TRUE;
9805
9806 lives_signal_handler_block(mainw->spinbutton_end, mainw->spin_end_func);
9807 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
9808
9809 oend = cfile->end;
9810 cfile->end = end;
9811
9812 if (mainw->selwidth_locked) {
9813 int new_start = cfile->start + cfile->end - oend;
9814 mainw->selwidth_locked = FALSE;
9815 if (new_start < 1) {
9816 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->end - cfile->start + 1);
9817 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), 1);
9818 lives_spin_button_update(LIVES_SPIN_BUTTON(mainw->spinbutton_start));
9819 } else {
9820 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), new_start);
9821 if (cfile->end > oend && cfile->fps > 0.) {
9822 redraw_timer_bars((double)oend / cfile->fps, (double)(cfile->end + 1) / cfile->fps, 0);
9823 rdrw_bars = FALSE;
9824 }
9825 lives_spin_button_update(LIVES_SPIN_BUTTON(mainw->spinbutton_start));
9826 }
9827 mainw->selwidth_locked = TRUE;
9828 }
9829 update_sel_menu();
9830
9831 if (!LIVES_IS_PLAYING && mainw->play_window && cfile->is_loaded) {
9832 /// load this first in case of caching - it is likely to be larger and higher quality
9833 if (mainw->prv_link == PRV_END && mainw->preview_frame != cfile->end)
9834 load_preview_image(FALSE);
9835 }
9836
9837 if (!LIVES_IS_PLAYING) load_end_image(cfile->end);
9838
9839 if (cfile->end < cfile->start) {
9840 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), cfile->end);
9841 }
9842
9843 set_sel_label(mainw->sel_label);
9844 if (rdrw_bars && cfile->fps > 0.) {
9845 if (cfile->end > oend)
9846 redraw_timer_bars((double)oend / cfile->fps, (double)(cfile->end + 1) / cfile->fps, 0);
9847 else
9848 redraw_timer_bars((double)cfile->end / cfile->fps, (double)(oend + 1) / cfile->fps, 0);
9849 }
9850
9851 lives_signal_handler_unblock(mainw->spinbutton_end, mainw->spin_end_func);
9852 updated = FALSE;
9853 }
9854
9855
9856 boolean all_expose(LiVESWidget * widget, lives_painter_t *cr, livespointer psurf) {
9857 lives_painter_surface_t **surf = (lives_painter_surface_t **)psurf;
9858 if (surf) {
9859 if (*surf) {
9860 lives_painter_set_source_surface(cr, *surf, 0., 0.);
9861 lives_painter_paint(cr);
9862 } else {
9863 return TRUE;
9864 }
9865 }
9866 return TRUE;
9867 }
9868
9869
9870 boolean all_expose_overlay(LiVESWidget * widget, lives_painter_t *creb, livespointer psurf) {
9871 /// quick and dirty copy / paste
9872 if (mainw->go_away) return FALSE;
9873 if (LIVES_IS_PLAYING && mainw->faded) return FALSE;
9874 if (!CURRENT_CLIP_IS_VALID) return FALSE;
9875 else {
9876 int bar_height;
9877 int allocy;
9878 double allocwidth = (double)lives_widget_get_allocation_width(mainw->video_draw), allocheight;
9879 double offset;
9880 double ptrtime = mainw->ptrtime;
9881 frames_t frame;
9882 int which = 0;
9883
9884 offset = ptrtime / CURRENT_CLIP_TOTAL_TIME * allocwidth;
9885
9886 lives_painter_set_line_width(creb, 1.);
9887
9888 if (palette->style & STYLE_LIGHT) {
9889 lives_painter_set_source_rgb_from_lives_widget_color(creb, &palette->black);
9890 } else {
9891 lives_painter_set_source_rgb_from_lives_widget_color(creb, &palette->white);
9892 }
9893
9894 if (!(frame = calc_frame_from_time(mainw->current_file, ptrtime)))
9895 frame = cfile->frames;
9896
9897 if (cfile->frames > 0 && (which == 0 || which == 1)) {
9898 if (mainw->video_drawable) {
9899 bar_height = CE_VIDBAR_HEIGHT;
9900
9901 allocheight = (double)lives_widget_get_allocation_height(mainw->vidbar) + bar_height + widget_opts.packing_height * 2.5;
9902 allocy = lives_widget_get_allocation_y(mainw->vidbar) - widget_opts.packing_height;
9903 lives_painter_move_to(creb, offset, allocy);
9904 lives_painter_line_to(creb, offset, allocy + allocheight);
9905 lives_painter_stroke(creb);
9906 }
9907 }
9908
9909 if (LIVES_IS_PLAYING) {
9910 if (which == 0) lives_ruler_set_value(LIVES_RULER(mainw->hruler), ptrtime);
9911 if (cfile->achans > 0 && cfile->is_loaded && prefs->audio_src != AUDIO_SRC_EXT) {
9912 if (is_realtime_aplayer(prefs->audio_player) && (!mainw->event_list || !mainw->preview)) {
9913 #ifdef ENABLE_JACK
9914 if (mainw->jackd && prefs->audio_player == AUD_PLAYER_JACK) {
9915 offset = allocwidth * ((double)mainw->jackd->seek_pos / cfile->arate / cfile->achans /
9916 cfile->asampsize * 8) / CURRENT_CLIP_TOTAL_TIME;
9917 }
9918 #endif
9919 #ifdef HAVE_PULSE_AUDIO
9920 if (mainw->pulsed && prefs->audio_player == AUD_PLAYER_PULSE) {
9921 offset = allocwidth * ((double)mainw->pulsed->seek_pos / cfile->arate / cfile->achans /
9922 cfile->asampsize * 8) / CURRENT_CLIP_TOTAL_TIME;
9923 }
9924 #endif
9925 } else offset = allocwidth * (mainw->aframeno - .5) / cfile->fps / CURRENT_CLIP_TOTAL_TIME;
9926 }
9927 } else {
9928 offset = cfile->real_pointer_time / CURRENT_CLIP_TOTAL_TIME * allocwidth;
9929 }
9930
9931 if (cfile->achans > 0) {
9932 bar_height = CE_AUDBAR_HEIGHT;
9933 if (mainw->laudio_drawable && (which == 0 || which == 2)) {
9934 allocheight = (double)lives_widget_get_allocation_height(mainw->laudbar) + bar_height
9935 + widget_opts.packing_height * 2.5;
9936 allocy = lives_widget_get_allocation_y(mainw->laudbar) - widget_opts.packing_height;
9937 lives_painter_move_to(creb, offset, allocy);
9938 lives_painter_line_to(creb, offset, allocy + allocheight);
9939 }
9940
9941 if (cfile->achans > 1 && (which == 0 || which == 3)) {
9942 if (mainw->raudio_drawable) {
9943 allocheight = (double)lives_widget_get_allocation_height(mainw->raudbar)
9944 + bar_height + widget_opts.packing_height * 2.5;
9945 allocy = lives_widget_get_allocation_y(mainw->raudbar) - widget_opts.packing_height;
9946 lives_painter_move_to(creb, offset, allocy);
9947 lives_painter_line_to(creb, offset, allocy + allocheight);
9948 }
9949 }
9950 }
9951
9952 lives_painter_stroke(creb);
9953 return TRUE;
9954 }
9955 }
9956
9957
9958 boolean all_expose_pb(LiVESWidget * widget, lives_painter_t *cr, livespointer psurf) {
9959 if (LIVES_IS_PLAYING) all_expose(widget, cr, psurf);
9960 return TRUE;
9961 }
9962
9963 boolean all_expose_nopb(LiVESWidget * widget, lives_painter_t *cr, livespointer psurf) {
9964 if (!LIVES_IS_PLAYING) all_expose(widget, cr, psurf);
9965 return TRUE;
9966 }
9967
9968 boolean expose_vid_draw(LiVESWidget * widget, lives_painter_t *cr, livespointer psurf) {
9969 if (mainw->video_drawable) {
9970 lives_painter_set_source_surface(cr, mainw->video_drawable, 0., 0.);
9971 lives_painter_paint(cr);
9972 }
9973 return TRUE;
9974 }
9975
9976 boolean config_vid_draw(LiVESWidget * widget, LiVESXEventConfigure * event, livespointer user_data) {
9977 if (mainw->video_drawable) lives_painter_surface_destroy(mainw->video_drawable);
9978 mainw->video_drawable = lives_widget_create_painter_surface(widget);
9979 clear_widget_bg(widget, mainw->video_drawable);
9980 update_timer_bars(0, 0, 0, 0, 1);
9981 return TRUE;
9982 }
9983
9984 boolean expose_laud_draw(LiVESWidget * widget, lives_painter_t *cr, livespointer psurf) {
9985 if (mainw->laudio_drawable) {
9986 lives_painter_set_source_surface(cr, mainw->laudio_drawable, 0., 0.);
9987 lives_painter_paint(cr);
9988 }
9989 return TRUE;
9990 }
9991
9992 boolean config_laud_draw(LiVESWidget * widget, LiVESXEventConfigure * event, livespointer user_data) {
9993 if (IS_VALID_CLIP(mainw->drawsrc)) {
9994 lives_painter_surface_t *surf = lives_widget_create_painter_surface(widget);
9995 lives_painter_surface_t *laudio_drawable;
9996
9997 clear_widget_bg(widget, surf);
9998 laudio_drawable = mainw->laudio_drawable;
9999 mainw->laudio_drawable = surf;
10000
10001 if (laudio_drawable) {
10002 lives_painter_surface_destroy(laudio_drawable);
10003 }
10004 mainw->files[mainw->drawsrc]->laudio_drawable = mainw->laudio_drawable;
10005 }
10006 return TRUE;
10007 }
10008
10009
10010 boolean expose_raud_draw(LiVESWidget * widget, lives_painter_t *cr, livespointer psurf) {
10011 if (mainw->raudio_drawable) {
10012 lives_painter_set_source_surface(cr, mainw->raudio_drawable, 0., 0.);
10013 lives_painter_paint(cr);
10014 }
10015 return TRUE;
10016 }
10017
10018 boolean config_raud_draw(LiVESWidget * widget, LiVESXEventConfigure * event, livespointer user_data) {
10019 if (IS_VALID_CLIP(mainw->drawsrc)) {
10020 lives_painter_surface_t *surf = lives_widget_create_painter_surface(widget);
10021 lives_painter_surface_t *raudio_drawable;
10022
10023 clear_widget_bg(widget, surf);
10024 raudio_drawable = mainw->raudio_drawable;
10025 mainw->raudio_drawable = surf;
10026
10027 if (raudio_drawable) {
10028 lives_painter_surface_destroy(raudio_drawable);
10029 }
10030 mainw->files[mainw->drawsrc]->raudio_drawable = mainw->raudio_drawable;
10031 }
10032 return TRUE;
10033 }
10034
10035 boolean config_event2(LiVESWidget * widget, LiVESXEventConfigure * event, livespointer user_data) {
10036 mainw->msg_area_configed = TRUE;
10037 return TRUE;
10038 }
10039
10040
10041 /// genric func. to create surfaces
10042 boolean all_config(LiVESWidget * widget, LiVESXEventConfigure * event, livespointer ppsurf) {
10043 lives_painter_surface_t **psurf = (lives_painter_surface_t **)ppsurf;
10044 if (mainw->no_configs) return TRUE;
10045
10046 if (!psurf) return FALSE;
10047 if (*psurf) lives_painter_surface_destroy(*psurf);
10048 *psurf = lives_widget_create_painter_surface(widget);
10049
10050 #ifdef USE_SPECIAL_BUTTONS
10051 if (LIVES_IS_DRAWING_AREA(widget)) {
10052 LiVESWidget *parent = lives_widget_get_parent(widget);
10053 if (parent && LIVES_IS_BUTTON(parent) && is_standard_widget(parent)) {
10054 sbutt_render(parent, 0, NULL);
10055 return FALSE;
10056 }
10057 }
10058 #endif
10059
10060 clear_widget_bg(widget, *psurf);
10061
10062 if (widget == mainw->start_image)
10063 load_start_image(CURRENT_CLIP_IS_VALID ? cfile->start : 0);
10064 else if (widget == mainw->end_image)
10065 load_end_image(CURRENT_CLIP_IS_VALID ? cfile->end : 0);
10066 else if (widget == mainw->preview_image)
10067 load_preview_image(FALSE);
10068 else if (widget == mainw->msg_area && !mainw->multitrack)
10069 msg_area_config(widget);
10070 else if (widget == mainw->dsu_widget)
10071 draw_dsu_widget(widget);
10072 else if (mainw->multitrack) {
10073 if (widget == mainw->multitrack->timeline_reg)
10074 draw_region(mainw->multitrack);
10075 else if (widget == mainw->multitrack->in_image || widget == mainw->multitrack->out_image) {
10076 show_in_out_images(mainw->multitrack);
10077 } else if (widget == mainw->play_image) {
10078 lives_idle_add_simple(mt_idle_show_current_frame, (livespointer)mainw->multitrack);
10079 //lives_widget_queue_draw(mainw->multitrack->preview_frame);
10080 //set_mt_play_sizes_cfg(mainw->multitrack);
10081 //mt_show_current_frame(mainw->multitrack, FALSE);
10082 } else if (widget == mainw->multitrack->msg_area) {
10083 msg_area_config(widget);
10084 }
10085 }
10086 return FALSE;
10087 }
10088
10089
10090 boolean config_event(LiVESWidget * widget, LiVESXEventConfigure * event, livespointer user_data) {
10091 if (!mainw->configured) {
10092 mainw->configured = TRUE;
10093 return FALSE;
10094 }
10095 if (widget == LIVES_MAIN_WINDOW_WIDGET) {
10096 int scr_width, scr_height;
10097 scr_width = GUI_SCREEN_PHYS_WIDTH;
10098 scr_height = GUI_SCREEN_PHYS_HEIGHT;
10099 if (event->width != scr_width || event->height != scr_height) {
10100 get_monitors(FALSE);
10101 if (scr_width != GUI_SCREEN_PHYS_WIDTH || scr_height != GUI_SCREEN_PHYS_HEIGHT) {
10102 if (!mainw->ignore_screen_size) {
10103 if (prefs->show_dev_opts) {
10104 g_printerr("VALLS %d %d %d %d %d %d\n", event->width, event->height, scr_width, scr_height,
10105 GUI_SCREEN_PHYS_WIDTH, GUI_SCREEN_PHYS_HEIGHT);
10106 }
10107 resize_widgets_for_monitor(FALSE);
10108 if (!CURRENT_CLIP_IS_VALID) {
10109 lives_ce_update_timeline(0, 0.);
10110 // *INDENT-OFF*
10111 }}}
10112 else mainw->ignore_screen_size = FALSE;
10113 }}
10114 // *INDENT-ON*
10115
10116 return FALSE;
10117 }
10118
10119
10120 // these two really belong with the processing widget
10121
10122 void on_effects_paused(LiVESButton * button, livespointer user_data) {
10123 char *com = NULL;
10124 const char *stockim;
10125 ticks_t xticks;
10126
10127 if (mainw->iochan || cfile->opening) {
10128 // pause during encoding (if we start using mainw->iochan for other things, this will
10129 // need changing...)
10130 if (!mainw->effects_paused) {
10131 lives_suspend_resume_process(cfile->handle, TRUE);
10132
10133 if (!cfile->opening) {
10134 lives_button_set_label(LIVES_BUTTON(button), _("Resume"));
10135 lives_label_set_text(LIVES_LABEL(mainw->proc_ptr->label2), _("\nPaused\n(click Resume to continue processing)"));
10136 d_print(_("paused..."));
10137 }
10138 } else {
10139 lives_suspend_resume_process(cfile->handle, FALSE);
10140
10141 if (!cfile->opening) {
10142 lives_button_set_label(LIVES_BUTTON(button), _("Paus_e"));
10143 lives_label_set_text(LIVES_LABEL(mainw->proc_ptr->label2), _("\nPlease Wait"));
10144 d_print(_("resumed..."));
10145 }
10146 }
10147 }
10148
10149 if (!mainw->iochan) {
10150 // pause during effects processing or opening
10151 xticks = lives_get_relative_ticks(mainw->origsecs, mainw->orignsecs);
10152 if (!mainw->effects_paused) {
10153 mainw->timeout_ticks -= xticks;
10154 com = lives_strdup_printf("%s pause \"%s\"", prefs->backend_sync, cfile->handle);
10155 if (!mainw->preview) {
10156 lives_button_set_label(LIVES_BUTTON(button), _("Resume"));
10157 if (!cfile->nokeep) {
10158 char *tmp, *ltext;
10159
10160 if (!cfile->opening) {
10161 ltext = (_("Keep"));
10162 } else {
10163 ltext = (_("Enough"));
10164 }
10165 stockim = LIVES_STOCK_KEEP;
10166 lives_button_set_image_from_stock(LIVES_BUTTON(mainw->proc_ptr->cancel_button), stockim);
10167 lives_button_set_label(LIVES_BUTTON(mainw->proc_ptr->cancel_button), ltext);
10168 lives_label_set_text(LIVES_LABEL(mainw->proc_ptr->label2),
10169 (tmp = lives_strdup_printf
10170 (_("\nPaused\n(click %s to keep what you have and stop)\n(click "
10171 "Resume to continue processing)"), ltext)));
10172 lives_free(tmp);
10173 lives_free(ltext);
10174 }
10175 if ((!mainw->multitrack && mainw->is_rendering && prefs->render_audio) || (mainw->multitrack &&
10176 mainw->multitrack->opts.render_audp)) {
10177 // render audio up to current tc
10178 mainw->flush_audio_tc = q_gint64((double)cfile->undo_end / cfile->fps * TICKS_PER_SECOND_DBL, cfile->fps);
10179 render_events_cb(FALSE);
10180 mainw->flush_audio_tc = 0;
10181 cfile->afilesize = reget_afilesize_inner(mainw->current_file);
10182 cfile->laudio_time = (double)(cfile->afilesize / (cfile->asampsize >> 3) / cfile->achans) / (double)cfile->arate;
10183 if (cfile->achans > 1) {
10184 cfile->raudio_time = cfile->laudio_time;
10185 }
10186 }
10187 d_print(_("paused..."));
10188 }
10189 #ifdef ENABLE_JACK
10190 if (mainw->jackd && mainw->jackd_read && mainw->jackd_read->in_use)
10191 if (mainw->proc_ptr->stop_button)
10192 lives_widget_hide(mainw->proc_ptr->stop_button);
10193 #endif
10194 #ifdef HAVE_PULSE_AUDIO
10195 if (mainw->pulsed && mainw->pulsed_read && mainw->pulsed_read->in_use)
10196 if (mainw->proc_ptr->stop_button)
10197 lives_widget_hide(mainw->proc_ptr->stop_button);
10198 #endif
10199 } else {
10200 mainw->timeout_ticks += xticks;
10201 com = lives_strdup_printf("%s resume \"%s\"", prefs->backend_sync, cfile->handle);
10202 if (!mainw->preview) {
10203 if (cfile->opening || !cfile->nokeep) lives_button_set_label(LIVES_BUTTON(button), _("Pause/_Enough"));
10204 else lives_button_set_label(LIVES_BUTTON(button), _("Paus_e"));
10205 lives_button_set_label(LIVES_BUTTON(mainw->proc_ptr->cancel_button), _("Cancel"));
10206 stockim = LIVES_STOCK_CANCEL;
10207 lives_button_set_image_from_stock(LIVES_BUTTON(mainw->proc_ptr->cancel_button), stockim);
10208 lives_label_set_text(LIVES_LABEL(mainw->proc_ptr->label2), _("\nPlease Wait"));
10209 d_print(_("resumed..."));
10210 }
10211 #ifdef ENABLE_JACK
10212 if (mainw->jackd && mainw->jackd_read && mainw->jackd_read->in_use)
10213 if (mainw->proc_ptr->stop_button)
10214 lives_widget_show_all(mainw->proc_ptr->stop_button);
10215 #endif
10216 #ifdef HAVE_PULSE_AUDIO
10217 if (mainw->pulsed && mainw->pulsed_read && mainw->pulsed_read->in_use)
10218 if (mainw->proc_ptr->stop_button)
10219 lives_widget_show_all(mainw->proc_ptr->stop_button);
10220 #endif
10221 }
10222
10223 if (!cfile->opening && !mainw->internal_messaging
10224 && !(
10225 #ifdef ENABLE_JACK
10226 (mainw->jackd && mainw->jackd_read && mainw->jackd_read->in_use)
10227 #else
10228 0
10229 #endif
10230 ||
10231 #ifdef HAVE_PULSE_AUDIO
10232 (mainw->pulsed && mainw->pulsed_read && mainw->pulsed->in_use)
10233 #else
10234 0
10235 #endif
10236 )) {
10237 lives_system(com, FALSE);
10238 }
10239 }
10240 lives_freep((void **)&com);
10241 mainw->effects_paused = !mainw->effects_paused;
10242 }
10243
10244
10245 void on_preview_clicked(LiVESButton * button, livespointer user_data) {
10246 // play an effect/tool preview
10247 // IMPORTANT: cfile->undo_start and cfile->undo_end determine which frames
10248 // should be played
10249
10250 weed_plant_t *filter_map = mainw->filter_map; // back this up in case we are rendering
10251 weed_plant_t *afilter_map = mainw->afilter_map; // back this up in case we are rendering
10252 weed_plant_t *audio_event = mainw->audio_event;
10253
10254 uint64_t old_rte; //TODO - block better
10255 ticks_t xticks;
10256
10257 static volatile boolean in_preview_func = FALSE;
10258
10259 boolean resume_after;
10260 boolean ointernal_messaging = mainw->internal_messaging;
10261
10262 int ostart = cfile->start;
10263 int oend = cfile->end;
10264
10265 int toy_type = mainw->toy_type;
10266
10267 int current_file = mainw->current_file;
10268
10269 if (in_preview_func) {
10270 // called a second time from playback loop
10271 // this is a special value of cancel - don't propogate it to "open"
10272 mainw->cancelled = CANCEL_NO_PROPOGATE;
10273 return;
10274 }
10275
10276 if (mainw->noswitch) {
10277 mainw->preview_req = TRUE;
10278 return;
10279 }
10280
10281 in_preview_func = TRUE;
10282
10283 old_rte = mainw->rte;
10284 xticks = lives_get_current_ticks();
10285 mainw->timeout_ticks -= xticks;
10286
10287 if (mainw->internal_messaging) {
10288 mainw->internal_messaging = FALSE;
10289 // for realtime fx previews, we will switch all effects off and restore old
10290 // value after
10291 mainw->rte = EFFECT_NONE;
10292 }
10293
10294 if (!LIVES_IS_PLAYING) {
10295 if (cfile->opening) {
10296 if (!cfile->opening_only_audio) {
10297 mainw->toy_type = LIVES_TOY_NONE;
10298 lives_widget_set_sensitive(mainw->toys_menu, FALSE);
10299 }
10300 if (!mainw->multitrack && prefs->show_gui) lives_widget_show(LIVES_MAIN_WINDOW_WIDGET);
10301
10302 if (!mainw->multitrack && !cfile->is_loaded) {
10303 if (mainw->play_window) {
10304 cfile->is_loaded = TRUE;
10305 resize_play_window();
10306 cfile->is_loaded = FALSE;
10307 }
10308 }
10309 }
10310
10311 resume_after = FALSE;
10312
10313 if (mainw->multitrack) {
10314 mt_prepare_for_playback(mainw->multitrack);
10315 if (cfile->opening) {
10316 lives_widget_set_sensitive(mainw->multitrack->playall, FALSE);
10317 lives_widget_set_sensitive(mainw->m_playbutton, FALSE);
10318 }
10319 }
10320
10321 if (user_data) {
10322 // called from multitrack
10323 /* if (mainw->play_window) { */
10324 /* resize_play_window(); */
10325 /* } */
10326 if (mainw->multitrack && mainw->multitrack->is_rendering) {
10327 mainw->play_start = 1;
10328 mainw->play_end = cfile->frames;
10329 } else {
10330 mainw->play_start = 1;
10331 mainw->play_end = INT_MAX;
10332 }
10333 } else {
10334 mainw->preview = TRUE;
10335 if (!mainw->is_processing && !mainw->is_rendering) {
10336 mainw->play_start = cfile->start = cfile->undo_start;
10337 mainw->play_end = cfile->end = cfile->undo_end;
10338 } else {
10339 if (mainw->is_processing && mainw->is_rendering && prefs->render_audio) {
10340 // render audio up to current tc
10341 mainw->flush_audio_tc = q_gint64((double)cfile->undo_end / cfile->fps * TICKS_PER_SECOND_DBL, cfile->fps);
10342 render_events_cb(FALSE);
10343 mainw->flush_audio_tc = 0;
10344 cfile->afilesize = reget_afilesize_inner(mainw->current_file);
10345 cfile->laudio_time = (double)(cfile->afilesize / (cfile->asampsize >> 3) / cfile->achans) / (double)cfile->arate;
10346 if (cfile->achans > 1) {
10347 cfile->raudio_time = cfile->laudio_time;
10348 }
10349 }
10350 mainw->play_start = calc_frame_from_time(mainw->current_file, event_list_get_start_secs(mainw->event_list));
10351 mainw->play_end = INT_MAX;
10352 }
10353 }
10354
10355 if (cfile->opening) mainw->effects_paused = TRUE;
10356 else {
10357 // stop effects processing (if preferred)
10358 if (prefs->pause_effect_during_preview) {
10359 if (!(mainw->effects_paused)) {
10360 on_effects_paused(LIVES_BUTTON(mainw->proc_ptr->pause_button), NULL);
10361 resume_after = TRUE;
10362 }
10363 }
10364 }
10365
10366 if (button) lives_button_set_label(LIVES_BUTTON(button), _("Stop"));
10367 if (mainw->proc_ptr) {
10368 lives_widget_set_sensitive(mainw->proc_ptr->pause_button, FALSE);
10369 lives_widget_set_sensitive(mainw->proc_ptr->cancel_button, FALSE);
10370 lives_widget_hide(mainw->proc_ptr->processing);
10371 }
10372 if (!cfile->opening) {
10373 lives_widget_set_sensitive(mainw->showfct, FALSE);
10374 }
10375
10376 desensitize();
10377
10378 if (cfile->opening || cfile->opening_only_audio) {
10379 lives_widget_hide(mainw->proc_ptr->processing);
10380 if (!mainw->multitrack && !cfile->opening_audio) {
10381 showclipimgs();
10382 }
10383 resize(1);
10384 }
10385
10386 if (ointernal_messaging) {
10387 lives_sync(3);
10388 }
10389 current_file = mainw->current_file;
10390 resize(1);
10391
10392 // play the clip
10393 on_playsel_activate(NULL, LIVES_INT_TO_POINTER(TRUE));
10394
10395 if (current_file != mainw->current_file) {
10396 if (mainw->is_rendering) {
10397 mainw->files[current_file]->next_event = cfile->next_event;
10398 cfile->next_event = NULL;
10399 mainw->current_file = current_file;
10400 } else if (!mainw->multitrack) {
10401 switch_to_file((mainw->current_file = 0), current_file);
10402 }
10403 }
10404
10405 if (mainw->is_rendering) {
10406 init_conversions(LIVES_INTENTION_RENDER);
10407 mainw->effort = -EFFORT_RANGE_MAX;
10408 }
10409
10410 if (cfile->opening) mainw->effects_paused = FALSE;
10411 else {
10412 // restart effects processing (if necessary)
10413 if (resume_after) on_effects_paused(LIVES_BUTTON(mainw->proc_ptr->pause_button), NULL);
10414 }
10415 // user_data is non-NULL if called from multitrack. We want to preserve the value of cancelled.
10416 if (!user_data) mainw->cancelled = CANCEL_NONE;
10417
10418 cfile->start = ostart;
10419 cfile->end = oend;
10420
10421 mainw->toy_type = (lives_toy_t)toy_type;
10422 lives_widget_set_sensitive(mainw->toys_menu, TRUE);
10423
10424 if (mainw->proc_ptr) {
10425 // proc_ptr can be NULL if we finished loading with a bg generator running
10426 lives_widget_show(mainw->proc_ptr->processing);
10427 if (button) lives_button_set_label(LIVES_BUTTON(button), _("Preview"));
10428 lives_widget_set_sensitive(mainw->proc_ptr->pause_button, TRUE);
10429 lives_widget_set_sensitive(mainw->proc_ptr->cancel_button, TRUE);
10430 }
10431 mainw->preview = FALSE;
10432 desensitize();
10433 procw_desensitize();
10434
10435 if (!cfile->opening) {
10436 lives_widget_set_sensitive(mainw->showfct, TRUE);
10437 } else {
10438 /* for (i=1;i<MAX_FILES;i++) {
10439 if (mainw->files[i]!=NULL) {
10440 if (mainw->files[i]->menuentry!=NULL) {
10441 lives_widget_set_sensitive (mainw->files[i]->menuentry, TRUE);
10442 }}}*/
10443 if (!mainw->multitrack && mainw->play_window) {
10444 resize_play_window();
10445 }
10446 }
10447 }
10448
10449 if (mainw->preview_box) lives_widget_set_tooltip_text(mainw->p_playbutton, _("Preview"));
10450 lives_widget_set_tooltip_text(mainw->m_playbutton, _("Preview"));
10451
10452 // redraw our bars for the clip
10453 if (!mainw->merge && !mainw->multitrack) {
10454 get_play_times();
10455 }
10456 if (ointernal_messaging) {
10457 mainw->internal_messaging = TRUE;
10458
10459 // switch realtime fx back on
10460 mainw->rte = old_rte;
10461 }
10462
10463 if (mainw->play_window && mainw->fs && !mainw->multitrack) {
10464 // this prevents a hang when the separate window is visible
10465 // it may be the first time we have shown it
10466 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
10467
10468 }
10469 xticks = lives_get_current_ticks();
10470 mainw->timeout_ticks += xticks;
10471 mainw->filter_map = filter_map;
10472 mainw->afilter_map = afilter_map;
10473 mainw->audio_event = audio_event;
10474
10475 if (mainw->multitrack) {
10476 current_file = mainw->current_file;
10477 mainw->current_file = mainw->multitrack->render_file;
10478 main_thread_execute((lives_funcptr_t)mt_post_playback, -1, NULL, "v", mainw->multitrack);
10479 mainw->current_file = current_file;
10480 }
10481
10482 in_preview_func = FALSE;
10483 }
10484
10485
10486 void vj_mode_toggled(LiVESCheckMenuItem * menuitem, livespointer user_data) {
10487 if (lives_check_menu_item_get_active(menuitem) && (prefs->warning_mask & WARN_MASK_VJMODE_ENTER) == 0) {
10488 if (!(do_yesno_dialog_with_check(_("VJ Mode is specifically designed to make LiVES ready for realtime presentation.\n"
10489 "Enabling VJ restart will have the following effects:\n"
10490 "\n\n - On startup, audio source will be set to external. "
10491 "Clips willl reload without audio (although the audio files will remain on the disk).\n"
10492 "Additionally, when playing external audio, LiVES uses the system clock for frame timings "
10493 "(rather than the soundcard) which may allow for slightly smoother playback.\n"
10494 "\n - only the lightest of checks will be done when reloading clips (unless a problem is detected "
10495 "during the reload.)\n\n"
10496 "Startup will be almost instantaneous, however in the rare occurence of corruption to "
10497 "a clip audio file, this will not be detected, as the file will not be loaded."
10498 "\nOn startup, LiVES will grab the keyboard and screen focus if it can,"
10499 "\n - Shutdown will be slightly more rapid as no cleanup of the working directory will be attempted"
10500 "\n - Rendered effects will not be loaded, which will further reduce the startup time. "
10501 "(Realtime effects will still be loaded as usual)\n"
10502 "\n - Any crash recovery files will be auto reloaded "
10503 "making it convenient to terminate LiVES using ctrl-c or simply shutting down the machine\n"
10504 "\n - Continuous looping of video will be enabled automatically on startup"),
10505 WARN_MASK_VJMODE_ENTER))) {
10506 lives_signal_handler_block(mainw->vj_mode, mainw->vj_mode_func);
10507 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->vj_mode), FALSE);
10508 lives_signal_handler_unblock(mainw->vj_mode, mainw->vj_mode_func);
10509 return;
10510 }
10511 }
10512 pref_factory_bool(PREF_VJMODE, !future_prefs->vj_mode, TRUE);
10513 }
10514
10515
10516 /**
10517 This is a super important function : almost everything related to velocity direction
10518 changes during playback should ensurre this function is called.
10519 For example it user_data is non-NULL, will also set the audio player rate / direction.
10520 Even if the clip is frozen, we still update the freeze fps so that when it is unfrozen it starts with the correct velocity.
10521 */
10522 void changed_fps_during_pb(LiVESSpinButton * spinbutton, livespointer user_data) {
10523 /// user_data non-NULL to force audio rate update
10524 double new_fps;
10525
10526 if (!LIVES_IS_PLAYING) return;
10527 if (!CURRENT_CLIP_IS_VALID) return;
10528
10529 new_fps = lives_fix(lives_spin_button_get_value(LIVES_SPIN_BUTTON(spinbutton)), 3);
10530
10531 if (!user_data && ((!cfile->play_paused && cfile->pb_fps == new_fps) || (cfile->play_paused && new_fps == 0.))) {
10532 mainw->period = TICKS_PER_SECOND_DBL / cfile->pb_fps;
10533 return;
10534 }
10535
10536 mainw->currticks = lives_get_current_playback_ticks(mainw->origsecs, mainw->orignsecs, NULL);
10537
10538 if (new_fps != cfile->pb_fps && fabs(new_fps) > .001 && !cfile->play_paused) {
10539 /// we must scale the frame delta, since e.g if we were a halfway through the frame and the fps increased,
10540 /// we could end up jumping several frames
10541 ticks_t delta_ticks;
10542 delta_ticks = (mainw->currticks - mainw->startticks);
10543 delta_ticks = (ticks_t)((double)delta_ticks + fabs(cfile->pb_fps / new_fps));
10544 /// the time we would shown the last frame at using the new fps
10545 mainw->startticks = mainw->currticks - delta_ticks;
10546 }
10547
10548 cfile->pb_fps = new_fps;
10549 mainw->period = TICKS_PER_SECOND_DBL / cfile->pb_fps;
10550
10551 if (prefs->audio_opts & AUDIO_OPTS_FOLLOW_FPS) {
10552 if (new_fps >= 0.) cfile->adirection = LIVES_DIRECTION_FORWARD;
10553 else cfile->adirection = LIVES_DIRECTION_REVERSE;
10554 // update our audio player
10555 #ifdef ENABLE_JACK
10556 if (prefs->audio_src == AUDIO_SRC_INT && prefs->audio_player == AUD_PLAYER_JACK && mainw->jackd) {
10557 if (mainw->jackd->playing_file == mainw->current_file) {
10558 mainw->jackd->sample_in_rate = cfile->arate * cfile->pb_fps / cfile->fps;
10559 if (mainw->record && !mainw->record_paused && (prefs->rec_opts & REC_AUDIO)
10560 && mainw->agen_key == 0 && !mainw->agen_needs_reinit) {
10561 jack_get_rec_avals(mainw->jackd);
10562 // *INDENT-OFF*
10563 }}}
10564 // *INDENT-ON*
10565 #endif
10566
10567 #ifdef HAVE_PULSE_AUDIO
10568 if (prefs->audio_src == AUDIO_SRC_INT && prefs->audio_player == AUD_PLAYER_PULSE && mainw->pulsed) {
10569 if (mainw->pulsed->playing_file == mainw->current_file) {
10570 mainw->pulsed->in_arate = cfile->arate * cfile->pb_fps / cfile->fps;
10571 if (mainw->pulsed->fd >= 0) {
10572 if (mainw->pulsed->in_arate > 0.) {
10573 lives_buffered_rdonly_set_reversed(mainw->pulsed->fd, FALSE);
10574 } else {
10575 lives_buffered_rdonly_set_reversed(mainw->pulsed->fd, TRUE);
10576 }
10577 }
10578 if (mainw->record && !mainw->record_paused && (prefs->rec_opts & REC_AUDIO)
10579 && mainw->agen_key == 0 && !mainw->agen_needs_reinit) {
10580 pulse_get_rec_avals(mainw->pulsed);
10581 // *INDENT-OFF*
10582 }}}
10583 // *INDENT-ON*
10584 #endif
10585 }
10586
10587 if (cfile->play_paused && new_fps != 0.) {
10588 cfile->freeze_fps = new_fps;
10589 // unfreeze the clip at the new (non-zero) fps rate
10590 freeze_callback(NULL, NULL, 0, (LiVESXModifierType)0, NULL);
10591 return;
10592 }
10593
10594 if (cfile->pb_fps == 0. && !cfile->play_paused) {
10595 // freeze the clip
10596 freeze_callback(NULL, NULL, 0, (LiVESXModifierType)0, NULL);
10597 return;
10598 }
10599 }
10600
10601
10602 boolean on_mouse_scroll(LiVESWidget * widget, LiVESXEventScroll * event, livespointer user_data) {
10603 lives_mt *mt = (lives_mt *)user_data;
10604 LiVESXModifierType kstate = (LiVESXModifierType)event->state;
10605 uint32_t type = 1;
10606
10607 if (!LIVES_IS_INTERACTIVE) return FALSE;
10608 if (mt) {
10609 // multitrack mode
10610 if ((kstate & LIVES_DEFAULT_MOD_MASK) == LIVES_CONTROL_MASK) {
10611 if (lives_get_scroll_direction(event) == LIVES_SCROLL_UP) mt_zoom_in(NULL, mt);
10612 else if (lives_get_scroll_direction(event) == LIVES_SCROLL_DOWN) mt_zoom_out(NULL, mt);
10613 return FALSE;
10614 }
10615
10616 if (!prefs->mouse_scroll_clips) return FALSE;
10617
10618 if (mt->poly_state == POLY_CLIPS) {
10619 // check if mouse pointer is over clip scroll tab
10620 LiVESXWindow *window = lives_display_get_window_at_pointer
10621 ((LiVESXDevice *)mainw->mgeom[widget_opts.monitor].mouse_device,
10622 mt->display, NULL, NULL);
10623
10624 if (widget == mt->clip_scroll || window == lives_widget_get_xwindow(mt->poly_box)) {
10625 // scroll fwd / back in clips
10626 if (lives_get_scroll_direction(event) == LIVES_SCROLL_UP) mt_prevclip(NULL, NULL, 0, (LiVESXModifierType)0, user_data);
10627 else if (lives_get_scroll_direction(event) == LIVES_SCROLL_DOWN) mt_nextclip(NULL, NULL, 0, (LiVESXModifierType)0, user_data);
10628 }
10629 }
10630 return FALSE;
10631 }
10632
10633 // clip editor mode
10634
10635 if (!prefs->mouse_scroll_clips) return FALSE;
10636
10637 if ((kstate & LIVES_DEFAULT_MOD_MASK) == (LIVES_CONTROL_MASK | LIVES_SHIFT_MASK)) type = 2; // bg
10638 else if ((kstate & LIVES_DEFAULT_MOD_MASK) == LIVES_CONTROL_MASK) type = 0; // fg or bg
10639
10640 if (lives_get_scroll_direction(event) == LIVES_SCROLL_UP) prevclip_callback(NULL, NULL, 0, (LiVESXModifierType)0,
10641 LIVES_INT_TO_POINTER(type));
10642 else if (lives_get_scroll_direction(event) == LIVES_SCROLL_DOWN) nextclip_callback(NULL, NULL, 0, (LiVESXModifierType)0,
10643 LIVES_INT_TO_POINTER(type));
10644
10645 return TRUE;
10646 }
10647
10648
10649 // next few functions are for the timer bars
10650 boolean on_mouse_sel_update(LiVESWidget * widget, LiVESXEventMotion * event, livespointer user_data) {
10651 if (!LIVES_IS_INTERACTIVE) return FALSE;
10652
10653 if (CURRENT_CLIP_IS_VALID && mainw->sel_start > 0) {
10654 int x, sel_current;
10655 double tpos;
10656
10657 lives_widget_get_pointer((LiVESXDevice *)mainw->mgeom[widget_opts.monitor].mouse_device,
10658 LIVES_MAIN_WINDOW_WIDGET, &x, NULL);
10659 tpos = (double)x / (double)(lives_widget_get_allocation_width(mainw->video_draw) - 1) * CLIP_TOTAL_TIME(mainw->current_file);
10660 if (mainw->sel_move == SEL_MOVE_AUTO)
10661 sel_current = calc_frame_from_time3(mainw->current_file, tpos);
10662 else
10663 sel_current = calc_frame_from_time(mainw->current_file, tpos);
10664
10665 if (mainw->sel_move == SEL_MOVE_SINGLE) {
10666 sel_current = calc_frame_from_time3(mainw->current_file, tpos);
10667 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), sel_current);
10668 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), sel_current);
10669 }
10670
10671 if (mainw->sel_move == SEL_MOVE_START || (mainw->sel_move == SEL_MOVE_AUTO && sel_current < mainw->sel_start)) {
10672 sel_current = calc_frame_from_time(mainw->current_file, tpos);
10673 if (LIVES_IS_PLAYING && sel_current > cfile->end) sel_current = cfile->end;
10674 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), sel_current);
10675 } else if (mainw->sel_move == SEL_MOVE_END || (mainw->sel_move == SEL_MOVE_AUTO && sel_current > mainw->sel_start)) {
10676 sel_current = calc_frame_from_time2(mainw->current_file, tpos);
10677 if (LIVES_IS_PLAYING && sel_current <= cfile->start) sel_current = cfile->start + 1;
10678 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), sel_current - 1);
10679 }
10680 }
10681 return FALSE;
10682 }
10683
10684
10685 boolean on_mouse_sel_reset(LiVESWidget * widget, LiVESXEventButton * event, livespointer user_data) {
10686 if (!LIVES_IS_INTERACTIVE) return FALSE;
10687
10688 if (mainw->current_file <= 0) return FALSE;
10689 mainw->sel_start = 0;
10690 if (!mainw->mouse_blocked) {
10691 lives_signal_handler_block(mainw->eventbox2, mainw->mouse_fn1);
10692 mainw->mouse_blocked = TRUE;
10693 }
10694 return FALSE;
10695 }
10696
10697
10698 boolean on_mouse_sel_start(LiVESWidget * widget, LiVESXEventButton * event, livespointer user_data) {
10699 int x;
10700
10701 if (!LIVES_IS_INTERACTIVE) return FALSE;
10702
10703 if (mainw->current_file <= 0) return FALSE;
10704
10705 lives_widget_get_pointer((LiVESXDevice *)mainw->mgeom[widget_opts.monitor].mouse_device,
10706 LIVES_MAIN_WINDOW_WIDGET, &x, NULL);
10707
10708 mainw->sel_start = calc_frame_from_time(mainw->current_file,
10709 (double)x / (double)(lives_widget_get_allocation_width(mainw->video_draw) - 1)
10710 * CLIP_TOTAL_TIME(mainw->current_file));
10711
10712 if (event->button == 3 && !mainw->selwidth_locked) {
10713 mainw->sel_start = calc_frame_from_time3(mainw->current_file,
10714 (double)x / (double)lives_widget_get_allocation_width(mainw->video_draw)
10715 * CLIP_TOTAL_TIME(mainw->current_file));
10716 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), mainw->sel_start);
10717 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), mainw->sel_start);
10718 mainw->sel_move = SEL_MOVE_AUTO;
10719 }
10720
10721 else {
10722 if (event->button == 2 && !mainw->selwidth_locked) {
10723 mainw->sel_start = calc_frame_from_time3(mainw->current_file,
10724 (double)x / (double)lives_widget_get_allocation_width(mainw->video_draw)
10725 * CLIP_TOTAL_TIME(mainw->current_file));
10726 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), mainw->sel_start);
10727 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), (int)mainw->sel_start);
10728 mainw->sel_move = SEL_MOVE_SINGLE;
10729 }
10730
10731 else {
10732 if (!mainw->selwidth_locked) {
10733 if ((mainw->sel_start < cfile->end && ((mainw->sel_start - cfile->start) <= (cfile->end - mainw->sel_start))) ||
10734 mainw->sel_start < cfile->start) {
10735 if (LIVES_IS_PLAYING && mainw->sel_start >= cfile->end) {
10736 mainw->sel_start = cfile->end;
10737 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), mainw->sel_start);
10738 }
10739 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), mainw->sel_start);
10740 mainw->sel_move = SEL_MOVE_START;
10741 } else {
10742 mainw->sel_start = calc_frame_from_time2(mainw->current_file,
10743 (double)x / (double)lives_widget_get_allocation_width(mainw->video_draw)
10744 * CLIP_TOTAL_TIME(mainw->current_file));
10745 if (LIVES_IS_PLAYING && mainw->sel_start <= cfile->start) {
10746 mainw->sel_start = cfile->start;
10747 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), mainw->sel_start);
10748 } else
10749 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), mainw->sel_start - 1);
10750 mainw->sel_move = SEL_MOVE_END;
10751 }
10752 } else {
10753 // locked selection
10754 if (mainw->sel_start > cfile->end) {
10755 // past end
10756 if (cfile->end + cfile->end - cfile->start + 1 <= cfile->frames) {
10757 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->end + cfile->end - cfile->start + 1);
10758 mainw->sel_move = SEL_MOVE_START;
10759 }
10760 } else {
10761 if (mainw->sel_start >= cfile->start) {
10762 if (mainw->sel_start > cfile->start + (cfile->end - cfile->start + 1) / 2) {
10763 // nearer to end
10764 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), mainw->sel_start);
10765 mainw->sel_move = SEL_MOVE_END;
10766 } else {
10767 // nearer to start
10768 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), mainw->sel_start);
10769 mainw->sel_move = SEL_MOVE_START;
10770 }
10771 } else {
10772 // before start
10773 if (cfile->start - cfile->end + cfile->start - 1 >= 1) {
10774 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), cfile->start - 1);
10775 mainw->sel_move = SEL_MOVE_END;
10776 // *INDENT-OFF*
10777 }}}}}}
10778 // *INDENT-ON*
10779
10780 if (mainw->mouse_blocked) {// stops a warning if the user clicks around a lot...
10781 lives_signal_handler_unblock(mainw->eventbox2, mainw->mouse_fn1);
10782 mainw->mouse_blocked = FALSE;
10783 }
10784 return FALSE;
10785 }
10786
10787
10788 #ifdef ENABLE_GIW_3
10789 void on_hrule_value_changed(LiVESWidget * widget, livespointer user_data) {
10790 if (!LIVES_IS_INTERACTIVE) return;
10791 if (CURRENT_CLIP_IS_CLIPBOARD || !CURRENT_CLIP_IS_VALID) return;
10792
10793 if (LIVES_IS_PLAYING) {
10794 lives_clip_t *pfile = mainw->files[mainw->playing_file];
10795 if (pfile->frames > 0) {
10796 pfile->frameno = pfile->last_frameno = calc_frame_from_time(mainw->playing_file,
10797 giw_timeline_get_value(GIW_TIMELINE(widget)));
10798 mainw->scratch = SCRATCH_JUMP;
10799 }
10800 return;
10801 }
10802
10803 cfile->pointer_time = lives_ce_update_timeline(0, giw_timeline_get_value(GIW_TIMELINE(widget)));
10804 if (cfile->frames > 0) cfile->frameno = cfile->last_frameno = calc_frame_from_time(mainw->current_file, cfile->pointer_time);
10805
10806 if (cfile->pointer_time > 0.) {
10807 lives_widget_set_sensitive(mainw->rewind, TRUE);
10808 lives_widget_set_sensitive(mainw->trim_to_pstart, (cfile->achans * cfile->frames > 0));
10809 lives_widget_set_sensitive(mainw->m_rewindbutton, TRUE);
10810 if (mainw->preview_box) {
10811 lives_widget_set_sensitive(mainw->p_rewindbutton, TRUE);
10812 }
10813 } else {
10814 lives_widget_set_sensitive(mainw->rewind, FALSE);
10815 lives_widget_set_sensitive(mainw->trim_to_pstart, FALSE);
10816 lives_widget_set_sensitive(mainw->m_rewindbutton, FALSE);
10817 if (mainw->preview_box) {
10818 lives_widget_set_sensitive(mainw->p_rewindbutton, FALSE);
10819 }
10820 }
10821 mainw->ptrtime = cfile->pointer_time;
10822 lives_widget_queue_draw(mainw->eventbox2);
10823 }
10824
10825 #else
10826
10827 boolean on_hrule_update(LiVESWidget * widget, LiVESXEventMotion * event, livespointer user_data) {
10828 LiVESXModifierType modmask;
10829 LiVESXDevice *device;
10830 int x;
10831 if (LIVES_IS_PLAYING) return TRUE;
10832 if (!LIVES_IS_INTERACTIVE) return TRUE;
10833 if (CURRENT_CLIP_IS_CLIPBOARD || !CURRENT_CLIP_IS_VALID) return TRUE;
10834
10835 device = (LiVESXDevice *)mainw->mgeom[widget_opts.monitor].mouse_device;
10836 lives_widget_get_modmask(device, widget, &modmask);
10837
10838 if (!(modmask & LIVES_BUTTON1_MASK)) return TRUE;
10839
10840 lives_widget_get_pointer(device, widget, &x, NULL);
10841 cfile->pointer_time = lives_ce_update_timeline(0,
10842 (double)x / (double()lives_widget_get_allocation_width(widget) - 1)
10843 * CLIP_TOTAL_TIME(mainw->current_file));
10844 if (cfile->frames > 0) cfile->frameno = calc_frame_from_time(mainw->current_file, cfile->pointer_time);
10845 return TRUE;
10846 }
10847
10848
10849 boolean on_hrule_reset(LiVESWidget * widget, LiVESXEventButton * event, livespointer user_data) {
10850 //button release
10851 int x;
10852
10853 if (LIVES_IS_PLAYING) return FALSE;
10854 if (!LIVES_IS_INTERACTIVE) return FALSE;
10855 if (CURRENT_CLIP_IS_CLIPBOARD || !CURRENT_CLIP_IS_VALID) return FALSE;
10856
10857 lives_widget_get_pointer((LiVESXDevice *)mainw->mgeom[widget_opts.monitor].mouse_device,
10858 widget, &x, NULL);
10859 cfile->pointer_time = lives_ce_update_timeline(0,
10860 (double)x / (double)(lives_widget_get_allocation_width(widget) - 1)
10861 * CLIP_TOTAL_TIME(mainw->current_file));
10862 if (cfile->frames > 0) {
10863 cfile->last_frameno = cfile->frameno = calc_frame_from_time(mainw->current_file, cfile->pointer_time);
10864 }
10865 if (cfile->pointer_time > 0.) {
10866 lives_widget_set_sensitive(mainw->rewind, TRUE);
10867 lives_widget_set_sensitive(mainw->trim_to_pstart, (cfile->achans * cfile->frames > 0));
10868 lives_widget_set_sensitive(mainw->m_rewindbutton, TRUE);
10869 if (mainw->preview_box) {
10870 lives_widget_set_sensitive(mainw->p_rewindbutton, TRUE);
10871 }
10872 } else {
10873 lives_widget_set_sensitive(mainw->rewind, FALSE);
10874 lives_widget_set_sensitive(mainw->trim_to_pstart, FALSE);
10875 lives_widget_set_sensitive(mainw->m_rewindbutton, FALSE);
10876 if (mainw->preview_box) {
10877 lives_widget_set_sensitive(mainw->p_rewindbutton, FALSE);
10878 }
10879 }
10880 return FALSE;
10881 }
10882
10883
10884 boolean on_hrule_set(LiVESWidget * widget, LiVESXEventButton * event, livespointer user_data) {
10885 // button press
10886 int x;
10887
10888 if (!LIVES_IS_INTERACTIVE) return FALSE;
10889 if (CURRENT_CLIP_IS_CLIPBOARD || !CURRENT_CLIP_IS_VALID) return TRUE;
10890
10891 lives_widget_get_pointer((LiVESXDevice *)mainw->mgeom[widget_opts.monitor].mouse_device,
10892 widget, &x, NULL);
10893
10894 cfile->pointer_time = lives_ce_update_timeline(0,
10895 (double)x / (double)(lives_widget_get_allocation_width(widget) - 1)
10896 * CLIP_TOTAL_TIME(mainw->current_file));
10897 if (cfile->frames > 0) cfile->frameno = cfile->last_frameno = calc_frame_from_time(mainw->current_file, cfile->pointer_time);
10898 if (LIVES_IS_PLAYING) mainw->scratch = SCRATCH_JUMP;
10899
10900 mainw->ptrtime = cfile->pointer_time;
10901 lives_widget_queue_draw(mainw->eventbox2);
10902 g_print("HRSET\n");
10903 return TRUE;
10904 }
10905
10906 #endif
10907
10908
10909 boolean frame_context(LiVESWidget * widget, LiVESXEventButton * event, livespointer which) {
10910 //popup a context menu when we right click on a frame
10911
10912 LiVESWidget *save_frame_as;
10913 LiVESWidget *menu;
10914
10915 int frame = 0;
10916
10917 if (!LIVES_IS_INTERACTIVE) return FALSE;
10918 if (CURRENT_CLIP_IS_CLIPBOARD || !CURRENT_CLIP_IS_VALID) return FALSE;
10919
10920 if (mainw->multitrack && !mainw->multitrack->event_list) return FALSE;
10921
10922 // only accept right mouse clicks
10923
10924 if (event->button != 3) return FALSE;
10925
10926 if (!mainw->multitrack) {
10927 switch (LIVES_POINTER_TO_INT(which)) {
10928 case 1:
10929 // start frame
10930 frame = cfile->start;
10931 break;
10932 case 2:
10933 // end frame
10934 frame = cfile->end;
10935 break;
10936 default:
10937 // preview frame
10938 frame = mainw->preview_frame;
10939 break;
10940 }
10941 }
10942
10943 menu = lives_menu_new();
10944 lives_menu_set_title(LIVES_MENU(menu), _("Selected Frame"));
10945
10946 if (palette->style & STYLE_1) {
10947 lives_widget_set_bg_color(menu, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
10948 lives_widget_set_fg_color(menu, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars_fore);
10949 }
10950
10951 if (cfile->frames > 0 || mainw->multitrack) {
10952 save_frame_as = lives_standard_menu_item_new_with_label(_("_Save Frame as..."));
10953 lives_signal_sync_connect(LIVES_GUI_OBJECT(save_frame_as), LIVES_WIDGET_ACTIVATE_SIGNAL,
10954 LIVES_GUI_CALLBACK(save_frame),
10955 LIVES_INT_TO_POINTER(frame));
10956
10957 if (capable->has_convert && capable->has_composite)
10958 lives_container_add(LIVES_CONTAINER(menu), save_frame_as);
10959 }
10960
10961 lives_widget_show_all(menu);
10962 lives_menu_popup(LIVES_MENU(menu), event);
10963
10964 return FALSE;
10965 }
10966
10967
10968 void on_less_pressed(LiVESButton * button, livespointer user_data) {
10969 if (CURRENT_CLIP_IS_CLIPBOARD || !CURRENT_CLIP_IS_VALID) return;
10970
10971 if (!LIVES_IS_PLAYING || mainw->internal_messaging || (mainw->is_processing && cfile->is_loaded)) return;
10972 if (cfile->next_event) return;
10973
10974 if (mainw->rte_keys != -1) {
10975 mainw->blend_factor -= prefs->blendchange_amount * (double)KEY_RPT_INTERVAL / 1000.;
10976 weed_set_blend_factor(mainw->rte_keys);
10977 }
10978 }
10979
10980
10981 void on_slower_pressed(LiVESButton * button, livespointer user_data) {
10982 double change = 1., new_fps;
10983
10984 int type = 0;
10985
10986 lives_clip_t *sfile = cfile;
10987 if (CURRENT_CLIP_IS_CLIPBOARD || !CURRENT_CLIP_IS_VALID) return;
10988
10989 if (!LIVES_IS_PLAYING || mainw->internal_messaging || (mainw->is_processing && cfile->is_loaded)) return;
10990 if (mainw->record && !(prefs->rec_opts & REC_FRAMES)) return;
10991 if (cfile->next_event) return;
10992
10993 if (mainw->record && !mainw->record_paused && !(prefs->rec_opts & REC_FPS)) return;
10994
10995 if (user_data) {
10996 type = LIVES_POINTER_TO_INT(user_data);
10997 if (type == SCREEN_AREA_BACKGROUND) {
10998 if (!IS_NORMAL_CLIP(mainw->blend_file)) return;
10999 sfile = mainw->files[mainw->blend_file];
11000 } else if (!IS_NORMAL_CLIP(mainw->current_file)) return;
11001 }
11002
11003 if (sfile->next_event) return;
11004
11005 change *= prefs->fpschange_amount / TICKS_PER_SECOND_DBL * (double)KEY_RPT_INTERVAL * sfile->pb_fps;
11006 if (button) change *= 4.;
11007 if (sfile->pb_fps == 0.) return;
11008 if (sfile->pb_fps > 0.) {
11009 if (sfile->pb_fps < 0.1 || sfile->pb_fps < change) sfile->pb_fps = change;
11010 new_fps = sfile->pb_fps - change;
11011 if (sfile == cfile) lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), new_fps);
11012 else sfile->pb_fps = new_fps;
11013 } else {
11014 if (sfile->pb_fps > change) sfile->pb_fps = change;
11015 if (sfile == cfile) lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), (sfile->pb_fps - change));
11016 else sfile->pb_fps -= change;
11017 }
11018 }
11019
11020
11021 void on_more_pressed(LiVESButton * button, livespointer user_data) {
11022 if (CURRENT_CLIP_IS_CLIPBOARD || !CURRENT_CLIP_IS_VALID) return;
11023
11024 if (!LIVES_IS_PLAYING || mainw->internal_messaging || (mainw->is_processing && cfile->is_loaded)) return;
11025 if (cfile->next_event) return;
11026
11027 if (mainw->rte_keys != -1) {
11028 mainw->blend_factor += prefs->blendchange_amount * (double)KEY_RPT_INTERVAL / 1000.;
11029 weed_set_blend_factor(mainw->rte_keys);
11030 }
11031 }
11032
11033
11034 void on_faster_pressed(LiVESButton * button, livespointer user_data) {
11035 double change = 1.;
11036 int type = 0;
11037
11038 lives_clip_t *sfile = cfile;
11039 if (CURRENT_CLIP_IS_CLIPBOARD || !CURRENT_CLIP_IS_VALID) return;
11040
11041 if (!LIVES_IS_PLAYING || mainw->internal_messaging || (mainw->is_processing && cfile->is_loaded)) return;
11042 if (mainw->record && !(prefs->rec_opts & REC_FRAMES)) return;
11043 if (cfile->next_event) return;
11044
11045 if (mainw->record && !mainw->record_paused && !(prefs->rec_opts & REC_FPS)) return;
11046
11047 if (user_data) {
11048 type = LIVES_POINTER_TO_INT(user_data);
11049 if (type == SCREEN_AREA_BACKGROUND) {
11050 if (!IS_NORMAL_CLIP(mainw->blend_file)) return;
11051 sfile = mainw->files[mainw->blend_file];
11052 } else if (!IS_NORMAL_CLIP(mainw->current_file)) return;
11053 }
11054
11055 if (sfile->play_paused && sfile->freeze_fps < 0.) {
11056 sfile->pb_fps = -.00000001; // want to keep this as a negative value so when we unfreeze we still play in reverse
11057 }
11058
11059 if (sfile->next_event) return;
11060
11061 change *= prefs->fpschange_amount / TICKS_PER_SECOND_DBL * (double)KEY_RPT_INTERVAL
11062 * (sfile->pb_fps == 0. ? 1. : sfile->pb_fps);
11063 if (button) change *= 4.;
11064
11065 if (sfile->pb_fps >= 0.) {
11066 if (sfile->pb_fps == FPS_MAX) return;
11067 if (sfile->pb_fps < 0.5) sfile->pb_fps = .5;
11068 if (sfile->pb_fps > FPS_MAX - change) sfile->pb_fps = FPS_MAX - change;
11069 if (sfile == cfile) lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), (sfile->pb_fps + change));
11070 else sfile->pb_fps = sfile->pb_fps + change;
11071 } else {
11072 if (sfile->pb_fps == -FPS_MAX) return;
11073 if (sfile->pb_fps < -FPS_MAX - change) sfile->pb_fps = -FPS_MAX - change;
11074 if (sfile == cfile) lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), (sfile->pb_fps + change));
11075 else sfile->pb_fps = sfile->pb_fps + change;
11076 }
11077 }
11078
11079
11080 void on_back_pressed(LiVESButton * button, livespointer user_data) {
11081 int type = 0;
11082 if (CURRENT_CLIP_IS_CLIPBOARD || !CURRENT_CLIP_IS_NORMAL) return;
11083 if (mainw->internal_messaging || (mainw->is_processing && cfile->is_loaded)) return;
11084 if (LIVES_IS_PLAYING && !clip_can_reverse(mainw->current_file)) return;
11085
11086 if (mainw->record && !(prefs->rec_opts & REC_FRAMES)) return;
11087 if (cfile->next_event) return;
11088
11089 if (!LIVES_IS_PLAYING) {
11090 if (cfile->real_pointer_time > 0.) {
11091 cfile->real_pointer_time--;
11092 if (cfile->real_pointer_time < 0.) cfile->real_pointer_time = 0.;
11093 lives_ce_update_timeline(0, cfile->real_pointer_time);
11094 }
11095 return;
11096 }
11097
11098 if (user_data) {
11099 type = LIVES_POINTER_TO_INT(user_data);
11100 if (type == SCREEN_AREA_BACKGROUND) return; // TODO: implement scratch play for the blend file
11101 }
11102
11103 if (button) mainw->scratch |= SCRATCH_BACK_EXTRA;
11104 else mainw->scratch = SCRATCH_BACK;
11105 }
11106
11107
11108 void on_forward_pressed(LiVESButton * button, livespointer user_data) {
11109 int type = 0;
11110 if (CURRENT_CLIP_IS_CLIPBOARD || !CURRENT_CLIP_IS_NORMAL) return;
11111 if (mainw->internal_messaging || (mainw->is_processing && cfile->is_loaded)) return;
11112
11113 if (mainw->record && !(prefs->rec_opts & REC_FRAMES)) return;
11114 if (cfile->next_event) return;
11115
11116 if (!LIVES_IS_PLAYING) {
11117 if (cfile->real_pointer_time < CURRENT_CLIP_TOTAL_TIME) {
11118 cfile->real_pointer_time++;
11119 if (cfile->real_pointer_time > CURRENT_CLIP_TOTAL_TIME) cfile->real_pointer_time = CURRENT_CLIP_TOTAL_TIME;
11120 lives_ce_update_timeline(0, cfile->real_pointer_time);
11121 }
11122 return;
11123 }
11124
11125 if (user_data) {
11126 type = LIVES_POINTER_TO_INT(user_data);
11127 if (type == SCREEN_AREA_BACKGROUND) return; // TODO: implement scratch play for the blend file
11128 }
11129
11130 if (button) mainw->scratch = SCRATCH_FWD_EXTRA;
11131 else mainw->scratch = SCRATCH_FWD;
11132 }
11133
11134
11135 boolean freeze_callback(LiVESAccelGroup * group, LiVESWidgetObject * obj, uint32_t keyval, LiVESXModifierType mod,
11136 livespointer user_data) {
11137 weed_timecode_t tc;
11138 static boolean norecurse = FALSE;
11139
11140 if (norecurse) return TRUE;
11141
11142 if (mainw->multitrack && (LIVES_IS_PLAYING || mainw->multitrack->is_paused)) {
11143 on_playall_activate(NULL, NULL);
11144 return TRUE;
11145 }
11146 if (CURRENT_CLIP_IS_CLIPBOARD || !CURRENT_CLIP_IS_VALID) return TRUE;
11147 if (!LIVES_IS_PLAYING || (mainw->is_processing && cfile->is_loaded)) return TRUE;
11148 if (mainw->record && !(prefs->rec_opts & REC_FRAMES)) return TRUE;
11149
11150 // TODO: make pref (reset keymode grab on freeze)
11151 //if (group) mainw->rte_keys = -1;
11152
11153 if (cfile->play_paused) {
11154 cfile->pb_fps = cfile->freeze_fps;
11155 if (cfile->pb_fps != 0.) mainw->period = TICKS_PER_SECOND_DBL / cfile->pb_fps;
11156 else mainw->period = INT_MAX;
11157 cfile->play_paused = FALSE;
11158 if (mainw->record && !mainw->record_paused) {
11159 pthread_mutex_lock(&mainw->event_list_mutex);
11160 // write a RECORD_START marker
11161 tc = get_event_timecode(get_last_event(mainw->event_list));
11162 mainw->event_list = append_marker_event(mainw->event_list, tc, EVENT_MARKER_RECORD_START); // mark record end
11163 pthread_mutex_unlock(&mainw->event_list_mutex);
11164 }
11165 } else {
11166 if (mainw->record) {
11167 pthread_mutex_lock(&mainw->event_list_mutex);
11168 // write a RECORD_END marker
11169 tc = get_event_timecode(get_last_event(mainw->event_list));
11170 mainw->event_list = append_marker_event(mainw->event_list, tc, EVENT_MARKER_RECORD_END); // mark record end
11171 pthread_mutex_unlock(&mainw->event_list_mutex);
11172 }
11173
11174 cfile->freeze_fps = cfile->pb_fps;
11175 cfile->play_paused = TRUE;
11176 cfile->pb_fps = 0.;
11177 mainw->timeout_ticks = mainw->currticks;
11178 }
11179
11180 if (group) {
11181 norecurse = TRUE;
11182 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), cfile->pb_fps);
11183 norecurse = FALSE;
11184 }
11185
11186 if (prefs->audio_src == AUDIO_SRC_INT) {
11187 #ifdef ENABLE_JACK
11188 if (mainw->jackd && prefs->audio_player == AUD_PLAYER_JACK
11189 && mainw->jackd->playing_file == mainw->playing_file && (prefs->jack_opts & JACK_OPTS_NOPLAY_WHEN_PAUSED ||
11190 prefs->audio_opts & AUDIO_OPTS_FOLLOW_FPS)) {
11191 mainw->jackd->is_paused = cfile->play_paused;
11192 if (mainw->record && !mainw->record_paused && (prefs->rec_opts & REC_AUDIO) && mainw->agen_key == 0 &&
11193 !mainw->agen_needs_reinit) {
11194 if (cfile->play_paused) {
11195 weed_plant_t *event = get_last_frame_event(mainw->event_list);
11196 insert_audio_event_at(event, -1, mainw->jackd->playing_file, 0., 0.); // audio switch off
11197 } else {
11198 jack_get_rec_avals(mainw->jackd);
11199 }
11200 }
11201 #ifdef ENABLE_JACK_TRANSPORT
11202 if (cfile->play_paused) jack_pb_stop();
11203 else jack_pb_start(-1.);
11204 #endif
11205 }
11206 #endif
11207 #ifdef HAVE_PULSE_AUDIO
11208 if (mainw->pulsed && prefs->audio_player == AUD_PLAYER_PULSE
11209 && mainw->pulsed->playing_file == mainw->playing_file && (prefs->audio_opts & AUDIO_OPTS_FOLLOW_FPS)) {
11210 if (!cfile->play_paused) mainw->pulsed->in_arate = cfile->arate * cfile->pb_fps / cfile->fps;
11211 mainw->pulsed->is_paused = cfile->play_paused;
11212 if (mainw->record && !mainw->record_paused && (prefs->rec_opts & REC_AUDIO) && mainw->agen_key == 0 &&
11213 !mainw->agen_needs_reinit) {
11214 if (cfile->play_paused) {
11215 if (!mainw->mute) {
11216 weed_plant_t *event = get_last_frame_event(mainw->event_list);
11217 insert_audio_event_at(event, -1, mainw->pulsed->playing_file, 0., 0.); // audio switch off
11218 }
11219 } else {
11220 pulse_get_rec_avals(mainw->pulsed);
11221 }
11222 }
11223 }
11224 #endif
11225 }
11226 if (LIVES_IS_PLAYING) mainw->force_show = TRUE;
11227 return TRUE;
11228 }
11229
11230
11231 boolean nervous_callback(LiVESAccelGroup * group, LiVESWidgetObject * obj, uint32_t keyval, LiVESXModifierType mod,
11232 livespointer clip_number) {
11233 if (mainw->multitrack) return FALSE;
11234 mainw->nervous = !mainw->nervous;
11235 return TRUE;
11236 }
11237
11238
11239 /**
11240 @brief lock or unlock audio track changes in free playback
11241 if lock is switched on then the prefs to follow video clip changes and rate / direction changes
11242 are overriden, in addition the audio is ismmediately synced to the current video track
11243
11244 switching off audio lock re-enables these prefs settings
11245
11246 if LiVES is not playing, or the audio player is non-realtime then there is no effect
11247 */
11248 boolean aud_lock_callback(LiVESAccelGroup * group, LiVESWidgetObject * obj, uint32_t keyval, LiVESXModifierType mod,
11249 livespointer statep) {
11250 boolean state = LIVES_POINTER_TO_INT(statep);
11251 if (!LIVES_IS_PLAYING || !is_realtime_aplayer(prefs->audio_player) || mainw->multitrack
11252 || mainw->is_rendering || mainw->preview || mainw->agen_key != 0 || mainw->agen_needs_reinit
11253 || prefs->audio_src == AUDIO_SRC_EXT) return TRUE;
11254
11255 if (!state) {
11256 // lock OFF
11257 prefs->audio_opts = future_prefs->audio_opts;
11258 return TRUE;
11259 }
11260 if (switch_audio_clip(mainw->current_file, TRUE)) {
11261 if (prefs->audio_opts & AUDIO_OPTS_FOLLOW_FPS) {
11262 mainw->currticks = lives_get_current_playback_ticks(mainw->origsecs, mainw->orignsecs, NULL);
11263 resync_audio(cfile->frameno);
11264 changed_fps_during_pb(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), LIVES_INT_TO_POINTER(TRUE));
11265 }
11266 }
11267 prefs->audio_opts &= ~(AUDIO_OPTS_FOLLOW_FPS | AUDIO_OPTS_FOLLOW_CLIPS);
11268 return TRUE;
11269 }
11270
11271
11272 char *get_palette_name_for_clip(int clipno) {
11273 lives_clip_t *sfile;
11274 char *palname = NULL;
11275 if (!IS_VALID_CLIP(clipno)) return NULL;
11276 sfile = mainw->files[clipno];
11277 if (IS_NORMAL_CLIP(clipno)) {
11278 if (is_virtual_frame(clipno, sfile->frameno)) {
11279 lives_clip_data_t *cdata = ((lives_decoder_t *)sfile->ext_src)->cdata;
11280 palname = lives_strdup(weed_palette_get_name_full(cdata->current_palette, cdata->YUV_clamping, cdata->YUV_subspace));
11281 } else {
11282 palname = lives_strdup(weed_palette_get_name((sfile->bpp == 24 ? WEED_PALETTE_RGB24 : WEED_PALETTE_RGBA32)));
11283 }
11284 } else switch (sfile->clip_type) {
11285 case CLIP_TYPE_GENERATOR: {
11286 weed_plant_t *inst = (weed_plant_t *)sfile->ext_src;
11287 if (inst) {
11288 weed_plant_t *channel = get_enabled_channel(inst, 0, FALSE);
11289 if (channel) {
11290 int clamping, subspace, pal;
11291 pal = weed_channel_get_palette_yuv(channel, &clamping, NULL, &subspace);
11292 palname = lives_strdup(weed_palette_get_name_full(pal, clamping, subspace));
11293 }
11294 }
11295 }
11296 break;
11297 case CLIP_TYPE_VIDEODEV: {
11298 #ifdef HAVE_UNICAP
11299 lives_vdev_t *ldev = (lives_vdev_t *)sfile->ext_src;
11300 palname = lives_strdup(weed_palette_get_name_full(ldev->current_palette, ldev->YUV_clamping, 0));
11301 #endif
11302 }
11303 break;
11304 default: break;
11305 }
11306 if (!palname) palname = lives_strdup("??????");
11307 return palname;
11308 }
11309
11310
11311 boolean show_sync_callback(LiVESAccelGroup * group, LiVESWidgetObject * obj, uint32_t keyval, LiVESXModifierType mod,
11312 livespointer keybd) {
11313 if (!LIVES_IS_PLAYING) return FALSE;
11314 if (!CURRENT_CLIP_HAS_VIDEO || CURRENT_CLIP_IS_CLIPBOARD) return FALSE;
11315
11316 if (!prefs->show_dev_opts) {
11317 int last_dprint_file = mainw->last_dprint_file;
11318 mainw->no_switch_dprint = TRUE;
11319 d_print_overlay(2.0, _("Playing frame %d / %d, at fps %.3f\n"),
11320 mainw->actual_frame, cfile->frames, cfile->pb_fps);
11321 mainw->no_switch_dprint = FALSE;
11322 mainw->last_dprint_file = last_dprint_file;
11323 return FALSE;
11324 }
11325
11326 #ifdef USE_LIVES_MFUNCS
11327 show_memstats();
11328 #endif
11329
11330 lives_freep((void **)&mainw->overlay_msg);
11331
11332 if (!keybd) mainw->lockstats = !mainw->lockstats;
11333 if (!mainw->lockstats) return FALSE;
11334
11335 mainw->overlay_msg = get_stats_msg(FALSE);
11336 return FALSE;
11337 }
11338
11339 /**
11340 @brief jump to a stored clip / frame position during free playback
11341 clip number and frame position can be stored and later triggered
11342 during playback
11343 */
11344 boolean storeclip_callback(LiVESAccelGroup * group, LiVESWidgetObject * obj, uint32_t keyval, LiVESXModifierType mod,
11345 livespointer clip_number) {
11346 // ctrl-fn key will store a clip for higher switching
11347 int clip = LIVES_POINTER_TO_INT(clip_number) - 1;
11348 register int i;
11349
11350 if (!LIVES_IS_INTERACTIVE) return TRUE;
11351
11352 if (!CURRENT_CLIP_IS_VALID || mainw->preview || (LIVES_IS_PLAYING && mainw->event_list && !mainw->record)
11353 || (mainw->is_processing && cfile->is_loaded) || !mainw->cliplist) return TRUE;
11354
11355 if (clip >= FN_KEYS - 1) {
11356 // last fn key will clear all
11357 for (i = 0; i < FN_KEYS - 1; i++) {
11358 mainw->clipstore[i][0] = -1;
11359 }
11360 return TRUE;
11361 }
11362
11363 if (!IS_VALID_CLIP(mainw->clipstore[clip][0])) {
11364 mainw->clipstore[clip][0] = mainw->current_file;
11365 if (LIVES_IS_PLAYING) {
11366 mainw->clipstore[clip][1] = mainw->actual_frame;
11367 } else {
11368 int frame = calc_frame_from_time4(mainw->current_file, cfile->pointer_time);
11369 if (frame <= cfile->frames) mainw->clipstore[clip][1] = frame;
11370 else mainw->clipstore[clip][1] = 1;
11371 }
11372 } else {
11373 lives_clip_t *sfile = mainw->files[mainw->clipstore[clip][0]];
11374 if (LIVES_IS_PLAYING) {
11375 sfile->frameno = sfile->last_frameno = mainw->clipstore[clip][1];
11376 mainw->scratch = SCRATCH_JUMP;
11377 }
11378 if ((LIVES_IS_PLAYING && mainw->clipstore[clip][0] != mainw->playing_file)
11379 || (!LIVES_IS_PLAYING && mainw->clipstore[clip][0] != mainw->current_file)) {
11380 switch_clip(0, mainw->clipstore[clip][0], TRUE);
11381 }
11382 if (!LIVES_IS_PLAYING) {
11383 cfile->real_pointer_time = (mainw->clipstore[clip][1] - 1.) / cfile->fps;
11384 lives_ce_update_timeline(0, cfile->real_pointer_time);
11385 }
11386 if (mainw->loop_locked) unlock_loop_lock();
11387 }
11388 return TRUE;
11389 }
11390
11391
11392 void on_toolbar_hide(LiVESButton * button, livespointer user_data) {
11393 lives_widget_hide(mainw->tb_hbox);
11394 fullscreen_internal();
11395 prefs->show_tool = FALSE;
11396 set_boolean_pref(PREF_SHOW_TOOLBAR, FALSE);
11397 }
11398
11399
11400 void on_capture_activate(LiVESMenuItem * menuitem, livespointer user_data) {
11401 char **array;
11402 double rec_end_time = -1.;
11403 char *com;
11404 boolean sgui;
11405 int curr_file = mainw->current_file;
11406 LiVESResponseType response;
11407 mainw->mt_needs_idlefunc = FALSE;
11408
11409 #if !GTK_CHECK_VERSION(3, 0, 0)
11410 #ifndef GDK_WINDOWING_X11
11411 do_error_dialog(
11412 _("\n\nThis function will only work with X11.\nPlease send a patch to get it working on other platforms.\n\n"));
11413 return;
11414 #endif
11415 #endif
11416
11417 if (!capable->has_xwininfo) {
11418 do_error_dialog(_("\n\nYou must install \"xwininfo\" before you can use this feature\n\n"));
11419 return;
11420 }
11421
11422 if (mainw->first_free_file == ALL_USED) {
11423 too_many_files();
11424 return;
11425 }
11426
11427 if (mainw->multitrack) {
11428 if (mainw->multitrack->idlefunc > 0) {
11429 lives_source_remove(mainw->multitrack->idlefunc);
11430 mainw->multitrack->idlefunc = 0;
11431 mainw->mt_needs_idlefunc = TRUE;
11432 }
11433 mt_desensitise(mainw->multitrack);
11434 }
11435
11436 if (prefs->rec_desktop_audio && ((prefs->audio_player == AUD_PLAYER_JACK && capable->has_jackd) ||
11437 (prefs->audio_player == AUD_PLAYER_PULSE && capable->has_pulse_audio))) {
11438 resaudw = create_resaudw(8, NULL, NULL);
11439 } else {
11440 resaudw = create_resaudw(9, NULL, NULL);
11441 }
11442 response = lives_dialog_run(LIVES_DIALOG(resaudw->dialog));
11443
11444 if (response != LIVES_RESPONSE_OK) {
11445 lives_widget_destroy(resaudw->dialog);
11446
11447 if (mainw->multitrack) {
11448 mt_sensitise(mainw->multitrack);
11449 maybe_add_mt_idlefunc();
11450 }
11451 return;
11452 }
11453
11454 if (prefs->rec_desktop_audio && ((prefs->audio_player == AUD_PLAYER_JACK && capable->has_jackd) ||
11455 (prefs->audio_player == AUD_PLAYER_PULSE && capable->has_pulse_audio))) {
11456 mainw->rec_arate = (int)atoi(lives_entry_get_text(LIVES_ENTRY(resaudw->entry_arate)));
11457 mainw->rec_achans = (int)atoi(lives_entry_get_text(LIVES_ENTRY(resaudw->entry_achans)));
11458 mainw->rec_asamps = (int)atoi(lives_entry_get_text(LIVES_ENTRY(resaudw->entry_asamps)));
11459
11460 if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(resaudw->rb_unsigned))) {
11461 mainw->rec_signed_endian = AFORM_UNSIGNED;
11462 }
11463 if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(resaudw->rb_bigend))) {
11464 mainw->rec_signed_endian |= AFORM_BIG_ENDIAN;
11465 }
11466 } else {
11467 mainw->rec_arate = mainw->rec_achans = mainw->rec_asamps = mainw->rec_signed_endian = 0;
11468 }
11469
11470 mainw->rec_fps = lives_spin_button_get_value(LIVES_SPIN_BUTTON(resaudw->fps_spinbutton));
11471
11472 if (!lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(resaudw->unlim_radiobutton))) {
11473 rec_end_time = (lives_spin_button_get_value(LIVES_SPIN_BUTTON(resaudw->hour_spinbutton)) * 60.
11474 + lives_spin_button_get_value(LIVES_SPIN_BUTTON(resaudw->minute_spinbutton))) * 60.
11475 + lives_spin_button_get_value(LIVES_SPIN_BUTTON(resaudw->second_spinbutton));
11476 mainw->rec_vid_frames = (rec_end_time * mainw->rec_fps + .5);
11477 } else mainw->rec_vid_frames = -1;
11478
11479 lives_widget_destroy(resaudw->dialog);
11480 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
11481
11482 lives_freep((void **)&resaudw);
11483
11484 if (prefs->rec_desktop_audio && mainw->rec_arate <= 0 && ((prefs->audio_player == AUD_PLAYER_JACK && capable->has_jackd) ||
11485 (prefs->audio_player == AUD_PLAYER_PULSE && capable->has_pulse_audio))) {
11486 do_audrate_error_dialog();
11487 return;
11488 }
11489
11490 if (rec_end_time == 0.) {
11491 widget_opts.non_modal = TRUE;
11492 do_error_dialog(_("\nRecord time must be greater than 0.\n"));
11493 widget_opts.non_modal = FALSE;
11494 if (mainw->multitrack) {
11495 mt_sensitise(mainw->multitrack);
11496 maybe_add_mt_idlefunc();
11497 }
11498 return;
11499 }
11500
11501 lives_widget_hide(LIVES_MAIN_WINDOW_WIDGET);
11502 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
11503
11504 sgui = prefs->show_gui;
11505 prefs->show_gui = FALSE;
11506
11507 if (!(do_warning_dialog(
11508 _("Capture an External Window:\n\nClick on 'OK', then click on any desktop window to select it\n"
11509 "Click 'Cancel' to cancel\n\n")))) {
11510 if (sgui) {
11511 prefs->show_gui = TRUE;
11512 lives_widget_show(LIVES_MAIN_WINDOW_WIDGET);
11513 }
11514 d_print(_("External window was released.\n"));
11515 if (mainw->multitrack) {
11516 mt_sensitise(mainw->multitrack);
11517 maybe_add_mt_idlefunc();
11518 }
11519 return;
11520 }
11521
11522 prefs->show_gui = sgui;
11523
11524 // an example of using 'get_temp_handle()' ////////
11525 if (!get_temp_handle(-1)) {
11526 if (prefs->show_gui) {
11527 lives_widget_show(LIVES_MAIN_WINDOW_WIDGET);
11528 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
11529 }
11530
11531 if (mainw->multitrack) {
11532 mt_sensitise(mainw->multitrack);
11533 maybe_add_mt_idlefunc();
11534 }
11535 return;
11536 }
11537
11538 com = lives_strdup_printf("%s get_window_id \"%s\"", prefs->backend, cfile->handle);
11539 lives_system(com, FALSE);
11540 lives_free(com);
11541
11542 if (THREADVAR(com_failed)) {
11543 close_temp_handle(curr_file);
11544 if (prefs->show_gui) {
11545 lives_widget_show(LIVES_MAIN_WINDOW_WIDGET);
11546 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
11547 }
11548
11549 if (mainw->multitrack) {
11550 mt_sensitise(mainw->multitrack);
11551 maybe_add_mt_idlefunc();
11552 }
11553 return;
11554 }
11555
11556 do_progress_dialog(TRUE, FALSE, _("Click on any desktop window to capture it\n"
11557 "When a blank LiVES window appears behind it, "
11558 "then it is being recorded.\n\n"
11559 "<b><big>To end recording, switch focus to the LiVES window,\n"
11560 "and press the 'q' key.</big></b>\n"));
11561
11562 if (get_token_count(mainw->msg, '|') < 6) {
11563 close_temp_handle(curr_file);
11564 if (prefs->show_gui) {
11565 lives_widget_show(LIVES_MAIN_WINDOW_WIDGET);
11566 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
11567 }
11568
11569 if (mainw->multitrack) {
11570 mt_sensitise(mainw->multitrack);
11571 maybe_add_mt_idlefunc();
11572 }
11573 return;
11574 }
11575
11576 array = lives_strsplit(mainw->msg, "|", -1);
11577 #if IS_MINGW
11578 mainw->foreign_id = (HWND)atoi(array[1]);
11579 #else
11580 #if GTK_CHECK_VERSION(3, 0, 0) || defined GUI_QT
11581 mainw->foreign_id = (Window)atoi(array[1]);
11582 #else
11583 mainw->foreign_id = (GdkNativeWindow)atoi(array[1]);
11584 #endif
11585 #endif
11586 mainw->foreign_width = atoi(array[2]);
11587 mainw->foreign_height = atoi(array[3]);
11588 mainw->foreign_bpp = atoi(array[4]);
11589 mainw->foreign_visual = lives_strdup(array[5]);
11590 lives_strfreev(array);
11591
11592 close_temp_handle(curr_file);
11593
11594 ////////////////////////////////////////
11595
11596 d_print(_("\nExternal window captured. Width=%d, height=%d, bpp=%d. *Do not resize*\n\n"
11597 "Stop or 'q' to finish.\n(Default of %.3f frames per second will be used.)\n"),
11598 mainw->foreign_width, mainw->foreign_height, mainw->foreign_bpp, mainw->rec_fps);
11599
11600 // start another copy of LiVES and wait for it to return values
11601 com = lives_strdup_printf("%s -capture %d %u %d %d %s %d %d %.4f %d %d %d %d \"%s\"",
11602 capable->myname_full, capable->mainpid,
11603 (unsigned int)mainw->foreign_id, mainw->foreign_width, mainw->foreign_height,
11604 get_image_ext_for_type(IMG_TYPE_BEST),
11605 mainw->foreign_bpp, mainw->rec_vid_frames, mainw->rec_fps, mainw->rec_arate,
11606 mainw->rec_asamps, mainw->rec_achans, mainw->rec_signed_endian, mainw->foreign_visual);
11607
11608 // force the dialog to disappear
11609 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
11610
11611 lives_system(com, FALSE);
11612
11613 if (prefs->show_gui) {
11614 lives_widget_show(LIVES_MAIN_WINDOW_WIDGET);
11615 }
11616
11617 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
11618
11619 if (!after_foreign_play() && mainw->cancelled == CANCEL_NONE) {
11620 widget_opts.non_modal = TRUE;
11621 do_error_dialog(_("LiVES was unable to capture this window. Sorry.\n"));
11622 widget_opts.non_modal = FALSE;
11623 sensitize();
11624 }
11625
11626 if (mainw->multitrack) {
11627 polymorph(mainw->multitrack, POLY_NONE);
11628 polymorph(mainw->multitrack, POLY_CLIPS);
11629 mt_sensitise(mainw->multitrack);
11630 maybe_add_mt_idlefunc();
11631 }
11632 }
11633
11634
11635 void on_capture2_activate(void) {
11636 // this is in the second copy of lives, we are now going to grab frames from the X window
11637 char *capfilename = lives_strdup_printf(".capture.%d", mainw->foreign_key);
11638 char *capfile = lives_build_filename(prefs->workdir, capfilename, NULL);
11639
11640 char buf[32];
11641
11642 boolean retval;
11643 int capture_fd;
11644 register int i;
11645
11646 retval = prepare_to_play_foreign();
11647
11648 lives_freep((void **)&mainw->foreign_visual);
11649
11650 if (!retval) exit(2);
11651
11652 mainw->record_foreign = TRUE; // for now...
11653
11654 play_file();
11655
11656 // pass the handle and frames back to the caller
11657 capture_fd = creat(capfile, S_IRUSR | S_IWUSR);
11658 if (capture_fd < 0) {
11659 lives_free(capfile);
11660 exit(1);
11661 }
11662
11663 for (i = 1; i < MAX_FILES; i++) {
11664 if (!mainw->files[i]) break;
11665 lives_write(capture_fd, mainw->files[i]->handle, lives_strlen(mainw->files[i]->handle), TRUE);
11666 lives_write(capture_fd, "|", 1, TRUE);
11667 lives_snprintf(buf, 32, "%d", cfile->frames);
11668 lives_write(capture_fd, buf, strlen(buf), TRUE);
11669 lives_write(capture_fd, "|", 1, TRUE);
11670 }
11671
11672 close(capture_fd);
11673 lives_free(capfilename);
11674 lives_free(capfile);
11675 exit(0);
11676 }
11677
11678
11679 // TODO - move all encoder related stuff from here and plugins.c into encoders.c
11680 void on_encoder_ofmt_changed(LiVESCombo * combo, livespointer user_data) {
11681 // change encoder format in the encoder plugin
11682 render_details *rdet = (render_details *)user_data;
11683
11684 LiVESList *ofmt_all = NULL;
11685
11686 char **array;
11687 int counter, i;
11688 const char *new_fmt;
11689
11690 if (!rdet) {
11691 new_fmt = lives_combo_get_active_text(LIVES_COMBO(prefsw->ofmt_combo));
11692 } else {
11693 new_fmt = lives_combo_get_active_text(LIVES_COMBO(rdet->ofmt_combo));
11694 }
11695
11696 if (!strlen(new_fmt) || !strcmp(new_fmt, mainw->string_constants[LIVES_STRING_CONSTANT_ANY])) {
11697 return;
11698 }
11699
11700 if ((ofmt_all = plugin_request_by_line(PLUGIN_ENCODERS, future_prefs->encoder.name, "get_formats")) != NULL) {
11701 // get details for the current format
11702 counter = 0;
11703 for (i = 0; i < lives_list_length(ofmt_all); i++) {
11704 if (get_token_count((char *)lives_list_nth_data(ofmt_all, i), '|') > 2) {
11705 array = lives_strsplit((char *)lives_list_nth_data(ofmt_all, i), "|", -1);
11706
11707 if (!strcmp(array[1], new_fmt)) {
11708 if (prefsw) {
11709 lives_signal_handler_block(prefsw->ofmt_combo, prefsw->encoder_ofmt_fn);
11710 lives_combo_set_active_index(LIVES_COMBO(prefsw->ofmt_combo), counter);
11711 lives_signal_handler_unblock(prefsw->ofmt_combo, prefsw->encoder_ofmt_fn);
11712 }
11713 if (rdet) {
11714 lives_signal_handler_block(rdet->ofmt_combo, rdet->encoder_ofmt_fn);
11715 lives_combo_set_active_index(LIVES_COMBO(rdet->ofmt_combo), counter);
11716 lives_signal_handler_unblock(rdet->ofmt_combo, rdet->encoder_ofmt_fn);
11717 }
11718 lives_snprintf(future_prefs->encoder.of_name, 64, "%s", array[0]);
11719 lives_snprintf(future_prefs->encoder.of_desc, 128, "%s", array[1]);
11720
11721 future_prefs->encoder.of_allowed_acodecs = atoi(array[2]);
11722 lives_snprintf(future_prefs->encoder.of_restrict, 1024, "%s", array[3]);
11723 lives_strfreev(array);
11724 break;
11725 }
11726 lives_strfreev(array);
11727 counter++;
11728 }
11729 }
11730 lives_list_free_all(&ofmt_all);
11731
11732 if (rdet && !prefsw) {
11733 if (strcmp(prefs->encoder.of_name, future_prefs->encoder.of_name)) {
11734 rdet->enc_changed = TRUE;
11735 lives_snprintf(prefs->encoder.of_name, 64, "%s", future_prefs->encoder.of_name);
11736 lives_snprintf(prefs->encoder.of_desc, 128, "%s", future_prefs->encoder.of_desc);
11737 lives_snprintf(prefs->encoder.of_restrict, 1024, "%s", future_prefs->encoder.of_restrict);
11738 prefs->encoder.of_allowed_acodecs = future_prefs->encoder.of_allowed_acodecs;
11739 set_string_pref(PREF_OUTPUT_TYPE, prefs->encoder.of_name);
11740 }
11741 }
11742 set_acodec_list_from_allowed(prefsw, rdet);
11743 } else {
11744 do_plugin_encoder_error(future_prefs->encoder.name);
11745 }
11746 }
11747
11748 // TODO - move all this to audio.c
11749
11750 void on_export_audio_activate(LiVESMenuItem * menuitem, livespointer user_data) {
11751
11752 char *filt[] = {"*."LIVES_FILE_EXT_WAV, NULL};
11753 char *filename, *file_name;
11754 char *com, *tmp;
11755
11756 double start, end;
11757
11758 int nrate = cfile->arps;
11759 int asigned = !(cfile->signed_endian & AFORM_UNSIGNED);
11760
11761 if (cfile->end > 0 && !LIVES_POINTER_TO_INT(user_data)) {
11762 filename = choose_file((*mainw->audio_dir) ? mainw->audio_dir : NULL, NULL,
11763 filt, LIVES_FILE_CHOOSER_ACTION_SAVE, _("Export Selected Audio as..."), NULL);
11764 } else {
11765 filename = choose_file((*mainw->audio_dir) ? mainw->audio_dir : NULL, NULL,
11766 filt, LIVES_FILE_CHOOSER_ACTION_SAVE, _("Export Audio as..."), NULL);
11767 }
11768
11769 if (!filename) return;
11770 file_name = ensure_extension(filename, LIVES_FILE_EXT_WAV);
11771 lives_free(filename);
11772
11773 // warn if arps!=arate
11774 if (cfile->arate != cfile->arps) {
11775 if (do_warning_dialog(
11776 _("\n\nThe audio playback speed has been altered for this clip.\nClick 'OK' to export at the new speed, "
11777 "or 'Cancel' to export at the original rate.\n"))) {
11778 nrate = cfile->arate;
11779 }
11780 }
11781
11782 if (cfile->start * cfile->end > 0 && !LIVES_POINTER_TO_INT(user_data)) {
11783 lives_snprintf(mainw->msg, MAINW_MSG_SIZE, _("Exporting audio frames %d to %d as %s..."), cfile->start, cfile->end, file_name);
11784 start = calc_time_from_frame(mainw->current_file, cfile->start);
11785 end = calc_time_from_frame(mainw->current_file, cfile->end);
11786 } else {
11787 lives_snprintf(mainw->msg, MAINW_MSG_SIZE, _("Exporting audio as %s..."), file_name);
11788 start = 0.;
11789 end = 0.;
11790 }
11791
11792 d_print(mainw->msg);
11793
11794 com = lives_strdup_printf("%s export_audio \"%s\" %.8f %.8f %d %d %d %d %d \"%s\"", prefs->backend, cfile->handle,
11795 start, end, cfile->arps, cfile->achans, cfile->asampsize, asigned, nrate,
11796 (tmp = lives_filename_from_utf8(file_name, -1, NULL, NULL, NULL)));
11797 lives_free(tmp);
11798
11799 lives_rm(cfile->info_file);
11800 lives_system(com, FALSE);
11801 lives_free(com);
11802
11803 if (THREADVAR(com_failed)) {
11804 lives_free(file_name);
11805 d_print_failed();
11806 return;
11807 }
11808
11809 do_progress_dialog(TRUE, FALSE, _("Exporting audio"));
11810
11811 if (mainw->error) {
11812 d_print_failed();
11813 widget_opts.non_modal = TRUE;
11814 do_error_dialog(mainw->msg);
11815 widget_opts.non_modal = FALSE;
11816 } else {
11817 d_print_done();
11818 lives_snprintf(mainw->audio_dir, PATH_MAX, "%s", file_name);
11819 get_dirname(mainw->audio_dir);
11820 }
11821 lives_free(file_name);
11822 }
11823
11824
11825 void on_normalise_audio_activate(LiVESMenuItem * menuitem, livespointer user_data) {
11826 char *com;
11827
11828 if (!CURRENT_CLIP_HAS_AUDIO) return;
11829
11830 d_print(_("Normalising audio..."));
11831
11832 if (menuitem) desensitize();
11833 do_threaded_dialog(_("Normalizing audio..."), TRUE);
11834
11835 threaded_dialog_spin(0.);
11836
11837 if (!prefs->conserve_space) {
11838 com = lives_strdup_printf("%s backup_audio \"%s\"", prefs->backend_sync, cfile->handle);
11839 lives_system(com, FALSE);
11840 lives_free(com);
11841 if (THREADVAR(com_failed)) {
11842 end_threaded_dialog();
11843 d_print_failed();
11844 if (menuitem) sensitize();
11845 return;
11846 }
11847 }
11848 normalise_audio(mainw->current_file, 0., 0., .95);
11849
11850 if (THREADVAR(write_failed) || THREADVAR(read_failed)) {
11851 THREADVAR(read_failed) = THREADVAR(write_failed) = 0;
11852 end_threaded_dialog();
11853 d_print_failed();
11854 if (menuitem) sensitize();
11855 return;
11856 }
11857
11858 if (mainw->cancelled != CANCEL_NONE) {
11859 com = lives_strdup_printf("%s undo_audio \"%s\"", prefs->backend_sync, cfile->handle);
11860 mainw->cancelled = CANCEL_NONE;
11861 lives_system(com, FALSE);
11862 lives_free(com);
11863 end_threaded_dialog();
11864 d_print_cancelled();
11865 if (menuitem) sensitize();
11866 return;
11867 }
11868
11869 if (menuitem) cfile->changed = TRUE;
11870 reget_afilesize(mainw->current_file);
11871
11872 if (!prefs->conserve_space) {
11873 set_undoable(_("Normalise audio"), TRUE);
11874 cfile->undo_action = UNDO_AUDIO_VOL;
11875 }
11876 if (menuitem) sensitize();
11877 end_threaded_dialog();
11878 d_print_done();
11879 }
11880
11881
11882 void on_append_audio_activate(LiVESMenuItem * menuitem, livespointer user_data) {
11883 LiVESWidget *chooser;
11884
11885 char *filt[] = LIVES_AUDIO_LOAD_FILTER;
11886
11887 char *com, *tmp, *tmp2;
11888 char *a_type;
11889
11890 uint32_t chk_mask = WARN_MASK_LAYOUT_ALTER_AUDIO;
11891
11892 boolean gotit = FALSE;
11893
11894 int asigned = !(cfile->signed_endian & AFORM_UNSIGNED);
11895 int aendian = !(cfile->signed_endian & AFORM_BIG_ENDIAN);
11896
11897 int resp;
11898
11899 register int i;
11900
11901 if (!CURRENT_CLIP_IS_VALID) return;
11902
11903 if (!check_for_layout_errors(NULL, mainw->current_file, 1, 0, &chk_mask)) {
11904 return;
11905 }
11906
11907 chooser = choose_file_with_preview((*mainw->audio_dir) ? mainw->audio_dir : NULL, _("Append Audio File"), filt,
11908 LIVES_FILE_SELECTION_AUDIO_ONLY);
11909
11910 resp = lives_dialog_run(LIVES_DIALOG(chooser));
11911
11912 end_fs_preview();
11913
11914 if (resp != LIVES_RESPONSE_ACCEPT) {
11915 on_filechooser_cancel_clicked(chooser);
11916 unbuffer_lmap_errors(FALSE);
11917 return;
11918 }
11919
11920 lives_snprintf(file_name, PATH_MAX, "%s",
11921 (tmp = lives_filename_to_utf8((tmp2 = lives_file_chooser_get_filename(LIVES_FILE_CHOOSER(
11922 chooser))),
11923 -1, NULL, NULL, NULL)));
11924 lives_free(tmp);
11925 lives_free(tmp2);
11926
11927 lives_widget_destroy(LIVES_WIDGET(chooser));
11928
11929 lives_widget_queue_draw_and_update(LIVES_MAIN_WINDOW_WIDGET);
11930
11931 lives_snprintf(mainw->audio_dir, PATH_MAX, "%s", file_name);
11932 get_dirname(mainw->audio_dir);
11933
11934 a_type = get_extension(file_name);
11935
11936 if (strlen(a_type)) {
11937 char *filt[] = LIVES_AUDIO_LOAD_FILTER;
11938 for (i = 0; filt[i]; i++) {
11939 if (!lives_ascii_strcasecmp(a_type, filt[i] + 2)) gotit = TRUE; // skip past "*." in filt
11940 }
11941 }
11942
11943 if (gotit) {
11944 com = lives_strdup_printf("%s append_audio \"%s\" \"%s\" %d %d %d %d %d \"%s\"", prefs->backend, cfile->handle,
11945 a_type, cfile->arate,
11946 cfile->achans, cfile->asampsize, asigned, aendian,
11947 (tmp = lives_filename_from_utf8(file_name, -1, NULL, NULL, NULL)));
11948 lives_free(tmp);
11949 } else {
11950 lives_free(a_type);
11951 do_audio_import_error();
11952 if (mainw->multitrack) {
11953 mt_sensitise(mainw->multitrack);
11954 maybe_add_mt_idlefunc();
11955 }
11956 unbuffer_lmap_errors(FALSE);
11957 return;
11958 }
11959
11960 lives_free(a_type);
11961
11962 lives_snprintf(mainw->msg, MAINW_MSG_SIZE, _("Appending audio file %s..."), file_name);
11963 d_print(""); // force switchtext
11964 d_print(mainw->msg);
11965
11966 lives_rm(cfile->info_file);
11967 lives_system(com, FALSE);
11968 lives_free(com);
11969
11970 if (THREADVAR(com_failed)) {
11971 if (mainw->multitrack) {
11972 mt_sensitise(mainw->multitrack);
11973 maybe_add_mt_idlefunc();
11974 }
11975 unbuffer_lmap_errors(FALSE);
11976 return;
11977 }
11978
11979 if (!do_progress_dialog(TRUE, TRUE, _("Appending audio"))) {
11980 lives_widget_queue_draw_and_update(LIVES_MAIN_WINDOW_WIDGET);
11981
11982 mainw->cancelled = CANCEL_NONE;
11983 mainw->error = FALSE;
11984 lives_rm(cfile->info_file);
11985 com = lives_strdup_printf("%s cancel_audio \"%s\"", prefs->backend, cfile->handle);
11986 lives_system(com, FALSE);
11987 if (!THREADVAR(com_failed)) {
11988 do_auto_dialog(_("Cancelling"), 0);
11989 check_backend_return(cfile);
11990 }
11991 lives_free(com);
11992 reget_afilesize(mainw->current_file);
11993 if (mainw->error) d_print_failed();
11994 if (mainw->multitrack) {
11995 mt_sensitise(mainw->multitrack);
11996 maybe_add_mt_idlefunc();
11997 }
11998 unbuffer_lmap_errors(FALSE);
11999 return;
12000 }
12001
12002 if (mainw->error) {
12003 d_print_failed();
12004 widget_opts.non_modal = TRUE;
12005 do_error_dialog(mainw->msg);
12006 widget_opts.non_modal = FALSE;
12007 } else {
12008 lives_widget_queue_draw_and_update(LIVES_MAIN_WINDOW_WIDGET);
12009
12010 com = lives_strdup_printf("%s commit_audio \"%s\"", prefs->backend, cfile->handle);
12011 mainw->cancelled = CANCEL_NONE;
12012 mainw->error = FALSE;
12013 lives_rm(cfile->info_file);
12014 lives_system(com, FALSE);
12015 lives_free(com);
12016
12017 if (THREADVAR(com_failed)) {
12018 d_print_failed();
12019 if (mainw->multitrack) {
12020 mt_sensitise(mainw->multitrack);
12021 maybe_add_mt_idlefunc();
12022 }
12023 unbuffer_lmap_errors(FALSE);
12024 return;
12025 }
12026
12027 do_auto_dialog(_("Committing audio"), 0);
12028 check_backend_return(cfile);
12029 if (mainw->error) {
12030 d_print_failed();
12031 widget_opts.non_modal = TRUE;
12032 if (mainw->cancelled != CANCEL_ERROR) do_error_dialog(mainw->msg);
12033 widget_opts.non_modal = FALSE;
12034 } else {
12035 get_dirname(file_name);
12036 lives_snprintf(mainw->audio_dir, PATH_MAX, "%s", file_name);
12037 reget_afilesize(mainw->current_file);
12038 cfile->changed = TRUE;
12039 d_print_done();
12040 }
12041 }
12042 cfile->undo_action = UNDO_APPEND_AUDIO;
12043 set_undoable(_("Append Audio"), !prefs->conserve_space);
12044
12045 if (mainw->multitrack) {
12046 mt_sensitise(mainw->multitrack);
12047 maybe_add_mt_idlefunc();
12048 }
12049 if (chk_mask != 0) popup_lmap_errors(NULL, LIVES_INT_TO_POINTER(chk_mask));
12050 }
12051
12052
12053 boolean on_trim_audio_activate(LiVESMenuItem * menuitem, livespointer user_data) {
12054 // type 0 == trim selected
12055 // type 1 == trim to play pointer
12056
12057 char *com, *msg, *tmp;
12058
12059 double start, end;
12060
12061 uint32_t chk_mask = WARN_MASK_LAYOUT_DELETE_AUDIO | WARN_MASK_LAYOUT_ALTER_AUDIO;
12062
12063 int type = LIVES_POINTER_TO_INT(user_data);
12064
12065 if (!CURRENT_CLIP_IS_VALID) return FALSE;
12066
12067 if (type == 0) {
12068 start = calc_time_from_frame(mainw->current_file, cfile->start);
12069 end = calc_time_from_frame(mainw->current_file, cfile->end + 1);
12070 } else {
12071 start = 0.;
12072 end = cfile->pointer_time;
12073 }
12074
12075 tmp = (_("Deletion"));
12076 if (!check_for_layout_errors(tmp, mainw->current_file, calc_frame_from_time(mainw->current_file, start),
12077 calc_frame_from_time(mainw->current_file, end), &chk_mask)) {
12078 lives_free(tmp);
12079 return FALSE;
12080 }
12081 lives_free(tmp);
12082
12083 if (end > cfile->laudio_time && end > cfile->raudio_time)
12084 msg = lives_strdup_printf(_("Padding audio to %.2f seconds..."), end);
12085 else
12086 msg = lives_strdup_printf(_("Trimming audio from %.2f to %.2f seconds..."), start, end);
12087
12088 d_print(msg);
12089 lives_free(msg);
12090
12091 com = lives_strdup_printf("%s trim_audio \"%s\" %.8f %.8f %d %d %d %d %d", prefs->backend, cfile->handle,
12092 start, end, cfile->arate,
12093 cfile->achans, cfile->asampsize, !(cfile->signed_endian & AFORM_UNSIGNED),
12094 !(cfile->signed_endian & AFORM_BIG_ENDIAN));
12095 lives_rm(cfile->info_file);
12096 lives_system(com, FALSE);
12097 lives_free(com);
12098
12099 if (THREADVAR(com_failed)) {
12100 unbuffer_lmap_errors(FALSE);
12101 d_print_failed();
12102 return FALSE;
12103 }
12104
12105 do_progress_dialog(TRUE, FALSE, _("Trimming/Padding audio"));
12106
12107 if (mainw->error) {
12108 d_print_failed();
12109 unbuffer_lmap_errors(FALSE);
12110 return FALSE;
12111 }
12112
12113 if (!prefs->conserve_space) {
12114 set_undoable(_("Trim/Pad Audio"), !prefs->conserve_space);
12115 cfile->undo_action = UNDO_TRIM_AUDIO;
12116 }
12117
12118 reget_afilesize(mainw->current_file);
12119 cfile->changed = TRUE;
12120 d_print_done();
12121
12122 if (mainw->sl_undo_mem && cfile->stored_layout_audio != 0.) {
12123 // need to invalidate undo/redo stack, in case file was used in some layout undo
12124 stored_event_list_free_undos();
12125 }
12126
12127 if (chk_mask != 0) popup_lmap_errors(NULL, LIVES_INT_TO_POINTER(chk_mask));
12128 return TRUE;
12129 }
12130
12131 void on_voladj_activate(LiVESMenuItem * menuitem, livespointer user_data) {create_new_pb_speed(3);}
12132
12133 void on_fade_audio_activate(LiVESMenuItem * menuitem, livespointer user_data) {
12134 // type == 0 fade in
12135 // type == 1 fade out
12136
12137 double startt, endt, startv, endv, time = 0.;
12138 char *msg, *msg2, *utxt, *com;
12139
12140 uint32_t chk_mask = 0;
12141
12142 lives_alarm_t alarm_handle;
12143 int type;
12144
12145 aud_dialog_t *aud_d = NULL;
12146
12147 if (!CURRENT_CLIP_IS_VALID) return;
12148
12149 if (menuitem) {
12150 cfile->undo1_int = type = LIVES_POINTER_TO_INT(user_data);
12151 aud_d = create_audfade_dialog(type);
12152 if (lives_dialog_run(LIVES_DIALOG(aud_d->dialog)) == LIVES_RESPONSE_CANCEL) {
12153 lives_free(aud_d);
12154 return;
12155 }
12156
12157 time = lives_spin_button_get_value(LIVES_SPIN_BUTTON(aud_d->time_spin));
12158
12159 lives_widget_destroy(aud_d->dialog);
12160 } else {
12161 type = cfile->undo1_int;
12162 }
12163
12164 if (!menuitem || !aud_d->is_sel) {
12165 if (!menuitem) {
12166 endt = cfile->undo1_dbl;
12167 startt = cfile->undo2_dbl;
12168 } else {
12169 if (type == 0) {
12170 cfile->undo2_dbl = startt = 0.;
12171 cfile->undo1_dbl = endt = time;
12172 } else {
12173 cfile->undo1_dbl = endt = cfile->laudio_time;
12174 cfile->undo2_dbl = startt = cfile->laudio_time - time;
12175 }
12176 }
12177 } else {
12178 cfile->undo2_dbl = startt = ((double)cfile->start - 1.) / cfile->fps;
12179 cfile->undo1_dbl = endt = (double)cfile->end / cfile->fps;
12180 }
12181
12182 if (type == 0) {
12183 startv = 0.;
12184 endv = 1.;
12185 msg2 = (_("Fading audio in"));
12186 utxt = (_("Fade audio in"));
12187 } else {
12188 startv = 1.;
12189 endv = 0.;
12190 msg2 = (_("Fading audio out"));
12191 utxt = (_("Fade audio out"));
12192 }
12193
12194 if (menuitem) {
12195 chk_mask = WARN_MASK_LAYOUT_ALTER_AUDIO;
12196 if (!check_for_layout_errors(NULL, mainw->current_file, 1, 0, &chk_mask)) {
12197 return;
12198 }
12199
12200 if (!aud_d->is_sel)
12201 msg = lives_strdup_printf(_("%s over %.1f seconds..."), msg2, time);
12202 else
12203 msg = lives_strdup_printf(_("%s from time %.2f seconds to %.2f seconds..."), msg2, startt, endt);
12204 d_print(msg);
12205 lives_free(msg);
12206 lives_free(msg2);
12207 }
12208
12209 desensitize();
12210 do_threaded_dialog(_("Fading audio..."), FALSE);
12211 alarm_handle = lives_alarm_set(LIVES_SHORTEST_TIMEOUT);
12212
12213 threaded_dialog_spin(0.);
12214 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
12215
12216 if (!prefs->conserve_space) {
12217 com = lives_strdup_printf("%s backup_audio \"%s\"", prefs->backend_sync, cfile->handle);
12218 lives_system(com, FALSE);
12219 lives_free(com);
12220
12221 if (THREADVAR(com_failed)) {
12222 lives_alarm_clear(alarm_handle);
12223 end_threaded_dialog();
12224 d_print_failed();
12225 sensitize();
12226 unbuffer_lmap_errors(FALSE);
12227 return;
12228 }
12229 }
12230
12231 aud_fade(mainw->current_file, startt, endt, startv, endv);
12232 audio_free_fnames();
12233
12234 while (lives_alarm_check(alarm_handle) > 0) {
12235 lives_usleep(prefs->sleep_time);
12236 }
12237
12238 lives_alarm_clear(alarm_handle);
12239
12240 end_threaded_dialog();
12241 d_print_done();
12242
12243 cfile->changed = TRUE;
12244 reget_afilesize(mainw->current_file);
12245
12246 if (!prefs->conserve_space) {
12247 set_undoable(utxt, TRUE);
12248 cfile->undo_action = UNDO_FADE_AUDIO;
12249 }
12250 lives_free(utxt);
12251 sensitize();
12252
12253 lives_freep((void **)&aud_d);
12254 if (chk_mask != 0) popup_lmap_errors(NULL, LIVES_INT_TO_POINTER(chk_mask));
12255 }
12256
12257
12258 boolean on_del_audio_activate(LiVESMenuItem * menuitem, livespointer user_data) {
12259 double start, end;
12260 char *com, *tmp, *msg = NULL;
12261
12262 uint32_t chk_mask = 0;
12263
12264 boolean bad_header = FALSE;
12265
12266 int i;
12267
12268 if (!CURRENT_CLIP_IS_VALID) return FALSE;
12269
12270 if (!menuitem) {
12271 // undo/redo
12272 start = cfile->undo1_dbl;
12273 end = cfile->undo2_dbl;
12274 } else {
12275 if (LIVES_POINTER_TO_INT(user_data)) {
12276 tmp = (_("Deleting all audio"));
12277 chk_mask = WARN_MASK_LAYOUT_DELETE_AUDIO | WARN_MASK_LAYOUT_ALTER_AUDIO;
12278 if (!check_for_layout_errors(tmp, mainw->current_file, 1, 0, &chk_mask)) {
12279 lives_free(tmp);
12280 return FALSE;
12281 }
12282 lives_free(tmp);
12283
12284 if (!CURRENT_CLIP_HAS_VIDEO) {
12285 if (do_warning_dialog(_("\nDeleting all audio will close this file.\nAre you sure ?"))) close_current_file(0);
12286 unbuffer_lmap_errors(FALSE);
12287 return FALSE;
12288 }
12289 msg = (_("Deleting all audio..."));
12290 start = end = 0.;
12291 } else {
12292 start = calc_time_from_frame(mainw->current_file, cfile->start);
12293 end = calc_time_from_frame(mainw->current_file, cfile->end + 1);
12294 msg = lives_strdup_printf(_("Deleting audio from %.2f to %.2f seconds..."), start, end);
12295 start *= (double)cfile->arate / (double)cfile->arps;
12296 end *= (double)cfile->arate / (double)cfile->arps;
12297
12298 tmp = (_("Deleting audio"));
12299 chk_mask = WARN_MASK_LAYOUT_DELETE_AUDIO | WARN_MASK_LAYOUT_ALTER_AUDIO;
12300 if (!check_for_layout_errors(tmp, mainw->current_file, 1, 0, &chk_mask)) {
12301 lives_free(tmp);
12302 return FALSE;
12303 }
12304 }
12305
12306 cfile->undo1_dbl = start;
12307 cfile->undo2_dbl = end;
12308 }
12309
12310 cfile->undo_arate = cfile->arate;
12311 cfile->undo_signed_endian = cfile->signed_endian;
12312 cfile->undo_achans = cfile->achans;
12313 cfile->undo_asampsize = cfile->asampsize;
12314 cfile->undo_arps = cfile->arps;
12315
12316 if (msg) {
12317 d_print("");
12318 d_print(msg);
12319 lives_free(msg);
12320 }
12321
12322 com = lives_strdup_printf("%s delete_audio \"%s\" %.8f %.8f %d %d %d", prefs->backend,
12323 cfile->handle, start, end, cfile->arps,
12324 cfile->achans, cfile->asampsize);
12325 lives_rm(cfile->info_file);
12326 lives_system(com, FALSE);
12327 lives_free(com);
12328
12329 if (THREADVAR(com_failed)) {
12330 if (menuitem) d_print_failed();
12331 unbuffer_lmap_errors(FALSE);
12332 return FALSE;
12333 }
12334
12335 do_progress_dialog(TRUE, FALSE, _("Deleting Audio"));
12336
12337 if (mainw->error) {
12338 if (menuitem) d_print_failed();
12339 unbuffer_lmap_errors(FALSE);
12340 return FALSE;
12341 }
12342
12343 set_undoable(_("Delete Audio"), TRUE);
12344 cfile->undo_action = UNDO_DELETE_AUDIO;
12345
12346 reget_afilesize(mainw->current_file);
12347 cfile->changed = TRUE;
12348 sensitize();
12349
12350 if (cfile->laudio_time == 0. || cfile->raudio_time == 0.) {
12351 if (cfile->audio_waveform) {
12352 for (i = 0; i < cfile->achans; lives_freep((void **)&cfile->audio_waveform[i++]));
12353 lives_freep((void **)&cfile->audio_waveform);
12354 lives_freep((void **)&cfile->aw_sizes);
12355 }
12356 if (cfile->laudio_time == cfile->raudio_time) cfile->achans = 0;
12357 else cfile->achans = 1;
12358 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ACHANS, &cfile->achans)) bad_header = TRUE;
12359
12360 if (bad_header) do_header_write_error(mainw->current_file);
12361 }
12362
12363 if (menuitem) {
12364 d_print_done();
12365 }
12366
12367 if (mainw->sl_undo_mem && cfile->stored_layout_audio != 0.) {
12368 // need to invalidate undo/redo stack, in case file was used in some layout undo
12369 stored_event_list_free_undos();
12370 }
12371
12372 if (chk_mask != 0) popup_lmap_errors(NULL, LIVES_INT_TO_POINTER(chk_mask));
12373
12374 return TRUE;
12375 }
12376
12377
12378 void on_rb_audrec_time_toggled(LiVESToggleButton * togglebutton, livespointer user_data) {
12379 _resaudw *resaudw = (_resaudw *)user_data;
12380 if (!resaudw) return;
12381 if (lives_toggle_button_get_active(togglebutton)) {
12382 lives_widget_set_sensitive(resaudw->hour_spinbutton, TRUE);
12383 lives_widget_set_sensitive(resaudw->minute_spinbutton, TRUE);
12384 lives_widget_set_sensitive(resaudw->second_spinbutton, TRUE);
12385 } else {
12386 lives_widget_set_sensitive(resaudw->hour_spinbutton, FALSE);
12387 lives_widget_set_sensitive(resaudw->minute_spinbutton, FALSE);
12388 lives_widget_set_sensitive(resaudw->second_spinbutton, FALSE);
12389 }
12390 }
12391
12392
12393 void on_recaudclip_activate(LiVESMenuItem * menuitem, livespointer user_data) {
12394 if (!is_realtime_aplayer(prefs->audio_player)) {
12395 do_nojack_rec_error();
12396 return;
12397 }
12398
12399 mainw->fx1_val = DEFAULT_AUDIO_RATE;
12400 mainw->fx2_val = DEFAULT_AUDIO_CHANS;
12401 mainw->fx3_val = DEFAULT_AUDIO_SAMPS;
12402 mainw->fx4_val = mainw->endian;
12403 mainw->rec_end_time = -1.;
12404 resaudw = create_resaudw(5, NULL, NULL);
12405 lives_widget_show(resaudw->dialog);
12406 }
12407
12408 static uint32_t lmap_error_recsel;
12409
12410 void on_recaudsel_activate(LiVESMenuItem * menuitem, livespointer user_data) {
12411 uint32_t chk_mask = WARN_MASK_LAYOUT_ALTER_AUDIO;
12412
12413 lmap_error_recsel = 0;
12414
12415 if (!CURRENT_CLIP_IS_VALID) return;
12416 if (!is_realtime_aplayer(prefs->audio_player)) {
12417 do_nojack_rec_error();
12418 return;
12419 }
12420
12421 if (!check_for_layout_errors(NULL, mainw->current_file, 1, 0, &chk_mask)) {
12422 return;
12423 }
12424
12425 lmap_error_recsel = chk_mask;
12426
12427 mainw->rec_end_time = (cfile->end - cfile->start + 1.) / cfile->fps;
12428
12429 if (cfile->achans > 0) {
12430 mainw->fx1_val = cfile->arate;
12431 mainw->fx2_val = cfile->achans;
12432 mainw->fx3_val = cfile->asampsize;
12433 mainw->fx4_val = cfile->signed_endian;
12434 resaudw = create_resaudw(7, NULL, NULL);
12435 } else {
12436 mainw->fx1_val = DEFAULT_AUDIO_RATE;
12437 mainw->fx2_val = DEFAULT_AUDIO_CHANS;
12438 mainw->fx3_val = DEFAULT_AUDIO_SAMPS;
12439 mainw->fx4_val = mainw->endian;
12440 resaudw = create_resaudw(6, NULL, NULL);
12441 }
12442 lives_widget_show_all(resaudw->dialog);
12443 }
12444
12445
12446 void on_recaudclip_ok_clicked(LiVESButton * button, livespointer user_data) {
12447 #ifdef RT_AUDIO
12448 ticks_t ins_pt;
12449 double aud_start, aud_end, vel = 1., vol = 1.;
12450
12451 uint32_t chk_mask;
12452
12453 boolean backr = FALSE;
12454
12455 int asigned = 1, aendian = 1;
12456 int old_file = mainw->current_file, new_file;
12457 int type = LIVES_POINTER_TO_INT(user_data);
12458 int oachans = 0, oarate = 0, oarps = 0, ose = 0, oasamps = 0;
12459
12460 char *com;
12461
12462 // type == 0 - new clip
12463 // type == 1 - existing clip
12464
12465 if (type == 1) d_print(""); // show switch message, if appropriate
12466
12467 mainw->current_file = mainw->first_free_file;
12468 if (!get_new_handle(mainw->current_file, NULL)) {
12469 mainw->current_file = old_file;
12470 return;
12471 }
12472
12473 cfile->is_loaded = TRUE;
12474 cfile->img_type = IMG_TYPE_BEST; // override the pref
12475
12476 cfile->arps = cfile->arate = (int)atoi(lives_entry_get_text(LIVES_ENTRY(resaudw->entry_arate)));
12477 cfile->achans = (int)atoi(lives_entry_get_text(LIVES_ENTRY(resaudw->entry_achans)));
12478 cfile->asampsize = (int)atoi(lives_entry_get_text(LIVES_ENTRY(resaudw->entry_asamps)));
12479
12480 mainw->rec_samples = -1;
12481 mainw->rec_end_time = -1.;
12482
12483 if (type == 0) {
12484 if (!lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(resaudw->unlim_radiobutton))) {
12485 mainw->rec_end_time = (lives_spin_button_get_value(LIVES_SPIN_BUTTON(resaudw->hour_spinbutton)) * 60.
12486 + lives_spin_button_get_value(LIVES_SPIN_BUTTON(resaudw->minute_spinbutton))) * 60.
12487 + lives_spin_button_get_value(LIVES_SPIN_BUTTON(resaudw->second_spinbutton));
12488 mainw->rec_samples = mainw->rec_end_time * cfile->arate;
12489 }
12490 }
12491
12492 if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(resaudw->rb_unsigned))) {
12493 asigned = 0;
12494 }
12495 if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(resaudw->rb_bigend))) {
12496 aendian = 0;
12497 }
12498
12499 mainw->is_processing = TRUE;
12500
12501 cfile->signed_endian = get_signed_endian(asigned, aendian);
12502 lives_widget_destroy(resaudw->dialog);
12503 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
12504
12505 lives_freep((void **)&resaudw);
12506
12507 if (cfile->arate <= 0) {
12508 do_audrate_error_dialog();
12509 mainw->is_processing = FALSE;
12510 close_temp_handle(old_file);
12511 return;
12512 }
12513
12514 if (mainw->rec_end_time == 0.) {
12515 widget_opts.non_modal = TRUE;
12516 do_error_dialog(_("\nRecord time must be greater than 0.\n"));
12517 widget_opts.non_modal = FALSE;
12518 mainw->is_processing = FALSE;
12519 close_temp_handle(old_file);
12520 return;
12521 }
12522
12523 asigned = !asigned;
12524
12525 if (type == 0) {
12526 lives_snprintf(cfile->type, 40, "Audio");
12527 add_to_clipmenu();
12528
12529 lives_notify(LIVES_OSC_NOTIFY_CLIP_OPENED, "");
12530 }
12531
12532 mainw->effects_paused = FALSE;
12533
12534 if (type == 1) {
12535 oachans = mainw->files[old_file]->achans;
12536 oarate = mainw->files[old_file]->arate;
12537 oarps = mainw->files[old_file]->arps;
12538 oasamps = mainw->files[old_file]->asampsize;
12539 ose = mainw->files[old_file]->signed_endian;
12540
12541 mainw->files[old_file]->arate = mainw->files[old_file]->arps = cfile->arate;
12542 mainw->files[old_file]->asampsize = cfile->asampsize;
12543 mainw->files[old_file]->achans = cfile->achans;
12544 mainw->files[old_file]->signed_endian = cfile->signed_endian;
12545 }
12546
12547 mainw->suppress_dprint = TRUE;
12548 mainw->no_switch_dprint = TRUE;
12549
12550 #ifdef ENABLE_JACK
12551 if (prefs->audio_player == AUD_PLAYER_JACK) {
12552 jack_rec_audio_to_clip(mainw->current_file, old_file, type == 0 ? RECA_NEW_CLIP : RECA_EXISTING);
12553 }
12554 #endif
12555 #ifdef HAVE_PULSE_AUDIO
12556 if (prefs->audio_player == AUD_PLAYER_PULSE) {
12557 pulse_rec_audio_to_clip(mainw->current_file, old_file, type == 0 ? RECA_NEW_CLIP : RECA_EXISTING);
12558 }
12559 #endif
12560
12561 if (type == 1) {
12562 // set these again, as playsel may have reset them
12563 mainw->files[old_file]->arate = mainw->files[old_file]->arps = cfile->arate;
12564 mainw->files[old_file]->asampsize = cfile->asampsize;
12565 mainw->files[old_file]->achans = cfile->achans;
12566 mainw->files[old_file]->signed_endian = cfile->signed_endian;
12567 }
12568
12569 if (type != 1 && mainw->cancelled == CANCEL_USER) {
12570 mainw->cancelled = CANCEL_NONE;
12571 if (type == 1) {
12572 mainw->files[old_file]->arps = oarps;
12573 mainw->files[old_file]->arate = oarate;
12574 mainw->files[old_file]->achans = oachans;
12575 mainw->files[old_file]->asampsize = oasamps;
12576 mainw->files[old_file]->signed_endian = ose;
12577 }
12578 mainw->is_processing = FALSE;
12579 close_temp_handle(old_file);
12580 mainw->suppress_dprint = FALSE;
12581 d_print_cancelled();
12582 mainw->no_switch_dprint = FALSE;
12583 return;
12584 }
12585
12586 mainw->cancelled = CANCEL_NONE;
12587 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
12588
12589 if (type == 1) {
12590 // set these again in case reget_afilesize() reset them
12591 cfile->arate = cfile->arps = mainw->files[old_file]->arate;
12592 cfile->asampsize = mainw->files[old_file]->asampsize;
12593 cfile->achans = mainw->files[old_file]->achans;
12594 cfile->signed_endian = mainw->files[old_file]->signed_endian;
12595
12596 do_threaded_dialog(_("Committing audio"), FALSE);
12597 aud_start = 0.;
12598 reget_afilesize(mainw->current_file);
12599 aud_end = cfile->laudio_time;
12600
12601 if (aud_end == 0.) {
12602 end_threaded_dialog();
12603 close_temp_handle(old_file);
12604 mainw->suppress_dprint = FALSE;
12605 d_print("nothing recorded...");
12606 d_print_failed();
12607 return;
12608 }
12609
12610 ins_pt = (mainw->files[old_file]->start - 1.) / mainw->files[old_file]->fps * TICKS_PER_SECOND_DBL;
12611
12612 if (!prefs->conserve_space && oachans > 0) {
12613 com = lives_strdup_printf("%s backup_audio \"%s\"", prefs->backend_sync, mainw->files[old_file]->handle);
12614 lives_system(com, FALSE);
12615 lives_free(com);
12616
12617 if (THREADVAR(com_failed)) {
12618 end_threaded_dialog();
12619 close_temp_handle(old_file);
12620 mainw->suppress_dprint = FALSE;
12621 d_print_failed();
12622 return;
12623 }
12624 }
12625
12626 THREADVAR(read_failed) = THREADVAR(write_failed) = FALSE;
12627 lives_freep((void **)&THREADVAR(read_failed_file));
12628
12629 // insert audio from old (new) clip to current
12630 render_audio_segment(1, &(mainw->current_file), old_file, &vel, &aud_start, ins_pt,
12631 ins_pt + (ticks_t)((aud_end - aud_start)*TICKS_PER_SECOND_DBL), &vol, vol, vol, NULL);
12632
12633 end_threaded_dialog();
12634 close_current_file(old_file);
12635
12636 if (THREADVAR(write_failed)) {
12637 // on failure
12638 int outfile = (mainw->multitrack ? mainw->multitrack->render_file : mainw->current_file);
12639 char *outfilename = lives_get_audio_file_name(outfile);
12640 do_write_failed_error_s(outfilename, NULL);
12641 lives_free(outfilename);
12642
12643 if (!prefs->conserve_space && type == 1) {
12644 // try to recover backup
12645 com = lives_strdup_printf("%s undo_audio \"%s\"", prefs->backend_sync, mainw->files[old_file]->handle);
12646 lives_system(com, FALSE);
12647 lives_free(com);
12648 backr = TRUE;
12649 }
12650 }
12651
12652 if (THREADVAR(read_failed)) {
12653 do_read_failed_error_s(THREADVAR(read_failed_file), NULL);
12654 lives_freep((void **)&THREADVAR(read_failed_file));
12655 if (!prefs->conserve_space && type == 1 && !backr) {
12656 // try to recover backup
12657 com = lives_strdup_printf("%s undo_audio \"%s\"", prefs->backend_sync, mainw->files[old_file]->handle);
12658 lives_system(com, FALSE);
12659 lives_free(com);
12660 }
12661 }
12662 }
12663
12664 mainw->suppress_dprint = FALSE;
12665 cfile->changed = TRUE;
12666 save_clip_values(mainw->current_file);
12667
12668 mainw->cancelled = CANCEL_NONE;
12669
12670 new_file = mainw->current_file;
12671 if (type == 0) {
12672 if (!mainw->multitrack) {
12673 switch_to_file((mainw->current_file = 0), new_file);
12674 }
12675 } else {
12676 if (!prefs->conserve_space) {
12677 set_undoable(_("Record new audio"), TRUE);
12678 cfile->undo_action = UNDO_REC_AUDIO;
12679 }
12680 }
12681
12682 d_print_done();
12683 mainw->no_switch_dprint = FALSE;
12684
12685 chk_mask = lmap_error_recsel;
12686 if (chk_mask != 0) popup_lmap_errors(NULL, LIVES_INT_TO_POINTER(chk_mask));
12687 lmap_error_recsel = 0;
12688 mainw->is_processing = FALSE;
12689
12690 #endif
12691 }
12692
12693
12694 boolean on_ins_silence_activate(LiVESMenuItem * menuitem, livespointer user_data) {
12695 double start = 0, end = 0;
12696 char *com;
12697
12698 uint32_t chk_mask = 0;
12699
12700 boolean has_new_audio = FALSE;
12701
12702 int i;
12703
12704 if (!CURRENT_CLIP_IS_VALID) return FALSE;
12705
12706 if (!CURRENT_CLIP_HAS_AUDIO) {
12707 has_new_audio = TRUE;
12708 }
12709
12710 if (!menuitem) {
12711 // redo
12712 if (cfile->achans != cfile->undo_achans) {
12713 if (cfile->audio_waveform) {
12714 for (i = 0; i < cfile->achans; lives_freep((void **)&cfile->audio_waveform[i++]));
12715 lives_freep((void **)&cfile->audio_waveform);
12716 lives_freep((void **)&cfile->aw_sizes);
12717 }
12718 }
12719 start = cfile->undo1_dbl;
12720 end = cfile->undo2_dbl;
12721 cfile->arate = cfile->undo_arate;
12722 cfile->signed_endian = cfile->undo_signed_endian;
12723 cfile->achans = cfile->undo_achans;
12724 cfile->asampsize = cfile->undo_asampsize;
12725 cfile->arps = cfile->undo_arps;
12726 }
12727
12728 if (!cfile->achans) {
12729 mainw->fx1_val = DEFAULT_AUDIO_RATE;
12730 mainw->fx2_val = DEFAULT_AUDIO_CHANS;
12731 mainw->fx3_val = DEFAULT_AUDIO_SAMPS;
12732 mainw->fx4_val = mainw->endian;
12733 resaudw = create_resaudw(2, NULL, NULL);
12734 if (lives_dialog_run(LIVES_DIALOG(resaudw->dialog)) != LIVES_RESPONSE_OK) return FALSE;
12735 if (mainw->error) {
12736 mainw->error = FALSE;
12737 return FALSE;
12738 }
12739
12740 cfile->undo_arate = cfile->arate;
12741 cfile->undo_signed_endian = cfile->signed_endian;
12742 cfile->undo_achans = cfile->achans;
12743 cfile->undo_asampsize = cfile->asampsize;
12744 }
12745
12746 if (menuitem) {
12747 char *tmp = (_("Inserting silence"));
12748 chk_mask = WARN_MASK_LAYOUT_SHIFT_AUDIO | WARN_MASK_LAYOUT_ALTER_AUDIO;
12749
12750 start = calc_time_from_frame(mainw->current_file, cfile->start);
12751 end = calc_time_from_frame(mainw->current_file, cfile->end + 1);
12752
12753 if (!check_for_layout_errors(tmp, mainw->current_file, cfile->start, cfile->end, &chk_mask)) {
12754 lives_free(tmp);
12755 return FALSE;
12756 }
12757 lives_free(tmp);
12758
12759 d_print(""); // force switchtext
12760 d_print(_("Inserting silence from %.2f to %.2f seconds..."), start, end);
12761 }
12762
12763 cfile->undo1_dbl = start;
12764 start *= (double)cfile->arate / (double)cfile->arps;
12765 cfile->undo2_dbl = end;
12766 end *= (double)cfile->arate / (double)cfile->arps;
12767
12768 // store values for undo
12769 cfile->old_laudio_time = cfile->laudio_time;
12770 cfile->old_raudio_time = cfile->raudio_time;
12771
12772 // with_sound is 2 (audio only), therefore start, end, where, are in seconds. rate is -ve to indicate silence
12773 com = lives_strdup_printf("%s insert \"%s\" \"%s\" %.8f 0. %.8f \"%s\" 2 0 0 0 0 %d %d %d %d %d 1",
12774 prefs->backend, cfile->handle,
12775 get_image_ext_for_type(cfile->img_type), start, end - start, cfile->handle, -cfile->arps,
12776 cfile->achans, cfile->asampsize, !(cfile->signed_endian & AFORM_UNSIGNED),
12777 !(cfile->signed_endian & AFORM_BIG_ENDIAN));
12778
12779 lives_rm(cfile->info_file);
12780 lives_system(com, FALSE);
12781 lives_free(com);
12782
12783 if (THREADVAR(com_failed)) {
12784 d_print_failed();
12785 if (has_new_audio) cfile->achans = cfile->arate = cfile->asampsize = cfile->arps = 0;
12786 unbuffer_lmap_errors(FALSE);
12787 return FALSE;
12788 }
12789
12790 do_progress_dialog(TRUE, FALSE, _("Inserting Silence"));
12791
12792 if (mainw->error) {
12793 d_print_failed();
12794 if (has_new_audio) cfile->achans = cfile->arate = cfile->asampsize = cfile->arps = 0;
12795 unbuffer_lmap_errors(FALSE);
12796 return FALSE;
12797 }
12798
12799 if (has_new_audio) {
12800 cfile->arate = cfile->arps = cfile->undo_arate;
12801 cfile->signed_endian = cfile->undo_signed_endian;
12802 cfile->achans = cfile->undo_achans;
12803 cfile->asampsize = cfile->undo_asampsize;
12804 }
12805
12806 set_undoable(_("Insert Silence"), TRUE);
12807 cfile->undo_action = UNDO_INSERT_SILENCE;
12808
12809 reget_afilesize(mainw->current_file);
12810 cfile->changed = TRUE;
12811
12812 save_clip_values(mainw->current_file);
12813
12814 if (menuitem) {
12815 sensitize();
12816 d_print_done();
12817 }
12818
12819 if (mainw->sl_undo_mem && cfile->stored_layout_audio != 0.) {
12820 // need to invalidate undo/redo stack, in case file was used in some layout undo
12821 stored_event_list_free_undos();
12822 }
12823
12824 if (chk_mask != 0) popup_lmap_errors(NULL, LIVES_INT_TO_POINTER(chk_mask));
12825
12826 return TRUE;
12827 }
12828
12829
12830 void on_ins_silence_details_clicked(LiVESButton * button, livespointer user_data) {
12831 int asigned = 1, aendian = 1;
12832 boolean bad_header = FALSE;
12833
12834 cfile->arps = cfile->arate = (int)atoi(lives_entry_get_text(LIVES_ENTRY(resaudw->entry_arate)));
12835 cfile->achans = (int)atoi(lives_entry_get_text(LIVES_ENTRY(resaudw->entry_achans)));
12836 cfile->asampsize = (int)atoi(lives_entry_get_text(LIVES_ENTRY(resaudw->entry_asamps)));
12837 if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(resaudw->rb_unsigned))) {
12838 asigned = 0;
12839 }
12840 if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(resaudw->rb_bigend))) {
12841 aendian = 0;
12842 }
12843 cfile->signed_endian = get_signed_endian(asigned, aendian);
12844 lives_widget_destroy(resaudw->dialog);
12845 lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
12846
12847 lives_freep((void **)&resaudw);
12848 if (cfile->arate <= 0) {
12849 do_audrate_error_dialog();
12850 cfile->achans = cfile->arate = cfile->arps = cfile->asampsize = 0;
12851 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ARATE, &cfile->arps)) bad_header = TRUE;
12852 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_PB_ARATE, &cfile->arate)) bad_header = TRUE;
12853 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ACHANS, &cfile->achans)) bad_header = TRUE;
12854 if (!save_clip_value(mainw->current_file, CLIP_DETAILS_ASAMPS, &cfile->asampsize)) bad_header = TRUE;
12855
12856 if (bad_header) do_header_write_error(mainw->current_file);
12857 mainw->error = TRUE;
12858 return;
12859 }
12860 mainw->error = FALSE;
12861 }
12862
12863
12864 void on_lerrors_clear_clicked(LiVESButton * button, livespointer user_data) {
12865 boolean close = LIVES_POINTER_TO_INT(user_data);
12866 mainw->mt_needs_idlefunc = FALSE;
12867
12868 if (mainw->multitrack) {
12869 if (mainw->multitrack->idlefunc > 0) {
12870 lives_source_remove(mainw->multitrack->idlefunc);
12871 mainw->multitrack->idlefunc = 0;
12872 mainw->mt_needs_idlefunc = TRUE;
12873 }
12874 mt_desensitise(mainw->multitrack);
12875 }
12876
12877 clear_lmap_errors();
12878 save_layout_map(NULL, NULL, NULL, NULL);
12879 if (close) {
12880 boolean needs_idlefunc = mainw->mt_needs_idlefunc;
12881 mainw->mt_needs_idlefunc = FALSE;
12882 lives_general_button_clicked(button, textwindow);
12883 mainw->mt_needs_idlefunc = needs_idlefunc;
12884 } else {
12885 lives_widget_queue_draw(lives_widget_get_toplevel(LIVES_WIDGET(button)));
12886 lives_widget_set_sensitive(textwindow->clear_button, FALSE);
12887 lives_widget_set_sensitive(textwindow->delete_button, FALSE);
12888
12889 if (mainw->multitrack) {
12890 mt_sensitise(mainw->multitrack);
12891 maybe_add_mt_idlefunc();
12892 }
12893 }
12894 }
12895
12896
12897 void on_lerrors_delete_clicked(LiVESButton * button, livespointer user_data) {
12898 int num_maps = lives_list_length(mainw->affected_layouts_map);
12899 char *msg = lives_strdup_printf(P_("\nDelete %d layout...are you sure ?\n", "\nDelete %d layouts...are you sure ?\n", num_maps),
12900 num_maps);
12901 mainw->mt_needs_idlefunc = FALSE;
12902
12903 if (mainw->multitrack) {
12904 if (mainw->multitrack->idlefunc > 0) {
12905 lives_source_remove(mainw->multitrack->idlefunc);
12906 mainw->multitrack->idlefunc = 0;
12907 mainw->mt_needs_idlefunc = TRUE;
12908 }
12909 mt_desensitise(mainw->multitrack);
12910 }
12911
12912 if (!do_warning_dialog(msg)) {
12913 lives_free(msg);
12914 if (mainw->multitrack) {
12915 mt_sensitise(mainw->multitrack);
12916 maybe_add_mt_idlefunc();
12917 }
12918 return;
12919 }
12920
12921 lives_free(msg);
12922 remove_layout_files(mainw->affected_layouts_map);
12923 on_lerrors_clear_clicked(button, LIVES_INT_TO_POINTER(TRUE));
12924 }
12925