We were having a problem where property actions were
not getting state updates because prop_actions_connect
was triggered from some instance_init function while
the widget class is not in place yet.
Delay that call until the widget is fully constructed,
so we can guarantee that we are dealing with the
correct class private struct, and see all class actions.
Before this commit, adding GtkWidgetAction to class private data would
require copying the actions to each subclass as they were built or
modified. This was convenient in that it is a sort of "copy on write"
semantic.
However, due to the way that GTypeInstance works with base _init()
functions, the "g_class" pointer in GTypeInstance is updated as each
_init() function is called. That means you cannot access the subclasses
class private data, but only the parent class private data.
If instead we use a singly linked list of GtkWidgetAction, each subclass
has their own "head" yet all subclasses share the tail of the
GtkWidgetAction chain.
This creates one bit of complexity though. You need a stable way to know
which "bit" is the "enabled" bit of the action so we can track enabled
GAction state. That is easily solved by calculating the distance to the
end of the chain for a given action so that base classes sort ahead of
subclasses. Since the parent class always knows its parent's actions, the
position is stable.
A new dynamic bitarray helper also helps us avoid allocations in all the
current cases (up to 64 actions per widget) and dynamically switches to
malloc if that is to ever be exceeded.
The only cases of stateful actions we've seen
so far have been boolean properties, and we
don't really want to add much state handling
API, so lets just go with property actions
for now.
Adapt the only user in GtkText.
Add a facility to register and install actions
at class init time. The intended use for these
actions is for
a) context and other model-based menus
b) key bindings
Most of these actions are going to be stateless,
so add separate apis for the simple and stateful
cases.
We avoid creating an action group for these by
teaching the action muxer about these actions.
The action muxer also maintains the enabled
state for these actions.
Instead of duplicating this code in multiple places,
add an api to look up an action group for a prefixed
name, and return the unprefixed name at the same time.