Re: GtkType stuff



Owen Taylor <otaylor@redhat.com> writes:

> My actual opinion is that if we want to go this route, we should go it
> all the way.

Exactly.

> The argument direction should act as in the CORBA C or C++ mapping -
> in that GTK_TYPE_INT | GTK_ARG_OUT gets mapped as int *, while
> "normal" GTK_TYPE_INT maps as before.

That would make GTK_ARG_OUT be part of the fundamental type.  We can
certainly do that, but I think it would be a more serious change than
conceptually decoupling the modes/flow-hints/qualifiers from the type.

What is GTK_FUNDAMENTAL_TYPE(GTK_TYPE_INT|GTK_ARG_OUT)?  It can't be
GTK_TYPE_INT because an "int*" has certainly to be treated differently
than an "int".  It can't be GTK_TYPE_POINTER because GTK_TYPE_POINTER
doesn't mean anything useful without also knowing alot about the
context.  What is it?

I'm in favour of not making the fundamental type be influenced by the
additional qualifiers.  We can maybe define things so that there is
only one allowed qualification of the existing fundamental types and
this qualification reflects the currently established semantics.

[ I'm trying out new terms again.  I'm now calling the things
  "qualifiers".  We have a "uninited" qualifier that says that a
  passed value has not been set to a meaningful value before calling
  the function.  And we have "mutable" which says that the function is
  allowed to mutate the value. ]

The scalar types which are now being passed by copying cannot have any
qualifiers because it doesn't make sense.  This is for GTK_TYPE_CHAR,
BOOL, INT, UINT, LONG, ULONG, FLOAT, DOUBLE, ENUM, FLAGS, CALLBACK.

GTK_TYPE_STRING can't have qualifiers either but this time because
this coincides with the defined semantics of this fundamental type.

GTK_TYPE_OBJECT is always "mutable".

GTK_TYPE_BOXED is more difficult.  I think we can start with "mutable"
and then go on to find uses of GTK_TYPE_BOXED that can be made more
precise by adding "uninited" or taking away "mutable".

Is GTK_TYPE_ARGS used anywhere?

> Types that are already pointers do not get the extra reference.

That contradicts the stuff you say below, I think.
 
> Anybody looking at this should definitely look the CORBA
> mapping.

I'll do that.

> The CORBA mapping is rather complex, so we wouldn't want to copy it,
> but some concepts probably carry over.
> 
> The way I would do it is that the following get an extra
> reference when passed out or inout:
> 
>  - Objects that are passed by value in C - ints, floats, etc.
>  - Objects that are inherently passed by reference, such as
>    GtkObject, or GdkWindow. That is, an out GtkObject is
>    passed as an GtkObject **.

Here's the contradiction, right?
 
> While things that are passed by reference in C, but are not
> conceptually always pass-by-reference, such as pointers to
> fixed-length structs, do not get the extra reference.

We have (or will have) for each fundamental type a precise definition
whether it will be passed by reference or not.  For example,
GTK_TYPE_INT is not passed by reference, while GTK_TYPE_STRING is.

Instead of stating that adding the "mutable" qualifier to a
GTK_TYPE_INT makes it be passed by reference, I would rather state
that you simply can't use the "mutable" qualifier with GTK_TYPE_INT.
No existing code expects a GTK_TYPE_INT to have a "mutable" qualifier.
We *could* make a new fundamental type GTK_TYPE_REFINT, but we can
just make GTK_TYPE_REFINT be a synonym for a fixed length array of
GTK_TYPE_INTs with length one and the "mutable" qualifier.

Not being able to have a mutable GTK_TYPE_INT is not a serious
restriction because we can use mutable arrays of GTK_TYPE_INTS
instead.  That's what C does, and it actually makes a lot of sense to
me.  We need a more useful notion of what an array is than C has, tho.
I'd like to have counted arrays where an extra (unmutable) int carries
the length of the array, zero-terminated arrays, where the end is
marked with a "0" entry, and fixed-length arrays, where the length is
part of the type.

> In fact, there is nothing currently defined in gtk.defs that
> fits into the latter category, but there is a need for such.
> The prime candidate are things like the GtkRequisition argument
> to size_request.

I intended to use GTK_TYPE_BOXED for this purpose.  This dictates
however that such a structure has associated copy/free functions that
can be used to control the lifetime of the value.

For example, a GdkEvent can be used as GTK_TYPE_GDK_EVENT.  This was
the main reason why I introduced the gdk_event_copy/gdk_event_free
functions.  They are needed, for example, when guile-gtk picks out a
GdkEvent pointer from a GtkArg struct that it gets during a signal
handler callback.  The lifetime of that GdkEvent must be extended
until Guile has no longer a need for it.  That can be long after the
handler has finished.  So guile-gtk has to copy it.  The same thing is
done for GdkColor.

You can also use a ref counting scheme to extend the lifetime.  This
is done for GdkColormap, GdkFont, GdkWindow, GtkStyle, GdkGC, etc.

Of course, copying and refcounting lead to very different semantics.
The qualifiers can help here, too.  All GTK_TYPE_BOXED types that have
copy semantics (like GTK_TYPE_GDK_EVENT, GTK_TYPE_GDK_COLOR) should be
un-"mutable".

> Much more tricky is what to do if we provide some way of passing
> GLists (or GPtrArrays) as signal or function parameters. This is the
> area where the CORBA mapping gets ugly. Probably we should just
> forget the possibility of 'out/inout' GLists. 

When viewing a list simply as a struct that is passed by reference,
everything falls into place, I think.  The type "list containing
GtkObjects" would mean "structure that consists of a pointer to a
GtkObject, and a pointer to another struct of the same type; such a
structure is passed by reference".  The qualifiers would be applied to
this structure.  "mutable" means that the called function is allowed
to change the pointer to the GtkObject, and is allowed to change the
pointer to the next structure.  The mutable carries over to all the
other list node structures, because the qualifiers are really part of
the type (but not the fundamental type).  Whether the pointed to
GtkObject might be mutated depends on which type has been specified
for the contents of the list nodes.

Note that the function can rearrange the nodes *after* the first one,
but it can not put a new node at the front of the list.

> > > > in general, "out" arguments are always a little questionable
> > > > for signal handlers, because there is 1) no mechanism to check
> > > > the returned values for validity upon every handler
> > > > invokation, and 2) it is not always clearly defined when such
> > > > modifications will take effect, i.e. does changing a value
> > > > that is passed by reference take effect if modified in an
> > > > _after handler?.
> > > 
> > > Yes, agreed.

I agreed that "out" or "mutable" arguments for signal handlers are a
little questionable.  But I also agree that, as you say, we can find
straightforward ways to solve the `problems'.

> The direction of the argument is not fixed for a single fundemental
> type, or even a single type. Now if you want to say that the type
> argument to gtk_signal_new is the bitwise or of a type and some
> flags, that might make sense.

I think we should make the qualifiers be part of the type.  See the
discussion of the recursive list types above.  Or we might want to
conceptually separate them, but I think we will mostly have to deal
with a type plus qualifiers.  So it is convenient to store them
together.  GtkType has enough room for the qualifiers.

> How about simply:
> 
>  GTK_TYPE_INT | GTK_DIRECTION_INOUT

Yes, that is much better.

[ Declarations in header files ]

> I don't want to go the route of having GTK+ written in some
> hybrid of scheme and C.

Why not?  The comment enclosed hints aren't exactly C, either.  In
fact, gtk.defs isn't Scheme, it just happens to use a Lisp inspired
syntax that is well defined, unambigous, flexible and dead easy to
parse from Scheme (and ELisp).  The grammar could use some
improvements, tho.

> If a widget writer doesn't get the comment enclosed hints right,
> then C will still work right, it will just happen that language
> bindings may not.

When a widget writer leaves out the detailed definitions, then C will
still work, it will just happen that language bindings are incomplete.
I prefer incompleteness over bugginess.

> But then it is an opportunity for somebody to submit patches.

Yeah, bugs are our friends because we can submit patches and get
famous... ;-)
 
> I think that most C programmers will feel more comfortable with:
> 
> GdkWindow*    gdk_window_get_pointer	 (GdkWindow	  *window,
> 					  gint		  *x,   /*< out >*/
> 					  gint		  *y,   /*< out >*/
> 					  GdkModifierType *mask /*< out >*/);
>  
> Then with:
> 
> (define-func gdk_window_get_pointer
>   GdkWindow window
>   ((GdkWindow window)
>    (out int x)
>    (out int y)
>    (out GdkModifierType mask)))
> 
> In fact, I'm sure of it.

I agree.

I just want to have it so that when there are *no* hints in the header
files, then *no* detailed definitions for gtk.defs should be
generated.  There should be at least a hint that says: "I hereby
declare that this function is safe to be included in gtk.defs and the
magical rules of the extraction script will get all details right."

There are a lot of functions that shouldn't be included in gtk.defs, I
think.  Like gtk_object_ref.  Refcounting is part of the fundamental
semantics of the Gtk object system.  It's inherent in the rules for
dealing with GTK_TYPE_OBJECT values.  gtk_object_ref is not a general
widget functionality accessor like gtk_label_set.  Just grabbing out
any function that doens't look too weird doesn't really work, I'd say.



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