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
  • [Gtk-sharp-l... Thorsten Schoel
    • Re: [Gt... Victor Rafael Rivarola Soerensen (FANATICO y LOCO por Cristo)
      • Re:... Michael Hutchinson
        • ... Victor Rafael Rivarola Soerensen (FANATICO y LOCO por Cristo)

Reply via email to