Age | Commit message (Collapse) | Author |
|
First elimination of open_memstream() usage...
|
|
Preparatory commit for bridging the gap separating a baked
til_setup_t from a runtime-populated descendant til_settings_t
like modules::rtv produces for its channels via
til_module_setup_randomize().
For these currently orphaned til_settings_t instances we don't
readily have access to the logical ancestor til_settings_t that
was used to produce the module_context's bound til_setup_t. But
we don't really need the ancestor til_settings_t, all we _really_
want is the ancestral path to prefix the orphan til_settings_t
instances.
So this commit introduces supplying a prefix which gets prepended
to paths printed via the settings instance. A later commit will
make use of this in modules::rtv when producing the settings
instance passed to til_module_setup_randomize()
|
|
These were being leaked by til_esttings_free()
|
|
In a world where "describing" settings is an iterative process,
especially post-nested-settings which are realized via the
desc-applying process, it's better to not even offer desc-setting
while adding a new setting.
This commit just gets rid of that.
The one caller that was passing a non-NULL desc to
til_settings_add_value(), til_module_setup_randomize(), was
redundantly doing so since the subsequent desc-processing was
assigning it again anyways. Future commits will likely change
til_module_setup_randomize() use a non-NULL desc for skipping
desc-applying, which wouldn't even work if it was always setting
the desc @ add time. That becomes necessary for partially
randomizing sparsely-populated settings.
|
|
In situations where modules wish to alias setting values like
expanding "all" -> "mod0,mod1,mod2,mod3" they need a way to
intercept the value-acceptance @ desc-assignment time in the
front-end. This optional override() function does just that when
present in the spec.
The current setting's value is passed to the override, and
if what's returned differs from what was passed (by pointer
value), then the current value is freed and the override takes
its place. The override function is expected to _always_ return
non-NULL; either the value provided, or a newly allocated value
override. The override function must never free the supplied
value, that's the front-end's job in applying the override.
The override() must return NULL on errors, which are assumed to
be limited to ENOMEM failures.
|
|
There doesn't seem to be a use case for inserting NULL-value
settings, and it's ergonomic to assume a til_setting_t.value is
always a non-NULL heap-allocated string.
|
|
These print to a stdio FILE*, which for now is harmless since
setup_interactively() will be the only consumer (... for now).
If one needed the path in a buffer, they could use
open_memstream() and pass that FILE* to the printers. And since
commit 40feb61 there's already a dependency on the function, but
it's icky to dig deeper into that portability trap.
Although it seemed like rototiller actually compiled on MacOS at
Gene's house, so maybe open_memstream() isn't as problematic as
it once was.
Anywhow, this commit only adds the path printing helpers, nothing
is using them yet.
|
|
Currently settings instances get labels from three sources:
1. explicitly labeled by a root-level til_settings_new() call,
like main.c::til_settings_new(NULL, "video", args->video);
2. implicitly labeled in a spec.as_nested_settings w/spec.key
3. positionally labeled in a spec.as_nested_settings w/o spec.key
But when constructing setting/desc paths, using strictly these
settings instance labels as the "directory name path component"
equivalent, leaves something to be desired.
Take this hypothetical module setting path for example:
/module/layers/[0]/viscosity
Strictly using settings instance labels as-is, the above is what
you'd get for the drizzle::viscosity setting in something like:
--module=compose,layers=drizzle
Which is really awkward. What's really desired is more like:
/module/compose/layers/[0]/drizzle/viscosity
Now one way to achieve that is to just create more settings
instances to hold these module names as labels and things would
Just Work more or less.
But that would be rather annoying and heavyweight, when what's
_really_ wanted is a way to turn the first entry's value of a
given setting instance into a sort of synthetic directory
component in the path.
So that's what this commit does. When a spec has .as_label
specified, it's saying that path construction should treat this
setting's value as if it were a label on a settings instance.
But it's special cased to only apply to descs hanging off the
first entry of a settings instance, as that's the only scenario
we're making use of, and it avoids having to do crazy things like
search all the entries for specs w/.as_label set.
It feels a bit janky but it does achieve what's needed with
little pain/churn.
|
|
Since these are ultimately intended for use in path construction,
it's redundant to include the settings->label in the generated
label. Instead what's really useful is just the subscript part:
/module/compose/layers/layers[0]/drizzle/viscosity
Becomes:
/module/compose/layers/[0]/drizzle/viscosity
which is far better. It may seem silly to have both the
positional subscript *and* the module name, as in why not just
have:
/module/compose/layers/drizzle/viscosity
But there's a need ot handle potential collisions like so:
/module/compose/layers/[0]/drizzle/viscosity
/module/compose/layers/[1]/stars
/module/compose/layers/[2]/drizzle/viscosity
So then maybe you think; ok, why have the module name? just use
the positional subscript since that alone prevents the
collisions. Result:
/module/compose/layers/[0]/viscosity
...
/module/compose/layers/[2]/viscosity
Well, now we've lost useful context. The viscosity setting
recurs on multiple modules, and we don't know just at a glance
what we're working with anymore.
Hence, why there's both. The module name in the path makes
things substantially more self-explanatory. These paths will
likely be what you're looking at as the labels of tracks in a
multitrack sequencer like GNU Rocket. So this decision is likely
affecting the UX at that level in the fullness of time.
|
|
Preparatory for constructing unique paths from a given
setting/settings instance by walking up the tree
|
|
til_settings_free() needs to recur on nested settings
|
|
settings->settings[] is obnoxious
largely mechanical rename to settings->entries[]
|
|
When there's a bare-value setting turned into a nested settings
instance, there's no key onhand for labeling the instance.
But such nameless settings are basically array elements only
positionally accessed. This helper produces labels in that style
for such settings by taking the container settings label and
adding [$idx] to the end.
These labels aren't really used as more than a debugging aid at
the moment. But module contexts already have paths in main, and
it seems like these settings instance labels will likely become
the name components in constructing those paths.
|
|
Currently in rototiller the only (de)serialization format of
settings is the args strings, so this is a rather critical piece
to get in for recursive settings to really be usable.
This is a quick and dirty implementation utilizing
open_memstream() which despite being POSIX has spotty support (I
don't think MacOS has it for instance). So that's probably
something to rip out in the future.
Nonetheless, this moves things forward and works fine on GNU.
|
|
This commit pivots everything over to using desc->container as
the target settings instance when adding settings, as well as
actually assigning the settings container @ desc create.
Given nothing is actually triggering settings heirarchies yet (no
specs set as_nested_settings) this shouldn't actually result in
any realized functional difference, yet. The settings pointer
being placed in desc->container should be identical to what was
getting used before.
|
|
There needs to be more flexibility in the value checking
enforcement.
This is just a quick blunt-hammer fix to not trip over nested
settings values which will be huge undeterministic messes vs.
what's likely just a set of simple presets in the spec.values[]
The individual leaf settings will still be checked if they
specify values. So this change just stops even bothering to
check unless the setting is a leaf.
This area needs more work in general, see comments.
For instance right now we can't just pass in arbitrary floats for
settings which list float values, not if that arbitrary float
isn't a member of the list. In some circumstances that's the
right thing to do, as in the module can only work with the
presets.
But most of the time, the module would be perfectly happy with e.g.
foo=.3379 with foo's spec.values[] = { .01, .1, .25, .75, 1} so
the check fails. That's dumb, and interferes with the creative
process when you're just poking different numbers into the
settings to see what happens.
TODO
|
|
Getter for accessing til_settings_t.num
With recursive settings modules will start using settings
instances to represent things like lists of module names.
(modules/compose::layers for instance)
For those cases they'll want to know the number of settings in
the instance before iterating across getting their values
positionally.
|
|
For recursive settings the individual setting being described
needs to get added to a potentially different settings instance
than the one being operated on at the top of the current
setup_func phase.
The settings instance being passed around for a setup_func to
operate on is constified, mainly to try ensure modules don't
start directly mucking with the settings. They're supposed to
just describe what they want next and iterate back and forth,
with the front-end creating the settings from the returned descs
however is appropriate, eventually building up the settings to
completion.
But since it's the setup_func that decides which settings
instance is appropriate for containing the setting.. at some
point it must associate a settings instance with the desc it's
producing, one that is going to be necessarily written to.
So here I'm just turning the existing til_setting_desc_t to a
"spec", unchanged. And introducing a new til_setting_desc_t
embedding the spec, accompanied by a non-const til_settings_t*
"container".
Now what setup_funcs use to express settings are a spec,
otherwise identically to before. Instead of cloning a desc to
allocate it for returning to the front-end, the desc is created
from a spec with the target settings instance passed in.
This turns the desc step where we take a constified settings
instance and cast it into a non-const a more formal act of going
from spec->desc, binding the spec to a specific settings
instance. It will also serve to isolate that hacky cast to a
til_settings function, and all the accessors of
til_setting_desc_t needing to operate on the containing settings
instance can just do so.
As of this commit, the container pointer is just sitting in the
desc_t but isn't being made use of or even assigned yet. This is
just to minimize the amount of churn happening in this otherwise
mostly mechanical and sprawling commit.
There's also been some small changes surrounding the desc
generators and plumbing of the settings instance where there
previously wasn't any. It's unclear to me if desc generators
will stay desc generators or turn into spec generators. For now
those are mostly just used by the drm_fb stuff anyways, modules
haven't made use of them, so they can stay a little crufty
harmlessly for now.
|
|
The core thing here is rather than turning a bare value into a
key as I was doing before - we just leave the bare value as a
bare value and its setting must be located positionally via
get_value_by_idx since there's no key.
Existing callers that used to get_key() positionally now
get_value_by_idx() positionally all the same, except it's the
value instead of the key. This is mostly done for things like
the module or fb name at the front of a settings instance.
The impetus for this change is partially just
cosmetic/ergonomics, but it's also rather strange for what's
really a key-less value to be treated as a value-less key. It
was also awkward to talk/reason about on the road to recursive
settings where bare values would be supported as a standalone
settings instance if properly escaped...
This also adds unescaping of keys, and adds a dependency on the
somewhat linux-specific open_memstream() which may need changing
in the future (see comments).
|
|
Preparatory commit for settings hierarchies.
|
|
This adds a mandatory label string to til_setttings_new() and
updates call sites accordingly.
For now the root-level settings created by main.c are simply
named "module" and "video" respectively. Any nested settings
creations on behalf of modules will be labeled using the module's
name the settings are being created for use with.
This might evolve with time, for now it's just a minimum churn
kind of decision. I can see it changing such that the top-level
settings also become labeled by the module/video driver name
rather than the obtuse "module" "video" strings.
How these will be leveraged is unclear presently. At the least
it'll be nice to have a label for debugging til_settings_t
heirarchies once recursive settings support lands. In a sense
this is a preparatory commit for that work. But I could see the
labels ending up in serialization contents as markup/syntactic
sugar just to self-document things as well.
There might also be a need to address til_settings_t instances in
the settings heirarchy, which may be something like a
"label/label/label/label" path style thing - though there'd be a
need to deal with name collisions in that approach.
I'm just thinking a bit about how knobs will become addressed
when those become a real thing. The settings label heirarchy
might be the convenient place to name everything in a tree, which
knobs could then inherit their parent paths from under which
their respective knob labels will reside. For the whole name
collision issue there could just be some builtin settings keys
for overriding the automatic module name labeling, something
like:
--module=compose,layers=checkers\,label=first\,fill_module=shapes:checkers\,label=second\,fill_module=shapes
would result in:
/module/first/shapes
/module/second/shapes
or in a world where the root settings weren't just named "module"
and "video":
/compose/first/shapes
/compose/second/shapes
then if there were knobs under checkers and shapes, say checkers
had a "foo" knob and checkers had a "bar" knob, they'd be under
.knobs in each directory:
/compose/first/.knobs/foo
/compose/first/shapes/.knobs/bar
/compose/second/.knobs/foo
/compose/second/shapes/.knobs/bar
something along those lines, and of course if compose had knobs
they'd be under /compose/.knobs
This is just a brain dump and will surely all change before
implemented.
|
|
This is a step towards properly handling nested settings, so we
can do stuff like:
--module=rtv,channels=compose\,layers=checkers\\\,fill_module=shapes\\\,size=64\,texture=plasma
and have rtv actually cycle through just compose with
checkers+plasma layers but holding the specified checkers
settings to shapes filler with a size of 64, randomizing the
rest.
There's more work to do before that can actually happen, but
first thing is to just support escaping the settings values.
|
|
Until now the fb init has been receiving a til_settings_t to
access its setup. Now that there's a til_setup_t for
representing the fully baked setup, let's bring the fb stuff
up to speed so their init() behaves more like
til_module_t.create_context() WRT settings/setup.
This involves some reworking of how settings are handled in
{drm,sdl}_fb.c but nothing majorly different.
The only real funcitonal change that happened in the course of
this work is I made it possible now to actually instruct SDL to
do a more legacy SDL_WINDOW_FULLSCREEN vs.
SDL_WINDOW_FULLSCREEN_DESKTOP where SDL will attempt to switch
the video mode.
This is triggered by specifying both a size=WxH and fullscreen=on
for video=sdl. Be careful though, I've observed some broken
display states when specifying goofy sizes, which look like Xorg
bugs.
|
|
I don't think rototiller is an appropriate place for being so
uncooperative, if someone gets the case wrong anywhere just make
it work. We should avoid making different things so subtly
different that case alone is the distinction anyways, so I don't
see this creating any future namespace collision problems.
|
|
The til_settings_get_and_describe_value() helper (and the calling
setup methods in the modules) can be useful in independently
spitting out a baked setup instance from a fully resolved
til_settings_t which has already gone through the whole
rigamarole of getting populated and described.
Normally when this all happens in one place with the setup
instance then either immediately fed to create_context(), or
stowed somewhere for future use, it's not a problem to always
require the res_desc,res_setting parameters.
But especially in GUI scenarios (glimmer) the whole populate and
describe phase of til_settings_t can very easily be done in a
separate place from the convenient place to produce a setup out
of it. So when the caller /knows/ the setup is finished and a
subsequent call with the same til_settings_t would produce a
res_setup immediately, the caller should be able to omit
res_setting and res_desc as they're of no use now.
This is all kind of crufty, but it's nice to have all this
happening in a single setup method to help keep the res_setup
phase from diverging/becoming out of sync with the
populate+describe phase. Will live with it for now. Frontends
get written far less than modules, so the API cruft from the
frontend perspective is relatively benign. It's still relatively
sane and ergonomic from the module writer's perspective.
|
|
Previously if you supplied an empty setting value like so:
"--module=compose,layers="
The interactive setup would get itself into an infinite loop
because the layers setting is already present, but has a NULL
value. This wasn't a NULL value, it was a "" value.
The parser should just fallthrough to the value state from the
equal state after recording the value's start pointer. This will
result in a "" value getting allocated and assigned to the value
before the loop breaks out on the '\0' immediately following the
'='.
There are probably other edge cases which need better handling
here.
|
|
Commit 7ff8ef included some fast and dirty fixups to
til_settings_apply_desc_generators(), but left an inappropriate
return path out of the iterator resulting in the caller accessing
a NULL res_desc.
The practical result of this was segfaulting in rototiller when
configuring anything utilizing desc generators, like drm_fb.
|
|
Particularly in implementing a stateful/"retained" GUI it can be
desirable to embed something like a widget pointer in a
til_setting_t once described and shown to the user.
Management of this pointer is largely nonexistant from the
libtil perspective. It's simply initialized to NULL when a new
setting is added, and never accessed again. 100% the caller's
responsibility.
This works fine since libtil/til_settings_t only accumulates
til_setting_t entries and never removes them except when
discarding an entire til_settings_t wholesale.
|
|
Now that til_setting_t.desc is not only a thing, but a thing that
is intended to be refreshed regularly in the course of things
like GUI interactive settings construction, it's not really
appropriate to try even act like this these are const anymore.
|
|
This is helpful for forcing underlying setup methods to
redescribe their settings, regardless of what a til_settings_t's
internal state is.
|
|
The existing iterative *_setup() interface only described
settings not found, quietly accepting usable settings already
present in the til_settings_t.
This worked fine for the existing interactive text setup thing,
but it's especially problematic for providing a GUI setup
frontend.
This commit makes it so the *_setup() methods always describe
undescribed settings they recognize, leaving the setup frontend
loop calling into the *_setup() methods to both apply the
description validation if wanted and actually tie the description
to respective setting returned by the _setup() methods as being
related to the returned description.
A new helper called til_settings_get_and_describe_value() has
been introduced primarily for use of module setup methods to
simplify this nonsense, replacing the til_settings_get_value()
calls and surrounding logic, but retaining the til_setting_desc_t
definitions largely verbatim.
This also results in discarding of some ad-hoc
til_setting_desc_check() calls, now that there's a centralized
place where settings become "described" (setup_interactively in
the case of rototiller).
Now a GUI frontend (like glimmer) would just provide its own
setup_interactively() equivalent for constructing its widgets for
a given *_setup() method's chain of returned descs. Whereas in
the past this wasn't really feasible unless there was never going
to be pre-supplied settings.
I suspect the til_setting_desc_check() integration into
setup_interactively() needs more work, but I think this is good
enough for now and I'm out of spare time for the moment.
|
|
Largely mechanical rename of librototiller -> libtil, but
introducing a til_ prefix to all librototiller (now libtil)
functions and types where a rototiller prefix was absent.
This is just a step towards a more libized librototiller, and til
is just a nicer to type/read prefix than rototiller_.
|