Re: signals versus vfuncs



muppet schrieb:
Christof Petig said:

Perhaps widget derivation on the fly (take a base widget and override
just some vfuncs without adding member variables (extending the instance
struct)) should deserve an API ???

e.g.
  GType modify_type(GType base, const char *new_type_s_name, <list of
vfuncs and implementations>);
  void gobject_change_type(GObject *, GType new_type);


i've tried coming up with something like this, as a custom wrapper for my
bindings to use. it's not easy, and it doesn't seem useful in practice. overriding existing vfuncs means you have to have the struct offsets
someplace, and you have to know how to marshall them.  with all that, you
either need a database of vfuncs and parameter types, or custom code all over
the place, which means the modifier functions are pointless.  rather than use
the database (which would be runtime overhead), i've chosen the code route
(maintenance overhead, but faster at runtime).

The scheme I had originally in mind didn't need any database: simply use the C headers for the pointer offset (IIRC a vfunc is just a function pointer in the class structure [a static member in C++ terms]. And IIRC the class structs are simply appended to the parent class structure (which enables you to override vfuncs in derived widgets)).

So a list of <offset_t, function_ptr> would be sufficient. No need for marshalling (that's signal stuff [and, I fear, language binding stuff]). On the other hand type safety would be the task of the widget designer without the compiler to help. This is usual for C/gtk+ and gtkmm goes a long way to make it the task of the compiler.

But I think that this extension alone would be of little value to you or gtkmm users. That is because gtkmm has it's own flavor of vfuncs (virtual _member_ functions with C++ wrapped arguments: typically the first gtk+ argument has been hidden in this). It's a _feasible_ extension for C programmers which _might_ get a decent language wrapping (with type safety) if ever useful and implemented.

unfortunately, that trick doesn't work in Perl.  when called from C (e.g. deep
within gtk+), the function in the derived class will never get called --- only
when it is called from perl code.  e.g.:

  # THIS CODE DOESN"T WORK
  package MyRenderer;
  our @ISA = qw(Gtk2::CellRendererText);
  sub render {
      print "hi!\n";  # do custom stuff, like draw a special background
      SUPER::render @_; # chain to parent to do normal text drawing
  }

will override render when called from perl, but will not be seen when the
renderer is used in a TreeView.  instead, you need to do something like this:

but doesn't perl have polymorphism aka virtual functions? [If you call a member func in the base class which is virtual and overridden in a derived widget and your instance is in fact of the derived type the overridden functions is used.] Gtkmm uses this feature for its vfunc mechanism (which is no great pain to use).

Actually it's something like:
register a new type for the C++ instance (to enable vfunc overriding), override every vfunc by a wrapper (static [C like] member functions) which calls the virtual member function [with C++ wrapped arguments] (which in turn, if not overridden, unwraps the arguments and calls the original gtk+ functions). This costs some overhead for each vfunc call (additional indirection). [Actually the gtkmm implementation shortcuts wrapping/unwrapping and the middle indirection if possible]

So it should be possible to do something similar in perl (use a C written mediator which calls the perl render (virtual function) which by default would turn back to the gtk+ implementation). And a fast shortcut for the default case should be possible, too.

  package MyRenderer;
  use Glib::Object::Subclass 'Gtk2::CellRendererText';
  # special Gtk2::CellRenderer method which installs in the object class
  # special vfuncs that marshal to perl methods:
  __PACKAGE__->install_overrides;
  # this gets called by the vfunc installed above:
  sub on_render {
      # do custom stuff
      $self->parent_render (@_);
          # yet another custom way to call the parent's implementation,
          # because the public method accessible to SUPER would wind up
          # marshalling this function again.  comparable to
          # g_signal_chain_from_overridden().
  }


as you see, it's not impossible, it's just heinously ugly.

If possible this would reduce the 3 variants (render, on_render, parent_render) to one (render). Is it possible in perl to explicitely use a different virtual function (e.g. use the parent's one) though it is overriden in the actual instance. If not possible you still eliminate "on_render" but need parent_render.

on a side note, for GInterfaces things are different; still painful to bind,
but not so painful to use, because we don't need a hack in place of SUPER.

Please excuse my total lack of perl knowledge.
   Christof





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