Hello,
I stumbled upon a behaviour of Gtk# that seems to be quite problematic
to me:
When a Widget is removed from a container and no more obvious references
to it exist it is still not destroyed. No Destroy or DestroyEvent event
is emitted. Also if you encapsulate a widget in a new class its
destructor isn't called, even after a call to System.GC.Sollect(). This
is in contrast to the same code written in C. I have attached three
examples: test.c showing the (correctly working) C-code, test.cs showing
the (not correctly working) C#-code using a simple Gtk#-object and
test2.cs showing the (not working correctly as well) C#-code using an
encapsulated object - in this last case the destructor is only called
when the whole program exits as its output is
Quit
Exit
Destructor called!
What the program does is simply remove a button from the window when it's
clicked.
My question is if this behaviour is a bug in Gtk# (it would be a rather
serious one in my opinion) or if I made some mistake in my code. Since I am
somehow confused about this behaviour of Gtk# I would appreciate any comments
that could enlighen me here.
Thank you
#include <stdlib.h>
#include <gtk/gtk.h>
static gboolean
on_delete_event (GtkWidget *widget,
GdkEvent *event,
gpointer data)
{
return (FALSE);
}
static void
on_destroy_event (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
on_button_clicked (GtkWidget *widget,
gpointer data)
{
GtkWidget *parent;
parent = gtk_widget_get_parent (GTK_WIDGET (widget));
gtk_container_remove (GTK_CONTAINER (parent), GTK_WIDGET (widget));
}
static void
on_button_destroyed (GtkWidget *widget,
gpointer pointer)
{
g_print ("Button destroyed!\n");
}
int
main (int argc, char *argv[])
{
GtkWindow *wnd;
GtkButton *button;
gtk_init (&argc, &argv);
wnd = GTK_WINDOW (gtk_window_new (GTK_WINDOW_TOPLEVEL));
button = GTK_BUTTON (gtk_button_new_with_label ("Test"));
gtk_container_add (GTK_CONTAINER (wnd), GTK_WIDGET (button));
g_signal_connect (G_OBJECT (wnd), "delete_event", G_CALLBACK (on_delete_event), NULL);
g_signal_connect (G_OBJECT (wnd), "destroy", G_CALLBACK (on_destroy_event), NULL);
g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (on_button_clicked), NULL);
g_signal_connect (G_OBJECT (button), "destroy", G_CALLBACK (on_button_destroyed), NULL);
gtk_widget_show_all (GTK_WIDGET (wnd));
gtk_main ();
return (0);
}
using System;
using Gtk;
namespace Test
{
class Test
{
private static void OnDeleteEvent (object sender, DeleteEventArgs args)
{
args.RetVal = false;
Application.Quit ();
}
private static void OnDestroyEvent (object sender, DestroyEventArgs args)
{
Application.Quit ();
}
private static void OnButtonClicked (object sender, EventArgs args)
{
Widget parent = ((Widget)sender).Parent;
//This should remove the only reference to the button.
((Container)parent).Remove ((Widget)sender);
//This should collect the button and trigger the Destroyed event.
GC.Collect ();
}
private static void OnButtonDestroyed (object sender, EventArgs args)
{
Console.WriteLine ("Button destroyed!");
}
public static void Main ()
{
Application.Init ();
Window wnd = new Window ("Test");
Button button = Button.NewWithLabel ("Test");
wnd.DeleteEvent += OnDeleteEvent;
wnd.DestroyEvent += OnDestroyEvent;
button.Clicked += OnButtonClicked;
button.Destroyed += OnButtonDestroyed;
wnd.Add (button);
wnd.ShowAll ();
Application.Run ();
}
}
}
using System;
using Gtk;
namespace Test
{
class TestWidget : Button
{
public TestWidget () : base ("Test")
{
Clicked += OnClicked;
//I try both, Destroyed and DestroyEvent, just to be sure.
Destroyed += OnDestroyed;
DestroyEvent += OnDestroyed;
}
~TestWidget ()
{
Console.WriteLine ("Destructor called!");
}
private static void OnClicked (object sender, EventArgs args)
{
Widget parent = ((Widget)sender).Parent;
//This should remove the only reference to the button.
((Container)parent).Remove ((Widget)sender);
//This should collect the button and trigger, Destroyed event and the destructor.
GC.Collect ();
}
private static void OnDestroyed (object sender, EventArgs args)
{
Console.WriteLine ("Button destroyed!");
}
}
class Test
{
private static void OnDeleteEvent (object sender, DeleteEventArgs args)
{
args.RetVal = false;
Application.Quit ();
Console.WriteLine ("Quit");
}
private static void OnDestroyEvent (object sender, DestroyEventArgs args)
{
Application.Quit ();
}
public static void Main ()
{
Application.Init ();
Window wnd = new Window ("Test");
TestWidget button = new TestWidget ();
wnd.DeleteEvent += OnDeleteEvent;
wnd.DestroyEvent += OnDestroyEvent;
wnd.Add (button);
wnd.ShowAll ();
Application.Run ();
Console.WriteLine ("Exit");
}
}
}
_______________________________________________
Gtk-sharp-list maillist - [email protected]
http://lists.ximian.com/mailman/listinfo/gtk-sharp-list