After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 161012 - Feature Request: Gtk2::TreeIters should be able to store data
Feature Request: Gtk2::TreeIters should be able to store data
Status: RESOLVED WONTFIX
Product: gnome-perl
Classification: Bindings
Component: Gtk2
unspecified
Other All
: Low enhancement
: ---
Assigned To: gtk2-perl-bugs
gtk2-perl-bugs
Depends on:
Blocks:
 
 
Reported: 2004-12-11 06:56 UTC by Zach Bean
Modified: 2005-02-20 20:31 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Zach Bean 2004-12-11 06:56:12 UTC
It would be very nice if, instead of the binding treating a GtkTreeIter as a
reference to a 4-element array, it could somehow attach a reference to an
arbitrary Perl object.  This would make it easier for custom TreeModel
implementers whose data is not already stored in Perl (and perhaps even for
those whose data is already in Perl).

For example, if you want to write a TreeModel to display data out of a SQL
database, it can become difficult to uniquely refer to a particular row in the
DB, especially if your data is stored over multiple tables.

This feature would also have other potential benefits.  For instance, suppose I
want to display a tree stored in a single SQL table, with fields for ID, Next,
and Parent.  If you can store the next and parent values directly in the
TreeIter, you can sometimes save a DB lookup.  I believe this feature would also
lead to less need to duplicate data, but I currently have no example for that case.
Comment 1 Torsten Schoenfeld 2004-12-11 14:15:46 UTC
If you implement a custom tree model, you're free to put whatever you want into
the array reference that represents an iterator.  See "CREATING A CUSTOM TREE
MODEL" in `perldoc Gtk2::TreeModel` for more.  Does that solve your problem?
Comment 2 muppet 2004-12-11 15:08:33 UTC
I would've loved to have made the Gtk2::TreeIter just be a hash reference.  The basic reason that wasn't 
possible was the fact that GtkTreeIter (in C) is designed to be used on the stack, as an object with no 
lifetime management.  It was designed this way for speed, but these semantics mean that perl can get 
no notification when the caller is finished with the iter so that the hash could be destroyed and its 
memory reclaimed.

As a workaround, the bindings allow you to specify arbitrary scalars in the last two elements of the iter 
array, but they do not persist (or else they would leak), so you need to keep copies around for yourself 
if they need to live.

As always, i'm open to suggestions.
Comment 3 Zach Bean 2004-12-11 18:29:22 UTC
To answer your question, Torsten, putting something into the array reference
doesn't help me very much because I have to keep a copy of it around at least
until the iter is no longer valid.  Generally speaking, if I have that, then
there's not much point putting it into the iter, too.

Let's say I have a unique id number in the first usable element of the iter
array, and some other piece of data I'd like to put in the second.  In order to
do that, I'm going to need to create Perl variables to store that data for each
valid iter until it isn't valid anymore.  To keep them organized, I'd probably
use an array, with the unique ID as an index.  I could then put a reference to
the right element into the TreeIter.

But that doesn't help much, because the array must persist as long as the
TreeIter is valid, so why not just store only the index in the Iter, and get the
data back out of the array when you need it?

My problem is, I don't want to have to have that array in the first place.  In
some cases, when you're implementing a custom TreeModel, you want to be able to
display data that's already stored in a Perl data structure, so there's no
problem; you can just put references from there into the TreeIter.  It has to
persist anyway, because it's the actual data.  But other times (like the one's
I'm working with :o) you want to display data that's stored somewhere else, like
a SQL database.  If I have to take data out of the DB and put it into an array
to be able to refer to it from an Iter, then I'm duplicating my data, which I
don't want to do :o)

This doesn't really become an issue until you need more than just one integer to
uniquely identify a particular data point.  Sometimes it would be nice, or maybe
lead to performance enhancements, but as long as one integer is unique enough,
then the Model can still be made to work.

I think, though, that the C implementation of a GtkTreeIter (which I didn't know
about before) means what I want can't work unless Gtk itself is changed, since
there's no way to manage lifetime.

I don't suppose there's any way to sort of make a "custom" TreeIter?  Since it
isn't a GObject (or a GInterface), I guess probably not.  If I could do that in
either Perl or C, I'd be all set, I think.

This probably isn't the right place, but I'm going to mention what I'm thinking
about so I don't lose it :o)  As long as it's designed to behave like a real
GtkTreeIter, that is, as long as it has a stamp accessible through iter->stamp,
could I make my own "struct MyTreeIter" that has lifetime management and can
notify perl when it's going to go away, but still have it work correctly with
the GtkTreeView?
Comment 4 Zach Bean 2004-12-16 08:31:33 UTC
It looks like the answer to my last question (can I make a "custom" TreeIter) is
"yes".  I made a subclass of GObject in C, with members called stamp and
user_data, and I was successful in passing it into some GtkListStore functions
by casting it to a (GtkTreeIter *).

Does being a GObject provide enough lifetime management to allow "better"
handling  of TreeIters in Perl?  If not, what other functionality should I try
to add?

Comment 5 muppet 2004-12-16 13:12:30 UTC
While GObject is reference-counted and therefore can be better managed for lifetime, passing a 
GObject pointer where a GtkTreeIter pointer is wanted is pretty dangerous.  I would imagine that the 
only reason you got away with it is that since GtkTreeIter is just a plain struct, gtk+ can't do sanity 
checks on it and so doesn't (it contains no type id).  Even though you created a GObject with stamp and 
user_data fields, the compiler will not find them at the safe struct offset, so code compiled to work with 
a real GtkTreeIter will fail mysteriously with a GObject --- it will think that the GObject's type id is the 
stamp, for example.

Furthermore, while gtk+ does no type checks on GtkTreeIters, the bindings expect that they are plain 
structs to be treated as GBoxed types, and will do the exactly wrong thing to a GObject pointer.  Let's 
track a call to gtk_tree_model_get_value() through both C and perl to see what i mean:

C:  you've passed a GObject * to gtk_tree_model_get_value() for the iter.

gtk_tree_model_get_value() checks that iter != NULL.  This is true.
gtk_tree_model_get_value() calls get_value() vfunc from your model's iface.  This actually calls a 
function in your custom model, which expects a GObject, so things mostly work.  If you passed it to a 
built-in model, however, it would eventually cause a segfault when gtk+ tried to use the bogus data.

Perl:  you attempt to pass a Glib::Object reference to Gtk2::TreeModel::get()

Gtk2::TreeModel::get() calls SvGtkTreeIter() to fetch the pointer from the reference in ST(1).
SvGtkTreeIter() is a macro (defined in gperl-autogen.h) that evaluates to gperl_get_boxed_check((sv), 
GTK_TYPE_TREE_ITER)).  GTK_TYPE_TREE_ITER is a boxed type id, and gperl_get_boxed_check() will look 
up the registered boxed wrapper (the default, in this case), which assumes that the SV points to a 
wrapper struct containing the type id, a boolean saying whether the wrapper owns the struct, and a 
pointer to the struct; however, you've actually passed a magical GObject reference.  The wrapper class's 
unwrap vfunc, in this case default_boxed_unwrap() in in Glib/GBoxed.xs, calls sv_derived_from() to 
verify that the reference is blessed into the package associated with GTK_TYPE_TREE_ITER, "Gtk2::
TreeIter".  However, your type is derived from Glib::Object, so this check will fail with the message 
"MyFoo is not of type Gtk2::TreeIter".

That is, you can't even get through the bindings to pass the wrong thing.


So, i don't think using a GObject for the iter will help.
Comment 6 Torsten Schoenfeld 2005-02-20 20:31:40 UTC
Closing and marking as WONTFIX as there really seems to nothing we can do about
this.