Chaining Class Closures



a long outstanding issue in the signal system is chaining from
class signal handlers to parent class signal handlers in language
bindings where custom closures are being used.
to enable that facility, i propose the addition of two new functions,
and like to discuss the public API here.

installing an overriding class closures for signals in derived
classes:
void g_signal_override_class_closure (guint     signal_id,
                                      GType     instance_type,
                                      GClosure *class_closure);
this function can't be used twice for the same instance_type,
and instance_type has to be derived from the itype that this
signal was created for (provided it's not an interface signal).


chaining from an overidden class_closure to a parent's type
class_closure will be done by:
void g_signal_chain_from_overridden (GSignalInvocationHint *ihint,
                                     GValue                *return_value,
                                     const GValue          *param_values);
where ihint has to be exactly the same pointer that was
passed to the class_closure currently being called from the
signal system. return_value and param_values[] have to consist
of the same types that were passed to that closure.
i'm not adding guint n_param_values, to the above prototype, as
that, and the length of the param_values[] array are implicit by
the signal id which is stored in GSignalInvocationHint.

for the implementation, i intend to encode in a hidden
portion of the GSignalInvocationHint, what closure is currently
being called from the signal system, for chaining, it can
then automatically figure what next parent type provides a class
closure and call it (i.e. encode the current chaining state in it).
the downside is that the following chaining setups can only be done
in C and not via class cloures:

struct BaseClass {
  void (*mysig) (Base*);
}
struct D1Class {
  BaseClass parent_class;
}
struct D2Class {
  D1Class parent_class;
}
void Base_mysig (Base *o);
void D1_mysig (Base *o);
void D2_mysig (Base *o)

/* initialize/override signal handlers for each class */
BaseClass *bclass = gtk_type_class (TYPE_BASE);
D1Class *d1class = gtk_type_class (TYPE_D1);
D2Class *d2class = gtk_type_class (TYPE_D2);
bclass->mysig = Base_mysig;
BASE_CLASS (d1class)->mysig = D1_mysig;
BASE_CLASS (d2class)->mysig = D2_mysig;
  
void D1_mysig (Base *o)
{
  gpointer class = gtk_type_class (TYPE_D1);
  gpointer parent_class = g_type_class_peek_parent (class);
  
  /* chain parent, this can be done for class_closures as well */
  BASE_CLASS (parent_class)->mysig (BASE (o)); // calls Base_mysig();

  /* chain parent twice, this cannot be done for class_closures */
  BASE_CLASS (parent_class)->mysig (BASE (o)); // calls Base_mysig();
}

void D2_mysig (Base *o)
{
  gpointer class = gtk_type_class (TYPE_D2);         
  gpointer parent_class = g_type_class_peek_parent (class);
  gpointer grandparent_class = g_type_class_peek_parent (parent_class);
  
  /* chain to parent of parent, this cannot be done for class_closures */
  BASE_CLASS (grandparent_class)->mysig (BASE (o)); // calls Base_mysig();
                                                    // instead of D1_mysig();
                                                    // which is the correct
                                                    // parent function to chain
}

Disclaimer: the above is pseudo code and of non-tutorial nature, in particular
            gtk_type_class() should be avoided in practice, it's being used
            here to simplify matters and spare class initializers.

however, both cases, chaining the parent class twice or chaining a grandparent
and omitting a parent type inbetween, are not used in C and are actually not
recommended. so i don't see limiting closure chaining to the point where
this is not possible, as a strong limitation.

comments, especially from LB authors, are apprechiated.

---
ciaoTJ




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]