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 
23 typedef struct {
24  uint32_t hash;
25  char *key;
26  char *data;
27 } lives_speed_cache_t;
28 
29 static boolean omute, osepwin, ofs, ofaded, odouble;
30 
31 static int get_hex_digit(const char c) GNU_CONST;
32 
33 
60 char *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 
94 LIVES_GLOBAL_INLINE int lives_open3(const char *pathname, int flags, mode_t mode) {
95  return open(pathname, flags, mode);
96 }
97 
98 
99 LIVES_GLOBAL_INLINE int lives_open2(const char *pathname, int flags) {
100  return open(pathname, flags);
101 }
102 
103 
104 LIVES_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 
120 LIVES_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 
132 LIVES_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 
145 int 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 
194 ssize_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 
288 lives_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 
309 ssize_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 
350 ssize_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 
359 int 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 
368 char *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 
379 size_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 
388 size_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 
437 static 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 
460 ssize_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 
486 ssize_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 
534 static 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 
578 static 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 
619 static size_t bigbytes = BUFFER_FILL_BYTES_LARGE;
620 static size_t medbytes = BUFFER_FILL_BYTES_MED;
621 static size_t smedbytes = BUFFER_FILL_BYTES_SMALLMED;
622 static size_t smbytes = BUFFER_FILL_BYTES_SMALL;
623 #define AUTOTUNE
624 #ifdef AUTOTUNE
625 static weed_plant_t *tunerl = NULL;
626 static boolean tunedl = FALSE;
627 static weed_plant_t *tunerm = NULL;
628 static boolean tunedm = FALSE;
629 static weed_plant_t *tunersm = NULL;
630 static boolean tunedsm = FALSE;
631 static weed_plant_t *tuners = NULL;
632 static boolean tuneds = FALSE;
633 #endif
634 
635 
637  return lives_open_real_buffered(pathname, O_RDONLY, 0, TRUE);
638 }
639 
640 
641 boolean _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 
671 void 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;
677  lives_nanosleep_until_nonzero(fbuff->offset | fbuff->eof);
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 
698 LIVES_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 
702 LIVES_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 
706 int 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 
716 int lives_close_buffered(int fd) {
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 
771 size_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 
782 static 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 
845 static 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 
895 off_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 
907 off_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 
924 ssize_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 
1098 rd_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
1148 rd_exit:
1149  if (!allow_less && count > 0) {
1150  do_file_read_error(fd, retval, NULL, ocount);
1152  }
1153 
1154  return retval;
1155 }
1156 
1157 
1158 ssize_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 
1170 boolean lives_read_buffered_eof(int fd) {
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 
1186 static 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 
1226 ssize_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 
1316 ssize_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 
1329 ssize_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 
1338 off_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 
1364 off_t lives_buffered_offset(int fd) {
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 
1393 int 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);
1403  do_chdir_failed_error(path);
1404  } else LIVES_DEBUG(msg);
1405  lives_free(msg);
1406  }
1407  return retval;
1408 }
1409 
1410 
1411 LIVES_GLOBAL_INLINE boolean lives_freep(void **ptr) {
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 
1432 LIVES_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 
1446 LIVES_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 
1453 LIVES_GLOBAL_INLINE uint32_t get_approx_ln(uint32_t x) {
1454  x |= (x >> 1); x |= (x >> 2); x |= (x >> 4); x |= (x >> 8); x |= (x >> 16);
1455  return (++x) >> 1;
1456 }
1457 
1458 LIVES_GLOBAL_INLINE uint64_t get_approx_ln64(uint64_t x) {
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 
1463 LIVES_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 
1472 static ticks_t delta = 0;
1473 
1476  lastt = LIVES_TIME_SOURCE_NONE;
1477  delta = 0;
1478 }
1479 
1480 
1481 ticks_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) ||
1545  (prefs->audio_src == AUDIO_SRC_EXT && mainw->pulsed_read && mainw->pulsed_read->in_use))) {
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 
1732 boolean 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 
1756 LIVES_GLOBAL_INLINE double calc_time_from_frame(int clip, int frame) {return (frame - 1.) / mainw->files[clip]->fps;}
1757 
1758 
1759 LIVES_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 
1768 LIVES_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 
1778 LIVES_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 
1788 LIVES_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 
1797 static 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 
1845 void 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;
1898  lives_direction_t dir;
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 
1984  if (mainw->scratch == SCRATCH_FWD_EXTRA || mainw->scratch == SCRATCH_BACK_EXTRA) ddtc *= 4;
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
2069  if (mainw->whentostop == STOP_ON_VID_END) {
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
2148  if (mainw->whentostop == STOP_ON_AUD_END) {
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 
2174 void 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 
2195 void 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 
2216 void 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 
2238 void 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 
2304 weed_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 
2338 char *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 
2367 static 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 
2381 int 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 
2416 int 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 
2497 boolean 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 
2523 boolean 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 
2542 void 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 
2576  add_messages_to_list(text);
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) {
2585  msg_area_scroll_to_end(mainw->multitrack->msg_area, mainw->multitrack->msg_adj);
2587  } else {
2590  }
2591  }
2592 
2593  if ((mainw->current_file == -1 || (cfile && cfile->clip_type != CLIP_TYPE_GENERATOR)) &&
2595 }
2596 
2597 
2598 static 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 
2640 void 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 
2656 void 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 
2673 boolean 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);
2711  case LMAP_ERROR_CLOSE_FILE:
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;
2769  case LMAP_ERROR_CLOSE_FILE:
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 
2858 void clear_lmap_errors(void) {
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 
2866  lmap = mainw->affected_layouts_map;
2867 
2868  while (lmap) {
2869  lives_free((livespointer)lmap->data);
2870  lmap = lmap->next;
2871  }
2872  lives_list_free(lmap);
2873 
2874  mainw->affected_layouts_map = NULL;
2876  if (mainw->multitrack) lives_widget_set_sensitive(mainw->multitrack->show_layout_errors, FALSE);
2877 
2880  }
2881 }
2882 
2894 boolean 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 
2902  clear_mainw_msg();
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 
2929 boolean 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 
2975 boolean 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 
3039 LIVES_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;
3042  return LIVES_IMAGE_TYPE_UNKNOWN;
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 
3074 boolean 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 
3109 int 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,
3112  get_image_ext_for_type(mainw->files[idx]->img_type), start);
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 
3124 boolean 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,
3131  get_image_ext_for_type(sfile->img_type))) {
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 
3143 boolean 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 
3167 void 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 
3185 char *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 
3194 LIVES_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 
3205 LIVES_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 
3214 LIVES_GLOBAL_INLINE char *lives_get_filename(char *uri) {return lives_strstop(lives_path_get_basename(uri), '.');}
3215 
3216 
3217 char *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 
3232 char *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 
3262 LIVES_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) {
3281  case LIVES_ELLIPSIZE_END:
3282  lives_memcpy(retval, ellipsis, 3);
3283  lives_memcpy(retval + 3, txt + slen - maxlen, maxlen + 1);
3284  break;
3285  case LIVES_ELLIPSIZE_START:
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 
3303 LIVES_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 
3333 LIVES_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 
3346 boolean 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 
3390 boolean 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 
3407 void 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
3434 boolean 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
3471 return (*cap == PRESENT || *cap == LOCAL);
3472 }
3473 
3474 
3475 uint64_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 
3500 uint64_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 
3522 char *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 
3534 char *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 
3559 void 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
3610  if (!lives_strncmp(fname, prefs->workdir, lives_strlen(prefs->workdir))) {
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
3658  prefs->ar_layout = FALSE;
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 
3677 void update_play_times(void) {
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  }
3686  get_play_times();
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 
3722 void find_when_to_stop(void) {
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 
3750 void 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 
3807 void zero_spinbuttons(void) {
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 
3819 boolean 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 
3864  if (mainw->is_ready && mainw->vpp && mainw->vpp->get_audio_fmts)
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 
3884 boolean 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 
3944 boolean 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 
4001 void 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;
4184  mainw->double_size = FALSE;
4185 
4188 
4189  return TRUE;
4190 }
4191 
4192 
4193 boolean 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
4246  && CLIP_TOTAL_TIME(mainw->current_file) > cfile->laudio_time + AV_TRACK_MIN_DIFF) {
4247  pad_init_silence();
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 
4267  add_to_clipmenu();
4268  if (!mainw->multitrack) switch_to_file(old_file, mainw->current_file);
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 
4284 LIVES_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 
4290 void 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 
4312 boolean 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 
4366 int 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 
4386 int 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 
4395 int 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 
4404 int 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 
4414 int 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 
4423 int 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 
4437 int 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 
4446 int 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 
4455 int 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 
4464 int 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 
4475 int 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 
4484 int 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 
4500 int 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 
4516 void 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 
4527 void 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 
4542 boolean 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 
4607 void 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 
4624 void activate_url(LiVESAboutDialog * about, const char *link, livespointer data) {
4625  activate_url_inner(link);
4626 }
4627 
4628 
4629 void 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 
4644 void 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 
4660 boolean 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 
4678 int 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 
4701 void 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++) {
4718  mtext = lives_menu_item_get_text(mainw->recent[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]);
4729  if (mainw->multitrack) lives_menu_item_set_text(mainw->multitrack->recent[i], mtext, FALSE);
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 
4741  if (mainw->multitrack) lives_menu_item_set_text(mainw->multitrack->recent[0], mfile, FALSE);
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++) {
4747  mtext = lives_menu_item_get_text(mainw->recent[i]);
4748  if (*mtext) lives_widget_show(mainw->recent[i]);
4749  }
4750 
4751  lives_free(mfile); lives_free(file);
4752 }
4753 
4754 
4755 int 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
4784 void 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  }
4799  lives_menu_item_set_text(mainw->undo, cfile->undo_text, TRUE);
4800  lives_menu_item_set_text(mainw->redo, cfile->redo_text, TRUE);
4801  }
4802 
4805  lives_widget_set_sensitive(mainw->undo, sensitive);
4806 
4807 #ifdef PRODUCE_LOG
4808  lives_log(what);
4809 #endif
4810 }
4811 
4812 
4813 void 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  }
4828  lives_menu_item_set_text(mainw->undo, cfile->undo_text, TRUE);
4829  lives_menu_item_set_text(mainw->redo, cfile->redo_text, TRUE);
4830  }
4831 
4834  lives_widget_set_sensitive(mainw->redo, sensitive);
4835 }
4836 
4837 
4838 void 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 {
4845  tstr = lives_strdup_printf("%.2f", calc_time_from_frame(mainw->current_file, cfile->end + 1) -
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;
4875  lives_list_free_strings(*list);
4876  lives_list_free(*list);
4877  *list = NULL;
4878 }
4879 
4880 
4881 LIVES_GLOBAL_INLINE void cached_list_free(LiVESList **list) {
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 
4897 void 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 
4909 LiVESList *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 
4966 char *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 
4980 char *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;
4990  case CLIP_DETAILS_PB_FPS:
4991  key = lives_strdup("pb_fps"); break;
4992  case CLIP_DETAILS_WIDTH:
4993  key = lives_strdup("width"); break;
4994  case CLIP_DETAILS_HEIGHT:
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;
5000  case CLIP_DETAILS_PB_ARATE:
5001  key = lives_strdup("pb_audio_rate"); break;
5002  case CLIP_DETAILS_ACHANS:
5003  key = lives_strdup("audio_channels"); break;
5004  case CLIP_DETAILS_ASIGNED:
5005  key = lives_strdup("audio_signed"); break;
5006  case CLIP_DETAILS_AENDIAN:
5007  key = lives_strdup("audio_endian"); break;
5008  case CLIP_DETAILS_ASAMPS:
5009  key = lives_strdup("audio_sample_size"); break;
5010  case CLIP_DETAILS_FRAMES:
5011  key = lives_strdup("frames"); break;
5012  case CLIP_DETAILS_TITLE:
5013  key = lives_strdup("title"); break;
5014  case CLIP_DETAILS_AUTHOR:
5015  key = lives_strdup("author"); break;
5016  case CLIP_DETAILS_COMMENT:
5017  key = lives_strdup("comment"); break;
5018  case CLIP_DETAILS_KEYWORDS:
5019  key = lives_strdup("keywords"); break;
5021  key = lives_strdup("pb_frameno"); break;
5022  case CLIP_DETAILS_CLIPNAME:
5023  key = lives_strdup("clipname"); break;
5024  case CLIP_DETAILS_FILENAME:
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 
5039 boolean 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);
5068  sfile->checked_for_old_header = TRUE;
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:
5113  case CLIP_DETAILS_HEIGHT:
5114  case CLIP_DETAILS_ARATE:
5115  case CLIP_DETAILS_ACHANS:
5116  case CLIP_DETAILS_ASAMPS:
5117  case CLIP_DETAILS_FRAMES:
5120  *(int *)retval = atoi(val); break;
5121  case CLIP_DETAILS_ASIGNED:
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;
5130  case CLIP_DETAILS_PB_ARATE:
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;
5141  case CLIP_DETAILS_PB_FPS:
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;
5152  case CLIP_DETAILS_AENDIAN:
5153  *(int *)retval = atoi(val) * 2; break;
5154  case CLIP_DETAILS_TITLE:
5155  case CLIP_DETAILS_AUTHOR:
5156  case CLIP_DETAILS_COMMENT:
5157  case CLIP_DETAILS_CLIPNAME:
5158  case CLIP_DETAILS_KEYWORDS:
5159  lives_snprintf((char *)retval, maxlen, "%s", val);
5160  break;
5161  case CLIP_DETAILS_FILENAME:
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 
5175 boolean 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;
5218  case CLIP_DETAILS_PB_FPS:
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;
5225  case CLIP_DETAILS_HEIGHT:
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;
5231  case CLIP_DETAILS_PB_ARATE:
5232  myval = lives_strdup_printf("%d", *(int *)val); break;
5233  case CLIP_DETAILS_ACHANS:
5234  myval = lives_strdup_printf("%d", *(int *)val); break;
5235  case CLIP_DETAILS_ASIGNED:
5236  if ((*(int *)val) == 1) myval = lives_strdup("true");
5237  else myval = lives_strdup("false");
5238  break;
5239  case CLIP_DETAILS_AENDIAN:
5240  myval = lives_strdup_printf("%d", (*(int *)val) / 2);
5241  break;
5242  case CLIP_DETAILS_ASAMPS:
5243  myval = lives_strdup_printf("%d", *(int *)val); break;
5244  case CLIP_DETAILS_FRAMES:
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;
5252  case CLIP_DETAILS_AUTHOR:
5253  myval = lives_strdup((char *)val); break;
5254  case CLIP_DETAILS_COMMENT:
5255  myval = lives_strdup((const char *)val); break;
5256  case CLIP_DETAILS_KEYWORDS:
5257  myval = lives_strdup((const char *)val); break;
5259  myval = lives_strdup_printf("%d", *(int *)val); break;
5260  case CLIP_DETAILS_CLIPNAME:
5261  myval = lives_strdup((char *)val); break;
5262  case CLIP_DETAILS_FILENAME:
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 
5305 LiVESList *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 
5361 boolean 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 
5379 double 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 
5395 char *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 
5408 uint32_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 
5430 size_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 
5443 char *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 
5458 int 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 
5469 LIVES_GLOBAL_INLINE int lives_utf8_strcmp(const char *s1, const char *s2) {
5470  return lives_utf8_collate(s1, s2);
5471 }
5472 
5473 
5474 LIVES_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 
5484 char *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 
5591 char *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 
5681 static 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 
5694 LIVES_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 
5701 boolean 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 
5721 boolean 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 
5744 LIVES_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
5755 LIVES_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 
5776 LIVES_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 
5789 LIVES_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 
5801 LiVESList *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 
5820 LIVES_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 
5831 boolean 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 
d_print_done
LIVES_GLOBAL_INLINE void d_print_done(void)
Definition: utils.c:2620
CLIP_DETAILS_TITLE
@ CLIP_DETAILS_TITLE
Definition: main.h:1155
LIVES_DEBUG
#define LIVES_DEBUG(x)
Definition: main.h:1848
lmap_error::data
livespointer data
Definition: multitrack.h:1035
mainwindow::foreign_width
int foreign_width
Definition: mainwindow.h:844
lives_format_storage_space_string
char * lives_format_storage_space_string(uint64_t space)
Definition: machinestate.c:664
lives_system
int lives_system(const char *com, boolean allow_error)
Definition: utils.c:145
LIVES_GLOBAL_INLINE
#define LIVES_GLOBAL_INLINE
Definition: main.h:239
mainwindow::layout_textbuffer
LiVESTextBuffer * layout_textbuffer
stores layout errors
Definition: mainwindow.h:1468
mainwindow::jackd
void * jackd
jack audio player / transport
Definition: mainwindow.h:1453
AFORM_UNSIGNED
#define AFORM_UNSIGNED
Definition: main.h:786
_prefs::max_messages
int max_messages
Definition: preferences.h:444
lives_xwindow_set_keep_above
WIDGET_HELPER_GLOBAL_INLINE boolean lives_xwindow_set_keep_above(LiVESXWindow *xwin, boolean setting)
Definition: widget-helper.c:4780
lives_cp_recursive
int lives_cp_recursive(const char *from, const char *to, boolean incl_dir)
Definition: utils.c:4423
lives_adjustment_set_value
WIDGET_HELPER_GLOBAL_INLINE boolean lives_adjustment_set_value(LiVESAdjustment *adj, double value)
Definition: widget-helper.c:5636
lives_file_buffer_t::ptr
uint8_t * ptr
buffer size for write, bytes left to read in case of read
Definition: main.h:1606
lives_spin_button_set_range
WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_set_range(LiVESSpinButton *button, double min, double max)
Definition: widget-helper.c:5129
get_set_list
LiVESList * get_set_list(const char *dir, boolean utf8)
Definition: utils.c:5305
INITSIZE
#define INITSIZE
Definition: utils.c:5482
do_std_checks
boolean do_std_checks(const char *type_name, const char *type, size_t maxlen, const char *nreject)
Definition: utils.c:2929
CLIP_DETAILS_HEADER_VERSION
@ CLIP_DETAILS_HEADER_VERSION
Definition: main.h:1161
calc_aframeno
void calc_aframeno(int fileno)
Definition: utils.c:1845
lives_clip_t::header_version
int header_version
Definition: main.h:940
lives_check_menu_item_set_active
WIDGET_HELPER_GLOBAL_INLINE boolean lives_check_menu_item_set_active(LiVESCheckMenuItem *item, boolean state)
Definition: widget-helper.c:6537
LIVES_IS_PLAYING
#define LIVES_IS_PLAYING
Definition: main.h:840
LIVES_LOCAL_INLINE
#define LIVES_LOCAL_INLINE
Definition: main.h:246
LMAP_ERROR_CLOSE_FILE
@ LMAP_ERROR_CLOSE_FILE
Definition: multitrack.h:1018
LIVES_CLIP_HEADER_OLD
#define LIVES_CLIP_HEADER_OLD
Definition: mainwindow.h:559
mainwindow::m_mutebutton
LiVESWidget * m_mutebutton
Definition: mainwindow.h:1370
get_nth_token
char * get_nth_token(const char *string, const char *delim, int pnumber)
Definition: utils.c:5443
after_foreign_play
boolean after_foreign_play(void)
Definition: utils.c:4193
mainwindow::fixed_fpsd
double fixed_fpsd
<=0. means free playback
Definition: mainwindow.h:990
lives_img_type_t
lives_img_type_t
Definition: main.h:774
O_DSYNC
#define O_DSYNC
Definition: utils.c:694
mainwindow::recent
LiVESWidget * recent[N_RECENT_FILES]
Definition: mainwindow.h:1129
PRId64
#define PRId64
Definition: machinestate.h:169
minimise_aspect_delta
void minimise_aspect_delta(double aspect, int hblock, int vblock, int hsize, int vsize, int *width, int *height)
Definition: utils.c:3750
lives_file_buffer_t::totbytes
int64_t totbytes
Definition: main.h:1617
JACK_OPTS_NOPLAY_WHEN_PAUSED
#define JACK_OPTS_NOPLAY_WHEN_PAUSED
play audio even when transport paused
Definition: preferences.h:236
ensure_isdir
boolean ensure_isdir(char *fname)
Definition: utils.c:3346
lives_free
#define lives_free
Definition: machinestate.h:52
resolve_img_type
lives_img_type_t resolve_img_type(lives_clip_t *sfile)
Definition: cvirtual.c:275
lives_clip_t::aseek_pos
volatile off64_t aseek_pos
audio seek posn. (bytes) for when we switch clips
Definition: main.h:1064
LIVES_WARN
#define LIVES_WARN(x)
Definition: main.h:1862
BUFF_SIZE_WRITE_SMALLMED
#define BUFF_SIZE_WRITE_SMALLMED
Definition: main.h:1599
mainwindow::rec_samples
int64_t rec_samples
Definition: mainwindow.h:1527
mainwindow::playarea
LiVESWidget * playarea
Definition: mainwindow.h:1321
lives_malloc
#define lives_malloc
Definition: machinestate.h:46
lives_file_buffer_t::bufsztype
int bufsztype
Definition: main.h:1610
mainwindow::is_ready
boolean is_ready
Definition: mainwindow.h:787
PREF_REC_EXT_AUDIO
#define PREF_REC_EXT_AUDIO
Definition: preferences.h:892
LIVES_CURSOR_NORMAL
@ LIVES_CURSOR_NORMAL
must be zero
Definition: widget-helper.h:1292
lives_utf8_strcmpfunc
int lives_utf8_strcmpfunc(livesconstpointer a, livesconstpointer b, livespointer fwd)
Definition: widget-helper.c:11025
lmap_error::atime
double atime
Definition: multitrack.h:1037
mainwindow::record
volatile boolean record
Definition: mainwindow.h:794
LIVES_ELLIPSIZE_END
#define LIVES_ELLIPSIZE_END
Definition: widget-helper.h:114
capability::cpu_bits
short cpu_bits
Definition: main.h:583
is_writeable_dir
boolean is_writeable_dir(const char *dir)
Definition: utils.c:5701
lives_create_buffered_nosync
LIVES_GLOBAL_INLINE int lives_create_buffered_nosync(const char *pathname, int mode)
Definition: utils.c:702
mainwindow::mgeom
lives_mgeometry_t * mgeom
multi-head support
Definition: mainwindow.h:1576
do_progress_dialog
boolean do_progress_dialog(boolean visible, boolean cancellable, const char *text)
Definition: dialogs.c:2274
lives_get_audio_file_name
LIVES_GLOBAL_INLINE char * lives_get_audio_file_name(int fnum)
Definition: audio.c:55
get_filename
LIVES_GLOBAL_INLINE void get_filename(char *filename, boolean strip_dir)
Definition: utils.c:3205
get_extension
char * get_extension(const char *filename)
Definition: utils.c:3217
do_yesno_dialogf
boolean do_yesno_dialogf(const char *fmt,...)
Definition: dialogs.c:635
mainwindow::foreign_visual
char * foreign_visual
Definition: mainwindow.h:846
break_me
void break_me(const char *brkstr)
Definition: main.c:159
get_interp_value
LIVES_GLOBAL_INLINE LiVESInterpType get_interp_value(short quality, boolean low_for_mt)
Definition: utils.c:5744
get_val_from_cached_list
char * get_val_from_cached_list(const char *key, size_t maxlen, LiVESList *cache)
Definition: utils.c:4966
WEED_LEAF_HOST_FLAGS
#define WEED_LEAF_HOST_FLAGS
Definition: colourspace.h:24
mainwindow::redo
LiVESWidget * redo
Definition: mainwindow.h:1147
mainwindow::file_buffers
LiVESList * file_buffers
list of open files for buffered i/o
Definition: mainwindow.h:1523
add_to_recent
void add_to_recent(const char *filename, double start, frames_t frames, const char *extra_params)
Definition: utils.c:4701
prepare_to_play_foreign
boolean prepare_to_play_foreign(void)
Definition: utils.c:4055
USEC_TO_TICKS
#define USEC_TO_TICKS
multiplying factor uSec -> ticks_t (def. 100)
Definition: mainwindow.h:38
mainwindow::loop
boolean loop
Definition: mainwindow.h:763
lives_set_cursor_style
void lives_set_cursor_style(lives_cursor_t cstyle, LiVESWidget *widget)
Definition: widget-helper.c:11950
weed_layer_new
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_new(int layer_type)
Definition: colourspace.c:9655
_prefs::workdir
char workdir[PATH_MAX]
kept in locale encoding
Definition: preferences.h:61
lmap_error::type
lives_lmap_error_t type
Definition: multitrack.h:1033
lives_unsetenv
LIVES_GLOBAL_INLINE boolean lives_unsetenv(const char *name)
Definition: utils.c:132
lives_spin_button_set_value
WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_set_value(LiVESSpinButton *button, double value)
Definition: widget-helper.c:5119
mainwindow::p_mutebutton
LiVESWidget * p_mutebutton
Definition: mainwindow.h:1379
version
const char * version(void)
_prefs::show_gui
boolean show_gui
Definition: preferences.h:290
wait_for_bg_audio_sync
void wait_for_bg_audio_sync(int fileno)
Definition: utils.c:4644
calc_new_playback_position
frames_t calc_new_playback_position(int fileno, ticks_t otc, ticks_t *ntc)
Definition: utils.c:1865
lives_image_type_to_img_type
LIVES_GLOBAL_INLINE lives_img_type_t lives_image_type_to_img_type(const char *lives_img_type)
Definition: utils.c:3046
_prefs::jack_opts
uint32_t jack_opts
Definition: preferences.h:232
mainwindow::is_exiting
volatile boolean is_exiting
set during shutdown (inverse of only_close then)
Definition: mainwindow.h:1440
BUFFER_FILL_BYTES_LARGE
#define BUFFER_FILL_BYTES_LARGE
Definition: main.h:1590
mainwindow::current_file
int current_file
Definition: mainwindow.h:727
IS_VALID_CLIP
#define IS_VALID_CLIP(clip)
Definition: main.h:808
lives_clip_details_t
lives_clip_details_t
Definition: main.h:1141
_prefs::crash_recovery
boolean crash_recovery
TRUE==maintain mainw->recovery file.
Definition: preferences.h:259
get_frames_sizes
boolean get_frames_sizes(int fileno, int frame, int *hsize, int *vsize)
Definition: utils.c:3124
mainwindow::vpp
_vid_playback_plugin * vpp
video plugin
Definition: mainwindow.h:1572
do_file_perm_error
LiVESResponseType do_file_perm_error(const char *file_name, boolean allow_cancel)
Definition: dialogs.c:4226
repl_workdir
char * repl_workdir(const char *entry, boolean fwd)
Definition: utils.c:3534
LIVES_IMAGE_TYPE_UNKNOWN
#define LIVES_IMAGE_TYPE_UNKNOWN
Definition: mainwindow.h:478
mainwindow::alives_pgid
lives_pgid_t alives_pgid
Definition: mainwindow.h:877
lives_clip_t::ext_src
void * ext_src
points to opaque source for non-disk types
Definition: main.h:1040
_prefs::show_overlay_msgs
boolean show_overlay_msgs
Definition: preferences.h:311
cfile
#define cfile
Definition: main.h:1833
mainwindow::preview
boolean preview
Definition: mainwindow.h:757
lives_widget_hide
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_hide(LiVESWidget *widget)
Definition: widget-helper.c:1514
lives_clip_t::start
frames_t start
Definition: main.h:891
count_resampled_frames
int count_resampled_frames(int in_frames, double orig_fps, double resampled_fps)
Definition: resample.c:72
CLIP_DETAILS_COMMENT
@ CLIP_DETAILS_COMMENT
Definition: main.h:1157
mainwindow::spin_end_func
ulong spin_end_func
Definition: mainwindow.h:1065
d_print_urgency
boolean d_print_urgency(double timeout, const char *fmt,...)
Definition: utils.c:2497
mainwindow::vol_label
LiVESWidget * vol_label
Definition: mainwindow.h:1365
mainwindow::rec_asamps
int rec_asamps
Definition: mainwindow.h:1532
PRESENT
@ PRESENT
Definition: main.h:394
_prefs::bigendbug
int bigendbug
default 0; 1==use old (bad) behaviour on bigendian machines (r/w bigend ints/doubles); 2==bad reads,...
Definition: preferences.h:374
do_set_locked_warning
LIVES_GLOBAL_INLINE boolean do_set_locked_warning(const char *setname)
Definition: dialogs.c:4357
LIVES_OSC_NOTIFY_NONE
#define LIVES_OSC_NOTIFY_NONE
Definition: osc_notify.h:31
lives_read
ssize_t lives_read(int fd, void *buf, ssize_t count, boolean allow_less)
Definition: utils.c:460
WORKDIR_LITERAL
#define WORKDIR_LITERAL
Definition: mainwindow.h:540
mainwindow::foreign_height
int foreign_height
Definition: mainwindow.h:844
AUDIO_PLAYER_NONE
#define AUDIO_PLAYER_NONE
Definition: preferences.h:47
BUFFER_FILL_BYTES_BIGMED
#define BUFFER_FILL_BYTES_BIGMED
Definition: main.h:1589
VER_MAJOR_MULT
#define VER_MAJOR_MULT
Definition: utils.c:3496
weed_layer_get_width
LIVES_GLOBAL_INLINE int weed_layer_get_width(weed_layer_t *layer)
Definition: colourspace.c:13941
LIVES_WEED_SUBTYPE_MESSAGE
#define LIVES_WEED_SUBTYPE_MESSAGE
Definition: machinestate.h:201
d_print_failed
LIVES_GLOBAL_INLINE void d_print_failed(void)
Definition: utils.c:2615
mainwindow::clip_switched
boolean clip_switched
for recording - did we switch clips ?
Definition: mainwindow.h:793
LIVES_ERROR
#define LIVES_ERROR(x)
Definition: main.h:1870
lives_clip_t::frames
frames_t frames
number of video frames
Definition: main.h:890
SCRATCH_FWD
#define SCRATCH_FWD
Definition: mainwindow.h:1029
IGN_RET
#define IGN_RET(a)
Definition: main.h:378
lives_presence_t
lives_presence_t
Definition: main.h:391
check_frame_count
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
mainwindow::foreign_bpp
int foreign_bpp
Definition: mainwindow.h:845
cvirtual.h
lives_label_set_text
WIDGET_HELPER_GLOBAL_INLINE boolean lives_label_set_text(LiVESLabel *label, const char *text)
Definition: widget-helper.c:6064
lives_timeout_t::tleft
ticks_t tleft
Definition: mainwindow.h:692
CLIP_DETAILS_ACHANS
@ CLIP_DETAILS_ACHANS
Definition: main.h:1150
mainwindow::play_window
LiVESWidget * play_window
Definition: mainwindow.h:947
LIVES_MANUAL_FILENAME
#define LIVES_MANUAL_FILENAME
Definition: mainwindow.h:522
LIVES_LAYER_GET_SIZE_ONLY
#define LIVES_LAYER_GET_SIZE_ONLY
Definition: colourspace.h:260
prefs
_prefs * prefs
Definition: preferences.h:847
lives_strcmp
LIVES_GLOBAL_INLINE boolean lives_strcmp(const char *st1, const char *st2)
returns FALSE if strings match
Definition: machinestate.c:1506
lives_read_buffered_eof
boolean lives_read_buffered_eof(int fd)
Definition: utils.c:1170
_prefs::backend
char backend[PATH_MAX *4]
Definition: preferences.h:411
get_image_ext_for_type
LIVES_GLOBAL_INLINE const char * get_image_ext_for_type(lives_img_type_t imgtype)
Definition: utils.c:3025
_prefs::audio_player
short audio_player
Definition: preferences.h:40
mainwindow::video_seek_ready
volatile boolean video_seek_ready
Definition: mainwindow.h:939
lmap_error::name
char * name
Definition: multitrack.h:1034
CLIP_DETAILS_WIDTH
@ CLIP_DETAILS_WIDTH
Definition: main.h:1145
capability::ln_cmd
char ln_cmd[PATH_MAX]
Definition: main.h:557
JACK_OPTS_TRANSPORT_CLIENT
#define JACK_OPTS_TRANSPORT_CLIENT
jack can start/stop
Definition: preferences.h:233
lives_fsync
LIVES_GLOBAL_INLINE boolean lives_fsync(int fd)
Definition: utils.c:109
LIVES_FILE_EXT_JPG
#define LIVES_FILE_EXT_JPG
Definition: mainwindow.h:488
pad_init_silence
void pad_init_silence(void)
Definition: saveplay.c:293
LMAP_ERROR_ALTER_AUDIO
@ LMAP_ERROR_ALTER_AUDIO
Definition: multitrack.h:1026
capability::cat_cmd
char cat_cmd[PATH_MAX]
Definition: main.h:559
get_best_audio
int64_t get_best_audio(_vid_playback_plugin *vpp)
Definition: plugins.c:1441
string_lists_differ
boolean string_lists_differ(LiVESList *alist, LiVESList *blist)
Definition: utils.c:5831
LIVES_DIRECTION_PAR
#define LIVES_DIRECTION_PAR(dir)
Definition: main.h:865
BUFFER_FILL_BYTES_MED
#define BUFFER_FILL_BYTES_MED
Definition: main.h:1588
d_print_file_error_failed
LIVES_GLOBAL_INLINE void d_print_file_error_failed(void)
Definition: utils.c:2625
VER_MICRO_MULT
#define VER_MICRO_MULT
Definition: utils.c:3498
WORKDIR_LITERAL_LEN
#define WORKDIR_LITERAL_LEN
Definition: mainwindow.h:541
d_print_cancelled
LIVES_GLOBAL_INLINE void d_print_cancelled(void)
Definition: utils.c:2610
mainwindow::foreign_id
Window foreign_id
Definition: mainwindow.h:840
mainwindow::loop_video
LiVESWidget * loop_video
Definition: mainwindow.h:1173
get_approx_ln64
LIVES_GLOBAL_INLINE uint64_t get_approx_ln64(uint64_t x)
Definition: utils.c:1458
lives_file_buffer_t::allow_fail
boolean allow_fail
Definition: main.h:1618
LIVES_STRING_CONSTANT_CL
@ LIVES_STRING_CONSTANT_CL
"the current layout"
Definition: mainwindow.h:374
CLIP_DETAILS_KEYWORDS
@ CLIP_DETAILS_KEYWORDS
Definition: main.h:1162
LIVES_DIRECTION_FORWARD
@ LIVES_DIRECTION_FORWARD
Definition: main.h:854
lives_text_buffer_insert
WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_buffer_insert(LiVESTextBuffer *tbuff, LiVESTextIter *iter, const char *text, int len)
Definition: widget-helper.c:4035
_prefs::rec_opts
int rec_opts
Definition: preferences.h:196
_prefs::show_msg_area
boolean show_msg_area
Definition: preferences.h:225
lives_rmdir
int lives_rmdir(const char *dir, boolean force)
Definition: utils.c:4366
LMAP_ERROR_SHIFT_AUDIO
@ LMAP_ERROR_SHIFT_AUDIO
Definition: multitrack.h:1025
mainwindow::alarmlist_mutex
pthread_mutex_t alarmlist_mutex
append / remove with file_buffer list
Definition: mainwindow.h:1507
KEY_RPT_INTERVAL
#define KEY_RPT_INTERVAL
Definition: keyboard.h:76
remove_trailing_zeroes
char * remove_trailing_zeroes(double val)
Definition: utils.c:5395
ensure_extension
char * ensure_extension(const char *fname, const char *ext)
Definition: utils.c:3232
lives_echo
int lives_echo(const char *text, const char *to, boolean append)
Definition: utils.c:4500
frames64_t
int64_t frames64_t
Definition: main.h:100
_prefs::backend_sync
char backend_sync[PATH_MAX *4]
Definition: preferences.h:410
mainwindow::mute_audio
LiVESWidget * mute_audio
Definition: mainwindow.h:1177
TICKS_PER_SECOND_DBL
#define TICKS_PER_SECOND_DBL
actually microseconds / 100.
Definition: mainwindow.h:37
lives_open_buffered_writer
int lives_open_buffered_writer(const char *pathname, int mode, boolean append)
Definition: utils.c:706
lives_buffered_orig_size
size_t lives_buffered_orig_size(int fd)
Definition: utils.c:1377
lives_file_buffer_t::reversed
boolean reversed
Definition: main.h:1613
mt_init_clips
void mt_init_clips(lives_mt *mt, int orig_file, boolean add)
Definition: multitrack.c:10859
free_n_msgs
int free_n_msgs(int frval)
Definition: utils.c:2381
weed_layer_get_height
LIVES_GLOBAL_INLINE int weed_layer_get_height(weed_layer_t *layer)
Definition: colourspace.c:13953
EXEC_PLAY
#define EXEC_PLAY
Definition: mainwindow.h:428
AUD_PLAYER_NONE
#define AUD_PLAYER_NONE
Definition: preferences.h:41
mainwindow::osc_auto
int osc_auto
bypass user choices automatically
Definition: mainwindow.h:918
_prefs::aplayer
char aplayer[512]
Definition: preferences.h:54
lives_lseek_buffered_writer
off_t lives_lseek_buffered_writer(int fd, off_t offset)
Definition: utils.c:1338
CLIP_TYPE_GENERATOR
@ CLIP_TYPE_GENERATOR
frames from generator plugin
Definition: main.h:766
add_to_clipmenu
void add_to_clipmenu(void)
Definition: gui.c:4512
lives_lmap_error_t
lives_lmap_error_t
Definition: multitrack.h:1015
capability::mainpid
pid_t mainpid
Definition: main.h:591
lives_write_buffered
ssize_t lives_write_buffered(int fd, const char *buf, ssize_t count, boolean allow_fail)
Definition: utils.c:1226
BUFF_SIZE_READ_MED
#define BUFF_SIZE_READ_MED
Definition: main.h:1594
TICKS_PER_SECOND
#define TICKS_PER_SECOND
ticks per second - GLOBAL TIMEBASE
Definition: mainwindow.h:36
lives_cat
int lives_cat(const char *from, const char *to, boolean append)
Definition: utils.c:4484
do_chdir_failed_error
void do_chdir_failed_error(const char *dir)
Definition: dialogs.c:4213
lives_widget_queue_draw
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_queue_draw(LiVESWidget *widget)
Definition: widget-helper.c:1580
mainwindow::agen_needs_reinit
volatile boolean agen_needs_reinit
Definition: mainwindow.h:1650
lives_file_buffer_t
Definition: main.h:1604
ABS
#define ABS(a)
Definition: videoplugin.h:63
CLIP_DETAILS_ASAMPS
@ CLIP_DETAILS_ASAMPS
Definition: main.h:1153
lives_freep
LIVES_GLOBAL_INLINE boolean lives_freep(void **ptr)
Definition: utils.c:1411
mainwindow::cadjticks
ticks_t cadjticks
used to equalise the timecode between alternate timer sources (clock -> source adjustment)
Definition: mainwindow.h:1008
mainwindow::show_layout_errors
LiVESWidget * show_layout_errors
Definition: mainwindow.h:1225
remove_current_from_affected_layouts
void remove_current_from_affected_layouts(lives_mt *mt)
Definition: multitrack.c:5851
LIVES_TIME_SOURCE_SYSTEM
@ LIVES_TIME_SOURCE_SYSTEM
Definition: mainwindow.h:227
lives_alarm_t
int lives_alarm_t
Definition: mainwindow.h:696
lives_nanosleep
#define lives_nanosleep(nanosec)
Definition: machinestate.h:307
q_gint64_floor
LIVES_GLOBAL_INLINE ticks_t q_gint64_floor(ticks_t in, double fps)
Definition: resample.c:35
RECA_MONITOR
@ RECA_MONITOR
Definition: audio.h:196
mainwindow::event_list
weed_event_t * event_list
current event_list, for recording
Definition: mainwindow.h:803
CLIP_DETAILS_AUTHOR
@ CLIP_DETAILS_AUTHOR
Definition: main.h:1156
LIVES_ELLIPSIZE_MIDDLE
#define LIVES_ELLIPSIZE_MIDDLE
Definition: widget-helper.h:113
mainwindow::playframe
LiVESWidget * playframe
Definition: mainwindow.h:1098
mainwindow::sl_undo_mem
unsigned char * sl_undo_mem
Definition: mainwindow.h:812
ticks_t
int64_t ticks_t
Definition: main.h:97
LIVES_MANUAL_URL
#define LIVES_MANUAL_URL
Definition: mainwindow.h:521
get_location
void get_location(const char *exe, char *val, int maxlen)
Definition: utils.c:3407
mainwindow::ref_message
weed_plant_t * ref_message
Definition: mainwindow.h:1730
CLIP_DETAILS_FRAMES
@ CLIP_DETAILS_FRAMES
Definition: main.h:1154
CLIP_DETAILS_AENDIAN
@ CLIP_DETAILS_AENDIAN
Definition: main.h:1152
show_manual_section
void show_manual_section(const char *lang, const char *section)
Definition: utils.c:4629
IMG_TYPE_BEST
#define IMG_TYPE_BEST
Definition: main.h:781
JACK_OPTS_TIMEBASE_CLIENT
#define JACK_OPTS_TIMEBASE_CLIENT
full timebase client
Definition: preferences.h:239
BUFF_SIZE_READ_SMALLMED
#define BUFF_SIZE_READ_SMALLMED
Definition: main.h:1593
do_error_dialog
LIVES_GLOBAL_INLINE LiVESResponseType do_error_dialog(const char *text)
Definition: dialogs.c:749
mainwindow::set_name
char set_name[256]
Definition: mainwindow.h:749
BUFF_SIZE_READ_SMALL
#define BUFF_SIZE_READ_SMALL
Definition: main.h:1592
WEED_LAYER_TYPE_VIDEO
#define WEED_LAYER_TYPE_VIDEO
Definition: colourspace.h:221
lives_create_buffered
LIVES_GLOBAL_INLINE int lives_create_buffered(const char *pathname, int mode)
Definition: utils.c:698
lives_pad
LIVES_GLOBAL_INLINE char * lives_pad(char *txt, size_t minlen, int align)
Definition: utils.c:3303
LIVES_SHORTEST_TIMEOUT
#define LIVES_SHORTEST_TIMEOUT
Definition: mainwindow.h:41
end_threaded_dialog
void end_threaded_dialog(void)
Definition: dialogs.c:3883
threaded_dialog_spin
void threaded_dialog_spin(double fraction)
Definition: dialogs.c:3823
mainwindow::next_free_alarm
int next_free_alarm
Definition: mainwindow.h:1640
TEMPFILE_MARKER
#define TEMPFILE_MARKER
Definition: mainwindow.h:574
_prefs::warning_mask
uint64_t warning_mask
Definition: preferences.h:80
CLIP_DETAILS_ASIGNED
@ CLIP_DETAILS_ASIGNED
Definition: main.h:1151
TRUE
#define TRUE
Definition: videoplugin.h:59
lives_clip_t::img_type
lives_img_type_t img_type
Definition: main.h:887
check_for_executable
boolean check_for_executable(lives_checkstatus_t *cap, const char *exec)
Definition: utils.c:3434
CLIP_DETAILS_FILENAME
@ CLIP_DETAILS_FILENAME
Definition: main.h:1159
mainwindow::pheight
int pheight
playback height
Definition: mainwindow.h:927
lives_fork
lives_pgid_t lives_fork(const char *com)
Definition: utils.c:288
CLIP_TYPE_DISK
@ CLIP_TYPE_DISK
imported video, broken into frames
Definition: main.h:764
mainwindow::spin_start_func
ulong spin_start_func
Definition: mainwindow.h:1064
capability::umask
mode_t umask
Definition: main.h:597
mainwindow::string_constants
char * string_constants[NUM_LIVES_STRING_CONSTANTS]
Definition: mainwindow.h:1539
lives_rmdir_with_parents
int lives_rmdir_with_parents(const char *dir)
Definition: utils.c:4386
IMG_TYPE_PNG
@ IMG_TYPE_PNG
Definition: main.h:777
capability::touch_cmd
char touch_cmd[PATH_MAX]
Definition: main.h:553
LIVES_TIME_SOURCE_EXTERNAL
@ LIVES_TIME_SOURCE_EXTERNAL
Definition: mainwindow.h:229
lives_pid_t
pid_t lives_pid_t
Definition: main.h:117
lives_list_sort_alpha
LIVES_GLOBAL_INLINE LiVESList * lives_list_sort_alpha(LiVESList *list, boolean fwd)
Definition: utils.c:5474
clip_detail_to_string
char * clip_detail_to_string(lives_clip_details_t what, size_t *maxlenp)
Definition: utils.c:4980
lives_get_filename
LIVES_GLOBAL_INLINE char * lives_get_filename(char *uri)
return filename (no dir, no .ext)
Definition: utils.c:3214
lives_ellipsize
LIVES_GLOBAL_INLINE char * lives_ellipsize(char *txt, size_t maxlen, LiVESEllipsizeMode mode)
Definition: utils.c:3262
verhash
int verhash(char *xv)
Definition: utils.c:4755
msg_area_scroll_to_end
LIVES_GLOBAL_INLINE void msg_area_scroll_to_end(LiVESWidget *widget, LiVESAdjustment *adj)
Definition: interface.c:7277
lives_memset
#define lives_memset
Definition: machinestate.h:61
mainwindow::ref_message_n
int ref_message_n
Definition: mainwindow.h:1732
mainwindow::whentostop
volatile lives_whentostop_t whentostop
Definition: mainwindow.h:929
_prefs::default_fps
double default_fps
Definition: preferences.h:173
mainwindow::recovering_files
boolean recovering_files
Definition: mainwindow.h:1485
lives_direction_t
lives_direction_t
use REVERSE / FORWARD when a sign is used, BACKWARD / FORWARD when a parity is used
Definition: main.h:851
THREADVAR
#define THREADVAR(var)
Definition: machinestate.h:531
lives_fread_string
size_t lives_fread_string(char *buff, size_t stlen, const char *fname)
Definition: utils.c:388
CLIP_DETAILS_INTERLACE
@ CLIP_DETAILS_INTERLACE
Definition: main.h:1163
lives_rm
int lives_rm(const char *file)
Definition: utils.c:4395
LiVESEllipsizeMode
LingoEllipsizeMode LiVESEllipsizeMode
Definition: widget-helper.h:110
mainwindow::loop_cont
volatile boolean loop_cont
Definition: mainwindow.h:764
MISSING
@ MISSING
not yet implemented (TODO)
Definition: main.h:392
lmap_error::frameno
int frameno
Definition: multitrack.h:1036
switch_aud_to_pulse
boolean switch_aud_to_pulse(boolean set_in_prefs)
Definition: utils.c:3884
check_dir_access
boolean check_dir_access(const char *dir, boolean leaveit)
Definition: utils.c:4542
UNDO_NONE
@ UNDO_NONE
Definition: main.h:660
get_dirname
void get_dirname(char *filename)
Definition: utils.c:3167
mainwindow::cancelled
volatile lives_cancel_t cancelled
Definition: mainwindow.h:798
lives_get_current_playback_ticks
ticks_t lives_get_current_playback_ticks(int64_t origsecs, int64_t orignsecs, lives_time_source_t *time_source)
Definition: utils.c:1481
lives_mgeometry_t::screen
LiVESXScreen * screen
Definition: mainwindow.h:359
lmap_error::current
boolean current
Definition: multitrack.h:1038
_prefs::audio_opts
volatile uint32_t audio_opts
Definition: preferences.h:254
is_realtime_aplayer
#define is_realtime_aplayer(ptype)
Definition: audio.h:236
lives_clip_t::fps
double fps
Definition: main.h:893
mainwindow::msg_adj
LiVESAdjustment * msg_adj
Definition: mainwindow.h:1326
mainwindow::msg_list
weed_plant_t * msg_list
Definition: mainwindow.h:1729
add_messages_to_list
int add_messages_to_list(const char *text)
Definition: utils.c:2416
REC_FRAMES
#define REC_FRAMES
Definition: preferences.h:197
lives_invalidate_all_file_buffers
void lives_invalidate_all_file_buffers(void)
Definition: utils.c:557
RECA_WINDOW_GRAB
@ RECA_WINDOW_GRAB
Definition: audio.h:197
mainwindow::rec_fps
double rec_fps
Definition: mainwindow.h:1528
BSIZE
#define BSIZE
Definition: utils.c:5481
CLIP_DETAILS_PB_FRAMENO
@ CLIP_DETAILS_PB_FRAMENO
Definition: main.h:1158
IMG_TYPE_JPEG
@ IMG_TYPE_JPEG
Definition: main.h:776
d_print
void d_print(const char *fmt,...)
Definition: utils.c:2542
callbacks.h
LOCAL
@ LOCAL
Definition: main.h:395
lives_lseek_buffered_rdonly
off_t lives_lseek_buffered_rdonly(int fd, off_t offset)
Definition: utils.c:895
lives_readlink
LIVES_GLOBAL_INLINE ssize_t lives_readlink(const char *path, char *buf, size_t bufsiz)
Definition: utils.c:104
BUFF_SIZE_WRITE_SMALL
#define BUFF_SIZE_WRITE_SMALL
Definition: main.h:1598
CLIP_TOTAL_TIME
#define CLIP_TOTAL_TIME(clip)
Definition: main.h:830
_prefs::audio_src
int audio_src
Definition: preferences.h:204
lives_clip_t::frameno
frames_t frameno
Definition: main.h:934
LMAP_ERROR_SHIFT_FRAMES
@ LMAP_ERROR_SHIFT_FRAMES
Definition: multitrack.h:1023
lives_buffered_offset
off_t lives_buffered_offset(int fd)
Definition: utils.c:1364
capable
capability * capable
Definition: main.h:627
lives_proc_thread_create
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
Definition: machinestate.c:1730
LIVES_EXT_SRC_DECODER
#define LIVES_EXT_SRC_DECODER
Definition: main.h:1044
reset_playback_clock
void reset_playback_clock(void)
Definition: utils.c:1474
calc_frame_from_time2
LIVES_GLOBAL_INLINE int calc_frame_from_time2(int filenum, double time)
nearest frame [1, frames+1]
Definition: utils.c:1768
SCRATCH_FWD_EXTRA
#define SCRATCH_FWD_EXTRA
Definition: mainwindow.h:1034
WEED_PLANT_LIVES
#define WEED_PLANT_LIVES
Definition: machinestate.h:196
mainwindow::preview_rendering
boolean preview_rendering
Definition: mainwindow.h:758
lives_write_le
ssize_t lives_write_le(int fd, const void *buf, ssize_t count, boolean allow_fail)
Definition: utils.c:350
lives_read_buffered
ssize_t lives_read_buffered(int fd, void *buf, ssize_t count, boolean allow_less)
Definition: utils.c:924
BUFF_SIZE_WRITE_BIGMED
#define BUFF_SIZE_WRITE_BIGMED
Definition: main.h:1601
switch_to_file
void switch_to_file(int old_file, int new_file)
Definition: main.c:9646
LIVES_DIRECTION_REVERSE
@ LIVES_DIRECTION_REVERSE
Definition: main.h:852
check_for_ratio_fps
boolean check_for_ratio_fps(double fps)
Definition: utils.c:5361
ALL_USED
#define ALL_USED
Definition: mainwindow.h:192
CLIP_DETAILS_PB_FPS
@ CLIP_DETAILS_PB_FPS
Definition: main.h:1144
mainwindow::ext_audio_checkbutton
LiVESWidget * ext_audio_checkbutton
Definition: mainwindow.h:1358
set_undoable
void set_undoable(const char *what, boolean sensitive)
Definition: utils.c:4784
CEIL
#define CEIL(a, b)
Definition: main.h:283
LIVES_URGENCY_ALARM
#define LIVES_URGENCY_ALARM
Definition: mainwindow.h:1636
BUFFER_FILL_BYTES_SMALL
#define BUFFER_FILL_BYTES_SMALL
fixed values only for write buffers (must be multiples of 16)
Definition: main.h:1586
mainwindow::preview_box
LiVESWidget * preview_box
Definition: mainwindow.h:1304
get_token_count
size_t get_token_count(const char *string, int delim)
Definition: utils.c:5430
mainwindow::overlay_alarm
lives_alarm_t overlay_alarm
Definition: mainwindow.h:1646
INSTALL_CANLOCAL
#define INSTALL_CANLOCAL
install guidance flags
Definition: main.h:389
LIVES_OSC_NOTIFY_CANCELLED
#define LIVES_OSC_NOTIFY_CANCELLED
for OSC only (not for C++)
Definition: osc_notify.h:54
mainwindow::clock_ticks
volatile ticks_t clock_ticks
unadjusted system time since pb start, measured concurrently with currticks
Definition: mainwindow.h:1003
lives_clip_t::menuentry_func
ulong menuentry_func
Definition: main.h:1012
SCRATCH_NONE
#define SCRATCH_NONE
Definition: mainwindow.h:1027
mainwindow::double_size
boolean double_size
Definition: mainwindow.h:760
UNCHECKED
@ UNCHECKED
Definition: main.h:393
mainwindow::deltaticks
ticks_t deltaticks
deltaticks for scratching
Definition: mainwindow.h:1006
get_play_times
LIVES_GLOBAL_INLINE void get_play_times(void)
recalculate video / audio lengths and draw the timer bars
Definition: utils.c:3672
GNU_CONST
#define GNU_CONST
Definition: main.h:79
CANCEL_VID_END
@ CANCEL_VID_END
video playback completed
Definition: main.h:725
mainwindow::sep_win
boolean sep_win
Definition: mainwindow.h:761
mainwindow::msg
char msg[MAINW_MSG_SIZE]
Definition: mainwindow.h:724
mainwindow::spinbutton_end
LiVESWidget * spinbutton_end
Definition: mainwindow.h:1288
EXEC_YOUTUBE_DL
#define EXEC_YOUTUBE_DL
Definition: mainwindow.h:399
CLIP_TYPE_FILE
@ CLIP_TYPE_FILE
unimported video, not or partially broken in frames
Definition: main.h:765
VER_MINOR_MULT
#define VER_MINOR_MULT
Definition: utils.c:3497
lives_string_ends_with
boolean lives_string_ends_with(const char *string, const char *fmt,...)
Definition: utils.c:3143
SignalHandlerPointer
void(* SignalHandlerPointer)(int)
Definition: main.h:1464
filename_from_fd
char * filename_from_fd(char *val, int fd)
: return filename from an open fd, freeing val first
Definition: utils.c:60
LEFloat_to_BEFloat
LIVES_GLOBAL_INLINE float LEFloat_to_BEFloat(float f)
Definition: utils.c:1750
unbuffer_lmap_errors
void unbuffer_lmap_errors(boolean add)
Definition: utils.c:2656
get_dir
char * get_dir(const char *filename)
Definition: utils.c:3185
swab4
LIVES_GLOBAL_INLINE void swab4(const void *from, const void *to, size_t gran)
Definition: machinestate.c:2462
mainwindow::playing_sel
boolean playing_sel
list of set names in current workdir, mau be NULL
Definition: mainwindow.h:756
mainwindow::spinbutton_start
LiVESWidget * spinbutton_start
Definition: mainwindow.h:1288
_vid_playback_plugin::audio_codec
uint32_t audio_codec
Definition: plugins.h:169
BUFFER_FILL_BYTES_SMALLMED
#define BUFFER_FILL_BYTES_SMALLMED
Definition: main.h:1587
lives_clip_t::last_frameno
frames_t last_frameno
Definition: main.h:934
mainwindow::recaudio_submenu
LiVESWidget * recaudio_submenu
Definition: mainwindow.h:1194
lives_write_le_buffered
ssize_t lives_write_le_buffered(int fd, const void *buf, ssize_t count, boolean allow_fail)
Definition: utils.c:1329
AUDIO_PLAYER_JACK
#define AUDIO_PLAYER_JACK
Definition: preferences.h:49
switch_aud_to_jack
boolean switch_aud_to_jack(boolean set_in_prefs)
Definition: utils.c:3819
pref_factory_bool
boolean pref_factory_bool(const char *prefidx, boolean newval, boolean permanent)
Definition: preferences.c:717
lives_open3
LIVES_GLOBAL_INLINE int lives_open3(const char *pathname, int flags, mode_t mode)
Definition: utils.c:94
lives_clip_t::ratio_fps
boolean ratio_fps
framerate of the clip
Definition: main.h:894
resize_all
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
Definition: colourspace.c:13622
calc_midspect
void calc_midspect(int rwidth, int rheight, int *cwidth, int *cheight)
Definition: utils.c:2216
SCRATCH_JUMP_NORESYNC
#define SCRATCH_JUMP_NORESYNC
jump with no audio resync
Definition: mainwindow.h:1032
mainwindow::scrap_file
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
get_file_size
off_t get_file_size(int fd)
Definition: machinestate.c:943
create_cfile
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
mainwindow::signals_deferred
boolean signals_deferred
Definition: mainwindow.h:1674
lives_file_buffer_t::invalid
volatile boolean invalid
Definition: main.h:1619
LIVES_DIRECTION_BACKWARD
@ LIVES_DIRECTION_BACKWARD
Definition: main.h:853
reverse_bytes
LIVES_GLOBAL_INLINE void reverse_bytes(char *buff, size_t count, size_t gran)
Definition: machinestate.c:2502
capability::rm_cmd
char rm_cmd[PATH_MAX]
Definition: main.h:554
STOP_ON_AUD_END
@ STOP_ON_AUD_END
Definition: main.h:695
interface.h
lives_clip_t::afilesize
size_t afilesize
Definition: main.h:912
reset_clipmenu
void reset_clipmenu(void)
Definition: utils.c:4290
mainwindow::foreign_window
LiVESXWindow * foreign_window
Definition: mainwindow.h:843
lives_file_buffer_t::slurping
boolean slurping
Definition: main.h:1614
lives_alarm_set
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
mainwindow::overlay_msg
char * overlay_msg
Definition: mainwindow.h:1644
CURRENT_CLIP_HAS_VIDEO
#define CURRENT_CLIP_HAS_VIDEO
Definition: main.h:815
dirs_equal
boolean dirs_equal(const char *dira, const char *dirb)
Definition: utils.c:3390
mainwindow::t_sepwin
LiVESWidget * t_sepwin
Definition: mainwindow.h:1340
_prefs::show_urgency_msgs
boolean show_urgency_msgs
Definition: preferences.h:310
PREF_AUDIO_PLAYER
#define PREF_AUDIO_PLAYER
Definition: preferences.h:910
capability::nmonitors
int nmonitors
Definition: main.h:588
lives_text_buffer_delete
WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_buffer_delete(LiVESTextBuffer *tbuff, LiVESTextIter *start, LiVESTextIter *end)
Definition: widget-helper.c:4126
resync_audio
boolean resync_audio(double frameno)
resync audio playback to the current video frame
Definition: audio.c:2822
lmap_error::clipno
int clipno
Definition: multitrack.h:1036
_vid_playback_plugin::fixed_fpsd
double fixed_fpsd
Definition: plugins.h:188
mainwindow::memok
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
update_play_times
void update_play_times(void)
like get_play_times, but will force redraw of audio waveforms
Definition: utils.c:3677
mainwindow::playing_file
int playing_file
which number file we are playing (or -1) [generally mainw->current_file]
Definition: mainwindow.h:943
P_
#define P_(String, StringPlural, n)
Definition: support.h:46
calc_frame_from_time
LIVES_GLOBAL_INLINE int calc_frame_from_time(int filenum, double time)
nearest frame [1, frames]
Definition: utils.c:1759
LMAP_INFO_SETNAME_CHANGED
@ LMAP_INFO_SETNAME_CHANGED
Definition: multitrack.h:1029
lives_list_move_to_first
LIVES_GLOBAL_INLINE LiVESList * lives_list_move_to_first(LiVESList *list, LiVESList *item)
Definition: utils.c:5789
int_array_contains_value
LIVES_GLOBAL_INLINE boolean int_array_contains_value(int *array, int num_elems, int value)
Definition: utils.c:4284
print_cache
void print_cache(LiVESList *cache)
Definition: utils.c:4897
lives_pgid_t
int lives_pgid_t
Definition: main.h:118
mainwindow::files
lives_clip_t * files[MAX_FILES+1]
+1 for the clipboard
Definition: mainwindow.h:729
lives_widget_get_allocation_height
WIDGET_HELPER_GLOBAL_INLINE int lives_widget_get_allocation_height(LiVESWidget *widget)
Definition: widget-helper.c:5470
lives_buffered_write_printf
ssize_t lives_buffered_write_printf(int fd, boolean allow_fail, const char *fmt,...)
Definition: utils.c:1316
cache_file_contents
LiVESList * cache_file_contents(const char *filename)
Definition: utils.c:4909
widget_opts_t::monitor
int monitor
monitor we are displaying on
Definition: widget-helper.h:1437
autotune_u64
void autotune_u64(weed_plant_t *tuner, uint64_t min, uint64_t max, int ntrials, double cost)
Definition: machinestate.c:182
mainwindow::first_free_file
int first_free_file
Definition: mainwindow.h:728
lives_clip_t::has_old_header
boolean has_old_header
Definition: main.h:1091
mainwindow::signal_caught
uint32_t signal_caught
Definition: mainwindow.h:1673
lives_strstop
LIVES_GLOBAL_INLINE char * lives_strstop(char *st, const char term)
Definition: machinestate.c:1634
mainwindow::pulsed
void * pulsed
pulseaudio player
Definition: mainwindow.h:1463
zero_spinbuttons
void zero_spinbuttons(void)
Definition: utils.c:3807
get_ratio_fps
double get_ratio_fps(const char *string)
Definition: utils.c:5379
mainwindow::play_start
frames_t play_start
Definition: mainwindow.h:931
do_warning_dialog
LIVES_GLOBAL_INLINE boolean do_warning_dialog(const char *text)
Definition: dialogs.c:564
mainwindow::aframeno
double aframeno
and the audio 'frame' for when we are looping
Definition: mainwindow.h:962
CLIP_DETAILS_CLIPNAME
@ CLIP_DETAILS_CLIPNAME
Definition: main.h:1160
lives_list_append_unique
LIVES_GLOBAL_INLINE LiVESList * lives_list_append_unique(LiVESList *xlist, const char *add)
Definition: utils.c:5776
mainwindow::rec_vid_frames
frames_t rec_vid_frames
values to be written to the event list concurrent with next video ftame event
Definition: mainwindow.h:1529
activate_url_inner
void activate_url_inner(const char *link)
Definition: utils.c:4607
add_to_recovery_file
void add_to_recovery_file(const char *handle)
Definition: saveplay.c:6460
remove_layout_files
void remove_layout_files(LiVESList *map)
Definition: utils.c:3559
get_near2pow
LIVES_GLOBAL_INLINE uint64_t get_near2pow(uint64_t val)
Definition: utils.c:1463
lives_10pow
LIVES_GLOBAL_INLINE uint64_t lives_10pow(int pow)
Definition: utils.c:1438
LIVES_TIME_SOURCE_NONE
@ LIVES_TIME_SOURCE_NONE
Definition: mainwindow.h:226
lives_killpg
LIVES_GLOBAL_INLINE int lives_killpg(lives_pgid_t pgrp, int sig)
Definition: utils.c:1432
PREF_RECENT
#define PREF_RECENT
Definition: preferences.h:956
_lives_buffered_rdonly_slurp
boolean _lives_buffered_rdonly_slurp(int fd, off_t skip)
Definition: utils.c:641
CLIP_NAME_MAXLEN
#define CLIP_NAME_MAXLEN
Definition: main.h:804
LIVES_CLIP_HEADER
#define LIVES_CLIP_HEADER
Definition: mainwindow.h:555
capability::chmod_cmd
char chmod_cmd[PATH_MAX]
Definition: main.h:558
lives_timeout_t
Definition: mainwindow.h:691
lives_clip_t::video_time
double video_time
Definition: main.h:929
CLIP_DETAILS_HEIGHT
@ CLIP_DETAILS_HEIGHT
Definition: main.h:1146
widget_opts_t::non_modal
boolean non_modal
non-modal for dialogs
Definition: widget-helper.h:1422
_vid_playback_plugin::get_audio_fmts
int *(* get_audio_fmts)(void)
Definition: plugins.h:167
error
error("LSD_RANDFUNC(ptr, size) must be defined")
BUFF_SIZE_READ_LARGE
#define BUFF_SIZE_READ_LARGE
Definition: main.h:1595
lives_adjustment_get_value
WIDGET_HELPER_GLOBAL_INLINE double lives_adjustment_get_value(LiVESAdjustment *adj)
Definition: widget-helper.c:5575
calc_minspect
void calc_minspect(int rwidth, int rheight, int *cwidth, int *cheight)
Definition: utils.c:2195
mainwindow::stored_event_list
weed_event_t * stored_event_list
stored mt -> clip editor
Definition: mainwindow.h:804
image_ext_to_lives_image_type
LIVES_GLOBAL_INLINE const char * image_ext_to_lives_image_type(const char *img_ext)
Definition: utils.c:3039
capability::mv_cmd
char mv_cmd[PATH_MAX]
Definition: main.h:555
mainwindow::adjticks
ticks_t adjticks
used to equalise the timecode between alternate timer sources (souce -> clock adjustment)
Definition: mainwindow.h:1007
lives_setenv
LIVES_GLOBAL_INLINE boolean lives_setenv(const char *name, const char *value)
Definition: utils.c:120
has_executable
LIVES_LOCAL_INLINE lives_presence_t has_executable(const char *exe)
Definition: utils.c:3421
dump_messages
char * dump_messages(int start, int end)
Definition: utils.c:2338
CLIP_DETAILS_ARATE
@ CLIP_DETAILS_ARATE
Definition: main.h:1148
lives_get_current_ticks
LIVES_GLOBAL_INLINE ticks_t lives_get_current_ticks(void)
Definition: machinestate.c:835
mainwindow::n_messages
int n_messages
Definition: mainwindow.h:1731
LMAP_ERROR_MISSING_CLIP
@ LMAP_ERROR_MISSING_CLIP
Definition: multitrack.h:1017
CLIP_DETAILS_DECODER_NAME
@ CLIP_DETAILS_DECODER_NAME
Definition: main.h:1164
clipboard
#define clipboard
Definition: main.h:1835
mainwindow::clip_header
FILE * clip_header
Definition: mainwindow.h:1521
SCRATCH_BACK
#define SCRATCH_BACK
Definition: mainwindow.h:1028
lives_text_buffer_get_end_iter
WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_buffer_get_end_iter(LiVESTextBuffer *tbuff, LiVESTextIter *iter)
Definition: widget-helper.c:4089
do_threaded_dialog
void do_threaded_dialog(const char *trans_text, boolean has_cancel)
Definition: dialogs.c:3849
mainwindow::syncticks
ticks_t syncticks
adjustment to compensate for missed clock updates when switching time sources
Definition: mainwindow.h:1010
lives_clip_t::arps
int arps
audio physical sample rate (i.e the "normal" sample rate of the clip when played at 1,...
Definition: main.h:905
mainwindow::jackd_read
void * jackd_read
dummy
Definition: mainwindow.h:1454
mainwindow::fbuffer_mutex
pthread_mutex_t fbuffer_mutex
Definition: mainwindow.h:1506
lives_file_buffer_t::nseqreads
int nseqreads
Definition: main.h:1615
clear_mainw_msg
LIVES_GLOBAL_INLINE void clear_mainw_msg(void)
Definition: utils.c:1435
ASPECT_ALLOWANCE
#define ASPECT_ALLOWANCE
Definition: utils.c:21
catch_sigint
void catch_sigint(int signum)
Definition: main.c:296
lives_strdup_printf
#define lives_strdup_printf(fmt,...)
Definition: support.c:27
cached_list_free
LIVES_GLOBAL_INLINE void cached_list_free(LiVESList **list)
Definition: utils.c:4881
add_lmap_error
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
lives_calloc
#define lives_calloc
Definition: machinestate.h:67
lives_clip_t::opening
boolean opening
Definition: main.h:946
LIVES_MAX_USER_ALARMS
#define LIVES_MAX_USER_ALARMS
Definition: mainwindow.h:1634
lives_clip_t::tcache_dubious_from
frames_t tcache_dubious_from
height for thumbnail cache (width is fixed, but if this changes, invalidate)
Definition: main.h:1099
mainwindow::cap_number
int cap_number
Definition: mainwindow.h:739
insert_newlines
char * insert_newlines(const char *text, int maxwidth)
Definition: utils.c:5591
LIVES_IMAGE_TYPE_JPEG
#define LIVES_IMAGE_TYPE_JPEG
Definition: mainwindow.h:479
calc_frame_from_time3
LIVES_GLOBAL_INLINE int calc_frame_from_time3(int filenum, double time)
nearest frame rounded down, [1, frames+1]
Definition: utils.c:1778
dirchange_callback
boolean dirchange_callback(LiVESAccelGroup *group, LiVESWidgetObject *obj, uint32_t keyval, LiVESXModifierType mod, livespointer area_enum)
Definition: callbacks.c:4996
lives_fgets
char * lives_fgets(char *s, int size, FILE *stream)
Definition: utils.c:368
weed_layer_t
weed_plant_t weed_layer_t
Definition: colourspace.h:71
mainwindow::scratch
volatile short scratch
Definition: mainwindow.h:1026
lives_pad_ellipsize
LIVES_GLOBAL_INLINE char * lives_pad_ellipsize(char *txt, size_t fixlen, int palign, LiVESEllipsizeMode emode)
Definition: utils.c:3333
clear_lmap_errors
void clear_lmap_errors(void)
Definition: utils.c:2858
mainwindow::t_infobutton
LiVESWidget * t_infobutton
Definition: mainwindow.h:1341
lives_open_buffered_rdonly
LIVES_GLOBAL_INLINE int lives_open_buffered_rdonly(const char *pathname)
Definition: utils.c:636
LIVES_OSC_NOTIFY_FAILED
#define LIVES_OSC_NOTIFY_FAILED
for OSC only (not for C++)
Definition: osc_notify.h:53
PRIu64
#define PRIu64
Definition: machinestate.h:170
get_clip_value
boolean get_clip_value(int which, lives_clip_details_t what, void *retval, size_t maxlen)
Definition: utils.c:5039
mainwindow::is_rendering
boolean is_rendering
Definition: mainwindow.h:821
LIVES_MAIN_WINDOW_WIDGET
#define LIVES_MAIN_WINDOW_WIDGET
Definition: mainwindow.h:188
lives_alarm_clear
boolean lives_alarm_clear(lives_alarm_t alarm_handle)
Definition: utils.c:1732
lives_cp
int lives_cp(const char *from, const char *to)
Definition: utils.c:4414
lives_clip_t::checked_for_old_header
boolean checked_for_old_header
Definition: main.h:1091
mainwindow::ncbstores
int ncbstores
Definition: mainwindow.h:1781
LIVES_THRDATTR_NONE
#define LIVES_THRDATTR_NONE
Definition: machinestate.h:437
lives_close_buffered
int lives_close_buffered(int fd)
Definition: utils.c:716
mainwindow::ascrap_file
int ascrap_file
scrap file for recording audio scraps
Definition: mainwindow.h:875
PB_QUALITY_MED
#define PB_QUALITY_MED
default
Definition: preferences.h:33
close_clip_decoder
void close_clip_decoder(int clipno)
Definition: plugins.c:2382
AUDIO_OPTS_FOLLOW_FPS
#define AUDIO_OPTS_FOLLOW_FPS
Definition: preferences.h:256
buff_to_list
LIVES_GLOBAL_INLINE LiVESList * buff_to_list(const char *buffer, const char *delim, boolean allow_blanks, boolean strip)
Definition: utils.c:5755
mainwindow::faded
boolean faded
Definition: mainwindow.h:759
WEED_LEAF_LIVES_MESSAGE_STRING
#define WEED_LEAF_LIVES_MESSAGE_STRING
Definition: machinestate.h:199
lives_file_buffer_t::pathname
char * pathname
Definition: main.h:1621
SCREEN_AREA_FOREGROUND
#define SCREEN_AREA_FOREGROUND
Definition: mainwindow.h:1680
lives_memcpy
#define lives_memcpy
Definition: machinestate.h:55
lives_strlen
LIVES_GLOBAL_INLINE size_t lives_strlen(const char *s)
Definition: machinestate.c:1468
lives_sync
LIVES_GLOBAL_INLINE void lives_sync(int times)
Definition: utils.c:115
lives_widget_set_sensitive
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_sensitive(LiVESWidget *widget, boolean state)
Definition: widget-helper.c:1477
lives_write
ssize_t lives_write(int fd, const void *buf, ssize_t count, boolean allow_fail)
Definition: utils.c:309
check_file
boolean check_file(const char *file_name, boolean check_existing)
check if file exists
Definition: utils.c:4312
CURRENT_CLIP_IS_NORMAL
#define CURRENT_CLIP_IS_NORMAL
Definition: main.h:838
lives_utf8_strcmp
LIVES_GLOBAL_INLINE int lives_utf8_strcmp(const char *s1, const char *s2)
Definition: utils.c:5469
lives_fread
size_t lives_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
Definition: utils.c:379
mainwindow::alarms
lives_timeout_t alarms[LIVES_MAX_ALARMS]
reserve 1 for emergency msgs
Definition: mainwindow.h:1639
capability::home_dir
char home_dir[PATH_MAX]
home directory - default location for config file - locale encoding
Definition: main.h:544
mainwindow::hdrs_cache
LiVESList * hdrs_cache
cache of a file header (e.g. header.lives)
Definition: mainwindow.h:1518
lives_alarm_reset
LIVES_GLOBAL_INLINE lives_alarm_t lives_alarm_reset(lives_alarm_t alarm_handle, ticks_t ticks)
Definition: utils.c:1618
lives_clip_t::raudio_time
double raudio_time
Definition: main.h:929
get_nth_info_message
weed_plant_t * get_nth_info_message(int n)
Definition: utils.c:2304
lives_file_buffer_t::totops
int totops
Definition: main.h:1616
mainwindow::multitrack
lives_mt * multitrack
holds a pointer to the entire multitrack environment; NULL in Clip Edit mode
Definition: mainwindow.h:1087
get_basename
LIVES_GLOBAL_INLINE void get_basename(char *filename)
Definition: utils.c:3194
lives_kill
LIVES_GLOBAL_INLINE int lives_kill(lives_pid_t pid, int sig)
Definition: utils.c:1423
CURRENT_CLIP_IS_VALID
#define CURRENT_CLIP_IS_VALID
Definition: main.h:809
is_legal_set_name
boolean is_legal_set_name(const char *set_name, boolean allow_dupes, boolean leeway)
Definition: utils.c:2975
lives_file_buffer_t::buffer
uint8_t * buffer
read point in buffer
Definition: main.h:1607
_prefs::ar_layout_name
char ar_layout_name[PATH_MAX]
locale
Definition: preferences.h:286
CLIP_DETAILS_BPP
@ CLIP_DETAILS_BPP
Definition: main.h:1142
LIVES_IMAGE_TYPE_PNG
#define LIVES_IMAGE_TYPE_PNG
Definition: mainwindow.h:480
lives_list_free_all
LIVES_GLOBAL_INLINE void lives_list_free_all(LiVESList **list)
Definition: utils.c:4873
mainwindow::go_away
boolean go_away
Definition: mainwindow.h:1614
mainwindow::suppress_dprint
boolean suppress_dprint
tidy up, e.g. by blocking "switched to file..." and "closed file..." messages
Definition: mainwindow.h:1537
mainwindow::int_audio_checkbutton
LiVESWidget * int_audio_checkbutton
Definition: mainwindow.h:1358
lives_clip_t::laudio_time
double laudio_time
Definition: main.h:929
lives_chdir
int lives_chdir(const char *path, boolean no_error_dlg)
Definition: utils.c:1393
mainwindow::aud_rec_fd
int aud_rec_fd
fd of file we are recording audio to
Definition: mainwindow.h:1525
lives_list_strcmp_index
int lives_list_strcmp_index(LiVESList *list, livesconstpointer data, boolean case_sensitive)
Definition: utils.c:4678
lives_touch
int lives_touch(const char *tfile)
Definition: utils.c:4455
mainwindow::record_paused
volatile boolean record_paused
pause during recording
Definition: mainwindow.h:1557
capability::rmdir_cmd
char rmdir_cmd[PATH_MAX]
Definition: main.h:565
lives_clip_t::opening_frames
frames_t opening_frames
Definition: main.h:947
SCRATCH_REV
#define SCRATCH_REV
set on direction change (video)
Definition: mainwindow.h:1030
do_write_failed_error_s_with_retry
LiVESResponseType do_write_failed_error_s_with_retry(const char *fname, const char *errtext)
Definition: dialogs.c:4058
mt_clip_select
void mt_clip_select(lives_mt *mt, boolean scroll)
Definition: multitrack.c:3024
mainwindow::last_dprint_file
int last_dprint_file
message output settings
Definition: mainwindow.h:1535
mainwindow::msg_area
LiVESWidget * msg_area
Definition: mainwindow.h:1324
xprocess::processing
LiVESWidget * processing
Definition: mainwindow.h:706
mainwindow::current_layouts_map
LiVESList * current_layouts_map
map of all layouts for set
Definition: mainwindow.h:1470
DEF_ALIGN
#define DEF_ALIGN
Definition: main.h:629
LOCAL_HOME_DIR
#define LOCAL_HOME_DIR
Definition: mainwindow.h:604
main.h
AFORM_UNKNOWN
#define AFORM_UNKNOWN
Definition: main.h:788
LIVES_CURSOR_BUSY
@ LIVES_CURSOR_BUSY
Definition: widget-helper.h:1293
CLIP_DETAILS_GAMMA_TYPE
@ CLIP_DETAILS_GAMMA_TYPE
Definition: main.h:1165
AUDIO_PLAYER_SOX
#define AUDIO_PLAYER_SOX
Definition: preferences.h:48
AUD_PLAYER_SOX
#define AUD_PLAYER_SOX
Definition: preferences.h:42
fast_hash
LIVES_GLOBAL_INLINE uint32_t fast_hash(const char *key)
Definition: machinestate.c:1596
mainwindow::play_end
frames_t play_end
Definition: mainwindow.h:931
STOP_ON_VID_END
@ STOP_ON_VID_END
Definition: main.h:694
CLIPBOARD_FILE
#define CLIPBOARD_FILE
Definition: main.h:1834
CLIP_DETAILS_UNIQUE_ID
@ CLIP_DETAILS_UNIQUE_ID
Definition: main.h:1147
MAX_FILES
#define MAX_FILES
max files is actually 1 more than this, since file 0 is the clipboard
Definition: main.h:184
mainwindow::fs
boolean fs
Definition: mainwindow.h:762
LIVES_FILE_EXT_TMP
#define LIVES_FILE_EXT_TMP
Definition: mainwindow.h:486
MAX_SET_NAME_LEN
#define MAX_SET_NAME_LEN
sets
Definition: mainwindow.h:748
lives_text_buffer_get_start_iter
WIDGET_HELPER_GLOBAL_INLINE boolean lives_text_buffer_get_start_iter(LiVESTextBuffer *tbuff, LiVESTextIter *iter)
Definition: widget-helper.c:4080
stored_event_list_free_all
void stored_event_list_free_all(boolean wiped)
Definition: multitrack.c:5897
resample.h
_prefs::sleep_time
int sleep_time
Definition: preferences.h:176
AUDIO_SRC_EXT
#define AUDIO_SRC_EXT
Definition: preferences.h:206
get_total_time
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
switch_aud_to_none
void switch_aud_to_none(boolean set_in_prefs)
Definition: utils.c:4001
_prefs::vj_mode
boolean vj_mode
Definition: preferences.h:459
lives_notify
void lives_notify(int msgnumber, const char *msgstring)
Definition: callbacks.c:49
get_signed_endian
uint32_t get_signed_endian(boolean is_signed, boolean little_endian)
produce bitmapped value
Definition: utils.c:5408
AUDIO_SRC_INT
#define AUDIO_SRC_INT
Definition: preferences.h:205
set_signal_handlers
void set_signal_handlers(SignalHandlerPointer sigfunc)
Definition: main.c:4077
sig
#define sig(a)
Definition: main.h:268
mainwindow::ext_playback
boolean ext_playback
using external video playback plugin
Definition: mainwindow.h:773
BUFF_SIZE_WRITE_LARGE
#define BUFF_SIZE_WRITE_LARGE
Definition: main.h:1602
mainw
mainwindow * mainw
Definition: main.c:103
autotune_u64_end
uint64_t autotune_u64_end(weed_plant_t **tuner, uint64_t val)
Definition: machinestate.c:259
lives_file_buffer_t::fd
int fd
Definition: main.h:1609
lmap_error
Definition: multitrack.h:1032
d_print_enough
LIVES_GLOBAL_INLINE void d_print_enough(int frames)
Definition: utils.c:2630
lives_buffered_rdonly_slurp
void lives_buffered_rdonly_slurp(int fd, off_t skip)
Definition: utils.c:671
capability::echo_cmd
char echo_cmd[PATH_MAX]
Definition: main.h:563
BUFF_SIZE_WRITE_MED
#define BUFF_SIZE_WRITE_MED
Definition: main.h:1600
lives_read_le
ssize_t lives_read_le(int fd, void *buf, ssize_t count, boolean allow_less)
Definition: utils.c:486
get_version_hash
uint64_t get_version_hash(const char *exe, const char *sep, int piece)
Definition: utils.c:3475
mainwindow::affected_layouts_map
LiVESList * affected_layouts_map
map of layouts with errors
Definition: mainwindow.h:1469
mainwindow::cursor_style
lives_cursor_t cursor_style
Definition: mainwindow.h:1296
lives_file_buffer_t::offset
off_t offset
ptr to data (ptr - buffer + bytes) gives the read size
Definition: main.h:1608
N_RECENT_FILES
#define N_RECENT_FILES
Definition: main.h:657
mainwindow::jack_can_stop
boolean jack_can_stop
Definition: mainwindow.h:934
lives_kill_subprocesses
void lives_kill_subprocesses(const char *dirname, boolean kill_parent)
Definition: utils.c:4516
AUDIO_PLAYER_PULSE
#define AUDIO_PLAYER_PULSE
used in pref and for external players (e.g -ao pulse, -aplayer pulse)
Definition: preferences.h:51
mainwindow::proc_ptr
xprocess * proc_ptr
Definition: mainwindow.h:1090
lives_rmglob
int lives_rmglob(const char *files)
Definition: utils.c:4404
_prefs::force_system_clock
boolean force_system_clock
Definition: preferences.h:366
find_in_file_buffers_by_pathname
lives_file_buffer_t * find_in_file_buffers_by_pathname(const char *pathname)
Definition: utils.c:419
capability::myname
char * myname
Definition: main.h:580
LIVES_OSC_NOTIFY_CLIP_OPENED
#define LIVES_OSC_NOTIFY_CLIP_OPENED
sent after a clip is opened
Definition: osc_notify.h:46
lives_slist_free_all
LIVES_GLOBAL_INLINE void lives_slist_free_all(LiVESSList **list)
Definition: utils.c:4865
frames_t
int frames_t
Definition: main.h:99
_prefs::ar_layout
boolean ar_layout
Definition: preferences.h:284
get_frame_count
int get_frame_count(int idx, int start)
sets mainw->files[idx]->frames with current framecount
Definition: utils.c:3109
get_approx_ln
LIVES_GLOBAL_INLINE uint32_t get_approx_ln(uint32_t x)
Definition: utils.c:1453
lives_clip_t::pb_fps
double pb_fps
current playback rate, may vary from fps, can be 0. or negative
Definition: main.h:1007
mainwindow::rec_signed_endian
int rec_signed_endian
Definition: mainwindow.h:1532
CLIP_DETAILS_PB_ARATE
@ CLIP_DETAILS_PB_ARATE
Definition: main.h:1149
lives_list_copy_strings
LIVES_GLOBAL_INLINE LiVESList * lives_list_copy_strings(LiVESList *list)
Definition: utils.c:5820
WARN_MASK_LAYOUT_MISSING_CLIPS
#define WARN_MASK_LAYOUT_MISSING_CLIPS
Definition: preferences.h:94
lives_widget_set_opacity
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_opacity(LiVESWidget *widget, double opacity)
Definition: widget-helper.c:1757
PB_QUALITY_LOW
#define PB_QUALITY_LOW
Definition: preferences.h:32
CLIP_DETAILS_FPS
@ CLIP_DETAILS_FPS
Definition: main.h:1143
LIVES_MAX_ALARMS
#define LIVES_MAX_ALARMS
Definition: mainwindow.h:1633
update_timer_bars
void update_timer_bars(int posx, int posy, int width, int height, int which)
draw the timer bars
Definition: interface.c:288
lives_widget_show_all
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_show_all(LiVESWidget *widget)
Definition: widget-helper.c:1523
lives_file_buffer_t::read
boolean read
Definition: main.h:1612
weed_layer_free
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_free(weed_layer_t *layer)
frees pixel_data for a layer, then the layer itself
Definition: colourspace.c:13883
buffer_lmap_error
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
lives_chomp
LIVES_GLOBAL_INLINE char * lives_chomp(char *buff)
Definition: machinestate.c:1641
capability::has_sox_play
lives_checkstatus_t has_sox_play
Definition: main.h:508
get_utf8_pref
LiVESResponseType get_utf8_pref(const char *key, char *val, int maxlen)
Definition: preferences.c:112
mainwindow::cbstores
lives_clip_t * cbstores[8]
Definition: mainwindow.h:1782
LMAP_ERROR_DELETE_FRAMES
@ LMAP_ERROR_DELETE_FRAMES
Definition: multitrack.h:1019
make_image_file_name
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
lives_funcptr_t
void *(* lives_funcptr_t)(void *)
Definition: machinestate.h:378
capability::cp_cmd
char cp_cmd[PATH_MAX]
Definition: main.h:556
lives_read_le_buffered
ssize_t lives_read_le_buffered(int fd, void *buf, ssize_t count, boolean allow_less)
Definition: utils.c:1158
widget_opts
widget_opts_t widget_opts
Definition: widget-helper.h:1442
resize
void resize(double scale)
Definition: main.c:10230
PATH_MAX
#define PATH_MAX
Definition: main.h:255
lives_timeout_t::lastcheck
volatile ticks_t lastcheck
Definition: mainwindow.h:693
lives_popen
ssize_t lives_popen(const char *com, boolean allow_error, char *buff, ssize_t buflen)
Definition: utils.c:194
LIVES_DIR_SEP
#define LIVES_DIR_SEP
Definition: main.h:197
AUD_PLAYER_PULSE
#define AUD_PLAYER_PULSE
Definition: preferences.h:44
_prefs::cmd_log
char cmd_log[PATH_MAX]
Definition: preferences.h:168
IMG_TYPE_UNKNOWN
@ IMG_TYPE_UNKNOWN
Definition: main.h:775
AUD_PLAYER_JACK
#define AUD_PLAYER_JACK
Definition: preferences.h:43
get_menu_name
char * get_menu_name(lives_clip_t *sfile, boolean add_setname)
Definition: gui.c:4487
lives_text_buffer_create_mark
WIDGET_HELPER_GLOBAL_INLINE LiVESTextMark * lives_text_buffer_create_mark(LiVESTextBuffer *tbuff, const char *mark_name, const LiVESTextIter *where, boolean left_gravity)
Definition: widget-helper.c:4107
hextodec
LIVES_GLOBAL_INLINE int hextodec(const char *string)
Definition: utils.c:5694
LIVES_WEED_SUBTYPE_TUNABLE
#define LIVES_WEED_SUBTYPE_TUNABLE
Definition: machinestate.h:203
lives_signal_handler_unblock
WIDGET_HELPER_GLOBAL_INLINE boolean lives_signal_handler_unblock(livespointer instance, unsigned long handler_id)
Definition: widget-helper.c:947
lives_file_buffer_t::orig_size
size_t orig_size
Definition: main.h:1620
lives_clip_t
corresponds to one clip in the GUI
Definition: main.h:877
set_sel_label
void set_sel_label(LiVESWidget *sel_label)
Definition: utils.c:4838
defer_sigint
void defer_sigint(int signum)
Definition: main.c:282
lives_calloc_safety
LIVES_GLOBAL_INLINE void * lives_calloc_safety(size_t nmemb, size_t xsize)
Definition: machinestate.c:603
activate_url
void activate_url(LiVESAboutDialog *about, const char *link, livespointer data)
Definition: utils.c:4624
PREF_AR_LAYOUT
#define PREF_AR_LAYOUT
Definition: preferences.h:933
lives_list_free_strings
LIVES_GLOBAL_INLINE void lives_list_free_strings(LiVESList *list)
Definition: utils.c:4860
BL_LIM
#define BL_LIM
Definition: utils.c:5754
mainwindow::no_switch_dprint
boolean no_switch_dprint
Definition: mainwindow.h:1536
_prefs::audio_play_command
char audio_play_command[PATH_MAX *2]
Definition: preferences.h:171
lives_lseek_buffered_rdonly_absolute
off_t lives_lseek_buffered_rdonly_absolute(int fd, off_t offset)
Definition: utils.c:907
mainwindow::pulsed_read
void * pulsed_read
Definition: mainwindow.h:1464
mainwindow::mute
boolean mute
Definition: mainwindow.h:770
d_print_overlay
boolean d_print_overlay(double timeout, const char *fmt,...)
Definition: utils.c:2523
lives_suspend_resume_process
void lives_suspend_resume_process(const char *dirname, boolean suspend)
Definition: utils.c:4527
lives_widget_process_updates
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_process_updates(LiVESWidget *widget)
Definition: widget-helper.c:1658
lives_widget_queue_draw_if_visible
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_queue_draw_if_visible(LiVESWidget *widget)
Definition: widget-helper.c:11009
find_in_file_buffers
lives_file_buffer_t * find_in_file_buffers(int fd)
Definition: utils.c:401
lives_nanosleep_until_nonzero
#define lives_nanosleep_until_nonzero(condition)
Definition: machinestate.h:310
lives_file_buffer_t::bytes
ssize_t bytes
Definition: main.h:1605
audio.h
BUFF_SIZE_READ_CUSTOM
#define BUFF_SIZE_READ_CUSTOM
Definition: main.h:1596
CANCEL_AUD_END
@ CANCEL_AUD_END
video playback completed
Definition: main.h:737
lives_menu_item_get_text
WIDGET_HELPER_GLOBAL_INLINE const char * lives_menu_item_get_text(LiVESWidget *menuitem)
Definition: widget-helper.c:11931
switch_aud_to_sox
boolean switch_aud_to_sox(boolean set_in_prefs)
Definition: utils.c:3944
calc_time_from_frame
LIVES_GLOBAL_INLINE double calc_time_from_frame(int clip, int frame)
Definition: utils.c:1756
mainwindow::urgency_msg
char * urgency_msg
OSD.
Definition: mainwindow.h:1643
lives_time_source_t
lives_time_source_t
timebase sources
Definition: mainwindow.h:225
LMAP_ERROR_ALTER_FRAMES
@ LMAP_ERROR_ALTER_FRAMES
Definition: multitrack.h:1024
mainwindow::ping_pong
volatile boolean ping_pong
Definition: mainwindow.h:765
check_for_lock_file
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_utf8_strcasecmp
int lives_utf8_strcasecmp(const char *s1, const char *s2)
Definition: utils.c:5458
calc_maxspect
void calc_maxspect(int rwidth, int rheight, int *cwidth, int *cheight)
Definition: utils.c:2174
lives_clip_t::asampsize
int asampsize
audio sample size in bits (8 or 16)
Definition: main.h:908
mainwindow::pwidth
int pwidth
PLAYBACK.
Definition: mainwindow.h:926
mainwindow::undo
LiVESWidget * undo
Definition: mainwindow.h:1146
mainwindow::agen_key
volatile int agen_key
which fx key is generating audio [1 based] (or 0 for none)
Definition: mainwindow.h:1649
lives_plant_new_with_index
LIVES_GLOBAL_INLINE weed_plant_t * lives_plant_new_with_index(int subtype, int64_t index)
Definition: machinestate.c:2273
lives_cp_keep_perms
int lives_cp_keep_perms(const char *from, const char *to)
Definition: utils.c:4437
lives_mv
int lives_mv(const char *from, const char *to)
Definition: utils.c:4446
WEED_LEAF_LIVES_SUBTYPE
#define WEED_LEAF_LIVES_SUBTYPE
Definition: machinestate.h:198
get_max_align
LIVES_GLOBAL_INLINE size_t get_max_align(size_t req_size, size_t align_max)
Definition: machinestate.c:596
lives_mgeometry_t::disp
LiVESXDisplay * disp
Definition: mainwindow.h:358
lives_ln
int lives_ln(const char *from, const char *to)
Definition: utils.c:4464
lives_image_ext_to_img_type
LIVES_GLOBAL_INLINE lives_img_type_t lives_image_ext_to_img_type(const char *img_ext)
Definition: utils.c:3034
SCRATCH_JUMP
#define SCRATCH_JUMP
jump and resync audio
Definition: mainwindow.h:1031
lives_signal_handler_block
WIDGET_HELPER_GLOBAL_INLINE boolean lives_signal_handler_block(livespointer instance, unsigned long handler_id)
Definition: widget-helper.c:933
resample_event
this struct is used only when physically resampling frames on the disk we create an array of these an...
Definition: main.h:641
mainwindow::vol_toolitem
LiVESWidget * vol_toolitem
Definition: mainwindow.h:1364
LIVES_FILE_EXT_PNG
#define LIVES_FILE_EXT_PNG
Definition: mainwindow.h:487
save_layout_map
void save_layout_map(int *lmap, double *lmap_audio, const char *file, const char *dir)
Definition: multitrack.c:19714
DEF_FILE_PERMS
#define DEF_FILE_PERMS
non-executable, is modified by the umask
Definition: main.h:209
unhash_version
char * unhash_version(uint64_t version)
Definition: utils.c:3522
lives_fix
LIVES_GLOBAL_INLINE double lives_fix(double val, int decimals)
Definition: utils.c:1446
_prefs::scratchback_amount
int scratchback_amount
Definition: preferences.h:229
save_clip_values
boolean save_clip_values(int which_file)
Definition: saveplay.c:103
lives_clip_t::arate
int arate
current audio playback rate (varies if the clip rate is changed)
Definition: main.h:906
lives_open2
LIVES_GLOBAL_INLINE int lives_open2(const char *pathname, int flags)
Definition: utils.c:99
mainwindow::rec_achans
int rec_achans
Definition: mainwindow.h:1532
subst
char * subst(const char *xstring, const char *from, const char *to)
Definition: utils.c:5484
_prefs::perm_audio_reader
boolean perm_audio_reader
Definition: preferences.h:426
lives_clip_t::menuentry
LiVESWidget * menuentry
Definition: main.h:1011
init_clipboard
void init_clipboard(void)
Definition: utils.c:2238
FALSE
#define FALSE
Definition: videoplugin.h:60
mainwindow::affected_layout_marks
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
get_read_buff_size
size_t get_read_buff_size(int sztype)
Definition: utils.c:771
create_event_space
boolean create_event_space(int length)
Definition: utils.c:4660
lives_widget_get_allocation_width
WIDGET_HELPER_GLOBAL_INLINE int lives_widget_get_allocation_width(LiVESWidget *widget)
Definition: widget-helper.c:5455
mainwindow::audio_end
int audio_end
Definition: mainwindow.h:771
lives_file_buffer_t::eof
boolean eof
Definition: main.h:1611
WEED_LEAF_NEXT
#define WEED_LEAF_NEXT
Definition: events.h:62
LMAP_ERROR_DELETE_AUDIO
@ LMAP_ERROR_DELETE_AUDIO
Definition: multitrack.h:1020
lives_clip_t::adirection
lives_direction_t adirection
audio play direction during playback, FORWARD or REVERSE.
Definition: main.h:1016
clip_can_reverse
boolean clip_can_reverse(int clipno)
Definition: callbacks.c:4980
_prefs::noframedrop
boolean noframedrop
Definition: preferences.h:469
lives_buffered_rdonly_set_reversed
LIVES_GLOBAL_INLINE boolean lives_buffered_rdonly_set_reversed(int fd, boolean val)
Definition: utils.c:681
lives_clip_t::handle
char handle[256]
Definition: main.h:881
_
#define _(String)
Definition: support.h:44
IS_NORMAL_CLIP
#define IS_NORMAL_CLIP(clip)
Definition: main.h:833
LIVES_TIME_SOURCE_SOUNDCARD
@ LIVES_TIME_SOURCE_SOUNDCARD
Definition: mainwindow.h:228
mainwindow::error
boolean error
Definition: mainwindow.h:801
do_error_dialogf
LiVESResponseType do_error_dialogf(const char *fmt,...)
Definition: dialogs.c:735
capability::byte_order
int byte_order
Definition: main.h:577
get_pref_from_file
LIVES_GLOBAL_INLINE LiVESResponseType get_pref_from_file(const char *filename, const char *key, char *val, int maxlen)
Definition: preferences.c:106
do_system_failed_error
LiVESResponseType do_system_failed_error(const char *com, int retval, const char *addinfo, boolean can_retry, boolean trysudo)
Definition: dialogs.c:3897
lives_list_delete_string
LiVESList * lives_list_delete_string(LiVESList *list, const char *string)
Definition: utils.c:5801
LIVES_ELLIPSIZE_START
#define LIVES_ELLIPSIZE_START
Definition: widget-helper.h:112
lives_alarm_check
ticks_t lives_alarm_check(lives_alarm_t alarm_handle)
Definition: utils.c:1687
lives_clip_t::achans
int achans
number of audio channels (0, 1 or 2)
Definition: main.h:907
save_clip_value
boolean save_clip_value(int which, lives_clip_details_t what, void *val)
Definition: utils.c:5175
calc_frame_from_time4
LIVES_GLOBAL_INLINE int calc_frame_from_time4(int filenum, double time)
nearest frame, no maximum
Definition: utils.c:1788
lives_fputs
int lives_fputs(const char *s, FILE *stream)
Definition: utils.c:359
AFORM_BIG_ENDIAN
#define AFORM_BIG_ENDIAN
Definition: main.h:787
EXEC_XDOTOOL
#define EXEC_XDOTOOL
Definition: mainwindow.h:427
SCRATCH_BACK_EXTRA
#define SCRATCH_BACK_EXTRA
Definition: mainwindow.h:1035
lives_widget_show
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_show(LiVESWidget *widget)
Definition: widget-helper.c:1505
find_when_to_stop
void find_when_to_stop(void)
Definition: utils.c:3722
mainwindow::aplayer_broken
boolean aplayer_broken
Definition: mainwindow.h:1653
lives_chmod
int lives_chmod(const char *target, const char *mode)
Definition: utils.c:4475
LIVES_ACLIP_HEADER
#define LIVES_ACLIP_HEADER
Definition: mainwindow.h:556
NEVER_STOP
@ NEVER_STOP
Definition: main.h:693
weed_layer_create_from_file_progressive
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
lives_get_relative_ticks
LIVES_GLOBAL_INLINE ticks_t lives_get_relative_ticks(ticks_t origsecs, ticks_t orignsecs)
Definition: machinestate.c:813
mainwindow::rec_arate
int rec_arate
Definition: mainwindow.h:1532
set_string_pref
int set_string_pref(const char *key, const char *value)
Definition: preferences.c:290
lives_strncmp
LIVES_GLOBAL_INLINE boolean lives_strncmp(const char *st1, const char *st2, size_t len)
returns FALSE if strings match
Definition: machinestate.c:1554
lives_make_writeable_dir
boolean lives_make_writeable_dir(const char *newdir)
Definition: utils.c:5721
MAINW_MSG_SIZE
#define MAINW_MSG_SIZE
mainw->msg bytesize
Definition: mainwindow.h:702
mainwindow::foreign
boolean foreign
for external window capture
Definition: mainwindow.h:824
lives_menu_item_set_text
WIDGET_HELPER_GLOBAL_INLINE void lives_menu_item_set_text(LiVESWidget *menuitem, const char *text, boolean use_mnemonic)
Definition: widget-helper.c:11920
make_version_hash
uint64_t make_version_hash(const char *ver)
Definition: utils.c:3500
lives_recalloc
LIVES_GLOBAL_INLINE void * lives_recalloc(void *p, size_t nmemb, size_t omemb, size_t xsize)
Definition: machinestate.c:615
lives_clip_t::end
frames_t end
Definition: main.h:891
WEED_LEAF_PREVIOUS
#define WEED_LEAF_PREVIOUS
Definition: events.h:63
AV_TRACK_MIN_DIFF
#define AV_TRACK_MIN_DIFF
ignore track time differences < this (seconds)
Definition: main.h:806
EXEC_WMCTRL
#define EXEC_WMCTRL
Definition: mainwindow.h:426
lives_clip_t::layout_map
LiVESList * layout_map
Definition: main.h:1037
_prefs::show_dev_opts
boolean show_dev_opts
Definition: preferences.h:463
set_redoable
void set_redoable(const char *what, boolean sensitive)
Definition: utils.c:4813
set_utf8_pref
int set_utf8_pref(const char *key, const char *value)
Definition: preferences.c:306
get_new_handle
boolean get_new_handle(int index, const char *name)
Definition: saveplay.c:3821
mainwindow::new_lmap_errors
LiVESList * new_lmap_errors
Definition: mainwindow.h:815