[patch] widget_hide, widget_destroy and ref_count




hi folks [especially peter],

as i mentioned before, i'm having problems with deletions of widgets in GUBI.
you should know that GUBI is very sensible about the execution of a widgets
"destroy" handler, i.e. if gtk_widget_destroy(test_widget) will not invoke
the destroy handlers of a widget (e.g. due to a widgets ref_count being != 0),
GUBI will certainly notice this one line after, or may be a little bit later
and complain (and i experienced that every time i got this complain, something
else will fail later on in the toolkit...).

now if GUBI destroyes a widget, it will gtk_widget_hide it before. this leads
to the following situation:

let's say we create a window with an arrow in it and destroy the arrow...

[...]
> arrow = gtk_arrow_new();
> gtk_container_add (window, arrow);
> gtk_widget_show (arrow);
[...]

now arrow->ref_count == 1 because of gtk_widget_set_parent() (after being
incremented and decremented for each of gtk_widget_queue_draw() and
gtk_widget_queue_resize()).

if now the widget is hidden, the hiding will queue it again for resizing.
[peter: why is there a gtk_widget_queue_resize() in gtk_real_widget_hide()?]

now the widget should be destroyed, which won't happen because of the
resize ref_count...
i therefore added a call to a new function
gtk_idle_remove_by_data(widget) and did a gtk_object_unref() for
GTK_WIDGET_REDRAW_PENDING() and/or GTK_WIDGET_RESIZE_NEEDED() in
gtk_widget_destroy() and gtk_widget_unparent().

now hide, unparent and destroy will work.

basicaly i'm having a few questions now:
-	is it ok to assume gtk_widget_destroy() will call the destroy handler
	in the normal case?
-	is it ok to assume i'm allowed to do a gtk_widget_hide() before a call
	to gtk_widget_destroy()?
	from Radek Doulik's patch mail (regarding "desktop property patch") to
	the gnome mailing list, i figured the hiding must have been a problem
	there as well.

i realy think the answer to both questions should be yes, otherwise i would
be in the needs to come up with some very strange programming approaches...

folks:	regarding the aplied patch you should notice, i will not upload it to
	ftp.gimp.org and if you don't know too much about the resizing/queueing
	stuff you probably do not want to aply it, as this is not my final word
	on this issue (i'm still getting "resize pending") and i guess it won't
	be peter's either...

peter:	please take a close look at this patch even if you don't aply it,
	the `if (widget)' and `if (resize_container)' conditions in
	gtkwindow.c are needed because these might be NULL (look at the
	`while (widget && ...)' condition).
	also the `g_return_if_fail (widget != NULL);' in gtk_widget_destroy()
	should stay, and i think having a gtk_idle_remove_by_data() is not a
	bad idea...


---
ciaoTJ




diff -ru gtk+970916/gtk/gtkmain.c /usr/src/gtk+/gtk/gtkmain.c
--- gtk+970916/gtk/gtkmain.c	Mon Sep 15 08:23:35 1997
+++ /usr/src/gtk+/gtk/gtkmain.c	Thu Sep 18 01:34:24 1997
@@ -104,6 +104,7 @@
 static GList *pending_idles = NULL;
 static GList *remove_timeouts = NULL;
 static GList *remove_idles = NULL;
+static GList *remove_idles_by_data = NULL;
 static gint handling_timeouts = FALSE;
 static gint handling_idle = FALSE;
 static GMemChunk *timeout_mem_chunk = NULL;
@@ -575,6 +576,61 @@
 }
 
 void
+gtk_idle_remove_by_data (gpointer data)
+{
+  GtkIdleFunction *idlef;
+  GList *tmp_list;
+
+  if (!handling_idle)
+    {
+      tmp_list = idle_functions;
+      while (tmp_list)
+	{
+	  idlef = tmp_list->data;
+
+	  if (idlef->data == data)
+	    {
+	      idle_functions = g_list_remove_link (idle_functions, tmp_list);
+	      g_list_free (tmp_list);
+	      g_mem_chunk_free (idle_mem_chunk, idlef);
+
+	      gtk_handle_timer ();
+	      return;
+	    }
+
+	  tmp_list = tmp_list->next;
+	}
+
+      tmp_list = pending_idles;
+      while (tmp_list)
+	{
+	  idlef = tmp_list->data;
+
+	  if (idlef->data == data)
+	    {
+	      idle_functions = g_list_remove_link (idle_functions, tmp_list);
+	      g_list_free (tmp_list);
+	      g_mem_chunk_free (idle_mem_chunk, idlef);
+
+	      gtk_handle_timer ();
+	      return;
+	    }
+
+	  tmp_list = tmp_list->next;
+	}
+    }
+  else
+    {
+      gpointer *d;
+
+      d = g_new (gpointer, 1);
+      *d = data;
+
+      remove_idles_by_data = g_list_prepend (remove_idles_by_data, d);
+    }
+}
+
+void
 gtk_get_current_event (GdkEvent *event)
 {
   g_assert (event != NULL);
@@ -816,6 +872,20 @@
 
 	  g_list_free (remove_idles);
 	  remove_idles = NULL;
+	}
+      
+      if (remove_idles_by_data)
+	{
+	  tmp_list = remove_idles_by_data;
+	  while (tmp_list)
+	    {
+	      gtk_idle_remove_by_data (*((gpointer*) tmp_list->data));
+	      g_free (tmp_list->data);
+	      tmp_list = tmp_list->next;
+	    }
+
+	  g_list_free (remove_idles_by_data);
+	  remove_idles_by_data = NULL;
 	}
     }
 }
diff -ru gtk+970916/gtk/gtkmain.h /usr/src/gtk+/gtk/gtkmain.h
--- gtk+970916/gtk/gtkmain.h	Tue Sep  2 04:30:56 1997
+++ /usr/src/gtk+/gtk/gtkmain.h	Thu Sep 18 01:26:26 1997
@@ -53,6 +53,8 @@
 				  gpointer       data);
 void       gtk_idle_remove       (gint           tag);
 
+void       gtk_idle_remove_by_data (gpointer     data);
+
 void       gtk_get_current_event (GdkEvent      *event);
 GtkWidget* gtk_get_event_widget  (GdkEvent      *event);
 
diff -ru gtk+970916/gtk/gtkwidget.c /usr/src/gtk+/gtk/gtkwidget.c
--- gtk+970916/gtk/gtkwidget.c	Tue Sep 16 00:12:58 1997
+++ /usr/src/gtk+/gtk/gtkwidget.c	Thu Sep 18 04:19:15 1997
@@ -803,6 +803,33 @@
 void
 gtk_widget_destroy (GtkWidget *widget)
 {
+  g_return_if_fail (widget != NULL);
+  
+  if (GTK_WIDGET_REDRAW_PENDING (widget))
+    {
+      GTK_WIDGET_UNSET_FLAGS (widget, GTK_REDRAW_PENDING);
+      gtk_object_unref (GTK_OBJECT (widget));
+      gtk_idle_remove_by_data (widget);
+    }
+  if (GTK_WIDGET_RESIZE_NEEDED (widget))
+    {
+      GtkWidget *toplevel;
+      GSList *resize_widgets;
+  
+      GTK_WIDGET_UNSET_FLAGS (widget, GTK_RESIZE_NEEDED);
+      gtk_object_unref (GTK_OBJECT (widget));
+      
+      toplevel = gtk_widget_get_toplevel (widget);
+      resize_widgets = gtk_object_get_data (GTK_OBJECT (toplevel), resize_widgets_key);
+      
+      if (resize_widgets)
+        {
+          resize_widgets = g_slist_remove (resize_widgets, widget);
+          
+          gtk_object_set_data (GTK_OBJECT (toplevel), resize_widgets_key, resize_widgets);
+        }
+    }
+  
   if (widget->parent)
     {
       if (!GTK_OBJECT_BEING_DESTROYED (widget->parent))
@@ -843,6 +870,25 @@
 	gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
     }
 
+  if (GTK_WIDGET_RESIZE_NEEDED (widget))
+    {
+      GtkWidget *toplevel;
+      GSList *resize_widgets;
+  
+      GTK_WIDGET_UNSET_FLAGS (widget, GTK_RESIZE_NEEDED);
+      gtk_object_unref (GTK_OBJECT (widget));
+      
+      toplevel = gtk_widget_get_toplevel (widget);
+      resize_widgets = gtk_object_get_data (GTK_OBJECT (toplevel), resize_widgets_key);
+      
+      if (resize_widgets)
+        {
+          resize_widgets = g_slist_remove (resize_widgets, widget);
+          
+          gtk_object_set_data (GTK_OBJECT (toplevel), resize_widgets_key, resize_widgets);
+        }
+    }
+  
   if (widget->window &&
       GTK_WIDGET_NO_WINDOW (widget) &&
       GTK_WIDGET_DRAWABLE (widget))
diff -ru gtk+970916/gtk/gtkwindow.c /usr/src/gtk+/gtk/gtkwindow.c
--- gtk+970916/gtk/gtkwindow.c	Mon Sep 15 07:29:30 1997
+++ /usr/src/gtk+/gtk/gtkwindow.c	Thu Sep 18 03:24:51 1997
@@ -917,7 +917,8 @@
                  (widget->allocation.height < widget->requisition.height)))
            widget = widget->parent;
 
-         GTK_WIDGET_SET_FLAGS (widget, GTK_RESIZE_PENDING);
+         if (widget)
+           GTK_WIDGET_SET_FLAGS (widget, GTK_RESIZE_PENDING);
        }
 
       resize_containers = NULL;
@@ -933,19 +934,23 @@
                 !GTK_WIDGET_RESIZE_PENDING (resize_container))
            resize_container = resize_container->parent;
 
-         widget = resize_container->parent;
-         while (widget)
+         if (resize_container)
            {
-             if (GTK_WIDGET_RESIZE_PENDING (widget))
+             widget = resize_container->parent;
+
+             while (widget)
                {
-                 GTK_WIDGET_UNSET_FLAGS (resize_container, GTK_RESIZE_PENDING);
-                 resize_container = widget;
+                 if (GTK_WIDGET_RESIZE_PENDING (widget))
+                   {
+                     GTK_WIDGET_UNSET_FLAGS (resize_container, GTK_RESIZE_PENDING);
+                     resize_container = widget;
+                   }
+                 widget = widget->parent;
                }
-             widget = widget->parent;
+             
+             if (g_slist_find (resize_containers, resize_container) == NULL)
+               resize_containers = g_slist_prepend (resize_containers, resize_container);
            }
-
-         if (g_slist_find (resize_containers, resize_container) == NULL)
-           resize_containers = g_slist_prepend (resize_containers, resize_container);
        }
 
       g_slist_free (resize_widgets);




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