the intention is to rely solely upon this abstract interface
in order to navigate the structure of the actual UI, so the
resolution process remains decoupled from the technicalities
of the actual UI toolkit set.
Through implementation of the corresponding unit test we'll determine
what it actually takes to build such a path resolution algorithm...
obviously, we get a trivial case, when the path is explicit,
and we need a tricky full blown resolution with backtracking
when forced to interpolate wildcards to cover a given UICoord
spec against the actual UI topology.
Do we need it?
* actually not right now
* but already a complete implementation of the ViewSpec concept
requires such a resolution
It is not possible to inherit through boost operators
and defining them explicitly is not that much fuss either.
Plus we avoid the boost include on widely used header
the usual drill...
once there is one additional non explicit conversion ctor,
lots of preferred conversion paths are opened under various conditions.
The only remedy is to define all ctors explicitly, instead of letting the
compiler infer them (from the imported base class ctors). Because this way
we're able to indicate a yet-more-preferred initialisation path and thus
prevent the compiler from going the conversion route.
In the actual case, the coordinate Builder is the culprit; obviously
we need smooth implicit conversion from builder expressions, and obviously
we also want to restrict Builder's ctors to be used from UICoord solely.
Unfortunately this misleads the compiler to do implement a simple copy construction
from non const reference by going through the prohibited Builder ctor, or to
instantiate the vararg-ctor inherited from PathArray.
Thus better be explicit and noisy...
After completing the self-contained UICoord data elements,
the next thing to consider might be how to resolve UI coordinates
against an actual window topology. We need to define a suitable
command-and-query interface in order to build and verify this
intricate resolution process separated from the actual UI code.
Explicitly assuming that those functions are called solely from IterAdapter
and that they are implemented in a typical standard style, we're able to elide
two redundant calls to the checkPoint() function. Since checkPoint typically performs
some non-trivial checks, this has the potential of a significant performance improvement
- we check (and throw ITER_EXHAUST) anyway from operator++, so we know that pos is valid
- the iterate() function ensures checkPoint is invoked right after iterNext,
and thus the typical standard implementation of iterNext need not do the same
...since that is what it meant to be.
To allow this chance, I've now added a default ctor to lib::Literal,
defaulting to the Symbol::EMPTY (the interned empty string)
The class Literal is used as a thin wrapper to mark the fact that
some string parameter or value is assumed to be given *literally*
For the contract this indicates
- that storage is somewhere
- storage is not owned and managed by Literal
- yet storage guaranteed to exist during the whole lifetime of the program
- Literal can not be altered
- Literal is transparently convertible to const char *
Currently I am in the course of building some path abstraction, and for that
task it makes sense to hold an array of Literals (instead of pointers), just
because it expresses the intent way more clear. I do not see anything in the
above mentioned contract to prohibit a default constructed Literal, with the
empty string being the most obvious choice.
Note: there is the class Symbol, which derives from Literal. Symbol takes
arbitrary strings, but *interns* them into a static symbol table.
...under the assumption that the content is normalised,
which means
- leading NULL is changed to Symbol::EMPTY
- missing elements in the middle are marked as "*"
- trailing NULL in extension storage is handled by adjusting nominal extension size
after various fruitless attempts to rely somehow on the array variant of unique_ptr,
I ended up with a hand coded version of an heap allocated array, managed automatically
as it turned out, the solution from yesterday works only with uniform argument lists,
but not with arbitrarily mixed types. Moreover the whole trickery with the
indices was shitty -- better use a predicate decision on template argument level.
This simple solution somehow just didn't occur to me...
...still somewhat unsatisfactory, because
- no clear compile error message when invoking pickArg with insufficient arguments
- the default initialisation case in SelectVararg is duplicated and messy
some time ago we abandoned our own tuple type in favour of std::tuple
Since then, the helpers and ported utilities provide some generic helpers
to deal with variadic argument sequences, especially to build index sequences,
which in turn can be used to "pick" individual arguments from a variadic parameter pack.
The expectation is for this part of the support library gradually to grow and
in parts to replace the existing type sequence processing helpers. The expectation
is that we'll retain the basic type sequence, lib::meta::Types, but retrofit it
to rely on variadic arguments
since the adoption of C++11, we gradually transition our metaprogramming helpers
to support and rely on variadic template parameters. For the time being,
we just augment existing facilities when it comes in handy, yet some more
heavyweight lifting and overall clean-up remains to be done eventually.
exploring the idea of a configuration DSL.
As a first step, this could be a simple internal DSL,
implemented as a bunch of static functor objects, which are internally bound
and thus implemented by the ViewLocator within InteractionDirector
responsible for access and allocation of component views.
Internally wired to the PanelLocator within the global WindowLocator
This setup settles those nasty qeustions of crosswise top-level access
this starts work on a new UI global topic (#1004)
- coin a new term: "view component"
- distinction between veiw component and Panel
- consider how to locate view components
- WindowList becomes WindowLocator
...since the generateErrorResponse() in UiDispatcher already adds some
explanatory boilerplate to the message; and we can not do anything beyond
publishing the message into the UI message box
basically DiffMessage has a "take everything" ctor, which happens
to match on type DiffMessage itslef, since the latter is obviously
a Lumiera Forward Operator. Unfortunately the compiler now considers
this "take everyting" ctor as copy constructor. Worse even, such a
template generated ctor qualifies as "best match".
The result was, when just returing a DiffMessage by value form a
function, this erroneous "copy" operation was invoked, thus wrapping
the existing implementation into a WrappedLumieraIterator.
The only tangible symptom of this unwanted storage bloat was the fact
that our already materialised diagnostics where seemingly "gone". Indee
they weren't gone for real, just covered up under yet another layer of
DiffMessage wrapping another Lumiera Forward Iterator
by moving, we can avoid the generation of up to 3 additional shared copies
of the DataHandle. The whole invocation now works without touching any shared count
and thus without incurring a memory barrier...
this becomes more relevant now, since the actual MutationMessage iterators
are implemented in terms of a shared_ptr to IterSource. Thus, when building
processing pipelines, we most definitively want to move that smart-ptr into
the destination, since this avoids touching the shared count and thus avoids
generating unnecessary memory barriers.
...allows us to get rid of quite some boost-includes
Incidentally, "our own" implementation is equivalent to both the
boost implementation and the implementation from C++14
It is just a bit more concise to write.
since we do not want to increase the footprint, we're bound to reuse
an existing VTable -- so IterAdapter itself is our only option.
Unfortunately we'll need to pass that through one additional
decoration layer, which is here the iterator; to be able to
add our string conversion there, we need to turn that into
a derived class and add a call to access the underlying
container, which gets us into element type definition mess....
now this highlights the unsettled decision still the more,
as can be seen by all that unnecessary copying. Basically we move the
Diff into the lambda-closure, from there into an anonymous instance,
from there into the embedded Buffer in MutationMessage, which again
just happens to sit in the closure storage when the action is invoked.
And all of this copying just to move the DiffMessage for consumption
into the TreeMutator...
thus by #1066 we should really get rid of the MutationMessage class altogether!
actually I do not know much regarding the actual situation when,
within the Builder run, we're able to detect a change and generate
a diff description. However, as a first step, I'll pick IterSrouce
as a base interface and use a "generation context", which is to be
passed by shared-ptr
basically we want a non-modal notification box in the UI,
which normally stays out of the way. A good example of how such
can be accomplished can be found in the Ardour UI.
This leads to the conclusion that we want to differentiate between
varoius degees of severity; some error conditions just can not be
ignored, and must be indicated in an obvious way, e.g. a prominent
nonmodal pop-up to appear for some seconds, while others just warant
an unobstrusive warning sign
again surprising how such fundamental bugs can hide for years...
Here the reason is that IterAdapter leaves the representation of "NIL" to
its instantiation / users; some users (here in for example the ScopedCollection)
can choose to allow for different representations of "NIL", but the comparison
provided by IterAdapter just compares the embedded pos by face value.
seems like most usages will want to expose this kind of diagnostics for unit testing
and in fact the queue or stack nature is the primary nature of this entity,
while iterability comes as additional trait
- concept for a first preliminary implementation of dispatch into the UI thread
- define an integration effort to build a complete working communication chain
This change was caused by investigation of UI event loop dispatch;
since the GTK UI is designed to run single threaded, any invocation
from other threads need to be diepatched explicitly.
A possible way to achieve this is to use Glib::Dispatcher, which
in turn requires that the current thread (which is in this case the UI thread)
already holds a Glib::MainContext
This prompted me to create a tight link between the external facade interfaces
of the UI and the event loop itself. What remains to be settled is how
to hand over arguments to the action in the main loop
This plugin is essentially an implementation detail, and there is no
mechanism yet to use several different implementations of the interface.
Thus it is pointless to expose the lifecycle methods on a public interface,
while there is no way to obtain an instance of this interface, since the
latter is confined to the internals of the UI subsystem lifecycle
After investigation of current GTK and GIO code, I came to the conclusion
that we do *not* want to rely on the shiny new Gtk::Application, which
provides a lot of additional "convenience" functionality we do neither
need nor want. Most notably, we do not want extended desktop integration
like automatically connecting to D-Bus or exposing application actions
as desktop events.
After stripping away all those optional functions and extensions, it turns
out the basic code to operate the GTK main event loop is quite simple.
This changeset extracts this code from the (deprecated) Gtk::Main and
integrates it directly in Lumiera's UI framework object (UiManager).
this is just a tiny change to make things more othogonal.
Now the unwinding and calls to any GTK / Widget dtors happen *after*
emitting the term signal from UI shutdown. Which means, the other subsystems
are shutting down (in their dedicated threads) as well, thus lowering
the probability of some action still using the UI and triggering an exception
as it turned out, the former functionality was deactivated in 2009
with changeset 6151415
The whole concept seems to be unfinished, and needs to be reworked
and integrated with "Views and Perspectives" (whatever that is...)
See also #1097
Gtk::Main is deprecated, but the new solution, instantiating a
Gtk::Application object does not match our use case, since we handle
all application concerns already and just need a Gtk main loop to run.
Anyway, it became clear that the "main object" will be the new UiManager.
As a first step, I've now moved the (deprecated) Gtk::Main object
down there. Next step (planned) will be to inherit from Gio::Application
and clone some functionality from Gtk::Application
...again to make it work with GCC-5,
also to allow more leeway using various compilers
Explanation: we use a helper function to abbreviate the
demangled type names to make diagnostic ouput more readable.
Obviously such a function needs to be adjusted to the
way concrete compilers generate their type output; GCC-5
slightly differs to GCC-4.9 here, so I've made the regular
expressions a bit more flexible
we have a catch-all template operator to get a string converted
or pretty printed output from "any object". Unfortunately
this overload counts equivalent to another overload by
the IO manipulators. Solution is to define both operarators
similar in the first argument, thus turing the overload
for the IO manipulators into the more specific overload
due to the explicitly given second argument
as a result of the preceding refactorings, we have created a
top level UI context, and most actions are now just forwarede
to a dedicated entity within this globalCtx, mostly to the
InteractionDirector.
Thus we're able to get rid of the one-liner functions in
the Actions class by directly delegating to the respective
entity from within the menu definition lambda.
Is this safe?
Under the assumption that the global context outlives the
GTK main loop, this is safe.
...which opens more questions than it solves at the moment.
Especially note #1096, the question how to refer to object-IDs
Maybe we need to enable sending EntryIDs via GenNode?
Anyway, the magic spell is broken now: we have a way how to
establish commands and how to issue them from the UI, with full integration
of UI-Bus, layer separation facade, instance management and ProcDispatcher
Looks like a stepping stone
after extended analysis, it turned out to be a "placeholder concept"
and introduces an indirection, which can be removed altogether
- simple command invocation happens at gui::model::Tangible
- it is based on the command (definition) ID
- instance management happens automatically and transparently
- the extended case of context-bound commands will be treated later,
and is entirely self-contained
while the initial design treated the commands in a strictly top-down manner,
where the ID is known solely to the CommandRegistry, this change and information
duplication became necessary now, since by default we now always enqueue and
dispatch anonymous clone copies from the original command definition (prototype).
This implementation uses the trick to tag this command-ID when a command-hanlde
is activated, which is also the moment when it is tracked in the registry.
due to the refactorings, the instance was moved out prior to checking for
bound arguments. This is ammended now, albeit at the price of passing an
additional flagn and some tricky boolean conditions
this seems like an obvious functionality and basically harmless,
since commands are designed to be inherently stateful, which is reflected
in all the internal storage holders to expos an assignment operator
(even while the actual implementation is based on placement new instead
of assigning values into the storage, and thus even supports immutable
values). The only possible ramification is that argument values must
be default constructible
in accordance to the design changes concluded yesterday.
- in the standard cases we now check the global registry first
- automatically create anonymous clone copy from global commands
- reorganise code internally to use common tail implementation
as it turns out, we can always trigger commands right away,
the moment all arguments are known. Thus it is sufficient to
send a single argument binding message, which allows us to
get rid of a lot or ugly complexities (payload visitor).
It seems more adequate to push the somewhat intricate mechanics
for the "fall back" onto generic commands down into the implementation
level of CommandInstanceManager. The point is, we know the standard
usage situation is to rely on the instance manager, and thus we want
to avoid redundant table lookups, only to support the rare case of
fallback to global commands. The latter is currently used only from
unit-tests, but might in future also be used by scripts.
Due to thread safety considerations, I have refrained from handing
out a direct reference to the command token sitting in the registry,
even while not doing so incurs a small runtime penalty (accessing
the shared ref-count for creating a copy of the smart-handle).
This is the typical situation where you'd be tempted to sacrifice
sanity for the sake of an imaginary performance benefit, which
in fact is dwarfed by all the machinery of UI-Bus and argument
passing via GenNode.
but I am not happy with the implementation yet: the maybeGet just
doesn't feel right. Likely it will be a better idea to push that
fallback mechanism generally down into the CommandInstanceManager?
this might turn into lock contention problem, but better optimise
a correct implementation than fix a fast yet broken one.
Hint: SessionCommandFunction_test demonstrates that the
symbol table can be corrupted by creating Symbol instances
in parallel without proper locking. So yes, this is for real.
since Symbol instance are now backed by a symbol table,
we can use a much faster hash function by just hashing the
pointer into the symbol table, since the Symbol string content
is already checked at initialisation.
Up to now, we tolerated null pointers in Literal instances.
But we can not tolerate passing a null cString to Symbol initialisation.
Rather, hereby we introduce a dedicated "bottom" Symbol, a valid "null object"
For this task, I've also investigated to use boost::operators
This would only incur a negligible penalty on build times and executable sizes,
however, I don't consider the boost based solution to improve readability,
since many of these comparisons are tricky or subtly different.
Moreover, since boost::operators needs to be mixed-in, the initialisation
of Symbol objects becomes difficult, not to mention the additional base class
information visible in the debugger when inspecting Symbol or Literal objects
For that reason, I decided *against* using Boost here and coded up
all the operators in all combinations manually
...which means, from now on identical input strings
will produce the same Symbol object (embedded pointer).
TODO: does not handle null pointers passed in as c-String properly
just by reasoning from the concept, an instance should always correspond
to a single invocation trail. Having several sets of invocation state
compete with each other, means to keep them distinct, otherwise the
implicit state is going to be corrupted
obsoleted by C++11
* in most cases, it can be replaced by an explicit conversion operator
* especially for the Lumiera Forward Iterators, we need an implicit conversion
This changeset fixes a huge pile of problems, as indicated in the
error log of the Doxygen run after merging all the recent Doxygen improvements
unfortunately, auto-linking does still not work at various places.
There is no clear indication what might be the problem.
Possibly the rather unstable Sqlite support in this Doxygen version
is the cause. Anyway, needs to be investigated further.
this is indeed a change of concept.
A 'command instance' can not be found through the official
Command front-end anymore, since we do not create a registration.
This allows us to avoid decorating command IDs with running counters
interesting new twist: we do not even need to decorate with a running number,
since we'll get away with an anonymous command instance, thanks to Command
being a smart-handle
it is not *that* hard to behave in a somewhat sane manner here.
And even more: this *is* basically the symbol table implementation we need.
Thus we only need to build the right front-end now...
...otherwise our log will be flooded with command definition messages soon
NOTE: to see all command definitions happening, set into environment:
NOBUG_LOG='command:TRACE
this is a prerequisite for command instance management:
We have now an (almost) complete framework for writing actual
command definitions in practice, which will be registered automatically.
This could be complemented (future work) by a script in the build process
to regenerate proc/cmd.hpp based on the IDs of those automatic definitions.
...better make it noncopyable to enforce the builder-style use.
In the recent test, I observed strange behaviour when erroneously passing
the CommandDef by value; the command seemed to be registered just fine,
but afterwards, the registry was empty. I must admit I don't understand
this, just from reading the code in CommandDef and Command it should
work just fine to activate a copy of the originally started CommandDef;
anyway, I didn't care to track that issue down, rather make the
CommandDef noncopyable as it should have been right from start.
...since there is not any test coverage for this trait, which
turned out to be quite deeply rooted in the system by now and
handles several rather subtle special cases
...and move the tail-call of the template instantiation into try.cpp
This experiment clearly shows the discrepancy now:
- binding a member pointer directly into a function object will expand the argument list
- but binding a similar lambda into a function object won't
(it is not necessary due to the context capture)
The result is that we need to drop support for one of those cases,
and it is clear that the member poiter will be the looser...
As a first step towards a gradual rework of our function metaprogramming helpers,
this change prepends a generic case for all kinds of functors to our existing
solution, which up to now was entirely based on explicit specialisations.
C++11 supplied the new language construct 'decltype(EXPR)', which allows us
to capture any class with an function operator, which also includes the Lambdas.
The solution was proposed 2011 on StackOverflow
http://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda/7943765#7943765
We used it already with success within our TreeMutator.
But obviously the goal should be to unite all the function trait / metaprogramming helpers,
which unfortunately is a more expensive undertaking, since it also involves
to get rid of the explicit specialisations and retrofit our Types<XXX...> helper
to rely on variadic templates rather than on loki-style typelists.
This first step here is rather conservative, since we'll still rely on our
explicit specialisations in most cases. Only the Lambdas will go through the
new, generic case, and from there invoke the specialisation for member functions.
The latter need to be rectified as well, which is subject of the next changeset...
The point in question is how to manage these definitions in practice,
since we're about to create a huge lot of them eventually. The solution
attempted here is heavily inspired by the boost-test framework
...because this topic serves as a vehicle to elaborate various core concepts
of the UI backbone, especially how to access, bind and invoke Proc-Layer commands