? log ? examples/customlist.pl ? examples/customrenderer.pl ? xs/.GdkPixbuf.xs.swp ? xs/.GtkTreeModel.xs.swp ? xs/GtkTreeModel.xs-interface Index: ChangeLog =================================================================== RCS file: /cvsroot/gtk2-perl/gtk2-perl-xs/Gtk2/ChangeLog,v retrieving revision 1.265 diff -u -r1.265 ChangeLog --- ChangeLog 14 Dec 2003 22:17:03 -0000 1.265 +++ ChangeLog 15 Dec 2003 05:30:19 -0000 @@ -1,3 +1,25 @@ +2003/12/15 00:10 (-0500) muppetman + + * xs/GtkTreeModel.xs: add marshallers for interface functions, and the + add_interface method wanted by the new key to + Glib::Type::register_object, so that Perl code can implement the + TreeModel interface on new Perl-derived GObjects. + this implementation is a real hack, and leaks all of the SVs stored + in the GtkTreeIters. this needs to be fixed before the code can be + used for real. + + * xs/GtkCellEditable.xs: likewise for CellEditable, but without + caveats. + + A examples/customlist.pl: port of the custom treemodel example from + the Gtk Tree View tutorial. + + A examples/customrenderer.pl: add the CellEditable interface to a + TextView so we can use the textview as the editable widget for a + custom multi-line text renderer. + + * MANIFEST: updated + 2003/12/14 17:16 (-0500) muppetman * t/paned.t: wait for size-allocate instead of using timeouts... still Index: MANIFEST =================================================================== RCS file: /cvsroot/gtk2-perl/gtk2-perl-xs/Gtk2/MANIFEST,v retrieving revision 1.36 diff -u -r1.36 MANIFEST --- MANIFEST 12 Dec 2003 16:47:20 -0000 1.36 +++ MANIFEST 15 Dec 2003 05:30:19 -0000 @@ -19,6 +19,8 @@ examples/cellrenderer_popup.pl examples/cellrenderer_spinbutton.pl examples/colorselectiontest.pl +examples/customlist.pl +examples/customrenderer.pl examples/histogramplot.pl examples/inline-images.pl examples/insert-text-test.pl Index: xs/GtkCellEditable.xs =================================================================== RCS file: /cvsroot/gtk2-perl/gtk2-perl-xs/Gtk2/xs/GtkCellEditable.xs,v retrieving revision 1.4 diff -u -r1.4 GtkCellEditable.xs --- xs/GtkCellEditable.xs 22 Sep 2003 00:04:25 -0000 1.4 +++ xs/GtkCellEditable.xs 15 Dec 2003 05:30:19 -0000 @@ -25,7 +25,74 @@ this is an interface */ +#define PREP(cell) \ + dSP; \ + ENTER; \ + SAVETMPS; \ + PUSHMARK (SP); \ + PUSHs (sv_2mortal (newSVGObject (G_OBJECT (cell)))); + +#define CALL(name) \ + PUTBACK; \ + call_method (name, G_VOID|G_DISCARD); \ + SPAGAIN; + +#define FINISH \ + FREETMPS; \ + LEAVE; + +static void +gtk2perl_cell_editable_start_editing (GtkCellEditable *cell_editable, + GdkEvent *event) +{ + PREP (cell_editable); + XPUSHs (sv_2mortal (newSVGdkEvent (event))); + CALL ("START_EDITING"); + FINISH; +} + +static void +gtk2perl_cell_editable_editing_done (GtkCellEditable *cell_editable) +{ + PREP (cell_editable); + CALL ("EDITING_DONE"); + FINISH; +} + +static void +gtk2perl_cell_editable_remove_widget (GtkCellEditable *cell_editable) +{ + PREP (cell_editable); + CALL ("REMOVE_WIDGET"); + FINISH; +} + +static void +gtk2perl_cell_editable_init (GtkCellEditableIface * iface) +{ + iface->start_editing = gtk2perl_cell_editable_start_editing; + iface->editing_done = gtk2perl_cell_editable_editing_done; + iface->remove_widget = gtk2perl_cell_editable_remove_widget; +} + + MODULE = Gtk2::CellEditable PACKAGE = Gtk2::CellEditable PREFIX = gtk_cell_editable_ + + +void +add_interface (class, const char * target_class) + CODE: + { + static const GInterfaceInfo iface_info = { + (GInterfaceInitFunc) gtk2perl_cell_editable_init, + (GInterfaceFinalizeFunc) NULL, + (gpointer) NULL + }; + GType gtype = gperl_object_type_from_package (target_class); + g_type_add_interface_static (gtype, GTK_TYPE_CELL_EDITABLE, + &iface_info); + } + ## void gtk_cell_editable_start_editing (GtkCellEditable *cell_editable, GdkEvent *event) void Index: xs/GtkCellRenderer.xs =================================================================== RCS file: /cvsroot/gtk2-perl/gtk2-perl-xs/Gtk2/xs/GtkCellRenderer.xs,v retrieving revision 1.12 diff -u -r1.12 GtkCellRenderer.xs --- xs/GtkCellRenderer.xs 21 Nov 2003 06:31:49 -0000 1.12 +++ xs/GtkCellRenderer.xs 15 Dec 2003 05:30:19 -0000 @@ -436,8 +436,11 @@ croak ("%s(%s) is not a GtkCellRenderer", package, g_type_name (gtype)); /* peek should suffice, as the bindings should keep this class - * alive for us. */ - class = g_type_class_peek (gtype); + * alive for us. however, we may be getting in here before the + * right things have happened, e.g., if we're creating such a class. + * so do a full ref. leak the ref, since we won't let it go away + * while the interpreter is alive. yes, this is evil. */ + class = g_type_class_ref (gtype); if (! class) croak ("internal problem: can't peek at type class for %s(%d)", g_type_name (gtype), gtype); Index: xs/GtkTreeModel.xs =================================================================== RCS file: /cvsroot/gtk2-perl/gtk2-perl-xs/Gtk2/xs/GtkTreeModel.xs,v retrieving revision 1.27 diff -u -r1.27 GtkTreeModel.xs --- xs/GtkTreeModel.xs 14 Dec 2003 19:27:55 -0000 1.27 +++ xs/GtkTreeModel.xs 15 Dec 2003 05:30:19 -0000 @@ -10,6 +10,13 @@ /* this is just an interface */ +#undef DEBUG +#ifdef DEBUG +# define bark warn +#else +# define bark +#endif + static gboolean gtk2perl_tree_model_foreach_func (GtkTreeModel *model, @@ -27,6 +34,339 @@ return retval; } +/* + * GtkTreeModelIface + */ + +/* + * Signals - these have class closures, so we can override them "normally" + * (for gtk2-perl, that is) + * + * row_changed + * row_inserted + * row_has_child_toggled + * row_deleted + * rows_reordered + */ + +/* + * Virtual Table - things for which we must provide overrides + */ + +static SV * +find_func (GtkTreeModel * tree_model, + const char * method_name) +{ + HV * stash = gperl_object_stash_from_type (G_OBJECT_TYPE (tree_model)); + return (SV*) gv_fetchmethod (stash, method_name); +} + +#define PUSH_INSTANCE(var) \ + PUSHs (sv_2mortal (newSVGObject (G_OBJECT (var)))) + +#define PREP(model) \ + dSP; \ + ENTER; \ + SAVETMPS; \ + PUSHMARK (SP); \ + PUSHs (sv_2mortal (newSVGObject (G_OBJECT (model)))); + +#define CALL(name, flags) \ + PUTBACK; \ + bark ("calling %s\n", name); \ + call_method (name, flags); \ + SPAGAIN; + +#define FINISH \ + PUTBACK; \ + FREETMPS; \ + LEAVE; + +static GtkTreeModelFlags +gtk2perl_tree_model_get_flags (GtkTreeModel *tree_model) +{ + GtkTreeModelFlags ret; + PREP (tree_model); + CALL ("GET_FLAGS", G_SCALAR); + ret = SvGtkTreeModelFlags (POPs); + FINISH; + return ret; +} + +static gint +gtk2perl_tree_model_get_n_columns (GtkTreeModel *tree_model) +{ + int ret; + PREP (tree_model); + CALL ("GET_N_COLUMNS", G_SCALAR); + ret = POPi; + FINISH; + return ret; +} + +static GType +gtk2perl_tree_model_get_column_type (GtkTreeModel *tree_model, + gint index_) +{ + GType ret; + SV * svret; + PREP (tree_model); + XPUSHs (sv_2mortal (newSViv (index_))); + CALL ("GET_COLUMN_TYPE", G_SCALAR); + svret = POPs; + PUTBACK; + ret = gperl_type_from_package (SvPV_nolen (svret)); + if (!ret) + croak ("package %s is not registered with GPerl\n", + SvPV_nolen (svret)); + FREETMPS; + LEAVE; + return ret; +} + +static SV * +sv_from_iter (GtkTreeIter * iter) +{ + AV * av = newAV (); + if (!iter) + return &PL_sv_undef; + av_push (av, newSVuv (iter->stamp)); + av_push (av, newSVsv (iter->user_data ? iter->user_data : &PL_sv_undef)); + av_push (av, newSVsv (iter->user_data2 ? iter->user_data2 : &PL_sv_undef)); + av_push (av, newSVsv (iter->user_data3 ? iter->user_data3 : &PL_sv_undef)); + bark ("sv_from_iter : av %p %x %x %x %x\n", av, + iter->stamp, iter->user_data, iter->user_data2, iter->user_data3); + return newRV_noinc ((SV*)av); +} + +static gboolean +iter_from_sv (GtkTreeIter * iter, + SV * sv) +{ + bark ("iter_from_sv 0x%x, 0x%x\n", iter, sv); + if (sv && SvROK (sv) && SvTYPE (SvRV (sv)) == SVt_PVAV) { + SV ** svp; + AV * av = (AV*) SvRV (sv); + if ((svp = av_fetch (av, 0, FALSE))) + iter->stamp = SvUV (*svp); + + if ((svp = av_fetch (av, 1, FALSE)) && SvOK (*svp)) + iter->user_data = /*sv_2mortal*/ (newSVsv (*svp)); + else + iter->user_data = NULL; + + if ((svp = av_fetch (av, 2, FALSE)) && SvOK (*svp)) + iter->user_data2 = /*sv_2mortal*/ (newSVsv (*svp)); + else + iter->user_data2 = NULL; + + if ((svp = av_fetch (av, 3, FALSE)) && SvOK (*svp)) + iter->user_data3 = /*sv_2mortal*/ (newSVsv (*svp)); + else + iter->user_data3 = NULL; + return TRUE; + } else { + iter->stamp = 0; + iter->user_data = 0; + iter->user_data2 = 0; + iter->user_data3 = 0; + return FALSE; + } +} + +static gboolean +gtk2perl_tree_model_get_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreePath *path) +{ + gboolean ret; + PREP (tree_model); + XPUSHs (sv_2mortal (path ? newSVGtkTreePath (path) : &PL_sv_undef)); + CALL ("GET_ITER", G_SCALAR); + ret = iter_from_sv (iter, POPs); + FINISH; + return ret; +} + +static GtkTreePath * +gtk2perl_tree_model_get_path (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + GtkTreePath * ret; + PREP (tree_model); + XPUSHs (sv_2mortal (sv_from_iter (iter))); + CALL ("GET_PATH", G_SCALAR); + ret = SvGtkTreePath_ornull (POPs); + FINISH; + return FALSE; +} + +static void +gtk2perl_tree_model_get_value (GtkTreeModel *tree_model, + GtkTreeIter *iter, + gint column, + GValue *value) +{ + g_value_init (value, gtk2perl_tree_model_get_column_type (tree_model, column)); + { + PREP (tree_model); + XPUSHs (sv_2mortal (sv_from_iter (iter))); + XPUSHs (sv_2mortal (newSViv (column))); + CALL ("GET_VALUE", G_SCALAR); + gperl_value_from_sv (value, POPs); + FINISH; + } +} + +static gboolean +gtk2perl_tree_model_iter_next (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + gboolean ret; + PREP (tree_model); + XPUSHs (sv_2mortal (sv_from_iter (iter))); + CALL ("ITER_NEXT", G_SCALAR); + ret = iter_from_sv (iter, POPs); + FINISH; + return ret; +} + +static gboolean +gtk2perl_tree_model_iter_children (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent) +{ + gboolean ret; + PREP (tree_model); + XPUSHs (sv_2mortal (sv_from_iter (parent))); + CALL ("ITER_CHILDREN", G_SCALAR); + ret = iter_from_sv (iter, POPs); + FINISH; + return ret; +} + +static gboolean +gtk2perl_tree_model_iter_has_child (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + gboolean ret; + PREP (tree_model); + XPUSHs (sv_2mortal (sv_from_iter (iter))); + CALL ("ITER_HAS_CHILD", G_SCALAR); + ret = POPi; + FINISH; + return ret; +} + +static gint +gtk2perl_tree_model_iter_n_children (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + gint ret; + PREP (tree_model); + XPUSHs (sv_2mortal (sv_from_iter (iter))); + CALL ("ITER_N_CHILDREN", G_SCALAR); + ret = POPi; + FINISH; + return ret; +} + +static gboolean +gtk2perl_tree_model_iter_nth_child (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent, + gint n) +{ + gboolean ret; + PREP (tree_model); + XPUSHs (sv_2mortal (sv_from_iter (parent))); + XPUSHs (sv_2mortal (newSViv (n))); + CALL ("ITER_NTH_CHILD", G_SCALAR); + ret = iter_from_sv (iter, POPs); + FINISH; + return ret; +} + +static gboolean +gtk2perl_tree_model_iter_parent (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *child) +{ + gboolean ret; + PREP (tree_model); + XPUSHs (sv_2mortal (sv_from_iter (child))); + CALL ("ITER_PARENT", G_SCALAR); + ret = iter_from_sv (iter, POPs); + FINISH; + return ret; +} + +static void +gtk2perl_tree_model_ref_node (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + SV * func = find_func (tree_model, "REF_NODE"); + if (func) { + PREP (tree_model); + XPUSHs (sv_2mortal (sv_from_iter (iter))); + PUTBACK; + call_sv (func, G_VOID|G_DISCARD); + FINISH; + } +} + +static void +gtk2perl_tree_model_unref_node (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + SV * func = find_func (tree_model, "UNREF_NODE"); + if (func) { + PREP (tree_model); + XPUSHs (sv_2mortal (sv_from_iter (iter))); + PUTBACK; + call_sv (func, G_VOID|G_DISCARD); + FINISH; + } +} + + +static void +gtk2perl_tree_model_init (GtkTreeModelIface * iface) +{ + iface->get_flags = gtk2perl_tree_model_get_flags; + iface->get_n_columns = gtk2perl_tree_model_get_n_columns; + iface->get_column_type = gtk2perl_tree_model_get_column_type; + iface->get_iter = gtk2perl_tree_model_get_iter; + iface->get_path = gtk2perl_tree_model_get_path; + iface->get_value = gtk2perl_tree_model_get_value; + iface->iter_next = gtk2perl_tree_model_iter_next; + iface->iter_children = gtk2perl_tree_model_iter_children; + iface->iter_has_child = gtk2perl_tree_model_iter_has_child; + iface->iter_n_children = gtk2perl_tree_model_iter_n_children; + iface->iter_nth_child = gtk2perl_tree_model_iter_nth_child; + iface->iter_parent = gtk2perl_tree_model_iter_parent; + iface->ref_node = gtk2perl_tree_model_ref_node; + iface->unref_node = gtk2perl_tree_model_unref_node; + bark ("gtk2perl_tree_model_init : %p %d %s\n", + iface, G_TYPE_FROM_INTERFACE (iface), + g_type_name (G_TYPE_FROM_INTERFACE (iface))); +} + +MODULE = Gtk2::TreeModel PACKAGE = Gtk2::TreeModel + +void +add_interface (class, const char * target_class) + CODE: + { + static const GInterfaceInfo iface_info = { + (GInterfaceInitFunc) gtk2perl_tree_model_init, + (GInterfaceFinalizeFunc) NULL, + (gpointer) NULL + }; + GType gtype = gperl_object_type_from_package (target_class); + g_type_add_interface_static (gtype, GTK_TYPE_TREE_MODEL, &iface_info); + } + MODULE = Gtk2::TreeModel PACKAGE = Gtk2::TreePath PREFIX = gtk_tree_path_