LiVES 3.2.0
utils.c
Go to the documentation of this file.
1// utils.c
2// LiVES
3// (c) G. Finch 2003 - 2020 <salsaman+lives@gmail.com>
4// released under the GNU GPL 3 or later
5// see file ../COPYING or www.gnu.org for licensing details
6
7#include <fcntl.h>
8#include <dirent.h>
9#include <sys/statvfs.h>
10#ifdef HAVE_LIBEXPLAIN
11#include <libexplain/system.h>
12#include <libexplain/read.h>
13#endif
14#include "main.h"
15#include "interface.h"
16#include "audio.h"
17#include "resample.h"
18#include "callbacks.h"
19#include "cvirtual.h"
20
21#define ASPECT_ALLOWANCE 0.005
22
23typedef struct {
24 uint32_t hash;
25 char *key;
26 char *data;
27} lives_speed_cache_t;
28
29static boolean omute, osepwin, ofs, ofaded, odouble;
30
31static int get_hex_digit(const char c) GNU_CONST;
32
33
60char *filename_from_fd(char *val, int fd) {
62 if (fbuff) {
63 return lives_strdup(fbuff->pathname);
64 } else {
65 char *fdpath;
66 char *fidi;
67 char rfdpath[PATH_MAX];
68 struct stat stb0, stb1;
69
70 ssize_t slen;
71
72 if (fstat(fd, &stb0)) return val;
73
74 fidi = lives_strdup_printf("%d", fd);
75 fdpath = lives_build_filename("/proc", "self", "fd", fidi, NULL);
76 lives_free(fidi);
77
78 if ((slen = lives_readlink(fdpath, rfdpath, PATH_MAX)) == -1) return val;
79 lives_free(fdpath);
80
81 lives_memset(rfdpath + slen, 0, 1);
82
83 if (stat(rfdpath, &stb1)) return val;
84 if (stb0.st_dev != stb1.st_dev) return val;
85 if (stb0.st_ino != stb1.st_ino) return val;
86 if (val) lives_free(val);
87 return lives_strdup(rfdpath);
88 }
89}
90
91
92// system calls
93
94LIVES_GLOBAL_INLINE int lives_open3(const char *pathname, int flags, mode_t mode) {
95 return open(pathname, flags, mode);
96}
97
98
99LIVES_GLOBAL_INLINE int lives_open2(const char *pathname, int flags) {
100 return open(pathname, flags);
101}
102
103
104LIVES_GLOBAL_INLINE ssize_t lives_readlink(const char *path, char *buf, size_t bufsiz) {
105 return readlink(path, buf, bufsiz);
106}
107
108
110 // ret TRUE on success
111 return !fsync(fd);
112}
113
114
116 for (int i = 0; i < times; i++) sync();
117}
118
119
120LIVES_GLOBAL_INLINE boolean lives_setenv(const char *name, const char *value) {
121 // ret TRUE on success
122#if IS_IRIX
123 char *env = lives_strdup_printf("%s=%s", name, val);
124 boolean ret = !putenv(env);
125 lives_free(env);
126 return ret;
127#else
128 return !setenv(name, value, 1);
129#endif
130}
131
132LIVES_GLOBAL_INLINE boolean lives_unsetenv(const char *name) {
133 // ret TRUE on success
134#if IS_IRIX
135 char *env = lives_strdup_printf("%s=", name);
136 boolean ret = !putenv(env);
137 lives_free(env);
138 return ret;
139#else
140 return !unsetenv(name);
141#endif
142}
143
144
145int lives_system(const char *com, boolean allow_error) {
146 LiVESResponseType response;
147 int retval;
148 boolean cnorm = FALSE;
149
150 //g_print("doing: %s\n",com);
151
152 if (mainw && mainw->is_ready && !mainw->is_exiting &&
154 (mainw->multitrack && mainw->multitrack->cursor_style == LIVES_CURSOR_NORMAL))) {
155 cnorm = TRUE;
157 /* lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET); */
158 }
159
160 do {
161 THREADVAR(com_failed) = FALSE;
162 response = LIVES_RESPONSE_NONE;
163 retval = system(com);
164 if (retval) {
165 char *msg = NULL;
166 THREADVAR(com_failed) = TRUE;
167 if (!allow_error) {
168 msg = lives_strdup_printf("lives_system failed with code %d: %s\n%s", retval, com,
169#ifdef HAVE_LIBEXPLAIN
170 explain_system(com)
171#else
172 ""
173#endif
174 );
175 LIVES_ERROR(msg);
176 response = do_system_failed_error(com, retval, NULL, TRUE, FALSE);
177 }
178#ifndef LIVES_NO_DEBUG
179 else {
180 msg = lives_strdup_printf("lives_system failed with code %d: %s (not an error)", retval, com);
181 LIVES_DEBUG(msg);
182 }
183#endif
184 if (msg) lives_free(msg);
185 }
186 } while (response == LIVES_RESPONSE_RETRY);
187
189
190 return retval;
191}
192
193
194ssize_t lives_popen(const char *com, boolean allow_error, char *buff, ssize_t buflen) {
195 // runs com, fills buff with a NUL terminated string (total length <= buflen)
196 // returns number of bytes read. If an error occurs during popen or fread
197 // then THREADVAR(com_failed) is set, and if allow_error is FALSE then an an error dialog is displayed to the user
198
199 // on error we return err as a -ve number
200
201 // id buflen is 0, then buff os cast from a textbuff, and the output will be appended to it
202
203 FILE *fp;
204 char *xbuff;
205 LiVESResponseType response;
206 ssize_t totlen = 0, xtotlen = 0;
207 size_t slen;
208 LiVESTextBuffer *tbuff = NULL;
209 LiVESTextIter end_iter;
210 boolean cnorm = FALSE;
211 int err = 0;
212
213 if (buflen <= 0) {
214 tbuff = (LiVESTextBuffer *)buff;
216 xbuff = (char *)lives_calloc(1, buflen);
217 } else {
218 xbuff = buff;
219 lives_memset(xbuff, 0, 1);
220 }
221 //g_print("doing: %s\n",com);
222
223 if (mainw && mainw->is_ready && !mainw->is_exiting &&
225 (mainw->multitrack && mainw->multitrack->cursor_style == LIVES_CURSOR_NORMAL))) {
226 cnorm = TRUE;
228 //lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET);
229 }
230
231 do {
232 char *strg = NULL;
233 response = LIVES_RESPONSE_NONE;
234 THREADVAR(com_failed) = FALSE;
235 fflush(NULL);
236 fp = popen(com, "r");
237 if (!fp) {
238 err = errno;
239 } else {
240 while (1) {
241 strg = fgets(xbuff + totlen, tbuff ? buflen : buflen - totlen, fp);
242 err = ferror(fp);
243 if (err != 0 || !strg || !(*strg)) break;
244 slen = lives_strlen(xbuff);
245 if (tbuff) {
246 lives_text_buffer_get_end_iter(LIVES_TEXT_BUFFER(tbuff), &end_iter);
247 lives_text_buffer_insert(LIVES_TEXT_BUFFER(tbuff), &end_iter, xbuff, slen);
248 xtotlen += slen;
249 } else {
250 //lives_snprintf(buff + totlen, buflen - totlen, "%s", xbuff);
251 totlen = slen;
252 if (slen >= buflen - 1) break;
253 }
254 }
255 pclose(fp);
256 }
257
258 if (tbuff) {
259 lives_free(xbuff);
260 totlen = xtotlen;
261 }
262
263 if (err != 0) {
264 char *msg = NULL;
265 THREADVAR(com_failed) = TRUE;
266 if (!allow_error) {
267 msg = lives_strdup_printf("lives_popen failed p after %ld bytes with code %d: %s",
268 !strg ? 0 : lives_strlen(strg), err, com);
269 LIVES_ERROR(msg);
270 response = do_system_failed_error(com, err, NULL, TRUE, FALSE);
271 }
272#ifndef LIVES_NO_DEBUG
273 else {
274 msg = lives_strdup_printf("lives_popen failed with code %d: %s (not an error)", err, com);
275 LIVES_DEBUG(msg);
276 }
277#endif
278 if (msg) lives_free(msg);
279 }
280 } while (response == LIVES_RESPONSE_RETRY);
281
283 if (err != 0) return -ABS(err);
284 return totlen;
285}
286
287
288lives_pgid_t lives_fork(const char *com) {
289 // returns a number which is the pgid to use for lives_killpg
290
291 // mingw - return PROCESS_INFORMATION * to use in GenerateConsoleCtrlEvent (?)
292
293 // to signal to sub process and all children
294 // TODO *** - error check
295
296 pid_t ret;
297
298 if (!(ret = fork())) {
299 setsid(); // create new session id
300 setpgid(capable->mainpid, 0); // create new pgid
301 IGN_RET(system(com));
302 _exit(0);
303 }
304
305 return ret;
306}
307
308
309ssize_t lives_write(int fd, const void *buf, ssize_t count, boolean allow_fail) {
310 ssize_t retval;
311 if (count <= 0) return 0;
312
313 retval = write(fd, buf, count);
314
315 if (retval < count) {
316 char *msg = NULL;
318 THREADVAR(write_failed) = fd + 1;
319 THREADVAR(write_failed_file) = filename_from_fd(THREADVAR(write_failed_file), fd);
320 if (retval >= 0)
321 msg = lives_strdup_printf("Write failed %"PRId64" of %"PRId64" in: %s", retval,
322 count, THREADVAR(write_failed_file));
323 else
324 msg = lives_strdup_printf("Write failed with error %"PRId64" in: %s", retval,
325 THREADVAR(write_failed_file));
326
327 if (!allow_fail) {
328 LIVES_ERROR(msg);
329 close(fd);
330 }
331#ifndef LIVES_NO_DEBUG
332 else {
333 char *ffile = filename_from_fd(NULL, fd);
334 if (retval >= 0)
335 msg = lives_strdup_printf("Write failed %"PRIu64" of %"PRIu64" in: %s (not an error)", (uint64_t)retval,
336 (uint64_t)count, ffile);
337 else
338 msg = lives_strdup_printf("Write failed with error %"PRIu64" in: %s (allowed)", (uint64_t)retval,
339 THREADVAR(write_failed_file));
340 LIVES_DEBUG(msg);
341 lives_free(ffile);
342 }
343#endif
344 if (msg) lives_free(msg);
345 }
346 return retval;
347}
348
349
350ssize_t lives_write_le(int fd, const void *buf, ssize_t count, boolean allow_fail) {
351 if (count <= 0) return 0;
352 if (capable->byte_order == LIVES_BIG_ENDIAN && (prefs->bigendbug != 1)) {
353 reverse_bytes((char *)buf, count, count);
354 }
355 return lives_write(fd, buf, count, allow_fail);
356}
357
358
359int lives_fputs(const char *s, FILE *stream) {
360 int retval = fputs(s, stream);
361 if (retval == EOF) {
362 THREADVAR(write_failed) = fileno(stream) + 1;
363 }
364 return retval;
365}
366
367
368char *lives_fgets(char *s, int size, FILE *stream) {
369 char *retval;
370 if (!size) return NULL;
371 retval = fgets(s, size, stream);
372 if (!retval && ferror(stream)) {
373 THREADVAR(read_failed) = fileno(stream) + 1;
374 }
375 return retval;
376}
377
378
379size_t lives_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) {
380 size_t bytes_read = fread(ptr, size, nmemb, stream);
381 if (ferror(stream)) {
382 THREADVAR(read_failed) = fileno(stream) + 1;
383 }
384 return bytes_read;
385}
386
387
388size_t lives_fread_string(char *buff, size_t stlen, const char *fname) {
389 size_t bread = 0;
390 FILE *infofile;
391 if (!stlen) return 0;
392 infofile = fopen(fname, "r");
393 if (!infofile) return 0;
394 bread = lives_fread(buff, 1, stlen - 1, infofile);
395 fclose(infofile);
396 lives_memset(buff + bread, 0, 1);
397 return bread;
398}
399
400
402 lives_file_buffer_t *fbuff = NULL;
403 LiVESList *fblist;
404
405 pthread_mutex_lock(&mainw->fbuffer_mutex);
406
407 for (fblist = mainw->file_buffers; fblist; fblist = fblist->next) {
408 fbuff = (lives_file_buffer_t *)fblist->data;
409 if (fbuff->fd == fd) break;
410 fbuff = NULL;
411 }
412
413 pthread_mutex_unlock(&mainw->fbuffer_mutex);
414
415 return fbuff;
416}
417
418
420 lives_file_buffer_t *fbuff = NULL;
421 LiVESList *fblist;
422
423 pthread_mutex_lock(&mainw->fbuffer_mutex);
424
425 for (fblist = mainw->file_buffers; fblist; fblist = fblist->next) {
426 fbuff = (lives_file_buffer_t *)fblist->data;
427 if (!lives_strcmp(fbuff->pathname, pathname)) break;
428 fbuff = NULL;
429 }
430
431 pthread_mutex_unlock(&mainw->fbuffer_mutex);
432
433 return fbuff;
434}
435
436
437static void do_file_read_error(int fd, ssize_t errval, void *buff, ssize_t count) {
438 char *msg = NULL;
439 THREADVAR(read_failed) = fd + 1;
440 THREADVAR(read_failed_file) = filename_from_fd(THREADVAR(read_failed_file), fd);
441
442 if (errval >= 0)
443 msg = lives_strdup_printf("Read failed %"PRId64" of %"PRId64" in: %s", (int64_t)errval,
444 count, THREADVAR(read_failed_file));
445 else {
446 msg = lives_strdup_printf("Read failed with error %"PRId64" in: %s (%s)", (int64_t)errval,
447 THREADVAR(read_failed_file),
448#ifdef HAVE_LIBEXPLAIN
449 buff ? explain_read(fd, buff, count) : ""
450#else
451 ""
452#endif
453 );
454 }
455 LIVES_ERROR(msg);
456 lives_free(msg);
457}
458
459
460ssize_t lives_read(int fd, void *buf, ssize_t count, boolean allow_less) {
461 ssize_t retval = read(fd, buf, count);
462 if (count <= 0) return 0;
463
464 if (retval < count) {
465 if (!allow_less || retval < 0) {
466 do_file_read_error(fd, retval, buf, count);
467 close(fd);
468 }
469#ifndef LIVES_NO_DEBUG
470 else {
471 char *msg = NULL;
472 char *ffile = filename_from_fd(NULL, fd);
473 msg = lives_strdup_printf("Read got %"PRIu64" of %"PRIu64" in: %s (not an error)",
474 (uint64_t)retval,
475 (uint64_t)count, ffile);
476 LIVES_DEBUG(msg);
477 lives_free(ffile);
478 lives_free(msg);
479 }
480#endif
481 }
482 return retval;
483}
484
485
486ssize_t lives_read_le(int fd, void *buf, ssize_t count, boolean allow_less) {
487 ssize_t retval;
488 if (count <= 0) return 0;
489 retval = lives_read(fd, buf, count, allow_less);
490 if (retval < count) return retval;
491 if (capable->byte_order == LIVES_BIG_ENDIAN && !prefs->bigendbug) {
492 reverse_bytes((char *)buf, count, count);
493 }
494 return retval;
495}
496
498
499// explanation of values
500
501// read:
502// fbuff->buffer holds (fbuff->ptr - fbuff->buffer + fbuff->bytes) bytes
503// fbuff->offset is the next real read position
504
505// read x bytes : fbuff->ptr increases by x, fbuff->bytes decreases by x
506// if fbuff->bytes is < x, then we concat fbuff->bytes, refill buffer from file, concat remaining bytes
507// on read: fbuff->ptr = fbuff->buffer. fbuff->offset += bytes read, fbuff->bytes = bytes read
508// if fbuff->reversed is set then we seek to a position offset - 3 / 4 buffsize, fbuff->ptr = fbuff->buffer + 3 / 4 buffsz, bytes = 1 / 4 buffsz
509
510
511// on seek (read only):
512// forward: seek by +z: if z < fbuff->bytes : fbuff->ptr += z, fbuff->bytes -= z
513// if z > fbuff->bytes: subtract fbuff->bytes from z. Increase fbuff->offset by remainder. Fill buffer.
514
515// backward: if fbuff->ptr - z >= fbuff->buffer : fbuff->ptr -= z, fbuff->bytes += z
516// fbuff->ptr - z < fbuff->buffer: z -= (fbuff->ptr - fbuff->buffer) : fbuff->offset -= (fbuff->bytes + z) : Fill buffer
517
518// seek absolute: current viritual posn is fbuff->offset - fbuff->bytes : subtract this from absolute posn
519
520// return value is: fbuff->offset - fbuff->bytes ?
521
522// when writing we simply fill up the buffer until full, then flush the buffer to file io
523// buffer is finally flushed when we close the file (or we call file_buffer_flush)
524
525// in this case fbuff->bytes holds the number of bytes written to fbuff->buffer, fbuff->offset contains the offset in the underlying fil
526
527// in append mode, seek is first tthe end of the file. In creat mode any existing file is truncated and overwritten.
528
529// in write mode, if we have fallocate, then we preallocate the buffer size on disk.
530// When the file is closed we truncate any remaining bytes. Thus CAUTION because the file size as read directly will include the
531// padding bytes, and thus appending directly to the file will write after the padding.bytes, and either be overwritten or truncated.
532// in this case the correct size can be obtained from
533
534static ssize_t file_buffer_flush(lives_file_buffer_t *fbuff) {
535 // returns number of bytes written to file io, or error code
536 ssize_t res = 0;
537
538 if (fbuff->buffer) res = lives_write(fbuff->fd, fbuff->buffer, fbuff->bytes, fbuff->allow_fail);
539 //g_print("writing %ld bytes to %d\n", fbuff->bytes, fbuff->fd);
540
541 if (!fbuff->allow_fail && res < fbuff->bytes) {
542 lives_close_buffered(-fbuff->fd); // use -fd as lives_write will have closed
543 return res;
544 }
545
546 if (res > 0) {
547 fbuff->offset += res;
548 fbuff->bytes = 0;
549 fbuff->ptr = fbuff->buffer;
550 }
551 //g_print("writer offs at %ld bytes to %d\n", fbuff->offset, fbuff->fd);
552
553 return res;
554}
555
556
558 lives_file_buffer_t *fbuff = NULL;
559 LiVESList *fblist;
560
561 pthread_mutex_lock(&mainw->fbuffer_mutex);
562
563 for (fblist = mainw->file_buffers; fblist; fblist = fblist->next) {
564 fbuff = (lives_file_buffer_t *)fblist->data;
565 // if a writer, flush
566 if (!fbuff->read && mainw->memok) {
567 file_buffer_flush(fbuff);
568 fbuff->buffer = NULL;
569 } else {
570 fbuff->invalid = TRUE;
571 }
572 }
573
574 pthread_mutex_unlock(&mainw->fbuffer_mutex);
575}
576
577
578static int lives_open_real_buffered(const char *pathname, int flags, int mode, boolean isread) {
579 lives_file_buffer_t *fbuff, *xbuff;
580 boolean is_append = FALSE;
581 int fd;
582
583 if (flags & O_APPEND) {
584 is_append = TRUE;
585 flags &= ~O_APPEND;
586 }
587
588 fd = lives_open3(pathname, flags, mode);
589 if (fd >= 0) {
590 fbuff = (lives_file_buffer_t *)lives_calloc(sizeof(lives_file_buffer_t) >> 2, 4);
591 fbuff->fd = fd;
592 fbuff->read = isread;
593 fbuff->pathname = lives_strdup(pathname);
595
596 if ((xbuff = find_in_file_buffers(fd)) != NULL) {
597 char *msg = lives_strdup_printf("Duplicate fd (%d) in file buffers !\n%s was not removed, and\n%s will be added.", fd,
598 xbuff->pathname,
599 fbuff->pathname);
600 break_me("dupe fd in fbuffs");
601 LIVES_ERROR(msg);
602 lives_free(msg);
604 } else {
605 if (!isread && !(flags & O_TRUNC)) {
606 if (is_append) fbuff->offset = fbuff->orig_size = lseek(fd, 0, SEEK_END);
607 else fbuff->orig_size = (size_t)get_file_size(fd);
609 }
610 }
611 pthread_mutex_lock(&mainw->fbuffer_mutex);
612 mainw->file_buffers = lives_list_prepend(mainw->file_buffers, (livespointer)fbuff);
613 pthread_mutex_unlock(&mainw->fbuffer_mutex);
614 }
615
616 return fd;
617}
618
619static size_t bigbytes = BUFFER_FILL_BYTES_LARGE;
620static size_t medbytes = BUFFER_FILL_BYTES_MED;
621static size_t smedbytes = BUFFER_FILL_BYTES_SMALLMED;
622static size_t smbytes = BUFFER_FILL_BYTES_SMALL;
623#define AUTOTUNE
624#ifdef AUTOTUNE
625static weed_plant_t *tunerl = NULL;
626static boolean tunedl = FALSE;
627static weed_plant_t *tunerm = NULL;
628static boolean tunedm = FALSE;
629static weed_plant_t *tunersm = NULL;
630static boolean tunedsm = FALSE;
631static weed_plant_t *tuners = NULL;
632static boolean tuneds = FALSE;
633#endif
634
635
637 return lives_open_real_buffered(pathname, O_RDONLY, 0, TRUE);
638}
639
640
641boolean _lives_buffered_rdonly_slurp(int fd, off_t skip) {
643 off_t fsize = get_file_size(fd) - skip, bufsize = smbytes, res;
644 if (fsize > 0) {
645 lseek(fd, skip, SEEK_SET);
646 fbuff->orig_size = fsize + skip;
647 fbuff->buffer = fbuff->ptr = lives_calloc(1, fsize);
648 //g_printerr("slurp for %d, %s with size %ld\n", fd, fbuff->pathname, fsize);
649 while (fsize > 0) {
650 if (bufsize > fsize) bufsize = fsize;
651 res = lives_read(fbuff->fd, fbuff->buffer + fbuff->offset, bufsize, TRUE);
652 //g_printerr("slurp for %d, %s with size %ld, read %lu bytes, remain\n", fd, fbuff->pathname, res, fsize);
653 if (res < 0) {
654 fbuff->eof = TRUE;
655 return FALSE;
656 }
657 if (res > fsize) res = fsize;
658 fbuff->offset += res;
659 fsize -= res;
660 if (fsize >= bigbytes && bufsize >= medbytes) bufsize = bigbytes;
661 else if (fsize >= medbytes && bufsize >= smedbytes) bufsize = medbytes;
662 else if (fsize >= smedbytes) bufsize = smedbytes;
663 //g_printerr("slurp %d oof %ld %ld remain %lu \n", fd, fbuff->offset, fsize, ofsize);
664 }
665 }
666 fbuff->eof = TRUE;
667 return TRUE;
668}
669
670
671void lives_buffered_rdonly_slurp(int fd, off_t skip) {
673 if (!fbuff || fbuff->slurping) return;
674 fbuff->slurping = TRUE;
675 fbuff->bytes = fbuff->offset = 0;
678}
679
680
683 if (!fbuff) {
684 // normal non-buffered file
685 LIVES_DEBUG("lives_buffered_readonly_set_reversed: no file buffer found");
686 return FALSE;
687 }
688 fbuff->reversed = val;
689 return TRUE;
690}
691
692
693#ifndef O_DSYNC
694#define O_DSYNC O_SYNC
695#define NO_O_DSYNC
696#endif
697
698LIVES_GLOBAL_INLINE int lives_create_buffered(const char *pathname, int mode) {
699 return lives_open_real_buffered(pathname, O_CREAT | O_WRONLY | O_TRUNC | O_DSYNC, mode, FALSE);
700}
701
702LIVES_GLOBAL_INLINE int lives_create_buffered_nosync(const char *pathname, int mode) {
703 return lives_open_real_buffered(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode, FALSE);
704}
705
706int lives_open_buffered_writer(const char *pathname, int mode, boolean append) {
707 return lives_open_real_buffered(pathname, O_CREAT | O_WRONLY | O_DSYNC | (append ? O_APPEND : 0), mode, FALSE);
708}
709
710#ifdef NO_O_DSYNC
711#undef O_DSYNC
712#undef NO_O_DSYNC
713#endif
714
715
717 lives_file_buffer_t *fbuff;
718 boolean should_close = TRUE;
719 int ret = 0;
720
722 fd == LIVES_POINTER_TO_INT(mainw->files[mainw->scrap_file]->ext_src))
723
724 if (fd < 0) {
725 should_close = FALSE;
726 fd = -fd;
727 }
728
729 fbuff = find_in_file_buffers(fd);
730
731 if (!fbuff) {
732 // normal non-buffered file
733 LIVES_DEBUG("lives_close_buffered: no file buffer found");
734 if (should_close) ret = close(fd);
735 return ret;
736 }
737
738 if (!fbuff->read && should_close) {
739 boolean allow_fail = fbuff->allow_fail;
740 ssize_t bytes = fbuff->bytes;
741
742 if (bytes > 0) {
743 ret = file_buffer_flush(fbuff);
744 // this is correct, as flush will have called close again with should_close=FALSE;
745 if (!allow_fail && ret < bytes) return ret;
746 }
747#ifdef HAVE_POSIX_FALLOCATE
748 IGN_RET(ftruncate(fbuff->fd, MAX(fbuff->offset, fbuff->orig_size)));
749 /* //g_print("truncated at %ld bytes in %d\n", MAX(fbuff->offset, fbuff->orig_size), fbuff->fd); */
750#endif
751 }
752
753 if (fbuff->slurping) lives_nanosleep_until_nonzero(fbuff->eof);
754 if (should_close && fbuff->fd >= 0) ret = close(fbuff->fd);
755
756 lives_free(fbuff->pathname);
757
758 pthread_mutex_lock(&mainw->fbuffer_mutex);
759 mainw->file_buffers = lives_list_remove(mainw->file_buffers, (livesconstpointer)fbuff);
760 pthread_mutex_unlock(&mainw->fbuffer_mutex);
761
762 if (fbuff->buffer && !fbuff->invalid) {
763 lives_free(fbuff->buffer);
764 }
765
766 lives_free(fbuff);
767 return ret;
768}
769
770
771size_t get_read_buff_size(int sztype) {
772 switch (sztype) {
773 case BUFF_SIZE_READ_SMALLMED: return smedbytes;
774 case BUFF_SIZE_READ_MED: return medbytes;
775 case BUFF_SIZE_READ_LARGE: return bigbytes;
776 default: break;
777 }
778 return smbytes;
779}
780
781
782static ssize_t file_buffer_fill(lives_file_buffer_t *fbuff, ssize_t min) {
783 ssize_t res;
784 ssize_t delta = 0;
785 size_t bufsize;
786
787 if (min < 0) min = 0;
788
789 if (fbuff->bufsztype == BUFF_SIZE_READ_CUSTOM) {
790 if (fbuff->buffer) bufsize = fbuff->ptr - fbuff->buffer + fbuff->bytes;
791 else {
792 bufsize = fbuff->bytes;
793 fbuff->bytes = 0;
794 }
795 } else bufsize = get_read_buff_size(fbuff->bufsztype);
796
797 if (fbuff->reversed) delta = (bufsize >> 2) * 3;
798 if (delta > fbuff->offset) delta = fbuff->offset;
799 if (bufsize - delta < min) bufsize = min + delta;
800 if (fbuff->buffer && bufsize > fbuff->ptr - fbuff->buffer + fbuff->bytes) {
801 lives_freep((void **)&fbuff->buffer);
802 }
803 if (!fbuff->buffer || !fbuff->ptr) {
804 fbuff->buffer = (uint8_t *)lives_calloc_safety(bufsize >> 1, 2);
805 }
806 fbuff->offset -= delta;
807 fbuff->offset = lseek(fbuff->fd, fbuff->offset, SEEK_SET);
808
809 res = lives_read(fbuff->fd, fbuff->buffer, bufsize, TRUE);
810 if (res < 0) {
811 lives_close_buffered(-fbuff->fd); // use -fd as lives_read will have closed
812 return res;
813 }
814
815 fbuff->bytes = res - delta;
816 fbuff->ptr = fbuff->buffer + delta;
817 fbuff->offset += res;
818 if (res < bufsize) fbuff->eof = TRUE;
819 else fbuff->eof = FALSE;
820
821#if defined HAVE_POSIX_FADVISE || (defined _GNU_SOURCE && defined __linux__)
822 if (fbuff->reversed) {
823#if defined HAVE_POSIX_FADVISE
824 posix_fadvise(fbuff->fd, 0, fbuff->offset - (bufsize >> 2) * 3, POSIX_FADV_RANDOM);
825 posix_fadvise(fbuff->fd, fbuff->offset - (bufsize >> 2) * 3, bufsize, POSIX_FADV_WILLNEED);
826#endif
827#ifdef __linux__
828 readahead(fbuff->fd, fbuff->offset - (bufsize >> 2) * 3, bufsize);
829#endif
830 } else {
831#if defined HAVE_POSIX_FADVISE
832 posix_fadvise(fbuff->fd, fbuff->offset, 0, POSIX_FADV_SEQUENTIAL);
833 posix_fadvise(fbuff->fd, fbuff->offset, bufsize, POSIX_FADV_WILLNEED);
834#endif
835#ifdef __linux__
836 readahead(fbuff->fd, fbuff->offset, bufsize);
837#endif
838 }
839#endif
840
841 return res - delta;
842}
843
844
845static off_t _lives_lseek_buffered_rdonly_relative(lives_file_buffer_t *fbuff, off_t offset) {
846 off_t newoffs;
847 if (offset == 0) return fbuff->offset - fbuff->bytes;
848 fbuff->nseqreads = 0;
849
850 if (offset > 0) {
851 // seek forwards
852 if (offset < fbuff->bytes) {
853 fbuff->ptr += offset;
854 fbuff->bytes -= offset;
855 newoffs = fbuff->offset - fbuff->bytes;
856 } else {
857 offset -= fbuff->bytes;
858 fbuff->offset += offset;
859 fbuff->bytes = 0;
860 newoffs = fbuff->offset;
861 }
862 } else {
863 // seek backwards
864 offset = -offset;
865 if (offset <= fbuff->ptr - fbuff->buffer) {
866 fbuff->ptr -= offset;
867 fbuff->bytes += offset;
868 newoffs = fbuff->offset - fbuff->bytes;
869 } else {
870 offset -= fbuff->ptr - fbuff->buffer;
871
872 fbuff->offset = fbuff->offset - (fbuff->ptr - fbuff->buffer + fbuff->bytes) - offset;
873 if (fbuff->offset < 0) fbuff->offset = 0;
874
875 fbuff->bytes = 0;
876
877 fbuff->eof = FALSE;
878 newoffs = fbuff->offset;
879 }
880 }
881
882#ifdef HAVE_POSIX_FADVISE
883 if (fbuff->reversed)
884 posix_fadvise(fbuff->fd, 0, fbuff->offset - fbuff->bytes, POSIX_FADV_RANDOM);
885 else
886 posix_fadvise(fbuff->fd, fbuff->offset, 0, POSIX_FADV_SEQUENTIAL);
887#endif
888
889 lseek(fbuff->fd, fbuff->offset, SEEK_SET);
890
891 return newoffs;
892}
893
894
895off_t lives_lseek_buffered_rdonly(int fd, off_t offset) {
896 // seek relative
897 lives_file_buffer_t *fbuff;
898 if (!(fbuff = find_in_file_buffers(fd))) {
899 LIVES_DEBUG("lives_lseek_buffered_rdonly: no file buffer found");
900 return lseek(fd, offset, SEEK_CUR);
901 }
902
903 return _lives_lseek_buffered_rdonly_relative(fbuff, offset);
904}
905
906
907off_t lives_lseek_buffered_rdonly_absolute(int fd, off_t offset) {
908 lives_file_buffer_t *fbuff;
909
910 if (!(fbuff = find_in_file_buffers(fd))) {
911 LIVES_DEBUG("lives_lseek_buffered_rdonly_absolute: no file buffer found");
912 return lseek(fd, offset, SEEK_SET);
913 }
914
915 if (!fbuff->ptr || !fbuff->buffer) {
916 fbuff->offset = offset;
917 return fbuff->offset;
918 }
919 offset -= fbuff->offset - fbuff->bytes;
920 return _lives_lseek_buffered_rdonly_relative(fbuff, offset);
921}
922
923
924ssize_t lives_read_buffered(int fd, void *buf, ssize_t count, boolean allow_less) {
925 lives_file_buffer_t *fbuff;
926 ssize_t retval = 0, res = 0;
927 size_t ocount = count;
928 uint8_t *ptr = (uint8_t *)buf;
929 int bufsztype;
930#ifdef AUTOTUNE
931 double cost;
932#endif
933
934 if (count <= 0) return retval;
935
936 if ((fbuff = find_in_file_buffers(fd)) == NULL) {
937 LIVES_DEBUG("lives_read_buffered: no file buffer found");
938 return lives_read(fd, buf, count, allow_less);
939 }
940
941 if (!fbuff->read) {
942 LIVES_ERROR("lives_read_buffered: wrong buffer type");
943 return 0;
944 }
945
946 bufsztype = fbuff->bufsztype;
947
948#ifdef AUTOTUNE
949 if (!fbuff->slurping && fbuff->bufsztype != BUFF_SIZE_READ_CUSTOM) {
950 cost = 1. / (1. + (double)fbuff->nseqreads);
951 if (fbuff->bufsztype == BUFF_SIZE_READ_SMALL) {
952 if (!tuneds && (!tuners || (tunedsm && !tunedm))) tuners = lives_plant_new_with_index(LIVES_WEED_SUBTYPE_TUNABLE, 3);
953 autotune_u64(tuners, 8, smedbytes / 4, 16, cost);
954 } else if (fbuff->bufsztype == BUFF_SIZE_READ_SMALLMED) {
955 if (tuneds && !tunedsm && !tunersm) tunersm = lives_plant_new_with_index(LIVES_WEED_SUBTYPE_TUNABLE, 4);
956 autotune_u64(tunersm, smbytes * 4, 32768, 16, cost);
957 } else if (fbuff->bufsztype == BUFF_SIZE_READ_MED) {
958 if (tunedsm && !tunedm && !tunerm) tunerm = lives_plant_new_with_index(LIVES_WEED_SUBTYPE_TUNABLE, 5);
959 autotune_u64(tunerm, smedbytes * 4, 65536 * 2, 32, cost);
960 } else if (fbuff->bufsztype == BUFF_SIZE_READ_LARGE) {
961 if (tunedm && !tunedl && !tunerl) tunerl = lives_plant_new_with_index(LIVES_WEED_SUBTYPE_TUNABLE, 6);
962 autotune_u64(tunerl, medbytes * 4, 8192 * 1024, 256, cost);
963 }
964 }
965#endif
966 if (!buf) {
968 lives_freep((void **)&fbuff->buffer);
969 if (allow_less) {
970 bufsztype = BUFF_SIZE_READ_SMALL;
971 if (ocount >= (smbytes >> 2) || count > smbytes) bufsztype = BUFF_SIZE_READ_SMALLMED;
972 if (ocount >= (smedbytes >> 2) || count > smedbytes) bufsztype = BUFF_SIZE_READ_MED;
973 if (ocount >= (medbytes >> 1) || count > medbytes) bufsztype = BUFF_SIZE_READ_LARGE;
974 fbuff->bufsztype = bufsztype;
975 } else {
977 fbuff->bytes = count;
978 }
979 return file_buffer_fill(fbuff, count);
980 }
981
982 fbuff->totops++;
983
984 // read bytes from fbuff
985 if (fbuff->bytes > 0 || fbuff->slurping) {
986 size_t nbytes;
987 if (fbuff->slurping) {
988 if (fbuff->orig_size - fbuff->bytes < count) {
989 nbytes = fbuff->orig_size - fbuff->bytes;
990 if (nbytes == 0) goto rd_exit;
991 } else {
992 while ((nbytes = fbuff->offset - fbuff->bytes) < count) {
993 lives_nanosleep(1000);
994 }
995 }
996 } else nbytes = fbuff->bytes;
997 if (nbytes > count) nbytes = count;
998
999 // use up buffer
1000
1001 if (fbuff->invalid) {
1002 if (mainw->is_exiting) {
1003 return retval;
1004 }
1005 fbuff->offset -= (fbuff->ptr - fbuff->buffer + fbuff->bytes);
1006 if (fbuff->bufsztype == BUFF_SIZE_READ_CUSTOM) fbuff->bytes = (fbuff->ptr - fbuff->buffer + fbuff->bytes);
1007 fbuff->buffer = NULL;
1008 file_buffer_fill(fbuff, fbuff->bytes);
1009 fbuff->invalid = FALSE;
1010 }
1011
1012 lives_memcpy(ptr, fbuff->ptr, nbytes);
1013
1014 retval += nbytes;
1015 count -= nbytes;
1016 fbuff->ptr += nbytes;
1017 ptr += nbytes;
1018 fbuff->totbytes += nbytes;
1019
1020 if (fbuff->slurping) fbuff->bytes += nbytes;
1021 else fbuff->bytes -= nbytes;
1022
1023 fbuff->nseqreads++;
1024 if (fbuff->slurping) goto rd_exit;
1025 if (count == 0) goto rd_done;
1026 if (fbuff->eof && !fbuff->reversed) goto rd_done;
1027 fbuff->nseqreads--;
1028 if (fbuff->reversed) {
1029 fbuff->offset -= (fbuff->ptr - fbuff->buffer) + count;
1030 }
1031 }
1032
1034
1035 if (count <= bigbytes || fbuff->bufsztype == BUFF_SIZE_READ_CUSTOM) {
1036 if (fbuff->bufsztype != BUFF_SIZE_READ_CUSTOM) {
1037 bufsztype = BUFF_SIZE_READ_SMALL;
1038 if (ocount >= (smbytes >> 2) || count > smbytes) bufsztype = BUFF_SIZE_READ_SMALLMED;
1039 if (ocount >= (smedbytes >> 2) || count > smedbytes) bufsztype = BUFF_SIZE_READ_MED;
1040 if (ocount >= (medbytes >> 1) || count > medbytes) bufsztype = BUFF_SIZE_READ_LARGE;
1041 if (fbuff->bufsztype < bufsztype) fbuff->bufsztype = bufsztype;
1042 } else bufsztype = BUFF_SIZE_READ_CUSTOM;
1043 if (fbuff->invalid) {
1044 if (mainw->is_exiting) {
1045 return retval;
1046 }
1047 fbuff->offset -= (fbuff->ptr - fbuff->buffer + fbuff->bytes);
1048 if (fbuff->bufsztype == BUFF_SIZE_READ_CUSTOM) fbuff->bytes = (fbuff->ptr - fbuff->buffer + fbuff->bytes);
1049 fbuff->buffer = NULL;
1050 file_buffer_fill(fbuff, fbuff->bytes);
1051 fbuff->invalid = FALSE;
1052 } else {
1053 if (fbuff->bufsztype != bufsztype) {
1054 lives_freep((void **)&fbuff->buffer);
1055 }
1056 }
1057
1058 if (fbuff->bufsztype != bufsztype) fbuff->nseqreads = 0;
1059 res = file_buffer_fill(fbuff, count);
1060 if (res < 0) {
1061 retval = res;
1062 goto rd_done;
1063 }
1064
1065 // buffer is sufficient (or eof hit)
1066 if (res > count) res = count;
1067 lives_memcpy(ptr, fbuff->ptr, res);
1068 retval += res;
1069 fbuff->ptr += res;
1070 fbuff->bytes -= res;
1071 count -= res;
1072 fbuff->totbytes += res;
1073 } else {
1074 // larger size -> direct read
1075 if (fbuff->bufsztype != bufsztype) {
1076 if (fbuff->invalid) {
1077 fbuff->buffer = NULL;
1078 fbuff->invalid = FALSE;
1079 } else {
1080 lives_freep((void **)&fbuff->buffer);
1081 }
1082 }
1083
1084 fbuff->offset = lseek(fbuff->fd, fbuff->offset, SEEK_SET);
1085
1086 res = lives_read(fbuff->fd, ptr, count, TRUE);
1087 if (res < 0) {
1088 retval = res;
1089 goto rd_done;
1090 }
1091 if (res < count) fbuff->eof = TRUE;
1092 fbuff->offset += res;
1093 count -= res;
1094 retval += res;
1095 fbuff->totbytes += res;
1096 }
1097
1098rd_done:
1099#ifdef AUTOTUNE
1100 if (fbuff->bufsztype == BUFF_SIZE_READ_SMALL) {
1101 if (tuners) {
1102 smbytes = autotune_u64_end(&tuners, smbytes);
1103 if (!tuners) {
1104 tuneds = TRUE;
1105 }
1106 }
1107 } else if (fbuff->bufsztype == BUFF_SIZE_READ_SMALLMED) {
1108 if (tunersm) {
1109 smedbytes = autotune_u64_end(&tunersm, smedbytes);
1110 if (!tunersm) {
1111 tunedsm = TRUE;
1112 smedbytes = get_near2pow(smedbytes);
1113 if (prefs->show_dev_opts) {
1114 char *tmp;
1115 g_printerr("value rounded to %s\n", (tmp = lives_format_storage_space_string(smedbytes)));
1116 lives_free(tmp);
1117 // *INDENT-OFF*
1118 }}}}
1119 // *INDENT-ON*
1120 else if (fbuff->bufsztype == BUFF_SIZE_READ_MED) {
1121 if (tunerm) {
1122 medbytes = autotune_u64_end(&tunerm, medbytes);
1123 if (!tunerm) {
1124 tunedm = TRUE;
1125 medbytes = get_near2pow(medbytes);
1126 if (prefs->show_dev_opts) {
1127 char *tmp;
1128 g_printerr("value rounded to %s\n", (tmp = lives_format_storage_space_string(medbytes)));
1129 lives_free(tmp);
1130 // *INDENT-OFF*
1131 }}}}
1132 // *INDENT-ON*
1133 else {
1134 if (tunerl) {
1135 bigbytes = autotune_u64_end(&tunerl, bigbytes);
1136 if (!tunerl) {
1137 tunedl = TRUE;
1138 bigbytes = get_near2pow(bigbytes);
1139 if (prefs->show_dev_opts) {
1140 char *tmp;
1141 g_printerr("value rounded to %s\n", (tmp = lives_format_storage_space_string(bigbytes)));
1142 lives_free(tmp);
1143 // *INDENT-OFF*
1144 }}}}
1145 // *INDENT-ON*
1146
1147#endif
1148rd_exit:
1149 if (!allow_less && count > 0) {
1150 do_file_read_error(fd, retval, NULL, ocount);
1152 }
1153
1154 return retval;
1155}
1156
1157
1158ssize_t lives_read_le_buffered(int fd, void *buf, ssize_t count, boolean allow_less) {
1159 ssize_t retval;
1160 if (count <= 0) return 0;
1161 retval = lives_read_buffered(fd, buf, count, allow_less);
1162 if (retval < count) return retval;
1163 if (capable->byte_order == LIVES_BIG_ENDIAN && !prefs->bigendbug) {
1164 reverse_bytes((char *)buf, count, count);
1165 }
1166 return retval;
1167}
1168
1169
1171 lives_file_buffer_t *fbuff;
1172 if ((fbuff = find_in_file_buffers(fd)) == NULL) {
1173 LIVES_DEBUG("lives_read_buffered: no file buffer found");
1174 return TRUE;
1175 }
1176
1177 if (!fbuff->read) {
1178 LIVES_ERROR("lives_read_buffered_eof: wrong buffer type");
1179 return FALSE;
1180 }
1181 return (fbuff->eof && ((!fbuff->reversed && !fbuff->bytes)
1182 || (fbuff->reversed && fbuff->ptr == fbuff->buffer)));
1183}
1184
1185
1186static ssize_t lives_write_buffered_direct(lives_file_buffer_t *fbuff, const char *buf, ssize_t count, boolean allow_fail) {
1187 ssize_t res = 0;
1188 ssize_t bytes = fbuff->bytes;
1189
1190 if (count <= 0) return 0;
1191
1192 if (bytes > 0) {
1193 res = file_buffer_flush(fbuff);
1194 // this is correct, as flush will have called close again with should_close=FALSE;
1195 if (!allow_fail && res < bytes) return 0;
1196 }
1197 res = 0;
1198
1199 while (count > 0) {
1200 size_t bytes;
1201#define WRITE_ALL
1202#ifdef WRITE_ALL
1203 size_t bigbsize = count;
1204#else
1205 size_t bigbsize = BUFFER_FILL_BYTES_LARGE;
1206#endif
1207 if (bigbsize > count) bigbsize = count;
1208 bytes = lives_write(fbuff->fd, buf + res, bigbsize, allow_fail);
1209 if (bytes == bigbsize) {
1210 fbuff->offset += bytes;
1211 count -= bytes;
1212 res += bytes;
1213 } else {
1214 LIVES_ERROR("lives_write_buffered: error in bigblock writer");
1215 if (!fbuff->allow_fail) {
1216 lives_close_buffered(-fbuff->fd); // use -fd as lives_write will have closed
1217 return res;
1218 }
1219 break;
1220 }
1221 }
1222 return res;
1223}
1224
1225
1226ssize_t lives_write_buffered(int fd, const char *buf, ssize_t count, boolean allow_fail) {
1227 lives_file_buffer_t *fbuff;
1228 ssize_t retval = 0, res;
1229 size_t space_left;
1230 int bufsztype = BUFF_SIZE_WRITE_SMALL;
1231 ssize_t buffsize;
1232
1233 if (!(fbuff = find_in_file_buffers(fd))) {
1234 LIVES_DEBUG("lives_write_buffered: no file buffer found");
1235 return lives_write(fd, buf, count, allow_fail);
1236 }
1237
1238 if (fbuff->read) {
1239 LIVES_ERROR("lives_write_buffered: wrong buffer type");
1240 return 0;
1241 }
1242
1243 if (count <= 0) return 0;
1244
1245 if (count > BUFFER_FILL_BYTES_LARGE) return lives_write_buffered_direct(fbuff, buf, count, allow_fail);
1246
1247 fbuff->totops++;
1248 fbuff->totbytes += count;
1249
1250 if (count >= BUFFER_FILL_BYTES_BIGMED >> 1)
1251 bufsztype = BUFF_SIZE_WRITE_LARGE;
1252 else if (count >= BUFFER_FILL_BYTES_MED >> 1)
1253 bufsztype = BUFF_SIZE_WRITE_BIGMED;
1254 else if (fbuff->totbytes >= BUFFER_FILL_BYTES_SMALLMED)
1255 bufsztype = BUFF_SIZE_WRITE_MED;
1256 else if (fbuff->totbytes >= BUFFER_FILL_BYTES_SMALL)
1257 bufsztype = BUFF_SIZE_WRITE_SMALLMED;
1258
1259 if (bufsztype < fbuff->bufsztype) bufsztype = fbuff->bufsztype;
1260
1261 fbuff->allow_fail = allow_fail;
1262
1263 // write bytes to fbuff
1264 while (count) {
1265 if (!fbuff->buffer) fbuff->bufsztype = bufsztype;
1266
1267 if (fbuff->bufsztype == BUFF_SIZE_WRITE_SMALL)
1268 buffsize = BUFFER_FILL_BYTES_SMALL;
1269 else if (fbuff->bufsztype == BUFF_SIZE_WRITE_SMALLMED)
1270 buffsize = BUFFER_FILL_BYTES_SMALLMED;
1271 else if (fbuff->bufsztype == BUFF_SIZE_WRITE_MED)
1272 buffsize = BUFFER_FILL_BYTES_MED;
1273 else if (fbuff->bufsztype == BUFF_SIZE_WRITE_BIGMED)
1274 buffsize = BUFFER_FILL_BYTES_BIGMED;
1275 else
1276 buffsize = BUFFER_FILL_BYTES_LARGE;
1277
1278 if (!fbuff->buffer) {
1279 fbuff->buffer = (uint8_t *)lives_calloc(buffsize >> 4, 16);
1280 fbuff->ptr = fbuff->buffer;
1281 fbuff->bytes = 0;
1282
1283#ifdef HAVE_POSIX_FALLOCATE
1284 // pre-allocate space for next buffer, we need to ftruncate this when closing the file
1285 //g_print("alloc space in %d from %ld to %ld\n", fbuff->fd, fbuff->offset, fbuff->offset + buffsize);
1286 posix_fallocate(fbuff->fd, fbuff->offset, buffsize);
1287 /* lseek(fbuff->fd, fbuff->offset, SEEK_SET); */
1288#endif
1289 }
1290
1291 space_left = buffsize - fbuff->bytes;
1292 if (space_left > count) {
1293 lives_memcpy(fbuff->ptr, buf, count);
1294 retval += count;
1295 fbuff->ptr += count;
1296 fbuff->bytes += count;
1297 count = 0;
1298 } else {
1299 lives_memcpy(fbuff->ptr, buf, space_left);
1300 fbuff->bytes = buffsize;
1301 res = file_buffer_flush(fbuff);
1302 retval += space_left;
1303 if (res < buffsize) return (res < 0 ? res : retval);
1304 count -= space_left;
1305 buf += space_left;
1306 if (fbuff->bufsztype != bufsztype) {
1307 lives_free(fbuff->buffer);
1308 fbuff->buffer = NULL;
1309 }
1310 }
1311 }
1312 return retval;
1313}
1314
1315
1316ssize_t lives_buffered_write_printf(int fd, boolean allow_fail, const char *fmt, ...) {
1317 ssize_t ret;
1318 va_list xargs;
1319 char *text;
1320 va_start(xargs, fmt);
1321 text = lives_strdup_vprintf(fmt, xargs);
1322 va_end(xargs);
1323 ret = lives_write_buffered(fd, text, lives_strlen(text), allow_fail);
1324 lives_free(text);
1325 return ret;
1326}
1327
1328
1329ssize_t lives_write_le_buffered(int fd, const void *buf, ssize_t count, boolean allow_fail) {
1330 if (count <= 0) return 0;
1331 if (capable->byte_order == LIVES_BIG_ENDIAN && (prefs->bigendbug != 1)) {
1332 reverse_bytes((char *)buf, count, count);
1333 }
1334 return lives_write_buffered(fd, (char *)buf, count, allow_fail);
1335}
1336
1337
1338off_t lives_lseek_buffered_writer(int fd, off_t offset) {
1339 lives_file_buffer_t *fbuff;
1340
1341 if ((fbuff = find_in_file_buffers(fd)) == NULL) {
1342 LIVES_DEBUG("lives_lseek_buffered_writer: no file buffer found");
1343 return lseek(fd, offset, SEEK_SET);
1344 }
1345
1346 if (fbuff->read) {
1347 LIVES_ERROR("lives_lseek_buffered_writer: wrong buffer type");
1348 return 0;
1349 }
1350
1351 if (fbuff->bytes > 0) {
1352 ssize_t res = file_buffer_flush(fbuff);
1353 if (res < 0) return res;
1354 if (res < fbuff->bytes && !fbuff->allow_fail) {
1355 fbuff->eof = TRUE;
1356 return fbuff->offset;
1357 }
1358 }
1359 fbuff->offset = lseek(fbuff->fd, offset, SEEK_SET);
1360 return fbuff->offset;
1361}
1362
1363
1365 lives_file_buffer_t *fbuff;
1366
1367 if ((fbuff = find_in_file_buffers(fd)) == NULL) {
1368 LIVES_DEBUG("lives_buffered_offset: no file buffer found");
1369 return lseek(fd, 0, SEEK_CUR);
1370 }
1371
1372 if (fbuff->read) return fbuff->offset - fbuff->bytes;
1373 return fbuff->offset + fbuff->bytes;
1374}
1375
1376
1378 lives_file_buffer_t *fbuff;
1379
1380 if ((fbuff = find_in_file_buffers(fd)) == NULL) {
1381 LIVES_DEBUG("lives_buffered_offset: no file buffer found");
1382 return lseek(fd, 0, SEEK_CUR);
1383 }
1384
1385 if (!fbuff->read) return fbuff->orig_size;
1386 if (fbuff->orig_size == 0) fbuff->orig_size = (size_t)get_file_size(fd);
1387 return fbuff->orig_size;
1388}
1389
1390
1392
1393int lives_chdir(const char *path, boolean no_error_dlg) {
1396 int retval = chdir(path);
1397
1398 if (retval) {
1399 char *msg = lives_strdup_printf("Chdir failed to: %s", path);
1400 THREADVAR(chdir_failed) = TRUE;
1401 if (!no_error_dlg) {
1402 LIVES_ERROR(msg);
1404 } else LIVES_DEBUG(msg);
1405 lives_free(msg);
1406 }
1407 return retval;
1408}
1409
1410
1412 // free a pointer and nullify it, only if it is non-null to start with
1413 // pass the address of the pointer in
1414 if (ptr && *ptr) {
1415 lives_free(*ptr);
1416 *ptr = NULL;
1417 return TRUE;
1418 }
1419 return FALSE;
1420}
1421
1422
1424 if (pid == 0) {
1425 LIVES_ERROR("Tried to kill pid 0");
1426 return -1;
1427 }
1428 return kill(pid, sig);
1429}
1430
1431
1432LIVES_GLOBAL_INLINE int lives_killpg(lives_pgid_t pgrp, int sig) {return killpg(pgrp, sig);}
1433
1434
1436
1437
1439 register int i;
1440 uint64_t res = 1;
1441 for (i = 0; i < pow; i++) res *= 10;
1442 return res;
1443}
1444
1445
1446LIVES_GLOBAL_INLINE double lives_fix(double val, int decimals) {
1447 double factor = (double)lives_10pow(decimals);
1448 if (val >= 0.) return (double)((int)(val * factor + 0.5)) / factor;
1449 return (double)((int)(val * factor - 0.5)) / factor;
1450}
1451
1452
1454 x |= (x >> 1); x |= (x >> 2); x |= (x >> 4); x |= (x >> 8); x |= (x >> 16);
1455 return (++x) >> 1;
1456}
1457
1459 x |= (x >> 1); x |= (x >> 2); x |= (x >> 4); x |= (x >> 8); x |= (x >> 16); x |= (x >> 32);
1460 return (++x) >> 1;
1461}
1462
1463LIVES_GLOBAL_INLINE uint64_t get_near2pow(uint64_t val) {
1464 uint64_t low = get_approx_ln64(val), high = low * 2;
1465 if (high < low || (val - low < high - val)) return low;
1466 return high;
1467}
1468
1470
1472static ticks_t delta = 0;
1473
1476 lastt = LIVES_TIME_SOURCE_NONE;
1477 delta = 0;
1478}
1479
1480
1481ticks_t lives_get_current_playback_ticks(int64_t origsecs, int64_t orignsecs, lives_time_source_t *time_source) {
1482 // get the time using a variety of methods
1483 // time_source may be NULL or LIVES_TIME_SOURCE_NONE to set auto
1484 // or another value to force it (EXTERNAL cannot be forced)
1485 lives_time_source_t *tsource, xtsource = LIVES_TIME_SOURCE_NONE;
1486 ticks_t clock_ticks, current = -1;
1487 static ticks_t lclock_ticks, interticks;
1488
1489 if (time_source) tsource = time_source;
1490 else tsource = &xtsource;
1491
1492 clock_ticks = lives_get_relative_ticks(origsecs, orignsecs);
1493 mainw->clock_ticks = clock_ticks;
1494
1495 if (*tsource == LIVES_TIME_SOURCE_EXTERNAL) *tsource = LIVES_TIME_SOURCE_NONE;
1496
1498 *tsource = LIVES_TIME_SOURCE_SYSTEM;
1499 current = clock_ticks;
1500 }
1501
1502 if (*tsource == LIVES_TIME_SOURCE_NONE) {
1503#ifdef ENABLE_JACK_TRANSPORT
1506 // calculate the time from jack transport
1507 *tsource = LIVES_TIME_SOURCE_EXTERNAL;
1508 current = jack_transport_get_current_ticks();
1509 }
1510#endif
1511 }
1512
1514 *tsource == LIVES_TIME_SOURCE_SOUNDCARD)) {
1515 if ((!mainw->is_rendering || (mainw->multitrack && !cfile->opening && !mainw->multitrack->is_rendering)) &&
1516 (!(mainw->fixed_fpsd > 0. || (mainw->vpp && mainw->vpp->fixed_fpsd > 0. && mainw->ext_playback)))) {
1517 // get time from soundcard
1518 // this is done so as to synch video stream with the audio
1519 // we do this in two cases:
1520 // - for internal audio, playing back a clip with audio (writing)
1521 // - or when audio source is set to external (reading) and we are recording, no internal audio generator is running
1522
1523 // we ignore this if we are running with a playback plugin which requires a fixed framerate (e.g a streaming plugin)
1524 // in that case we will adjust the audio rate to fit the system clock
1525
1526 // or if we are rendering
1527
1528#ifdef ENABLE_JACK
1530 ((prefs->audio_src == AUDIO_SRC_INT && mainw->jackd && mainw->jackd->in_use &&
1531 IS_VALID_CLIP(mainw->jackd->playing_file) && mainw->files[mainw->jackd->playing_file]->achans > 0) ||
1532 (prefs->audio_src == AUDIO_SRC_EXT && mainw->jackd_read && mainw->jackd_read->in_use))) {
1533 *tsource = LIVES_TIME_SOURCE_SOUNDCARD;
1535 current = lives_jack_get_time(mainw->jackd_read);
1536 else
1537 current = lives_jack_get_time(mainw->jackd);
1538 }
1539#endif
1540
1541#ifdef HAVE_PULSE_AUDIO
1543 ((prefs->audio_src == AUDIO_SRC_INT && mainw->pulsed && mainw->pulsed->in_use &&
1544 IS_VALID_CLIP(mainw->pulsed->playing_file) && mainw->files[mainw->pulsed->playing_file]->achans > 0) ||
1546 *tsource = LIVES_TIME_SOURCE_SOUNDCARD;
1548 current = lives_pulse_get_time(mainw->pulsed_read);
1549 else current = lives_pulse_get_time(mainw->pulsed);
1550 }
1551#endif
1552 }
1553 }
1554
1555 if (*tsource == LIVES_TIME_SOURCE_NONE || current == -1) {
1556 *tsource = LIVES_TIME_SOURCE_SYSTEM;
1557 current = clock_ticks;
1558 }
1559
1560 //if (lastt != *tsource) {
1561 /* g_print("t1 = %ld, t2 = %ld cadj =%ld, adj = %ld del =%ld %ld %ld\n", clock_ticks, current, mainw->cadjticks, mainw->adjticks, */
1562 /* delta, clock_ticks + mainw->cadjticks, current + mainw->adjticks); */
1563 //}
1564
1577 // cadjticks_new = clock_ticks - (source_ticks + adjticks) = delta + cadjticks_old
1580
1587
1588 if (*tsource == LIVES_TIME_SOURCE_SYSTEM) {
1589 if (lastt != LIVES_TIME_SOURCE_SYSTEM && lastt != LIVES_TIME_SOURCE_NONE) {
1590 // current + adjt == clock_ticks - cadj /// interticks == lcurrent + adj
1591 // current - ds + adjt == clock_ticks - dc - cadj /// interticks == lcurrent + adj
1592
1593 // cadj = clock_ticks - interticks + (current - lcurrent) - since we may not have current
1594 // we have to approximate with clock_ticks - lclock_ticks
1595 mainw->cadjticks = clock_ticks - interticks - (clock_ticks - lclock_ticks);
1596 }
1597 interticks = clock_ticks - mainw->cadjticks;
1598 } else {
1599 if (lastt == LIVES_TIME_SOURCE_SYSTEM) {
1600 // current - ds + adjt == clock_ticks - dc - cadj /// iinterticks == lclock_ticks - cadj ///
1601 mainw->adjticks = interticks - current + (clock_ticks - lclock_ticks);
1602 }
1603 interticks = current + mainw->adjticks;
1604 }
1605
1606 /* if (lastt != *tsource) { */
1607 /* g_print("aft t1 = %ld, t2 = %ld cadj =%ld, adj = %ld del =%ld %ld %ld\n", clock_ticks, current, mainw->cadjticks, */
1608 /* mainw->adjticks, delta, clock_ticks + mainw->cadjticks, current + mainw->adjticks); */
1609 /* } */
1610 lclock_ticks = clock_ticks;
1611 lastt = *tsource;
1612 return interticks + mainw->syncticks;
1613}
1614
1615
1617
1619 // set to now + offset
1620 // invalid alarm number
1621 lives_timeout_t *alarm;
1622 if (alarm_handle <= 0 || alarm_handle > LIVES_MAX_ALARMS) {
1623 LIVES_WARN("Invalid alarm handle");
1624 break_me("inv alarm handle in lives_alarm_reset");
1625 return -1;
1626 }
1627
1628 // offset of 1 was added for caller
1629 alarm = &mainw->alarms[--alarm_handle];
1630
1632 alarm->tleft = ticks;
1633 return ++alarm_handle;
1634}
1635
1636
1644 int i;
1645
1646 // we will assign [this] next
1647 lives_alarm_t ret;
1648
1649 pthread_mutex_lock(&mainw->alarmlist_mutex);
1650
1651 ret = mainw->next_free_alarm;
1652
1653 if (ret > LIVES_MAX_USER_ALARMS) ret--;
1654 else {
1655 // no alarm slots left
1656 if (mainw->next_free_alarm == ALL_USED) {
1657 pthread_mutex_unlock(&mainw->alarmlist_mutex);
1658 LIVES_WARN("No alarms left");
1659 return ALL_USED;
1660 }
1661 }
1662
1663 // system alarms
1664 if (ret >= LIVES_MAX_USER_ALARMS) {
1665 lives_alarm_reset(++ret, ticks);
1666 pthread_mutex_unlock(&mainw->alarmlist_mutex);
1667 return ret;
1668 }
1669
1670 i = ++mainw->next_free_alarm;
1671
1672 // find free slot for next time
1673 while (mainw->alarms[i].lastcheck != 0 && i < LIVES_MAX_USER_ALARMS) i++;
1674
1675 if (i == LIVES_MAX_USER_ALARMS) mainw->next_free_alarm = ALL_USED; // no more alarm slots
1676 else mainw->next_free_alarm = i; // OK
1677 lives_alarm_reset(++ret, ticks);
1678 pthread_mutex_unlock(&mainw->alarmlist_mutex);
1679
1680 return ret;
1681}
1682
1683
1684/*** check if alarm time passed yet, if so clear that alarm and return TRUE
1685 else return FALSE
1686*/
1688 ticks_t curticks;
1689 lives_timeout_t *alarm;
1690
1691 // invalid alarm number
1692 if (alarm_handle <= 0 || alarm_handle > LIVES_MAX_ALARMS) {
1693 LIVES_WARN("Invalid alarm handle");
1694 break_me("inv alarm handle in lives_alarm_check");
1695 return -1;
1696 }
1697
1698 // offset of 1 was added for caller
1699 alarm = &mainw->alarms[--alarm_handle];
1700
1701 // alarm time was never set !
1702 if (alarm->lastcheck == 0) {
1703 LIVES_WARN("Alarm time not set");
1704 return 0;
1705 }
1706
1707 curticks = lives_get_current_ticks();
1708
1709 if (prefs->show_dev_opts) {
1711 // if the last check was > 5 seconds ago, we ignore the time jump, updating the check time but not reducing the time left
1712 if (curticks - alarm->lastcheck > 5 * TICKS_PER_SECOND) {
1713 alarm->lastcheck = curticks;
1714 return alarm->tleft;
1715 }
1716 }
1717
1718 alarm->tleft -= curticks - alarm->lastcheck;
1719
1720 if (alarm->tleft <= 0) {
1721 // reached alarm time, free up this timer and return TRUE
1722 alarm->lastcheck = 0;
1723 LIVES_DEBUG("Alarm reached");
1724 return 0;
1725 }
1726 alarm->lastcheck = curticks;
1727 // alarm time not reached yet
1728 return alarm->tleft;
1729}
1730
1731
1732boolean lives_alarm_clear(lives_alarm_t alarm_handle) {
1733 if (alarm_handle <= 0 || alarm_handle > LIVES_MAX_ALARMS) {
1734 LIVES_WARN("Invalid clear alarm handle");
1735 return FALSE;
1736 }
1737
1738 mainw->alarms[--alarm_handle].lastcheck = 0;
1739
1740 if (alarm_handle < LIVES_MAX_USER_ALARMS
1741 && (mainw->next_free_alarm == ALL_USED || alarm_handle < mainw->next_free_alarm)) {
1742 mainw->next_free_alarm = alarm_handle;
1743 }
1744 return TRUE;
1745}
1746
1747
1748
1749/* convert to/from a big endian 32 bit float for internal use */
1751 if (capable->byte_order == LIVES_LITTLE_ENDIAN) swab4(&f, &f, 1);
1752 return f;
1753}
1754
1755
1756LIVES_GLOBAL_INLINE double calc_time_from_frame(int clip, int frame) {return (frame - 1.) / mainw->files[clip]->fps;}
1757
1758
1759LIVES_GLOBAL_INLINE int calc_frame_from_time(int filenum, double time) {
1760 // return the nearest frame (rounded) for a given time, max is cfile->frames
1761 int frame = 0;
1762 if (time < 0.) return mainw->files[filenum]->frames ? 1 : 0;
1763 frame = (int)(time * mainw->files[filenum]->fps + 1.49999);
1764 return (frame < mainw->files[filenum]->frames) ? frame : mainw->files[filenum]->frames;
1765}
1766
1767
1768LIVES_GLOBAL_INLINE int calc_frame_from_time2(int filenum, double time) {
1769 // return the nearest frame (rounded) for a given time
1770 // allow max (frames+1)
1771 int frame = 0;
1772 if (time < 0.) return mainw->files[filenum]->frames ? 1 : 0;
1773 frame = (int)(time * mainw->files[filenum]->fps + 1.49999);
1774 return (frame < mainw->files[filenum]->frames + 1) ? frame : mainw->files[filenum]->frames + 1;
1775}
1776
1777
1778LIVES_GLOBAL_INLINE int calc_frame_from_time3(int filenum, double time) {
1779 // return the nearest frame (floor) for a given time
1780 // allow max (frames+1)
1781 int frame = 0;
1782 if (time < 0.) return mainw->files[filenum]->frames ? 1 : 0;
1783 frame = (int)(time * mainw->files[filenum]->fps + 1.);
1784 return (frame < mainw->files[filenum]->frames + 1) ? frame : mainw->files[filenum]->frames + 1;
1785}
1786
1787
1788LIVES_GLOBAL_INLINE int calc_frame_from_time4(int filenum, double time) {
1789 // return the nearest frame (rounded) for a given time, no maximum
1790 int frame = 0;
1791 if (time < 0.) return mainw->files[filenum]->frames ? 1 : 0;
1792 frame = (int)(time * mainw->files[filenum]->fps + 1.49999);
1793 return frame;
1794}
1795
1796
1797static boolean check_for_audio_stop(int fileno, frames_t first_frame, frames_t last_frame) {
1798 // this is only used for older versions with non-realtime players
1799 // return FALSE if audio stops playback
1800 lives_clip_t *sfile = mainw->files[fileno];
1801#ifdef ENABLE_JACK
1802 if (prefs->audio_player == AUD_PLAYER_JACK && mainw->jackd && mainw->jackd->playing_file == fileno) {
1803 if (!mainw->loop || mainw->playing_sel) {
1804 if (!mainw->loop_cont) {
1805 if ((sfile->adirection == LIVES_DIRECTION_REVERSE && mainw->aframeno - 0.0001 < (double)first_frame + 0.0001)
1806 || (sfile->adirection == LIVES_DIRECTION_FORWARD && mainw->aframeno + 0.0001 >= (double)last_frame - 0.0001)) {
1807 return FALSE;
1808 }
1809 }
1810 } else {
1811 if (!mainw->loop_cont) {
1812 if ((sfile->adirection == LIVES_DIRECTION_REVERSE && mainw->aframeno < 0.9999) ||
1814 >= cfile->laudio_time - 0.0001)) {
1815 return FALSE;
1816 // *INDENT-OFF*
1817 }}}}
1818 // *INDENT-ON*
1819
1820#endif
1821#ifdef HAVE_PULSE_AUDIO
1822 if (prefs->audio_player == AUD_PLAYER_PULSE && mainw->pulsed && mainw->pulsed->playing_file == fileno) {
1823 if (!mainw->loop || mainw->playing_sel) {
1824 if (!mainw->loop_cont) {
1825 if ((sfile->adirection == LIVES_DIRECTION_REVERSE && mainw->aframeno - 0.0001 < (double)first_frame + 0.0001)
1826 || (sfile->adirection == LIVES_DIRECTION_FORWARD && mainw->aframeno + 1.0001 >= (double)last_frame - 0.0001)) {
1827 return FALSE;
1828 }
1829 }
1830 } else {
1831 if (!mainw->loop_cont) {
1832 if ((sfile->adirection == LIVES_DIRECTION_REVERSE && mainw->aframeno < 0.9999) ||
1834 >= cfile->laudio_time - 0.0001)) {
1835 return FALSE;
1836 // *INDENT-OFF*
1837 }}}}
1838 // *INDENT-ON*
1839
1840#endif
1841 return TRUE;
1842}
1843
1844
1845void calc_aframeno(int fileno) {
1846#ifdef ENABLE_JACK
1847 if (prefs->audio_player == AUD_PLAYER_JACK && ((mainw->jackd && mainw->jackd->playing_file == fileno) ||
1848 (mainw->jackd_read && mainw->jackd_read->playing_file == fileno))) {
1849 // get seek_pos from jack
1850 if (mainw->jackd_read) mainw->aframeno = lives_jack_get_pos(mainw->jackd_read) * cfile->fps + 1.;
1851 else mainw->aframeno = lives_jack_get_pos(mainw->jackd) * cfile->fps + 1.;
1852 }
1853#endif
1854#ifdef HAVE_PULSE_AUDIO
1855 if (prefs->audio_player == AUD_PLAYER_PULSE && ((mainw->pulsed && mainw->pulsed->playing_file == fileno) ||
1856 (mainw->pulsed_read && mainw->pulsed_read->playing_file == fileno))) {
1857 // get seek_pos from pulse
1858 if (mainw->pulsed_read) mainw->aframeno = lives_pulse_get_pos(mainw->pulsed_read) * cfile->fps + 1.;
1859 else mainw->aframeno = lives_pulse_get_pos(mainw->pulsed) * cfile->fps + 1.;
1860 }
1861#endif
1862}
1863
1864
1866 // returns a frame number (floor) using sfile->last_frameno and ntc-otc
1867 // takes into account looping modes
1868
1869 // the range is first_frame -> last_frame
1870
1871 // which is generally 1 -> sfile->frames, unless we are playing a selection
1872
1873 // in case the frame is out of range and playing, returns 0 and sets mainw->cancelled
1874
1875 // ntc is adjusted backwards to timecode of the new frame
1876
1877 // the basic operation is quite simple, given the time difference between the last frame and
1878 // now, we calculate the new frame from the current fps and then ensure it is in the range
1879 // first_frame -> last_frame
1880
1881 // Complications arise because we have ping-pong loop mode where the play direction
1882 // alternates - here we need to determine how many times we have reached the start or end
1883 // play point. This is similar to the winding number in topological calculations.
1884
1885 // caller should check return value of ntc, and if it differs from otc, show the frame
1886
1887 // note we also calculate the audio "frame" and position for realtime audio players
1888 // this is done so we can check here if audio limits stopped playback
1889
1890 static boolean norecurse = FALSE;
1891 static ticks_t last_ntc = 0;
1892
1893 ticks_t ddtc = *ntc - last_ntc;
1894 ticks_t dtc = *ntc - otc;
1895 int64_t first_frame, last_frame, selrange;
1896 lives_clip_t *sfile = mainw->files[fileno];
1897 double fps;
1899 frames_t cframe, nframe, fdelta;
1900 int nloops;
1901 int aplay_file = fileno;
1902
1903 if (!sfile) return 0;
1904
1905 cframe = sfile->last_frameno;
1906 if (norecurse) return cframe;
1907
1908 if (sfile->achans > 0) {
1909#ifdef HAVE_PULSE_AUDIO
1911 if (mainw->pulsed) aplay_file = mainw->pulsed->playing_file;
1912 }
1913#endif
1914#ifdef ENABLE_JACK
1916 if (mainw->jackd) aplay_file = mainw->jackd->playing_file;
1917 }
1918#endif
1919 if (!IS_VALID_CLIP(aplay_file)) aplay_file = -1;
1920 else {
1921 if (fileno != aplay_file) {
1922 off64_t aseek_pos_delta = (off64_t)((double)dtc / TICKS_PER_SECOND_DBL * (double)(sfile->arate))
1923 * sfile->achans * sfile->asampsize / 8;
1924 if (sfile->adirection == LIVES_DIRECTION_FORWARD) sfile->aseek_pos += aseek_pos_delta;
1925 else sfile->aseek_pos -= aseek_pos_delta;
1926 if (sfile->aseek_pos < 0 || sfile->aseek_pos > sfile->afilesize) {
1927 nloops = sfile->aseek_pos / sfile->afilesize;
1928 if (mainw->ping_pong && (sfile->adirection == LIVES_DIRECTION_REVERSE || clip_can_reverse(fileno))) {
1929 sfile->adirection += nloops;
1930 sfile->adirection &= 1;
1931 if (sfile->adirection == LIVES_DIRECTION_BACKWARD && !clip_can_reverse(fileno))
1933 }
1934 sfile->aseek_pos -= nloops * sfile->afilesize;
1935 if (sfile->adirection == LIVES_DIRECTION_REVERSE) sfile->aseek_pos = sfile->afilesize - sfile->aseek_pos;
1936 // *INDENT-OFF*
1937 }}}}
1938 // *INDENT-ON*
1939
1940 if (sfile->frames == 0 && !mainw->foreign) {
1941 if (fileno == mainw->playing_file) mainw->scratch = SCRATCH_NONE;
1942 return 0;
1943 }
1944
1945 fps = sfile->pb_fps;
1946 if (!LIVES_IS_PLAYING || (fps < 0.001 && fps > -0.001 && mainw->scratch != SCRATCH_NONE)) fps = sfile->fps;
1947
1948 if (fps < 0.001 && fps > -0.001) {
1949 *ntc = otc;
1950 if (fileno == mainw->playing_file) {
1952 if (prefs->audio_src == AUDIO_SRC_INT) calc_aframeno(fileno);
1953 }
1954 return cframe;
1955 }
1956
1957 // dtc is delta ticks (last frame time - current time), quantise this to the frame rate and round down
1958 dtc = q_gint64_floor(dtc, fps);
1959
1960 // ntc is the time when the next frame should be / have been played, or if dtc is zero we just set it to otc - the last frame time
1961 *ntc = otc + dtc;
1962
1963 // nframe is our new frame; convert dtc to sencods, and multiply by the frame rate, then add or subtract from current frame number
1964 // the small constant is just to account for rounding errors
1965 if (fps >= 0.)
1966 nframe = cframe + (frames_t)((double)dtc / TICKS_PER_SECOND_DBL * fps + .00001);
1967 else
1968 nframe = cframe + (frames_t)((double)dtc / TICKS_PER_SECOND_DBL * fps - .00001);
1969
1970 if (nframe != cframe) {
1971 if (!IS_NORMAL_CLIP(fileno)) {
1972 return 1;
1973 }
1974 if (mainw->foreign) return sfile->frameno + 1;
1975 }
1976
1977 if (fileno == mainw->playing_file) {
1981
1990 // dtc is delta ticks, quantise this to the frame rate and round down
1992 }
1993
1994 if (nframe != cframe) {
1995 int delval = (ticks_t)((double)mainw->deltaticks / TICKS_PER_SECOND_DBL * fps + .5);
1996 if (delval <= -1 || delval >= 1) {
1998 frames64_t xnframe = cframe + (int64_t)delval;
1999 frames64_t dframes = xnframe - nframe;
2000
2001 if (xnframe != nframe) {
2002 nframe = xnframe;
2004 mainw->deltaticks -= (ticks_t)((double)delval / fps * TICKS_PER_SECOND_DBL);
2005 if (nframe != cframe) {
2006 sfile->last_frameno += dframes;
2007 if (fps < 0. && mainw->scratch == SCRATCH_FWD) sfile->last_frameno--;
2008 if (fps > 0. && mainw->scratch == SCRATCH_BACK) sfile->last_frameno++;
2010 } else mainw->scratch = SCRATCH_NONE;
2011 }
2012 }
2013 }
2014 last_ntc = *ntc;
2015 }
2016
2017 last_frame = sfile->frames;
2018 first_frame = 1;
2019
2020 if (fileno == mainw->playing_file) {
2021 // calculate audio "frame" from the number of samples played
2022 if (prefs->audio_src == AUDIO_SRC_INT) calc_aframeno(fileno);
2023
2024 if (nframe == cframe || mainw->foreign) {
2025 if (!mainw->foreign && fileno == mainw->playing_file &&
2028 resync_audio(nframe);
2030 }
2031 return nframe;
2032 }
2033
2035 last_frame = mainw->playing_sel ? sfile->end : mainw->play_end;
2036 if (last_frame > sfile->frames) last_frame = sfile->frames;
2037 first_frame = mainw->playing_sel ? sfile->start : mainw->loop_video ? mainw->play_start : 1;
2038 if (first_frame > sfile->frames) first_frame = sfile->frames;
2039 }
2040
2041 if (sfile->frames > 1 && prefs->noframedrop && (mainw->scratch == SCRATCH_NONE || mainw->scratch == SCRATCH_REV)) {
2042 // if noframedrop is set, we may not skip any frames
2043 // - the usual situation is that we are allowed to drop late frames
2044 // in this mode we may be forced to play at a reduced framerate
2045 if (nframe > cframe + 1) {
2046 // update this so the player can calculate 'dropped' frames correctly
2047 cfile->last_frameno -= (nframe - cframe - 1);
2048 nframe = cframe + 1;
2049 } else if (nframe < cframe - 1) {
2050 cfile->last_frameno += (cframe - 1 - nframe);
2051 nframe = cframe - 1;
2052 }
2053 }
2054 }
2055
2056 while (IS_NORMAL_CLIP(fileno) && (nframe < first_frame || nframe > last_frame)) {
2057 // get our frame back to within bounds:
2058 // define even parity (0) as backwards, odd parity (1) as forwards
2059 // we subtract the lower bound from the new frame, and divide the result by the selection length,
2060 // rounding towards zero. (nloops)
2061 // in ping mode this is then added to the original direction, and the resulting parity gives the new direction
2062 // the remainder after doing the division is then either added to the selection start (forwards)
2064 // lower bound and nloops and the remainder will be negative, so we subtract and add the negatvie value instead]
2065 // we must also set
2066
2067 if (fileno == mainw->playing_file) {
2068 // check if video stopped playback
2072 return 0;
2073 }
2074 // we need to set this for later in the function
2076 }
2077
2078 if (first_frame == last_frame) {
2079 nframe = first_frame;
2080 break;
2081 }
2082
2083 if (fps < 0.) dir = LIVES_DIRECTION_BACKWARD; // 0, and even parity
2084 else dir = LIVES_DIRECTION_FORWARD; // 1, and odd parity
2085
2086 if (dir == LIVES_DIRECTION_FORWARD && nframe < first_frame) {
2087 // if FWD and before lower bound, just jump to lower bound
2088 nframe = first_frame;
2089 sfile->last_frameno = first_frame;
2090 break;
2091 }
2092
2093 if (dir == LIVES_DIRECTION_BACKWARD && nframe > last_frame) {
2094 // if BACK and after upper bound, just jump to upper bound
2095 nframe = last_frame;
2096 sfile->last_frameno = last_frame;
2097 break;
2098 }
2099
2100 fdelta = ABS(sfile->frameno - sfile->last_frameno);
2101 nframe -= first_frame;
2102 selrange = (1 + last_frame - first_frame);
2103 if (nframe < 0) nframe = -nframe;
2104 nloops = nframe / selrange;
2105 if (mainw->ping_pong && (dir == LIVES_DIRECTION_BACKWARD || (clip_can_reverse(fileno)))) {
2106 dir += nloops + dir + 1;
2107 dir = LIVES_DIRECTION_PAR(dir);
2108 if (dir == LIVES_DIRECTION_BACKWARD && !clip_can_reverse(fileno))
2110 }
2111
2112 nframe -= nloops * selrange;
2113
2114 if (dir == LIVES_DIRECTION_FORWARD) {
2115 nframe += first_frame;
2116 sfile->last_frameno = nframe - fdelta;
2117 if (fps < 0.) {
2118 // backwards -> forwards
2119 if (fileno == mainw->playing_file) {
2121 norecurse = TRUE;
2122 dirchange_callback(NULL, NULL, 0, (LiVESXModifierType)0,
2123 LIVES_INT_TO_POINTER(SCREEN_AREA_FOREGROUND));
2124 norecurse = FALSE;
2125 } else sfile->pb_fps = -sfile->pb_fps;
2126 }
2127 }
2128
2129 else {
2130 nframe = last_frame - nframe;
2131 sfile->last_frameno = nframe + fdelta;
2132 if (fps > 0.) {
2133 // forwards -> backwards
2134 if (fileno == mainw->playing_file) {
2135 norecurse = TRUE;
2136 dirchange_callback(NULL, NULL, 0, (LiVESXModifierType)0,
2137 LIVES_INT_TO_POINTER(SCREEN_AREA_FOREGROUND));
2138 norecurse = FALSE;
2139 } else sfile->pb_fps = -sfile->pb_fps;
2140 }
2141 }
2142 break;
2143 }
2144
2145 if (fileno == mainw->playing_file && prefs->audio_src == AUDIO_SRC_INT && fileno == aplay_file && sfile->achans > 0
2149 // check if audio stopped playback. The audio player will also be checking this, BUT: we have to check here too
2150 // before doing any resync, otherwise the video can loop and if the audio is then resynced it may never reach the end
2151 calc_aframeno(fileno);
2152 if (!check_for_audio_stop(fileno, first_frame + 1, last_frame - 1)) {
2155 return 0;
2156 }
2157 resync_audio(nframe);
2158 if (mainw->scratch == SCRATCH_JUMP) {
2161 }
2162 }
2163 }
2164 if (fileno == mainw->playing_file) {
2165 if (mainw->scratch != SCRATCH_NONE) {
2166 sfile->last_frameno = nframe;
2168 }
2169 }
2170 return nframe;
2171}
2172
2173
2174void calc_maxspect(int rwidth, int rheight, int *cwidth, int *cheight) {
2175 // calculate maxspect (maximum size which maintains aspect ratio)
2176 // of cwidth, cheight - given restrictions rwidth * rheight
2177
2178 double aspect;
2179 if (*cwidth <= 0 || *cheight <= 0 || rwidth <= 0 || rheight <= 0) return;
2180
2181 aspect = (double)(*cwidth) / (double)(*cheight);
2182
2183 *cwidth = rwidth;
2184 *cheight = (double)(*cwidth) / aspect;
2185 if (*cheight > rheight) {
2186 // image too tall shrink it
2187 *cheight = rheight;
2188 *cwidth = (double)(*cheight) * aspect;
2189 }
2190 *cwidth = ((*cwidth + 1) >> 1) << 1;
2191 *cheight = ((*cheight + 1) >> 1) << 1;
2192}
2193
2194
2195void calc_minspect(int rwidth, int rheight, int *cwidth, int *cheight) {
2196 // calculate minspect (maximum size which conforms to aspect ratio of
2197 // of rwidth, rheight) - given restrictions cwidth * cheight
2198
2199 double aspect, dheight;
2200
2201 if (*cwidth <= 0 || *cheight <= 0 || rwidth <= 0 || rheight <= 0) return;
2202
2203 aspect = (double)(rwidth) / (double)(rheight);
2204 dheight = (double)(*cwidth) / aspect;
2205
2206 if (dheight <= ((double)(*cheight) * (1. + ASPECT_ALLOWANCE)))
2207 *cheight = (int)dheight;
2208 else
2209 *cwidth = (int)((double)(*cheight * aspect));
2210
2211 *cwidth = ((*cwidth + 1) >> 1) << 1;
2212 *cheight = ((*cheight + 1) >> 1) << 1;
2213}
2214
2215
2216void calc_midspect(int rwidth, int rheight, int *cwidth, int *cheight) {
2217 // calculate midspect (minimum size which conforms to aspect ratio of
2218 // of rwidth, rheight) - which contains cwidth, cheight
2219
2220 double aspect, dheight;
2221
2222 if (*cwidth <= 0 || *cheight <= 0 || rwidth <= 0 || rheight <= 0) return;
2223
2224 aspect = (double)(rwidth) / (double)(rheight);
2225 dheight = (double)(*cwidth) / aspect;
2226
2227 if (dheight >= ((double)(*cheight) * (1. - ASPECT_ALLOWANCE)))
2228 *cheight = (int)dheight;
2229 else
2230 *cwidth = (int)((double)(*cheight * aspect));
2231
2232 *cwidth = ((*cwidth + 1) >> 1) << 1;
2233 *cheight = ((*cheight + 1) >> 1) << 1;
2234}
2235
2237
2238void init_clipboard(void) {
2239 int current_file = mainw->current_file;
2240 char *com;
2241
2242 if (!clipboard) {
2243 // here is where we create the clipboard
2244 // use get_new_handle(clipnumber,name);
2245 if (!get_new_handle(CLIPBOARD_FILE, "clipboard")) {
2246 mainw->error = TRUE;
2247 return;
2248 }
2249 } else {
2250 // experimental feature - we can have duplicate copies of the clipboard with different palettes / gamma
2251 for (int i = 0; i < mainw->ncbstores; i++) {
2252 if (mainw->cbstores[i] != clipboard) {
2253 char *clipd = lives_build_path(prefs->workdir, mainw->cbstores[i]->handle, NULL);
2254 if (lives_file_test(clipd, LIVES_FILE_TEST_EXISTS)) {
2255 char *com = lives_strdup_printf("%s close \"%s\"", prefs->backend, mainw->cbstores[i]->handle);
2256 char *permitname = lives_build_path(clipd, TEMPFILE_MARKER "." LIVES_FILE_EXT_TMP, NULL);
2257 lives_touch(permitname);
2258 lives_free(permitname);
2259 lives_system(com, TRUE);
2260 lives_free(com);
2261 }
2262 lives_free(clipd);
2263 }
2264 }
2265 mainw->ncbstores = 0;
2266
2267 if (clipboard->frames > 0) {
2268 // clear old clipboard
2269 // need to set current file to 0 before monitoring progress
2271 cfile->cb_src = current_file;
2272
2273 if (cfile->clip_type == CLIP_TYPE_FILE) {
2274 lives_freep((void **)&cfile->frame_index);
2275 if (cfile->ext_src && cfile->ext_src_type == LIVES_EXT_SRC_DECODER) {
2277 }
2278 cfile->clip_type = CLIP_TYPE_DISK;
2279 }
2280
2281 com = lives_strdup_printf("%s clear_clipboard \"%s\"", prefs->backend, clipboard->handle);
2282 lives_rm(clipboard->info_file);
2283 lives_system(com, FALSE);
2284 lives_free(com);
2285
2286 if (THREADVAR(com_failed)) {
2287 mainw->current_file = current_file;
2288 return;
2289 }
2290
2291 cfile->progress_start = cfile->start;
2292 cfile->progress_end = cfile->end;
2293 // show a progress dialog, not cancellable
2294 do_progress_dialog(TRUE, FALSE, _("Clearing the clipboard"));
2295 }
2296 }
2297 mainw->current_file = current_file;
2298 *clipboard->file_name = 0;
2299 clipboard->img_type = IMG_TYPE_BEST; // override the pref
2300 clipboard->cb_src = current_file;
2301}
2302
2303
2304weed_plant_t *get_nth_info_message(int n) {
2305 weed_plant_t *msg = mainw->msg_list;
2306 const char *leaf;
2307 weed_error_t error;
2308 int m = 0;
2309
2310 if (n < 0) return NULL;
2311
2312 if (n >= mainw->n_messages) n = mainw->n_messages - 1;
2313
2314 if (n >= (mainw->n_messages >> 1)) {
2315 m = mainw->n_messages - 1;
2316 msg = weed_get_plantptr_value(msg, WEED_LEAF_PREVIOUS, &error);
2317 }
2318 if (mainw->ref_message && ABS(mainw->ref_message_n - n) < ABS(m - n)) {
2319 m = mainw->ref_message_n;
2320 msg = mainw->ref_message;
2321 }
2322
2323 if (m > n) leaf = WEED_LEAF_PREVIOUS;
2324 else leaf = WEED_LEAF_NEXT;
2325
2326 while (m != n) {
2327 msg = weed_get_plantptr_value(msg, leaf, &error);
2328 if (error != WEED_SUCCESS) return NULL;
2329 if (m > n) m--;
2330 else m++;
2331 }
2332 mainw->ref_message = msg;
2333 mainw->ref_message_n = n;
2334 return msg;
2335}
2336
2337
2338char *dump_messages(int start, int end) {
2339 weed_plant_t *msg = mainw->msg_list;
2340 char *text = lives_strdup(""), *tmp, *msgtext;
2341 boolean needs_newline = FALSE;
2342 int msgno = 0;
2343 int error;
2344
2345 while (msg) {
2346 msgtext = weed_get_string_value(msg, WEED_LEAF_LIVES_MESSAGE_STRING, &error);
2347 if (error != WEED_SUCCESS) break;
2348 if (msgno >= start) {
2349#ifdef SHOW_MSG_LINENOS
2350 tmp = lives_strdup_printf("%s%s(%d)%s", text, needs_newline ? "\n" : "", msgno, msgtext);
2351#else
2352 tmp = lives_strdup_printf("%s%s%s", text, needs_newline ? "\n" : "", msgtext);
2353#endif
2354 lives_free(text);
2355 text = tmp;
2356 needs_newline = TRUE;
2357 }
2358 lives_free(msgtext);
2359 if (++msgno > end) if (end > -1) break;
2360 msg = weed_get_plantptr_value(msg, WEED_LEAF_NEXT, &error);
2361 if (error != WEED_SUCCESS) break;
2362 }
2363 return text;
2364}
2365
2366
2367static weed_plant_t *make_msg(const char *text) {
2368 // make single msg. text should have no newlines in it, except possibly as the last character.
2369 weed_plant_t *msg = weed_plant_new(WEED_PLANT_LIVES);
2370 if (!msg) return NULL;
2371
2372 weed_set_int_value(msg, WEED_LEAF_LIVES_SUBTYPE, LIVES_WEED_SUBTYPE_MESSAGE);
2373 weed_set_string_value(msg, WEED_LEAF_LIVES_MESSAGE_STRING, text);
2374
2375 weed_set_plantptr_value(msg, WEED_LEAF_NEXT, NULL);
2376 weed_set_plantptr_value(msg, WEED_LEAF_PREVIOUS, NULL);
2377 return msg;
2378}
2379
2380
2381int free_n_msgs(int frval) {
2382 int error;
2383 weed_plant_t *next, *end;
2384
2385 if (frval <= 0) return WEED_SUCCESS;
2386 if (frval > mainw->n_messages || !mainw->msg_list) frval = mainw->n_messages;
2387
2388 end = weed_get_plantptr_value(mainw->msg_list, WEED_LEAF_PREVIOUS, &error); // list end
2389 if (error != WEED_SUCCESS) {
2390 return error;
2391 }
2392
2393 while (frval-- && mainw->msg_list) {
2394 next = weed_get_plantptr_value(mainw->msg_list, WEED_LEAF_NEXT, &error); // becomes new head
2395 if (error != WEED_SUCCESS) {
2396 return error;
2397 }
2398 weed_plant_free(mainw->msg_list);
2399 mainw->msg_list = next;
2400 if (mainw->msg_list) {
2401 if (mainw->msg_list == end) weed_set_plantptr_value(mainw->msg_list, WEED_LEAF_PREVIOUS, NULL);
2402 else weed_set_plantptr_value(mainw->msg_list, WEED_LEAF_PREVIOUS, end);
2403 }
2404 mainw->n_messages--;
2405 if (mainw->ref_message) {
2406 if (--mainw->ref_message_n < 0) mainw->ref_message = NULL;
2407 }
2408 }
2409
2410 if (mainw->msg_adj)
2412 return WEED_SUCCESS;
2413}
2414
2415
2416int add_messages_to_list(const char *text) {
2417 // append text to our message list, splitting it into lines
2418 // if we hit the max message limit then free the oldest one
2419 // returns a weed error
2420 weed_plant_t *msg, *end;;
2421 char **lines;
2422 int error, i, numlines;
2423
2424 if (prefs->max_messages == 0) return WEED_SUCCESS;
2425 if (!text || !*text) return WEED_SUCCESS;
2426
2427 // split text into lines
2428 numlines = get_token_count(text, '\n');
2429 lines = lives_strsplit(text, "\n", numlines);
2430
2431 for (i = 0; i < numlines; i++) {
2432 if (!mainw->msg_list) {
2433 mainw->msg_list = make_msg(lines[i]);
2434 if (!mainw->msg_list) {
2435 mainw->n_messages = 0;
2436 lives_strfreev(lines);
2437 return WEED_ERROR_MEMORY_ALLOCATION;
2438 }
2439 mainw->n_messages = 1;
2440 continue;
2441 }
2442
2443 end = weed_get_plantptr_value(mainw->msg_list, WEED_LEAF_PREVIOUS, &error);
2444 if (error != WEED_SUCCESS) {
2445 lives_strfreev(lines);
2446 return error;
2447 }
2448 if (!end) end = mainw->msg_list;
2449
2450 if (i == 0) {
2451 // append first line to text of last msg
2452 char *strg2, *strg = weed_get_string_value(end, WEED_LEAF_LIVES_MESSAGE_STRING, &error);
2453 if (error != WEED_SUCCESS) {
2454 lives_strfreev(lines);
2455 return error;
2456 }
2457 strg2 = lives_strdup_printf("%s%s", strg, lines[0]);
2458 weed_set_string_value(end, WEED_LEAF_LIVES_MESSAGE_STRING, strg2);
2459 lives_free(strg);
2460 lives_free(strg2);
2461 continue;
2462 }
2463
2464 if (prefs->max_messages > 0 && mainw->n_messages + 1 > prefs->max_messages) {
2465 // retire the oldest if we reached the limit
2466 error = free_n_msgs(1);
2467 if (error != WEED_SUCCESS) {
2468 lives_strfreev(lines);
2469 return error;
2470 }
2471 if (!mainw->msg_list) {
2472 i = numlines - 2;
2473 continue;
2474 }
2475 }
2476
2477 msg = make_msg(lines[i]);
2478 if (!msg) {
2479 lives_strfreev(lines);
2480 return WEED_ERROR_MEMORY_ALLOCATION;
2481 }
2482
2483 mainw->n_messages++;
2484
2485 // head will get new previous (us)
2486 weed_set_plantptr_value(mainw->msg_list, WEED_LEAF_PREVIOUS, msg);
2487 // we will get new previous (end)
2488 weed_set_plantptr_value(msg, WEED_LEAF_PREVIOUS, end);
2489 // end will get new next (us)
2490 weed_set_plantptr_value(end, WEED_LEAF_NEXT, msg);
2491 }
2492 lives_strfreev(lines);
2493 return WEED_SUCCESS;
2494}
2495
2496
2497boolean d_print_urgency(double timeout, const char *fmt, ...) {
2498 // overlay emergency message on playback frame
2499 va_list xargs;
2500 char *text;
2501
2502 va_start(xargs, fmt);
2503 text = lives_strdup_vprintf(fmt, xargs);
2504 va_end(xargs);
2505
2506 d_print(text);
2507
2509 int nfa = mainw->next_free_alarm;
2511 lives_freep((void **)&mainw->urgency_msg);
2513 mainw->next_free_alarm = nfa;
2514 mainw->urgency_msg = lives_strdup(text);
2515 lives_free(text);
2516 return TRUE;
2517 }
2518 lives_free(text);
2519 return FALSE;
2520}
2521
2522
2523boolean d_print_overlay(double timeout, const char *fmt, ...) {
2524 // overlay a message on playback frame
2525 va_list xargs;
2526 char *text;
2527 va_start(xargs, fmt);
2528 text = lives_strdup_vprintf(fmt, xargs);
2529 va_end(xargs);
2531 lives_freep((void **)&mainw->overlay_msg);
2532 mainw->overlay_msg = lives_strdup(text);
2533 lives_free(text);
2535 return TRUE;
2536 }
2537 lives_free(text);
2538 return FALSE;
2539}
2540
2541
2542void d_print(const char *fmt, ...) {
2543 // collect output for the main message area (and info log)
2544
2545 // there are several small tweaks for this:
2546
2547 // mainw->suppress_dprint :: TRUE - dont print anything, return (for silencing noisy message blocks)
2548 // mainw->no_switch_dprint :: TRUE - disable printing of switch message when maine->current_file changes
2549
2550 // mainw->last_dprint_file :: clip number of last mainw->current_file;
2551 va_list xargs;
2552
2553 char *tmp, *text;
2554
2555 if (!prefs->show_gui) return;
2556 if (mainw->suppress_dprint) return;
2557
2558 va_start(xargs, fmt);
2559 text = lives_strdup_vprintf(fmt, xargs);
2560 va_end(xargs);
2561
2563 (mainw->current_file == -1 || (cfile && cfile->clip_type != CLIP_TYPE_GENERATOR)) && !mainw->no_switch_dprint) {
2564 if (mainw->current_file > 0) {
2565 char *swtext = lives_strdup_printf(_("\n==============================\nSwitched to clip %s\n"),
2566 tmp = get_menu_name(cfile,
2567 TRUE));
2568 lives_free(tmp);
2569 add_messages_to_list(swtext);
2570 lives_free(swtext);
2571 } else {
2572 add_messages_to_list(_("\n==============================\nSwitched to empty clip\n"));
2573 }
2574 }
2575
2577 lives_free(text);
2578
2580 && ((!mainw->multitrack && mainw->msg_area
2581 && mainw->msg_adj)
2582 || (!mainw->multitrack && mainw->multitrack->msg_area
2583 && mainw->multitrack->msg_adj))) {
2584 if (mainw->multitrack) {
2587 } else {
2590 }
2591 }
2592
2593 if ((mainw->current_file == -1 || (cfile && cfile->clip_type != CLIP_TYPE_GENERATOR)) &&
2595}
2596
2597
2598static void d_print_utility(const char *text, int osc_note, const char *osc_detail) {
2599 boolean nsdp = mainw->no_switch_dprint;
2601 d_print(text);
2602 if (osc_note != LIVES_OSC_NOTIFY_NONE) lives_notify(osc_note, osc_detail);
2603 if (!nsdp) {
2605 d_print("");
2606 }
2607}
2608
2609
2611 d_print_utility(_("cancelled.\n"), LIVES_OSC_NOTIFY_CANCELLED, "");
2612}
2613
2614
2616 d_print_utility(_("failed.\n"), LIVES_OSC_NOTIFY_FAILED, "");
2617}
2618
2619
2621 d_print_utility(_("done.\n"), 0, NULL);
2622}
2623
2624
2626 d_print_utility(_("error in file. Failed.\n"), 0, NULL);
2627}
2628
2629
2631 if (frames == 0) d_print_cancelled();
2632 else {
2633 char *msg = lives_strdup_printf(P_("%d frame is enough !\n", "%d frames are enough !\n", frames), frames);
2634 d_print_utility(msg, 0, NULL);
2635 lives_free(msg);
2636 }
2637}
2638
2639
2640void buffer_lmap_error(lives_lmap_error_t lerror, const char *name, livespointer user_data, int clipno,
2641 int frameno, double atime, boolean affects_current) {
2642 lmap_error *err = (lmap_error *)lives_malloc(sizeof(lmap_error));
2643 if (!err) return;
2644 err->type = lerror;
2645 if (name) err->name = lives_strdup(name);
2646 else err->name = NULL;
2647 err->data = user_data;
2648 err->clipno = clipno;
2649 err->frameno = frameno;
2650 err->atime = atime;
2651 err->current = affects_current;
2652 mainw->new_lmap_errors = lives_list_prepend(mainw->new_lmap_errors, err);
2653}
2654
2655
2656void unbuffer_lmap_errors(boolean add) {
2657 LiVESList *list = mainw->new_lmap_errors;
2658 while (list) {
2659 lmap_error *err = (lmap_error *)list->data;
2660 if (add) add_lmap_error(err->type, err->name, err->data, err->clipno, err->frameno, err->atime, err->current);
2661 else mainw->files[err->clipno]->tcache_dubious_from = 0;
2662 if (err->name) lives_free(err->name);
2663 lives_free(err);
2664 list = list->next;
2665 }
2666 if (mainw->new_lmap_errors) {
2667 lives_list_free(mainw->new_lmap_errors);
2668 mainw->new_lmap_errors = NULL;
2669 }
2670}
2671
2672
2673boolean add_lmap_error(lives_lmap_error_t lerror, const char *name, livespointer user_data, int clipno,
2674 int frameno, double atime, boolean affects_current) {
2675 // potentially add a layout map error to the layout textbuffer
2676 LiVESTextIter end_iter;
2677 LiVESList *lmap;
2678
2679 char *text, *name2;
2680 char **array;
2681
2682 double orig_fps;
2683 double max_time;
2684
2685 int resampled_frame;
2686
2687 lives_text_buffer_get_end_iter(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &end_iter);
2688
2689 if (affects_current && !user_data) {
2691 (livespointer)lives_text_buffer_create_mark
2692 (LIVES_TEXT_BUFFER(mainw->layout_textbuffer), NULL, &end_iter, TRUE));
2693 }
2694
2695 switch (lerror) {
2697 if (!(*name)) name2 = (_("(blank)"));
2698 else name2 = lives_strdup(name);
2699 text = lives_strdup_printf
2700 (_("The set name has been changed from %s to %s. Affected layouts have been updated accordingly\n"),
2701 name2, (char *)user_data);
2702 lives_text_buffer_insert(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &end_iter, text, -1);
2703 lives_free(name2);
2704 lives_free(text);
2705 break;
2708 text = lives_strdup_printf(_("The clip %s is missing from this set.\nIt is required by the following layouts:\n"), name);
2709 lives_text_buffer_insert(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &end_iter, text, -1);
2710 lives_free(text);
2712 text = lives_strdup_printf(_("The clip %s has been closed.\nIt is required by the following layouts:\n"), name);
2713 lives_text_buffer_insert(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &end_iter, text, -1);
2714 lives_free(text);
2715 break;
2717 text = lives_strdup_printf(_("Frames have been shifted in the clip %s.\nThe following layouts are affected:\n"), name);
2718 lives_text_buffer_insert(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &end_iter, text, -1);
2719 lives_free(text);
2720 break;
2722 text = lives_strdup_printf(_("Frames have been deleted from the clip %s.\nThe following layouts are affected:\n"), name);
2723 lives_text_buffer_insert(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &end_iter, text, -1);
2724 lives_free(text);
2725 break;
2727 text = lives_strdup_printf(_("Audio has been deleted from the clip %s.\nThe following layouts are affected:\n"), name);
2728 lives_text_buffer_insert(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &end_iter, text, -1);
2729 lives_free(text);
2730 break;
2732 text = lives_strdup_printf(_("Audio has been shifted in clip %s.\nThe following layouts are affected:\n"), name);
2733 lives_text_buffer_insert(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &end_iter, text, -1);
2734 lives_free(text);
2735 break;
2737 text = lives_strdup_printf(_("Audio has been altered in the clip %s.\nThe following layouts are affected:\n"), name);
2738 lives_text_buffer_insert(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &end_iter, text, -1);
2739 lives_free(text);
2740 break;
2742 text = lives_strdup_printf(_("Frames have been altered in the clip %s.\nThe following layouts are affected:\n"), name);
2743 lives_text_buffer_insert(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &end_iter, text, -1);
2744 lives_free(text);
2745 break;
2746 }
2747
2748 if (affects_current && user_data) {
2750 (livespointer)lives_text_buffer_create_mark
2751 (LIVES_TEXT_BUFFER(mainw->layout_textbuffer), NULL, &end_iter, TRUE));
2752 }
2753
2754 switch (lerror) {
2756 lmap = mainw->current_layouts_map;
2757 while (lmap) {
2758 array = lives_strsplit((char *)lmap->data, "|", -1);
2759 text = lives_strdup_printf("%s\n", array[0]);
2760 lives_text_buffer_insert(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &end_iter, text, -1);
2761 lives_free(text);
2762 // we could list all affected layouts, which could potentially be a lot !
2763 //mainw->affected_layouts_map=lives_list_append_unique(mainw->affected_layouts_map,array[0]);
2764 lives_strfreev(array);
2765 lmap = lmap->next;
2766 }
2767 break;
2770 if (affects_current) {
2772 lives_text_buffer_insert(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &end_iter, text, -1);
2773 lives_free(text);
2776
2778 (livespointer)lives_text_buffer_create_mark(LIVES_TEXT_BUFFER(mainw->layout_textbuffer),
2779 NULL, &end_iter, TRUE));
2780
2781 }
2782 lmap = (LiVESList *)user_data;
2783 while (lmap) {
2784 array = lives_strsplit((char *)lmap->data, "|", -1);
2785 text = lives_strdup_printf("%s\n", array[0]);
2786 lives_text_buffer_insert(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &end_iter, text, -1);
2787 lives_free(text);
2789 lives_strfreev(array);
2790 lmap = lmap->next;
2791 }
2792 break;
2796 if (affects_current) {
2798 lives_text_buffer_insert(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &end_iter, text, -1);
2799 lives_free(text);
2802
2804 (livespointer)lives_text_buffer_create_mark(LIVES_TEXT_BUFFER(mainw->layout_textbuffer),
2805 NULL, &end_iter, TRUE));
2806 }
2807 lmap = (LiVESList *)user_data;
2808 while (lmap) {
2809 array = lives_strsplit((char *)lmap->data, "|", -1);
2810 orig_fps = strtod(array[3], NULL);
2811 resampled_frame = count_resampled_frames(frameno, orig_fps, mainw->files[clipno]->fps);
2812 if (resampled_frame <= atoi(array[2])) {
2813 text = lives_strdup_printf("%s\n", array[0]);
2814 lives_text_buffer_insert(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &end_iter, text, -1);
2815 lives_free(text);
2817 }
2818 lives_strfreev(array);
2819 lmap = lmap->next;
2820 }
2821 break;
2825 if (affects_current) {
2827 lives_text_buffer_insert(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &end_iter, text, -1);
2828 lives_free(text);
2831
2833 (livespointer)lives_text_buffer_create_mark(LIVES_TEXT_BUFFER(mainw->layout_textbuffer),
2834 NULL, &end_iter, TRUE));
2835 }
2836 lmap = (LiVESList *)user_data;
2837 while (lmap) {
2838 array = lives_strsplit((char *)lmap->data, "|", -1);
2839 max_time = strtod(array[4], NULL);
2840 if (max_time > 0. && atime <= max_time) {
2841 text = lives_strdup_printf("%s\n", array[0]);
2842 lives_text_buffer_insert(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &end_iter, text, -1);
2843 lives_free(text);
2845 }
2846 lives_strfreev(array);
2847 lmap = lmap->next;
2848 }
2849 break;
2850 }
2851
2853 if (mainw->multitrack) lives_widget_set_sensitive(mainw->multitrack->show_layout_errors, TRUE);
2854 return TRUE;
2855}
2856
2857
2859 LiVESTextIter start_iter, end_iter;
2860 LiVESList *lmap;
2861
2862 lives_text_buffer_get_start_iter(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &start_iter);
2863 lives_text_buffer_get_end_iter(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &end_iter);
2864 lives_text_buffer_delete(LIVES_TEXT_BUFFER(mainw->layout_textbuffer), &start_iter, &end_iter);
2865
2867
2868 while (lmap) {
2869 lives_free((livespointer)lmap->data);
2870 lmap = lmap->next;
2871 }
2872 lives_list_free(lmap);
2873
2876 if (mainw->multitrack) lives_widget_set_sensitive(mainw->multitrack->show_layout_errors, FALSE);
2877
2880 }
2881}
2882
2894boolean check_for_lock_file(const char *set_name, int type) {
2895 char *com;
2896
2897 if (type == 1 && !lives_strcmp(set_name, mainw->set_name)) return TRUE;
2898
2899 com = lives_strdup_printf("%s check_for_lock \"%s\" \"%s\" %d", prefs->backend_sync, set_name, capable->myname,
2900 capable->mainpid);
2901
2903
2907 lives_free(com);
2908
2909 if (THREADVAR(com_failed)) return FALSE;
2910
2911 if (*(mainw->msg)) {
2912 if (type == 0) {
2913 if (mainw->recovering_files) return do_set_locked_warning(set_name);
2916 do_error_dialogf(_("Set %s\ncannot be opened, as it is in use\nby another copy of LiVES.\n"), set_name);
2919 } else if (type == 1) {
2920 if (!mainw->osc_auto) do_error_dialogf(_("\nThe set %s is currently in use by another copy of LiVES.\n"
2921 "Please choose another set name.\n"), set_name);
2922 }
2923 return FALSE;
2924 }
2925 return TRUE;
2926}
2927
2928
2929boolean do_std_checks(const char *type_name, const char *type, size_t maxlen, const char *nreject) {
2930 char *xtype = lives_strdup(type), *msg;
2931 const char *reject = " /\\*\"";
2932 size_t slen = strlen(type_name);
2933
2934 if (nreject) reject = nreject;
2935
2936 if (slen == 0) {
2937 msg = lives_strdup_printf(_("\n%s names may not be blank.\n"), xtype);
2938 if (!mainw->osc_auto) do_error_dialog(msg);
2939 lives_free(msg);
2940 lives_free(xtype);
2941 return FALSE;
2942 }
2943
2944 if (slen > MAX_SET_NAME_LEN) {
2945 msg = lives_strdup_printf(_("\n%s names may not be longer than %d characters.\n"), xtype, (int)maxlen);
2946 if (!mainw->osc_auto) do_error_dialog(msg);
2947 lives_free(msg);
2948 lives_free(xtype);
2949 return FALSE;
2950 }
2951
2952 if (strcspn(type_name, reject) != slen) {
2953 msg = lives_strdup_printf(_("\n%s names may not contain spaces or the characters%s.\n"), xtype, reject);
2954 if (!mainw->osc_auto) do_error_dialog(msg);
2955 lives_free(msg);
2956 lives_free(xtype);
2957 return FALSE;
2958 }
2959
2960 for (int i = 0; i < slen; i++) {
2961 if (type_name[i] == '.' && (i == 0 || type_name[i - 1] == '.')) {
2962 msg = lives_strdup_printf(_("\n%s names may not start with a '.' or contain '..'\n"), xtype);
2963 if (!mainw->osc_auto) do_error_dialog(msg);
2964 lives_free(msg);
2965 lives_free(xtype);
2966 return FALSE;
2967 }
2968 }
2969
2970 lives_free(xtype);
2971 return TRUE;
2972}
2973
2974
2975boolean is_legal_set_name(const char *set_name, boolean allow_dupes, boolean leeway) {
2976 // check (clip) set names for validity
2977 // - may not be of zero length
2978 // - may not contain spaces or characters / \ * "
2979 // - must NEVER be name of a set in use by another copy of LiVES (i.e. with a lock file)
2980
2981 // - as of 1.6.0:
2982 // - may not start with a .
2983 // - may not contain ..
2984
2985 // - as of 3.2.0
2986 // - must start with a letter [a - z] or [A - Z]
2987
2988 // should be in FILESYSTEM encoding
2989
2990 // may not be longer than MAX_SET_NAME_LEN chars
2991
2992 // iff allow_dupes is FALSE then we disallow the name of any existing set (has a subdirectory in the working directory)
2993
2994 if (!do_std_checks(set_name, _("Set"), MAX_SET_NAME_LEN, NULL)) return FALSE;
2995
2996 // check if this is a set in use by another copy of LiVES
2997 if (mainw && mainw->is_ready && !check_for_lock_file(set_name, 1)) return FALSE;
2998
2999 if ((set_name[0] < 'a' || set_name[0] > 'z') && (set_name[0] < 'A' || set_name[0] > 'Z')) {
3000 if (leeway) {
3001 if (mainw->is_ready)
3002 do_warning_dialog(_("As of LiVES 3.2.0 all set names must begin with alphabetical character\n"
3003 "(A - Z or a - z)\nYou will need to give a new name for the set when saving it.\n"));
3004 } else {
3005 do_error_dialog(_("All set names must begin with an alphabetical character\n(A - Z or a - z)\n"));
3006 return FALSE;
3007 }
3008 }
3009
3010 if (!allow_dupes) {
3011 // check for duplicate set names
3012 char *set_dir = lives_build_filename(prefs->workdir, set_name, NULL);
3013 if (lives_file_test(set_dir, LIVES_FILE_TEST_IS_DIR)) {
3014 lives_free(set_dir);
3015 return do_yesno_dialogf(_("\nThe set %s already exists.\n"
3016 "Do you want to add the current clips to the existing set ?.\n"), set_name);
3017 }
3018 lives_free(set_dir);
3019 }
3020
3021 return TRUE;
3022}
3023
3024
3026 switch (imgtype) {
3027 case IMG_TYPE_JPEG: return LIVES_FILE_EXT_JPG; // "jpg"
3028 case IMG_TYPE_PNG: return LIVES_FILE_EXT_PNG; // "png"
3029 default: return "";
3030 }
3031}
3032
3033
3036}
3037
3038
3039LIVES_GLOBAL_INLINE const char *image_ext_to_lives_image_type(const char *img_ext) {
3040 if (!strcmp(img_ext, LIVES_FILE_EXT_PNG)) return LIVES_IMAGE_TYPE_PNG;
3041 if (!strcmp(img_ext, LIVES_FILE_EXT_JPG)) return LIVES_IMAGE_TYPE_JPEG;
3043}
3044
3045
3047 if (!strcmp(lives_img_type, LIVES_IMAGE_TYPE_PNG)) return IMG_TYPE_PNG;
3048 if (!strcmp(lives_img_type, LIVES_IMAGE_TYPE_JPEG)) return IMG_TYPE_JPEG;
3049 return IMG_TYPE_UNKNOWN;
3050}
3051
3052
3054 const char *img_ext) {
3055 char *fname, *ret;
3056 if (!*img_ext) {
3057 sfile->img_type = resolve_img_type(sfile);
3058 img_ext = get_image_ext_for_type(sfile->img_type);
3059 }
3060 fname = lives_strdup_printf("%08d.%s", frame, img_ext);
3061 ret = lives_build_filename(prefs->workdir, sfile->handle, fname, NULL);
3062 lives_free(fname);
3063 return ret;
3064}
3065
3066
3074boolean check_frame_count(int idx, boolean last_checked) {
3076 char *frame;
3077 if (mainw->files[idx]->frames > 0) {
3078 frame = make_image_file_name(mainw->files[idx], mainw->files[idx]->frames,
3080 if (!lives_file_test(frame, LIVES_FILE_TEST_EXISTS)) {
3081 // not enough frames
3082 lives_free(frame);
3083 return FALSE;
3084 }
3085 lives_free(frame);
3086 }
3087
3089 frame = make_image_file_name(mainw->files[idx], mainw->files[idx]->frames + 1,
3091
3092 if (lives_file_test(frame, LIVES_FILE_TEST_EXISTS)) {
3094 lives_free(frame);
3095 return FALSE;
3096 }
3097 lives_free(frame);
3098
3100 return TRUE;
3101}
3102
3103
3109int get_frame_count(int idx, int start) {
3110 ssize_t bytes;
3111 char *com = lives_strdup_printf("%s count_frames \"%s\" %s %d", prefs->backend_sync, mainw->files[idx]->handle,
3113
3114 bytes = lives_popen(com, FALSE, mainw->msg, MAINW_MSG_SIZE);
3115 lives_free(com);
3116
3117 if (THREADVAR(com_failed)) return 0;
3118
3119 if (bytes > 0) return atoi(mainw->msg);
3120 return 0;
3121}
3122
3123
3124boolean get_frames_sizes(int fileno, int frame, int *hsize, int *vsize) {
3125 // get the actual physical frame size
3126 lives_clip_t *sfile = mainw->files[fileno];
3128 char *fname = make_image_file_name(sfile, frame, get_image_ext_for_type(sfile->img_type));
3129 weed_set_int_value(layer, WEED_LEAF_HOST_FLAGS, LIVES_LAYER_GET_SIZE_ONLY);
3130 if (!weed_layer_create_from_file_progressive(layer, fname, 0, 0, WEED_PALETTE_END,
3132 lives_free(fname);
3133 return FALSE;
3134 }
3135 lives_free(fname);
3136 *hsize = weed_layer_get_width(layer);
3137 *vsize = weed_layer_get_height(layer);
3138 weed_layer_free(layer);
3139 return FALSE;
3140}
3141
3142
3143boolean lives_string_ends_with(const char *string, const char *fmt, ...) {
3144 char *textx;
3145 va_list xargs;
3146 size_t slen, cklen;
3147 boolean ret = FALSE;
3148
3149 if (!string) return FALSE;
3150
3151 va_start(xargs, fmt);
3152 textx = lives_strdup_vprintf(fmt, xargs);
3153 va_end(xargs);
3154 if (!textx) return FALSE;
3155 slen = lives_strlen(string);
3156 cklen = lives_strlen(textx);
3157 if (cklen == 0 || cklen > slen) {
3158 lives_free(textx);
3159 return FALSE;
3160 }
3161 if (!lives_strncmp(string + slen - cklen, textx, cklen)) ret = TRUE;
3162 lives_free(textx);
3163 return ret;
3164}
3165
3166
3167void get_dirname(char *filename) {
3168 char *tmp;
3169 // get directory name from a file
3170 // filename should point to char[PATH_MAX]
3171 // WARNING: will change contents of filename
3172
3173 lives_snprintf(filename, PATH_MAX, "%s%s", (tmp = lives_path_get_dirname(filename)), LIVES_DIR_SEP);
3174 if (!strcmp(tmp, ".")) {
3175 char *tmp1 = lives_get_current_dir(), *tmp2 = lives_build_filename(tmp1, filename + 2, NULL);
3176 lives_free(tmp1);
3177 lives_snprintf(filename, PATH_MAX, "%s", tmp2);
3178 lives_free(tmp2);
3179 }
3180
3181 lives_free(tmp);
3182}
3183
3184
3185char *get_dir(const char *filename) {
3186 // get directory as string, should free after use
3187 char tmp[PATH_MAX];
3188 lives_snprintf(tmp, PATH_MAX, "%s", filename);
3189 get_dirname(tmp);
3190 return lives_strdup(tmp);
3191}
3192
3193
3194LIVES_GLOBAL_INLINE void get_basename(char *filename) {
3195 // get basename from a file
3196 // (filename without directory)
3197 // filename should point to char[PATH_MAX]
3198 // WARNING: will change contents of filename
3199 char *tmp = lives_path_get_basename(filename);
3200 lives_snprintf(filename, PATH_MAX, "%s", tmp);
3201 lives_free(tmp);
3202}
3203
3204
3205LIVES_GLOBAL_INLINE void get_filename(char *filename, boolean strip_dir) {
3206 // get filename (part without extension) of a file
3207 //filename should point to char[PATH_MAX]
3208 // WARNING: will change contents of filename
3209 if (strip_dir) get_basename(filename);
3210 lives_strstop(filename, '.');
3211}
3212
3214LIVES_GLOBAL_INLINE char *lives_get_filename(char *uri) {return lives_strstop(lives_path_get_basename(uri), '.');}
3215
3216
3217char *get_extension(const char *filename) {
3218 // return file extension without the "."
3219 char *tmp = lives_path_get_basename(filename);
3220 char *ptr = strrchr(tmp, '.');
3221 if (!ptr) {
3222 lives_free(tmp);
3223 return lives_strdup("");
3224 } else {
3225 char *ret = lives_strdup(ptr + 1);
3226 lives_free(tmp);
3227 return ret;
3228 }
3229}
3230
3231
3232char *ensure_extension(const char *fname, const char *ext) {
3233 // make sure filename fname has file extension ext
3234 // if ext does not begin with a "." we prepend one to the start of ext
3235 // we then check if fname ends with ext. If not we append ext to fname.
3236 // we return a copy of fname, possibly modified. The string returned should be freed after use.
3237 // NOTE: the original ext is not changed.
3238
3239 size_t se = strlen(ext), sf;
3240 char *eptr = (char *)ext;
3241
3242 if (!fname) return NULL;
3243
3244 if (se == 0) return lives_strdup(fname);
3245
3246 if (eptr[0] == '.') {
3247 eptr++;
3248 se--;
3249 }
3250
3251 sf = lives_strlen(fname);
3252 if (sf < se + 1 || strcmp(fname + sf - se, eptr) || fname[sf - se - 1] != '.') {
3253 return lives_strconcat(fname, ".", eptr, NULL);
3254 }
3255
3256 return lives_strdup(fname);
3257}
3258
3259
3260// input length includes terminating NUL
3261
3262LIVES_GLOBAL_INLINE char *lives_ellipsize(char *txt, size_t maxlen, LiVESEllipsizeMode mode) {
3266 // LIVES_ELLIPSIZE_NONE - do not ellipsise
3267 // return value should be freed, unless txt is returned
3268 const char ellipsis[4] = "...\0";
3269 size_t slen = lives_strlen(txt);
3270 off_t stlen, enlen;
3271 char *retval = txt;
3272 if (!maxlen) return NULL;
3273 if (slen >= maxlen) {
3274 if (maxlen == 1) return lives_strdup("");
3275 retval = (char *)lives_malloc(maxlen);
3276 if (maxlen == 2) return lives_strdup(".");
3277 if (maxlen == 3) return lives_strdup("..");
3278 if (maxlen == 4) return lives_strdup("...");
3279 maxlen -= 4;
3280 switch (mode) {
3282 lives_memcpy(retval, ellipsis, 3);
3283 lives_memcpy(retval + 3, txt + slen - maxlen, maxlen + 1);
3284 break;
3286 lives_memcpy(retval, txt, maxlen);
3287 lives_memcpy(retval + maxlen, ellipsis, 4);
3288 break;
3290 enlen = maxlen >> 1;
3291 stlen = maxlen - enlen;
3292 lives_memcpy(retval, txt, stlen);
3293 lives_memcpy(retval + stlen, ellipsis, 3);
3294 lives_memcpy(retval + stlen + 3, txt + slen - enlen, enlen + 1);
3295 break;
3296 default: break;
3297 }
3298 }
3299 return retval;
3300}
3301
3302
3303LIVES_GLOBAL_INLINE char *lives_pad(char *txt, size_t minlen, int align) {
3304 // pad with spaces at start and end respectively
3305 // ealign gives ellipsis pos, palign can be LIVES_ALIGN_START, LIVES_ALIGN_END
3306 // LIVES_ALIGN_START -> pad end, LIVES_ALIGN_END -> pad start
3307 // LIVES_ALIGN_CENTER -> pad on both sides
3308 // LIVES_ALIGN_FILL - do not pad
3309 size_t slen = lives_strlen(txt);
3310 char *retval = txt;
3311 off_t ipos = 0;
3312 if (align == LIVES_ALIGN_FILL) return txt;
3313 if (slen < minlen - 1) {
3314 retval = (char *)lives_malloc(minlen);
3315 lives_memset(retval, ' ', --minlen);
3316 retval[minlen] = 0;
3317 switch (align) {
3318 case LIVES_ALIGN_END:
3319 ipos = minlen - slen;
3320 break;
3321 case LIVES_ALIGN_CENTER:
3322 ipos = minlen - slen;
3323 break;
3324 default:
3325 break;
3326 }
3327 lives_memcpy(retval + ipos, txt, slen);
3328 }
3329 return retval;
3330}
3331
3332
3333LIVES_GLOBAL_INLINE char *lives_pad_ellipsize(char *txt, size_t fixlen, int palign, LiVESEllipsizeMode emode) {
3334 // if len of txt < fixlen it will be padded, if longer, ellipsised
3335 // ealign gives ellipsis pos, palign can be LIVES_ALIGN_START, LIVES_ALIGN_END
3336 // pad with spaces at start and end respectively
3337 // LIVES_ALIGN_CENTER -> pad on both sides
3338 // LIVES_ALIGN_FILL - do not pad
3339 size_t slen = lives_strlen(txt);
3340 if (slen == fixlen - 1) return txt;
3341 if (slen >= fixlen) return lives_ellipsize(txt, fixlen, emode);
3342 return lives_pad(txt, fixlen, palign);
3343}
3344
3345
3346boolean ensure_isdir(char *fname) {
3347 // ensure dirname ends in a single dir separator
3348 // fname should be char[PATH_MAX]
3349
3350 // returns TRUE if fname was altered
3351
3352 size_t tlen = lives_strlen(fname), slen, tlen2;
3353 size_t dslen = strlen(LIVES_DIR_SEP);
3354 ssize_t offs;
3355 boolean ret = FALSE;
3356 char *tmp = lives_strdup(fname), *tmp2;
3357
3358 while (1) {
3359 // recursively remove double DIR_SEP
3361 if ((tlen2 = lives_strlen(tmp2)) < tlen) {
3362 ret = TRUE;
3363 lives_free(tmp);
3364 tmp = tmp2;
3365 tlen = tlen2;
3366 } else {
3367 lives_free(tmp2);
3368 break;
3369 }
3370 }
3371
3372 if (ret) lives_snprintf(fname, PATH_MAX, "%s", tmp);
3373 lives_free(tmp);
3374
3375 slen = tlen - 1;
3376 offs = slen;
3377
3378 // we should now only have one or zero DIR_SEP at the end, but just in case we remove all but the last one
3379 while (offs >= 0 && !strncmp(fname + offs, LIVES_DIR_SEP, dslen)) offs -= dslen;
3380 if (offs == slen - dslen) return ret; // format is OK as-is
3381
3382 // strip off all terminating DIR_SEP and then append one
3383 if (++offs < 0) offs = 0;
3384 if (offs < slen) fname[offs] = 0;
3385 fname = strncat(fname, LIVES_DIR_SEP, PATH_MAX - offs - 1);
3386 return TRUE;
3387}
3388
3389
3390boolean dirs_equal(const char *dira, const char *dirb) {
3391 // filenames in locale encoding
3392 char *tmp;
3393 char dir1[PATH_MAX];
3394 char dir2[PATH_MAX];
3395 lives_snprintf(dir1, PATH_MAX, "%s", (tmp = F2U8(dira)));
3396 lives_free(tmp);
3397 lives_snprintf(dir2, PATH_MAX, "%s", (tmp = F2U8(dirb)));
3398 lives_free(tmp);
3399 ensure_isdir(dir1);
3400 ensure_isdir(dir2);
3401 // TODO: for some (Linux) fstypes we should use strcasecmp
3402 // can get this using "df -T"
3403 return (!lives_strcmp(dir1, dir2));
3404}
3405
3406
3407void get_location(const char *exe, char *val, int maxlen) {
3408 // find location of "exe" in path
3409 // sets it in val which is a char array of maxlen bytes
3410
3411 char *loc;
3412 if ((loc = lives_find_program_in_path(exe)) != NULL) {
3413 lives_snprintf(val, maxlen, "%s", loc);
3414 lives_free(loc);
3415 } else {
3416 lives_memset(val, 0, 1);
3417 }
3418}
3419
3420
3422 char *loc;
3423 if ((loc = lives_find_program_in_path(exe)) != NULL) {
3424 lives_free(loc);
3425 return PRESENT;
3426 }
3427 // for now we don't return MISSING (requires code update to differentiate MISSING / UNCHECKED / PRESENT)
3428 return FALSE;
3429}
3430
3431
3432// check if executable is present, missing or unchecked
3433// if unchecked, check for it, and if not found ask the user politely to install it
3434boolean check_for_executable(lives_checkstatus_t *cap, const char *exec) {
3435#ifdef NEW_CHECKSTATUS
3436 if (!cap || (*cap)->present == UNCHECKED) {
3437 if (!cap || ((*cap)->flags & INSTALL_CANLOCAL)) {
3439#else
3440 if (!cap || *cap == UNCHECKED) {
3441 if (!lives_strcmp(exec, EXEC_YOUTUBE_DL)) {
3442#endif
3443 char *localv = lives_build_filename(capable->home_dir, LOCAL_HOME_DIR, "bin", exec, NULL);
3444 if (lives_file_test(localv, LIVES_FILE_TEST_IS_EXECUTABLE)) {
3445 lives_free(localv);
3446 if (cap) *cap = LOCAL;
3447 return TRUE;
3448 }
3449 lives_free(localv);
3450 }
3451 if (has_executable(exec)) {
3452 if (cap) *cap = PRESENT;
3453 return TRUE;
3454 } else {
3455 if (!lives_strcmp(exec, EXEC_XDOTOOL) || !lives_strcmp(exec, EXEC_WMCTRL)) {
3456 if (cap) *cap = MISSING;
3457 }
3458 //if (importance == necessary)
3459 //do_please_install(exec);
3460#ifdef HAS_MISSING_PRESENCE
3461 if (cap) *cap = MISSING;
3462#endif
3463 //do_program_not_found_error(exec);
3464 return FALSE;
3465 }
3466 }
3467#if 0
3468}
3469}
3470#endif
3471return (*cap == PRESENT || *cap == LOCAL);
3472}
3473
3474
3475uint64_t get_version_hash(const char *exe, const char *sep, int piece) {
3477 uint64_t val;
3478 char buff[128];
3479 char **array;
3480 int ntok;
3481
3482 lives_popen(exe, TRUE, buff, 128);
3483 if (THREADVAR(com_failed)) {
3484 THREADVAR(com_failed) = FALSE;
3485 return -2;
3486 }
3487 ntok = get_token_count(buff, sep[0]);
3488 if (ntok < piece) return -1;
3489 array = lives_strsplit(buff, sep, ntok);
3490 val = make_version_hash(array[piece]);
3491 lives_strfreev(array);
3492 return val;
3493}
3494
3495
3496#define VER_MAJOR_MULT 1000000
3497#define VER_MINOR_MULT 1000
3498#define VER_MICRO_MULT 1
3499
3500uint64_t make_version_hash(const char *ver) {
3502 char **array;
3503 uint64_t hash;
3504 int ntok;
3505
3506 if (!ver) return 0;
3507
3508 ntok = get_token_count((char *)ver, '.');
3509 array = lives_strsplit(ver, ".", ntok);
3510
3511 hash = atoi(array[0]) * VER_MAJOR_MULT;
3512 if (ntok > 1) {
3513 hash += atoi(array[1]) * VER_MINOR_MULT;
3514 if (ntok > 2) hash += atoi(array[2]) * VER_MICRO_MULT;
3515 }
3516
3517 lives_strfreev(array);
3518 return hash;
3519}
3520
3521
3522char *unhash_version(uint64_t version) {
3523 if (!version) return lives_strdup(_("'Unknown'"));
3524 else {
3525 uint64_t maj = version / VER_MAJOR_MULT, min;
3526 version -= maj * VER_MAJOR_MULT;
3527 min = version / VER_MINOR_MULT;
3528 version -= min * VER_MINOR_MULT;
3529 return lives_strdup_printf("%lu.%lu.%lu", maj, min, version);
3530 }
3531}
3532
3533
3534char *repl_workdir(const char *entry, boolean fwd) {
3535 // replace prefs->workdir with string workdir or vice-versa. This allows us to relocate workdir if necessary.
3536 // used for layout.map file
3537 // return value should be freed
3538
3539 // fwd TRUE replaces "/tmp/foo" with "workdir"
3540 // fwd FALSE replaces "workdir" with "/tmp/foo"
3541 size_t wdl;
3542 char *string = lives_strdup(entry);
3543
3544 if (fwd) {
3545 if (!lives_strncmp(entry, prefs->workdir, (wdl = lives_strlen(prefs->workdir)))) {
3546 lives_free(string);
3547 string = lives_strdup_printf("%s%s", WORKDIR_LITERAL, entry + wdl);
3548 }
3549 } else {
3551 lives_free(string);
3552 string = lives_build_filename(prefs->workdir, entry + WORKDIR_LITERAL_LEN, NULL);
3553 }
3554 }
3555 return string;
3556}
3557
3558
3559void remove_layout_files(LiVESList * map) {
3560 // removes a LiVESList of layouts from the set layout map
3561
3562 // removes from: - global layouts map
3563 // - disk
3564 // - clip layout maps
3565
3566 // called after, for example: a clip is removed or altered and the user opts to remove all associated layouts
3567
3568 LiVESList *lmap, *lmap_next, *cmap, *cmap_next, *map_next;
3569 size_t maplen;
3570 char **array;
3571 char *fname, *fdir;
3572 boolean is_current;
3573
3574 while (map) {
3575 map_next = map->next;
3576 if (map->data) {
3578 is_current = TRUE;
3579 fname = lives_strdup(mainw->string_constants[LIVES_STRING_CONSTANT_CL]);
3580 } else {
3581 is_current = FALSE;
3582 maplen = lives_strlen((char *)map->data);
3583
3584 // remove from mainw->current_layouts_map
3585 cmap = mainw->current_layouts_map;
3586 while (cmap) {
3587 cmap_next = cmap->next;
3588 if (!lives_utf8_strcasecmp((char *)cmap->data, (char *)map->data)) {
3589 lives_free((livespointer)cmap->data);
3590 mainw->current_layouts_map = lives_list_delete_link(mainw->current_layouts_map, cmap);
3591 break;
3592 }
3593 cmap = cmap_next;
3594 }
3595
3596 array = lives_strsplit((char *)map->data, "|", -1);
3597 fname = repl_workdir(array[0], FALSE);
3598 lives_strfreev(array);
3599 }
3600
3601 // fname should now hold the layout name on disk
3602 d_print(_("Removing layout %s\n"), fname);
3603
3604 if (!is_current) {
3605 lives_rm(fname);
3606
3607 // if no more layouts in parent dir, we can delete dir
3608
3609 // ensure that parent dir is below our own working dir
3611 // is in workdir, safe to remove parents
3612
3613 char *protect_file = lives_build_filename(prefs->workdir, "noremove", NULL);
3614
3615 // touch a file in tpmdir, so we cannot remove workdir itself
3616 lives_touch(protect_file);
3617
3618 if (!THREADVAR(com_failed)) {
3619 // ok, the "touch" worked
3620 // now we call rmdir -p : remove directory + any empty parents
3621 fdir = lives_path_get_dirname(fname);
3623 lives_free(fdir);
3624 }
3625
3626 // remove the file we touched to clean up
3627 lives_rm(protect_file);
3628 lives_free(protect_file);
3629 }
3630
3631 // remove from mainw->files[]->layout_map
3632 for (int i = 1; i <= MAX_FILES; i++) {
3633 if (mainw->files[i]) {
3634 if (mainw->files[i]->layout_map) {
3635 lmap = mainw->files[i]->layout_map;
3636 while (lmap) {
3637 lmap_next = lmap->next;
3638 if (!lives_strncmp((char *)lmap->data, (char *)map->data, maplen)) {
3639 lives_free((livespointer)lmap->data);
3640 mainw->files[i]->layout_map = lives_list_delete_link(mainw->files[i]->layout_map, lmap);
3641 }
3642 lmap = lmap_next;
3643 // *INDENT-OFF*
3644 }}}}
3645 // *INDENT-ON*
3646
3647 } else {
3648 // asked to remove the currently loaded layout
3649
3651 // we are in CE mode, so event_list is in storage
3653 }
3654 // in mt mode we need to do more
3656
3657 // and we dont want to try reloading this next time
3661 }
3662 lives_free(fname);
3663 }
3664 map = map_next;
3665 }
3666
3667 // save updated layout.map
3668 save_layout_map(NULL, NULL, NULL, NULL);
3669}
3670
3671
3673 update_timer_bars(0, 0, 0, 0, 0);
3674}
3675
3676
3678 // force a redraw, reread audio
3679 if (!CURRENT_CLIP_IS_VALID) return;
3680 if (cfile->audio_waveform) {
3681 int i;
3682 for (i = 0; i < cfile->achans; lives_freep((void **)&cfile->audio_waveform[i++]));
3683 lives_freep((void **)&cfile->audio_waveform);
3684 lives_freep((void **)&cfile->aw_sizes);
3685 }
3687}
3688
3689
3691 // get times (video, left and right audio)
3692
3693 file->laudio_time = file->raudio_time = file->video_time = 0.;
3694
3695 if (file->opening) {
3696 int frames;
3697 if (file->frames != 123456789) frames = file->frames;
3698 else frames = file->opening_frames;
3699 if (frames * file->fps > 0) {
3700 file->video_time = file->frames / file->fps;
3701 }
3702 return;
3703 }
3704
3705 if (file->fps > 0.) {
3706 file->video_time = file->frames / file->fps;
3707 }
3708
3709 if (file->asampsize >= 8 && file->arate > 0 && file->achans > 0) {
3710 file->laudio_time = (double)(file->afilesize / (file->asampsize >> 3) / file->achans) / (double)file->arate;
3711 if (file->achans > 1) {
3712 file->raudio_time = file->laudio_time;
3713 }
3714 }
3715
3716 if (file->laudio_time + file->raudio_time == 0. && !file->opening) {
3717 file->achans = file->afilesize = file->asampsize = file->arate = file->arps = 0;
3718 }
3719}
3720
3721
3723 // work out when to stop playing
3724 //
3725 // ---------------
3726 // no loop loop to fit loop cont
3727 // ------- ----------- ---------
3728 // a>v stop on video end stop on audio end no stop
3729 // v>a stop on video end stop on video end no stop
3730 // generator start - not playing : stop on vid_end, unless pure audio;
3732 else if (mainw->aud_rec_fd != -1 &&
3735 else if (!CURRENT_CLIP_IS_NORMAL) {
3738 } else if (cfile->opening_only_audio) mainw->whentostop = STOP_ON_AUD_END;
3739 else if (cfile->opening_audio) mainw->whentostop = STOP_ON_VID_END;
3740 else if (!mainw->preview && (mainw->loop_cont)) mainw->whentostop = NEVER_STOP;
3741 else if (!CURRENT_CLIP_HAS_VIDEO || (mainw->loop && cfile->achans > 0 && !mainw->is_rendering
3742 && (mainw->audio_end / cfile->fps)
3743 < MAX(cfile->laudio_time, cfile->raudio_time) &&
3746 else mainw->whentostop = STOP_ON_VID_END; // tada...
3747}
3748
3749
3750void minimise_aspect_delta(double aspect, int hblock, int vblock, int hsize, int vsize, int *width, int *height) {
3751 // we will use trigonometry to calculate the smallest difference between a given
3752 // aspect ratio and the actual frame size. If the delta is smaller than current
3753 // we set the height and width
3754 int cw = width[0];
3755 int ch = height[0];
3756
3757 int real_width, real_height;
3758 uint64_t delta, current_delta;
3759
3760 // minimise d[(x-x1)^2 + (y-y1)^2]/d[x1], to get approximate values
3761 int calc_width = (int)((vsize + aspect * hsize) * aspect / (aspect * aspect + 1.));
3762
3763 int i;
3764
3765 current_delta = (hsize - cw) * (hsize - cw) + (vsize - ch) * (vsize - ch);
3766
3767#ifdef DEBUG_ASPECT
3768 lives_printerr("aspect %.8f : width %d height %d is best fit\n", aspect, calc_width, (int)(calc_width / aspect));
3769#endif
3770 // use the block size to find the nearest allowed size
3771 for (i = -1; i < 2; i++) {
3772 real_width = (int)(calc_width / hblock + i) * hblock;
3773 real_height = (int)(real_width / aspect / vblock + .5) * vblock;
3774 delta = (hsize - real_width) * (hsize - real_width) + (vsize - real_height) * (vsize - real_height);
3775
3776 if (real_width % hblock != 0 || real_height % vblock != 0 ||
3777 ABS((double)real_width / (double)real_height - aspect) > ASPECT_ALLOWANCE) {
3778 // encoders can be fussy, so we need to fit both aspect ratio and blocksize
3779 while (1) {
3780 real_width = ((int)(real_width / hblock) + 1) * hblock;
3781 real_height = (int)((double)real_width / aspect + .5);
3782
3783 if (real_height % vblock == 0) break;
3784
3785 real_height = ((int)(real_height / vblock) + 1) * vblock;
3786 real_width = (int)((double)real_height * aspect + .5);
3787
3788 if (real_width % hblock == 0) break;
3789 }
3790 }
3791
3792#ifdef DEBUG_ASPECT
3793 lives_printerr("block quantise to %d x %d\n", real_width, real_height);
3794#endif
3795 if (delta < current_delta) {
3796#ifdef DEBUG_ASPECT
3797 lives_printerr("is better fit\n");
3798#endif
3799 current_delta = delta;
3800 width[0] = real_width;
3801 height[0] = real_height;
3802 }
3803 }
3804}
3805
3806
3809 lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_start), 0., 0.);
3810 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_start), 0.);
3813 lives_spin_button_set_range(LIVES_SPIN_BUTTON(mainw->spinbutton_end), 0., 0.);
3814 lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_end), 0.);
3816}
3817
3818
3819boolean switch_aud_to_jack(boolean set_in_prefs) {
3820#ifdef ENABLE_JACK
3821 if (mainw->is_ready) {
3822 if (!mainw->jack_inited) lives_jack_init();
3823 if (!mainw->jackd) {
3824 jack_audio_init();
3825 jack_audio_read_init();
3826 mainw->jackd = jack_get_driver(0, TRUE);
3827 if (!jack_create_client_writer(mainw->jackd)) {
3828 mainw->jackd = NULL;
3829 return FALSE;
3830 }
3831 mainw->jackd->whentostop = &mainw->whentostop;
3832 mainw->jackd->cancelled = &mainw->cancelled;
3833 mainw->jackd->in_use = FALSE;
3834 mainw->jackd->play_when_stopped = (prefs->jack_opts & JACK_OPTS_NOPLAY_WHEN_PAUSED) ? FALSE : TRUE;
3835 jack_write_driver_activate(mainw->jackd);
3836 }
3837
3843
3844 if (mainw->vpp && mainw->vpp->get_audio_fmts)
3846
3847#ifdef HAVE_PULSE_AUDIO
3848 if (mainw->pulsed_read) {
3849 pulse_close_client(mainw->pulsed_read);
3850 mainw->pulsed_read = NULL;
3851 }
3852
3853 if (mainw->pulsed) {
3854 pulse_close_client(mainw->pulsed);
3855 mainw->pulsed = NULL;
3856 pulse_shutdown();
3857 }
3858#endif
3859 }
3862 lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_JACK);
3863
3866
3868 jack_rec_audio_to_clip(-1, -1, RECA_MONITOR);
3869 mainw->jackd_read->in_use = FALSE;
3870 }
3871
3877
3878 return TRUE;
3879#endif
3880 return FALSE;
3881}
3882
3883
3884boolean switch_aud_to_pulse(boolean set_in_prefs) {
3885#ifdef HAVE_PULSE_AUDIO
3886 boolean retval;
3887
3888 if (mainw->is_ready) {
3889 if ((retval = lives_pulse_init(-1))) {
3890 if (!mainw->pulsed) {
3891 pulse_audio_init();
3892 pulse_audio_read_init();
3893 mainw->pulsed = pulse_get_driver(TRUE);
3894 mainw->pulsed->whentostop = &mainw->whentostop;
3895 mainw->pulsed->cancelled = &mainw->cancelled;
3896 mainw->pulsed->in_use = FALSE;
3897 pulse_driver_activate(mainw->pulsed);
3898 }
3904
3907 lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_PULSE);
3908
3909 if (mainw->vpp && mainw->vpp->get_audio_fmts)
3911 }
3912
3913#ifdef ENABLE_JACK
3914 if (mainw->jackd_read) {
3915 jack_close_device(mainw->jackd_read);
3916 mainw->jackd_read = NULL;
3917 }
3918
3919 if (mainw->jackd) {
3920 jack_close_device(mainw->jackd);
3921 mainw->jackd = NULL;
3922 }
3923#endif
3924
3926 pulse_rec_audio_to_clip(-1, -1, RECA_MONITOR);
3927 mainw->pulsed_read->in_use = FALSE;
3928 }
3929
3934 if (mainw->play_window)
3936
3937 return retval;
3938 }
3939#endif
3940 return FALSE;
3941}
3942
3943
3944boolean switch_aud_to_sox(boolean set_in_prefs) {
3945 if (!capable->has_sox_play) return FALSE; // TODO - show error
3946
3948 lives_snprintf(prefs->audio_play_command, 256, "%s", EXEC_PLAY);
3950 lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_SOX);
3951 //set_string_pref(PREF_AUDIO_PLAY_COMMAND, prefs->audio_play_command);
3952
3953 if (mainw->is_ready) {
3954 /* //ubuntu / Unity has a hissy fit if you hide things in the menu !
3955 lives_widget_hide(mainw->vol_toolitem);
3956 if (mainw->vol_label) lives_widget_hide(mainw->vol_label);
3957 */
3960
3961 if (mainw->vpp && mainw->vpp->get_audio_fmts)
3963
3965
3971 }
3972
3973#ifdef ENABLE_JACK
3974 if (mainw->jackd_read) {
3975 jack_close_device(mainw->jackd_read);
3976 mainw->jackd_read = NULL;
3977 }
3978
3979 if (mainw->jackd) {
3980 jack_close_device(mainw->jackd);
3981 mainw->jackd = NULL;
3982 }
3983#endif
3984
3985#ifdef HAVE_PULSE_AUDIO
3986 if (mainw->pulsed_read) {
3987 pulse_close_client(mainw->pulsed_read);
3988 mainw->pulsed_read = NULL;
3989 }
3990
3991 if (mainw->pulsed) {
3992 pulse_close_client(mainw->pulsed);
3993 mainw->pulsed = NULL;
3994 pulse_shutdown();
3995 }
3996#endif
3997 return TRUE;
3998}
3999
4000
4001void switch_aud_to_none(boolean set_in_prefs) {
4004 lives_snprintf(prefs->aplayer, 512, "%s", AUDIO_PLAYER_NONE);
4005
4006 if (mainw->is_ready) {
4007 /* //ubuntu has a hissy fit if you hide things in the menu
4008 lives_widget_hide(mainw->vol_toolitem);
4009 if (mainw->vol_label) lives_widget_hide(mainw->vol_label);
4010 */
4012 // lives_widget_hide(mainw->recaudio_submenu);
4013
4014 if (mainw->vpp && mainw->vpp->get_audio_fmts)
4016
4018
4023 if (mainw->preview_box) {
4025 }
4026 }
4027
4028#ifdef ENABLE_JACK
4029 if (mainw->jackd_read) {
4030 jack_close_device(mainw->jackd_read);
4031 mainw->jackd_read = NULL;
4032 }
4033
4034 if (mainw->jackd) {
4035 jack_close_device(mainw->jackd);
4036 mainw->jackd = NULL;
4037 }
4038#endif
4039
4040#ifdef HAVE_PULSE_AUDIO
4041 if (mainw->pulsed_read) {
4042 pulse_close_client(mainw->pulsed_read);
4043 mainw->pulsed_read = NULL;
4044 }
4045
4046 if (mainw->pulsed) {
4047 pulse_close_client(mainw->pulsed);
4048 mainw->pulsed = NULL;
4049 pulse_shutdown();
4050 }
4051#endif
4052}
4053
4054
4056 // here we are going to 'play' a captured external window
4057
4058#ifdef GUI_GTK
4059
4060#if !GTK_CHECK_VERSION(3, 0, 0)
4061#ifdef GDK_WINDOWING_X11
4062 GdkVisual *vissi = NULL;
4063 register int i;
4064#endif
4065#endif
4066#endif
4067
4068 int new_file = mainw->first_free_file;
4069
4070 mainw->foreign_window = NULL;
4071
4072 // create a new 'file' to play into
4073 if (!get_new_handle(new_file, NULL)) {
4074 return FALSE;
4075 }
4076
4077 mainw->current_file = new_file;
4078
4079 if (mainw->rec_achans > 0) {
4080 cfile->arate = cfile->arps = mainw->rec_arate;
4081 cfile->achans = mainw->rec_achans;
4082 cfile->asampsize = mainw->rec_asamps;
4083 cfile->signed_endian = mainw->rec_signed_endian;
4084#ifdef HAVE_PULSE_AUDIO
4086 pulse_rec_audio_to_clip(mainw->current_file, -1, RECA_WINDOW_GRAB);
4087 mainw->pulsed_read->in_use = TRUE;
4088 }
4089#endif
4090#ifdef ENABLE_JACK
4092 jack_rec_audio_to_clip(mainw->current_file, -1, RECA_WINDOW_GRAB);
4093 mainw->jackd_read->in_use = TRUE;
4094 }
4095#endif
4096 }
4097
4098 cfile->hsize = mainw->foreign_width / 2 + 1;
4099 cfile->vsize = mainw->foreign_height / 2 + 3;
4100
4101 cfile->fps = cfile->pb_fps = mainw->rec_fps;
4102
4103 resize(-2);
4104
4109
4110 // size must be exact, must not be larger than play window or we end up with nothing
4111 mainw->pwidth = lives_widget_get_allocation_width(mainw->playframe);// - H_RESIZE_ADJUST + 2;
4112 mainw->pheight = lives_widget_get_allocation_height(mainw->playframe);// - V_RESIZE_ADJUST + 2;
4113
4114 cfile->hsize = mainw->pwidth;
4115 cfile->vsize = mainw->pheight;
4116
4117 cfile->img_type = IMG_TYPE_BEST; // override the pref
4118
4119#ifdef GUI_GTK
4120#if GTK_CHECK_VERSION(3, 0, 0)
4121
4122#ifdef GDK_WINDOWING_X11
4123 mainw->foreign_window = gdk_x11_window_foreign_new_for_display
4125 mainw->foreign_id);
4126#else
4127#ifdef GDK_WINDOWING_WIN32
4128 if (!mainw->foreign_window)
4129 mainw->foreign_window = gdk_win32_window_foreign_new_for_display
4131 mainw->foreign_id);
4132#endif
4133
4134#endif // GDK_WINDOWING
4135
4137
4138#else // 3, 0, 0
4139 mainw->foreign_window = gdk_window_foreign_new(mainw->foreign_id);
4140#endif
4141#endif // GUI_GTK
4142
4143#ifdef GUI_GTK
4144#ifdef GDK_WINDOWING_X11
4145#if !GTK_CHECK_VERSION(3, 0, 0)
4146
4147 if (mainw->foreign_visual) {
4148 for (i = 0; i < capable->nmonitors; i++) {
4149 vissi = gdk_x11_screen_lookup_visual(mainw->mgeom[i].screen, hextodec(mainw->foreign_visual));
4150 if (vissi) break;
4151 }
4152 }
4153
4154 if (!vissi) vissi = gdk_visual_get_best_with_depth(mainw->foreign_bpp);
4155 if (!vissi) return FALSE;
4156
4157 mainw->foreign_cmap = gdk_x11_colormap_foreign_new(vissi,
4158 gdk_x11_colormap_get_xcolormap(gdk_colormap_new(vissi, TRUE)));
4159
4160 if (!mainw->foreign_cmap) return FALSE;
4161
4162#endif
4163#endif
4164#endif
4165
4166 if (!mainw->foreign_window) return FALSE;
4167
4168 mainw->play_start = 1;
4169 if (mainw->rec_vid_frames == -1) mainw->play_end = INT_MAX;
4171
4172 mainw->rec_samples = -1;
4173
4174 omute = mainw->mute;
4175 osepwin = mainw->sep_win;
4176 ofs = mainw->fs;
4177 ofaded = mainw->faded;
4178 odouble = mainw->double_size;
4179
4180 mainw->mute = TRUE;
4181 mainw->sep_win = FALSE;
4182 mainw->fs = FALSE;
4183 mainw->faded = TRUE;
4185
4188
4189 return TRUE;
4190}
4191
4192
4193boolean after_foreign_play(void) {
4194 // read details from capture file
4195 int capture_fd = -1;
4196 char *capfile = lives_strdup_printf("%s/.capture.%d", prefs->workdir, capable->mainpid);
4197 char capbuf[256];
4198 ssize_t length;
4199 int new_frames = 0;
4200 int old_file = mainw->current_file;
4201
4202 char **array;
4203
4204 // assume for now we only get one clip passed back
4205 if ((capture_fd = lives_open2(capfile, O_RDONLY)) > -1) {
4206 lives_memset(capbuf, 0, 256);
4207 if ((length = read(capture_fd, capbuf, 256))) {
4208 if (get_token_count(capbuf, '|') > 2) {
4209 array = lives_strsplit(capbuf, "|", 3);
4210 new_frames = atoi(array[1]);
4211 if (new_frames > 0) {
4212 create_cfile(-1, array[0], FALSE);
4213 lives_strfreev(array);
4214 lives_snprintf(cfile->file_name, 256, "Capture %d", mainw->cap_number);
4215 lives_snprintf(cfile->name, CLIP_NAME_MAXLEN, "Capture %d", mainw->cap_number++);
4216 lives_snprintf(cfile->type, 40, "Frames");
4217
4218 cfile->progress_start = cfile->start = 1;
4219 cfile->progress_end = cfile->frames = cfile->end = new_frames;
4220 cfile->pb_fps = cfile->fps = mainw->rec_fps;
4221
4222 cfile->hsize = CEIL(mainw->foreign_width, 4);
4223 cfile->vsize = CEIL(mainw->foreign_height, 4);
4224
4225 cfile->img_type = IMG_TYPE_BEST;
4226 cfile->changed = TRUE;
4227
4228 if (mainw->rec_achans > 0) {
4229 cfile->arate = cfile->arps = mainw->rec_arate;
4230 cfile->achans = mainw->rec_achans;
4231 cfile->asampsize = mainw->rec_asamps;
4232 cfile->signed_endian = mainw->rec_signed_endian;
4233 }
4234
4237
4238 close(capture_fd);
4239 lives_rm(capfile);
4240 capture_fd = -1;
4241 do_threaded_dialog(_("Cleaning up clip"), FALSE);
4243 resize_all(mainw->current_file, cfile->hsize, cfile->vsize, cfile->img_type, FALSE, NULL, NULL);
4245 if (cfile->afilesize > 0 && cfile->achans > 0
4248 }
4249 // *INDENT-OFF*
4250 }}}}
4251 // *INDENT-ON*
4252
4253 if (capture_fd > -1) {
4254 close(capture_fd);
4255 lives_rm(capfile);
4256 }
4257
4258 if (new_frames == 0) {
4259 // nothing captured; or cancelled
4260 lives_free(capfile);
4261 return FALSE;
4262 }
4263
4264 cfile->nopreview = FALSE;
4265 lives_free(capfile);
4266
4269
4270 else {
4271 int new_file = mainw->current_file;
4272 mainw->current_file = mainw->multitrack->render_file;
4273 mt_init_clips(mainw->multitrack, new_file, TRUE);
4275 }
4276
4277 cfile->is_loaded = TRUE;
4278 cfile->changed = TRUE;
4280 return TRUE;
4281}
4282
4283
4284LIVES_GLOBAL_INLINE boolean int_array_contains_value(int *array, int num_elems, int value) {
4285 for (int i = 0; i < num_elems; i++) if (array[i] == value) return TRUE;
4286 return FALSE;
4287}
4288
4289
4290void reset_clipmenu(void) {
4291 // sometimes the clip menu gets messed up, e.g. after reloading a set.
4292 // This function will clean up the 'x's and so on.
4293
4294 if (mainw->current_file > 0 && cfile && cfile->menuentry) {
4295#ifdef GTK_RADIO_MENU_BUG
4296 register int i;
4297 for (i = 1; i < MAX_FILES; i++) {
4298 if (i != mainw->current_file && mainw->files[i] && mainw->files[i]->menuentry) {
4300 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(mainw->files[i]->menuentry), FALSE);
4302 }
4303 }
4304#endif
4305 lives_signal_handler_block(cfile->menuentry, cfile->menuentry_func);
4306 lives_check_menu_item_set_active(LIVES_CHECK_MENU_ITEM(cfile->menuentry), TRUE);
4307 lives_signal_handler_unblock(cfile->menuentry, cfile->menuentry_func);
4308 }
4309}
4310
4311
4312boolean check_file(const char *file_name, boolean check_existing) {
4313 int check;
4314 boolean exists = FALSE;
4315 char *msg;
4316 // file_name should be in utf8
4317 char *lfile_name = U82F(file_name);
4318
4319 mainw->error = FALSE;
4320
4321 while (1) {
4322 // check if file exists
4323 if (lives_file_test(lfile_name, LIVES_FILE_TEST_EXISTS)) {
4324 if (check_existing) {
4325 msg = lives_strdup_printf(_("\n%s\nalready exists.\n\nOverwrite ?\n"), file_name);
4326 if (!do_warning_dialog(msg)) {
4327 lives_free(msg);
4328 lives_free(lfile_name);
4329 return FALSE;
4330 }
4331 lives_free(msg);
4332 }
4333 check = open(lfile_name, O_WRONLY);
4334 exists = TRUE;
4335 }
4336 // if not, check if we can write to it
4337 else {
4338 check = open(lfile_name, O_CREAT | O_EXCL | O_WRONLY, DEF_FILE_PERMS);
4339 }
4340
4341 if (check < 0) {
4342 LiVESResponseType resp = LIVES_RESPONSE_NONE;
4343 mainw->error = TRUE;
4344 if (mainw && mainw->is_ready) {
4345 if (errno == EACCES)
4346 resp = do_file_perm_error(lfile_name, TRUE);
4347 else
4348 resp = do_write_failed_error_s_with_retry(lfile_name, NULL);
4349 if (resp == LIVES_RESPONSE_RETRY) {
4350 continue;
4351 }
4352 }
4353 lives_free(lfile_name);
4354 return FALSE;
4355 }
4356
4357 close(check);
4358 break;
4359 }
4360 if (!exists) lives_rm(lfile_name);
4361 lives_free(lfile_name);
4362 return TRUE;
4363}
4364
4365
4366int lives_rmdir(const char *dir, boolean force) {
4367 // if force is TRUE, removes non-empty dirs, otherwise leaves them
4368 // may fail
4369 char *com, *cmd;
4370 int retval;
4371
4372 if (force) {
4373 cmd = lives_strdup_printf("%s -rf", capable->rm_cmd);
4374 } else {
4375 cmd = lives_strdup(capable->rmdir_cmd);
4376 }
4377
4378 com = lives_strdup_printf("%s \"%s/\" >\"%s\" 2>&1", cmd, dir, prefs->cmd_log);
4379 retval = lives_system(com, TRUE);
4380 lives_free(com);
4381 lives_free(cmd);
4382 return retval;
4383}
4384
4385
4386int lives_rmdir_with_parents(const char *dir) {
4387 // may fail, will not remove empty dirs
4388 char *com = lives_strdup_printf("%s -p \"%s\" >\"%s\" 2>&1", capable->rmdir_cmd, dir, prefs->cmd_log);
4389 int retval = lives_system(com, TRUE);
4390 lives_free(com);
4391 return retval;
4392}
4393
4394
4395int lives_rm(const char *file) {
4396 // may fail
4397 char *com = lives_strdup_printf("%s -f \"%s\" >\"%s\" 2>&1", capable->rm_cmd, file, prefs->cmd_log);
4398 int retval = lives_system(com, TRUE);
4399 lives_free(com);
4400 return retval;
4401}
4402
4403
4404int lives_rmglob(const char *files) {
4405 // delete files with name "files"*
4406 // may fail
4407 char *com = lives_strdup_printf("%s \"%s\"* >\"%s\" 2>&1", capable->rm_cmd, files, prefs->cmd_log);
4408 int retval = lives_system(com, TRUE);
4409 lives_free(com);
4410 return retval;
4411}
4412
4413
4414int lives_cp(const char *from, const char *to) {
4415 // may not fail - BUT seems to return -1 sometimes
4416 char *com = lives_strdup_printf("%s \"%s\" \"%s\" >\"%s\" 2>&1", capable->cp_cmd, from, to, prefs->cmd_log);
4417 int retval = lives_system(com, FALSE);
4418 lives_free(com);
4419 return retval;
4420}
4421
4422
4423int lives_cp_recursive(const char *from, const char *to, boolean incl_dir) {
4424 // may not fail
4425 int retval;
4426 char *com;
4427 if (incl_dir) com = lives_strdup_printf("%s -r \"%s\" \"%s\" >\"%s\" 2>&1", capable->cp_cmd, from, to, prefs->cmd_log);
4428 else com = lives_strdup_printf("%s -rf \"%s\"/* \"%s\" >\"%s\" 2>&1", capable->cp_cmd, from, to, prefs->cmd_log);
4429 if (!lives_file_test(to, LIVES_FILE_TEST_EXISTS))
4430 lives_mkdir_with_parents(to, capable->umask);
4431 retval = lives_system(com, FALSE);
4432 lives_free(com);
4433 return retval;
4434}
4435
4436
4437int lives_cp_keep_perms(const char *from, const char *to) {
4438 // may not fail
4439 char *com = lives_strdup_printf("%s -a \"%s\" \"%s/\" >\"%s\" 2>&1", capable->cp_cmd, from, to, prefs->cmd_log);
4440 int retval = lives_system(com, FALSE);
4441 lives_free(com);
4442 return retval;
4443}
4444
4445
4446int lives_mv(const char *from, const char *to) {
4447 // may not fail
4448 char *com = lives_strdup_printf("%s \"%s\" \"%s\"", capable->mv_cmd, from, to);
4449 int retval = lives_system(com, FALSE);
4450 lives_free(com);
4451 return retval;
4452}
4453
4454
4455int lives_touch(const char *tfile) {
4456 // may not fail
4457 char *com = lives_strdup_printf("%s \"%s\" >\"%s\" 2>&1", capable->touch_cmd, tfile, prefs->cmd_log);
4458 int retval = lives_system(com, FALSE);
4459 lives_free(com);
4460 return retval;
4461}
4462
4463
4464int lives_ln(const char *from, const char *to) {
4465 // may not fail
4466 char *com;
4467 int retval;
4468 com = lives_strdup_printf("%s -s \"%s\" \"%s\" >\"%s\" 2>&1", capable->ln_cmd, from, to, prefs->cmd_log);
4469 retval = lives_system(com, FALSE);
4470 lives_free(com);
4471 return retval;
4472}
4473
4474
4475int lives_chmod(const char *target, const char *mode) {
4476 // may not fail
4477 char *com = lives_strdup_printf("%s %s \"%s\" >\"%s\" 2>&1", capable->chmod_cmd, mode, target, prefs->cmd_log);
4478 int retval = lives_system(com, FALSE);
4479 lives_free(com);
4480 return retval;
4481}
4482
4483
4484int lives_cat(const char *from, const char *to, boolean append) {
4485 // may not fail
4486 char *com;
4487 char *op;
4488 int retval;
4489
4490 if (append) op = ">>";
4491 else op = ">";
4492
4493 com = lives_strdup_printf("%s \"%s\" %s \"%s\" >\"%s\" 2>&1", capable->cat_cmd, from, op, to, prefs->cmd_log);
4494 retval = lives_system(com, FALSE);
4495 lives_free(com);
4496 return retval;
4497}
4498
4499
4500int lives_echo(const char *text, const char *to, boolean append) {
4501 // may not fail
4502 char *com;
4503 char *op;
4504 int retval;
4505
4506 if (append) op = ">>";
4507 else op = ">";
4508
4509 com = lives_strdup_printf("%s \"%s\" %s \"%s\" 2>\"%s\"", capable->echo_cmd, text, op, to, prefs->cmd_log);
4510 retval = lives_system(com, FALSE);
4511 lives_free(com);
4512 return retval;
4513}
4514
4515
4516void lives_kill_subprocesses(const char *dirname, boolean kill_parent) {
4517 char *com;
4518 if (kill_parent)
4519 com = lives_strdup_printf("%s stopsubsub \"%s\"", prefs->backend_sync, dirname);
4520 else
4521 com = lives_strdup_printf("%s stopsubsubs \"%s\"", prefs->backend_sync, dirname);
4522 lives_system(com, TRUE);
4523 lives_free(com);
4524}
4525
4526
4527void lives_suspend_resume_process(const char *dirname, boolean suspend) {
4528 char *com;
4529 if (!suspend)
4530 com = lives_strdup_printf("%s stopsubsub \"%s\" SIGCONT 2>/dev/null", prefs->backend_sync, dirname);
4531 else
4532 com = lives_strdup_printf("%s stopsubsub \"%s\" SIGTSTP 2>/dev/null", prefs->backend_sync, dirname);
4533 lives_system(com, TRUE);
4534 lives_free(com);
4535
4536 com = lives_strdup_printf("%s resume \"%s\"", prefs->backend_sync, dirname);
4537 lives_system(com, FALSE);
4538 lives_free(com);
4539}
4540
4541
4542boolean check_dir_access(const char *dir, boolean leaveit) {
4543 // if a directory exists, make sure it is readable and writable
4544 // otherwise create it and then check
4545 // we test here by actually creating a (mkstemp) file and writing to it
4546 // dir is in locale encoding
4547
4548 // see also is_writeable_dir() which uses statvfs
4549
4550 // WARNING: may leave some parents around
4551 char test[5] = "1234";
4552 char *testfile;
4553 boolean exists = lives_file_test(dir, LIVES_FILE_TEST_EXISTS);
4554 int fp;
4555
4556 if (!exists) lives_mkdir_with_parents(dir, capable->umask);
4557
4558 if (!lives_file_test(dir, LIVES_FILE_TEST_IS_DIR)) return FALSE;
4559
4560 testfile = lives_build_filename(dir, "livestst-XXXXXX", NULL);
4561 fp = g_mkstemp(testfile);
4562 if (fp == -1) {
4563 lives_free(testfile);
4564 if (!exists) {
4565 lives_rmdir(dir, FALSE);
4566 }
4567 return FALSE;
4568 }
4569 if (lives_write(fp, test, 4, TRUE) != 4) {
4570 close(fp);
4571 lives_rm(testfile);
4572 if (!exists) {
4573 lives_rmdir(dir, FALSE);
4574 }
4575 lives_free(testfile);
4576 return FALSE;
4577 }
4578 close(fp);
4579 fp = lives_open2(testfile, O_RDONLY);
4580 if (fp < 0) {
4581 lives_rm(testfile);
4582 if (!exists) {
4583 lives_rmdir(dir, FALSE);
4584 }
4585 lives_free(testfile);
4586 return FALSE;
4587 }
4588 if (lives_read(fp, test, 4, TRUE) != 4) {
4589 close(fp);
4590 lives_rm(testfile);
4591 if (!exists) {
4592 lives_rmdir(dir, FALSE);
4593 }
4594 lives_free(testfile);
4595 return FALSE;
4596 }
4597 close(fp);
4598 lives_rm(testfile);
4599 if (!exists && !leaveit) {
4600 lives_rmdir(dir, FALSE);
4601 }
4602 lives_free(testfile);
4603 return TRUE;
4604}
4605
4606
4607void activate_url_inner(const char *link) {
4608#if GTK_CHECK_VERSION(2, 14, 0)
4609 LiVESError *err = NULL;
4610#if GTK_CHECK_VERSION(3, 22, 0)
4611 gtk_show_uri_on_window(NULL, link, GDK_CURRENT_TIME, &err);
4612#else
4613 gtk_show_uri(NULL, link, GDK_CURRENT_TIME, &err);
4614#endif
4615#else
4616 char *com = getenv("BROWSER");
4617 com = lives_strdup_printf("\"%s\" '%s' &", com ? com : "gnome-open", link);
4618 lives_system(com, FALSE);
4619 lives_free(com);
4620#endif
4621}
4622
4623
4624void activate_url(LiVESAboutDialog * about, const char *link, livespointer data) {
4625 activate_url_inner(link);
4626}
4627
4628
4629void show_manual_section(const char *lang, const char *section) {
4630 char *tmp = NULL, *tmp2 = NULL;
4631 const char *link;
4632
4633 link = lives_strdup_printf("%s%s%s%s", LIVES_MANUAL_URL, (lang == NULL ? "" : (tmp2 = lives_strdup_printf("//%s//", lang))),
4634 LIVES_MANUAL_FILENAME, (section == NULL ? "" : (tmp = lives_strdup_printf("#%s", section))));
4635
4636 activate_url_inner(link);
4637
4638 if (tmp) lives_free(tmp);
4639 if (tmp2) lives_free(tmp2);
4640}
4641
4642
4643
4644void wait_for_bg_audio_sync(int fileno) {
4645 char *afile = lives_get_audio_file_name(fileno);
4647 int fd;
4648
4649 while ((fd = open(afile, O_RDONLY)) < 0 && lives_alarm_check(alarm_handle) > 0) {
4650 lives_sync(1);
4651 lives_usleep(prefs->sleep_time);
4652 }
4653 lives_alarm_clear(alarm_handle);
4654
4655 if (fd >= 0) close(fd);
4656 lives_free(afile);
4657}
4658
4659
4660boolean create_event_space(int length) {
4661 // try to create desired events
4662 // if we run out of memory, all events requested are freed, and we return FALSE
4663 // otherwise we return TRUE
4664
4665 // NOTE: this is the OLD event system, it's only used for reordering in the clip editor
4666
4667 if (cfile->resample_events) {
4668 lives_free(cfile->resample_events);
4669 }
4670 if ((cfile->resample_events = (resample_event *)(lives_calloc(length, sizeof(resample_event)))) == NULL) {
4671 // memory overflow
4672 return FALSE;
4673 }
4674 return TRUE;
4675}
4676
4677
4678int lives_list_strcmp_index(LiVESList * list, livesconstpointer data, boolean case_sensitive) {
4679 // find data in list, using strcmp
4680 int i;
4681 int len;
4682 if (!list) return -1;
4683
4684 len = lives_list_length(list);
4685
4686 if (case_sensitive) {
4687 for (i = 0; i < len; i++) {
4688 if (!lives_strcmp((const char *)lives_list_nth_data(list, i), (const char *)data)) return i;
4689 if (!lives_strcmp((const char *)lives_list_nth_data(list, i), (const char *)data)) return i;
4690 }
4691 } else {
4692 for (i = 0; i < len; i++) {
4693 if (!lives_utf8_strcasecmp((const char *)lives_list_nth_data(list, i), (const char *)data)) return i;
4694 if (!lives_utf8_strcasecmp((const char *)lives_list_nth_data(list, i), (const char *)data)) return i;
4695 }
4696 }
4697 return -1;
4698}
4699
4700
4701void add_to_recent(const char *filename, double start, frames_t frames, const char *extra_params) {
4702 const char *mtext;
4703 char buff[PATH_MAX * 2];
4704 char *file, *mfile, *prefname;
4705 register int i;
4706
4707 if (frames > 0) {
4708 mfile = lives_strdup_printf("%s|%.2f|%d", filename, start, frames);
4709 if (!extra_params || (!(*extra_params))) file = lives_strdup(mfile);
4710 else file = lives_strdup_printf("%s\n%s", mfile, extra_params);
4711 } else {
4712 mfile = lives_strdup(filename);
4713 if (!extra_params || (!(*extra_params))) file = lives_strdup(mfile);
4714 else file = lives_strdup_printf("%s\n%s", mfile, extra_params);
4715 }
4716
4717 for (i = 0; i < N_RECENT_FILES; i++) {
4719 if (!lives_strcmp(mfile, mtext)) break;
4720 }
4721
4722 if (i == 0) return;
4723
4724 if (i == N_RECENT_FILES) --i;
4725
4726 for (; i > 0; i--) {
4727 mtext = lives_menu_item_get_text(mainw->recent[i - 1]);
4730
4731 prefname = lives_strdup_printf("%s%d", PREF_RECENT, i);
4732 get_utf8_pref(prefname, buff, PATH_MAX * 2);
4733 lives_free(prefname);
4734
4735 prefname = lives_strdup_printf("%s%d", PREF_RECENT, i + 1);
4736 set_utf8_pref(prefname, buff);
4737 lives_free(prefname);
4738 }
4739
4742 prefname = lives_strdup_printf("%s%d", PREF_RECENT, 1);
4743 set_utf8_pref(prefname, file);
4744 lives_free(prefname);
4745
4746 for (; i < N_RECENT_FILES; i++) {
4748 if (*mtext) lives_widget_show(mainw->recent[i]);
4749 }
4750
4751 lives_free(mfile); lives_free(file);
4752}
4753
4754
4755int verhash(char *xv) {
4756 char *version, *s;
4757 int major = 0, minor = 0, micro = 0;
4758
4759 if (!xv) return 0;
4760
4761 version = lives_strdup(xv);
4762
4763 if (!(*version)) {
4765 return 0;
4766 }
4767
4768 s = strtok(version, ".");
4769 if (s) {
4770 major = atoi(s);
4771 s = strtok(NULL, ".");
4772 if (s) {
4773 minor = atoi(s);
4774 s = strtok(NULL, ".");
4775 if (s) micro = atoi(s);
4776 }
4777 }
4779 return major * 1000000 + minor * 1000 + micro;
4780}
4781
4782
4783// TODO - move into undo.c
4784void set_undoable(const char *what, boolean sensitive) {
4785 if (mainw->current_file > -1) {
4786 cfile->redoable = FALSE;
4787 cfile->undoable = sensitive;
4788 if (what) {
4789 char *what_safe = lives_strdelimit(lives_strdup(what), "_", ' ');
4790 lives_snprintf(cfile->undo_text, 32, _("_Undo %s"), what_safe);
4791 lives_snprintf(cfile->redo_text, 32, _("_Redo %s"), what_safe);
4792 lives_free(what_safe);
4793 } else {
4794 cfile->undoable = FALSE;
4795 cfile->undo_action = UNDO_NONE;
4796 lives_snprintf(cfile->undo_text, 32, "%s", _("_Undo"));
4797 lives_snprintf(cfile->redo_text, 32, "%s", _("_Redo"));
4798 }
4801 }
4802
4806
4807#ifdef PRODUCE_LOG
4808 lives_log(what);
4809#endif
4810}
4811
4812
4813void set_redoable(const char *what, boolean sensitive) {
4814 if (mainw->current_file > -1) {
4815 cfile->undoable = FALSE;
4816 cfile->redoable = sensitive;
4817 if (what) {
4818 char *what_safe = lives_strdelimit(lives_strdup(what), "_", ' ');
4819 lives_snprintf(cfile->undo_text, 32, _("_Undo %s"), what_safe);
4820 lives_snprintf(cfile->redo_text, 32, _("_Redo %s"), what_safe);
4821 lives_free(what_safe);
4822 } else {
4823 cfile->redoable = FALSE;
4824 cfile->undo_action = UNDO_NONE;
4825 lives_snprintf(cfile->undo_text, 32, "%s", _("_Undo"));
4826 lives_snprintf(cfile->redo_text, 32, "%s", _("_Redo"));
4827 }
4830 }
4831
4835}
4836
4837
4838void set_sel_label(LiVESWidget * sel_label) {
4839 char *tstr, *frstr, *tmp;
4840 char *sy, *sz;
4841
4842 if (mainw->current_file == -1 || !cfile->frames || mainw->multitrack) {
4843 lives_label_set_text(LIVES_LABEL(sel_label), _("-------------Selection------------"));
4844 } else {
4847 frstr = lives_strdup_printf("%d", cfile->end - cfile->start + 1);
4848
4849 // TRANSLATORS: - try to keep the text of the middle part the same length, by deleting "-" if necessary
4850 lives_label_set_text(LIVES_LABEL(sel_label),
4851 (tmp = lives_strconcat("---------- [ ", tstr, (sy = ((_(" sec ] ----------Selection---------- [ ")))),
4852 frstr, (sz = (_(" frames ] ----------"))), NULL)));
4853 lives_free(sy); lives_free(sz);
4854 lives_free(tmp); lives_free(frstr); lives_free(tstr);
4855 }
4856 lives_widget_queue_draw(sel_label);
4857}
4858
4859
4861 for (; list; list = list->next) lives_freep((void **)&list->data);
4862}
4863
4864
4866 if (!list || !*list) return;
4867 lives_list_free_strings((LiVESList *)*list);
4868 lives_slist_free(*list);
4869 *list = NULL;
4870}
4871
4872
4874 if (!list || !*list) return;
4876 lives_list_free(*list);
4877 *list = NULL;
4878}
4879
4880
4882 lives_speed_cache_t *speedy;
4883 for (LiVESList *xlist = *list; xlist; xlist = xlist->next) {
4884 speedy = (lives_speed_cache_t *)(*list)->data;
4885 if (speedy) {
4886 if (speedy->key) lives_free(speedy->key);
4887 if (speedy->data) lives_free(speedy->data);
4888 lives_free(speedy);
4889 }
4890 xlist->data = NULL;
4891 }
4892 lives_list_free(*list);
4893 *list = NULL;
4894}
4895
4896
4897void print_cache(LiVESList * cache) {
4899 lives_speed_cache_t *speedy;
4900 LiVESList *ll = cache;
4901 g_print("dumping cache %p\n", cache);
4902 for (; ll; ll = ll->next) {
4903 speedy = (lives_speed_cache_t *)ll->data;
4904 g_print("cach dets: %s = %s\n", speedy->key, speedy->data);
4905 }
4906}
4907
4908
4909LiVESList *cache_file_contents(const char *filename) {
4910 lives_speed_cache_t *speedy;
4911 LiVESList *list = NULL;
4912 FILE *hfile;
4913 size_t kelen;
4914 char buff[65536];
4915 char *key = NULL, *keystr_end = NULL, *cptr, *tmp, *data = NULL;
4916
4917 if (!(hfile = fopen(filename, "r"))) return NULL;
4918 while (fgets(buff, 65536, hfile)) {
4919 if (!*buff) continue;
4920 if (*buff == '#') continue;
4921 if (key) {
4922 if (!lives_strncmp(buff, keystr_end, kelen)) {
4923 speedy = (lives_speed_cache_t *)lives_calloc(1, sizeof(lives_speed_cache_t));
4924 speedy->hash = fast_hash(key);
4925 speedy->key = key;
4926 speedy->data = data;
4927 key = data = NULL;
4928 lives_free(keystr_end);
4929 keystr_end = NULL;
4930 list = lives_list_prepend(list, speedy);
4931 continue;
4932 }
4933 cptr = buff;
4934 if (data) {
4935 if (*buff != '|') continue;
4936 cptr++;
4937 }
4938 lives_chomp(cptr);
4939 tmp = lives_strdup_printf("%s%s", data ? data : "", cptr);
4940 if (data) lives_free(data);
4941 data = tmp;
4942 continue;
4943 }
4944 if (*buff != '<') continue;
4945 kelen = 0;
4946 for (cptr = buff; cptr; cptr++) {
4947 if (*cptr == '>') {
4948 kelen = cptr - buff;
4949 if (kelen > 2) {
4950 *cptr = 0;
4951 key = lives_strdup(buff + 1);
4952 keystr_end = lives_strdup_printf("</%s>", key);
4953 kelen++;
4954 }
4955 break;
4956 }
4957 }
4958 }
4959 fclose(hfile);
4960 if (key) lives_free(key);
4961 if (keystr_end) lives_free(keystr_end);
4962 return lives_list_reverse(list);
4963}
4964
4965
4966char *get_val_from_cached_list(const char *key, size_t maxlen, LiVESList * cache) {
4967 // WARNING - contents may be invalid if the underlying file is updated (e.g with set_*_pref())
4968 LiVESList *list = cache;
4969 uint32_t khash = fast_hash(key);
4970 lives_speed_cache_t *speedy;
4971 for (; list; list = list->next) {
4972 speedy = (lives_speed_cache_t *)list->data;
4973 if (khash == speedy->hash && !lives_strcmp(key, speedy->key))
4974 return lives_strndup(speedy->data, maxlen);
4975 }
4976 return NULL;
4977}
4978
4979
4980char *clip_detail_to_string(lives_clip_details_t what, size_t *maxlenp) {
4981 char *key = NULL;
4982
4983 switch (what) {
4985 key = lives_strdup("header_version"); break;
4986 case CLIP_DETAILS_BPP:
4987 key = lives_strdup("bpp"); break;
4988 case CLIP_DETAILS_FPS:
4989 key = lives_strdup("fps"); break;
4991 key = lives_strdup("pb_fps"); break;
4992 case CLIP_DETAILS_WIDTH:
4993 key = lives_strdup("width"); break;
4995 key = lives_strdup("height"); break;
4997 key = lives_strdup("unique_id"); break;
4998 case CLIP_DETAILS_ARATE:
4999 key = lives_strdup("audio_rate"); break;
5001 key = lives_strdup("pb_audio_rate"); break;
5003 key = lives_strdup("audio_channels"); break;
5005 key = lives_strdup("audio_signed"); break;
5007 key = lives_strdup("audio_endian"); break;
5009 key = lives_strdup("audio_sample_size"); break;
5011 key = lives_strdup("frames"); break;
5012 case CLIP_DETAILS_TITLE:
5013 key = lives_strdup("title"); break;
5015 key = lives_strdup("author"); break;
5017 key = lives_strdup("comment"); break;
5019 key = lives_strdup("keywords"); break;
5021 key = lives_strdup("pb_frameno"); break;
5023 key = lives_strdup("clipname"); break;
5025 key = lives_strdup("filename"); break;
5027 key = lives_strdup("interlace"); break;
5029 key = lives_strdup("decoder"); break;
5031 key = lives_strdup("gamma_type"); break;
5032 default: break;
5033 }
5034 if (maxlenp && *maxlenp == 0) *maxlenp = 256;
5035 return key;
5036}
5037
5038
5039boolean get_clip_value(int which, lives_clip_details_t what, void *retval, size_t maxlen) {
5040 lives_clip_t *sfile = mainw->files[which];
5041 char *lives_header = NULL;
5042 char *val, *key, *tmp;
5043
5044 int retval2 = LIVES_RESPONSE_NONE;
5045
5046 if (!IS_VALID_CLIP(which)) return FALSE;
5047
5048 if (!mainw->hdrs_cache) {
5053 if (which == mainw->ascrap_file) {
5054 lives_header = lives_build_filename(prefs->workdir, mainw->files[which]->handle,
5055 LIVES_ACLIP_HEADER, NULL);
5056 if (!lives_file_test(lives_header, LIVES_FILE_TEST_EXISTS)) {
5057 lives_free(lives_header);
5058 lives_header = NULL;
5059 }
5060 }
5061 if (!lives_header)
5062 lives_header = lives_build_filename(prefs->workdir, mainw->files[which]->handle,
5063 LIVES_CLIP_HEADER, NULL);
5064 if (!sfile->checked_for_old_header) {
5065 struct stat mystat;
5066 time_t old_time = 0, new_time = 0;
5067 char *old_header = lives_build_filename(prefs->workdir, sfile->handle, LIVES_CLIP_HEADER_OLD, NULL);
5069 if (!lives_file_test(old_header, LIVES_FILE_TEST_EXISTS)) {
5070 if (!stat(old_header, &mystat)) old_time = mystat.st_mtime;
5071 if (!stat(lives_header, &mystat)) new_time = mystat.st_mtime;
5072 if (old_time > new_time) {
5073 sfile->has_old_header = TRUE;
5074 lives_free(lives_header);
5075 return FALSE; // clip has been edited by an older version of LiVES
5076 }
5077 }
5078 lives_free(old_header);
5079 }
5080 }
5081
5083 key = clip_detail_to_string(what, &maxlen);
5084
5085 if (!key) {
5086 tmp = lives_strdup_printf("Invalid detail %d requested from file %s", which, lives_header);
5087 LIVES_ERROR(tmp);
5088 lives_free(tmp);
5089 lives_free(lives_header);
5090 return FALSE;
5091 }
5092
5093 if (mainw->hdrs_cache) {
5094 val = get_val_from_cached_list(key, maxlen, mainw->hdrs_cache);
5095 lives_free(key);
5096 if (!val) return FALSE;
5097 } else {
5098 val = (char *)lives_malloc(maxlen);
5099 if (!val) return FALSE;
5100 retval2 = get_pref_from_file(lives_header, key, val, maxlen);
5101 lives_free(lives_header);
5102 lives_free(key);
5103 }
5104
5105 if (retval2 == LIVES_RESPONSE_CANCEL) {
5106 lives_free(val);
5107 return FALSE;
5108 }
5109
5110 switch (what) {
5111 case CLIP_DETAILS_BPP:
5112 case CLIP_DETAILS_WIDTH:
5114 case CLIP_DETAILS_ARATE:
5120 *(int *)retval = atoi(val); break;
5122 *(int *)retval = 0;
5123 if (sfile->header_version == 0) *(int *)retval = atoi(val);
5124 if (*(int *)retval == 0 && (!strcasecmp(val, "false"))) *(int *)retval = 1; // unsigned
5125 break;
5127 *(int *)retval = atoi(val);
5128 if (retval == 0) *(int *)retval = 1;
5129 break;
5131 *(int *)retval = atoi(val);
5132 if (retval == 0) *(int *)retval = sfile->arps;
5133 break;
5135 *(int *)retval = atoi(val);
5136 break;
5137 case CLIP_DETAILS_FPS:
5138 *(double *)retval = strtod(val, NULL);
5139 if (*(double *)retval == 0.) *(double *)retval = prefs->default_fps;
5140 break;
5142 *(double *)retval = strtod(val, NULL);
5143 if (*(double *)retval == 0.) *(double *)retval = sfile->fps;
5144 break;
5146 if (capable->cpu_bits == 32) {
5147 *(uint64_t *)retval = (uint64_t)atoll(val);
5148 } else {
5149 *(uint64_t *)retval = (uint64_t)atol(val);
5150 }
5151 break;
5153 *(int *)retval = atoi(val) * 2; break;
5154 case CLIP_DETAILS_TITLE:
5159 lives_snprintf((char *)retval, maxlen, "%s", val);
5160 break;
5163 lives_snprintf((char *)retval, maxlen, "%s", (tmp = F2U8(val)));
5164 lives_free(tmp);
5165 break;
5166 default:
5167 lives_free(val);
5168 return FALSE;
5169 }
5170 lives_free(val);
5171 return TRUE;
5172}
5173
5174
5175boolean save_clip_value(int which, lives_clip_details_t what, void *val) {
5176 lives_clip_t *sfile;
5177 char *lives_header;
5178 char *com, *tmp;
5179 char *myval;
5180 char *key;
5181
5182 boolean needs_sigs = FALSE;
5183
5184 THREADVAR(write_failed) = 0;
5185 THREADVAR(com_failed) = FALSE;
5186
5187 if (which == 0 || which == mainw->scrap_file) return FALSE;
5188
5189 if (!IS_VALID_CLIP(which)) return FALSE;
5190
5191 sfile = mainw->files[which];
5192
5195 if (which == mainw->ascrap_file)
5196 lives_header = lives_build_filename(prefs->workdir, sfile->handle, LIVES_ACLIP_HEADER, NULL);
5197 else
5198 lives_header = lives_build_filename(prefs->workdir, sfile->handle, LIVES_CLIP_HEADER, NULL);
5199
5200 key = clip_detail_to_string(what, NULL);
5201
5202 if (!key) {
5203 tmp = lives_strdup_printf("Invalid detail %d added for file %s", which, lives_header);
5204 LIVES_ERROR(tmp);
5205 lives_free(tmp);
5206 lives_free(lives_header);
5207 return FALSE;
5208 }
5209
5210 switch (what) {
5211 case CLIP_DETAILS_BPP:
5212 myval = lives_strdup_printf("%d", *(int *)val);
5213 break;
5214 case CLIP_DETAILS_FPS:
5215 if (!sfile->ratio_fps) myval = lives_strdup_printf("%.3f", *(double *)val);
5216 else myval = lives_strdup_printf("%.8f", *(double *)val);
5217 break;
5219 if (sfile->ratio_fps && (sfile->pb_fps == sfile->fps))
5220 myval = lives_strdup_printf("%.8f", *(double *)val);
5221 else myval = lives_strdup_printf("%.3f", *(double *)val);
5222 break;
5223 case CLIP_DETAILS_WIDTH:
5224 myval = lives_strdup_printf("%d", *(int *)val); break;
5226 myval = lives_strdup_printf("%d", *(int *)val); break;
5228 myval = lives_strdup_printf("%"PRIu64, *(uint64_t *)val); break;
5229 case CLIP_DETAILS_ARATE:
5230 myval = lives_strdup_printf("%d", *(int *)val); break;
5232 myval = lives_strdup_printf("%d", *(int *)val); break;
5234 myval = lives_strdup_printf("%d", *(int *)val); break;
5236 if ((*(int *)val) == 1) myval = lives_strdup("true");
5237 else myval = lives_strdup("false");
5238 break;
5240 myval = lives_strdup_printf("%d", (*(int *)val) / 2);
5241 break;
5243 myval = lives_strdup_printf("%d", *(int *)val); break;
5245 myval = lives_strdup_printf("%d", *(int *)val); break;
5247 myval = lives_strdup_printf("%d", *(int *)val); break;
5249 myval = lives_strdup_printf("%d", *(int *)val); break;
5250 case CLIP_DETAILS_TITLE:
5251 myval = lives_strdup((char *)val); break;
5253 myval = lives_strdup((char *)val); break;
5255 myval = lives_strdup((const char *)val); break;
5257 myval = lives_strdup((const char *)val); break;
5259 myval = lives_strdup_printf("%d", *(int *)val); break;
5261 myval = lives_strdup((char *)val); break;
5263 myval = U82F((const char *)val); break;
5265 myval = U82F((const char *)val); break;
5267 myval = lives_strdup_printf("%d", *(int *)val); break;
5268 default:
5269 return FALSE;
5270 }
5271
5272 if (mainw->clip_header) {
5273 char *keystr_start = lives_strdup_printf("<%s>\n", key);
5274 char *keystr_end = lives_strdup_printf("\n</%s>\n\n", key);
5275 lives_fputs(keystr_start, mainw->clip_header);
5276 lives_fputs(myval, mainw->clip_header);
5277 lives_fputs(keystr_end, mainw->clip_header);
5278 lives_free(keystr_start);
5279 lives_free(keystr_end);
5280 } else {
5281 if (!mainw->signals_deferred) {
5283 needs_sigs = TRUE;
5284 }
5285 com = lives_strdup_printf("%s set_clip_value \"%s\" \"%s\" \"%s\"", prefs->backend_sync, lives_header, key, myval);
5286 lives_system(com, FALSE);
5289 lives_free(com);
5290 }
5291
5292 lives_free(lives_header);
5293 lives_free(myval);
5294 lives_free(key);
5295
5296 if (mainw->clip_header && THREADVAR(write_failed) == fileno(mainw->clip_header) + 1) {
5297 THREADVAR(write_failed) = 0;
5298 return FALSE;
5299 }
5300 if (THREADVAR(com_failed)) return FALSE;
5301 return TRUE;
5302}
5303
5304
5305LiVESList *get_set_list(const char *dir, boolean utf8) {
5306 // get list of sets in top level dir
5307 // values will be in filename encoding
5308
5309 LiVESList *setlist = NULL;
5310 DIR *tldir, *subdir;
5311 struct dirent *tdirent, *subdirent;
5312 char *subdirname;
5313
5314 if (!dir) return NULL;
5315
5316 tldir = opendir(dir);
5317
5318 if (!tldir) return NULL;
5319
5322
5323 while (1) {
5324 tdirent = readdir(tldir);
5325
5326 if (!tdirent) {
5327 closedir(tldir);
5329 return setlist;
5330 }
5331
5332 if (tdirent->d_name[0] == '.'
5333 && (!tdirent->d_name[1] || tdirent->d_name[1] == '.')) continue;
5334
5335 subdirname = lives_build_filename(dir, tdirent->d_name, NULL);
5336 subdir = opendir(subdirname);
5337
5338 if (!subdir) {
5339 lives_free(subdirname);
5340 continue;
5341 }
5342
5343 while (1) {
5344 subdirent = readdir(subdir);
5345 if (!subdirent) break;
5346
5347 if (!strcmp(subdirent->d_name, "order")) {
5348 if (!utf8)
5349 setlist = lives_list_append(setlist, lives_strdup(tdirent->d_name));
5350 else
5351 setlist = lives_list_append(setlist, F2U8(tdirent->d_name));
5352 break;
5353 }
5354 }
5355 lives_free(subdirname);
5356 closedir(subdir);
5357 }
5358}
5359
5360
5361boolean check_for_ratio_fps(double fps) {
5362 boolean ratio_fps;
5363 char *test_fps_string1 = lives_strdup_printf("%.3f00000", fps);
5364 char *test_fps_string2 = lives_strdup_printf("%.8f", fps);
5365
5366 if (strcmp(test_fps_string1, test_fps_string2)) {
5367 // got a ratio
5368 ratio_fps = TRUE;
5369 } else {
5370 ratio_fps = FALSE;
5371 }
5372 lives_free(test_fps_string1);
5373 lives_free(test_fps_string2);
5374
5375 return ratio_fps;
5376}
5377
5378
5379double get_ratio_fps(const char *string) {
5380 // return a ratio (8dp) fps from a string with format num:denom
5381 double fps;
5382 char *fps_string;
5383 char **array = lives_strsplit(string, ":", 2);
5384 int num = atoi(array[0]);
5385 int denom = atoi(array[1]);
5386 lives_strfreev(array);
5387 fps = (double)num / (double)denom;
5388 fps_string = lives_strdup_printf("%.8f", fps);
5389 fps = lives_strtod(fps_string, NULL);
5390 lives_free(fps_string);
5391 return fps;
5392}
5393
5394
5395char *remove_trailing_zeroes(double val) {
5396 int i;
5397 double xval = val;
5398
5399 if (val == (int)val) return lives_strdup_printf("%d", (int)val);
5400 for (i = 0; i <= 16; i++) {
5401 xval *= 10.;
5402 if (xval == (int)xval) return lives_strdup_printf("%.*f", i, val);
5403 }
5404 return lives_strdup_printf("%.*f", i, val);
5405}
5406
5407
5408uint32_t get_signed_endian(boolean is_signed, boolean little_endian) {
5409 // asigned TRUE == signed, FALSE == unsigned
5410
5411 if (is_signed) {
5412 if (little_endian) {
5413 return 0;
5414 } else {
5415 return AFORM_BIG_ENDIAN;
5416 }
5417 } else {
5418 if (!is_signed) {
5419 if (little_endian) {
5420 return AFORM_UNSIGNED;
5421 } else {
5423 }
5424 }
5425 }
5426 return AFORM_UNKNOWN;
5427}
5428
5429
5430size_t get_token_count(const char *string, int delim) {
5431 size_t pieces = 1;
5432 if (!string) return 0;
5433 if (delim <= 0 || delim > 255) return 1;
5434
5435 while ((string = strchr(string, delim)) != NULL) {
5436 pieces++;
5437 string++;
5438 }
5439 return pieces;
5440}
5441
5442
5443char *get_nth_token(const char *string, const char *delim, int pnumber) {
5444 char **array;
5445 char *ret = NULL;
5446 register int i;
5447 if (pnumber < 0 || pnumber >= get_token_count(string, (int)delim[0])) return NULL;
5448 array = lives_strsplit(string, delim, pnumber + 1);
5449 for (i = 0; i < pnumber; i++) {
5450 if (i == pnumber) ret = array[i];
5451 else lives_free(array[i]);
5452 }
5453 lives_free(array);
5454 return ret;
5455}
5456
5457
5458int lives_utf8_strcasecmp(const char *s1, const char *s2) {
5459 // ignore case
5460 char *s1u = lives_utf8_casefold(s1, -1);
5461 char *s2u = lives_utf8_casefold(s2, -1);
5462 int ret = lives_strcmp(s1u, s2u);
5463 lives_free(s1u);
5464 lives_free(s2u);
5465 return ret;
5466}
5467
5468
5469LIVES_GLOBAL_INLINE int lives_utf8_strcmp(const char *s1, const char *s2) {
5470 return lives_utf8_collate(s1, s2);
5471}
5472
5473
5474LIVES_GLOBAL_INLINE LiVESList *lives_list_sort_alpha(LiVESList * list, boolean fwd) {
5477 return lives_list_sort_with_data(list, lives_utf8_strcmpfunc, LIVES_INT_TO_POINTER(fwd));
5478}
5479
5480
5481#define BSIZE (8)
5482#define INITSIZE 32
5483
5484char *subst(const char *xstring, const char *from, const char *to) {
5485 // return a string with all occurrences of from replaced with to
5486 // return value should be freed after use
5487 char *ret = lives_calloc(INITSIZE, BSIZE);
5488 uint64_t ubuff = 0;
5489 char *buff;
5490
5491 const size_t fromlen = strlen(from);
5492 const size_t tolen = strlen(to);
5493 const size_t tolim = BSIZE - tolen;
5494
5495 size_t match = 0;
5496 size_t xtolen = tolen;
5497 size_t bufil = 0;
5498 size_t retfil = 0;
5499 size_t retsize = INITSIZE;
5500 size_t retlimit = retsize - BSIZE;
5501
5502 buff = (char *)&ubuff;
5503
5504 for (char *cptr = (char *)xstring; *cptr; cptr++) {
5505 if (*cptr == from[match++]) {
5506 if (match == fromlen) {
5507 match = 0;
5508 if (bufil > tolim) xtolen = BSIZE - bufil;
5509 lives_memcpy(buff + bufil, to, xtolen);
5510 if ((bufil += xtolen) == BSIZE) {
5511 if (retfil > retlimit) {
5512 ret = lives_recalloc(ret, retsize * 2, retsize, BSIZE);
5513 retsize *= 2;
5514 retlimit = (retsize - 1) * BSIZE;
5515 }
5516 lives_memcpy(ret + retfil, buff, BSIZE);
5517 retfil += BSIZE;
5518 bufil = 0;
5519 if (xtolen < tolen) {
5520 lives_memcpy(buff, to + xtolen, tolen - xtolen);
5521 bufil += tolen - xtolen;
5522 xtolen = tolen;
5523 }
5524 }
5525 }
5526 continue;
5527 }
5528 if (--match > 0) {
5529 xtolen = match;
5530 if (bufil > BSIZE - match) xtolen = BSIZE - bufil;
5531 lives_memcpy(buff + bufil, from, xtolen);
5532 if ((bufil += xtolen) == BSIZE) {
5533 if (retfil > retlimit) {
5534 ret = lives_recalloc(ret, retsize * 2, retsize, BSIZE);
5535 retsize *= 2;
5536 retlimit = (retsize - 1) * BSIZE;
5537 }
5538 lives_memcpy(ret + retfil, buff, BSIZE);
5539 retfil += BSIZE;
5540 bufil = 0;
5541 if (xtolen < fromlen) {
5542 lives_memcpy(buff, from + xtolen, fromlen - xtolen);
5543 bufil += fromlen - xtolen;
5544 xtolen = tolen;
5545 }
5546 }
5547 match = 0;
5548 }
5549 buff[bufil] = *cptr;
5550 if (++bufil == BSIZE) {
5551 if (retfil > retlimit) {
5552 ret = lives_recalloc(ret, retsize * 2, retsize, BSIZE);
5553 retsize *= 2;
5554 retlimit = (retsize - 1) * BSIZE;
5555 }
5556 lives_memcpy(ret + retfil, buff, BSIZE);
5557 retfil += BSIZE;
5558 bufil = 0;
5559 }
5560 }
5561
5562 if (bufil) {
5563 if (retsize > retlimit) {
5564 ret = lives_recalloc(ret, retsize + 1, retsize, BSIZE);
5565 retsize++;
5566 }
5567 lives_memcpy(ret + retfil, buff, bufil);
5568 retfil += bufil;
5569 }
5570 if (match) {
5571 if (retsize > retlimit) {
5572 ret = lives_recalloc(ret, retsize + 1, retsize, BSIZE);
5573 retsize++;
5574 }
5575 lives_memcpy(ret + retsize, from, match);
5576 retfil += match;
5577 }
5578 ret[retfil++] = 0;
5579 retsize *= BSIZE;
5580
5581 if (retsize - retfil > (retsize >> 2)) {
5582 char *tmp = lives_malloc(retfil);
5583 lives_memcpy(tmp, ret, retfil);
5584 lives_free(ret);
5585 return tmp;
5586 }
5587 return ret;
5588}
5589
5590
5591char *insert_newlines(const char *text, int maxwidth) {
5592 // crude formating of strings, ensure a newline after every run of maxwidth chars
5593 // does not take into account for example utf8 multi byte chars
5594
5595 wchar_t utfsym;
5596 char *retstr;
5597
5598 size_t runlen = 0;
5599 size_t req_size = 1; // for the terminating \0
5600 size_t tlen, align = 1;
5601
5602 int xtoffs;
5603
5604 boolean needsnl = FALSE;
5605
5606 register int i;
5607
5608 if (!text) return NULL;
5609
5610 if (maxwidth < 1) return lives_strdup("Bad maxwidth, dummy");
5611
5612 tlen = lives_strlen(text);
5613
5614 xtoffs = mbtowc(NULL, NULL, 0); // reset read state
5615
5616 //pass 1, get the required size
5617 for (i = 0; i < tlen; i += xtoffs) {
5618 xtoffs = mbtowc(&utfsym, &text[i], 4); // get next utf8 wchar
5619 if (!xtoffs) break;
5620 if (xtoffs == -1) {
5621 LIVES_WARN("mbtowc returned -1");
5622 return lives_strdup(text);
5623 }
5624
5625 if (*(text + i) == '\n') runlen = 0; // is a newline (in any encoding)
5626 else {
5627 runlen++;
5628 if (needsnl) req_size++;
5629 }
5630
5631 if (runlen == maxwidth) {
5632 if (i < tlen - 1 && (*(text + i + 1) != '\n')) {
5633 // needs a newline
5634 needsnl = TRUE;
5635 runlen = 0;
5636 }
5637 } else needsnl = FALSE;
5638 req_size += xtoffs;
5639 }
5640
5641 xtoffs = mbtowc(NULL, NULL, 0); // reset read state
5642
5643 align = get_max_align(req_size, DEF_ALIGN);
5644
5645 retstr = (char *)lives_calloc(req_size / align, align);
5646 req_size = 0; // reuse as a ptr to offset in retstr
5647 runlen = 0;
5648 needsnl = FALSE;
5649
5650 //pass 2, copy and insert newlines
5651
5652 for (i = 0; i < tlen; i += xtoffs) {
5653 xtoffs = mbtowc(&utfsym, &text[i], 4); // get next utf8 wchar
5654 if (!xtoffs) break;
5655 if (*(text + i) == '\n') runlen = 0; // is a newline (in any encoding)
5656 else {
5657 runlen++;
5658 if (needsnl) {
5659 *(retstr + req_size) = '\n';
5660 req_size++;
5661 }
5662 }
5663
5664 if (runlen == maxwidth) {
5665 if (i < tlen - 1 && (*(text + i + 1) != '\n')) {
5666 // needs a newline
5667 needsnl = TRUE;
5668 runlen = 0;
5669 }
5670 } else needsnl = FALSE;
5671 lives_memcpy(retstr + req_size, &utfsym, xtoffs);
5672 req_size += xtoffs;
5673 }
5674
5675 *(retstr + req_size) = 0;
5676
5677 return retstr;
5678}
5679
5680
5681static int get_hex_digit(const char c) {
5682 switch (c) {
5683 case 'a': case 'A': return 10;
5684 case 'b': case 'B': return 11;
5685 case 'c': case 'C': return 12;
5686 case 'd': case 'D': return 13;
5687 case 'e': case 'E': return 14;
5688 case 'f': case 'F': return 15;
5689 default: return c - 48;
5690 }
5691}
5692
5693
5694LIVES_GLOBAL_INLINE int hextodec(const char *string) {
5695 int tot = 0;
5696 for (char c = *string; c; c = *(++string)) tot = (tot << 4) + get_hex_digit(c);
5697 return tot;
5698}
5699
5700
5701boolean is_writeable_dir(const char *dir) {
5702 // return FALSE if we cannot create / write to dir
5703 // dir should be in locale encoding
5704 // WARNING: this will actually create the directory (since we dont know if its parents are needed)
5705
5706 struct statvfs sbuf;
5707 if (!lives_file_test(dir, LIVES_FILE_TEST_IS_DIR)) {
5708 lives_mkdir_with_parents(dir, capable->umask);
5709 if (!lives_file_test(dir, LIVES_FILE_TEST_IS_DIR)) {
5710 return FALSE;
5711 }
5712 }
5713
5714 // use statvfs to get fs details
5715 if (statvfs(dir, &sbuf) == -1) return FALSE;
5716 if (sbuf.f_flag & ST_RDONLY) return FALSE;
5717 return TRUE;
5718}
5719
5720
5721boolean lives_make_writeable_dir(const char *newdir) {
5724 int ret = lives_mkdir_with_parents(newdir, capable->umask);
5725 int myerrno = errno;
5726 if (!check_dir_access(newdir, TRUE)) {
5727 // abort if we cannot create the new subdir
5728 if (myerrno == EINVAL) {
5729 LIVES_ERROR("Could not write to directory");
5730 } else LIVES_ERROR("Could not create directory");
5731 LIVES_ERROR(newdir);
5732 THREADVAR(com_failed) = FALSE;
5733 return FALSE;
5734 } else {
5735 if (ret != -1) {
5736 LIVES_DEBUG("Created directory");
5737 LIVES_DEBUG(newdir);
5738 }
5739 }
5740 return TRUE;
5741}
5742
5743
5744LIVES_GLOBAL_INLINE LiVESInterpType get_interp_value(short quality, boolean low_for_mt) {
5745 if ((mainw->is_rendering || (mainw->multitrack && mainw->multitrack->is_rendering)) && !mainw->preview_rendering)
5746 return LIVES_INTERP_BEST;
5747 if (low_for_mt && mainw->multitrack) return LIVES_INTERP_FAST;
5748 if (quality <= PB_QUALITY_LOW) return LIVES_INTERP_FAST;
5749 else if (quality == PB_QUALITY_MED) return LIVES_INTERP_NORMAL;
5750 return LIVES_INTERP_BEST;
5751}
5752
5753
5754#define BL_LIM 128
5755LIVES_GLOBAL_INLINE LiVESList *buff_to_list(const char *buffer, const char *delim, boolean allow_blanks, boolean strip) {
5756 LiVESList *list = NULL;
5757 int pieces = get_token_count(buffer, delim[0]);
5758 char *buf, **array = lives_strsplit(buffer, delim, pieces);
5759 boolean biglist = pieces >= BL_LIM;
5760 for (int i = 0; i < pieces; i++) {
5761 if (array[i]) {
5762 if (strip) buf = lives_strstrip(array[i]);
5763 else buf = array[i];
5764 if (*buf || allow_blanks) {
5765 if (biglist) list = lives_list_prepend(list, lives_strdup(buf));
5766 else list = lives_list_append(list, lives_strdup(buf));
5767 }
5768 }
5769 }
5770 lives_strfreev(array);
5771 if (biglist && list) return lives_list_reverse(list);
5772 return list;
5773}
5774
5775
5776LIVES_GLOBAL_INLINE LiVESList *lives_list_append_unique(LiVESList * xlist, const char *add) {
5777 LiVESList *list = xlist, *listlast = NULL;
5778 while (list) {
5779 listlast = list;
5780 if (!lives_utf8_strcasecmp((const char *)list->data, add)) return xlist;
5781 list = list->next;
5782 }
5783 list = lives_list_append(listlast, lives_strdup(add));
5784 if (!xlist) return list;
5785 return xlist;
5786}
5787
5788
5789LIVES_GLOBAL_INLINE LiVESList *lives_list_move_to_first(LiVESList * list, LiVESList * item) {
5790 // move item to first in list
5791 LiVESList *xlist = item;
5792 if (xlist == list || !xlist) return list;
5793 if (xlist->prev) xlist->prev->next = xlist->next;
5794 if (xlist->next) xlist->next->prev = xlist->prev;
5795 xlist->prev = NULL;
5796 if ((xlist->next = list) != NULL) list->prev = xlist;
5797 return xlist;
5798}
5799
5800
5801LiVESList *lives_list_delete_string(LiVESList * list, const char *string) {
5802 // remove string from list, using strcmp
5803
5804 LiVESList *xlist = list;
5805 for (; xlist; xlist = xlist->next) {
5806 if (!lives_utf8_strcasecmp((char *)xlist->data, string)) {
5807 lives_free((livespointer)xlist->data);
5808 if (xlist->prev) xlist->prev->next = xlist->next;
5809 else list = xlist;
5810 if (xlist->next) xlist->next->prev = xlist->prev;
5811 xlist->next = xlist->prev = NULL;
5812 lives_list_free(xlist);
5813 return list;
5814 }
5815 }
5816 return list;
5817}
5818
5819
5820LIVES_GLOBAL_INLINE LiVESList *lives_list_copy_strings(LiVESList * list) {
5821 // copy a list, copying the strings too
5822 LiVESList *xlist = NULL, *olist = list;
5823 while (olist) {
5824 xlist = lives_list_prepend(xlist, lives_strdup((char *)olist->data));
5825 olist = olist->next;
5826 }
5827 return lives_list_reverse(xlist);
5828}
5829
5830
5831boolean string_lists_differ(LiVESList * alist, LiVESList * blist) {
5832 // compare 2 lists of strings and see if they are different (ignoring ordering)
5833 // for long lists this would be quicker if we sorted the lists first; however this function
5834 // is designed to deal with short lists only
5835
5836 LiVESList *plist, *rlist = blist;
5837
5838 if (lives_list_length(alist) != lives_list_length(blist)) return TRUE; // check the simple case first
5839
5840 // run through alist and see if we have a mismatch
5841
5842 plist = alist;
5843 while (plist) {
5844 LiVESList *qlist = rlist;
5845 boolean matched = TRUE;
5846 while (qlist) {
5847 if (!(lives_utf8_strcasecmp((char *)plist->data, (char *)qlist->data))) {
5848 if (matched) rlist = qlist->next;
5849 break;
5850 }
5851 matched = FALSE;
5852 qlist = qlist->next;
5853 }
5854 if (!qlist) return TRUE;
5855 plist = plist->next;
5856 }
5857
5858 // since both lists were of the same length, there is no need to check blist
5859
5860 return FALSE;
5861}
5862
boolean resync_audio(double frameno)
resync audio playback to the current video frame
Definition: audio.c:2822
LIVES_GLOBAL_INLINE char * lives_get_audio_file_name(int fnum)
Definition: audio.c:55
#define is_realtime_aplayer(ptype)
Definition: audio.h:236
@ RECA_WINDOW_GRAB
Definition: audio.h:197
@ RECA_MONITOR
Definition: audio.h:196
boolean dirchange_callback(LiVESAccelGroup *group, LiVESWidgetObject *obj, uint32_t keyval, LiVESXModifierType mod, livespointer area_enum)
Definition: callbacks.c:4996
void lives_notify(int msgnumber, const char *msgstring)
Definition: callbacks.c:49
boolean clip_can_reverse(int clipno)
Definition: callbacks.c:4980
int resize_all(int fileno, int width, int height, lives_img_type_t imgtype, boolean do_back, int *nbad, int *nmiss)
utility funcs for GUI
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_free(weed_layer_t *layer)
frees pixel_data for a layer, then the layer itself
LIVES_GLOBAL_INLINE int weed_layer_get_height(weed_layer_t *layer)
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_new(int layer_type)
Definition: colourspace.c:9655
LIVES_GLOBAL_INLINE int weed_layer_get_width(weed_layer_t *layer)
#define WEED_LAYER_TYPE_VIDEO
Definition: colourspace.h:221
#define LIVES_LAYER_GET_SIZE_ONLY
Definition: colourspace.h:260
#define WEED_LEAF_HOST_FLAGS
Definition: colourspace.h:24
weed_plant_t weed_layer_t
Definition: colourspace.h:71
lives_img_type_t resolve_img_type(lives_clip_t *sfile)
Definition: cvirtual.c:275
LIVES_GLOBAL_INLINE boolean do_set_locked_warning(const char *setname)
Definition: dialogs.c:4357
LiVESResponseType do_error_dialogf(const char *fmt,...)
Definition: dialogs.c:735
LiVESResponseType do_system_failed_error(const char *com, int retval, const char *addinfo, boolean can_retry, boolean trysudo)
Definition: dialogs.c:3897
void do_threaded_dialog(const char *trans_text, boolean has_cancel)
Definition: dialogs.c:3849
boolean do_yesno_dialogf(const char *fmt,...)
Definition: dialogs.c:635
LiVESResponseType do_write_failed_error_s_with_retry(const char *fname, const char *errtext)
Definition: dialogs.c:4058
void end_threaded_dialog(void)
Definition: dialogs.c:3883
void do_chdir_failed_error(const char *dir)
Definition: dialogs.c:4213
LIVES_GLOBAL_INLINE LiVESResponseType do_error_dialog(const char *text)
Definition: dialogs.c:749
LIVES_GLOBAL_INLINE boolean do_warning_dialog(const char *text)
Definition: dialogs.c:564
void threaded_dialog_spin(double fraction)
Definition: dialogs.c:3823
LiVESResponseType do_file_perm_error(const char *file_name, boolean allow_cancel)
Definition: dialogs.c:4226
boolean do_progress_dialog(boolean visible, boolean cancellable, const char *text)
Definition: dialogs.c:2274
#define WEED_LEAF_NEXT
Definition: events.h:62
#define WEED_LEAF_PREVIOUS
Definition: events.h:63
void add_to_clipmenu(void)
Definition: gui.c:4512
char * get_menu_name(lives_clip_t *sfile, boolean add_setname)
Definition: gui.c:4487
void update_timer_bars(int posx, int posy, int width, int height, int which)
draw the timer bars
Definition: interface.c:288
LIVES_GLOBAL_INLINE void msg_area_scroll_to_end(LiVESWidget *widget, LiVESAdjustment *adj)
Definition: interface.c:7277
#define KEY_RPT_INTERVAL
Definition: keyboard.h:76
error("LSD_RANDFUNC(ptr, size) must be defined")
LIVES_GLOBAL_INLINE boolean lives_strcmp(const char *st1, const char *st2)
returns FALSE if strings match
LIVES_GLOBAL_INLINE void * lives_calloc_safety(size_t nmemb, size_t xsize)
Definition: machinestate.c:603
off_t get_file_size(int fd)
Definition: machinestate.c:943
LIVES_GLOBAL_INLINE size_t lives_strlen(const char *s)
LIVES_GLOBAL_INLINE char * lives_strstop(char *st, const char term)
void autotune_u64(weed_plant_t *tuner, uint64_t min, uint64_t max, int ntrials, double cost)
Definition: machinestate.c:182
LIVES_GLOBAL_INLINE ticks_t lives_get_current_ticks(void)
Definition: machinestate.c:835
char * lives_format_storage_space_string(uint64_t space)
Definition: machinestate.c:664
LIVES_GLOBAL_INLINE uint32_t fast_hash(const char *key)
LIVES_GLOBAL_INLINE size_t get_max_align(size_t req_size, size_t align_max)
Definition: machinestate.c:596
LIVES_GLOBAL_INLINE void swab4(const void *from, const void *to, size_t gran)
uint64_t autotune_u64_end(weed_plant_t **tuner, uint64_t val)
Definition: machinestate.c:259
LIVES_GLOBAL_INLINE char * lives_chomp(char *buff)
LIVES_GLOBAL_INLINE boolean lives_strncmp(const char *st1, const char *st2, size_t len)
returns FALSE if strings match
LIVES_GLOBAL_INLINE ticks_t lives_get_relative_ticks(ticks_t origsecs, ticks_t orignsecs)
Definition: machinestate.c:813
LIVES_GLOBAL_INLINE void reverse_bytes(char *buff, size_t count, size_t gran)
LIVES_GLOBAL_INLINE weed_plant_t * lives_plant_new_with_index(int subtype, int64_t index)
lives_proc_thread_t lives_proc_thread_create(lives_thread_attr_t attr, lives_funcptr_t func, int return_type, const char *args_fmt,...)
create the specific plant which defines a background task to be run
LIVES_GLOBAL_INLINE void * lives_recalloc(void *p, size_t nmemb, size_t omemb, size_t xsize)
Definition: machinestate.c:615
#define LIVES_WEED_SUBTYPE_TUNABLE
Definition: machinestate.h:203
#define WEED_LEAF_LIVES_MESSAGE_STRING
Definition: machinestate.h:199
#define LIVES_WEED_SUBTYPE_MESSAGE
Definition: machinestate.h:201
#define lives_nanosleep(nanosec)
Definition: machinestate.h:307
#define lives_calloc
Definition: machinestate.h:67
#define WEED_PLANT_LIVES
Definition: machinestate.h:196
#define THREADVAR(var)
Definition: machinestate.h:531
#define lives_free
Definition: machinestate.h:52
#define lives_memset
Definition: machinestate.h:61
#define lives_nanosleep_until_nonzero(condition)
Definition: machinestate.h:310
#define WEED_LEAF_LIVES_SUBTYPE
Definition: machinestate.h:198
#define lives_malloc
Definition: machinestate.h:46
#define lives_memcpy
Definition: machinestate.h:55
#define PRIu64
Definition: machinestate.h:170
void *(* lives_funcptr_t)(void *)
Definition: machinestate.h:378
#define PRId64
Definition: machinestate.h:169
#define LIVES_THRDATTR_NONE
Definition: machinestate.h:437
void defer_sigint(int signum)
Definition: main.c:282
void catch_sigint(int signum)
Definition: main.c:296
void set_signal_handlers(SignalHandlerPointer sigfunc)
Definition: main.c:4077
void resize(double scale)
Definition: main.c:10230
void break_me(const char *brkstr)
Definition: main.c:159
mainwindow * mainw
Definition: main.c:103
void switch_to_file(int old_file, int new_file)
Definition: main.c:9646
boolean weed_layer_create_from_file_progressive(weed_layer_t *layer, const char *fname, int width, int height, int tpalette, const char *img_ext)
Definition: main.c:6989
int64_t frames64_t
Definition: main.h:100
#define LIVES_WARN(x)
Definition: main.h:1862
#define LIVES_DIRECTION_PAR(dir)
Definition: main.h:865
int frames_t
Definition: main.h:99
#define BUFF_SIZE_READ_LARGE
Definition: main.h:1595
#define IMG_TYPE_BEST
Definition: main.h:781
#define BUFF_SIZE_WRITE_BIGMED
Definition: main.h:1601
#define BUFF_SIZE_WRITE_SMALL
Definition: main.h:1598
#define BUFF_SIZE_READ_CUSTOM
Definition: main.h:1596
void(* SignalHandlerPointer)(int)
Definition: main.h:1464
#define clipboard
Definition: main.h:1835
#define LIVES_EXT_SRC_DECODER
Definition: main.h:1044
@ UNDO_NONE
Definition: main.h:660
@ STOP_ON_AUD_END
Definition: main.h:695
@ STOP_ON_VID_END
Definition: main.h:694
@ NEVER_STOP
Definition: main.h:693
#define MAX_FILES
max files is actually 1 more than this, since file 0 is the clipboard
Definition: main.h:184
pid_t lives_pid_t
Definition: main.h:117
#define LIVES_DEBUG(x)
Definition: main.h:1848
#define BUFF_SIZE_WRITE_LARGE
Definition: main.h:1602
#define CLIP_NAME_MAXLEN
Definition: main.h:804
#define LIVES_GLOBAL_INLINE
Definition: main.h:239
#define IGN_RET(a)
Definition: main.h:378
#define BUFFER_FILL_BYTES_LARGE
Definition: main.h:1590
#define AV_TRACK_MIN_DIFF
ignore track time differences < this (seconds)
Definition: main.h:806
#define DEF_FILE_PERMS
non-executable, is modified by the umask
Definition: main.h:209
#define LIVES_IS_PLAYING
Definition: main.h:840
#define IS_NORMAL_CLIP(clip)
Definition: main.h:833
#define DEF_ALIGN
Definition: main.h:629
#define BUFF_SIZE_WRITE_MED
Definition: main.h:1600
#define BUFFER_FILL_BYTES_SMALLMED
Definition: main.h:1587
#define BUFFER_FILL_BYTES_MED
Definition: main.h:1588
#define AFORM_UNKNOWN
Definition: main.h:788
#define LIVES_LOCAL_INLINE
Definition: main.h:246
#define N_RECENT_FILES
Definition: main.h:657
boolean get_new_handle(int index, const char *name)
Definition: saveplay.c:3821
#define sig(a)
Definition: main.h:268
#define BUFFER_FILL_BYTES_SMALL
fixed values only for write buffers (must be multiples of 16)
Definition: main.h:1586
#define AFORM_UNSIGNED
Definition: main.h:786
#define BUFF_SIZE_READ_SMALLMED
Definition: main.h:1593
#define CLIPBOARD_FILE
Definition: main.h:1834
#define GNU_CONST
Definition: main.h:79
int count_resampled_frames(int in_frames, double orig_fps, double resampled_fps)
Definition: resample.c:72
lives_clip_t * create_cfile(int new_file, const char *handle, boolean is_loaded)
set default values for a clip (in memory)
Definition: saveplay.c:3656
boolean save_clip_values(int which_file)
Definition: saveplay.c:103
lives_clip_details_t
Definition: main.h:1141
@ CLIP_DETAILS_KEYWORDS
Definition: main.h:1162
@ CLIP_DETAILS_UNIQUE_ID
Definition: main.h:1147
@ CLIP_DETAILS_TITLE
Definition: main.h:1155
@ CLIP_DETAILS_AUTHOR
Definition: main.h:1156
@ CLIP_DETAILS_DECODER_NAME
Definition: main.h:1164
@ CLIP_DETAILS_COMMENT
Definition: main.h:1157
@ CLIP_DETAILS_PB_FPS
Definition: main.h:1144
@ CLIP_DETAILS_ASAMPS
Definition: main.h:1153
@ CLIP_DETAILS_INTERLACE
Definition: main.h:1163
@ CLIP_DETAILS_HEIGHT
Definition: main.h:1146
@ CLIP_DETAILS_FPS
Definition: main.h:1143
@ CLIP_DETAILS_CLIPNAME
Definition: main.h:1160
@ CLIP_DETAILS_GAMMA_TYPE
Definition: main.h:1165
@ CLIP_DETAILS_WIDTH
Definition: main.h:1145
@ CLIP_DETAILS_PB_FRAMENO
Definition: main.h:1158
@ CLIP_DETAILS_FILENAME
Definition: main.h:1159
@ CLIP_DETAILS_ASIGNED
Definition: main.h:1151
@ CLIP_DETAILS_ACHANS
Definition: main.h:1150
@ CLIP_DETAILS_AENDIAN
Definition: main.h:1152
@ CLIP_DETAILS_PB_ARATE
Definition: main.h:1149
@ CLIP_DETAILS_BPP
Definition: main.h:1142
@ CLIP_DETAILS_ARATE
Definition: main.h:1148
@ CLIP_DETAILS_FRAMES
Definition: main.h:1154
@ CLIP_DETAILS_HEADER_VERSION
Definition: main.h:1161
#define CURRENT_CLIP_HAS_VIDEO
Definition: main.h:815
#define BUFFER_FILL_BYTES_BIGMED
Definition: main.h:1589
lives_direction_t
use REVERSE / FORWARD when a sign is used, BACKWARD / FORWARD when a parity is used
Definition: main.h:851
@ LIVES_DIRECTION_REVERSE
Definition: main.h:852
@ LIVES_DIRECTION_FORWARD
Definition: main.h:854
@ LIVES_DIRECTION_BACKWARD
Definition: main.h:853
#define IS_VALID_CLIP(clip)
Definition: main.h:808
int64_t ticks_t
Definition: main.h:97
#define CURRENT_CLIP_IS_NORMAL
Definition: main.h:838
capability * capable
Definition: main.h:627
lives_presence_t
Definition: main.h:391
@ UNCHECKED
Definition: main.h:393
@ PRESENT
Definition: main.h:394
@ LOCAL
Definition: main.h:395
@ MISSING
not yet implemented (TODO)
Definition: main.h:392
#define cfile
Definition: main.h:1833
#define BUFF_SIZE_WRITE_SMALLMED
Definition: main.h:1599
#define INSTALL_CANLOCAL
install guidance flags
Definition: main.h:389
#define LIVES_ERROR(x)
Definition: main.h:1870
lives_img_type_t
Definition: main.h:774
@ IMG_TYPE_UNKNOWN
Definition: main.h:775
@ IMG_TYPE_PNG
Definition: main.h:777
@ IMG_TYPE_JPEG
Definition: main.h:776
void pad_init_silence(void)
Definition: saveplay.c:293
void add_to_recovery_file(const char *handle)
Definition: saveplay.c:6460
int lives_pgid_t
Definition: main.h:118
#define AFORM_BIG_ENDIAN
Definition: main.h:787
#define CURRENT_CLIP_IS_VALID
Definition: main.h:809
#define BUFF_SIZE_READ_MED
Definition: main.h:1594
#define PATH_MAX
Definition: main.h:255
#define LIVES_DIR_SEP
Definition: main.h:197
@ CLIP_TYPE_FILE
unimported video, not or partially broken in frames
Definition: main.h:765
@ CLIP_TYPE_GENERATOR
frames from generator plugin
Definition: main.h:766
@ CLIP_TYPE_DISK
imported video, broken into frames
Definition: main.h:764
#define CLIP_TOTAL_TIME(clip)
Definition: main.h:830
#define BUFF_SIZE_READ_SMALL
Definition: main.h:1592
@ CANCEL_AUD_END
video playback completed
Definition: main.h:737
@ CANCEL_VID_END
video playback completed
Definition: main.h:725
#define CEIL(a, b)
Definition: main.h:283
#define LIVES_CLIP_HEADER_OLD
Definition: mainwindow.h:559
#define MAINW_MSG_SIZE
mainw->msg bytesize
Definition: mainwindow.h:702
#define EXEC_XDOTOOL
Definition: mainwindow.h:427
#define SCRATCH_BACK_EXTRA
Definition: mainwindow.h:1035
#define LIVES_IMAGE_TYPE_JPEG
Definition: mainwindow.h:479
#define SCRATCH_BACK
Definition: mainwindow.h:1028
#define ALL_USED
Definition: mainwindow.h:192
#define EXEC_WMCTRL
Definition: mainwindow.h:426
#define LIVES_MANUAL_FILENAME
Definition: mainwindow.h:522
#define WORKDIR_LITERAL
Definition: mainwindow.h:540
#define LIVES_MAX_ALARMS
Definition: mainwindow.h:1633
#define SCRATCH_REV
set on direction change (video)
Definition: mainwindow.h:1030
#define LIVES_SHORTEST_TIMEOUT
Definition: mainwindow.h:41
#define TICKS_PER_SECOND
ticks per second - GLOBAL TIMEBASE
Definition: mainwindow.h:36
#define USEC_TO_TICKS
multiplying factor uSec -> ticks_t (def. 100)
Definition: mainwindow.h:38
#define LIVES_MAX_USER_ALARMS
Definition: mainwindow.h:1634
#define LIVES_MANUAL_URL
Definition: mainwindow.h:521
#define SCRATCH_NONE
Definition: mainwindow.h:1027
#define TEMPFILE_MARKER
Definition: mainwindow.h:574
#define LIVES_MAIN_WINDOW_WIDGET
Definition: mainwindow.h:188
#define TICKS_PER_SECOND_DBL
actually microseconds / 100.
Definition: mainwindow.h:37
#define LIVES_ACLIP_HEADER
Definition: mainwindow.h:556
@ LIVES_STRING_CONSTANT_CL
"the current layout"
Definition: mainwindow.h:374
#define EXEC_YOUTUBE_DL
Definition: mainwindow.h:399
#define LIVES_FILE_EXT_PNG
Definition: mainwindow.h:487
#define LIVES_FILE_EXT_TMP
Definition: mainwindow.h:486
#define EXEC_PLAY
Definition: mainwindow.h:428
#define LIVES_CLIP_HEADER
Definition: mainwindow.h:555
#define SCRATCH_JUMP
jump and resync audio
Definition: mainwindow.h:1031
#define MAX_SET_NAME_LEN
sets
Definition: mainwindow.h:748
#define SCRATCH_FWD
Definition: mainwindow.h:1029
#define WORKDIR_LITERAL_LEN
Definition: mainwindow.h:541
#define LIVES_IMAGE_TYPE_PNG
Definition: mainwindow.h:480
#define SCRATCH_FWD_EXTRA
Definition: mainwindow.h:1034
#define LIVES_FILE_EXT_JPG
Definition: mainwindow.h:488
#define SCRATCH_JUMP_NORESYNC
jump with no audio resync
Definition: mainwindow.h:1032
lives_time_source_t
timebase sources
Definition: mainwindow.h:225
@ LIVES_TIME_SOURCE_NONE
Definition: mainwindow.h:226
@ LIVES_TIME_SOURCE_SOUNDCARD
Definition: mainwindow.h:228
@ LIVES_TIME_SOURCE_SYSTEM
Definition: mainwindow.h:227
@ LIVES_TIME_SOURCE_EXTERNAL
Definition: mainwindow.h:229
#define LIVES_IMAGE_TYPE_UNKNOWN
Definition: mainwindow.h:478
#define LOCAL_HOME_DIR
Definition: mainwindow.h:604
#define LIVES_URGENCY_ALARM
Definition: mainwindow.h:1636
int lives_alarm_t
Definition: mainwindow.h:696
#define SCREEN_AREA_FOREGROUND
Definition: mainwindow.h:1680
void mt_clip_select(lives_mt *mt, boolean scroll)
Definition: multitrack.c:3024
void save_layout_map(int *lmap, double *lmap_audio, const char *file, const char *dir)
Definition: multitrack.c:19714
void stored_event_list_free_all(boolean wiped)
Definition: multitrack.c:5897
void remove_current_from_affected_layouts(lives_mt *mt)
Definition: multitrack.c:5851
void mt_init_clips(lives_mt *mt, int orig_file, boolean add)
Definition: multitrack.c:10859
lives_lmap_error_t
Definition: multitrack.h:1015
@ LMAP_ERROR_DELETE_AUDIO
Definition: multitrack.h:1020
@ LMAP_ERROR_SHIFT_FRAMES
Definition: multitrack.h:1023
@ LMAP_ERROR_ALTER_FRAMES
Definition: multitrack.h:1024
@ LMAP_ERROR_MISSING_CLIP
Definition: multitrack.h:1017
@ LMAP_ERROR_DELETE_FRAMES
Definition: multitrack.h:1019
@ LMAP_INFO_SETNAME_CHANGED
Definition: multitrack.h:1029
@ LMAP_ERROR_CLOSE_FILE
Definition: multitrack.h:1018
@ LMAP_ERROR_ALTER_AUDIO
Definition: multitrack.h:1026
@ LMAP_ERROR_SHIFT_AUDIO
Definition: multitrack.h:1025
#define LIVES_OSC_NOTIFY_CLIP_OPENED
sent after a clip is opened
Definition: osc_notify.h:46
#define LIVES_OSC_NOTIFY_NONE
Definition: osc_notify.h:31
#define LIVES_OSC_NOTIFY_FAILED
for OSC only (not for C++)
Definition: osc_notify.h:53
#define LIVES_OSC_NOTIFY_CANCELLED
for OSC only (not for C++)
Definition: osc_notify.h:54
int64_t get_best_audio(_vid_playback_plugin *vpp)
Definition: plugins.c:1441
void close_clip_decoder(int clipno)
Definition: plugins.c:2382
LIVES_GLOBAL_INLINE LiVESResponseType get_pref_from_file(const char *filename, const char *key, char *val, int maxlen)
Definition: preferences.c:106
int set_string_pref(const char *key, const char *value)
Definition: preferences.c:290
int set_utf8_pref(const char *key, const char *value)
Definition: preferences.c:306
boolean pref_factory_bool(const char *prefidx, boolean newval, boolean permanent)
Definition: preferences.c:717
LiVESResponseType get_utf8_pref(const char *key, char *val, int maxlen)
Definition: preferences.c:112
#define AUDIO_PLAYER_NONE
Definition: preferences.h:47
#define PREF_RECENT
Definition: preferences.h:956
#define PREF_REC_EXT_AUDIO
Definition: preferences.h:892
#define JACK_OPTS_TRANSPORT_CLIENT
jack can start/stop
Definition: preferences.h:233
_prefs * prefs
Definition: preferences.h:847
#define WARN_MASK_LAYOUT_MISSING_CLIPS
Definition: preferences.h:94
#define PREF_AUDIO_PLAYER
Definition: preferences.h:910
#define AUD_PLAYER_SOX
Definition: preferences.h:42
#define AUDIO_PLAYER_JACK
Definition: preferences.h:49
#define AUDIO_PLAYER_SOX
Definition: preferences.h:48
#define AUDIO_PLAYER_PULSE
used in pref and for external players (e.g -ao pulse, -aplayer pulse)
Definition: preferences.h:51
#define PREF_AR_LAYOUT
Definition: preferences.h:933
#define JACK_OPTS_TIMEBASE_CLIENT
full timebase client
Definition: preferences.h:239
#define AUD_PLAYER_NONE
Definition: preferences.h:41
#define JACK_OPTS_NOPLAY_WHEN_PAUSED
play audio even when transport paused
Definition: preferences.h:236
#define AUDIO_OPTS_FOLLOW_FPS
Definition: preferences.h:256
#define AUD_PLAYER_JACK
Definition: preferences.h:43
#define PB_QUALITY_MED
default
Definition: preferences.h:33
#define PB_QUALITY_LOW
Definition: preferences.h:32
#define REC_FRAMES
Definition: preferences.h:197
#define AUDIO_SRC_EXT
Definition: preferences.h:206
#define AUDIO_SRC_INT
Definition: preferences.h:205
#define AUD_PLAYER_PULSE
Definition: preferences.h:44
LIVES_GLOBAL_INLINE ticks_t q_gint64_floor(ticks_t in, double fps)
Definition: resample.c:35
char backend[PATH_MAX *4]
Definition: preferences.h:411
char audio_play_command[PATH_MAX *2]
Definition: preferences.h:171
boolean vj_mode
Definition: preferences.h:459
boolean show_urgency_msgs
Definition: preferences.h:310
boolean perm_audio_reader
Definition: preferences.h:426
boolean crash_recovery
TRUE==maintain mainw->recovery file.
Definition: preferences.h:259
volatile uint32_t audio_opts
Definition: preferences.h:254
int audio_src
Definition: preferences.h:204
uint64_t warning_mask
Definition: preferences.h:80
char aplayer[512]
Definition: preferences.h:54
boolean show_gui
Definition: preferences.h:290
boolean ar_layout
Definition: preferences.h:284
double default_fps
Definition: preferences.h:173
char cmd_log[PATH_MAX]
Definition: preferences.h:168
boolean force_system_clock
Definition: preferences.h:366
char workdir[PATH_MAX]
kept in locale encoding
Definition: preferences.h:61
int rec_opts
Definition: preferences.h:196
boolean noframedrop
Definition: preferences.h:469
boolean show_msg_area
Definition: preferences.h:225
int bigendbug
default 0; 1==use old (bad) behaviour on bigendian machines (r/w bigend ints/doubles); 2==bad reads,...
Definition: preferences.h:374
uint32_t jack_opts
Definition: preferences.h:232
boolean show_overlay_msgs
Definition: preferences.h:311
int sleep_time
Definition: preferences.h:176
char ar_layout_name[PATH_MAX]
locale
Definition: preferences.h:286
boolean show_dev_opts
Definition: preferences.h:463
int max_messages
Definition: preferences.h:444
char backend_sync[PATH_MAX *4]
Definition: preferences.h:410
short audio_player
Definition: preferences.h:40
int scratchback_amount
Definition: preferences.h:229
uint32_t audio_codec
Definition: plugins.h:169
int *(* get_audio_fmts)(void)
Definition: plugins.h:167
char touch_cmd[PATH_MAX]
Definition: main.h:553
char home_dir[PATH_MAX]
home directory - default location for config file - locale encoding
Definition: main.h:544
int nmonitors
Definition: main.h:588
pid_t mainpid
Definition: main.h:591
int byte_order
Definition: main.h:577
lives_checkstatus_t has_sox_play
Definition: main.h:508
char chmod_cmd[PATH_MAX]
Definition: main.h:558
char rmdir_cmd[PATH_MAX]
Definition: main.h:565
char mv_cmd[PATH_MAX]
Definition: main.h:555
char cat_cmd[PATH_MAX]
Definition: main.h:559
char rm_cmd[PATH_MAX]
Definition: main.h:554
char cp_cmd[PATH_MAX]
Definition: main.h:556
char ln_cmd[PATH_MAX]
Definition: main.h:557
short cpu_bits
Definition: main.h:583
char echo_cmd[PATH_MAX]
Definition: main.h:563
char * myname
Definition: main.h:580
mode_t umask
Definition: main.h:597
corresponds to one clip in the GUI
Definition: main.h:877
int arps
audio physical sample rate (i.e the "normal" sample rate of the clip when played at 1,...
Definition: main.h:905
frames_t frames
number of video frames
Definition: main.h:890
frames_t tcache_dubious_from
height for thumbnail cache (width is fixed, but if this changes, invalidate)
Definition: main.h:1099
LiVESWidget * menuentry
Definition: main.h:1011
frames_t end
Definition: main.h:891
lives_direction_t adirection
audio play direction during playback, FORWARD or REVERSE.
Definition: main.h:1016
void * ext_src
points to opaque source for non-disk types
Definition: main.h:1040
int asampsize
audio sample size in bits (8 or 16)
Definition: main.h:908
lives_img_type_t img_type
Definition: main.h:887
boolean checked_for_old_header
Definition: main.h:1091
frames_t last_frameno
Definition: main.h:934
volatile off64_t aseek_pos
audio seek posn. (bytes) for when we switch clips
Definition: main.h:1064
int header_version
Definition: main.h:940
int achans
number of audio channels (0, 1 or 2)
Definition: main.h:907
LiVESList * layout_map
Definition: main.h:1037
boolean ratio_fps
framerate of the clip
Definition: main.h:894
double laudio_time
Definition: main.h:929
double pb_fps
current playback rate, may vary from fps, can be 0. or negative
Definition: main.h:1007
frames_t frameno
Definition: main.h:934
boolean has_old_header
Definition: main.h:1091
size_t afilesize
Definition: main.h:912
double video_time
Definition: main.h:929
int arate
current audio playback rate (varies if the clip rate is changed)
Definition: main.h:906
frames_t opening_frames
Definition: main.h:947
double raudio_time
Definition: main.h:929
double fps
Definition: main.h:893
ulong menuentry_func
Definition: main.h:1012
char handle[256]
Definition: main.h:881
boolean opening
Definition: main.h:946
frames_t start
Definition: main.h:891
boolean read
Definition: main.h:1612
size_t orig_size
Definition: main.h:1620
char * pathname
Definition: main.h:1621
int64_t totbytes
Definition: main.h:1617
volatile boolean invalid
Definition: main.h:1619
boolean allow_fail
Definition: main.h:1618
boolean slurping
Definition: main.h:1614
ssize_t bytes
Definition: main.h:1605
off_t offset
ptr to data (ptr - buffer + bytes) gives the read size
Definition: main.h:1608
uint8_t * ptr
buffer size for write, bytes left to read in case of read
Definition: main.h:1606
uint8_t * buffer
read point in buffer
Definition: main.h:1607
boolean reversed
Definition: main.h:1613
LiVESXDisplay * disp
Definition: mainwindow.h:358
LiVESXScreen * screen
Definition: mainwindow.h:359
volatile ticks_t lastcheck
Definition: mainwindow.h:693
boolean current
Definition: multitrack.h:1038
double atime
Definition: multitrack.h:1037
livespointer data
Definition: multitrack.h:1035
lives_lmap_error_t type
Definition: multitrack.h:1033
char * name
Definition: multitrack.h:1034
char * foreign_visual
Definition: mainwindow.h:846
int64_t rec_samples
Definition: mainwindow.h:1527
char * overlay_msg
Definition: mainwindow.h:1644
weed_plant_t * ref_message
Definition: mainwindow.h:1730
lives_cursor_t cursor_style
Definition: mainwindow.h:1296
_vid_playback_plugin * vpp
video plugin
Definition: mainwindow.h:1572
int ref_message_n
Definition: mainwindow.h:1732
volatile int agen_key
which fx key is generating audio [1 based] (or 0 for none)
Definition: mainwindow.h:1649
LiVESWidget * redo
Definition: mainwindow.h:1147
boolean aplayer_broken
Definition: mainwindow.h:1653
volatile boolean video_seek_ready
Definition: mainwindow.h:939
frames_t rec_vid_frames
values to be written to the event list concurrent with next video ftame event
Definition: mainwindow.h:1529
double aframeno
and the audio 'frame' for when we are looping
Definition: mainwindow.h:962
int osc_auto
bypass user choices automatically
Definition: mainwindow.h:918
LiVESTextBuffer * layout_textbuffer
stores layout errors
Definition: mainwindow.h:1468
pthread_mutex_t alarmlist_mutex
append / remove with file_buffer list
Definition: mainwindow.h:1507
volatile short scratch
Definition: mainwindow.h:1026
uint32_t signal_caught
Definition: mainwindow.h:1673
char msg[MAINW_MSG_SIZE]
Definition: mainwindow.h:724
int aud_rec_fd
fd of file we are recording audio to
Definition: mainwindow.h:1525
int last_dprint_file
message output settings
Definition: mainwindow.h:1535
double fixed_fpsd
<=0. means free playback
Definition: mainwindow.h:990
unsigned char * sl_undo_mem
Definition: mainwindow.h:812
void * pulsed
pulseaudio player
Definition: mainwindow.h:1463
LiVESWidget * vol_toolitem
Definition: mainwindow.h:1364
lives_clip_t * files[MAX_FILES+1]
+1 for the clipboard
Definition: mainwindow.h:729
int rec_signed_endian
Definition: mainwindow.h:1532
volatile boolean record
Definition: mainwindow.h:794
pthread_mutex_t fbuffer_mutex
Definition: mainwindow.h:1506
int n_messages
Definition: mainwindow.h:1731
boolean is_rendering
Definition: mainwindow.h:821
LiVESWidget * recent[N_RECENT_FILES]
Definition: mainwindow.h:1129
lives_mgeometry_t * mgeom
multi-head support
Definition: mainwindow.h:1576
boolean clip_switched
for recording - did we switch clips ?
Definition: mainwindow.h:793
boolean go_away
Definition: mainwindow.h:1614
volatile boolean loop_cont
Definition: mainwindow.h:764
int foreign_width
Definition: mainwindow.h:844
char * string_constants[NUM_LIVES_STRING_CONSTANTS]
Definition: mainwindow.h:1539
LiVESWidget * playframe
Definition: mainwindow.h:1098
lives_alarm_t overlay_alarm
Definition: mainwindow.h:1646
volatile lives_cancel_t cancelled
Definition: mainwindow.h:798
int cap_number
Definition: mainwindow.h:739
lives_clip_t * cbstores[8]
Definition: mainwindow.h:1782
boolean preview
Definition: mainwindow.h:757
int rec_asamps
Definition: mainwindow.h:1532
int next_free_alarm
Definition: mainwindow.h:1640
int current_file
Definition: mainwindow.h:727
boolean is_ready
Definition: mainwindow.h:787
LiVESWidget * play_window
Definition: mainwindow.h:947
LiVESWidget * loop_video
Definition: mainwindow.h:1173
void * jackd
jack audio player / transport
Definition: mainwindow.h:1453
boolean loop
Definition: mainwindow.h:763
LiVESList * file_buffers
list of open files for buffered i/o
Definition: mainwindow.h:1523
lives_pgid_t alives_pgid
Definition: mainwindow.h:877
int scrap_file
we throw odd sized frames here when recording in real time; used if a source is a generator or stream
Definition: mainwindow.h:874
LiVESList * affected_layout_marks
list of pairs of marks in affected_layouts_map, text between them should be deleted when stored_layou...
Definition: mainwindow.h:1474
lives_timeout_t alarms[LIVES_MAX_ALARMS]
reserve 1 for emergency msgs
Definition: mainwindow.h:1639
LiVESAdjustment * msg_adj
Definition: mainwindow.h:1326
boolean recovering_files
Definition: mainwindow.h:1485
weed_plant_t * msg_list
Definition: mainwindow.h:1729
boolean signals_deferred
Definition: mainwindow.h:1674
LiVESWidget * spinbutton_end
Definition: mainwindow.h:1288
volatile boolean is_exiting
set during shutdown (inverse of only_close then)
Definition: mainwindow.h:1440
boolean no_switch_dprint
Definition: mainwindow.h:1536
LiVESList * new_lmap_errors
Definition: mainwindow.h:815
boolean fs
Definition: mainwindow.h:762
void * pulsed_read
Definition: mainwindow.h:1464
LiVESWidget * m_mutebutton
Definition: mainwindow.h:1370
LiVESWidget * p_mutebutton
Definition: mainwindow.h:1379
int pwidth
PLAYBACK.
Definition: mainwindow.h:926
boolean error
Definition: mainwindow.h:801
boolean ext_playback
using external video playback plugin
Definition: mainwindow.h:773
LiVESWidget * ext_audio_checkbutton
Definition: mainwindow.h:1358
boolean suppress_dprint
tidy up, e.g. by blocking "switched to file..." and "closed file..." messages
Definition: mainwindow.h:1537
int pheight
playback height
Definition: mainwindow.h:927
LiVESWidget * t_sepwin
Definition: mainwindow.h:1340
int audio_end
Definition: mainwindow.h:771
frames_t play_start
Definition: mainwindow.h:931
boolean sep_win
Definition: mainwindow.h:761
ulong spin_start_func
Definition: mainwindow.h:1064
char * urgency_msg
OSD.
Definition: mainwindow.h:1643
LiVESWidget * show_layout_errors
Definition: mainwindow.h:1225
double rec_fps
Definition: mainwindow.h:1528
weed_event_t * stored_event_list
stored mt -> clip editor
Definition: mainwindow.h:804
LiVESWidget * mute_audio
Definition: mainwindow.h:1177
LiVESWidget * preview_box
Definition: mainwindow.h:1304
boolean playing_sel
list of set names in current workdir, mau be NULL
Definition: mainwindow.h:756
LiVESWidget * spinbutton_start
Definition: mainwindow.h:1288
LiVESWidget * recaudio_submenu
Definition: mainwindow.h:1194
volatile ticks_t clock_ticks
unadjusted system time since pb start, measured concurrently with currticks
Definition: mainwindow.h:1003
LiVESList * current_layouts_map
map of all layouts for set
Definition: mainwindow.h:1470
LiVESWidget * vol_label
Definition: mainwindow.h:1365
boolean jack_can_stop
Definition: mainwindow.h:934
volatile boolean record_paused
pause during recording
Definition: mainwindow.h:1557
int ascrap_file
scrap file for recording audio scraps
Definition: mainwindow.h:875
LiVESWidget * msg_area
Definition: mainwindow.h:1324
lives_mt * multitrack
holds a pointer to the entire multitrack environment; NULL in Clip Edit mode
Definition: mainwindow.h:1087
boolean faded
Definition: mainwindow.h:759
xprocess * proc_ptr
Definition: mainwindow.h:1090
volatile boolean ping_pong
Definition: mainwindow.h:765
boolean foreign
for external window capture
Definition: mainwindow.h:824
volatile boolean agen_needs_reinit
Definition: mainwindow.h:1650
boolean memok
set to FALSE if a segfault is received, ie. we should assume all memory is corrupted and exit ASAP
Definition: mainwindow.h:1776
Window foreign_id
Definition: mainwindow.h:840
LiVESWidget * int_audio_checkbutton
Definition: mainwindow.h:1358
ticks_t cadjticks
used to equalise the timecode between alternate timer sources (clock -> source adjustment)
Definition: mainwindow.h:1008
boolean preview_rendering
Definition: mainwindow.h:758
LiVESWidget * undo
Definition: mainwindow.h:1146
char set_name[256]
Definition: mainwindow.h:749
LiVESWidget * t_infobutton
Definition: mainwindow.h:1341
int first_free_file
Definition: mainwindow.h:728
frames_t play_end
Definition: mainwindow.h:931
ticks_t syncticks
adjustment to compensate for missed clock updates when switching time sources
Definition: mainwindow.h:1010
boolean double_size
Definition: mainwindow.h:760
ticks_t deltaticks
deltaticks for scratching
Definition: mainwindow.h:1006
ticks_t adjticks
used to equalise the timecode between alternate timer sources (souce -> clock adjustment)
Definition: mainwindow.h:1007
LiVESList * affected_layouts_map
map of layouts with errors
Definition: mainwindow.h:1469
boolean mute
Definition: mainwindow.h:770
volatile lives_whentostop_t whentostop
Definition: mainwindow.h:929
int playing_file
which number file we are playing (or -1) [generally mainw->current_file]
Definition: mainwindow.h:943
int foreign_height
Definition: mainwindow.h:844
ulong spin_end_func
Definition: mainwindow.h:1065
int rec_achans
Definition: mainwindow.h:1532
FILE * clip_header
Definition: mainwindow.h:1521
int foreign_bpp
Definition: mainwindow.h:845
LiVESXWindow * foreign_window
Definition: mainwindow.h:843
void * jackd_read
dummy
Definition: mainwindow.h:1454
weed_event_t * event_list
current event_list, for recording
Definition: mainwindow.h:803
LiVESList * hdrs_cache
cache of a file header (e.g. header.lives)
Definition: mainwindow.h:1518
LiVESWidget * playarea
Definition: mainwindow.h:1321
this struct is used only when physically resampling frames on the disk we create an array of these an...
Definition: main.h:641
boolean non_modal
non-modal for dialogs
int monitor
monitor we are displaying on
LiVESWidget * processing
Definition: mainwindow.h:706
#define lives_strdup_printf(fmt,...)
Definition: support.c:27
#define _(String)
Definition: support.h:44
#define P_(String, StringPlural, n)
Definition: support.h:46
LIVES_GLOBAL_INLINE void clear_mainw_msg(void)
Definition: utils.c:1435
ssize_t lives_read_buffered(int fd, void *buf, ssize_t count, boolean allow_less)
Definition: utils.c:924
LIVES_GLOBAL_INLINE void lives_list_free_strings(LiVESList *list)
Definition: utils.c:4860
int lives_close_buffered(int fd)
Definition: utils.c:716
boolean string_lists_differ(LiVESList *alist, LiVESList *blist)
Definition: utils.c:5831
ssize_t lives_write_le_buffered(int fd, const void *buf, ssize_t count, boolean allow_fail)
Definition: utils.c:1329
boolean switch_aud_to_jack(boolean set_in_prefs)
Definition: utils.c:3819
boolean d_print_urgency(double timeout, const char *fmt,...)
Definition: utils.c:2497
LIVES_GLOBAL_INLINE LiVESList * lives_list_copy_strings(LiVESList *list)
Definition: utils.c:5820
void calc_aframeno(int fileno)
Definition: utils.c:1845
LiVESList * lives_list_delete_string(LiVESList *list, const char *string)
Definition: utils.c:5801
char * insert_newlines(const char *text, int maxwidth)
Definition: utils.c:5591
ssize_t lives_write(int fd, const void *buf, ssize_t count, boolean allow_fail)
Definition: utils.c:309
LIVES_GLOBAL_INLINE uint64_t get_near2pow(uint64_t val)
Definition: utils.c:1463
ssize_t lives_popen(const char *com, boolean allow_error, char *buff, ssize_t buflen)
Definition: utils.c:194
#define VER_MINOR_MULT
Definition: utils.c:3497
LIVES_GLOBAL_INLINE lives_img_type_t lives_image_ext_to_img_type(const char *img_ext)
Definition: utils.c:3034
boolean add_lmap_error(lives_lmap_error_t lerror, const char *name, livespointer user_data, int clipno, int frameno, double atime, boolean affects_current)
Definition: utils.c:2673
void activate_url(LiVESAboutDialog *about, const char *link, livespointer data)
Definition: utils.c:4624
int lives_cat(const char *from, const char *to, boolean append)
Definition: utils.c:4484
LIVES_GLOBAL_INLINE int hextodec(const char *string)
Definition: utils.c:5694
void wait_for_bg_audio_sync(int fileno)
Definition: utils.c:4644
size_t get_token_count(const char *string, int delim)
Definition: utils.c:5430
double get_ratio_fps(const char *string)
Definition: utils.c:5379
int get_frame_count(int idx, int start)
sets mainw->files[idx]->frames with current framecount
Definition: utils.c:3109
LIVES_GLOBAL_INLINE void get_filename(char *filename, boolean strip_dir)
Definition: utils.c:3205
LIVES_GLOBAL_INLINE LiVESList * lives_list_append_unique(LiVESList *xlist, const char *add)
Definition: utils.c:5776
LIVES_GLOBAL_INLINE LiVESList * lives_list_move_to_first(LiVESList *list, LiVESList *item)
Definition: utils.c:5789
void get_total_time(lives_clip_t *file)
calculate laudio, raudio and video time (may be deprecated and replaced with macros)
Definition: utils.c:3690
LIVES_GLOBAL_INLINE char * lives_ellipsize(char *txt, size_t maxlen, LiVESEllipsizeMode mode)
Definition: utils.c:3262
off_t lives_lseek_buffered_writer(int fd, off_t offset)
Definition: utils.c:1338
LIVES_GLOBAL_INLINE boolean int_array_contains_value(int *array, int num_elems, int value)
Definition: utils.c:4284
int lives_touch(const char *tfile)
Definition: utils.c:4455
void calc_minspect(int rwidth, int rheight, int *cwidth, int *cheight)
Definition: utils.c:2195
char * unhash_version(uint64_t version)
Definition: utils.c:3522
int lives_chdir(const char *path, boolean no_error_dlg)
Definition: utils.c:1393
boolean check_for_ratio_fps(double fps)
Definition: utils.c:5361
LIVES_GLOBAL_INLINE int lives_create_buffered_nosync(const char *pathname, int mode)
Definition: utils.c:702
#define BSIZE
Definition: utils.c:5481
boolean check_file(const char *file_name, boolean check_existing)
check if file exists
Definition: utils.c:4312
#define VER_MICRO_MULT
Definition: utils.c:3498
boolean ensure_isdir(char *fname)
Definition: utils.c:3346
void minimise_aspect_delta(double aspect, int hblock, int vblock, int hsize, int vsize, int *width, int *height)
Definition: utils.c:3750
ssize_t lives_write_buffered(int fd, const char *buf, ssize_t count, boolean allow_fail)
Definition: utils.c:1226
void get_dirname(char *filename)
Definition: utils.c:3167
LIVES_GLOBAL_INLINE int calc_frame_from_time4(int filenum, double time)
nearest frame, no maximum
Definition: utils.c:1788
boolean save_clip_value(int which, lives_clip_details_t what, void *val)
Definition: utils.c:5175
LIVES_GLOBAL_INLINE void d_print_cancelled(void)
Definition: utils.c:2610
LIVES_GLOBAL_INLINE boolean lives_fsync(int fd)
Definition: utils.c:109
LIVES_GLOBAL_INLINE int lives_open_buffered_rdonly(const char *pathname)
Definition: utils.c:636
LIVES_GLOBAL_INLINE int calc_frame_from_time(int filenum, double time)
nearest frame [1, frames]
Definition: utils.c:1759
boolean create_event_space(int length)
Definition: utils.c:4660
int add_messages_to_list(const char *text)
Definition: utils.c:2416
void clear_lmap_errors(void)
Definition: utils.c:2858
void add_to_recent(const char *filename, double start, frames_t frames, const char *extra_params)
Definition: utils.c:4701
int lives_utf8_strcasecmp(const char *s1, const char *s2)
Definition: utils.c:5458
boolean lives_read_buffered_eof(int fd)
Definition: utils.c:1170
boolean lives_make_writeable_dir(const char *newdir)
Definition: utils.c:5721
size_t lives_buffered_orig_size(int fd)
Definition: utils.c:1377
int lives_chmod(const char *target, const char *mode)
Definition: utils.c:4475
LIVES_GLOBAL_INLINE void lives_sync(int times)
Definition: utils.c:115
void lives_suspend_resume_process(const char *dirname, boolean suspend)
Definition: utils.c:4527
ssize_t lives_read_le_buffered(int fd, void *buf, ssize_t count, boolean allow_less)
Definition: utils.c:1158
LIVES_GLOBAL_INLINE int lives_create_buffered(const char *pathname, int mode)
Definition: utils.c:698
LIVES_GLOBAL_INLINE void d_print_failed(void)
Definition: utils.c:2615
char * get_nth_token(const char *string, const char *delim, int pnumber)
Definition: utils.c:5443
LIVES_GLOBAL_INLINE lives_img_type_t lives_image_type_to_img_type(const char *lives_img_type)
Definition: utils.c:3046
LIVES_GLOBAL_INLINE int lives_utf8_strcmp(const char *s1, const char *s2)
Definition: utils.c:5469
LIVES_GLOBAL_INLINE LiVESList * buff_to_list(const char *buffer, const char *delim, boolean allow_blanks, boolean strip)
Definition: utils.c:5755
boolean d_print_overlay(double timeout, const char *fmt,...)
Definition: utils.c:2523
boolean lives_alarm_clear(lives_alarm_t alarm_handle)
Definition: utils.c:1732
LIVES_GLOBAL_INLINE boolean lives_unsetenv(const char *name)
Definition: utils.c:132
void set_redoable(const char *what, boolean sensitive)
Definition: utils.c:4813
LIVES_GLOBAL_INLINE void d_print_file_error_failed(void)
Definition: utils.c:2625
boolean dirs_equal(const char *dira, const char *dirb)
Definition: utils.c:3390
LIVES_GLOBAL_INLINE uint32_t get_approx_ln(uint32_t x)
Definition: utils.c:1453
int lives_system(const char *com, boolean allow_error)
Definition: utils.c:145
char * clip_detail_to_string(lives_clip_details_t what, size_t *maxlenp)
Definition: utils.c:4980
void find_when_to_stop(void)
Definition: utils.c:3722
void set_undoable(const char *what, boolean sensitive)
Definition: utils.c:4784
boolean get_clip_value(int which, lives_clip_details_t what, void *retval, size_t maxlen)
Definition: utils.c:5039
void lives_kill_subprocesses(const char *dirname, boolean kill_parent)
Definition: utils.c:4516
void switch_aud_to_none(boolean set_in_prefs)
Definition: utils.c:4001
char * repl_workdir(const char *entry, boolean fwd)
Definition: utils.c:3534
char * get_extension(const char *filename)
Definition: utils.c:3217
LIVES_GLOBAL_INLINE float LEFloat_to_BEFloat(float f)
Definition: utils.c:1750
boolean is_writeable_dir(const char *dir)
Definition: utils.c:5701
int free_n_msgs(int frval)
Definition: utils.c:2381
LIVES_GLOBAL_INLINE double calc_time_from_frame(int clip, int frame)
Definition: utils.c:1756
LIVES_GLOBAL_INLINE char * lives_pad(char *txt, size_t minlen, int align)
Definition: utils.c:3303
LIVES_GLOBAL_INLINE char * lives_pad_ellipsize(char *txt, size_t fixlen, int palign, LiVESEllipsizeMode emode)
Definition: utils.c:3333
boolean do_std_checks(const char *type_name, const char *type, size_t maxlen, const char *nreject)
Definition: utils.c:2929
char * lives_fgets(char *s, int size, FILE *stream)
Definition: utils.c:368
LIVES_GLOBAL_INLINE void d_print_enough(int frames)
Definition: utils.c:2630
LiVESList * get_set_list(const char *dir, boolean utf8)
Definition: utils.c:5305
int lives_cp(const char *from, const char *to)
Definition: utils.c:4414
LIVES_LOCAL_INLINE lives_presence_t has_executable(const char *exe)
Definition: utils.c:3421
void reset_playback_clock(void)
Definition: utils.c:1474
void lives_invalidate_all_file_buffers(void)
Definition: utils.c:557
LIVES_GLOBAL_INLINE const char * get_image_ext_for_type(lives_img_type_t imgtype)
Definition: utils.c:3025
boolean _lives_buffered_rdonly_slurp(int fd, off_t skip)
Definition: utils.c:641
int lives_rmglob(const char *files)
Definition: utils.c:4404
ssize_t lives_read_le(int fd, void *buf, ssize_t count, boolean allow_less)
Definition: utils.c:486
LIVES_GLOBAL_INLINE int lives_open2(const char *pathname, int flags)
Definition: utils.c:99
LIVES_GLOBAL_INLINE boolean lives_setenv(const char *name, const char *value)
Definition: utils.c:120
void update_play_times(void)
like get_play_times, but will force redraw of audio waveforms
Definition: utils.c:3677
ssize_t lives_buffered_write_printf(int fd, boolean allow_fail, const char *fmt,...)
Definition: utils.c:1316
LIVES_GLOBAL_INLINE lives_alarm_t lives_alarm_reset(lives_alarm_t alarm_handle, ticks_t ticks)
Definition: utils.c:1618
LIVES_GLOBAL_INLINE void d_print_done(void)
Definition: utils.c:2620
LIVES_GLOBAL_INLINE int calc_frame_from_time3(int filenum, double time)
nearest frame rounded down, [1, frames+1]
Definition: utils.c:1778
frames_t calc_new_playback_position(int fileno, ticks_t otc, ticks_t *ntc)
Definition: utils.c:1865
int lives_mv(const char *from, const char *to)
Definition: utils.c:4446
uint64_t make_version_hash(const char *ver)
Definition: utils.c:3500
LIVES_GLOBAL_INLINE char * lives_get_filename(char *uri)
return filename (no dir, no .ext)
Definition: utils.c:3214
char * ensure_extension(const char *fname, const char *ext)
Definition: utils.c:3232
lives_alarm_t lives_alarm_set(ticks_t ticks)
set alarm for now + delta ticks (10 nanosec) param ticks (10 nanoseconds) is the offset when we want ...
Definition: utils.c:1643
char * get_val_from_cached_list(const char *key, size_t maxlen, LiVESList *cache)
Definition: utils.c:4966
int lives_rmdir(const char *dir, boolean force)
Definition: utils.c:4366
LIVES_GLOBAL_INLINE LiVESInterpType get_interp_value(short quality, boolean low_for_mt)
Definition: utils.c:5744
boolean check_frame_count(int idx, boolean last_checked)
check number of frames is correct for files of type CLIP_TYPE_DISK
Definition: utils.c:3074
void get_location(const char *exe, char *val, int maxlen)
Definition: utils.c:3407
LIVES_GLOBAL_INLINE LiVESList * lives_list_sort_alpha(LiVESList *list, boolean fwd)
Definition: utils.c:5474
LIVES_GLOBAL_INLINE void get_basename(char *filename)
Definition: utils.c:3194
int lives_cp_recursive(const char *from, const char *to, boolean incl_dir)
Definition: utils.c:4423
boolean switch_aud_to_pulse(boolean set_in_prefs)
Definition: utils.c:3884
int lives_rm(const char *file)
Definition: utils.c:4395
LIVES_GLOBAL_INLINE int lives_killpg(lives_pgid_t pgrp, int sig)
Definition: utils.c:1432
ssize_t lives_read(int fd, void *buf, ssize_t count, boolean allow_less)
Definition: utils.c:460
LiVESList * cache_file_contents(const char *filename)
Definition: utils.c:4909
LIVES_GLOBAL_INLINE int lives_open3(const char *pathname, int flags, mode_t mode)
Definition: utils.c:94
lives_pgid_t lives_fork(const char *com)
Definition: utils.c:288
void remove_layout_files(LiVESList *map)
Definition: utils.c:3559
boolean after_foreign_play(void)
Definition: utils.c:4193
LIVES_GLOBAL_INLINE boolean lives_freep(void **ptr)
Definition: utils.c:1411
#define BL_LIM
Definition: utils.c:5754
boolean prepare_to_play_foreign(void)
Definition: utils.c:4055
off_t lives_buffered_offset(int fd)
Definition: utils.c:1364
LIVES_GLOBAL_INLINE boolean lives_buffered_rdonly_set_reversed(int fd, boolean val)
Definition: utils.c:681
LIVES_GLOBAL_INLINE int lives_kill(lives_pid_t pid, int sig)
Definition: utils.c:1423
char * filename_from_fd(char *val, int fd)
: return filename from an open fd, freeing val first
Definition: utils.c:60
char * subst(const char *xstring, const char *from, const char *to)
Definition: utils.c:5484
boolean check_for_lock_file(const char *set_name, int type)
check for set lock file do this via the back-end (smogrify) this allows for the locking scheme to be ...
Definition: utils.c:2894
LIVES_GLOBAL_INLINE char * make_image_file_name(lives_clip_t *sfile, frames_t frame, const char *img_ext)
lives_image_type can be a string, lives_img_type_t is an enumeration
Definition: utils.c:3053
void reset_clipmenu(void)
Definition: utils.c:4290
char * dump_messages(int start, int end)
Definition: utils.c:2338
int lives_list_strcmp_index(LiVESList *list, livesconstpointer data, boolean case_sensitive)
Definition: utils.c:4678
void print_cache(LiVESList *cache)
Definition: utils.c:4897
void d_print(const char *fmt,...)
Definition: utils.c:2542
int lives_open_buffered_writer(const char *pathname, int mode, boolean append)
Definition: utils.c:706
boolean check_dir_access(const char *dir, boolean leaveit)
Definition: utils.c:4542
LIVES_GLOBAL_INLINE void get_play_times(void)
recalculate video / audio lengths and draw the timer bars
Definition: utils.c:3672
LIVES_GLOBAL_INLINE void lives_list_free_all(LiVESList **list)
Definition: utils.c:4873
#define VER_MAJOR_MULT
Definition: utils.c:3496
boolean lives_string_ends_with(const char *string, const char *fmt,...)
Definition: utils.c:3143
int lives_cp_keep_perms(const char *from, const char *to)
Definition: utils.c:4437
int lives_echo(const char *text, const char *to, boolean append)
Definition: utils.c:4500
boolean check_for_executable(lives_checkstatus_t *cap, const char *exec)
Definition: utils.c:3434
lives_file_buffer_t * find_in_file_buffers(int fd)
Definition: utils.c:401
LIVES_GLOBAL_INLINE void lives_slist_free_all(LiVESSList **list)
Definition: utils.c:4865
void lives_buffered_rdonly_slurp(int fd, off_t skip)
Definition: utils.c:671
void activate_url_inner(const char *link)
Definition: utils.c:4607
LIVES_GLOBAL_INLINE ssize_t lives_readlink(const char *path, char *buf, size_t bufsiz)
Definition: utils.c:104
size_t lives_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
Definition: utils.c:379
uint64_t get_version_hash(const char *exe, const char *sep, int piece)
Definition: utils.c:3475
int verhash(char *xv)
Definition: utils.c:4755
weed_plant_t * get_nth_info_message(int n)
Definition: utils.c:2304
lives_file_buffer_t * find_in_file_buffers_by_pathname(const char *pathname)
Definition: utils.c:419
void unbuffer_lmap_errors(boolean add)
Definition: utils.c:2656
off_t lives_lseek_buffered_rdonly(int fd, off_t offset)
Definition: utils.c:895
void calc_midspect(int rwidth, int rheight, int *cwidth, int *cheight)
Definition: utils.c:2216
#define INITSIZE
Definition: utils.c:5482
off_t lives_lseek_buffered_rdonly_absolute(int fd, off_t offset)
Definition: utils.c:907
LIVES_GLOBAL_INLINE uint64_t lives_10pow(int pow)
Definition: utils.c:1438
ssize_t lives_write_le(int fd, const void *buf, ssize_t count, boolean allow_fail)
Definition: utils.c:350
uint32_t get_signed_endian(boolean is_signed, boolean little_endian)
produce bitmapped value
Definition: utils.c:5408
void calc_maxspect(int rwidth, int rheight, int *cwidth, int *cheight)
Definition: utils.c:2174
#define ASPECT_ALLOWANCE
Definition: utils.c:21
void buffer_lmap_error(lives_lmap_error_t lerror, const char *name, livespointer user_data, int clipno, int frameno, double atime, boolean affects_current)
Definition: utils.c:2640
boolean switch_aud_to_sox(boolean set_in_prefs)
Definition: utils.c:3944
boolean is_legal_set_name(const char *set_name, boolean allow_dupes, boolean leeway)
Definition: utils.c:2975
size_t lives_fread_string(char *buff, size_t stlen, const char *fname)
Definition: utils.c:388
void zero_spinbuttons(void)
Definition: utils.c:3807
char * get_dir(const char *filename)
Definition: utils.c:3185
void init_clipboard(void)
Definition: utils.c:2238
char * remove_trailing_zeroes(double val)
Definition: utils.c:5395
LIVES_GLOBAL_INLINE int calc_frame_from_time2(int filenum, double time)
nearest frame [1, frames+1]
Definition: utils.c:1768
void set_sel_label(LiVESWidget *sel_label)
Definition: utils.c:4838
int lives_ln(const char *from, const char *to)
Definition: utils.c:4464
#define O_DSYNC
Definition: utils.c:694
int lives_fputs(const char *s, FILE *stream)
Definition: utils.c:359
LIVES_GLOBAL_INLINE uint64_t get_approx_ln64(uint64_t x)
Definition: utils.c:1458
ticks_t lives_alarm_check(lives_alarm_t alarm_handle)
Definition: utils.c:1687
void show_manual_section(const char *lang, const char *section)
Definition: utils.c:4629
boolean get_frames_sizes(int fileno, int frame, int *hsize, int *vsize)
Definition: utils.c:3124
ticks_t lives_get_current_playback_ticks(int64_t origsecs, int64_t orignsecs, lives_time_source_t *time_source)
Definition: utils.c:1481
LIVES_GLOBAL_INLINE const char * image_ext_to_lives_image_type(const char *img_ext)
Definition: utils.c:3039
size_t get_read_buff_size(int sztype)
Definition: utils.c:771
int lives_rmdir_with_parents(const char *dir)
Definition: utils.c:4386
LIVES_GLOBAL_INLINE double lives_fix(double val, int decimals)
Definition: utils.c:1446
LIVES_GLOBAL_INLINE void cached_list_free(LiVESList **list)
Definition: utils.c:4881
const char * version(void)
#define TRUE
Definition: videoplugin.h:59
#define FALSE
Definition: videoplugin.h:60
#define ABS(a)
Definition: videoplugin.h:63
void lives_set_cursor_style(lives_cursor_t cstyle, LiVESWidget *widget)
WIDGET_HELPER_GLOBAL_INLINE void lives_menu_item_set_text(LiVESWidget *menuitem, const char *text, boolean use_mnemonic)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_buffer_get_end_iter(LiVESTextBuffer *tbuff, LiVESTextIter *iter)
WIDGET_HELPER_GLOBAL_INLINE int lives_widget_get_allocation_width(LiVESWidget *widget)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_set_value(LiVESSpinButton *button, double value)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_opacity(LiVESWidget *widget, double opacity)
WIDGET_HELPER_GLOBAL_INLINE const char * lives_menu_item_get_text(LiVESWidget *menuitem)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_buffer_get_start_iter(LiVESTextBuffer *tbuff, LiVESTextIter *iter)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_xwindow_set_keep_above(LiVESXWindow *xwin, boolean setting)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_signal_handler_unblock(livespointer instance, unsigned long handler_id)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_queue_draw(LiVESWidget *widget)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_sensitive(LiVESWidget *widget, boolean state)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_label_set_text(LiVESLabel *label, const char *text)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_signal_handler_block(livespointer instance, unsigned long handler_id)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_show(LiVESWidget *widget)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_adjustment_set_value(LiVESAdjustment *adj, double value)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_check_menu_item_set_active(LiVESCheckMenuItem *item, boolean state)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_buffer_insert(LiVESTextBuffer *tbuff, LiVESTextIter *iter, const char *text, int len)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_hide(LiVESWidget *widget)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_show_all(LiVESWidget *widget)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_buffer_delete(LiVESTextBuffer *tbuff, LiVESTextIter *start, LiVESTextIter *end)
WIDGET_HELPER_GLOBAL_INLINE double lives_adjustment_get_value(LiVESAdjustment *adj)
WIDGET_HELPER_GLOBAL_INLINE int lives_widget_get_allocation_height(LiVESWidget *widget)
WIDGET_HELPER_GLOBAL_INLINE LiVESTextMark * lives_text_buffer_create_mark(LiVESTextBuffer *tbuff, const char *mark_name, const LiVESTextIter *where, boolean left_gravity)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_process_updates(LiVESWidget *widget)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_queue_draw_if_visible(LiVESWidget *widget)
int lives_utf8_strcmpfunc(livesconstpointer a, livesconstpointer b, livespointer fwd)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_set_range(LiVESSpinButton *button, double min, double max)
LingoEllipsizeMode LiVESEllipsizeMode
@ LIVES_CURSOR_NORMAL
must be zero
@ LIVES_CURSOR_BUSY
#define LIVES_ELLIPSIZE_END
#define LIVES_ELLIPSIZE_MIDDLE
widget_opts_t widget_opts
#define LIVES_ELLIPSIZE_START