[gtk+/popovers: 42/42] window: Use GList to store popover structs



commit fbc73150d7e99ce064e1911437852f30ecc903b3
Author: Carlos Garnacho <carlosg gnome org>
Date:   Wed Jan 15 13:28:32 2014 +0100

    window: Use GList to store popover structs
    
    When all popovers are removed on destroy(), if a popover is nested into
    (eg. with relative_to within) another popover, the removal of one can
    lead to the other being removed while the hashtable is being iterated,
    which would lead to undefined behavior in further iterations.
    
    Then, use a GList to store popovers, iterating can be made more resilient
    on these situations, and unless on pathological cases there's not going
    to be as many of those popovers as to cause performance decreases at the
    times those are iterated.

 gtk/gtkwindow.c |  119 +++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 94 insertions(+), 25 deletions(-)
---
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 2cd3eff..389735b 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -147,7 +147,7 @@ struct _GtkWindowPrivate
   GdkScreen             *screen;
   GtkApplication        *application;
 
-  GHashTable            *popovers;
+  GList                 *popovers;
 
   GdkModifierType        mnemonic_modifier;
   GdkWindowTypeHint      gdk_type_hint;
@@ -1398,8 +1398,6 @@ gtk_window_init (GtkWindow *window)
   priv->has_resize_grip = TRUE;
   priv->mnemonics_visible = TRUE;
   priv->focus_visible = TRUE;
-  priv->popovers = g_hash_table_new_full (NULL, NULL, NULL,
-                                          (GDestroyNotify) popover_destroy);
 
   g_object_ref_sink (window);
   priv->has_user_ref_count = TRUE;
@@ -2664,7 +2662,14 @@ gtk_window_dispose (GObject *object)
   GtkWindow *window = GTK_WINDOW (object);
   GtkWindowPrivate *priv = window->priv;
 
-  g_hash_table_remove_all (priv->popovers);
+  while (priv->popovers)
+    {
+      GtkWindowPopover *popover;
+
+      popover = priv->popovers->data;
+      priv->popovers = g_list_remove_link (priv->popovers, priv->popovers);
+      popover_destroy (popover);
+    }
 
   gtk_window_set_focus (window, NULL);
   gtk_window_set_default (window, NULL);
@@ -5194,8 +5199,6 @@ gtk_window_finalize (GObject *object)
       priv->mnemonics_display_timeout_id = 0;
     }
 
-  g_hash_table_destroy (priv->popovers);
-
   G_OBJECT_CLASS (gtk_window_parent_class)->finalize (object);
 }
 
@@ -5470,6 +5473,7 @@ gtk_window_map (GtkWidget *widget)
   GtkWindow *window = GTK_WINDOW (widget);
   GtkWindowPrivate *priv = window->priv;
   GdkWindow *gdk_window;
+  GList *link;
 
   if (!gtk_widget_is_toplevel (widget))
     {
@@ -5577,7 +5581,14 @@ gtk_window_map (GtkWidget *widget)
   if (priv->application)
     gtk_application_handle_window_map (priv->application, window);
 
-  g_hash_table_foreach (priv->popovers, (GHFunc) popover_map, window);
+  link = priv->popovers;
+
+  while (link)
+    {
+      GtkWindowPopover *popover = link->data;
+      link = link->next;
+      popover_map (popover->widget, popover);
+    }
 }
 
 static gboolean
@@ -5607,6 +5618,7 @@ gtk_window_unmap (GtkWidget *widget)
   GtkWindowGeometryInfo *info;
   GdkWindow *gdk_window;
   GdkWindowState state;
+  GList *link;
 
   if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
     {
@@ -5614,7 +5626,15 @@ gtk_window_unmap (GtkWidget *widget)
       return;
     }
 
-  g_hash_table_foreach (priv->popovers, (GHFunc) popover_unmap, window);
+  link = priv->popovers;
+
+  while (link)
+    {
+      GtkWindowPopover *popover = link->data;
+      link = link->next;
+      popover_unmap (popover->widget, popover);
+    }
+
   gdk_window = gtk_widget_get_window (widget);
 
   gtk_widget_set_mapped (widget, FALSE);
@@ -5868,6 +5888,7 @@ gtk_window_realize (GtkWidget *widget)
   GtkWindowPrivate *priv;
   gint i;
   int old_scale;
+  GList *link;
 
   window = GTK_WINDOW (widget);
   priv = window->priv;
@@ -6106,7 +6127,14 @@ gtk_window_realize (GtkWidget *widget)
   if (priv->has_resize_grip)
     resize_grip_create_window (window);
 
-  g_hash_table_foreach (priv->popovers, (GHFunc) popover_realize, window);
+  link = priv->popovers;
+
+  while (link)
+    {
+      GtkWindowPopover *popover = link->data;
+      link = link->next;
+      popover_realize (popover->widget, popover, window);
+    }
 
   old_scale = priv->scale;
   priv->scale = gtk_widget_get_scale_factor (widget);
@@ -6129,6 +6157,7 @@ gtk_window_unrealize (GtkWidget *widget)
   GtkWindow *window = GTK_WINDOW (widget);
   GtkWindowPrivate *priv = window->priv;
   GtkWindowGeometryInfo *info;
+  GList *link;
   gint i;
 
   /* On unrealize, we reset the size of the window such
@@ -6173,7 +6202,14 @@ gtk_window_unrealize (GtkWidget *widget)
         }
     }
 
-  g_hash_table_foreach (priv->popovers, (GHFunc) popover_unrealize, window);
+  link = priv->popovers;
+
+  while (link)
+    {
+      GtkWindowPopover *popover = link->data;
+      link = link->next;
+      popover_unrealize (popover->widget, popover);
+    }
 
   GTK_WIDGET_CLASS (gtk_window_parent_class)->unrealize (widget);
 }
@@ -6921,8 +6957,10 @@ gtk_window_size_allocate (GtkWidget     *widget,
                           GtkAllocation *allocation)
 {
   GtkWindow *window = GTK_WINDOW (widget);
+  GtkWindowPrivate *priv = window->priv;
   GtkWidget *child;
   GtkAllocation child_allocation;
+  GList *link;
 
   _gtk_window_set_allocation (window, allocation, &child_allocation);
 
@@ -6930,8 +6968,14 @@ gtk_window_size_allocate (GtkWidget     *widget,
   if (child && gtk_widget_get_visible (child))
     gtk_widget_size_allocate (child, &child_allocation);
 
-  g_hash_table_foreach (window->priv->popovers,
-                        (GHFunc) popover_size_allocate, widget);
+  link = priv->popovers;
+
+  while (link)
+    {
+      GtkWindowPopover *popover = link->data;
+      link = link->next;
+      popover_size_allocate (popover->widget, popover, window);
+    }
 }
 
 static gint
@@ -7853,6 +7897,24 @@ gtk_window_focus_out_event (GtkWidget     *widget,
   return FALSE;
 }
 
+static GtkWindowPopover *
+_gtk_window_has_popover (GtkWindow *window,
+                         GtkWidget *widget)
+{
+  GtkWindowPrivate *priv = window->priv;
+  GList *link;
+
+  for (link = priv->popovers; link; link = link->next)
+    {
+      GtkWindowPopover *popover = link->data;
+
+      if (popover->widget == widget)
+        return popover;
+    }
+
+  return NULL;
+}
+
 static void
 gtk_window_remove (GtkContainer *container,
                   GtkWidget     *widget)
@@ -7861,7 +7923,7 @@ gtk_window_remove (GtkContainer *container,
 
   if (widget == window->priv->title_box)
     unset_titlebar (window);
-  else if (g_hash_table_contains (window->priv->popovers, widget))
+  else if (_gtk_window_has_popover (window, widget))
     gtk_window_remove_popover (window, widget);
   else
     GTK_CONTAINER_CLASS (gtk_window_parent_class)->remove (container, widget);
@@ -9642,8 +9704,8 @@ gtk_window_draw (GtkWidget *widget,
   gboolean ret = FALSE;
   GtkAllocation allocation;
   GtkBorder window_border;
-  GHashTableIter iter;
   gint title_height;
+  GList *link;
 
   context = gtk_widget_get_style_context (widget);
 
@@ -9727,10 +9789,13 @@ gtk_window_draw (GtkWidget *widget,
       gtk_style_context_restore (context);
     }
 
-  g_hash_table_iter_init (&iter, priv->popovers);
+  link = priv->popovers;
 
-  while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &popover))
+  while (link)
     {
+      popover = link->data;
+      link = link->next;
+
       if (popover->window && gtk_widget_is_visible (popover->widget) &&
           gtk_cairo_should_draw_window (cr, popover->window))
         gtk_container_propagate_draw (GTK_CONTAINER (widget),
@@ -11975,12 +12040,12 @@ gtk_window_add_popover (GtkWindow *window,
 
   priv = window->priv;
 
-  if (g_hash_table_contains (priv->popovers, popover))
+  if (_gtk_window_has_popover (window, popover))
     return;
 
   data = g_new0 (GtkWindowPopover, 1);
   data->widget = popover;
-  g_hash_table_insert (priv->popovers, popover, data);
+  priv->popovers = g_list_prepend (priv->popovers, data);
 
   if (gtk_widget_get_realized (GTK_WIDGET (window)))
     popover_realize (popover, data, window);
@@ -12002,12 +12067,20 @@ gtk_window_remove_popover (GtkWindow *window,
                            GtkWidget *popover)
 {
   GtkWindowPrivate *priv;
+  GtkWindowPopover *data;
 
   g_return_if_fail (GTK_IS_WINDOW (window));
   g_return_if_fail (GTK_IS_WIDGET (popover));
 
   priv = window->priv;
-  g_hash_table_remove (priv->popovers, popover);
+
+  data = _gtk_window_has_popover (window, popover);
+
+  if (!data)
+    return;
+
+  priv->popovers = g_list_remove (priv->popovers, data);
+  popover_destroy (data);
 }
 
 /**
@@ -12031,13 +12104,11 @@ gtk_window_set_popover_position (GtkWindow                   *window,
                                  const cairo_rectangle_int_t *rect)
 {
   GtkWindowPopover *data;
-  GtkWindowPrivate *priv;
 
   g_return_if_fail (GTK_IS_WINDOW (window));
   g_return_if_fail (GTK_IS_WIDGET (popover));
 
-  priv = window->priv;
-  data = g_hash_table_lookup (priv->popovers, popover);
+  data = _gtk_window_has_popover (window, popover);
 
   if (!data)
     {
@@ -12088,13 +12159,11 @@ gtk_window_get_popover_position (GtkWindow             *window,
                                  cairo_rectangle_int_t *rect)
 {
   GtkWindowPopover *data;
-  GtkWindowPrivate *priv;
 
   g_return_if_fail (GTK_IS_WINDOW (window));
   g_return_if_fail (GTK_IS_WIDGET (popover));
 
-  priv = window->priv;
-  data = g_hash_table_lookup (priv->popovers, popover);
+  data = _gtk_window_has_popover (window, popover);
 
   if (!data)
     {


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