LiVES 3.2.0
machinestate.c
Go to the documentation of this file.
1// machinestate.c
2// LiVES
3// (c) G. Finch 2019 - 2020 <salsaman+lives@gmail.com>
4// released under the GNU GPL 3 or later
5// see file ../COPYING for licensing details
6
7// functions for dealing with externalities
8
9#include <sys/statvfs.h>
10#include "main.h"
11#include "callbacks.h"
12
13LIVES_LOCAL_INLINE char *mini_popen(char *cmd);
14
15#if IS_X86_64
16
17static void cpuid(unsigned int ax, unsigned int *p) {
18 __asm __volatile
19 ("movl %%ebx, %%esi\n\tcpuid\n\txchgl %%ebx, %%esi"
20 : "=a"(p[0]), "=S"(p[1]), "=c"(p[2]), "=d"(p[3])
21 : "0"(ax));
22}
23
24static int get_cacheline_size(void) {
25 unsigned int cacheline = -1;
26 unsigned int regs[4], regs2[4];
27 cpuid(0x00000000, regs);
28 if (regs[0] >= 0x00000001) {
29 cpuid(0x00000001, regs2);
30 cacheline = ((regs2[1] >> 8) & 0xFF) * 8;
31 //has_sse2 = (regs2[3] & 0x4000000) ? TRUE : FALSE;
32 }
33 return cacheline;
34}
35
36#endif
37
38static uint64_t fastrand_val = 0;
39
41 fastrand_val ^= (fastrand_val << 13); fastrand_val ^= (fastrand_val >> 7);
42 fastrand_val = ((fastrand_val & 0xFFFFFFFF00000000) >> 32) | ((fastrand_val & 0xFFFFFFFF) << 32);
43 fastrand_val ^= (fastrand_val << 17);
44 return fastrand_val;
45}
46
47LIVES_GLOBAL_INLINE void fastrand_add(uint64_t entropy) {fastrand_val += entropy;}
48
49LIVES_GLOBAL_INLINE double fastrand_dbl(double range) {
50 static const double divd = (double)(0xFFFFFFFFFFFFFFFF); return (double)fastrand() / divd * range;
51}
52
54LIVES_GLOBAL_INLINE uint32_t fastrand_int(uint32_t range) {return (uint32_t)(fastrand_dbl((double)(++range)));}
55
56LIVES_GLOBAL_INLINE void lives_srandom(unsigned int seed) {srandom(seed);}
57
58LIVES_GLOBAL_INLINE uint64_t lives_random(void) {return random();}
59
60void lives_get_randbytes(void *ptr, size_t size) {
61 if (size <= 8) {
62 uint64_t rbytes = gen_unique_id();
63 lives_memcpy(ptr, &rbytes, size);
64 }
65}
66
67
68uint64_t gen_unique_id(void) {
69 static uint64_t last_rnum = 0;
70 uint64_t rnum;
71#if HAVE_GETENTROPY
72 int randres = getentropy(&rnum, 8);
73#else
74 int randres = 1;
75#endif
76 if (randres) {
77 fastrand_val = lives_random();
78 fastrand();
79 fastrand_val ^= lives_get_current_ticks();
80 rnum = fastrand();
81 }
83 // a number < 1 billion is approx. 2 ^ 30 / 2 ^ 64 or about 1 chance in 17 trillion
84 // the chance of it happening the first time is thus minscule
85 // and the chance of it happening twice by chance is so unlikely we should discount it
86 if (rnum < BILLIONS(1) && last_rnum < BILLIONS(1)) abort();
87 last_rnum = rnum;
88 return rnum;
89}
90
91
93 uint32_t rseed;
94#ifdef HAVE_GETENTROPY
95 if (getentropy(&rseed, 4)) rseed = (gen_unique_id() & 0xFFFFFFFF);
96#else
97 rseed = (gen_unique_id() & 0xFFFFFFFF);
98#endif
99 lives_srandom(rseed);
100 fastrand_val = gen_unique_id();
101}
102
103
105
106struct _decomp {
107 uint64_t value;
108 int i, j;
109};
110
111struct _decomp_tab {
112 uint64_t value;
113 int i, j;
114 struct _decomp_tab *lower, *higher;
115};
116
117static struct _decomp_tab nxttbl[64][25];
118static boolean nxttab_inited = FALSE;
119
120void make_nxttab(void) {
121 LiVESList *preplist = NULL, *dccl, *dccl_last = NULL;
122 uint64_t val6 = 1ul, val;
123 struct _decomp *dcc;
124 int max2pow, xi, xj;
125 if (nxttab_inited) return;
126 for (int j = 0; j < 25; j++) {
127 val = val6;
128 max2pow = 64 - ((j * 10 + 7) >> 2);
129 dccl = preplist;
130 for (int i = 0; i < max2pow; i++) {
131 dcc = (struct _decomp *)lives_malloc(sizeof(struct _decomp));
132 dcc->value = val;
133 dcc->i = i;
134 dcc->j = j;
135 if (!preplist) dccl = preplist = lives_list_append(preplist, dcc);
136 else {
137 LiVESList *dccl2 = lives_list_append(NULL, (livespointer)dcc);
138 for (; dccl; dccl = dccl->next) {
139 dcc = (struct _decomp *)dccl->data;
140 if (dcc->value > val) break;
141 dccl_last = dccl;
142 }
143 if (!dccl) {
144 dccl_last->next = dccl2;
145 dccl2->prev = dccl_last;
146 dccl2->next = NULL;
147 dccl = dccl2;
148 } else {
149 dccl2->next = dccl;
150 dccl2->prev = dccl->prev;
151 if (dccl->prev) dccl->prev->next = dccl2;
152 else preplist = dccl2;
153 dccl->prev = dccl2;
154 }
155 }
156 val *= 2;
157 }
158 val6 *= 6;
159 }
160 for (dccl = preplist; dccl; dccl = dccl->next) {
161 dcc = (struct _decomp *)dccl->data;
162 xi = dcc->i;
163 xj = dcc->j;
164 nxttbl[xi][xj].value = dcc->value;
165 nxttbl[xi][xj].i = xi;
166 nxttbl[xi][xj].j = xj;
167 if (dccl->prev) {
168 dcc = (struct _decomp *)dccl->prev->data;
169 nxttbl[xi][xj].lower = &(nxttbl[dcc->i][dcc->j]);
170 } else nxttbl[xi][xj].lower = NULL;
171 if (dccl->next) {
172 dcc = (struct _decomp *)dccl->next->data;
173 nxttbl[xi][xj].higher = &(nxttbl[dcc->i][dcc->j]);
174 } else nxttbl[xi][xj].higher = NULL;
175 }
176 lives_list_free_all(&preplist);
177 nxttab_inited = TRUE;
178}
179
180
181
182void autotune_u64(weed_plant_t *tuner, uint64_t min, uint64_t max, int ntrials, double cost) {
183 if (tuner) {
184 double tc = cost;
185 int trials = weed_get_int_value(tuner, "trials", NULL);
186 if (trials == 0) {
187 weed_set_int_value(tuner, "ntrials", ntrials);
188 weed_set_int64_value(tuner, "min", min);
189 weed_set_int64_value(tuner, "max", max);
190 } else tc += weed_get_double_value(tuner, "tcost", NULL);
191 weed_set_double_value(tuner, "tcost", tc);
192 weed_set_int64_value(tuner, "tstart", lives_get_current_ticks());
193 }
194}
195
196#define NCYCS 16
197
198uint64_t nxtval(uint64_t val, uint64_t lim, boolean less) {
199 // to avoid only checking powers of 2, we want some number which is (2 ** i) * (6 ** j)
200 // which gives a nice range of results
201 uint64_t oval = val;
202 int i = 0, j = 0;
203 if (!nxttab_inited) make_nxttab();
206 if (val & 1) {
207 if (less) val--;
208 else val++;
209 }
210 for (; !(val % 6) && val > 0; j++, val /= 6);
212 for (; val > 1; i++, val /= 2) {
213 if (val & 1) {
214 if (less) val--;
215 else val++;
216 }
217 }
218 val = nxttbl[i][j].value;
219 if (less) {
220 if (val == oval) {
221 if (nxttbl[i][j].lower) val = nxttbl[i][j].lower->value;
222 } else {
223 while (nxttbl[i][j].higher->value < oval) {
224 int xi = nxttbl[i][j].higher->i;
225 val = nxttbl[i][j].value;
226 j = nxttbl[i][j].higher->j;
227 i = xi;
228 }
229 }
230 return val > lim ? val : lim;
231 }
232 if (val == oval) {
233 if (nxttbl[i][j].higher) val = nxttbl[i][j].higher->value;
234 } else {
235 while (nxttbl[i][j].lower && nxttbl[i][j].lower->value > oval) {
236 int xi = nxttbl[i][j].lower->i;
237 j = nxttbl[i][j].lower->j;
238 i = xi;
239 val = nxttbl[i][j].value;
240 }
241 }
242 return val < lim ? val : lim;
243}
244
245
246static const char *get_tunert(int idx) {
247 switch (idx) {
248 case 2: return "orc_memcpy cutoff";
249 case 3: return "read buffer size (small)";
250 case 4: return "read buffer size (small / medium)";
251 case 5: return "read buffer size (medium)";
252 case 6: return "read buffer size (large)";
253 default: break;
254 }
255 return "unknown variable";
256}
257
258
259uint64_t autotune_u64_end(weed_plant_t **tuner, uint64_t val) {
260 if (!tuner || !*tuner) return val;
261 else {
263 int ntrials, trials;
264 int64_t max;
265 int64_t min = weed_get_int64_value(*tuner, "min", NULL);
266
267 if (val < min) {
268 val = min;
269 weed_set_int_value(*tuner, "trials", 0);
270 weed_set_int64_value(*tuner, "tottime", 0);
271 weed_set_double_value(*tuner, "tcost", 0);
272 return val;
273 }
274 max = weed_get_int64_value(*tuner, "max", NULL);
275 if (val > max) {
276 val = max;
277 weed_set_int_value(*tuner, "trials", 0);
278 weed_set_int64_value(*tuner, "tottime", 0);
279 weed_set_double_value(*tuner, "tcost", 0);
280 return val;
281 }
282
283 ntrials = weed_get_int_value(*tuner, "ntrials", NULL);
284 trials = weed_get_int_value(*tuner, "trials", NULL);
285
286 weed_set_int_value(*tuner, "trials", ++trials);
287 tottime += (weed_get_int64_value(*tuner, "tottime", NULL)) - weed_get_int64_value(*tuner, "tstart", NULL);
288 weed_set_int64_value(*tuner, "tottime", tottime);
289
290 if (trials >= ntrials) {
291 int cycs = weed_get_int_value(*tuner, "cycles", NULL) + 1;
292 if (cycs < NCYCS) {
293 double tcost = (double)weed_get_double_value(*tuner, "tcost", NULL);
294 double totcost = (double)tottime * tcost;
295 double avcost = totcost / (double)(cycs * ntrials);
296 double ccosts, ccostl;
297 boolean smfirst = FALSE;
298 char *key1 = lives_strdup_printf("tottrials_%lu", val);
299 char *key2 = lives_strdup_printf("totcost_%lu", val);
300
301 weed_set_int_value(*tuner, key1, weed_get_int_value(*tuner, key1, NULL) + trials);
302 weed_set_double_value(*tuner, key2, weed_get_double_value(*tuner, key2, NULL) + totcost);
303
304 lives_free(key1);
305 lives_free(key2);
306
307 if (cycs & 1) smfirst = TRUE;
308 weed_set_int_value(*tuner, "cycles", cycs);
309
310 weed_set_int_value(*tuner, "trials", 0);
311 weed_set_int64_value(*tuner, "tottime", 0);
312 weed_set_double_value(*tuner, "tcost", 0);
313
314 if (smfirst) {
315 if (val > max || weed_plant_has_leaf(*tuner, "smaller")) {
316 ccosts = weed_get_double_value(*tuner, "smaller", NULL);
317 if (val > max || (ccosts < avcost)) {
318 weed_set_double_value(*tuner, "larger", avcost);
319 weed_leaf_delete(*tuner, "smaller");
320 if (val > max) return max;
321 return nxtval(val, min, TRUE); // TRUE to get smaller val
322 }
323 }
324 }
325
326 if (val < min || weed_plant_has_leaf(*tuner, "larger")) {
327 ccostl = weed_get_double_value(*tuner, "larger", NULL);
328 if (val < min || (ccostl < avcost)) {
329 weed_set_double_value(*tuner, "smaller", avcost);
330 weed_leaf_delete(*tuner, "larger");
331 if (val < min) return min;
332 return nxtval(val, max, FALSE);
333 }
334 }
335
336 if (!smfirst) {
337 if (val > max || weed_plant_has_leaf(*tuner, "smaller")) {
338 ccosts = weed_get_double_value(*tuner, "smaller", NULL);
339 if (val > max || (ccosts < avcost)) {
340 weed_set_double_value(*tuner, "larger", avcost);
341 weed_leaf_delete(*tuner, "smaller");
342 if (val > max) return max;
343 return nxtval(val, min, TRUE);
344 }
345 }
346
347 if (!weed_plant_has_leaf(*tuner, "larger")) {
348 weed_set_double_value(*tuner, "smaller", avcost);
349 weed_leaf_delete(*tuner, "larger");
350 return nxtval(val, max, FALSE);
351 }
352 }
353
354 if (!weed_plant_has_leaf(*tuner, "smaller")) {
355 weed_set_double_value(*tuner, "larger", avcost);
356 weed_leaf_delete(*tuner, "smaller");
357 return nxtval(val, min, TRUE);
358 }
359
360 if (smfirst) {
361 if (!weed_plant_has_leaf(*tuner, "larger")) {
362 weed_set_double_value(*tuner, "smaller", avcost);
363 weed_leaf_delete(*tuner, "larger");
364 return nxtval(val, max, FALSE);
365 }
366 }
367
368 weed_leaf_delete(*tuner, "smaller");
369 weed_leaf_delete(*tuner, "larger");
370 if (!smfirst) {
371 return nxtval(nxtval(val, max, FALSE), max, FALSE);
372 } else {
373 return nxtval(nxtval(val, min, TRUE), min, TRUE);
374 }
375 } else {
376 weed_size_t nleaves;
377 char **res = weed_plant_list_leaves(*tuner, &nleaves);
378 uint64_t bestval = val, xval;
379 const char *key1 = "totcost_";
380 char *key2;
381 double avcost, costmin = 0.;
382 boolean gotcost = FALSE;
383 int j;
384
385 for (int i = 1; i < nleaves; i++) {
386 if (!strncmp(res[i], key1, 8)) {
387 xval = strtoul((const char *)(res[i] + 8), NULL, 10);
388 key2 = lives_strdup_printf("totrials_%lu", xval);
389 for (j = i + 1; j < nleaves; j++) {
390 if (!strcmp(res[j], key2)) break;
391 }
392 if (j == nleaves) {
393 for (j = 0; j < i; j++) {
394 if (!strcmp(res[j], key2)) break;
395 }
396 }
397 if ((avcost = weed_get_double_value(*tuner, res[i], NULL)
398 / (double)weed_get_int_value(*tuner, res[j], NULL)) < costmin
399 || !gotcost) {
400 costmin = avcost;
401 bestval = xval;
402 gotcost = TRUE;
403 }
404 lives_free(key2);
405 }
406 }
407 val = bestval;
408 if (prefs->show_dev_opts)
409 g_printerr("value of %s tuned to %lu\n",
410 get_tunert(weed_get_int64_value(*tuner, WEED_LEAF_INDEX, NULL)), val);
411 // TODO: store value so we can recalibrate again later
412 //tuned = (struct tuna *)lives_malloc(sizeof(tuna));
413 //tuna->wptpp = tuner;
414 //tuna->id = weed_get_in
415 //lives_list_prepend(tunables, tuned);
416 weed_plant_free(*tuner);
417 *tuner = NULL;
418 for (j = 0; j < nleaves; lives_free(res[j++]));
419 lives_free(res);
420 }
421 return val;
422 }
423 weed_set_int64_value(*tuner, "tottime", tottime);
424 }
425 return val;
426}
427
428
430#define OIL_MEMCPY_MAX_BYTES 12288 // this can be tuned to provide optimal performance
431
432#ifdef ENABLE_ORC
433livespointer lives_orc_memcpy(livespointer dest, livesconstpointer src, size_t n) {
434 static size_t maxbytes = OIL_MEMCPY_MAX_BYTES;
435 static weed_plant_t *tuner = NULL;
436 static boolean tuned = FALSE;
437 static pthread_mutex_t tuner_mutex = PTHREAD_MUTEX_INITIALIZER;
438 boolean haslock = FALSE;
439 if (n == 0) return dest;
440 if (n < 32) return memcpy(dest, src, n);
441
443 if (!tuned && !tuner) tuner = lives_plant_new_with_index(LIVES_WEED_SUBTYPE_TUNABLE, 2);
444 if (tuner) {
445 if (!pthread_mutex_trylock(&tuner_mutex)) {
446 haslock = TRUE;
447 }
448 }
449 }
450
451 if (maxbytes > 0 ? n <= maxbytes : n >= -maxbytes) {
464 if (haslock) autotune_u64(tuner, -1024 * 1024, 1024 * 1024, 32, 1. / (double)n);
465 orc_memcpy((uint8_t *)dest, (const uint8_t *)src, n);
466
467 if (haslock) {
468 maxbytes = autotune_u64_end(&tuner, maxbytes);
469 if (!tuner) tuned = TRUE;
470 pthread_mutex_unlock(&tuner_mutex);
471 }
472 return dest;
473 }
474 if (haslock) autotune_u64(tuner, -1024 * 1024, 1024 * 1024, 128, -1. / (double)n);
475 memcpy(dest, src, n);
476 if (haslock) {
477 maxbytes = autotune_u64_end(&tuner, maxbytes);
478 if (!tuner) tuned = TRUE;
479 pthread_mutex_unlock(&tuner_mutex);
480 }
481 return dest;
482}
483#endif
484
485
486#ifdef ENABLE_OIL
487livespointer lives_oil_memcpy(livespointer dest, livesconstpointer src, size_t n) {
488 static size_t maxbytes = OIL_MEMCPY_MAX_BYTES;
489 static weed_plant_t *tuner = NULL;
490 static boolean tuned = FALSE;
491 static pthread_mutex_t tuner_mutex = PTHREAD_MUTEX_INITIALIZER;
492 boolean haslock = FALSE;
493 if (n == 0) return dest;
494 if (n < 32) return memcpy(dest, src, n);
495
497 if (!tuned && !tuner) tuner = lives_plant_new_with_index(LIVES_WEED_SUBTYPE_TUNABLE, 2);
498 if (tuner) {
499 if (!pthread_mutex_trylock(&tuner_mutex)) {
500 haslock = TRUE;
501 }
502 }
503 }
504
505 if (maxbytes > 0 ? n <= maxbytes : n >= -maxbytes) {
506 if (haslock) autotune_u64(tuner, -1024 * 1024, 1024 * 1024, 32, 1. / (double)n);
507 oil_memcpy((uint8_t *)dest, (const uint8_t *)src, n);
508
509 if (haslock) {
510 maxbytes = autotune_u64_end(&tuner, maxbytes);
511 if (!tuner) tuned = TRUE;
512 pthread_mutex_unlock(&tuner_mutex);
513 }
514 return dest;
515 }
516 if (haslock) autotune_u64(tuner, -1024 * 1024, 1024 * 1024, 128, -1. / (double)n);
517 memcpy(dest, src, n);
518 if (haslock) {
519 maxbytes = autotune_u64_end(&tuner, maxbytes);
520 if (!tuner) tuned = TRUE;
521 pthread_mutex_unlock(&tuner_mutex);
522 }
523 return dest;
524}
525#endif
526
527#define _cpy_if_nonnull(d, s, size) (d ? lives_memcpy(d, s, size) : d)
528
529// functions with fixed pointers that we can pass to plugins ///
530void *_ext_malloc(size_t n) {
531#ifdef USE_RPMALLOC
532 return rpmalloc(n);
533#else
534 return (n == 0 ? NULL : lives_malloc(n));
535#endif
536}
537
538
539void *_ext_malloc_and_copy(size_t bsize, const void *block) {
540 if (!block || bsize == 0) return NULL;
541#ifdef lives_malloc_and_copy
542 return lives_malloc_and_copy(bsize, block);
543#endif
544 return (_cpy_if_nonnull(malloc(bsize), block, bsize));
545}
546
547void _ext_unmalloc_and_copy(size_t bsize, void *p) {
548 if (!p || bsize == 0) return;
549#ifdef lives_unmalloc_and_copy
550 lives_unmalloc_and_copy(bsize, p);
551#else
552 _ext_free(p);
553#endif
554}
555
556void _ext_free(void *p) {
557#ifdef USE_RPMALLOC
558 rpfree(p);
559#else
560 if (p) lives_free(p);
561#endif
562}
563
564
565void *_ext_free_and_return(void *p) {_ext_free(p); return NULL;}
566
567void *_ext_memcpy(void *dest, const void *src, size_t n) {return lives_memcpy(dest, src, n);}
568
569int _ext_memcmp(const void *s1, const void *s2, size_t n) {return lives_memcmp(s1, s2, n);}
570
571void *_ext_memset(void *p, int i, size_t n) {return lives_memset(p, i, n);}
572
573void *_ext_memmove(void *dest, const void *src, size_t n) {return lives_memmove(dest, src, n);}
574
575void *_ext_realloc(void *p, size_t n) {
576#ifdef USE_RPMALLOC
577 return rprealloc(p, n);
578#else
579 return lives_realloc(p, n);
580}
581#endif
582}
583
584void *_ext_calloc(size_t nmemb, size_t msize) {
585#ifdef USE_RPMALLOC
586 return quick_calloc(nmemb, msize);
587#else
588 return lives_calloc(nmemb, msize);
589}
590#endif
591}
592
593LIVES_GLOBAL_INLINE void *lives_free_and_return(void *p) {lives_free(p); return NULL;}
594
595
596LIVES_GLOBAL_INLINE size_t get_max_align(size_t req_size, size_t align_max) {
597 size_t align = 1;
598 while (align < align_max && !(req_size & align)) align *= 2;
599 return align;
600}
601
602
603LIVES_GLOBAL_INLINE void *lives_calloc_safety(size_t nmemb, size_t xsize) {
604 void *p;
605 size_t totsize = nmemb * xsize;
606 if (!totsize) return NULL;
607 if (xsize < DEF_ALIGN) {
608 xsize = DEF_ALIGN;
609 nmemb = (totsize / xsize) + 1;
610 }
611 p = __builtin_assume_aligned(lives_calloc(nmemb + (EXTRA_BYTES / xsize), xsize), DEF_ALIGN);
612 return p;
613}
614
615LIVES_GLOBAL_INLINE void *lives_recalloc(void *p, size_t nmemb, size_t omemb, size_t xsize) {
618 void *np = __builtin_assume_aligned(lives_calloc_safety(nmemb, xsize), DEF_ALIGN);
619 void *op = __builtin_assume_aligned(p, DEF_ALIGN);
620 if (omemb > nmemb) omemb = nmemb;
621 lives_memcpy(np, op, omemb * xsize);
622 lives_free(p);
623 return np;
624}
625
626void quick_free(void *p) {rpfree(p);}
627
628void *quick_calloc(size_t n, size_t s) {return rpaligned_calloc(DEF_ALIGN, n, s);}
629
630boolean init_memfuncs(void) {
631#ifdef USE_RPMALLOC
633#endif
634 return TRUE;
635}
636
637
638boolean init_thread_memfuncs(void) {
639#ifdef USE_RPMALLOC
641#endif
642 return TRUE;
643}
644
645
646char *get_md5sum(const char *filename) {
648 char **array;
649 char *md5;
650 char *com = lives_strdup_printf("%s \"%s\"", EXEC_MD5SUM, filename);
652 lives_free(com);
653 if (THREADVAR(com_failed)) {
654 THREADVAR(com_failed) = FALSE;
655 return NULL;
656 }
657 array = lives_strsplit(mainw->msg, " ", 2);
658 md5 = lives_strdup(array[0]);
659 lives_strfreev(array);
660 return md5;
661}
662
663
665 char *fmt;
666
667 if (space >= lives_10pow(18)) {
668 // TRANSLATORS: Exabytes
669 fmt = lives_strdup_printf(_("%.2f EB"), (double)space / (double)lives_10pow(18));
670 } else if (space >= lives_10pow(15)) {
671 // TRANSLATORS: Petabytes
672 fmt = lives_strdup_printf(_("%.2f PB"), (double)space / (double)lives_10pow(15));
673 } else if (space >= lives_10pow(12)) {
674 // TRANSLATORS: Terabytes
675 fmt = lives_strdup_printf(_("%.2f TB"), (double)space / (double)lives_10pow(12));
676 } else if (space >= lives_10pow(9)) {
677 // TRANSLATORS: Gigabytes
678 fmt = lives_strdup_printf(_("%.2f GB"), (double)space / (double)lives_10pow(9));
679 } else if (space >= lives_10pow(6)) {
680 // TRANSLATORS: Megabytes
681 fmt = lives_strdup_printf(_("%.2f MB"), (double)space / (double)lives_10pow(6));
682 } else if (space >= 1024) {
683 // TRANSLATORS: Kilobytes (1024 bytes)
684 fmt = lives_strdup_printf(_("%.2f KiB"), (double)space / 1024.);
685 } else {
686 fmt = lives_strdup_printf(_("%d bytes"), space);
687 }
688
689 return fmt;
690}
691
692
693lives_storage_status_t get_storage_status(const char *dir, uint64_t warn_level, int64_t *dsval, int64_t ds_resvd) {
694 // WARNING: this will actually create the directory (since we dont know if its parents are needed)
695 // call with dsval set to ds_used to check for OVER_QUOTA
696 // dsval is overwritten and set to ds_free
697 int64_t ds;
699 if (dsval && prefs->disk_quota > 0 && *dsval > (int64_t)((double)prefs->disk_quota * prefs->quota_limit / 100.))
701 if (!is_writeable_dir(dir)) return status;
702 ds = (int64_t)get_ds_free(dir);
703 ds -= ds_resvd;
704 if (dsval) *dsval = ds;
705 if (ds <= 0) return LIVES_STORAGE_STATUS_OVERFLOW;
706 if (ds < prefs->ds_crit_level) return LIVES_STORAGE_STATUS_CRITICAL;
707 if (status != LIVES_STORAGE_STATUS_UNKNOWN) return status;
708 if (ds < warn_level) return LIVES_STORAGE_STATUS_WARNING;
710}
711
712static lives_proc_thread_t running = NULL;
713static char *running_for = NULL;
714
715boolean disk_monitor_running(const char *dir) {return (running != NULL && (!dir || !lives_strcmp(dir, running_for)));}
716
720 dir);
722 running_for = lives_strdup(dir);
723 return running;
724}
725
726int64_t disk_monitor_check_result(const char *dir) {
727 // caller MUST check if mainw->ds_valid is TRUE, or recheck the results
728 int64_t bytes;
730 if (!lives_strcmp(dir, running_for)) {
731 if (!lives_proc_thread_check(running)) {
732 return -1;
733 }
734 bytes = lives_proc_thread_join_int64(running);
735 lives_proc_thread_free(running);
736 running = NULL;
737 } else bytes = (int64_t)get_dir_size(dir);
738 return bytes;
739}
740
741
742LIVES_GLOBAL_INLINE int64_t disk_monitor_wait_result(const char *dir, ticks_t timeout) {
743 // caller MUST check if mainw->ds_valid is TRUE, or recheck the results
744 lives_alarm_t alarm_handle = LIVES_NO_ALARM;
745 int64_t dsval;
746
747 if (*running_for && !lives_strcmp(dir, running_for)) {
748 if (timeout) return -1;
749 return get_dir_size(dir);
750 }
751
752 if (timeout < 0) timeout = LIVES_LONGEST_TIMEOUT;
753 if (timeout > 0) alarm_handle = lives_alarm_set(timeout);
754
755 while ((dsval = disk_monitor_check_result(dir)) < 0
756 && (alarm_handle == LIVES_NO_ALARM || ((timeout = lives_alarm_check(alarm_handle)) > 0))) {
757 lives_nanosleep(1000);
758 }
759 if (alarm_handle != LIVES_NO_ALARM) {
760 lives_alarm_clear(alarm_handle);
761 if (!timeout) {
763 return -1;
764 }
765 }
766 return dsval;
767}
768
770 if (!disk_monitor_running(NULL)) return;
772 running = NULL;
773}
774
775
776uint64_t get_ds_free(const char *dir) {
777 // get free space in bytes for volume containing directory dir
778 // return 0 if we cannot create/write to dir
779
780 // caller should test with is_writeable_dir() first before calling this
781 // since 0 is a valid return value
782
783 // dir should be in locale encoding
784
785 // WARNING: this may temporarily create the directory (since we dont know if its parents are needed)
786
787 struct statvfs sbuf;
788
789 uint64_t bytes = 0;
790 boolean must_delete = FALSE;
791
792 if (!lives_file_test(dir, LIVES_FILE_TEST_IS_DIR)) must_delete = TRUE;
793 if (!is_writeable_dir(dir)) goto getfserr;
794
795 // use statvfs to get fs details
796 if (statvfs(dir, &sbuf) == -1) goto getfserr;
797 if (sbuf.f_flag & ST_RDONLY) goto getfserr;
798
799 // result is block size * blocks available
800 bytes = sbuf.f_bsize * sbuf.f_bavail;
801 if (!strcmp(dir, prefs->workdir)) {
802 capable->ds_free = bytes;
803 capable->ds_tot = sbuf.f_bsize * sbuf.f_blocks;
804 }
805
806getfserr:
807 if (must_delete) lives_rmdir(dir, FALSE);
808
809 return bytes;
810}
811
812
814 ticks_t ret = -1;
815#if _POSIX_TIMERS
816 struct timespec ts;
817 clock_gettime(CLOCK_MONOTONIC, &ts);
818 ret = ((ts.tv_sec * ONE_BILLION + ts.tv_nsec) - (origsecs * ONE_BILLION + orignsecs)) / TICKS_TO_NANOSEC;
819#else
820#ifdef USE_MONOTONIC_TIME
821 ret = (lives_get_monotonic_time() - orignsecs) / 10;
822#else
823 struct timeval tv;
824 gettimeofday(&tv, NULL);
825 ret = ((tv.tv_sec * ONE_MILLLION + tv.tv_usec) - (origsecs * ONE_MILLION + orignsecs / 1000)) * USEC_TO_TICKS;
826#endif
827#endif
828 mainw->wall_ticks = ret;
829 if (ret >= 0)
830 mainw->wall_ticks += (origsecs * ONE_BILLION + orignsecs) / TICKS_TO_NANOSEC;
831 return ret;
832}
833
834
836 // return current (wallclock) time in ticks (units of 10 nanoseconds)
837 return lives_get_relative_ticks(0, 0);
838}
839
840
841#define SECS_IN_DAY 86400
842char *lives_datetime_rel(const char *datetime) {
844 char *dtxt;
845 char *today = NULL, *yesterday = NULL;
846 struct timeval otv;
847 gettimeofday(&otv, NULL);
848 today = lives_datetime(otv.tv_sec, TRUE);
849 yesterday = lives_datetime(otv.tv_sec - SECS_IN_DAY, TRUE);
850 if (!lives_strncmp(datetime, today, 10)) dtxt = lives_strdup_printf(_("Today %s"), datetime + 11);
851 else if (!lives_strncmp(datetime, yesterday, 10))
852 dtxt = lives_strdup_printf(_("Yesterday %s"), datetime + 11);
853 else dtxt = (char *)datetime;
854 if (today) lives_free(today);
855 if (yesterday) lives_free(yesterday);
856 return dtxt;
857}
858
859
860char *lives_datetime(uint64_t secs, boolean use_local) {
861 char buf[128];
862 char *datetime = NULL;
863 struct tm *gm = use_local ? localtime((time_t *)&secs) : gmtime((time_t *)&secs);
864 ssize_t written;
865
866 if (gm) {
867 written = (ssize_t)strftime(buf, 128, "%Y-%m-%d %H:%M:%S", gm);
868 if ((written > 0) && ((size_t)written < 128)) {
869 datetime = lives_strdup(buf);
870 }
871 }
872 return datetime;
873}
874
875
876boolean check_dev_busy(char *devstr) {
877 int ret;
878#ifdef IS_SOLARIS
879 struct flock lock;
880 lock.l_start = 0;
881 lock.l_whence = SEEK_SET;
882 lock.l_len = 0;
883 lock.l_type = F_WRLCK;
884#endif
885 int fd = open(devstr, O_RDONLY | O_NONBLOCK);
886 if (fd == -1) return FALSE;
887#ifdef IS_SOLARIS
888 ret = fcntl(fd, F_SETLK, &lock);
889#else
890 ret = flock(fd, LOCK_EX | LOCK_NB);
891#endif
892 close(fd);
893 if (ret == -1) return FALSE;
894 return TRUE;
895}
896
897
898boolean compress_files_in_dir(const char *dir, int method, void *data) {
902
905 char buff[65536];
906 char *com, *cwd;
907 boolean retval = FALSE;
908
910 if (lives_file_test(dir, LIVES_FILE_TEST_IS_DIR)) {
911 boolean needs_norem = FALSE;
912 char *norem = lives_build_filename(dir, LIVES_FILENAME_NOREMOVE, NULL);
913 if (lives_file_test(norem, LIVES_FILE_TEST_EXISTS)) {
914 needs_norem = TRUE;
915 lives_rm(norem);
916 }
917 cwd = lives_get_current_dir();
918 THREADVAR(chdir_failed) = FALSE;
919 lives_chdir(dir, TRUE);
920 if (THREADVAR(chdir_failed)) {
921 THREADVAR(chdir_failed) = FALSE;
922 lives_chdir(cwd, TRUE);
923 lives_free(cwd);
924 lives_free(norem);
925 return FALSE;
926 }
927 com = lives_strdup_printf("%s * 2>&1", EXEC_GZIP);
928 lives_popen(com, TRUE, buff, 65536);
929 lives_free(com);
930 if (THREADVAR(com_failed)) THREADVAR(com_failed) = FALSE;
931 else retval = TRUE;
932 lives_chdir(cwd, TRUE);
933 lives_free(cwd);
934 if (needs_norem) {
935 lives_touch(norem);
936 lives_free(norem);
937 }
938 }
939 return retval;
940}
941
942
943off_t get_file_size(int fd) {
944 // get the size of file fd
945 struct stat filestat;
946 off_t fsize;
947 lives_file_buffer_t *fbuff;
948 fstat(fd, &filestat);
949 fsize = filestat.st_size;
950 //g_printerr("fssize for %d is %ld\n", fd, fsize);
951 if ((fbuff = find_in_file_buffers(fd)) != NULL) {
952 if (!fbuff->read) {
954 off_t f2size;
955 if ((f2size = (off_t)(fbuff->offset + fbuff->bytes)) > fsize) return f2size;
956 }
957 }
958 return fsize;
959}
960
961
962off_t sget_file_size(const char *name) {
963 off_t res;
964 struct stat xstat;
965 if (!name) return 0;
966 res = stat(name, &xstat);
967 if (res < 0) return res;
968 return xstat.st_size;
969}
970
971
972void reget_afilesize(int fileno) {
973 // re-get the audio file size
974 lives_clip_t *sfile = mainw->files[fileno];
975 boolean bad_header = FALSE;
976
977 if (mainw->multitrack) return; // otherwise achans gets set to 0...
978
979 sfile->afilesize = reget_afilesize_inner(fileno);
980
981 if (sfile->afilesize == 0l) {
982 if (!sfile->opening && fileno != mainw->ascrap_file && fileno != mainw->scrap_file) {
983 if (sfile->arate != 0 || sfile->achans != 0 || sfile->asampsize != 0 || sfile->arps != 0) {
984 sfile->arate = sfile->achans = sfile->asampsize = sfile->arps = 0;
985 if (!save_clip_value(fileno, CLIP_DETAILS_ACHANS, &sfile->achans)) bad_header = TRUE;
986 if (!save_clip_value(fileno, CLIP_DETAILS_ARATE, &sfile->arps)) bad_header = TRUE;
987 if (!save_clip_value(fileno, CLIP_DETAILS_PB_ARATE, &sfile->arate)) bad_header = TRUE;
988 if (!save_clip_value(fileno, CLIP_DETAILS_ASAMPS, &sfile->asampsize)) bad_header = TRUE;
989 if (bad_header) do_header_write_error(fileno);
990 }
991 }
992 }
993
994 if (mainw->is_ready && fileno > 0 && fileno == mainw->current_file) {
995 // force a redraw
997 }
998}
999
1000
1001off_t reget_afilesize_inner(int fileno) {
1002 // safe version that just returns the audio file size
1003 off_t filesize;
1004 char *afile = lives_get_audio_file_name(fileno);
1005 lives_sync(1);
1006 filesize = sget_file_size(afile);
1007 lives_free(afile);
1008 if (filesize < 0) filesize = 0;
1009 return filesize;
1010}
1011
1012
1013boolean is_empty_dir(const char *dirname) {
1014 DIR *tldir;
1015 struct dirent *tdirent;
1016 boolean empty = TRUE;
1017 if (!dirname) return TRUE;
1018 tldir = opendir(dirname);
1019 if (!tldir) return FALSE;
1020 while (empty && (tdirent = readdir(tldir))) {
1021 if (tdirent->d_name[0] == '.'
1022 && (!tdirent->d_name[1] || tdirent->d_name[1] == '.')) continue;
1023 empty = FALSE;
1024 }
1025 closedir(tldir);
1026 return empty;
1027}
1028
1029
1030char *get_mountpoint_for(const char *dir) {
1031 char *mp = NULL, *tmp, *com, *res;
1032 size_t lmatch = 0, slen;
1033 int j;
1034
1035 if (!dir) return NULL;
1036 slen = lives_strlen(dir);
1037
1038 com = lives_strdup("df -P");
1039 if ((res = mini_popen(com))) {
1040 int lcount = get_token_count(res, '\n');
1041 char **array0 = lives_strsplit(res, "\n", lcount);
1042 for (int l = 0; l < lcount; l++) {
1043 int pccount = get_token_count(array0[l], ' ');
1044 char **array1 = lives_strsplit(array0[l], " ", pccount);
1045 lives_chomp(array1[pccount - 1]);
1046 for (j = 0; array1[pccount - 1][j] && j < slen; j++) if (array1[pccount - 1][j] != dir[j]) break;
1047 if (j > lmatch && !array1[pccount - 1][j]) {
1048 lmatch = j;
1049 if (mp) lives_free(mp);
1050 tmp = lives_strdup(array1[0]);
1051 mp = lives_filename_to_utf8(tmp, -1, NULL, NULL, NULL);
1052 lives_free(tmp);
1053 }
1054 lives_strfreev(array1);
1055 }
1056 lives_strfreev(array0);
1057 lives_free(res);
1058 }
1059 return mp;
1060}
1061
1062
1063#ifdef IS_FREEBSD
1064#define DU_BLOCKSIZE 1024
1065#else
1066#define DU_BLOCKSIZE 1
1067#endif
1068
1069off_t get_dir_size(const char *dirname) {
1070 off_t dirsize = -1;
1071 if (!dirname || !*dirname || !lives_file_test(dirname, LIVES_FILE_TEST_IS_DIR)) return -1;
1073 char buff[PATH_MAX * 2];
1074 char *com = lives_strdup_printf("%s -sB %d \"%s\"", EXEC_DU, DU_BLOCKSIZE, dirname);
1075 lives_popen(com, TRUE, buff, PATH_MAX * 2);
1076 lives_free(com);
1077 if (THREADVAR(com_failed)) THREADVAR(com_failed) = FALSE;
1078 else dirsize = atol(buff) / DU_BLOCKSIZE;
1079 }
1080 return dirsize;
1081}
1082
1083
1084void free_fdets_list(LiVESList **listp) {
1085 LiVESList *list = *listp;
1086 lives_file_dets_t *filedets;
1087 for (; list && list->data; list = list->next) {
1088 filedets = (lives_file_dets_t *)list->data;
1089 lives_struct_free(filedets->lsd);
1090 list->data = NULL;
1091 }
1092 if (*listp) {
1093 lives_list_free(*listp);
1094 *listp = NULL;
1095 }
1096}
1097
1098
1099int stat_to_file_dets(const char *fname, lives_file_dets_t *fdets) {
1100 struct stat filestat;
1101 int ret = stat(fname, &filestat);
1102 if (ret) {
1103 if (prefs->show_dev_opts) {
1104 char *msg = lives_strdup_printf("\nstat failed for file %s\n", fname);
1105 perror(msg);
1106 lives_free(msg);
1107 }
1108 fdets->size = -2;
1110 return ret;
1111 }
1112 fdets->type = (uint64_t)((filestat.st_mode & S_IFMT) >> 12);
1113 fdets->size = filestat.st_size;
1114 fdets->mode = (uint64_t)(filestat.st_mode & 0x0FFF);
1115 fdets->uid = filestat.st_uid;
1116 fdets->gid = filestat.st_gid;
1117 fdets->blk_size = (uint64_t)filestat.st_blksize;
1118 fdets->atime_sec = filestat.st_atim.tv_sec;
1119 fdets->atime_nsec = filestat.st_atim.tv_nsec;
1120 fdets->mtime_sec = filestat.st_mtim.tv_sec;
1121 fdets->mtime_nsec = filestat.st_mtim.tv_nsec;
1122 fdets->ctime_sec = filestat.st_ctim.tv_sec;
1123 fdets->ctime_nsec = filestat.st_ctim.tv_nsec;
1124 return ret;
1125}
1126
1127
1128static char *file_to_file_details(const char *filename, lives_file_dets_t *fdets, lives_proc_thread_t tinfo, uint64_t extra) {
1129 char *tmp, *tmp2;
1130 char *extra_details = lives_strdup("");
1131
1132 if (!stat_to_file_dets(filename, fdets)) {
1133 // if stat fails, we have set set size to -2, type to LIVES_FILE_TYPE_UNKNOWN
1134 // and here we set extra_details to ""
1135 if (tinfo && lives_proc_thread_cancelled(tinfo)) {
1136 lives_free(extra_details);
1137 return NULL;
1138 }
1139 if (LIVES_FILE_IS_DIRECTORY(fdets->type)) {
1140 boolean emptyd = FALSE;
1141 if (extra & EXTRA_DETAILS_EMPTY_DIRS) {
1142 if ((emptyd = is_empty_dir(filename))) {
1144 tmp2 = lives_strdup_printf("%s%s%s", extra_details, *extra_details ? ", " : "",
1145 (tmp = _("(empty)")));
1146 lives_free(tmp);
1147 lives_free(extra_details);
1148 extra_details = tmp2;
1149 }
1150 if (tinfo && lives_proc_thread_cancelled(tinfo)) {
1151 lives_free(extra_details);
1152 return NULL;
1153 }
1154 }
1155 if ((extra & EXTRA_DETAILS_DIRSIZE) &&
1157 && !emptyd && fdets->type == LIVES_FILE_TYPE_DIRECTORY) {
1158 fdets->size = get_dir_size(filename);
1159 }
1160
1161 if (!emptyd && (extra & EXTRA_DETAILS_CLIPHDR)) {
1162 int clipno;
1163
1164 clipno = create_nullvideo_clip("tmp");
1165
1166 if (clipno && IS_VALID_CLIP(clipno)) {
1167 if (read_headers(clipno, filename, NULL)) {
1168 lives_clip_t *sfile = mainw->files[clipno];
1169 char *name = lives_strdup(sfile->name);
1170 extra_details =
1171 lives_strdup_printf("%s%s%s", extra_details, *extra_details ? ", " : "",
1172 (tmp = lives_strdup_printf
1173 (_("Source: %s, frames: %d, size: %d X %d, fps: %.3f"),
1174 name, sfile->frames, sfile->hsize,
1175 sfile->vsize, sfile->fps)));
1176 lives_free(tmp);
1177 lives_free(name);
1178 lives_freep((void **)&mainw->files[clipno]);
1179 if (mainw->first_free_file == ALL_USED || mainw->first_free_file > clipno)
1180 mainw->first_free_file = clipno;
1181 }
1183 // *INDENT-OFF*
1184 }}}
1185 if (extra & EXTRA_DETAILS_MD5SUM) {
1186 fdets->md5sum = get_md5sum(filename);
1187 }
1188 if (extra & EXTRA_DETAILS_SYMLINK) {
1189 if (lives_file_test(filename, LIVES_FILE_TEST_IS_SYMLINK))
1191 }
1192 if (extra & EXTRA_DETAILS_EXECUTABLE) {
1193 if (lives_file_test(filename, LIVES_FILE_TEST_IS_EXECUTABLE))
1195 }
1197 /* if (extra & EXTRA_DETAILS_WRITEABLE) { */
1198 /* if (LIVES_FILE_TEST_IS_EXECUTABLE(filename)) fdets->type |= LIVES_FILE_TYPE_FLAG_EXECUTABLE; */
1199 /* } */
1200 /* if (extra & EXTRA_DETAILS_ACCESSIBLE) { */
1201 /* if (LIVES_FILE_TEST_IS_EXECUTABLE(filename)) fdets->type |= LIVES_FILE_TYPE_FLAG_EXECUTABLE; */
1202 /* } */
1203 }
1204 // *INDENT-ON*
1205 else {
1207 if (extra & EXTRA_DETAILS_CHECK_MISSING) {
1208 if (!lives_file_test(filename, LIVES_FILE_TEST_EXISTS)) {
1210 tmp2 = lives_strdup_printf("%s%s%s", extra_details, *extra_details ? ", " : "",
1211 (tmp = _("(ABSENT)")));
1212 lives_free(tmp);
1213 lives_free(extra_details);
1214 extra_details = tmp2;
1215 }
1216 }
1217 }
1218 return extra_details;
1219}
1220
1221
1227void *_item_to_file_details(LiVESList **listp, const char *item,
1228 const char *orig_loc, uint64_t extra, int type) {
1229 // type 0 = dir
1230 // type 1 = ordfile
1231 lives_file_dets_t *fdets;
1232 lives_proc_thread_t tinfo = NULL;
1233 LiVESList *list;
1234 char *extra_details;
1235 const char *dir = NULL;
1236 char *subdirname;
1237 boolean empty = TRUE;
1238
1239 tinfo = THREADVAR(tinfo);
1240 if (tinfo) lives_proc_thread_set_cancellable(tinfo);
1241
1242 switch (type) {
1243 case 0: {
1244 DIR *tldir;
1245 struct dirent *tdirent;
1246 // dir
1247 dir = item;
1248 if (!dir) return NULL;
1249 tldir = opendir(dir);
1250 if (!tldir) {
1251 *listp = lives_list_append(*listp, NULL);
1252 return NULL;
1253 }
1254
1255 while (1) {
1256 tdirent = readdir(tldir);
1257 if (lives_proc_thread_cancelled(tinfo) || !tdirent) {
1258 closedir(tldir);
1259 if (lives_proc_thread_cancelled(tinfo)) return NULL;
1260 break;
1261 }
1262 if (tdirent->d_name[0] == '.'
1263 && (!tdirent->d_name[1] || tdirent->d_name[1] == '.')) continue;
1265 fdets->name = lives_strdup(tdirent->d_name);
1266 //g_print("GOT %s\n", fdets->name);
1267 fdets->size = -1;
1268 *listp = lives_list_append(*listp, fdets);
1269 if (lives_proc_thread_cancelled(tinfo)) {
1270 closedir(tldir);
1271 return NULL;
1272 }
1273 }
1274 break;
1275 }
1276 case 1: {
1277 FILE *orderfile;
1278 char buff[PATH_MAX];
1279 const char *ofname = item;
1280
1281 if (!(orderfile = fopen(ofname, "r"))) return NULL;
1282 while (1) {
1283 if (lives_proc_thread_cancelled(tinfo) || !orderfile) {
1284 if (orderfile) {
1285 fclose(orderfile);
1286 }
1287 return NULL;
1288 }
1289 if (!lives_fgets(buff, PATH_MAX, orderfile)) {
1290 fclose(orderfile);
1291 break;
1292 }
1293 lives_chomp(buff);
1294
1296
1297 fdets->name = lives_strdup(buff);
1298 fdets->size = -1;
1299 *listp = lives_list_append(*listp, fdets);
1300 if (lives_proc_thread_cancelled(tinfo)) {
1301 fclose(orderfile);
1302 return NULL;
1303 }
1304 }
1305 break;
1306 }
1307 default: return NULL;
1308 }
1309
1310 if (*listp) empty = FALSE;
1311 *listp = lives_list_append(*listp, NULL);
1312
1313 if (empty || lives_proc_thread_cancelled(tinfo)) return NULL;
1314
1315 // listing done, now get details for each entry
1316 list = *listp;
1317 while (list && list->data) {
1318 if (lives_proc_thread_cancelled(tinfo)) return NULL;
1319
1320 extra_details = lives_strdup("");
1321 fdets = (lives_file_dets_t *)list->data;
1322
1323 if (orig_loc && *orig_loc) subdirname = lives_build_filename(orig_loc, fdets->name, NULL);
1324 else subdirname = lives_build_path(dir, fdets->name, NULL);
1325
1326 // need to call even with no extra, because it gets size / type tc.
1327 if (!(extra_details = file_to_file_details(subdirname, fdets, tinfo, extra))) {
1328 lives_free(subdirname);
1329 lives_free(extra_details);
1330 return NULL;
1331 }
1332
1333 lives_free(subdirname);
1334
1335 if (tinfo && lives_proc_thread_cancelled(tinfo)) {
1336 lives_free(extra_details);
1337 return NULL;
1338 }
1339 fdets->extra_details = lives_strdup(extra_details);
1340 lives_free(extra_details);
1341 list = list->next;
1342 }
1343
1344 return NULL;
1345}
1346
1353lives_proc_thread_t dir_to_file_details(LiVESList **listp, const char *dir,
1354 const char *orig_loc, uint64_t extra) {
1356 listp, dir, orig_loc, extra, 0);
1357}
1358
1359
1360lives_proc_thread_t ordfile_to_file_details(LiVESList **listp, const char *ofname,
1361 const char *orig_loc, uint64_t extra) {
1363 listp, ofname, orig_loc, extra, 1);
1364}
1365
1366
1367#ifdef PRODUCE_LOG
1368// disabled by default
1369void lives_log(const char *what) {
1370 char *lives_log_file = lives_build_filename(prefs->workdir, LIVES_LOG_FILE, NULL);
1371 if (mainw->log_fd < 0) mainw->log_fd = open(lives_log_file, O_WRONLY | O_CREAT, DEF_FILE_PERMS);
1372 if (mainw->log_fd != -1) {
1373 char *msg = lives_strdup("%s|%d|", what, mainw->current_file);
1374 write(mainw->log_fd, msg, strlen(msg));
1375 lives_free(msg);
1376 }
1377 lives_free(lives_log_file);
1378}
1379#endif
1380
1381
1383 int i, fcount;
1384 char *fname_next;
1385 boolean maybeok = FALSE;
1386
1387 fcount = get_frame_count(mainw->current_file, 1);
1388
1389 for (i = 1; i <= fcount; i++) {
1390 fname_next = make_image_file_name(cfile, i, get_image_ext_for_type(cfile->img_type));
1391 if (sget_file_size(fname_next) > 0) {
1392 lives_free(fname_next);
1393 maybeok = TRUE;
1394 break;
1395 }
1396 lives_free(fname_next);
1397 }
1398
1399 if (!maybeok) {
1402 _("Your version of mplayer/ffmpeg may be broken !\nSee http://bugzilla.mplayerhq.hu/show_bug.cgi?id=2071\n\n"
1403 "You can work around this temporarily by switching to jpeg output in Preferences/Decoding.\n\n"
1404 "Try running Help/Troubleshoot for more information."));
1406 return CANCEL_ERROR;
1407 }
1408 return CANCEL_NONE;
1409}
1410
1411
1412LIVES_GLOBAL_INLINE char *lives_concat_sep(char *st, const char *sep, char *x) {
1414 // uses realloc / memcpy, frees x
1415 char *tmp;
1416 if (st) {
1417 size_t s1 = lives_strlen(st), s2 = lives_strlen(x), s3 = lives_strlen(sep);
1418 tmp = (char *)lives_realloc(st, ++s2 + s1 + s3);
1419 lives_memcpy(tmp + s1, sep, s3);
1420 lives_memcpy(tmp + s1 + s3, x, s2);
1421 } else tmp = lives_strdup(x);
1422 lives_free(x);
1423 return tmp;
1424}
1425
1426LIVES_GLOBAL_INLINE char *lives_concat(char *st, char *x) {
1428 // uses realloc / memcpy, frees x
1429 size_t s1 = lives_strlen(st), s2 = lives_strlen(x);
1430 char *tmp = (char *)lives_realloc(st, ++s2 + s1);
1431 lives_memcpy(tmp + s1, x, s2);
1432 lives_free(x);
1433 return tmp;
1434}
1435
1436LIVES_GLOBAL_INLINE int lives_strappend(const char *string, int len, const char *xnew) {
1438 size_t sz = lives_strlen(string);
1439 int newln = lives_snprintf((char *)(string + sz), len - sz, "%s", xnew);
1440 if (newln > len) newln = len;
1441 return --newln - sz; // returns strlen(xnew)
1442}
1443
1444LIVES_GLOBAL_INLINE const char *lives_strappendf(const char *string, int len, const char *fmt, ...) {
1445 va_list xargs;
1446 char *text;
1447
1448 va_start(xargs, fmt);
1449 text = lives_strdup_vprintf(fmt, xargs);
1450 va_end(xargs);
1451
1452 lives_strappend(string, len, text);
1453 lives_free(text);
1454 return string;
1455}
1456
1459#define hasNulByte(x) (((x) - 0x0101010101010101) & ~(x) & 0x8080808080808080)
1460#define getnulpos(nulmask) ((nulmask & 2155905152ul) ? ((nulmask & 32896ul) ? ((nulmask & 128ul) ? 0 : 1) : \
1461 ((nulmask & 8388608ul) ? 2 : 3)) : (nulmask & 141287244169216ul) ? \
1462 ((nulmask & 549755813888ul) ? 4 : 5) : ((nulmask & 36028797018963968ul) ? 6 : 7))
1463
1464#define getnulpos_be(nulmask) ((nulmask & 9259542121117908992ul) ? ((nulmask & 9259400833873739776ul) ? \
1465 ((nulmask & 9223372036854775808ul) ? 0 : 1) : ((nulmask & 140737488355328ul) ? 2 : 3)) \
1466 : (nulmask & 2155872256ul) ? ((nulmask & 2147483648ul) ? 4 : 5) : ((nulmask & 32768ul) ? 6 : 7))
1467
1468LIVES_GLOBAL_INLINE size_t lives_strlen(const char *s) {
1469 if (!s) return 0;
1470#ifndef STD_STRINGFUNCS
1471 else {
1472 uint64_t *pi = (uint64_t *)s, nulmask;
1473 if ((void *)pi == (void *)s) {
1474 while (!(nulmask = hasNulByte(*pi))) pi++;
1475 return (char *)pi - s + (capable->byte_order == LIVES_LITTLE_ENDIAN ? getnulpos(nulmask)
1476 : getnulpos_be(nulmask));
1477 }
1478 }
1479#endif
1480 return strlen(s);
1481}
1482
1483
1485 if (!s) return NULL;
1486#ifndef STD_STRINGFUNCS
1487 else {
1488 uint64_t *pi = (uint64_t *)s, nulmask, stlen;
1489 if (!s) return NULL;
1490 if ((void *)pi == (void *)s) {
1491 while (!(nulmask = hasNulByte(*pi))) pi++;
1492 stlen = (char *)pi - s + 1
1493 + (capable->byte_order == LIVES_LITTLE_ENDIAN)
1494 ? getnulpos(nulmask) : getnulpos_be(nulmask);
1495 return lives_memcpy(lives_malloc(stlen), s, stlen);
1496 }
1497 }
1498#endif
1499 return lives_strdup(s);
1500}
1501
1502
1503
1504
1506LIVES_GLOBAL_INLINE boolean lives_strcmp(const char *st1, const char *st2) {
1507 if (!st1 || !st2) return (st1 != st2);
1508 else {
1509#ifdef STD_STRINGFUNCS
1510 return strcmp(st1, st2);
1511#endif
1512 uint64_t d1, d2, *ip1 = (uint64_t *)st1, *ip2 = (uint64_t *)st2;
1513 while (1) {
1514 if ((void *)ip1 == (void *)st1 && (void *)ip2 == (void *)st2) {
1515 while (1) {
1516 if ((d1 = *(ip1++)) == (d2 = *(ip2++))) {if (hasNulByte(d1)) return FALSE;}
1517 else {
1518 if (!hasNulByte(d1 | d2)) return TRUE;
1519 break;
1520 }
1521 }
1522 st1 = (const char *)(--ip1); st2 = (const char *)(--ip2);
1523 }
1524 if (*st1 != *(st2++)) return TRUE;
1525 if (!(*(st1++))) return FALSE;
1526 }
1527 }
1528 return FALSE;
1529}
1530
1531LIVES_GLOBAL_INLINE int lives_strcmp_ordered(const char *st1, const char *st2) {
1532 if (!st1 || !st2) return (st1 != st2);
1533 else {
1534#ifdef STD_STRINGFUNCS
1535 return strcmp(st1, st2);
1536#endif
1537 uint64_t d1, d2, *ip1 = (uint64_t *)st1, *ip2 = (uint64_t *)st2;
1538 while (1) {
1539 if ((void *)ip1 == (void *)st1 && (void *)ip2 == (void *)st2) {
1540 do {
1541 d1 = *(ip1++);
1542 d2 = *(ip2++);
1543 } while (d1 == d2 && !hasNulByte(d1));
1544 st1 = (const char *)(--ip1); st2 = (const char *)(--ip2);
1545 }
1546 if (*st1 != *st2 || !(*st1)) break;
1547 st1++; st2++;
1548 }
1549 }
1550 return (*st1 > *st2) - (*st1 < *st2);
1551}
1552
1554LIVES_GLOBAL_INLINE boolean lives_strncmp(const char *st1, const char *st2, size_t len) {
1555 if (!st1 || !st2) return (st1 != st2);
1556 else {
1557#ifdef STD_STRINGFUNCS
1558 return strncmp(st1, st2, len);
1559#endif
1560 size_t xlen = len >> 3;
1561 uint64_t d1, d2, *ip1 = (uint64_t *)st1, *ip2 = (uint64_t *)st2;
1562 while (1) {
1563 if (xlen && (void *)ip1 == (void *)st1 && (void *)ip2 == (void *)st2) {
1564 do {
1565 d1 = *(ip1++);
1566 d2 = *(ip2++);
1567 } while (d1 == d2 && !hasNulByte(d1) && --xlen);
1568 if (xlen) {
1569 if (!hasNulByte(d2)) return TRUE;
1570 ip1--;
1571 ip2--;
1572 }
1573 st1 = (void *)ip1; st2 = (void *)ip2;
1574 len -= ((len >> 3) - xlen) << 3;
1575 }
1576 if (!(len--)) return FALSE;
1577 if (*st1 != *(st2++)) return TRUE;
1578 if (!(*(st1++))) return FALSE;
1579 }
1580 }
1581 return (*st1 != *st2);
1582}
1583
1584#define HASHROOT 5381
1585LIVES_GLOBAL_INLINE uint32_t lives_string_hash(const char *st) {
1586 if (st) for (uint32_t hash = HASHROOT;; hash += (hash << 5)
1587 + * (st++)) if (!(*st)) return hash;
1588 return 0;
1589}
1590
1591
1592// fast hash from: http://www.azillionmonkeys.com/qed/hash.html
1593// (c) Paul Hsieh
1594#define get16bits(d) (*((const uint16_t *) (d)))
1595
1596LIVES_GLOBAL_INLINE uint32_t fast_hash(const char *key) {
1598 if (key && *key) {
1599 int len = lives_strlen(key), rem = len & 3;
1600 uint32_t hash = len + HASHROOT, tmp;
1601 len >>= 2;
1602 for (; len > 0; len--) {
1603 hash += get16bits(key);
1604 tmp = (get16bits(key + 2) << 11) ^ hash;
1605 hash = (hash << 16) ^ tmp;
1606 key += 4;
1607 hash += hash >> 11;
1608 }
1609
1610 /* Handle end cases */
1611 switch (rem) {
1612 case 3: hash += get16bits(key);
1613 hash ^= hash << 16;
1614 hash ^= ((int8_t)key[2]) << 18;
1615 hash += hash >> 11;
1616 break;
1617 case 2: hash += get16bits(key);
1618 hash ^= hash << 11; hash += hash >> 17;
1619 break;
1620 case 1: hash += (int8_t) * key;
1621 hash ^= hash << 10; hash += hash >> 1;
1622 break;
1623 default: break;
1624 }
1625
1626 /* Force "avalanching" of final 127 bits */
1627 hash ^= hash << 3; hash += hash >> 5; hash ^= hash << 4;
1628 hash += hash >> 17; hash ^= hash << 25; hash += hash >> 6;
1629 return hash;
1630 }
1631 return 0;
1632}
1633
1634LIVES_GLOBAL_INLINE char *lives_strstop(char *st, const char term) {
1636 if (st && term) for (int i = 0; st[i]; i++) if (st[i] == term) {st[i] = 0; break;}
1637 return st;
1638}
1639
1640
1643 if (buff) {
1644 size_t xs = lives_strlen(buff);
1645 if (xs && buff[xs - 1] == '\n') buff[--xs] = '\0'; // remove trailing newline
1646 }
1647 return buff;
1648}
1649
1650
1651LIVES_GLOBAL_INLINE char *lives_strtrim(const char *buff) {
1654 int i, j;
1655 if (!buff) return NULL;
1656 for (i = 0; buff[i] == '\n'; i++);
1657 for (j = i; buff[j]; j++) if (buff[j] == '\n') break;
1658 return lives_strndup(buff + i, j - i);
1659}
1660
1661
1670typedef weed_plantptr_t lives_proc_thread_t;
1671
1673
1674static lives_proc_thread_t _lives_proc_thread_create(lives_thread_attr_t attr, lives_funcptr_t func,
1675 int return_type, const char *args_fmt, va_list xargs) {
1676 int p = 0;
1677 const char *c;
1678 weed_plant_t *thread_info = lives_plant_new(LIVES_WEED_SUBTYPE_PROC_THREAD);
1679 if (!thread_info) return NULL;
1680 weed_set_funcptr_value(thread_info, WEED_LEAF_THREADFUNC, func);
1681 if (return_type) {
1682 pthread_mutex_t *dcmutex = (pthread_mutex_t *)lives_malloc(sizeof(pthread_mutex_t));
1683 pthread_mutex_init(dcmutex, NULL);
1684 weed_set_voidptr_value(thread_info, WEED_LEAF_DONTCARE_MUTEX, dcmutex);
1685 weed_set_boolean_value(thread_info, WEED_LEAF_NOTIFY, WEED_TRUE);
1686 if (return_type > 0) weed_leaf_set(thread_info, WEED_LEAF_RETURN_VALUE, return_type, 0, NULL);
1687 }
1688 c = args_fmt;
1689 for (c = args_fmt; *c; c++) {
1690 char *pkey = lives_strdup_printf("%s%d", WEED_LEAF_THREAD_PARAM, p++);
1691 switch (*c) {
1692 case 'i': weed_set_int_value(thread_info, pkey, va_arg(xargs, int)); break;
1693 case 'd': weed_set_double_value(thread_info, pkey, va_arg(xargs, double)); break;
1694 case 'b': weed_set_boolean_value(thread_info, pkey, va_arg(xargs, int)); break;
1695 case 's': case 'S': weed_set_string_value(thread_info, pkey, va_arg(xargs, char *)); break;
1696 case 'I': weed_set_int64_value(thread_info, pkey, va_arg(xargs, int64_t)); break;
1697 case 'F': weed_set_funcptr_value(thread_info, pkey, va_arg(xargs, weed_funcptr_t)); break;
1698 case 'V': case 'v': weed_set_voidptr_value(thread_info, pkey, va_arg(xargs, void *)); break;
1699 case 'P': weed_set_plantptr_value(thread_info, pkey, va_arg(xargs, weed_plantptr_t)); break;
1700 default: weed_plant_free(thread_info); return NULL;
1701 }
1702 lives_free(pkey);
1703 }
1704
1705 if (!(attr & LIVES_THRDATTR_FG_THREAD)) {
1706 resubmit_proc_thread(thread_info, attr);
1707 if (!return_type) return NULL;
1708 }
1709 return thread_info;
1710}
1711
1712
1731 int return_type, const char *args_fmt, ...) {
1733 va_list xargs;
1734 va_start(xargs, args_fmt);
1735 lpt = _lives_proc_thread_create(attr, func, return_type, args_fmt, xargs);
1736 va_end(xargs);
1737 return lpt;
1738}
1739
1740
1741void *main_thread_execute(lives_funcptr_t func, int return_type, void *retval, const char *args_fmt, ...) {
1743 va_list xargs;
1744 void *ret;
1745 va_start(xargs, args_fmt);
1746 lpt = _lives_proc_thread_create(LIVES_THRDATTR_FG_THREAD, func, return_type, args_fmt, xargs);
1747 ret = lives_fg_run(lpt, retval);
1748 va_end(xargs);
1749 return ret;
1750}
1751
1752
1753static void call_funcsig(funcsig_t sig, lives_proc_thread_t info) {
1758 uint32_t ret_type = weed_leaf_seed_type(info, _RV_);
1759 allfunc_t *thefunc = (allfunc_t *)lives_malloc(sizeof(allfunc_t));
1760 char *msg;
1761
1762 thefunc->func = weed_get_funcptr_value(info, WEED_LEAF_THREADFUNC, NULL);
1763
1764#define FUNCSIG_VOID 0X00000000
1765#define FUNCSIG_INT 0X00000001
1766#define FUNCSIG_DOUBLE 0X00000002
1767#define FUNCSIG_STRING 0X00000004
1768#define FUNCSIG_VOIDP 0X0000000D
1769#define FUNCSIG_INT_INT64 0X00000015
1770#define FUNCSIG_STRING_INT 0X00000041
1771#define FUNCSIG_STRING_BOOL 0X00000043
1772#define FUNCSIG_VOIDP_VOIDP 0X000000DD
1773#define FUNCSIG_VOIDP_DOUBLE 0X000000D2
1774#define FUNCSIG_PLANTP_BOOL 0X000000E3
1775#define FUNCSIG_VOIDP_VOIDP_VOIDP 0X00000DDD
1776#define FUNCSIG_PLANTP_VOIDP_INT64 0X00000ED5
1777 // 4p
1778#define FUNCSIG_STRING_STRING_VOIDP_INT 0X000044D1
1779#define FUNCSIG_INT_INT_BOOL_VOIDP 0X0000113D
1780 // 5p
1781#define FUNCSIG_INT_INT_INT_BOOL_VOIDP 0X0001113D
1782#define FUNCSIG_VOIDP_STRING_STRING_INT64_INT 0X000D4451
1783 // 6p
1784#define FUNCSIG_STRING_STRING_VOIDP_INT_STRING_VOIDP 0X0044D14D
1785
1786 // Note: C compilers don't care about the type / number of function args., (else it would be impossible to alias any function pointer)
1787 // just the type / number must be correct at runtime;
1788 // However it DOES care about the return type. The funcsigs are a guide so that the correct cast / number of args. can be
1789 // determined in the code., the first argument to the GETARG macro is set by this.
1790 // return_type determines which function flavour to call, e.g func, funcb, funci
1792
1794
1798
1799 switch (sig) {
1800 case FUNCSIG_VOID:
1801 switch (ret_type) {
1802 case WEED_SEED_INT64: CALL_0(int64); break;
1803 default: CALL_VOID_0(); break;
1804 }
1805 break;
1806 case FUNCSIG_INT:
1807 switch (ret_type) {
1808 default: CALL_VOID_1(int); break;
1809 }
1810 break;
1811 case FUNCSIG_DOUBLE:
1812 switch (ret_type) {
1813 default: CALL_VOID_1(double); break;
1814 }
1815 break;
1816 case FUNCSIG_STRING:
1817 switch (ret_type) {
1818 case WEED_SEED_STRING: CALL_1(string, string); break;
1819 case WEED_SEED_INT64: CALL_1(int64, string); break;
1820 default: CALL_VOID_1(string); break;
1821 }
1822 break;
1823 case FUNCSIG_VOIDP:
1824 switch (ret_type) {
1825 case WEED_SEED_BOOLEAN: CALL_1(boolean, voidptr); break;
1826 case WEED_SEED_INT: CALL_1(int, voidptr); break;
1827 default: CALL_VOID_1(voidptr); break;
1828 }
1829 break;
1830 case FUNCSIG_INT_INT64:
1831 switch (ret_type) {
1832 default: CALL_VOID_2(int, int64); break;
1833 }
1834 break;
1835 case FUNCSIG_STRING_INT:
1836 switch (ret_type) {
1837 default: CALL_VOID_2(string, int); break;
1838 }
1839 break;
1841 switch (ret_type) {
1842 default: CALL_VOID_2(string, boolean); break;
1843 }
1844 break;
1846 switch (ret_type) {
1847 default: CALL_VOID_2(voidptr, double); break;
1848 }
1849 break;
1851 switch (ret_type) {
1852 case WEED_SEED_BOOLEAN: CALL_2(boolean, voidptr, voidptr); break;
1853 default: CALL_VOID_2(voidptr, voidptr); break;
1854 }
1855 break;
1857 switch (ret_type) {
1858 default: CALL_VOID_2(plantptr, boolean); break;
1859 }
1860 break;
1862 switch (ret_type) {
1863 case WEED_SEED_BOOLEAN: CALL_3(boolean, voidptr, voidptr, voidptr); break;
1864 default: CALL_VOID_3(voidptr, voidptr, voidptr); break;
1865 }
1866 break;
1868 switch (ret_type) {
1869 case WEED_SEED_BOOLEAN: CALL_3(boolean, plantptr, voidptr, int64); break;
1870 default: CALL_VOID_3(plantptr, voidptr, int64); break;
1871 }
1872 break;
1874 switch (ret_type) {
1875 case WEED_SEED_STRING: CALL_4(string, string, string, voidptr, int); break;
1876 default: CALL_VOID_4(string, string, voidptr, int); break;
1877 }
1878 break;
1880 switch (ret_type) {
1881 case WEED_SEED_BOOLEAN: CALL_4(boolean, int, int, boolean, voidptr); break;
1882 default: CALL_VOID_4(int, int, boolean, voidptr); break;
1883 }
1884 break;
1886 switch (ret_type) {
1887 default: CALL_VOID_5(voidptr, string, string, int64, int); break;
1888 }
1889 break;
1891 switch (ret_type) {
1892 default: CALL_VOID_5(int, int, int, boolean, voidptr); break;
1893 }
1894 break;
1896 switch (ret_type) {
1897 case WEED_SEED_STRING: CALL_6(string, string, string, voidptr, int, string, voidptr); break;
1898 default: CALL_VOID_6(string, string, voidptr, int, string, voidptr); break;
1899 }
1900 break;
1901 default:
1902 msg = lives_strdup_printf("Unknown funcsig with tyte 0x%016lX called", sig);
1903 LIVES_FATAL(msg);
1904 lives_free(msg);
1905 break;
1906 }
1907
1908 lives_free(thefunc);
1909}
1910
1912 volatile boolean *sync_ready = (volatile boolean *)weed_get_voidptr_value(tinfo, "sync_ready", NULL);
1913 if (sync_ready) *sync_ready = TRUE;
1914}
1915
1918 if (!tinfo) return TRUE;
1919 if (weed_plant_has_leaf(tinfo, WEED_LEAF_NOTIFY) && weed_get_boolean_value(tinfo, WEED_LEAF_DONE, NULL)
1920 == WEED_FALSE)
1921 return FALSE;
1922 return (weed_leaf_num_elements(tinfo, _RV_) > 0
1923 || weed_get_boolean_value(tinfo, WEED_LEAF_DONE, NULL) == WEED_TRUE);
1924}
1925
1928 return (weed_get_int_value(tinfo, WEED_LEAF_SIGNALLED, NULL) == WEED_TRUE);
1929}
1930
1933 lives_thread_data_t *tdata = (lives_thread_data_t *)weed_get_voidptr_value(tinfo, WEED_LEAF_SIGNAL_DATA, NULL);
1934 if (tdata) return tdata->idx;
1935 return 0;
1936}
1937
1939 weed_set_boolean_value(tinfo, WEED_LEAF_THREAD_CANCELLABLE, WEED_TRUE);
1940}
1941
1943 return weed_get_boolean_value(tinfo, WEED_LEAF_THREAD_CANCELLABLE, NULL) == WEED_TRUE ? TRUE : FALSE;
1944}
1945
1947 if (!lives_proc_thread_get_cancellable(tinfo)) return FALSE;
1948 weed_set_boolean_value(tinfo, WEED_LEAF_THREAD_CANCELLED, WEED_TRUE);
1950 return TRUE;
1951}
1952
1957 pthread_mutex_t *dcmutex = weed_get_voidptr_value(tinfo, WEED_LEAF_DONTCARE_MUTEX, NULL);
1958 if (dcmutex) {
1959 pthread_mutex_lock(dcmutex);
1960 if (!lives_proc_thread_check(tinfo)) {
1961 weed_set_boolean_value(tinfo, WEED_LEAF_DONTCARE, WEED_TRUE);
1962 pthread_mutex_unlock(dcmutex);
1963 } else {
1964 pthread_mutex_unlock(dcmutex);
1966 }
1967 }
1968 return TRUE;
1969}
1970
1972 return (tinfo && weed_get_boolean_value(tinfo, WEED_LEAF_THREAD_CANCELLED, NULL) == WEED_TRUE)
1973 ? TRUE : FALSE;
1974}
1975
1976#define _join(stype) lives_nanosleep_until_nonzero(weed_leaf_num_elements(tinfo, _RV_)); \
1977 return weed_get_##stype##_value(tinfo, _RV_, NULL);
1978
1980 // WARNING !! version without a return value will free tinfo !
1981 void *dcmutex;
1982 lives_nanosleep_until_nonzero((weed_get_boolean_value(tinfo, WEED_LEAF_DONE, NULL) == WEED_TRUE));
1983 dcmutex = weed_get_voidptr_value(tinfo, WEED_LEAF_DONTCARE_MUTEX, NULL);
1984 if (dcmutex) lives_free(dcmutex);
1985 weed_plant_free(tinfo);
1986}
1995
2000static funcsig_t make_funcsig(lives_proc_thread_t func_info) {
2001 funcsig_t funcsig = 0;
2002 for (register int nargs = 0; nargs < 16; nargs++) {
2003 char *lname = lives_strdup_printf("%s%d", WEED_LEAF_THREAD_PARAM, nargs);
2004 int st = weed_leaf_seed_type(func_info, lname);
2005 lives_free(lname);
2006 if (!st) break;
2007 funcsig <<= 4;
2008 if (st < 12) funcsig |= st; // 1 == int, 2 == double, 3 == boolean (int), 4 == char *, 5 == int64_t
2009 else {
2010 switch (st) {
2011 case WEED_SEED_FUNCPTR: funcsig |= 0XC; break;
2012 case WEED_SEED_VOIDPTR: funcsig |= 0XD; break;
2013 case WEED_SEED_PLANTPTR: funcsig |= 0XE; break;
2014 default: funcsig |= 0XF; break;
2015 }
2016 }
2017 }
2018 return funcsig;
2019}
2020
2021static void *_plant_thread_func(void *args) {
2023 uint32_t ret_type = weed_leaf_seed_type(info, _RV_);
2024 funcsig_t sig = make_funcsig(info);
2025 THREADVAR(tinfo) = info;
2026 if (weed_get_boolean_value(info, "no_gui", NULL) == WEED_TRUE) THREADVAR(no_gui) = TRUE;
2027 call_funcsig(sig, info);
2028
2029 if (weed_get_boolean_value(info, WEED_LEAF_NOTIFY, NULL) == WEED_TRUE) {
2030 boolean dontcare;
2031 pthread_mutex_t *dcmutex = (pthread_mutex_t *)weed_get_voidptr_value(info, WEED_LEAF_DONTCARE_MUTEX, NULL);
2032 pthread_mutex_lock(dcmutex);
2033 dontcare = weed_get_boolean_value(info, WEED_LEAF_DONTCARE, NULL);
2034 weed_set_boolean_value(info, WEED_LEAF_DONE, WEED_TRUE);
2035 pthread_mutex_unlock(dcmutex);
2036 if (dontcare == WEED_TRUE) {
2037 lives_free(dcmutex);
2038 weed_plant_free(info);
2039 }
2040 } else if (!ret_type) weed_plant_free(info);
2041 return NULL;
2042}
2043
2044
2045void *fg_run_func(lives_proc_thread_t lpt, void *retval) {
2046 uint32_t ret_type = weed_leaf_seed_type(lpt, _RV_);
2047 funcsig_t sig = make_funcsig(lpt);
2048
2049 call_funcsig(sig, lpt);
2050
2051 switch (ret_type) {
2052 case WEED_SEED_INT: {
2053 int *ival = (int *)retval;
2054 *ival = weed_get_int_value(lpt, _RV_, NULL);
2055 weed_plant_free(lpt);
2056 return (void *)ival;
2057 }
2058 case WEED_SEED_BOOLEAN: {
2059 int *bval = (int *)retval;
2060 *bval = weed_get_boolean_value(lpt, _RV_, NULL);
2061 weed_plant_free(lpt);
2062 return (void *)bval;
2063 }
2064 case WEED_SEED_DOUBLE: {
2065 double *dval = (double *)retval;
2066 *dval = weed_get_double_value(lpt, _RV_, NULL);
2067 weed_plant_free(lpt);
2068 return (void *)dval;
2069 }
2070 case WEED_SEED_STRING: {
2071 char *chval = weed_get_string_value(lpt, _RV_, NULL);
2072 weed_plant_free(lpt);
2073 return (void *)chval;
2074 }
2075 case WEED_SEED_INT64: {
2076 int64_t *i64val = (int64_t *)retval;
2077 *i64val = weed_get_int64_value(lpt, _RV_, NULL);
2078 weed_plant_free(lpt);
2079 return (void *)i64val;
2080 }
2081 case WEED_SEED_VOIDPTR: {
2082 void *val;
2083 val = weed_get_voidptr_value(lpt, _RV_, NULL);
2084 weed_plant_free(lpt);
2085 return val;
2086 }
2087 case WEED_SEED_PLANTPTR: {
2088 weed_plant_t *pval;
2089 pval = weed_get_plantptr_value(lpt, _RV_, NULL);
2090 weed_plant_free(lpt);
2091 return (void *)pval;
2092 }
2094 default:
2095 weed_plant_free(lpt);
2096 break;
2097 }
2098 return NULL;
2099}
2100
2101#undef _RV_
2102
2109 thrd_work_t *work;
2110
2113 lives_thread_create(thread, attr, _plant_thread_func, (void *)thread_info);
2114 work = (thrd_work_t *)thread->data;
2115 if (attr & LIVES_THRDATTR_WAIT_SYNC) {
2116 weed_set_voidptr_value(thread_info, "sync_ready", (void *) & (work->sync_ready));
2117 }
2118 if (attr & LIVES_THRDATTR_NO_GUI) {
2119 weed_set_boolean_value(thread_info, "no_gui", WEED_TRUE);
2120 }
2121}
2122
2123
2125
2127#ifndef VALGRIND_ON
2128#define MINPOOLTHREADS 8
2129#else
2130#define MINPOOLTHREADS 2
2131#endif
2132static int npoolthreads;
2133static pthread_t **poolthrds;
2134static pthread_cond_t tcond = PTHREAD_COND_INITIALIZER;
2135static pthread_mutex_t tcond_mutex = PTHREAD_MUTEX_INITIALIZER;
2136static pthread_mutex_t pool_mutex = PTHREAD_MUTEX_INITIALIZER;
2137static pthread_mutex_t twork_mutex = PTHREAD_MUTEX_INITIALIZER;
2138static pthread_mutex_t twork_count_mutex = PTHREAD_MUTEX_INITIALIZER;
2139static LiVESList *twork_first, *twork_last;
2140static volatile int ntasks;
2141static boolean threads_die;
2142
2143static LiVESList *allctxs = NULL;
2144
2145lives_thread_data_t *get_thread_data(void) {
2146 LiVESWidgetContext *ctx = lives_widget_context_get_thread_default();
2147 LiVESList *list = allctxs;
2148 if (!ctx) ctx = lives_widget_context_default();
2149 for (; list; list = list->next) {
2150 if (((lives_thread_data_t *)list->data)->ctx == ctx) return list->data;
2151 }
2152 return NULL;
2153}
2154
2155
2157 static lives_threadvars_t *dummyvars = NULL;
2158 lives_thread_data_t *thrdat = get_thread_data();
2159 if (!thrdat) {
2160 if (!dummyvars) dummyvars = lives_calloc(1, sizeof(lives_threadvars_t));
2161 return dummyvars;
2162 }
2163 return &thrdat->vars;
2164}
2165
2166static lives_thread_data_t *get_thread_data_by_id(uint64_t idx) {
2167 LiVESList *list = allctxs;
2168 for (; list; list = list->next) {
2169 if (((lives_thread_data_t *)list->data)->idx == idx) return list->data;
2170 }
2171 return NULL;
2172}
2173
2174lives_thread_data_t *lives_thread_data_create(uint64_t idx) {
2175 lives_thread_data_t *tdata = (lives_thread_data_t *)lives_calloc(1, sizeof(lives_thread_data_t));
2176 if (idx != 0) tdata->ctx = lives_widget_context_new();
2177 else tdata->ctx = lives_widget_context_default();
2178 tdata->idx = idx;
2179 tdata->vars.var_rowstride_alignment = ALIGN_DEF;
2180 tdata->vars.var_last_sws_block = -1;
2181 tdata->vars.var_mydata = tdata;
2182 allctxs = lives_list_prepend(allctxs, (livespointer)tdata);
2183 return tdata;
2184}
2185
2186
2187static boolean gsrc_wrapper(livespointer data) {
2188 thrd_work_t *mywork = (thrd_work_t *)data;
2189 (*mywork->func)(mywork->arg);
2190 return FALSE;
2191}
2192
2193
2194boolean do_something_useful(lives_thread_data_t *tdata) {
2196 LiVESList *list;
2197 thrd_work_t *mywork;
2198 uint64_t myflags = 0;
2199
2200 if (!tdata->idx) abort();
2201
2202 pthread_mutex_lock(&twork_mutex);
2203 list = twork_last;
2204 if (LIVES_UNLIKELY(!list)) {
2205 pthread_mutex_unlock(&twork_mutex);
2206 return FALSE;
2207 }
2208
2209 if (twork_first == list) twork_last = twork_first = NULL;
2210 else {
2211 twork_last = list->prev;
2212 twork_last->next = NULL;
2213 }
2214 pthread_mutex_unlock(&twork_mutex);
2215
2216 mywork = (thrd_work_t *)list->data;
2217 mywork->busy = tdata->idx;
2218 myflags = mywork->flags;
2219
2220 if (myflags & LIVES_THRDFLAG_WAIT_SYNC) {
2222 }
2223
2224 lives_widget_context_invoke(tdata->ctx, gsrc_wrapper, mywork);
2225 //(*mywork->func)(mywork->arg);
2226
2227 if (myflags & LIVES_THRDFLAG_AUTODELETE) {
2228 lives_free(mywork); lives_free(list);
2229 } else mywork->done = tdata->idx;
2230
2231 pthread_mutex_lock(&twork_count_mutex);
2232 ntasks--;
2233 pthread_mutex_unlock(&twork_count_mutex);
2234 return TRUE;
2235}
2236
2237
2238static void *thrdpool(void *arg) {
2239 boolean skip_wait = FALSE;
2240 lives_thread_data_t *tdata = (lives_thread_data_t *)arg;
2243 }
2244
2245 lives_widget_context_push_thread_default(tdata->ctx);
2246
2247 while (!threads_die) {
2248 if (!skip_wait) {
2249 pthread_mutex_lock(&tcond_mutex);
2250 pthread_cond_wait(&tcond, &tcond_mutex);
2251 pthread_mutex_unlock(&tcond_mutex);
2252 }
2253 if (LIVES_UNLIKELY(threads_die)) break;
2254 skip_wait = do_something_useful(tdata);
2257 }
2258 }
2261 }
2262 return NULL;
2263}
2264
2265
2266LIVES_GLOBAL_INLINE weed_plant_t *lives_plant_new(int subtype) {
2267 weed_plant_t *plant = weed_plant_new(WEED_PLANT_LIVES);
2268 weed_set_int_value(plant, WEED_LEAF_LIVES_SUBTYPE, subtype);
2269 return plant;
2270}
2271
2272
2273LIVES_GLOBAL_INLINE weed_plant_t *lives_plant_new_with_index(int subtype, int64_t index) {
2274 weed_plant_t *plant = lives_plant_new(subtype);
2275 weed_set_int64_value(plant, WEED_LEAF_INDEX, index);
2276 return plant;
2277}
2278
2279
2281 npoolthreads = MINPOOLTHREADS;
2282 if (prefs->nfx_threads > npoolthreads) npoolthreads = prefs->nfx_threads;
2283 poolthrds = (pthread_t **)lives_calloc(npoolthreads, sizeof(pthread_t *));
2284 threads_die = FALSE;
2285 twork_first = twork_last = NULL;
2286 ntasks = 0;
2287 for (int i = 0; i < npoolthreads; i++) {
2288 lives_thread_data_t *tdata = lives_thread_data_create(i + 1);
2289 poolthrds[i] = (pthread_t *)lives_malloc(sizeof(pthread_t));
2290 pthread_create(poolthrds[i], NULL, thrdpool, tdata);
2291 }
2292}
2293
2294
2296 threads_die = TRUE;
2297 pthread_mutex_lock(&tcond_mutex);
2298 pthread_cond_broadcast(&tcond);
2299 pthread_mutex_unlock(&tcond_mutex);
2300 for (int i = 0; i < npoolthreads; i++) {
2301 lives_thread_data_t *tdata = get_thread_data_by_id(i + 1);
2302 pthread_cond_broadcast(&tcond);
2303 pthread_mutex_unlock(&tcond_mutex);
2304 pthread_join(*(poolthrds[i]), NULL);
2305 lives_widget_context_unref(tdata->ctx);
2306 lives_free(tdata);
2307 lives_free(poolthrds[i]);
2308 }
2309 lives_free(poolthrds);
2310 poolthrds = NULL;
2311 npoolthreads = 0;
2312 lives_list_free_all((LiVESList **)&twork_first);
2313 twork_first = twork_last = NULL;
2314 ntasks = 0;
2315}
2316
2317
2319 LiVESList *list = (LiVESList *)thread;
2320 thrd_work_t *work = (thrd_work_t *)lives_calloc(1, sizeof(thrd_work_t));
2321 if (!thread) list = (LiVESList *)lives_calloc(1, sizeof(LiVESList));
2322 else list->next = list->prev = NULL;
2323 list->data = work;
2324 work->func = func;
2325 work->arg = arg;
2326
2327 if (!thread || (attr & LIVES_THRDATTR_AUTODELETE))
2329 if (attr & LIVES_THRDATTR_WAIT_SYNC) {
2331 work->sync_ready = FALSE;
2332 }
2333
2334 pthread_mutex_lock(&twork_mutex);
2335 if (!twork_first) {
2336 twork_first = twork_last = list;
2337 } else {
2338 if (!(attr & LIVES_THRDATTR_PRIORITY)) {
2339 twork_first->prev = list;
2340 list->next = twork_first;
2341 twork_first = list;
2342 } else {
2343 twork_last->next = list;
2344 list->prev = twork_last;
2345 twork_last = list;
2346 }
2347 }
2348 pthread_mutex_unlock(&twork_mutex);
2349 pthread_mutex_lock(&twork_count_mutex);
2350 ntasks++;
2351 pthread_mutex_unlock(&twork_count_mutex);
2352 pthread_mutex_lock(&tcond_mutex);
2353 pthread_cond_signal(&tcond);
2354 pthread_mutex_unlock(&tcond_mutex);
2355 pthread_mutex_lock(&pool_mutex);
2356 if (ntasks >= npoolthreads) {
2357 pthread_mutex_lock(&tcond_mutex);
2358 pthread_cond_broadcast(&tcond);
2359 pthread_mutex_unlock(&tcond_mutex);
2360 poolthrds = (pthread_t **)lives_realloc(poolthrds, (npoolthreads + MINPOOLTHREADS) * sizeof(pthread_t *));
2361 for (int i = npoolthreads; i < npoolthreads + MINPOOLTHREADS; i++) {
2362 lives_thread_data_t *tdata = lives_thread_data_create(i + 1);
2363 poolthrds[i] = (pthread_t *)lives_malloc(sizeof(pthread_t));
2364 pthread_create(poolthrds[i], NULL, thrdpool, tdata);
2365 pthread_mutex_lock(&tcond_mutex);
2366 pthread_cond_signal(&tcond);
2367 pthread_mutex_unlock(&tcond_mutex);
2368 }
2369 npoolthreads += MINPOOLTHREADS;
2370 }
2371 pthread_mutex_unlock(&pool_mutex);
2372 return 0;
2373}
2374
2375
2376uint64_t lives_thread_join(lives_thread_t work, void **retval) {
2377 thrd_work_t *task = (thrd_work_t *)work.data;
2378 uint64_t nthrd = 0;
2379 if (task->flags & LIVES_THRDFLAG_AUTODELETE) {
2380 LIVES_FATAL("lives_thread_join() called on an autodelete thread");
2381 return 0;
2382 }
2383
2384 while (!task->busy) {
2385 pthread_mutex_lock(&tcond_mutex);
2386 pthread_cond_signal(&tcond);
2387 pthread_mutex_unlock(&tcond_mutex);
2388 if (task->busy) break;
2389 sched_yield();
2390 lives_nanosleep(1000);
2391 }
2392
2393 if (!task->done) {
2394 pthread_mutex_lock(&tcond_mutex);
2395 pthread_cond_signal(&tcond);
2396 pthread_mutex_unlock(&tcond_mutex);
2397 }
2398
2400 nthrd = task->done;
2401
2402 if (retval) *retval = task->ret;
2403 lives_free(task);
2404 return nthrd;
2405}
2406
2407
2409#ifdef IS_MINGW
2410 return GetCurrentProcessId(),
2411#else
2412 return getpid();
2413#endif
2414}
2415
2417 return geteuid();
2418}
2419
2421 return getegid();
2422}
2423
2424static uint16_t swabtab[65536];
2425static boolean swabtab_inited = FALSE;
2426
2427static void init_swabtab(void) {
2428 for (int i = 0; i < 256; i++) {
2429 int z = i << 8;
2430 for (int j = 0; j < 256; j++) {
2431 swabtab[z++] = (j << 8) + i;
2432 }
2433 }
2434 swabtab_inited = TRUE;
2435}
2436
2437union split8 {
2438 uint64_t u64;
2439 uint32_t u32[2];
2440};
2441
2442union split4 {
2443 uint32_t u32;
2444 uint16_t u16[2];
2445};
2446
2447// gran(ularity) may be 1, or 2
2448LIVES_GLOBAL_INLINE void swab2(const void *from, const void *to, size_t gran) {
2449 uint16_t *s = (uint16_t *)from;
2450 uint16_t *d = (uint16_t *)to;
2451 if (gran == 2) {
2452 uint16_t tmp = *s;
2453 *s = *d;
2454 *d = tmp;
2455 return;
2456 }
2457 if (!swabtab_inited) init_swabtab();
2458 *d = swabtab[*s];
2459}
2460
2461// gran(ularity) may be 1, 2 or 4
2462LIVES_GLOBAL_INLINE void swab4(const void *from, const void *to, size_t gran) {
2463 union split4 *d = (union split4 *)to, s;
2464 uint16_t tmp;
2465
2466 if (gran > 2) {
2467 lives_memcpy((void *)to, from, gran);
2468 return;
2469 }
2470 s.u32 = *(uint32_t *)from;
2471 tmp = s.u16[0];
2472 if (gran == 2) {
2473 d->u16[0] = s.u16[1];
2474 d->u16[1] = tmp;
2475 } else {
2476 swab2(&s.u16[1], &d->u16[0], 1);
2477 swab2(&tmp, &d->u16[1], 1);
2478 }
2479}
2480
2481
2482// gran(ularity) may be 1, 2 or 4
2483LIVES_GLOBAL_INLINE void swab8(const void *from, const void *to, size_t gran) {
2484 union split8 *d = (union split8 *)to, s;
2485 uint32_t tmp;
2486 if (gran > 4) {
2487 lives_memcpy((void *)to, from, gran);
2488 return;
2489 }
2490 s.u64 = *(uint64_t *)from;
2491 tmp = s.u32[0];
2492 if (gran == 4) {
2493 d->u32[0] = s.u32[1];
2494 d->u32[1] = tmp;
2495 } else {
2496 swab4(&s.u32[1], &d->u32[0], gran);
2497 swab4(&tmp, &d->u32[1], gran);
2498 }
2499}
2500
2501
2502LIVES_GLOBAL_INLINE void reverse_bytes(char *buff, size_t count, size_t gran) {
2503 if (count == 2) swab2(buff, buff, 1);
2504 else if (count == 4) swab4(buff, buff, gran);
2505 else if (count == 8) swab8(buff, buff, gran);
2506}
2507
2508
2509boolean reverse_buffer(uint8_t *buff, size_t count, size_t chunk) {
2510 // reverse chunk sized bytes in buff, count must be a multiple of chunk
2511 ssize_t start = -1, end;
2512 size_t ocount = count;
2513
2514 if (chunk < 8) {
2515 if ((chunk != 4 && chunk != 2 && chunk != 1) || (count % chunk) != 0) return FALSE;
2516 } else {
2517 if ((chunk & 0x01) || (count % chunk) != 0) return FALSE;
2518 else {
2519#ifdef USE_RPMALLOC
2520 void *tbuff = rpmalloc(chunk);
2521#else
2522 void *tbuff = lives_malloc(chunk);
2523#endif
2524 start++;
2525 end = ocount - 1 - chunk;
2526 while (start + chunk < end) {
2527 lives_memcpy(tbuff, &buff[end], chunk);
2528 lives_memcpy(&buff[end], &buff[start], chunk);
2529 lives_memcpy(&buff[start], tbuff, chunk);
2530 start += chunk;
2531 end -= chunk;
2532 }
2533#ifdef USE_RPMALLOC
2534 rpfree(tbuff);
2535#else
2536 lives_free(tbuff);
2537#endif
2538 return TRUE;
2539 }
2540 }
2541
2543 count >>= 1;
2544
2545 if (count >= 8 && (ocount & 0x07) == 0) {
2546 // start by swapping 8 bytes from each end
2547 uint64_t *buff8 = (uint64_t *)buff;
2548 if ((void *)buff8 == (void *)buff) {
2549 end = ocount >> 3;
2550 for (; count >= 8; count -= 8) {
2552 uint64_t tmp8 = buff8[--end];
2553 if (chunk == 8) {
2554 buff8[end] = buff8[++start];
2555 buff8[start] = tmp8;
2556 } else {
2557 swab8(&buff8[++start], &buff8[end], chunk);
2558 swab8(&tmp8, &buff8[start], chunk);
2559 }
2560 }
2561 if (count <= chunk / 2) return TRUE;
2562 start = (start + 1) << 3;
2563 start--;
2564 }
2565 }
2566
2568 if (chunk >= 8) return FALSE;
2569
2570 if (count >= 4 && (ocount & 0x03) == 0) {
2571 uint32_t *buff4 = (uint32_t *)buff;
2572 if ((void *)buff4 == (void *)buff) {
2573 if (start > 0) {
2574 end = (ocount - start) >> 2;
2575 start >>= 2;
2576 } else end = ocount >> 2;
2577 for (; count >= 4; count -= 4) {
2579 uint32_t tmp4 = buff4[--end];
2580 if (chunk == 4) {
2581 buff4[end] = buff4[++start];
2582 buff4[start] = tmp4;
2583 } else {
2584 swab4(&buff4[++start], &buff4[end], chunk);
2585 swab4(&tmp4, &buff4[start], chunk);
2586 }
2587 }
2588 if (count <= chunk / 2) return TRUE;
2589 start = (start + 1) << 2;
2590 start--;
2591 }
2592 }
2593
2595 if (chunk >= 4) return FALSE;
2596
2597 if (count > 0) {
2598 uint16_t *buff2 = (uint16_t *)buff;
2599 if ((void *)buff2 == (void *)buff) {
2600 if (start > 0) {
2601 end = (ocount - start) >> 1;
2602 start >>= 1;
2603 } else end = ocount >> 1;
2604 for (; count >= chunk / 2; count -= 2) {
2606 uint16_t tmp2 = buff2[--end];
2607 if (chunk >= 2) {
2608 buff2[end] = buff2[++start];
2609 buff2[start] = tmp2;
2610 }
2612 else {
2613 swab2(&buff2[++start], &buff2[end], 1);
2614 swab2(&tmp2, &buff2[start], 1);
2615 // *INDENT-OFF*
2616 }}}}
2617 // *INDENT-ON*
2618
2619 if (count == 0) return TRUE;
2620 return FALSE;
2621}
2622
2623
2625static int16_t theflow[EFFORT_RANGE_MAX];
2626static int flowlen = 0;
2627static boolean inited = FALSE;
2628static int struggling = 0;
2629static int badthingcount = 0;
2630static int goodthingcount = 0;
2631
2632static int pop_flowstate(void) {
2633 int ret = theflow[0];
2634 flowlen--;
2635 for (int i = 0; i < flowlen; i++) {
2636 theflow[i] = theflow[i + 1];
2637 }
2638 return ret;
2639}
2640
2641
2642void reset_effort(void) {
2644 mainw->blend_palette = WEED_PALETTE_END;
2645 lives_memset(theflow, 0, sizeof(theflow));
2646 inited = TRUE;
2647 badthingcount = goodthingcount = 0;
2648 struggling = 0;
2650 && mainw->multitrack->is_rendering)) && !mainw->preview_rendering)
2652 else mainw->effort = 0;
2653}
2654
2655
2656void update_effort(int nthings, boolean badthings) {
2657 int spcycles;
2658 short pb_quality = prefs->pb_quality;
2659 if (!inited) reset_effort();
2660 if (!nthings) return;
2661
2662 if (nthings > EFFORT_RANGE_MAX) nthings = EFFORT_RANGE_MAX;
2663
2664 //g_print("VALS %d %d %d %d %d\n", nthings, badthings, mainw->effort, badthingcount, goodthingcount);
2665 if (badthings) {
2666 badthingcount += nthings;
2667 goodthingcount = 0;
2668 spcycles = -1;
2669 } else {
2670 spcycles = nthings;
2671 if (spcycles + goodthingcount > EFFORT_RANGE_MAX) spcycles = EFFORT_RANGE_MAX - goodthingcount;
2672 goodthingcount += spcycles;
2673 if (goodthingcount > EFFORT_RANGE_MAX) goodthingcount = EFFORT_RANGE_MAX;
2674 nthings = 1;
2675 }
2676
2677 while (nthings-- > 0) {
2678 if (flowlen >= EFFORT_RANGE_MAX) {
2680 int res = pop_flowstate();
2681 if (res > 0) badthingcount -= res;
2682 else goodthingcount += res;
2683 //g_print("vals %d %d %d ", res, badthingcount, goodthingcount);
2684 }
2686 theflow[flowlen] = -spcycles;
2687 flowlen++;
2688 }
2689
2690 //g_print("vals2x %d %d %d %d\n", mainw->effort, badthingcount, goodthingcount, struggling);
2691
2692 if (!badthingcount) {
2694 if (goodthingcount > EFFORT_RANGE_MAX) goodthingcount = EFFORT_RANGE_MAX;
2696 } else {
2697 if (badthingcount > EFFORT_RANGE_MAX) badthingcount = EFFORT_RANGE_MAX;
2698 mainw->effort = badthingcount;
2699 }
2700 //g_print("vals2 %d %d %d %d\n", mainw->effort, badthingcount, goodthingcount, struggling);
2701
2702 if (mainw->effort < 0) {
2703 if (struggling > -EFFORT_RANGE_MAX) {
2704 struggling--;
2705 }
2706 if (mainw->effort < -EFFORT_LIMIT_MED) {
2707 if (struggling == -EFFORT_RANGE_MAX && pb_quality < PB_QUALITY_HIGH) {
2708 pb_quality++;
2709 } else if (struggling < -EFFORT_LIMIT_MED && pb_quality < PB_QUALITY_MED) {
2710 pb_quality++;
2711 }
2712 }
2713 }
2714
2715 if (mainw->effort > 0) {
2716 if (pb_quality > future_prefs->pb_quality) {
2717 pb_quality = future_prefs->pb_quality;
2718 goto tryset;
2719 }
2720 if (!struggling) {
2721 struggling = 1;
2722 return;
2723 }
2724 if (mainw->effort > EFFORT_LIMIT_MED || (struggling > 0 && (mainw->effort > EFFORT_LIMIT_LOW))) {
2725 if (struggling < EFFORT_RANGE_MAX) struggling++;
2726 if (struggling == EFFORT_RANGE_MAX) {
2727 if (pb_quality > PB_QUALITY_LOW) {
2728 pb_quality = PB_QUALITY_LOW;
2729 } else if (mainw->effort > EFFORT_LIMIT_MED) {
2730 if (pb_quality > PB_QUALITY_MED) {
2731 pb_quality--;
2732 }
2733 }
2734 } else {
2735 if (pb_quality > future_prefs->pb_quality) {
2736 pb_quality = future_prefs->pb_quality;
2737 } else if (future_prefs->pb_quality > PB_QUALITY_LOW) {
2738 pb_quality = future_prefs->pb_quality - 1;
2739 }
2740 // *INDENT-OFF*
2741 }}}
2742 // *INDENT-ON
2743 tryset:
2744 if (pb_quality != prefs->pb_quality && (!mainw->frame_layer_preload || mainw->pred_frame == -1
2746 prefs->pb_quality = pb_quality;
2747 mainw->blend_palette = WEED_PALETTE_END;
2748 }
2749
2750 //g_print("STRG %d and %d %d\n", struggling, mainw->effort, prefs->pb_quality);
2751}
2752
2753
2754char *grep_in_cmd(const char *cmd, int mstart, int npieces, const char *mphrase, int ridx, int rlen) {
2755 char **lines, **words, **mwords;
2756 char *match = NULL;
2757 char buff[65536];
2758 size_t nlines, mwlen;
2759 int m, minpieces;
2760
2761 //break_me("GIC");
2762
2763 if (!mphrase || npieces < -1 || !npieces || rlen < 1 || (ridx <= mstart && ridx + rlen > mstart)
2764 || (npieces > 0 && (ridx + rlen > npieces || mstart >= npieces))) return NULL;
2765
2766 mwlen = get_token_count(mphrase, ' ');
2767 if (mstart + mwlen > npieces
2768 || (ridx + rlen > mstart && ridx < mstart + mwlen)) return NULL;
2769
2770 mwords = lives_strsplit(mphrase, " ", mwlen);
2771
2772 if (!cmd || !mphrase || !*cmd || !*mphrase) goto grpcln;
2773 lives_popen(cmd, FALSE, buff, 65536);
2774 if (THREADVAR(com_failed)
2775 || (!*buff || !(nlines = get_token_count(buff, '\n')))) {
2776 THREADVAR(com_failed) = FALSE;
2777 goto grpcln;
2778 }
2779
2780 minpieces = MAX(mstart + mwlen, ridx + rlen);
2781
2782 lines = lives_strsplit(buff, "\n", nlines);
2783 for (int l = 0; l < nlines; l++) {
2784 if (*lines[l] && get_token_count(lines[l], ' ') >= minpieces) {
2785 words = lives_strsplit(lines[l], " ", npieces);
2786 for (m = 0; m < mwlen; m++) {
2787 if (lives_strcmp(words[m + mstart], mwords[m])) break;
2788 }
2789 if (m == mwlen) {
2790 match = lives_strdup(words[ridx]);
2791 for (int w = 1; w < rlen; w++) {
2792 char *tmp = lives_strdup_printf(" %s", words[ridx + w]);
2793 match = lives_concat(match, tmp);
2794 }
2795 }
2796 lives_strfreev(words);
2797 }
2798 if (match) break;
2799 }
2800 lives_strfreev(lines);
2801 grpcln:
2802 lives_strfreev(mwords);
2803 return match;
2804}
2805
2806LIVES_LOCAL_INLINE boolean mini_run(char *cmd) {
2807 if (!cmd) return FALSE;
2808 lives_system(cmd, TRUE);
2809 lives_free(cmd);
2810 if (THREADVAR(com_failed)) return FALSE;
2811 return TRUE;
2812}
2813
2815 if (!cmd) return NULL;
2816 else {
2817 char buff[PATH_MAX];
2818 //char *com = lives_strdup_printf("%s $(%s)", capable->echo_cmd, EXEC_MKTEMP);
2819 lives_popen(cmd, TRUE, buff, PATH_MAX);
2820 lives_free(cmd);
2821 lives_chomp(buff);
2822 return lives_strdup(buff);
2823 }
2824}
2825
2826
2827LiVESResponseType send_to_trash(const char *item) {
2828 LiVESResponseType resp = LIVES_RESPONSE_NONE;
2829 boolean retval = TRUE;
2830 char *reason = NULL;
2831#ifndef IMPL_TRASH
2832 do {
2833 resp = LIVES_RESPONSE_NONE;
2835 reason = lives_strdup_printf(_("%s was not found\n"), EXEC_GIO);
2836 retval = FALSE;
2837 }
2838 else {
2839 char *com = lives_strdup_printf("%s trash \"%s\"", EXEC_GIO, item);
2840 retval = mini_run(com);
2841 }
2842#else
2849
2851
2855
2858 // see: https://specifications.freedesktop.org/trash-spec/trashspec-latest.html
2859 int vnum = 0;
2860 char *trashdir;
2861 char *mp1 = get_mountpount_for(item);
2862 char *mp2 = get_mountpount_for(capable->home_dir);
2863 if (!lives_strcmp(mp1, mp2)) {
2864 char *localshare = lives_strdup(capable->xdg_data_home);
2865 if (!*localshare) {
2866 lives_free(localshare);
2867 localshare = lives_build_path(capable->home_dir, LOCAL_HOME_DIR, "share", NULL);
2868 }
2869 trashdir = lives_build_path(localshare, "Trash", NULL);
2870 trashinfodir = lives_build_path(trashdir, "info", NULL);
2871 trashfilesdir = lives_build_path(trashdir, "files", NULL);
2872 umask = capable->umask;
2873 capable->umask = 0700;
2874 if (!check_dir_access(trashinfodir, TRUE)) {
2875 retval = FALSE;
2876 reason = lives_strdup_printf(_("Could not write to %s\n"), trashinfodir);
2877 }
2878 if (retval) {
2879 if (!check_dir_access(trashfilesdir, TRUE)) {
2880 retval = FALSE;
2881 reason = lives_strdup_printf(_("Could not write to %s\n"), trashfilesdir);
2882 }
2883 }
2884 capable->umask = umask;
2885 if (retval) {
2886 char *trashinfo;
2887 int fd;
2888 while (1) {
2889 if (!vnum) trashinfo = lives_strdup_printf("%s.trashinfo", basenm);
2890 else trashinfo = lives_strdup_printf("%s.%d.trashinfo", basenm, vnum);
2891 fname = lives_build_filename(trashinfodir, trashinfo, NULL);
2892 fd = lives_open2(fname, O_CREAT | O_EXCL);
2893 if (fd) break;
2894 vnum++;
2895 }
2896 // TODO - write stuff, close, move item
2897
2898
2899 }
2900 }
2902#endif
2903 if (!retval) {
2904 char *msg = lives_strdup_printf(_("LiVES was unable to send the item to trash.\n%s"), reason ? reason : "");
2905 lives_freep((void **)&reason);
2906 resp = do_abort_cancel_retry_dialog(msg);
2907 lives_free(msg);
2908 if (resp == LIVES_RESPONSE_CANCEL) return resp;
2909 }
2910 } while (resp == LIVES_RESPONSE_RETRY);
2911 return LIVES_RESPONSE_OK;
2912}
2913
2914
2916
2917char *get_wid_for_name(const char *wname) {
2918#ifndef GDK_WINDOWING_X11
2919 return NULL;
2920#else
2921 char *wid = NULL, *cmd;
2922 if (!wname || !*wname) return NULL;
2923
2925 cmd = lives_strdup_printf("%s -l", EXEC_WMCTRL);
2926 wid = grep_in_cmd(cmd, 3, 4, wname, 0, 1);
2927 lives_free(cmd);
2928 if (wid) return wid;
2929 }
2931 cmd = lives_strdup_printf("%s -name \"%s\" 2>/dev/null", EXEC_XWININFO, wname);
2932 wid = grep_in_cmd(cmd, 1, -1, "Window id:", 3, 1);
2933 lives_free(cmd);
2934 if (wid) return wid;
2935 }
2937 char buff[65536];
2938 size_t nlines;
2939 // returns a list, and we need to check each one
2940 cmd = lives_strdup_printf("%s search \"%s\"", EXEC_XDOTOOL, wname);
2941 lives_popen(cmd, FALSE, buff, 65536);
2942 lives_free(cmd);
2943 if (THREADVAR(com_failed)
2944 || (!*buff || !(nlines = get_token_count(buff, '\n')))) {
2945 if (THREADVAR(com_failed)) THREADVAR(com_failed) = FALSE;
2946 }
2947 else {
2948 char buff2[1024];
2949 char **lines = lives_strsplit(buff, "\n", nlines);
2950 for (int l = 0; l < nlines; l++) {
2951 if (!*lines[l]) continue;
2952 cmd = lives_strdup_printf("%s getwindowname %s", EXEC_XDOTOOL, lines[l]);
2953 lives_popen(cmd, FALSE, buff2, 1024);
2954 lives_free(cmd);
2955 if (THREADVAR(com_failed)) {
2956 THREADVAR(com_failed) = FALSE;
2957 break;
2958 }
2959 lives_chomp(buff2);
2960 if (!lives_strcmp(wname, buff2)) {
2961 wid = lives_strdup_printf("0x%lX", atol(lines[l]));
2962 break;
2963 }
2964 }
2965 lives_strfreev(lines);
2966 }
2967 }
2968 return wid;
2969#endif
2970}
2971
2972
2973boolean hide_x11_window(const char *wid) {
2974 char *cmd = NULL;
2975#ifndef GDK_WINDOWING_X11
2976 return NULL;
2977#endif
2978 if (!wid) return FALSE;
2980 cmd = lives_strdup_printf("%s windowminimize \"%s\"", EXEC_XDOTOOL, wid);
2981 return mini_run(cmd);
2982 }
2983 return FALSE;
2984}
2985
2986
2987boolean unhide_x11_window(const char *wid) {
2988 char *cmd = NULL;
2989#ifndef GDK_WINDOWING_X11
2990 return FALSE;
2991#endif
2992 if (!wid) return FALSE;
2994 cmd = lives_strdup_printf("%s windowmap \"%s\"", EXEC_XDOTOOL, wid);
2995 return mini_run(cmd);
2996}
2997
2998boolean activate_x11_window(const char *wid) {
2999 char *cmd = NULL;
3000#ifndef GDK_WINDOWING_X11
3001 return FALSE;
3002#endif
3003 if (!wid) return FALSE;
3004
3005 if (capable->has_xdotool != MISSING) {
3007 cmd = lives_strdup_printf("%s windowactivate \"%s\"", EXEC_XDOTOOL, wid);
3008 }
3009 else if (capable->has_wmctrl != MISSING) {
3011 cmd = lives_strdup_printf("%s -Fa \"%s\"", EXEC_WMCTRL, wid);
3012 }
3013 else return FALSE;
3014 return mini_run(cmd);
3015}
3016
3017
3018boolean get_wm_caps(void) {
3019 char *wmname;
3020 if (capable->has_wm_caps) return TRUE;
3022
3023#if IS_MINGW
3025 capable->wm_caps.root_window = gdk_screen_get_root_window(mainw->mgeom[widget_opts.monitor].screen);
3026#else
3027#ifdef GUI_GTK
3028 capable->wm_caps.is_composited = gdk_screen_is_composited(mainw->mgeom[widget_opts.monitor].screen);
3029 capable->wm_caps.root_window = gdk_screen_get_root_window(mainw->mgeom[widget_opts.monitor].screen);
3030#else
3032 capable->wm_caps.root_window = NULL;
3033#endif
3034#endif
3035
3036 capable->wm_type = getenv(XDG_SESSION_TYPE);
3037
3038 wmname = getenv(XDG_CURRENT_DESKTOP);
3039
3040 if (!wmname) {
3041 if (capable->wm_name) wmname = capable->wm_name;
3042 }
3043 if (!wmname) return FALSE;
3044
3046 lives_snprintf(capable->wm_caps.wm_name, 64, "%s", wmname);
3047
3048 if (!strcmp(capable->wm_caps.wm_name, WM_XFWM4) || !strcmp(capable->wm_name, WM_XFWM4)) {
3049 lives_snprintf(capable->wm_caps.panel, 64, "%s", WM_XFCE4_PANEL);
3052 lives_snprintf(capable->wm_caps.ssave, 64, "%s", WM_XFCE4_SSAVE);
3053 lives_snprintf(capable->wm_caps.color_settings, 64, "%s", WM_XFCE4_COLOR);
3054 lives_snprintf(capable->wm_caps.display_settings, 64, "%s", WM_XFCE4_DISP);
3055 lives_snprintf(capable->wm_caps.ssv_settings, 64, "%s", WM_XFCE4_SSAVE);
3056 lives_snprintf(capable->wm_caps.pow_settings, 64, "%s", WM_XFCE4_POW);
3057 lives_snprintf(capable->wm_caps.settings, 64, "%s", WM_XFCE4_SETTINGS);
3058 lives_snprintf(capable->wm_caps.term, 64, "%s", WM_XFCE4_TERMINAL);
3059 lives_snprintf(capable->wm_caps.taskmgr, 64, "%s", WM_XFCE4_TASKMGR);
3060 lives_snprintf(capable->wm_caps.sshot, 64, "%s", WM_XFCE4_SSHOT);
3061 return TRUE;
3062 }
3063 if (!strcmp(capable->wm_caps.wm_name, WM_KWIN) || !strcmp(capable->wm_name, WM_KWIN)) {
3064 lives_snprintf(capable->wm_caps.panel, 64, "%s", WM_KWIN_PANEL);
3065 lives_snprintf(capable->wm_caps.ssave, 64, "%s", WM_KWIN_SSAVE);
3066 lives_snprintf(capable->wm_caps.color_settings, 64, "%s", WM_KWIN_COLOR);
3067 lives_snprintf(capable->wm_caps.display_settings, 64, "%s", WM_KWIN_DISP);
3068 lives_snprintf(capable->wm_caps.ssv_settings, 64, "%s", WM_KWIN_SSAVE);
3069 lives_snprintf(capable->wm_caps.pow_settings, 64, "%s", WM_KWIN_POW);
3070 lives_snprintf(capable->wm_caps.settings, 64, "%s", WM_KWIN_SETTINGS);
3071 lives_snprintf(capable->wm_caps.term, 64, "%s", WM_KWIN_TERMINAL);
3072 lives_snprintf(capable->wm_caps.taskmgr, 64, "%s", WM_KWIN_TASKMGR);
3073 lives_snprintf(capable->wm_caps.sshot, 64, "%s", WM_KWIN_SSHOT);
3074 return TRUE;
3075 }
3076 return FALSE;
3077}
3078
3079
3080int get_window_stack_level(LiVESXWindow *xwin, int *nwins) {
3081#ifndef GUI_GTK
3082 if (nwins) *nwins = -1;
3083 return -1;
3084#else
3085 int mywin = -1, i = 0;
3086 LiVESList *winlist = gdk_screen_get_window_stack(mainw->mgeom[widget_opts.monitor].screen), *list = winlist;
3087 for (; list; list = list->next, i++) {
3088 if ((LiVESXWindow *)list->data == xwin) mywin = i;
3089 lives_widget_object_unref(list->data);
3090 }
3091 lives_list_free(winlist);
3092 if (nwins) *nwins = ++i;
3093 return mywin;
3094#endif
3095}
3096
3097
3098boolean show_desktop_panel(void) {
3099 boolean ret = FALSE;
3100#ifdef GDK_WINDOWING_X11
3101 char *wid = get_wid_for_name(capable->wm_caps.panel);
3102 if (wid) {
3103 ret = unhide_x11_window(wid);
3104 lives_free(wid);
3105 }
3106#endif
3107 return ret;
3108}
3109
3110boolean hide_desktop_panel(void) {
3111 boolean ret = FALSE;
3112#ifdef GDK_WINDOWING_X11
3113 char *wid = get_wid_for_name(capable->wm_caps.panel);
3114 if (wid) {
3115 ret = hide_x11_window(wid);
3116 lives_free(wid);
3117 }
3118#endif
3119 return ret;
3120}
3121
3122
3123boolean get_x11_visible(const char *wname) {
3124 char *cmd = NULL;
3125#ifndef GDK_WINDOWING_X11
3126 return FALSE;
3127#endif
3128 if (!wname || !*wname) return FALSE;
3130 char *state;
3131 cmd = lives_strdup_printf("%s -name \"%s\"", EXEC_XWININFO, wname);
3132 state = grep_in_cmd(cmd, 2, -1, "Map State:", 4, 1);
3133 lives_free(cmd);
3134 if (state && !strcmp(state, "IsViewable")) {
3135 lives_free(state);
3136 return TRUE;
3137 }
3138 }
3140 char buff[65536];
3141 size_t nlines;
3142
3143 // returns a list, and we need to check each one
3144 cmd = lives_strdup_printf("%s search --all --onlyvisible \"%s\" 2>/dev/null", EXEC_XDOTOOL, wname);
3145 lives_popen(cmd, FALSE, buff, 65536);
3146 lives_free(cmd);
3147 if (THREADVAR(com_failed)
3148 || (!*buff || !(nlines = get_token_count(buff, '\n')))) {
3149 if (THREADVAR(com_failed)) THREADVAR(com_failed) = FALSE;
3150 }
3151 else {
3152 char *wid = get_wid_for_name(wname);
3153 if (wid) {
3154 int l;
3155 char **lines = lives_strsplit(buff, "\n", nlines), *xwid;
3156 for (l = 0; l < nlines; l++) {
3157 if (!*lines[l]) continue;
3158 xwid = lives_strdup_printf("0x%08lX", atol(lines[l]));
3159 if (!strcmp(xwid, wid)) break;
3160 }
3161 lives_strfreev(lines);
3162 lives_free(wid);
3163 if (l < nlines) return TRUE;
3164 }
3165 }
3166 }
3167 return FALSE;
3168}
3169
3170#define XTEMP "XXXXXXXXXX"
3171
3172static char *get_systmp_inner(const char *suff, boolean is_dir, const char *prefix) {
3178 char *res = NULL;
3179
3180 if (!check_for_executable(&capable->has_mktemp, EXEC_MKTEMP)) return NULL;
3181 else {
3182 size_t slen;
3183 char *tmp, *com;
3184 const char *dirflg, *tmpopt;
3185 if (!prefix) {
3186 // no prefix, create in $TMPDIR
3187 if (suff) tmp = lives_strdup_printf("lives-%s-%s", XTEMP, suff);
3188 else tmp = lives_strdup_printf("lives-%s", XTEMP);
3189 tmpopt = "t";
3190 slen = lives_strlen(tmp) + 2;
3191 }
3192 else {
3194 char *tmpfile = lives_strdup_printf("%s%s", prefix, XTEMP);
3195 tmp = lives_build_filename(suff, tmpfile, NULL);
3196 lives_free(tmpfile);
3197 tmpopt = "";
3198 slen = lives_strlen(tmp);
3199 }
3200
3201 if (is_dir) dirflg = "d";
3202 else dirflg = "";
3203
3204 com = lives_strdup_printf("%s -n $(%s -q%s%s \"%s\")", capable->echo_cmd, EXEC_MKTEMP, tmpopt,
3205 dirflg, tmp);
3206 lives_free(tmp);
3207 res = mini_popen(com);
3208 if (!res) return NULL;
3209 if (THREADVAR(com_failed)) {
3210 lives_free(res);
3211 return NULL;
3212 }
3213 if (lives_strlen(res) < slen) {
3214 lives_free(res);
3215 return NULL;
3216 }
3217 }
3218 if (!lives_file_test(res, LIVES_FILE_TEST_EXISTS)
3219 || lives_file_test(res, LIVES_FILE_TEST_IS_SYMLINK)) {
3220 lives_free(res);
3221 return NULL;
3222 }
3223 if (is_dir) {
3224 if (!check_dir_access(res, FALSE)) {
3225 lives_free(res);
3226 return NULL;
3227 }
3228 }
3229 return res;
3230}
3231
3232char *get_systmp(const char *suff, boolean is_dir) {
3233 return get_systmp_inner(suff, is_dir, NULL);
3234}
3235
3236static char *_get_worktmp(const char *prefix, boolean is_dir) {
3237 char *dirname = NULL;
3238 char *tmpdir = get_systmp_inner(prefs->workdir, is_dir, prefix);
3239 if (tmpdir) {
3240 dirname = lives_path_get_basename(tmpdir);
3241 lives_free(tmpdir);
3242 }
3243 return dirname;
3244}
3245
3246char *get_worktmp(const char *prefix) {
3247 if (!prefix) return NULL;
3248 return _get_worktmp(prefix, TRUE);
3249}
3250
3251char *get_worktmpfile(const char *prefix) {
3252 if (!prefix) return NULL;
3253 return _get_worktmp(prefix, FALSE);
3254}
3255
3256
3257boolean check_snap(const char *prog) {
3258 // not working yet...
3260 char *com = lives_strdup_printf("%s find %s", EXEC_SNAP, prog);
3261 char *res = grep_in_cmd(com, 0, 1, prog, 0, 1);
3262 if (!res) return FALSE;
3263 lives_free(res);
3264 return TRUE;
3265}
3266
3267
3268boolean get_distro_dets(void) {
3269#ifndef IS_LINUX
3270 capable->distro_name = lives_strdup(capable->os_name);
3271 capable->distro_ver = lives_strdup(capable->os_release);
3272#else
3273#define LSB_OS_FILE "/etc/lsb-release"
3274 char *com = lives_strdup_printf("%s %s", capable->cat_cmd, LSB_OS_FILE), *ret;
3275 if ((ret = mini_popen(com))) {
3276 int xlen = get_token_count(ret, '=');
3277 char **array = lives_strsplit(ret, "=", xlen);
3278 lives_free(ret);
3279 if (xlen > 1) {
3280 lives_strstop(array[1], '\n');
3281 capable->distro_name = lives_strdup(array[1]);
3282 if (xlen > 2) {
3283 lives_strstop(array[2], '\n');
3284 capable->distro_ver = lives_strdup(array[2]);
3285 if (xlen > 3) {
3286 lives_strstop(array[3], '\n');
3287 capable->distro_codename = lives_strdup(array[3]);
3288 }}}
3289 lives_strfreev(array);
3290 return TRUE;
3291 }
3292#endif
3293 return FALSE;
3294}
3295
3296
3297int get_num_cpus(void) {
3298#ifdef IS_DARWIN
3299 kerr = host_processor_info(mach_host_self(), PROCESSOR_BASIC_INFO, &numProcessors, &processorInfo, &numProcessorInfo);
3300 if (kerr == KERN_SUCCESS) {
3301 vm_deallocate(mach_task_self(), (vm_address_t) processorInfo, numProcessorInfo * sizint);
3302 }
3303 return numProcessors;
3304#else
3305 char buffer[1024];
3306 char command[PATH_MAX];
3307#ifdef IS_FREEBSD
3308 lives_snprintf(command, PATH_MAX, "sysctl -n kern.smp.cpus");
3309#else
3310 lives_snprintf(command, PATH_MAX, "%s processor /proc/cpuinfo 2>/dev/null | %s -l 2>/dev/null",
3312#endif
3313 lives_popen(command, TRUE, buffer, 1024);
3314 return atoi(buffer);
3315#endif
3316}
3317
3318
3319boolean get_machine_dets(void) {
3320#ifdef IS_FREEBSD
3321 char *com = lives_strdup("sysctl -n hw.model");
3322#else
3323 char *com = lives_strdup_printf("%s -m1 \"^model name\" /proc/cpuinfo | %s -e \"s/.*: //\" -e \"s:\\s\\+:/:g\"",
3325#endif
3326 capable->cpu_name = mini_popen(com);
3327
3328 com = lives_strdup("uname -o");
3329 capable->os_name = mini_popen(com);
3330
3331 com = lives_strdup("uname -r");
3333
3334 com = lives_strdup("uname -m");
3336
3338
3339#if IS_X86_64
3340 if (!strcmp(capable->os_hardware, "x86_64")) capable->cacheline_size = get_cacheline_size();
3341#endif
3342
3343 com = lives_strdup("uname -n");
3345
3346 com = lives_strdup("whoami");
3347 capable->username = mini_popen(com);
3348
3349 if (THREADVAR(com_failed)) {
3350 THREADVAR(com_failed) = FALSE;
3351 return FALSE;
3352 }
3353 return TRUE;
3354}
3355
3356
3357#define DISK_STATS_FILE "/proc/diskstats"
3358
3359double get_disk_load(const char *mp) {
3360 if (!mp) return -1;
3361 else {
3362 static ticks_t lticks = 0;
3363 static uint64_t lval = 0;
3364 double ret = -1.;
3365 const char *xmp;
3366 char *com, *res;
3367 if (!lives_strncmp(mp, "/dev/", 5))
3368 xmp = (char *)mp + 5;
3369 else
3370 xmp = mp;
3371 com = lives_strdup_printf("%s -n $(%s %s %s)", capable->echo_cmd, capable->grep_cmd, xmp, DISK_STATS_FILE);
3372 if ((res = mini_popen(com))) {
3373 int xbits = get_token_count(res, ' ');
3374 char **array = lives_strsplit(res, " ", xbits);
3375 lives_free(res);
3376 if (xbits > 13) {
3377 uint64_t val = atoll(array[13]);
3378 ticks_t clock_ticks;
3379 if (LIVES_IS_PLAYING) clock_ticks = mainw->clock_ticks;
3380 else clock_ticks = lives_get_current_ticks();
3381 if (lticks > 0 && clock_ticks > lticks) ret = (double)(val - lval) / ((double)(clock_ticks - lticks)
3383 lticks = clock_ticks;
3384 lval = val;
3385 }
3386 lives_strfreev(array);
3387 }
3388 return ret;
3389 }
3390 return -1.;
3391}
3392
3393
3394#define CPU_STATS_FILE "/proc/stat"
3395
3396int64_t get_cpu_load(int cpun) {
3399 static uint64_t lidle = 0, lsum = 0;
3400 int64_t ret = -1;
3401 char *res, *target, *com;
3402 if (cpun > 0) target = lives_strdup_printf("cpu%d", --cpun);
3403 else if (cpun == 0) target = lives_strdup_printf("cpu");
3404 else target = lives_strdup_printf("btime");
3405 com = lives_strdup_printf("%s -n $(%s %s %s)", capable->echo_cmd, capable->grep_cmd, target, CPU_STATS_FILE);
3406 if ((res = mini_popen(com))) {
3407 int xbits = get_token_count(res, ' ');
3408 char **array = lives_strsplit(res, " ", xbits);
3409 lives_free(res);
3410 if (cpun == -1) {
3411 // get boot time
3412 if (xbits > 1) {
3413 ret = atoll(array[1]);
3414 }
3415 }
3416 else {
3417 if (xbits > 7) {
3418 uint64_t user = atoll(array[1]);
3419 uint64_t nice = atoll(array[2]);
3420 uint64_t sys = atoll(array[3]);
3421 uint64_t idle = atoll(array[4]);
3422 uint64_t iowait = atoll(array[5]);
3423 uint64_t irq = atoll(array[6]);
3424 uint64_t softirq = atoll(array[7]);
3425 uint64_t sum = user + nice + sys + idle + iowait + irq + softirq;
3426 if (lsum) {
3427 double load = 1. - (double)(idle - lidle) / (double)(sum - lsum);
3428 ret = load * (double)MILLIONS(1);
3429 }
3430 lsum = sum;
3431 lidle = idle;
3432 }
3433 lives_strfreev(array);
3434 }
3435 }
3436 return ret;
3437}
LIVES_GLOBAL_INLINE char * lives_get_audio_file_name(int fnum)
Definition: audio.c:55
#define ALIGN_DEF
Definition: colourspace.h:32
boolean do_header_write_error(int clip)
Definition: dialogs.c:4169
LIVES_GLOBAL_INLINE LiVESResponseType do_abort_cancel_retry_dialog(const char *text)
Definition: dialogs.c:708
LIVES_GLOBAL_INLINE LiVESResponseType do_error_dialog(const char *text)
Definition: dialogs.c:749
#define WEED_LEAF_INDEX
Definition: events.h:58
void * struct_from_template(lives_struct_type st_type)
Definition: lsd-tab.c:76
@ LIVES_STRUCT_FILE_DETS_T
Definition: lsd-tab.h:13
#define FUNCSIG_STRING_BOOL
void * quick_calloc(size_t n, size_t s)
Definition: machinestate.c:628
void * _ext_malloc(size_t n)
Definition: machinestate.c:530
LIVES_GLOBAL_INLINE const char * lives_strappendf(const char *string, int len, const char *fmt,...)
boolean show_desktop_panel(void)
#define FUNCSIG_DOUBLE
LIVES_GLOBAL_INLINE int lives_getgid(void)
LIVES_GLOBAL_INLINE weed_plantptr_t lives_proc_thread_join_plantptr(lives_proc_thread_t tinfo)
char * lives_datetime(uint64_t secs, boolean use_local)
Definition: machinestate.c:860
LIVES_GLOBAL_INLINE boolean lives_strcmp(const char *st1, const char *st2)
returns FALSE if strings match
boolean hide_desktop_panel(void)
#define FUNCSIG_VOIDP_VOIDP
boolean get_x11_visible(const char *wname)
boolean get_distro_dets(void)
LIVES_GLOBAL_INLINE int64_t lives_proc_thread_signalled_idx(lives_proc_thread_t tinfo)
char * get_md5sum(const char *filename)
Definition: machinestate.c:646
LIVES_GLOBAL_INLINE boolean lives_proc_thread_cancel(lives_proc_thread_t tinfo)
off_t get_dir_size(const char *dirname)
weed_plantptr_t lives_proc_thread_t
lives proc_threads API
boolean unhide_x11_window(const char *wid)
char * get_worktmpfile(const char *prefix)
LIVES_GLOBAL_INLINE void * lives_calloc_safety(size_t nmemb, size_t xsize)
Definition: machinestate.c:603
char * get_mountpoint_for(const char *dir)
lives_thread_data_t * lives_thread_data_create(uint64_t idx)
uint64_t get_ds_free(const char *dir)
Definition: machinestate.c:776
boolean activate_x11_window(const char *wid)
void make_nxttab(void)
Definition: machinestate.c:120
off_t get_file_size(int fd)
Definition: machinestate.c:943
LIVES_GLOBAL_INLINE int64_t lives_proc_thread_join_int64(lives_proc_thread_t tinfo)
LIVES_GLOBAL_INLINE int64_t disk_monitor_wait_result(const char *dir, ticks_t timeout)
Definition: machinestate.c:742
LIVES_GLOBAL_INLINE uint64_t lives_random(void)
Definition: machinestate.c:58
lives_proc_thread_t disk_monitor_start(const char *dir)
Definition: machinestate.c:717
#define FUNCSIG_PLANTP_VOIDP_INT64
LIVES_GLOBAL_INLINE void lives_proc_thread_free(lives_proc_thread_t lpt)
boolean init_memfuncs(void)
Definition: machinestate.c:630
#define DISK_STATS_FILE
LIVES_GLOBAL_INLINE weed_funcptr_t lives_proc_thread_join_funcptr(lives_proc_thread_t tinfo)
LIVES_GLOBAL_INLINE char * lives_proc_thread_join_string(lives_proc_thread_t tinfo)
#define FUNCSIG_VOIDP_STRING_STRING_INT64_INT
LIVES_GLOBAL_INLINE boolean lives_proc_thread_get_cancellable(lives_proc_thread_t tinfo)
LIVES_GLOBAL_INLINE size_t lives_strlen(const char *s)
off_t sget_file_size(const char *name)
Definition: machinestate.c:962
void init_random()
Definition: machinestate.c:92
LIVES_GLOBAL_INLINE int lives_proc_thread_join_int(lives_proc_thread_t tinfo)
void free_fdets_list(LiVESList **listp)
LIVES_GLOBAL_INLINE void * lives_free_and_return(void *p)
TODO: this file should be split into at least: memory functions, thread functions,...
Definition: machinestate.c:593
LIVES_GLOBAL_INLINE int lives_proc_thread_join_boolean(lives_proc_thread_t tinfo)
void * _ext_calloc(size_t nmemb, size_t msize)
Definition: machinestate.c:584
LIVES_GLOBAL_INLINE char * lives_strstop(char *st, const char term)
LIVES_LOCAL_INLINE char * mini_popen(char *cmd)
LIVES_GLOBAL_INLINE int lives_proc_thread_signalled(lives_proc_thread_t tinfo)
LIVES_LOCAL_INLINE boolean mini_run(char *cmd)
LIVES_GLOBAL_INLINE char * lives_strtrim(const char *buff)
void autotune_u64(weed_plant_t *tuner, uint64_t min, uint64_t max, int ntrials, double cost)
Definition: machinestate.c:182
LiVESResponseType send_to_trash(const char *item)
void * fg_run_func(lives_proc_thread_t lpt, void *retval)
void * _ext_malloc_and_copy(size_t bsize, const void *block)
Definition: machinestate.c:539
void _ext_free(void *p)
Definition: machinestate.c:556
void lives_threadpool_init(void)
LIVES_GLOBAL_INLINE void lives_proc_thread_set_cancellable(lives_proc_thread_t tinfo)
only threads with no return value can possibly be cancellable. For threads with a value,...
#define FUNCSIG_VOIDP
#define hasNulByte(x)
each byte B can be thought of as a signed char, subtracting 1 sets bit 7 if B was <= 0,...
#define FUNCSIG_INT
void disk_monitor_forget(void)
Definition: machinestate.c:769
lives_thread_data_t * get_thread_data(void)
LIVES_GLOBAL_INLINE char * lives_strdup_quick(const char *s)
LIVES_GLOBAL_INLINE void * lives_proc_thread_join_voidptr(lives_proc_thread_t tinfo)
#define CPU_STATS_FILE
#define FUNCSIG_STRING
LIVES_GLOBAL_INLINE char * lives_concat_sep(char *st, const char *sep, char *x)
#define FUNCSIG_STRING_STRING_VOIDP_INT
LIVES_GLOBAL_INLINE boolean lives_proc_thread_check(lives_proc_thread_t tinfo)
returns FALSE while the thread is running, TRUE once it has finished
#define FUNCSIG_INT_INT_BOOL_VOIDP
LIVES_GLOBAL_INLINE ticks_t lives_get_current_ticks(void)
Definition: machinestate.c:835
void update_effort(int nthings, boolean badthings)
int get_num_cpus(void)
boolean disk_monitor_running(const char *dir)
Definition: machinestate.c:715
LIVES_GLOBAL_INLINE int lives_strappend(const char *string, int len, const char *xnew)
LIVES_GLOBAL_INLINE lives_threadvars_t * get_threadvars(void)
void * _ext_memset(void *p, int i, size_t n)
Definition: machinestate.c:571
boolean check_dev_busy(char *devstr)
Definition: machinestate.c:876
LIVES_GLOBAL_INLINE int lives_getuid(void)
boolean get_machine_dets(void)
int64_t disk_monitor_check_result(const char *dir)
Definition: machinestate.c:726
#define FUNCSIG_STRING_STRING_VOIDP_INT_STRING_VOIDP
#define SECS_IN_DAY
Definition: machinestate.c:841
boolean hide_x11_window(const char *wid)
#define HASHROOT
boolean compress_files_in_dir(const char *dir, int method, void *data)
Definition: machinestate.c:898
double get_disk_load(const char *mp)
void quick_free(void *p)
Definition: machinestate.c:626
LIVES_GLOBAL_INLINE uint32_t fastrand_int(uint32_t range)
pick a pseudo random uint between 0 and range (inclusive)
Definition: machinestate.c:54
#define FUNCSIG_INT_INT_INT_BOOL_VOIDP
void _ext_unmalloc_and_copy(size_t bsize, void *p)
Definition: machinestate.c:547
LIVES_GLOBAL_INLINE void swab2(const void *from, const void *to, size_t gran)
void * _ext_memcpy(void *dest, const void *src, size_t n)
Definition: machinestate.c:567
lives_storage_status_t get_storage_status(const char *dir, uint64_t warn_level, int64_t *dsval, int64_t ds_resvd)
Definition: machinestate.c:693
uint64_t nxtval(uint64_t val, uint64_t lim, boolean less)
Definition: machinestate.c:198
#define FUNCSIG_VOID
#define NCYCS
Definition: machinestate.c:196
boolean check_snap(const char *prog)
void * _ext_free_and_return(void *p)
Definition: machinestate.c:565
boolean init_thread_memfuncs(void)
Definition: machinestate.c:638
void lives_threadpool_finish(void)
LIVES_GLOBAL_INLINE void fastrand_add(uint64_t entropy)
Definition: machinestate.c:47
char * get_wid_for_name(const char *wname)
x11 stuff
#define getnulpos_be(nulmask)
char * lives_format_storage_space_string(uint64_t space)
Definition: machinestate.c:664
LIVES_GLOBAL_INLINE uint32_t fast_hash(const char *key)
void * _ext_realloc(void *p, size_t n)
Definition: machinestate.c:575
LIVES_GLOBAL_INLINE size_t get_max_align(size_t req_size, size_t align_max)
Definition: machinestate.c:596
LIVES_GLOBAL_INLINE void swab4(const void *from, const void *to, size_t gran)
LIVES_GLOBAL_INLINE double fastrand_dbl(double range)
Definition: machinestate.c:49
int get_window_stack_level(LiVESXWindow *xwin, int *nwins)
#define XTEMP
uint64_t autotune_u64_end(weed_plant_t **tuner, uint64_t val)
Definition: machinestate.c:259
LIVES_GLOBAL_INLINE pid_t lives_getpid(void)
LIVES_GLOBAL_INLINE void lives_proc_thread_join(lives_proc_thread_t tinfo)
uint64_t gen_unique_id(void)
Definition: machinestate.c:68
off_t reget_afilesize_inner(int fileno)
LIVES_GLOBAL_INLINE char * lives_chomp(char *buff)
int stat_to_file_dets(const char *fname, lives_file_dets_t *fdets)
LIVES_GLOBAL_INLINE uint32_t lives_string_hash(const char *st)
#define get16bits(d)
LIVES_GLOBAL_INLINE boolean lives_strncmp(const char *st1, const char *st2, size_t len)
returns FALSE if strings match
LIVES_GLOBAL_INLINE char * lives_concat(char *st, char *x)
LIVES_GLOBAL_INLINE ticks_t lives_get_relative_ticks(ticks_t origsecs, ticks_t orignsecs)
Definition: machinestate.c:813
char * get_worktmp(const char *prefix)
#define FUNCSIG_VOIDP_DOUBLE
void reset_effort(void)
LIVES_GLOBAL_INLINE uint64_t fastrand(void)
Definition: machinestate.c:40
#define OIL_MEMCPY_MAX_BYTES
susbtitute memory functions. These must be real functions and not #defines since we need fn pointers
Definition: machinestate.c:430
int64_t get_cpu_load(int cpun)
percent * 1 million
#define DU_BLOCKSIZE
void resubmit_proc_thread(lives_proc_thread_t thread_info, lives_thread_attr_t attr)
(re)submission point, the function call is added to the threadpool tasklist if we have sufficient thr...
#define MINPOOLTHREADS
LIVES_GLOBAL_INLINE int lives_strcmp_ordered(const char *st1, const char *st2)
LIVES_GLOBAL_INLINE void reverse_bytes(char *buff, size_t count, size_t gran)
void * main_thread_execute(lives_funcptr_t func, int return_type, void *retval, const char *args_fmt,...)
uint64_t lives_thread_join(lives_thread_t work, void **retval)
boolean do_something_useful(lives_thread_data_t *tdata)
LIVES_GLOBAL_INLINE weed_plant_t * lives_plant_new_with_index(int subtype, int64_t index)
#define FUNCSIG_STRING_INT
void * _ext_memmove(void *dest, const void *src, size_t n)
Definition: machinestate.c:573
boolean get_wm_caps(void)
boolean is_empty_dir(const char *dirname)
#define FUNCSIG_PLANTP_BOOL
lives_proc_thread_t dir_to_file_details(LiVESList **listp, const char *dir, const char *orig_loc, uint64_t extra)
create a list from a (sub)directory '.
int check_for_bad_ffmpeg(void)
#define getnulpos(nulmask)
#define _join(stype)
lives_proc_thread_t lives_proc_thread_create(lives_thread_attr_t attr, lives_funcptr_t func, int return_type, const char *args_fmt,...)
create the specific plant which defines a background task to be run
LIVES_GLOBAL_INLINE boolean lives_proc_thread_cancelled(lives_proc_thread_t tinfo)
int lives_thread_create(lives_thread_t *thread, lives_thread_attr_t attr, lives_funcptr_t func, void *arg)
#define FUNCSIG_VOIDP_VOIDP_VOIDP
char * get_systmp(const char *suff, boolean is_dir)
void lives_get_randbytes(void *ptr, size_t size)
Definition: machinestate.c:60
boolean lives_proc_thread_dontcare(lives_proc_thread_t tinfo)
tell a threead with return value that we no longer need the value so it can free itself
char * lives_datetime_rel(const char *datetime)
Definition: machinestate.c:842
void * _item_to_file_details(LiVESList **listp, const char *item, const char *orig_loc, uint64_t extra, int type)
create a list from a (sub)directory '.
LIVES_GLOBAL_INLINE double lives_proc_thread_join_double(lives_proc_thread_t tinfo)
LIVES_GLOBAL_INLINE void * lives_recalloc(void *p, size_t nmemb, size_t omemb, size_t xsize)
Definition: machinestate.c:615
int _ext_memcmp(const void *s1, const void *s2, size_t n)
Definition: machinestate.c:569
#define FUNCSIG_INT_INT64
LIVES_GLOBAL_INLINE weed_plant_t * lives_plant_new(int subtype)
LIVES_GLOBAL_INLINE void lives_proc_thread_sync_ready(lives_proc_thread_t tinfo)
boolean reverse_buffer(uint8_t *buff, size_t count, size_t chunk)
LIVES_GLOBAL_INLINE void swab8(const void *from, const void *to, size_t gran)
void reget_afilesize(int fileno)
Definition: machinestate.c:972
#define _cpy_if_nonnull(d, s, size)
Definition: machinestate.c:527
lives_proc_thread_t ordfile_to_file_details(LiVESList **listp, const char *ofname, const char *orig_loc, uint64_t extra)
char * grep_in_cmd(const char *cmd, int mstart, int npieces, const char *mphrase, int ridx, int rlen)
LIVES_GLOBAL_INLINE void lives_srandom(unsigned int seed)
Definition: machinestate.c:56
#define WM_KWIN_SSAVE
Definition: machinestate.h:596
#define WM_XFCE4_COLOR
Definition: machinestate.h:586
#define LIVES_THRDFLAG_WAIT_SYNC
Definition: machinestate.h:432
#define XDG_CURRENT_DESKTOP
Definition: machinestate.h:605
#define WM_XFCE4_DISP
Definition: machinestate.h:587
#define CALL_4(ret, t1, t2, t3, t4)
Definition: machinestate.h:499
#define LIVES_THRDATTR_PRIORITY
Definition: machinestate.h:439
#define EXTRA_DETAILS_CHECK_MISSING
extras we can check for, may consume more time
Definition: machinestate.h:326
#define LIVES_WEED_SUBTYPE_TUNABLE
Definition: machinestate.h:203
LiVESList lives_thread_t
Definition: machinestate.h:434
#define LIVES_THRDATTR_FG_THREAD
Definition: machinestate.h:441
#define WEED_LEAF_DONTCARE_MUTEX
ensures we can set dontcare without it finishing while doing so
Definition: machinestate.h:419
#define CALL_0(ret)
Definition: machinestate.h:503
#define EXTRA_DETAILS_EXECUTABLE
Definition: machinestate.h:332
#define WEED_LEAF_SIGNAL_DATA
Definition: machinestate.h:422
#define WEED_LEAF_NOTIFY
Definition: machinestate.h:411
#define EXTRA_BYTES
TODO - split into: memory, files, sysops, threads.
Definition: machinestate.h:16
#define lives_nanosleep(nanosec)
Definition: machinestate.h:307
#define lives_calloc
Definition: machinestate.h:67
lives_storage_status_t
disk/storage status values
Definition: machinestate.h:181
@ LIVES_STORAGE_STATUS_CRITICAL
Definition: machinestate.h:185
@ LIVES_STORAGE_STATUS_NORMAL
Definition: machinestate.h:183
@ LIVES_STORAGE_STATUS_WARNING
Definition: machinestate.h:184
@ LIVES_STORAGE_STATUS_UNKNOWN
Definition: machinestate.h:182
@ LIVES_STORAGE_STATUS_OVER_QUOTA
Definition: machinestate.h:187
@ LIVES_STORAGE_STATUS_OVERFLOW
Definition: machinestate.h:186
#define WM_XFCE4_SETTINGS
Definition: machinestate.h:589
#define lives_memcmp
Definition: machinestate.h:58
#define CALL_VOID_6(t1, t2, t3, t4, t5, t6)
Definition: machinestate.h:481
#define EXTRA_DETAILS_SYMLINK
Definition: machinestate.h:329
#define WEED_PLANT_LIVES
Definition: machinestate.h:196
#define CALL_VOID_3(t1, t2, t3)
Definition: machinestate.h:484
#define LIVES_THRDATTR_NO_GUI
Definition: machinestate.h:442
#define WEED_LEAF_DONE
Definition: machinestate.h:412
#define CALL_3(ret, t1, t2, t3)
Definition: machinestate.h:500
#define WEED_LEAF_THREAD_CANCELLED
Definition: machinestate.h:416
#define CALL_2(ret, t1, t2)
Definition: machinestate.h:501
#define LIVES_THRDFLAG_AUTODELETE
Definition: machinestate.h:430
#define CALL_VOID_0()
Definition: machinestate.h:487
#define CALL_VOID_2(t1, t2)
Definition: machinestate.h:485
#define WM_XFCE4_TERMINAL
Definition: machinestate.h:590
#define WM_XFCE4_SSAVE
Definition: machinestate.h:585
#define EXTRA_DETAILS_MD5SUM
derived values
Definition: machinestate.h:336
#define WM_KWIN
Definition: machinestate.h:594
#define WM_XFWM4
Definition: machinestate.h:583
#define WM_KWIN_SETTINGS
Definition: machinestate.h:600
#define THREADVAR(var)
Definition: machinestate.h:531
#define lives_free
Definition: machinestate.h:52
#define LIVES_THRDATTR_WAIT_SYNC
Definition: machinestate.h:440
#define lives_memset
Definition: machinestate.h:61
#define WM_KWIN_POW
Definition: machinestate.h:599
#define WEED_LEAF_THREADFUNC
Definition: machinestate.h:413
#define lives_nanosleep_until_nonzero(condition)
Definition: machinestate.h:310
uint64_t funcsig_t
Definition: machinestate.h:453
#define WEED_LEAF_LIVES_SUBTYPE
Definition: machinestate.h:198
#define LIVES_WEED_SUBTYPE_PROC_THREAD
Definition: machinestate.h:204
#define CALL_1(ret, t1)
Definition: machinestate.h:502
#define WM_KWIN_COLOR
Definition: machinestate.h:597
uint64_t lives_thread_attr_t
Definition: machinestate.h:435
#define lives_malloc
Definition: machinestate.h:46
#define WEED_LEAF_THREAD_PARAM
Definition: machinestate.h:424
#define LIVES_THRDATTR_AUTODELETE
Definition: machinestate.h:438
#define WEED_LEAF_DONTCARE
tell proc_thread with return value that we n o longer need return val.
Definition: machinestate.h:418
#define WM_XFCE4_PANEL
Definition: machinestate.h:584
#define lives_memcpy
Definition: machinestate.h:55
#define CALL_VOID_1(t1)
Definition: machinestate.h:486
#define WM_KWIN_DISP
Definition: machinestate.h:598
#define WM_XFCE4_POW
Definition: machinestate.h:588
#define _RV_
Definition: machinestate.h:451
#define WM_KWIN_TERMINAL
Definition: machinestate.h:601
#define CALL_VOID_5(t1, t2, t3, t4, t5)
Definition: machinestate.h:482
#define EXTRA_DETAILS_CLIPHDR
Definition: machinestate.h:333
#define WM_KWIN_TASKMGR
Definition: machinestate.h:602
#define WEED_LEAF_SIGNALLED
Definition: machinestate.h:421
#define WEED_LEAF_THREAD_CANCELLABLE
Definition: machinestate.h:415
void *(* lives_funcptr_t)(void *)
Definition: machinestate.h:378
#define WEED_LEAF_RETURN_VALUE
Definition: machinestate.h:417
#define CALL_6(ret, t1, t2, t3, t4, t5, t6)
Definition: machinestate.h:497
#define WM_XFCE4_TASKMGR
Definition: machinestate.h:591
#define lives_memmove
Definition: machinestate.h:64
#define CALL_VOID_4(t1, t2, t3, t4)
Definition: machinestate.h:483
#define EXTRA_DETAILS_DIRSIZE
Definition: machinestate.h:327
#define lives_realloc
Definition: machinestate.h:49
#define WM_KWIN_SSHOT
Definition: machinestate.h:603
#define EXTRA_DETAILS_EMPTY_DIRS
Definition: machinestate.h:328
#define WM_KWIN_PANEL
Definition: machinestate.h:595
#define XDG_SESSION_TYPE
Definition: machinestate.h:606
#define WM_XFCE4_SSHOT
Definition: machinestate.h:592
#define LIVES_THRDATTR_NONE
Definition: machinestate.h:437
ssize_t sizint
type sizes
Definition: main.c:102
mainwindow * mainw
Definition: main.c:103
int get_frame_count(int idx, int xsize)
sets mainw->files[idx]->frames with current framecount
Definition: utils.c:3109
ssize_t lives_popen(const char *com, boolean allow_error, char *buff, ssize_t buflen)
Definition: utils.c:194
void lives_list_free_all(LiVESList **)
Definition: utils.c:4873
size_t get_token_count(const char *string, int delim)
Definition: utils.c:5430
#define is_layer_ready(layer)
Definition: main.h:1485
void lives_sync(int times)
Definition: utils.c:115
void cached_list_free(LiVESList **list)
Definition: utils.c:4881
int lives_touch(const char *tfile)
Definition: utils.c:4455
#define LIVES_GLOBAL_INLINE
Definition: main.h:239
int lives_chdir(const char *path, boolean no_error_dlg)
Definition: utils.c:1393
#define ANNOY_DISPLAY
Definition: main.h:441
#define ANNOY_FS
Definition: main.h:449
#define DEF_FILE_PERMS
non-executable, is modified by the umask
Definition: main.h:209
#define LIVES_IS_PLAYING
Definition: main.h:840
#define DEF_ALIGN
Definition: main.h:629
uint64_t lives_10pow(int pow) GNU_CONST
Definition: utils.c:1438
boolean lives_alarm_clear(lives_alarm_t alarm_handle)
Definition: utils.c:1732
#define LIVES_LOCAL_INLINE
Definition: main.h:246
int lives_system(const char *com, boolean allow_error)
Definition: utils.c:145
#define sig(a)
Definition: main.h:268
boolean is_writeable_dir(const char *dir)
Definition: utils.c:5701
char * lives_fgets(char *s, int size, FILE *stream)
Definition: utils.c:368
int create_nullvideo_clip(const char *handle)
Definition: saveplay.c:3808
const char * get_image_ext_for_type(lives_img_type_t imgtype)
Definition: utils.c:3025
void update_play_times(void)
like get_play_times, but will force redraw of audio waveforms
Definition: utils.c:3677
@ CLIP_DETAILS_ASAMPS
Definition: main.h:1153
@ CLIP_DETAILS_ACHANS
Definition: main.h:1150
@ CLIP_DETAILS_PB_ARATE
Definition: main.h:1149
@ CLIP_DETAILS_ARATE
Definition: main.h:1148
#define RES_HIDE
Definition: main.h:456
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
struct timeval tv
Definition: main.h:1136
int lives_rmdir(const char *dir, boolean force)
Definition: utils.c:4366
#define IS_VALID_CLIP(clip)
Definition: main.h:808
int lives_rm(const char *file)
Definition: utils.c:4395
int64_t ticks_t
Definition: main.h:97
capability * capable
Definition: main.h:627
#define RESTYPE_ACTION
Definition: main.h:462
@ MISSING
not yet implemented (TODO)
Definition: main.h:392
#define cfile
Definition: main.h:1833
int lives_open2(const char *pathname, int flags)
Definition: utils.c:99
boolean check_dir_access(const char *dir, boolean leaveit)
Definition: utils.c:4542
boolean check_for_executable(lives_checkstatus_t *cap, const char *exec)
Definition: utils.c:3434
lives_file_buffer_t * find_in_file_buffers(int fd)
Definition: utils.c:401
boolean read_headers(int clipno, const char *dir, const char *file_name)
Definition: saveplay.c:4465
#define PATH_MAX
Definition: main.h:255
boolean lives_freep(void **ptr)
Definition: utils.c:1411
#define LIVES_FATAL(x)
Definition: main.h:1886
char * make_image_file_name(lives_clip_t *clip, 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
boolean save_clip_value(int which, lives_clip_details_t, void *val)
Definition: utils.c:5175
ticks_t lives_alarm_check(lives_alarm_t alarm_handle)
Definition: utils.c:1687
@ CANCEL_NONE
no cancel
Definition: main.h:701
@ CANCEL_ERROR
cancelled because of error
Definition: main.h:740
#define EXEC_SNAP
Definition: mainwindow.h:431
#define MAINW_MSG_SIZE
mainw->msg bytesize
Definition: mainwindow.h:702
#define EXEC_XDOTOOL
Definition: mainwindow.h:427
#define BILLIONS(n)
Definition: mainwindow.h:24
#define ALL_USED
Definition: mainwindow.h:192
#define EXEC_DU
Definition: mainwindow.h:408
#define LIVES_FILE_TYPE_FLAG_MISSING
Definition: mainwindow.h:459
#define EXEC_WMCTRL
Definition: mainwindow.h:426
#define EXEC_GZIP
Definition: mainwindow.h:407
#define LIVES_LONGEST_TIMEOUT
Definition: mainwindow.h:45
#define LIVES_FILE_IS_DIRECTORY(ftype)
Definition: mainwindow.h:465
#define USEC_TO_TICKS
multiplying factor uSec -> ticks_t (def. 100)
Definition: mainwindow.h:38
#define EFFORT_LIMIT_MED
default 32
Definition: mainwindow.h:1772
#define LIVES_NO_ALARM
lives_alarms
Definition: mainwindow.h:1632
#define LIVES_FILE_TYPE_FLAG_SYMLINK
Definition: mainwindow.h:453
#define TICKS_PER_SECOND_DBL
actually microseconds / 100.
Definition: mainwindow.h:37
#define ONE_MILLION
Definition: mainwindow.h:27
#define LIVES_FILE_TYPE_FLAG_EXECUTABLE
Definition: mainwindow.h:454
#define EFFORT_LIMIT_LOW
default 8
Definition: mainwindow.h:1771
#define TICKS_TO_NANOSEC
Definition: mainwindow.h:39
#define EXEC_MKTEMP
Definition: mainwindow.h:430
#define EXEC_XWININFO
Definition: mainwindow.h:422
#define EXEC_GIO
Definition: mainwindow.h:429
#define MILLIONS(n)
Definition: mainwindow.h:26
#define EFFORT_RANGE_MAX
if set to TRUE during playback then a new frame (or possibly the current one) will be displayed ASAP
Definition: mainwindow.h:1770
#define LIVES_FILE_TYPE_DIRECTORY
Definition: mainwindow.h:441
#define LIVES_FILE_TYPE_FLAG_EMPTY
Definition: mainwindow.h:458
#define EXEC_MD5SUM
Definition: mainwindow.h:405
#define LIVES_FILE_TYPE_UNKNOWN
Definition: mainwindow.h:437
#define LOCAL_HOME_DIR
Definition: mainwindow.h:604
#define ONE_BILLION
Definition: mainwindow.h:25
int lives_alarm_t
Definition: mainwindow.h:696
#define LIVES_FILENAME_NOREMOVE
Definition: mainwindow.h:577
_prefs * prefs
Definition: preferences.h:847
#define PB_QUALITY_HIGH
Definition: preferences.h:34
#define PB_QUALITY_MED
default
Definition: preferences.h:33
#define PB_QUALITY_LOW
Definition: preferences.h:32
_future_prefs * future_prefs
Definition: preferences.h:848
void rpmalloc_thread_finalize(void)
Finalize thread, orphan heap.
Definition: rpmalloc.c:2577
void rpfree(void *ptr)
Free the given memory block.
Definition: rpmalloc.c:2612
RPMALLOC_ALLOCATOR void * rpmalloc(size_t size)
Allocate a memory block of at least the given size.
Definition: rpmalloc.c:2600
void rpmalloc_thread_collect(void)
Perform deferred deallocations pending for the calling thread heap.
Definition: rpmalloc.c:2720
int rpmalloc_is_thread_initialized(void)
Query if allocator is initialized for calling thread.
Definition: rpmalloc.c:2588
void rpmalloc_thread_initialize(void)
Initialize thread, assign heap.
Definition: rpmalloc.c:2562
RPMALLOC_ALLOCATOR void * rprealloc(void *ptr, size_t size)
Reallocate the given block to at least the given size.
Definition: rpmalloc.c:2644
int rpmalloc_initialize(void)
Initialize the allocator and setup global data.
Definition: rpmalloc.c:2318
RPMALLOC_ALLOCATOR void * rpaligned_calloc(size_t alignment, size_t num, size_t size)
Definition: rpmalloc.c:2675
short pb_quality
Definition: preferences.h:831
int nfx_threads
Definition: preferences.h:356
uint64_t disk_quota
Definition: preferences.h:383
double quota_limit
Definition: preferences.h:486
char workdir[PATH_MAX]
kept in locale encoding
Definition: preferences.h:61
boolean show_dev_opts
Definition: preferences.h:463
short pb_quality
Definition: preferences.h:31
char * os_name
Definition: main.h:612
char * distro_codename
Definition: main.h:618
lives_checkstatus_t has_xdotool
Definition: main.h:531
char home_dir[PATH_MAX]
home directory - default location for config file - locale encoding
Definition: main.h:544
char * cpu_name
Definition: main.h:582
char sed_cmd[PATH_MAX]
Definition: main.h:561
char grep_cmd[PATH_MAX]
Definition: main.h:560
int byte_order
Definition: main.h:577
char * distro_name
Definition: main.h:616
int64_t ds_tot
Definition: main.h:609
lives_checkstatus_t has_wmctrl
Definition: main.h:530
char * distro_ver
Definition: main.h:617
char wc_cmd[PATH_MAX]
Definition: main.h:562
char cat_cmd[PATH_MAX]
Definition: main.h:559
int64_t ds_free
Definition: main.h:609
char * wm_type
window manager type, e.g. x11
Definition: main.h:604
char * os_release
Definition: main.h:613
char * xdg_data_home
Definition: main.h:548
lives_checkstatus_t has_xwininfo
Definition: main.h:524
short cpu_bits
Definition: main.h:583
lives_checkstatus_t has_gio
Definition: main.h:537
wm_caps_t wm_caps
Definition: main.h:607
lives_checkstatus_t has_mktemp
Definition: main.h:540
char echo_cmd[PATH_MAX]
Definition: main.h:563
lives_checkstatus_t has_snap
Definition: main.h:541
char * wm_name
window manager name, may be different from wm_caps.wwm_name
Definition: main.h:605
lives_checkstatus_t has_gzip
Definition: main.h:526
char * os_hardware
Definition: main.h:614
char * mach_name
Definition: main.h:620
int cacheline_size
Definition: main.h:584
mode_t umask
Definition: main.h:597
lives_checkstatus_t has_du
Definition: main.h:535
char * username
Definition: main.h:595
boolean has_wm_caps
Definition: main.h:606
corresponds to one clip in the GUI
Definition: main.h:877
int arps
audio physical sample rate (i.e the "normal" sample rate of the clip when played at 1,...
Definition: main.h:905
frames_t frames
number of video frames
Definition: main.h:890
int asampsize
audio sample size in bits (8 or 16)
Definition: main.h:908
int vsize
frame height (vertical) in pixels
Definition: main.h:897
int achans
number of audio channels (0, 1 or 2)
Definition: main.h:907
int hsize
frame width (horizontal) in pixels (NOT macropixels !)
Definition: main.h:896
char name[CLIP_NAME_MAXLEN]
the display name
Definition: main.h:922
size_t afilesize
Definition: main.h:912
int arate
current audio playback rate (varies if the clip rate is changed)
Definition: main.h:906
double fps
Definition: main.h:893
boolean opening
Definition: main.h:946
boolean read
Definition: main.h:1612
ssize_t bytes
Definition: main.h:1605
off_t offset
ptr to data (ptr - buffer + bytes) gives the read size
Definition: main.h:1608
char * extra_details
only filled if EXTRA_DETAILS_MD5 is set, otherwis NULL
Definition: machinestate.h:357
uint64_t gid
userid as uint64_t
Definition: machinestate.h:348
lives_struct_def_t * lsd
Definition: machinestate.h:342
off_t size
e.g. LIVES_FILE_TYPE_FILE
Definition: machinestate.h:345
LiVESXScreen * screen
Definition: mainwindow.h:359
char msg[MAINW_MSG_SIZE]
Definition: mainwindow.h:724
lives_clip_t * files[MAX_FILES+1]
+1 for the clipboard
Definition: mainwindow.h:729
boolean is_rendering
Definition: mainwindow.h:821
lives_mgeometry_t * mgeom
multi-head support
Definition: mainwindow.h:1576
boolean dsu_valid
Definition: mainwindow.h:1791
frames64_t pred_frame
Definition: mainwindow.h:955
int current_file
Definition: mainwindow.h:727
boolean is_ready
Definition: mainwindow.h:787
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
volatile int blend_palette
here we can store the details of the blend file at the insertion point, if nothing changes we can tar...
Definition: mainwindow.h:980
volatile ticks_t clock_ticks
unadjusted system time since pb start, measured concurrently with currticks
Definition: mainwindow.h:1003
int ascrap_file
scrap file for recording audio scraps
Definition: mainwindow.h:875
lives_mt * multitrack
holds a pointer to the entire multitrack environment; NULL in Clip Edit mode
Definition: mainwindow.h:1087
boolean preview_rendering
Definition: mainwindow.h:758
int first_free_file
Definition: mainwindow.h:728
ticks_t wall_ticks
Definition: mainwindow.h:1004
weed_plant_t * frame_layer_preload
predictive caching apparatus
Definition: mainwindow.h:954
LiVESList * hdrs_cache
cache of a file header (e.g. header.lives)
Definition: mainwindow.h:1518
volatile boolean sync_ready
Definition: machinestate.h:408
volatile uint64_t done
Definition: machinestate.h:406
uint64_t flags
Definition: machinestate.h:404
volatile uint64_t busy
Definition: machinestate.h:405
lives_funcptr_t func
Definition: machinestate.h:402
boolean non_modal
non-modal for dialogs
int monitor
monitor we are displaying on
boolean is_composited
Definition: main.h:439
uint64_t pan_annoy
Definition: main.h:471
char settings[64]
Definition: main.h:484
char sshot[64]
Definition: main.h:487
char ssv_settings[64]
Definition: main.h:482
char display_settings[64]
Definition: main.h:481
char wm_name[64]
Definition: main.h:433
char panel[64]
Definition: main.h:470
char term[64]
Definition: main.h:485
LiVESXWindow * root_window
Definition: main.h:438
char ssave[64]
Definition: main.h:473
char color_settings[64]
Definition: main.h:480
char taskmgr[64]
Definition: main.h:486
uint64_t pan_res
Definition: main.h:472
char pow_settings[64]
Definition: main.h:483
#define lives_strdup_printf(fmt,...)
Definition: support.c:27
#define _(String)
Definition: support.h:44
weed_funcptr_t func
Definition: machinestate.h:506
#define TRUE
Definition: videoplugin.h:59
#define FALSE
Definition: videoplugin.h:60
void * lives_fg_run(lives_proc_thread_t lpt, void *retval)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_object_unref(livespointer object)
decrease refcount by one: if refcount==0, object is destroyed
widget_opts_t widget_opts