Re: GType::register RFE
- From: Brett Kosinski <brettk frodo dyn gno org>
- To: muppet <scott asofyet org>
- Cc: gtk-perl-list gnome org
- Subject: Re: GType::register RFE
- Date: Tue, 25 Nov 2003 01:17:15 -0700 (MST)
Is there any way Glib::Object::Subclass can be enhanced to allow one to
pass in custom base_init and class_init functions (which would be executed
before/after the built-in ones)? I'm trying to implement element
subclassing in GStreamer, and in order to do it properly, I need to be
able to do this.
i made a few assumptions when writing Glib::Type::register:
1) we're only going to be creating GObject derivatives.
2) classes won't be finalized (because perl does not undefine code)
3) class_init will run only once (follows from 2)
given 2 and 3, there's no need to make the code wait around for class_init to
run, so we ref the class right there in register. this allows us to simplify
the programmer's interface to it, and take signals and properties as creation
parameters rather than requiring you to code those directly.
thus, there is no need for a class_init at the perl level. you can consider
the loading of your module to be class_init (your module gets parsed and
executed once, which is when the registration happens).
Well, the reason I'll likely need to provide custom class_init code is due
to what is really a problem with GStreamer (at least, IMHO). Basically,
in order to create a GstElement subclass, in addition to traditional
signal overrides, the code will quite often also override methods in the
virtual function table of the class. I consider this a GStreamer problem
because, as has been mentioned elsewhere, the official way to override
virtual functions is through the signal interface (at least, this was my
understanding). Unfortunately, I don't see this changing any time soon.
As a result, in order to implement subclassing, I need to be able to
define a class_init function which can do the nitty gritty work of
overriding these virtual methods (with a perlish interface to make it nice
when you get into base_init(), you have a void pointer, which is an
arbitrary class structure. when we do G_TYPE_FROM_CLASS on this
pointer, we get the gtype of the type being created --- *not* the gtype
of the one whose base we are initializing! if we could associate some
user data with that function pointer, we'd have no problems, but, well,
how the hell are we going to do that? i tried tacking some extra space
onto the class structure and storing information in there, but all i can
ever get from G_TYPE_FROM_CLASS is the bottommost type, not the one we
need. normal C code knows what type it's base-init-ing by what function
you've called, but we're going to be using the same function for all
perl-derived classed (unless somebody knows how to write self-modifying
C programs that don't get caught by noexec traps).
Hmm... okay, after stewing over this for a while, this is what I've come
up with. Basically, when we enter our gperl_base_init function, we don't
know the type we're currently initializing, right? However, we do know
the order in which the types are to be initialized (starting at the base
and working down the tree) and we can exploit this as follows:
1) When entering gperl_base_init for the first time for a given class
instance, we use G_TYPE_FROM_CLASS to get the type of the instance.
Then, we traverse backward (g_type_parent) and, for each type, do the
a) Check if the type is registered with us. If not, continue.
b) Otherwise, add the type to a linked list.
Then, we associate this linked list with the class pointer (perhaps
with a(nother) global GHashTable).
Okay, now, we know that each time we enter gperl_base_init for a given
class pointer, we're doing so for one of the types in the list we just
constructed (because the base_init process walks down the type tree, and
we're called only for GPerl-registered types). Moreover, we know the
order that these types will be initialized in (top-down). So, when we
first enter gperl_base_init, we build this list and associate it with the
class pointer. Then, we do the following:
1) Get the list for the given class instance and pull the last GType off
the list (our list is reversed, of course). This must be the type
being initialized (because of the known traversal order).
2) Use gperl_package_from_type to get the package for the type.
3) Call INIT_BASE for that package.
4) If there are no more entries in the list, remove the list from the
GHashTable and free it, since we're done base_init'ing (from Perl's
And voila. Assuming, of course, I'm not totally off my rocker. ;)
] [Thread Prev