diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2023-06-12 15:22:59 -0700 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2023-06-12 17:02:58 -0700 |
commit | a56b2c248356ec505f38b88651f26f92c00de981 (patch) | |
tree | 1f3b87f93de1b8ad38079db96a5401ac47f63418 | |
parent | 8b0c8e1e4336ce0c40c467fc86dec40fb2c94128 (diff) |
til: introduce "ref" built-in module
This opens up the possibility of referencing contexts on-stream
by-path anywhere a module may be used:
ref,path=/path/to/existing/context
Currently the path lookup is performed @ render time, and a
reference is taken on the context found there on the first time
it's located. That reference is then held in the ref's context
until its context is destroyed.
There are more details to flesh out, and what probably needs to
happen is some til_stream API for maintaining the reference in
the event that the context at that path gets replaced. Due to
refcounting, the referenced context will persist even if the
stream-resident instance goes away, but there should probably be
a way for that replacement to invalidate the existing references
so they replace theirs with a fresh lookup at the path...
Either way this is a good start. With this addition you can
effectively implement scene transitions in rkt, via the mixer
module, something like (sans proper escaping):
mixer,a_module=ref\,path=/foo/previous/ctxt,b_module=ref\,path=/foo/next/ctxt
-rw-r--r-- | src/til.c | 136 |
1 files changed, 133 insertions, 3 deletions
@@ -16,6 +16,7 @@ #include "til_fb.h" #include "til_module_context.h" #include "til_settings.h" +#include "til_stream.h" #include "til_threads.h" #include "til_util.h" @@ -107,6 +108,7 @@ void til_shutdown(void) } +/* "blank" built-in module */ static void _blank_prepare_frame(til_module_context_t *context, til_stream_t *stream, unsigned ticks, til_fb_fragment_t **fragment_ptr, til_frame_plan_t *res_frame_plan) { *res_frame_plan = (til_frame_plan_t){ .fragmenter = til_fragmenter_slice_per_cpu }; @@ -128,11 +130,139 @@ static til_module_t _blank_module = { }; +/* "ref" built-in module */ +#include "libs/txt/txt.h" /* for rendering some diagnostics */ + +typedef struct _ref_setup_t { + til_setup_t til_setup; + + char *path; +} _ref_setup_t; + + +typedef struct _ref_context_t { + til_module_context_t til_module_context; + + til_module_context_t *ref; +} _ref_context_t; + + +static til_module_context_t * _ref_create_context(const til_module_t *module, til_stream_t *stream, unsigned seed, unsigned ticks, unsigned n_cpus, til_setup_t *setup) +{ + _ref_context_t *ctxt; + + ctxt = til_module_context_new(module, sizeof(*ctxt), stream, seed, ticks, n_cpus, setup); + if (!ctxt) + return NULL; + + return &ctxt->til_module_context; +} + + +static void _ref_destroy_context(til_module_context_t *context) +{ + _ref_context_t *ctxt = (_ref_context_t *)context; + + ctxt->ref = til_module_context_free(ctxt->ref); + free(context); +} + + +static void _ref_render_fragment(til_module_context_t *context, til_stream_t *stream, unsigned ticks, unsigned cpu, til_fb_fragment_t **fragment_ptr) +{ + _ref_context_t *ctxt = (_ref_context_t *)context; + _ref_setup_t *s = (_ref_setup_t *)context->setup; + + if (!ctxt->ref) { + int r; + + /* TODO: switch to til_stream_find_module_context(), this clones concept is DOA. */ + r = til_stream_find_module_contexts(stream, s->path, 1, &ctxt->ref); + if (r < 0) { + txt_t *msg = txt_newf("%s: BAD PATH \"%s\"", context->setup->path, s->path); + + til_fb_fragment_clear(*fragment_ptr); + txt_render_fragment(msg, *fragment_ptr, 0xffffffff, + 0, 0, + (txt_align_t){ + .horiz = TXT_HALIGN_LEFT, + .vert = TXT_VALIGN_TOP, + }); + txt_free(msg); + /* TODO: maybe print all available contexts into the fragment? */ + return; + } + } + + til_module_render(ctxt->ref, stream, ticks, fragment_ptr); +} + + +static void _ref_setup_free(til_setup_t *setup) +{ + _ref_setup_t *s = (_ref_setup_t *)setup; + + free(s->path); + free(s); +} + + +static int _ref_setup(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup) +{ + const char *path; + int r; + + r = til_settings_get_and_describe_value(settings, + &(til_setting_spec_t){ + .name = "Context path to reference", + .key = "path", + .regex = "[a-zA-Z0-9/_]+", + .preferred = "", + }, + &path, + res_setting, + res_desc); + if (r) + return r; + + if (res_setup) { + _ref_setup_t *setup; + + setup = til_setup_new(settings, sizeof(*setup), _ref_setup_free); + if (!setup) + return -ENOMEM; + + setup->path = strdup(path); + if (!setup->path) { + til_setup_free(&setup->til_setup); + + return -ENOMEM; + } + + *res_setup = &setup->til_setup; + } + + return 0; +} + + +static til_module_t _ref_module = { + .create_context = _ref_create_context, + .destroy_context = _ref_destroy_context, + .render_fragment = _ref_render_fragment, + .setup = _ref_setup, + .name = "ref", + .description = "built-in context referencer", + .author = "built-in", +}; + + const til_module_t * til_lookup_module(const char *name) { - static const til_module_t *builtins[] = { - &_blank_module, - }; + static const til_module_t *builtins[] = { + &_blank_module, + &_ref_module, + }; static struct { const til_module_t **modules; size_t n_modules; |