Exporting the Gtk+ object system to interpreters [was: no_marshall signals and GtkTypeInfo]



Tim Janik <timj@gtk.org> writes:

> 1998-12-06  Marius Vollmer  <mvo@zagadka.ping.de>
> 
>         * gtk/gtksignal.c (gtk_signal_newv): Allow a NULL marshaller.
>         (gtk_signal_connect_by_type): Allow only no_marshal handlers to
>         connect to signals with a NULL marshaller.
> 
>         * gtk/gtktypeutils.c (gtk_type_get_info): New.
>         gtk/gtktypeutils.h (gtk_type_get_info): New prototype.
> 
> could you tell us what your reasons are to expose the GtkTypeInfo structure
> to the user?

Of course.

I'm currently hacking (rather unfocused) on exporting the Gtk+ object
system to Guile Scheme.  For that I need a few hooks into the Gtk+
signal and type system.  I thought that the stuff that I committed is
innocent enough to just go in without much justification.  Obviously I
was wrong and I want to apologize for not following the `Dienstweg' ;-)

I think that most of your reservations are unfounded, but of course,
if I can't convince you (and Owen) of the usefulness and harmlessness
of the changes, then they should not go in.

Ok, here is what I have in mind for exposing the Gtk+ object system to
dynamic languages:

One of the problems are the class functions, I think.  With "class
function" I'm referring to the functions that are directly pointed to
from the class structures of a type, like gtk_button_draw.  I want to
be able to use interpreted functions for these class functions, altho
I'm not sure if I need them.  Therefore, I want to add this function
to Gtk+:

  void gtk_signal_set_class_function_full (GtkType            type,
	    				   const gchar       *signal,
		    			   GtkSignalFunc      func,
					   GtkCallbackMarshal marshal,
					   gpointer           data,
					   GtkDestroyNotify   destroy_func);

It would do some magic so that one is able to use the established
"full" interface for setting class functions, including ones with a
custom marshaller and destroy notification.  This can be done with an
overhead of two flag tests per signal invocation when the above
function has not been called on a type (which will be the ususal case)
and two additional words in GtkObjectClass.

The above function will cover replacing the default handler for
existing signals.  It should also be possible to add new signals to
new types.

The problem with that is to provide default marshal functions for
arbitrary new signals.  So I settled for allowing for signals without
default marshallers.  You can only connect handlers to such signals
that have their own custom marshaller.

Additionally, to derive at runtime from arbitrary types requires
knowledge about the sizes of their objects and their class struct.

The meat of the changes deal with the
gtk_signal_set_class_function_full function.  I have a patch that adds
it, but it's not ready for 1.2, I think.  The other two changes are
simply enough, in my view, so that they can go in 1.2.  That would
allow me (and probably other interpreter guys) to usefully hook into
the Gtk+ object system in a way that is enough for composite widgets
(like the TicTacToe from the tutorial for example, which already works
in Guile).

I hope we can find a way that both of us are happy.

> there are a variety of reasons to not expose this structure through
> the API. for one we keep internal private data in there that no one
> needs to mess with or should rely on to have a certain meaning.

The private data is not exported.  gtk_type_get_info only hands you
back the information that was put into gtk_type_unique.  Additionally,
gtk_type_get_info can not be abused to change the internal copy of the
GtkTypeInfo.

In general, I'm not much of a fan of `write-only' interfaces.  If
possible, an interface should be able to give you the information back
you have put into it.

> for two, these structures are allocated through a dynamic array, so
> they may become invalidated at any point.

gtk_type_info does not return pointers to internals data structures.
Instead, it copies the GtkTypeInfo member of the GtkTypeNode structure
into space provided by the user.  There is no danger when the internal
data structure gets moved about.

> regarding your signal changes, please take into account that there
> may exists third party code that will eventuall want to conect to
> any signal of an object. so marshallers are a must to be provided.

A default marshaller is a must for signals that want to allow
connections from handlers that are written in C in the usual fashion.
I see the creation of a signal without a default marshaller as a
conscious act of saying: "Look, as much as I like to, I just *can't*
give you a default marshaller.  I know that C handlers with a static
interface can't connect to this signal, but I'm willing to live with
that."  From my point of view, this is a reasonable compromise because
C handlers with a static interface that want to connect to dynamically
(at run-time) defined signals can be avoided without loosing
functionality (but convenience).

Let me chew on the "C handler with static interface" thing a bit more.

I'm referring to the `usual' way to define handlers in C: functions
that receive their arguments in the normal C style:

    gboolean
    button_press_event_handler (GtkObject *obj, GdkEvent *ev, void *data)
    {
       ...
    }

When you write such a function, you need to know the precise signature
of the signal.  I venture that most of not all signals that you want
to connect to in such a way are also defined in C and thus have a
default marshaller.  It will onyl very, very seldomly happen that you
want to connect a static-interface C handler to a signal defined in
Scheme (or Perl, Phython, ...).  If you want to correctly connect to
arbitrary signals from C, the only way I can see is to use a custom
marshaller anyway.

Even if it does happen, not all is lost.  That is why I have
emphasized the static-interface bit.  You *can* write C handlers that
use their own custom marshaller.  This is not convenient, but
possible.  In effect you would do the job that the signal definer
couldn't do.  That's not ideal but OK, in my view.

> apart from that, allowing one to pass NULL into gtk_signal_new() can
> not be integreated well with an automatic marshaller lookup that we
> may want to implement at a later point.

The NULL just means "I can't provide a default marshaller".  When Gtk+
can find a suitable marshaller, the much the better.  So I don't see a
problem here.

> i'm certainly willing in helping you out with better ways to achive
> what you actually intended, e.g. supplying a GtkTypeQuery mechanism
> or something similar.

I'm still perfectly happy with my current solution as I couldn't
follow any of your points.  I think I was careful not to break any
existing code.  It was certainly a mistake not to document the changes
in more detail.  I hope I could make myself clearer now.  Are you
still worried?

- Marius



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