Re: [gtk-list] Re: Tracking object deletion




Kenneth Albanowski <kjahds@kjahds.com> writes:

> On 11 Dec 1997, Owen Taylor wrote:
> 
> > But I still think that [keeping a refererence count, and making Gtk
> > functions fail silently] better [than the deletion callback]- when
              ^^^^^^^^^^^^^
In the special case where the user has stored a reference to a window
independently of a widget, and that window is destroyed by external
forces. Not in general.

> > combined with a way for users to check if GdkWindow/Pixmap is still
> > valid or not. It is the way you want to handle most objects - if the
> > user keeps around a reference in Perl to an object, it shouldn't be
> > destroyed, IMO. And thus its probably better to handle objects that are
> > destroyable by outside-forces in the same manner. 
> 
> My thought is something in between: reference counting is good, because it
> lets both Gtk and external language keep hold of an object (so that if I
> say:
> 
>   $b = new Gtk::Button "Add sheep";
> 
> then $b will still around no matter what I do to it, or where I add or
> remove it from, until $b itself is cleared) but when it conflicts with the
> window management, everything goes haywire.

Read Marius's proposal. (If desired, I could repost it.) Essentially,
the idea is that an object has an extra reference and a "floating" flag
until it is added to a parent for the first time. (Toplevels have
a virtual parent) After that, the widget heirarchy reference counts
in the normal manner.

Which means that:

  b = gtk_button_new_with_label ("Add sheep");
  b = NULL;

is a memory leak (no surprise). To keep 

  $b = new Gtk::Button "Add sheep";
  $b = undef

From being a memory leak, a language binding would internally in
the new() method doing something like.

  widget->gtk_widget = gtk_button_new();
  gtk_widget_ref (widget->gtk_widget);
  gtk_widget_sink (widget->gtk_widget); // Clear "floating" flag and
                                        // extra ref

 
> The other token is that a deletion callback turns out to be _critical_,
> for reasons I had completely missed. Consider creating a new Gtk widget in
> Perl, called GtkFoo, that is descended from GtkButton:

[...]

> (Before you ask, yes that is legal & functional code in the version I'm
> working on.) 

Cool. Though I hope people will still try to write the more basic
widgets in C so they can be used from all languages.

> Once I say:
> 
>   $x = new Gtk::Foo "GtkButton::label" => "Add goat";
> 
> I've got a Perl object, called a "shadow object", that allows Perl to
> invoke Gtk functions, and also can store arbitrary data that is
> effectively connected with the Gtk object (it's even available from C
> programs, if you really wanted it.). If I then say: 
> 
>   $x->{arbitraryData} = 3;
>   $window->add($x);
>   $x = unref;
>   $y = $window->children[0];
>   print $y->{arbitraryData};
> 
> then $y must contain the same Perl object refernce as $x did. (In the
> current release, $y is constructed anew, and {arbitraryData} will not be
> present). For this to work, we've got two options:
> 
>   1) the new Gtk object type must contain a reference to the Perl object,
>      so that when we reconstitute $y from the pointer that
>      gtk_container_children() gave us, we simply use the stored reference.
>      However, this means we've got a reference loop, as the Perl object
>      refers to the Gtk object, and vice versa. Now reference counting is
>      worthless again, unless we go back to manual destruction functions,
>      weak references, extremely dangerous coding, or don't let the Perl
>      object refer to the Gtk object (which means all Perl calls must
>      verify a valid reference count).
> 
>   2) create the Perl shadow object the first time the Gtk pointer is seen,
>      and install a hook to catch deletion of that object. The Perl object
>      holds a reference to the Gtk object, but not vice versa. If the Perl
>      object is deleted, the Gtk object stays around (unless its references
>      run out) and if Perl gets hold of it again, the same shadow object
>      will be used (via a hash that does not hold true references, just
>      pointers). The shadow object is only deleted when the
>      destruction callback is invoked and, by definition, the Perl
>      shadow object will already have been deleted.
> 
> #2 seems far safer and maintainable. Some sort of weak references are
> probably feasible, but mean much more coding all around.

A third possibility is to separate out the Perl shadow object from
the object the user deals with. i.e.

3) for any GTK widget, implemented in Perl or not, there is a Perl
   object that refers to the GTK widget, but is not referred to by
   the GTK widget. For widgets implemented in Perl, there is a shadow 
   object that is referred to by the GTK widget but does not refer
   to the Perl widget. (If desired a shadow object could also be kept
   for non-Perl widgets). The user object is destroyed when the last 
   Perl object is destroyed, and recreated if necessary. 

I suppose 2) really just combines the two objects into a single
object that serves both purposes. (Since user object => shadow
object, there is no real need for a separate user object) But
I don't quite see how you are going to figure out when an object
really should be destroyed. As long as the Perl object holds
a reference to the GTK object, it will never be destroyed, So you'd
have to unref() the GTK object when the Perl reference count
drops to 1. (You have to keep an extra reference count around,
or it will be destroyed.) The only way I can think of implementing
this uses an auxiliary object anyways...

> In any case, I still very much would like to see reference counting, but
> _not_ mixed up with the window management. A container should certainly
> keep references to its children, and letting objects destroy themselves if
> their container is destroyed makes good garbage collection sense. But the
> window manager "close window" function should _not_ trigger an unref(), as
> that means programs now have to actually catch unref() and then undo it,
> if they want to stick around for a while. 
> 
> Probably the simplest approach would be to have a "wm_close" signal that,
> by default, is set to widget_unref(). If a programmer wants to trap the
> close event on a window, they merely replaces the "wm_close" signal, and
> issue hide(), unref(), or something else entirely, as they desires.

Currently the "delete_event" handler by default does nothing. (The
window isn't deleted unless an installed handler returns TRUE) The
default should probably be reversed. The code that does the
destruction currently does a gtk_window_destroy, which will, recall,
in the future be treated as a confusing alias for
gtk_window_unparent(), which removes the widget from the object
tree, thus decrememting its refcount.

So if the application writer wants the window to stick around, he
installs a handler that returns TRUE. If he wants the object to
stick around, he keeps an extra reference to it.
  
> I think I can sum my thoughts up this way: 
>
>  1) make an "object deletion" hook, something a bit lower down then a
>     signal, that serves only to tell programs that an object is being
>     destroyed. This hook _must_ be called after every other conceivable
>     signal/hook that might want to do something constructive [sic] with
>     the object. 
> 
>  2) every single set of ref/unref calls should be rewritten to meet the
>     usual definition: no externally accessible destroy() call, and when
>     unref() removes the last reference, the object is automatically
>     destroy()'d. This is probably going to be an absolute pain for some of
>     the GdkColor stuff, BTW. 
> 
>  3) any operations that the programmer might want to catch (WM_CLOSE,
>     etc.) should not call unref() directly, but should call a signal that
>     in turn calls unref() by default.

1) I'm not completely sure this is necessary. I think it should be
sufficient to:
  a) reference count
  b) Proved deletetion hooks for all forms of arbitrary data 

(This excludes one thing - allowing language objects to last longer
 than GTK objects - but I think as long as long as GTK objects can
 be kept around without keeping X windows around this is OK. In any
 case, for GtkObjects, I think the "destroy" hook will be what you
 are looking for. In Marius's proposal, a handler for "destroy" by
 definition can't do anything constructive with the object.)

2) This is what Marius's proposal and patch do.

3) See above

> > Normally CORBA doesn't keep a reference count so local surrogates may
> > become invalid. (But CORBA does have EH - which is a slight help) ILU
> > allows keeping of reference counts as an extension, which is handy for
> > many things (DCOM is similar, I think). But for networked objects, you
> > need a keep-alive callback for the clients holding reference counts,
> > since otherwise if the remote client dies silently, objects will never
> > be destroyed.
> 
> I think this could work either way. A reference count can _always_ be
> implemented (unless CORBA truly assumes that programs delete random
> objects for no apparent reason at random times. And the keep-alive that
> destroys the objects when the link is dead can easily trigger a
> destruction event while it is at it.

Well, remote objects may well be destroyed for no apparent reason. (Power
failure, etc) A keep-alive is a way of doing sanity checks on
the reference count. If a surrogate doesn't respond to a callback,
then it just like the reference count had been decremented. CORBA
leaves such things to the interface writer, however.

> > Wow, I really strayed off track. I guess the short answer is - for
> > now, use "destroy" and warn users off referring to the object in an
> > installed "destroy" handler. In the future, you probably shouldn't
> > have such a thing.
> 
> I really hope we have something just as useful then.

I wasn't saying that the "destroy" signal would be removed. I was
just saying that in the simplest possible way of implementing Perl
objects, it wouldn't be needed. For more complicated methods of
doing things, it might be.

> For example, I just realized that gtk_object_set_data() could work in
> exactly the manner I need, _if_ there was a callback that could be invoked
> when the data was cleared, due to object destruction. The most basic point
> is I need _some_ way to tell all Gtk objects, even ones not descended from
> a Perl class, that they need to tell Perl about their disappearence.

This is probably a good idea, in any case. Generally, I think that
any possible way of storing arbitrary data into a GTK structure should
have an associated destruction callback.

Regards,
                                        Owen



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