From b02acd863102cd3b714930a99bcc7ec1fd1c0372 Mon Sep 17 00:00:00 2001 From: nick black Date: Fri, 17 Jan 2020 09:30:53 -0500 Subject: [PATCH] Curry a void* to fader callbacks #284 --- README.md | 11 ++++---- doc/man/man3/notcurses_fade.3.md | 12 ++++++-- doc/man/man3/notcurses_ncvisual.3.md | 8 ++++-- include/notcurses.h | 8 +++--- src/demo/demo.h | 16 ++++------- src/demo/fallin.c | 41 ++++++++++++++++++++++++++-- src/demo/hud.c | 3 +- src/demo/intro.c | 2 +- src/demo/outro.c | 4 +-- src/demo/trans.c | 4 ++- src/demo/witherworm.c | 2 +- src/lib/fade.c | 20 +++++++------- tests/fade.cpp | 15 +++++----- 13 files changed, 95 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 82b285e78..f35e1147f 100644 --- a/README.md +++ b/README.md @@ -1056,27 +1056,26 @@ My 14 year-old self would never forgive me if we didn't have sweet palette fades // Called for each delta performed in a fade on ncp. If anything but 0 is returned, // the fading operation ceases immediately, and that value is propagated out. If provided // and not NULL, the faders will not themselves call notcurses_render(). -typedef int (*fadecb)(struct notcurses* nc, struct ncplane* ncp); +typedef int (*fadecb)(struct notcurses* nc, struct ncplane* ncp, void* curry); // Fade the ncplane out over the provided time, calling the specified function // when done. Requires a terminal which supports direct color, or at least // palette modification (if the terminal uses a palette, our ability to fade // planes is limited, and affected by the complexity of the rest of the screen). -// It is not safe to resize or destroy the plane during the fadeout. -int ncplane_fadeout(struct ncplane* n, const struct timespec* ts, fadecb fader); +// It is not safe to resize or destroy the plane during the fadeout FIXME. +int ncplane_fadeout(struct ncplane* n, const struct timespec* ts, fadecb fader, void* curry); // Fade the ncplane in over the specified time. Load the ncplane with the // target cells without rendering, then call this function. When it's done, the // ncplane will have reached the target levels, starting from zeroes. -// It is not safe to resize or destroy the plane during the fadein. -int ncplane_fadein(struct ncplane* n, const struct timespec* ts, fadecb fader); +int ncplane_fadein(struct ncplane* n, const struct timespec* ts, fadecb fader, void* curry); // Pulse the plane in and out until the callback returns non-zero, relying on // the callback 'fader' to initiate rendering. 'ts' defines the half-period // (i.e. the transition from black to full brightness, or back again). Proper // use involves preparing (but not rendering) an ncplane, then calling // ncplane_pulse(), which will fade in from black to the specified colors. -int ncplane_pulse(struct ncplane* n, const struct timespec* ts, fadecb fader); +int ncplane_pulse(struct ncplane* n, const struct timespec* ts, fadecb fader, void* curry); ``` #### Plane channels API diff --git a/doc/man/man3/notcurses_fade.3.md b/doc/man/man3/notcurses_fade.3.md index ab95b1db8..73dcabd4e 100644 --- a/doc/man/man3/notcurses_fade.3.md +++ b/doc/man/man3/notcurses_fade.3.md @@ -11,14 +11,20 @@ notcurses_fade - fade ncplanes in and out **#include ** ```c +// Called for each delta performed in a fade on ncp. If anything but 0 is +// returned, the fading operation ceases immediately, and that value is +// propagated out. If provided and not NULL, the faders will not themselves +// call notcurses_render(). typedef int (*fadecb)(struct notcurses* nc, struct ncplane* ncp); ``` -**int ncplane_fadeout(struct ncplane* n, const struct timespec* ts);** +**bool notcurses_canfade(const struct notcurses* nc);** -**int ncplane_fadein(struct ncplane* n, const struct timespec* ts);** +**int ncplane_fadeout(struct ncplane* n, const struct timespec* ts, fadecb fader, void* curry);** -**int ncplane_pulse(struct ncplane* n, const struct timespec* ts, fadecb fader);** +**int ncplane_fadein(struct ncplane* n, const struct timespec* ts, fadecb fader, void* curry);** + +**int ncplane_pulse(struct ncplane* n, const struct timespec* ts, fadecb fader, void* curry);** # DESCRIPTION diff --git a/doc/man/man3/notcurses_ncvisual.3.md b/doc/man/man3/notcurses_ncvisual.3.md index 51c7dcaf7..b1eeb879a 100644 --- a/doc/man/man3/notcurses_ncvisual.3.md +++ b/doc/man/man3/notcurses_ncvisual.3.md @@ -9,9 +9,6 @@ notcurses_ncvisual - notcurses multimedia **#include ** -**struct ncvisual* ncplane_visual_open(struct ncplane* nc, const char* file, - int* averr);** - ```c typedef enum { NCSCALE_NONE, @@ -22,6 +19,11 @@ typedef enum { typedef int (*streamcb)(struct notcurses*, struct ncvisual*, void*); ``` +**bool notcurses_canopen(const struct notcurses* nc);** + +**struct ncvisual* ncplane_visual_open(struct ncplane* nc, const char* file, + int* averr);** + **struct ncvisual* ncvisual_open_plane(struct notcurses* nc, const char* file, int* averr, int y, int x, ncscale_e style);** diff --git a/include/notcurses.h b/include/notcurses.h index 81b55699c..8b2c23883 100644 --- a/include/notcurses.h +++ b/include/notcurses.h @@ -1435,26 +1435,26 @@ API unsigned ncplane_styles(struct ncplane* n); // Called for each delta performed in a fade on ncp. If anything but 0 is returned, // the fading operation ceases immediately, and that value is propagated out. If provided // and not NULL, the faders will not themselves call notcurses_render(). -typedef int (*fadecb)(struct notcurses* nc, struct ncplane* ncp); +typedef int (*fadecb)(struct notcurses* nc, struct ncplane* ncp, void* curry); // Fade the ncplane out over the provided time, calling the specified function // when done. Requires a terminal which supports direct color, or at least // palette modification (if the terminal uses a palette, our ability to fade // planes is limited, and affected by the complexity of the rest of the screen). // It is not safe to resize or destroy the plane during the fadeout FIXME. -API int ncplane_fadeout(struct ncplane* n, const struct timespec* ts, fadecb fader); +API int ncplane_fadeout(struct ncplane* n, const struct timespec* ts, fadecb fader, void* curry); // Fade the ncplane in over the specified time. Load the ncplane with the // target cells without rendering, then call this function. When it's done, the // ncplane will have reached the target levels, starting from zeroes. -API int ncplane_fadein(struct ncplane* n, const struct timespec* ts, fadecb fader); +API int ncplane_fadein(struct ncplane* n, const struct timespec* ts, fadecb fader, void* curry); // Pulse the plane in and out until the callback returns non-zero, relying on // the callback 'fader' to initiate rendering. 'ts' defines the half-period // (i.e. the transition from black to full brightness, or back again). Proper // use involves preparing (but not rendering) an ncplane, then calling // ncplane_pulse(), which will fade in from black to the specified colors. -API int ncplane_pulse(struct ncplane* n, const struct timespec* ts, fadecb fader); +API int ncplane_pulse(struct ncplane* n, const struct timespec* ts, fadecb fader, void* curry); // Working with cells diff --git a/src/demo/demo.h b/src/demo/demo.h index 7151c3aa6..708c75c8f 100644 --- a/src/demo/demo.h +++ b/src/demo/demo.h @@ -123,7 +123,7 @@ int hud_schedule(const char* demoname); // demo_render(), which will ensure the HUD stays on the top of the z-stack. int demo_render(struct notcurses* nc); -int demo_fader(struct notcurses* nc, struct ncplane* ncp); +int demo_fader(struct notcurses* nc, struct ncplane* ncp, void* curry); // grab the hud with the mouse int hud_grab(int y, int x); @@ -146,16 +146,12 @@ const demoresult* demoresult_lookup(int idx); /*----------------------------------HUD----------------------------------*/ static inline int -pulser(struct notcurses* nc, struct ncplane* ncp __attribute__ ((unused))){ - static struct timespec first = { .tv_sec = 0, .tv_nsec = 0, }; +pulser(struct notcurses* nc, struct ncplane* ncp __attribute__ ((unused)), void* curry){ + struct timespec* start = curry; struct timespec now; - if(timespec_to_ns(&first) == 0){ - clock_gettime(CLOCK_MONOTONIC, &first); - }else{ - clock_gettime(CLOCK_MONOTONIC, &now); - if(timespec_to_ns(&now) - timespec_to_ns(&first) >= timespec_to_ns(&demodelay) * 4 / 3){ - return 1; - } + clock_gettime(CLOCK_MONOTONIC, &now); + if(timespec_to_ns(&now) - timespec_to_ns(start) >= timespec_to_ns(&demodelay) * 4 / 3){ + return 1; } return demo_render(nc); } diff --git a/src/demo/fallin.c b/src/demo/fallin.c index 377269dd9..edb20f03e 100644 --- a/src/demo/fallin.c +++ b/src/demo/fallin.c @@ -1,4 +1,32 @@ #include "demo.h" +#include + +static bool done = false; +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + +static int +patentpulser(struct notcurses* nc, struct ncplane* ncp, void* curry){ + (void)ncp; + (void)curry; + if(notcurses_render(nc)){ + return -1; + } + bool donecheck; + pthread_mutex_lock(&lock); + donecheck = done; + pthread_mutex_unlock(&lock); + if(donecheck){ + return 1; + } + return 0; +} + +static void* +patentpulsar(void* n){ + struct notcurses* nc = n; + ncplane_pulse(notcurses_stdplane(nc), &demodelay, patentpulser, NULL); + return NULL; +} static int drop_bricks(struct notcurses* nc, struct ncplane** arr, int arrcount){ @@ -184,11 +212,20 @@ int fallin_demo(struct notcurses* nc){ ncvisual_destroy(ncv); return -1; } - notcurses_render(nc); + pthread_t tid; + if(pthread_create(&tid, NULL, patentpulsar, nc)){ + return -1; + } int ret = drop_bricks(nc, arr, arrcount); + sleep(1); + pthread_mutex_lock(&lock); + done = true; + pthread_mutex_unlock(&lock); + if(pthread_join(tid, NULL)){ + return -1; + } assert(ncvisual_decode(ncv, &averr) == NULL); assert(averr == AVERROR_EOF); ncvisual_destroy(ncv); - ncplane_pulse(notcurses_stdplane(nc), &demodelay, pulser); return ret; } diff --git a/src/demo/hud.c b/src/demo/hud.c index 6f26ee804..ca8e7b407 100644 --- a/src/demo/hud.c +++ b/src/demo/hud.c @@ -32,8 +32,9 @@ static struct elem* running; // it, and throw away the oldest entry each time. static int writeline = HUD_ROWS - 1; -int demo_fader(struct notcurses* nc, struct ncplane* ncp){ +int demo_fader(struct notcurses* nc, struct ncplane* ncp, void* curry){ (void)ncp; + (void)curry; return demo_render(nc); } diff --git a/src/demo/intro.c b/src/demo/intro.c index b3acd87f8..fa4e397b0 100644 --- a/src/demo/intro.c +++ b/src/demo/intro.c @@ -96,6 +96,6 @@ int intro(struct notcurses* nc){ } nanosleep(&demodelay, NULL); struct timespec fade = demodelay; - ncplane_fadeout(ncp, &fade, demo_fader); + ncplane_fadeout(ncp, &fade, demo_fader, NULL); return 0; } diff --git a/src/demo/outro.c b/src/demo/outro.c index 4f12ad743..d1f2146d9 100644 --- a/src/demo/outro.c +++ b/src/demo/outro.c @@ -27,7 +27,7 @@ fadethread(void* vnc){ struct notcurses* nc = vnc; struct ncplane* ncp = notcurses_stdplane(nc); struct timespec fade = { .tv_sec = 2, .tv_nsec = 0, }; - ncplane_fadeout(ncp, &fade, demo_fader); + ncplane_fadeout(ncp, &fade, demo_fader, NULL); ncvisual_destroy(chncv); int averr; char* path = find_data("samoa.avi"); @@ -158,7 +158,7 @@ int outro(struct notcurses* nc){ targy = 3; pthread_create(&tid, NULL, fadethread, nc); pthread_join(tid, &ret); - ncplane_fadeout(on, &demodelay, demo_fader); + ncplane_fadeout(on, &demodelay, demo_fader, NULL); ncplane_destroy(on); } if(ret == NULL){ diff --git a/src/demo/trans.c b/src/demo/trans.c index 6a5ed76b2..cb3d24af6 100644 --- a/src/demo/trans.c +++ b/src/demo/trans.c @@ -264,7 +264,9 @@ int trans_demo(struct notcurses* nc){ if(demo_render(nc)){ return -1; } - ncplane_pulse(l, &demodelay, pulser); + struct timespec now; + clock_gettime(CLOCK_MONOTONIC_RAW, &now); + ncplane_pulse(l, &demodelay, pulser, &now); ncplane_destroy(l); return slidepanel(nc); } diff --git a/src/demo/witherworm.c b/src/demo/witherworm.c index 63b986210..4d116642f 100644 --- a/src/demo/witherworm.c +++ b/src/demo/witherworm.c @@ -538,7 +538,7 @@ int witherworm_demo(struct notcurses* nc){ }else{ ns_to_timespec(delay, &tv); } - ncplane_fadein(n, &tv, demo_fader); + ncplane_fadein(n, &tv, demo_fader, NULL); } pthread_t tid; pthread_create(&tid, NULL, worm_thread, nc); diff --git a/src/lib/fade.c b/src/lib/fade.c index dd00e0305..105677642 100644 --- a/src/lib/fade.c +++ b/src/lib/fade.c @@ -81,7 +81,7 @@ alloc_ncplane_palette(ncplane* n, planepalette* pp){ static int ncplane_fadein_internal(ncplane* n, const struct timespec* ts, - fadecb fader, planepalette* pp){ + fadecb fader, planepalette* pp, void* curry){ int maxfsteps = pp->maxg > pp->maxr ? (pp->maxb > pp->maxg ? pp->maxb : pp->maxg) : (pp->maxb > pp->maxr ? pp->maxb : pp->maxr); int maxbsteps = pp->maxbg > pp->maxbr ? (pp->maxbb > pp->maxbg ? pp->maxbb : pp->maxbg) : @@ -133,7 +133,7 @@ ncplane_fadein_internal(ncplane* n, const struct timespec* ts, } } if(fader){ - ret |= fader(n->nc, n); + ret |= fader(n->nc, n, curry); }else{ ret |= notcurses_render(n->nc); } @@ -155,7 +155,7 @@ ncplane_fadein_internal(ncplane* n, const struct timespec* ts, return ret; } -int ncplane_fadeout(ncplane* n, const struct timespec* ts, fadecb fader){ +int ncplane_fadeout(ncplane* n, const struct timespec* ts, fadecb fader, void* curry){ planepalette pp; if(!n->nc->RGBflag && !n->nc->CCCflag){ // terminal can't fade return -1; @@ -227,7 +227,7 @@ int ncplane_fadeout(ncplane* n, const struct timespec* ts, fadecb fader){ cell_set_bg_rgb(&n->basecell, br, bg, bb); } if(fader){ - ret = fader(n->nc, n); + ret = fader(n->nc, n, curry); }else{ ret = notcurses_render(n->nc); } @@ -250,11 +250,11 @@ int ncplane_fadeout(ncplane* n, const struct timespec* ts, fadecb fader){ return ret; } -int ncplane_fadein(ncplane* n, const struct timespec* ts, fadecb fader){ +int ncplane_fadein(ncplane* n, const struct timespec* ts, fadecb fader, void* curry){ planepalette pp; if(!n->nc->RGBflag && !n->nc->CCCflag){ // terminal can't fade if(fader){ - fader(n->nc, n); + fader(n->nc, n, curry); }else{ notcurses_render(n->nc); } @@ -263,12 +263,12 @@ int ncplane_fadein(ncplane* n, const struct timespec* ts, fadecb fader){ if(alloc_ncplane_palette(n, &pp)){ return -1; } - int ret = ncplane_fadein_internal(n, ts, fader, &pp); + int ret = ncplane_fadein_internal(n, ts, fader, &pp, curry); free(pp.channels); return ret; } -int ncplane_pulse(ncplane* n, const struct timespec* ts, fadecb fader){ +int ncplane_pulse(ncplane* n, const struct timespec* ts, fadecb fader, void* curry){ planepalette pp; int ret; if(!n->nc->RGBflag && !n->nc->CCCflag){ // terminal can't fade @@ -278,11 +278,11 @@ int ncplane_pulse(ncplane* n, const struct timespec* ts, fadecb fader){ return -1; } for(;;){ - ret = ncplane_fadein_internal(n, ts, fader, &pp); + ret = ncplane_fadein_internal(n, ts, fader, &pp, curry); if(ret){ break; } - ret = ncplane_fadeout(n, ts, fader); + ret = ncplane_fadeout(n, ts, fader, curry); if(ret){ break; } diff --git a/tests/fade.cpp b/tests/fade.cpp index 006d62036..6a9c811a3 100644 --- a/tests/fade.cpp +++ b/tests/fade.cpp @@ -3,15 +3,14 @@ #include #include "internal.h" -struct timespec pulsestart; - -int pulser(struct notcurses* nc, struct ncplane* ncp __attribute__ ((unused))){ +int pulser(struct notcurses* nc, struct ncplane* ncp __attribute__ ((unused)), void* curry){ + struct timespec* pulsestart = static_cast(curry); if(notcurses_render(nc)){ return -1; } struct timespec now; clock_gettime(CLOCK_MONOTONIC_RAW, &now); - auto delta = timespec_to_ns(&now) - timespec_to_ns(&pulsestart); + auto delta = timespec_to_ns(&now) - timespec_to_ns(pulsestart); if(delta > 1000000000){ return 1; } @@ -53,19 +52,20 @@ TEST_CASE("Fade") { } } + SUBCASE("FadeOut") { CHECK(0 == notcurses_render(nc_)); struct timespec ts; ts.tv_sec = 1; ts.tv_nsec = 0; - CHECK(0 == ncplane_fadeout(n_, &ts, nullptr)); + CHECK(0 == ncplane_fadeout(n_, &ts, nullptr, nullptr)); } SUBCASE("FadeIn") { struct timespec ts; ts.tv_sec = 1; ts.tv_nsec = 0; - CHECK(0 == ncplane_fadein(n_, &ts, nullptr)); + CHECK(0 == ncplane_fadein(n_, &ts, nullptr, nullptr)); } SUBCASE("Pulse") { @@ -75,8 +75,9 @@ TEST_CASE("Fade") { ncplane_erase(n_); ncplane_set_fg(n_, 0xffd700); CHECK(0 < ncplane_printf_aligned(n_, dimy - 1, NCALIGN_CENTER, "pulllllllse")); + struct timespec pulsestart; clock_gettime(CLOCK_MONOTONIC_RAW, &pulsestart); - CHECK(0 < ncplane_pulse(n_, &ts, pulser)); + CHECK(0 < ncplane_pulse(n_, &ts, pulser, &pulsestart)); } CHECK(0 == notcurses_stop(nc_));