[gtk+] Avoid copying lists during draw



commit ff3cb8ac7168da084e49203e835b11dfe751aad8
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Sep 27 00:32:40 2015 -0400

    Avoid copying lists during draw
    
    We can use gdk_window_peek_children here, instead of copying
    the list. Note that we preserve the bottom-to-top ordering by
    iterating the list from the end.
    gdk_window_get_children_with_user_data was doing a list
    reversal while filtering the list.

 gtk/gtkwidget.c |  121 ++++++++++++++++++++++++++++++-------------------------
 1 files changed, 66 insertions(+), 55 deletions(-)
---
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 3fa9394..1214150 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -6870,13 +6870,14 @@ _gtk_widget_draw_internal (GtkWidget *widget,
 }
 
 /* Emit draw() on the widget that owns window,
-   and on any child windows that also belong
-   to the widget. */
+ * and on any child windows that also belong
+ * to the widget.
+ */
 static void
 _gtk_widget_draw_windows (GdkWindow *window,
-                         cairo_t *cr,
-                         int window_x,
-                         int window_y)
+                         cairo_t   *cr,
+                         int        window_x,
+                         int        window_y)
 {
   cairo_pattern_t *pattern;
   gboolean do_clip;
@@ -6894,9 +6895,10 @@ _gtk_widget_draw_windows (GdkWindow *window,
   window_clip.height = gdk_window_get_height (window);
 
   /* Cairo paths are fixed point 24.8, but GDK supports 32-bit window
-     sizes, so we can't feed window_clip to e.g. cairo_rectangle()
-     directly. Instead, we pre-clip the window clip to the existing
-     clip regions in full 32-bit precision and feed that to cairo. */
+   * sizes, so we can't feed window_clip to e.g. cairo_rectangle()
+   * directly. Instead, we pre-clip the window clip to the existing
+   * clip regions in full 32-bit precision and feed that to cairo.
+   */
   if (!gdk_cairo_get_clip_rectangle (cr, &current_clip) ||
       !gdk_rectangle_intersect (&window_clip, &current_clip, &window_clip))
     return;
@@ -6914,44 +6916,47 @@ _gtk_widget_draw_windows (GdkWindow *window,
       gdk_window_get_user_data (window, (gpointer *) &widget);
 
       /* Only clear bg if double buffered. This is what we used
-        to do before, where begin_paint() did the clearing. */
+       * to do before, where begin_paint() did the clearing.
+       */
       pattern = gdk_window_get_background_pattern (window);
-      if (pattern != NULL &&
-         widget->priv->double_buffered)
-       {
-         cairo_save (cr);
-         cairo_set_source (cr, pattern);
-         cairo_paint (cr);
-         cairo_restore (cr);
-       }
+      if (pattern != NULL && widget->priv->double_buffered)
+        {
+          cairo_save (cr);
+          cairo_set_source (cr, pattern);
+          cairo_paint (cr);
+          cairo_restore (cr);
+        }
 
-      do_clip = _gtk_widget_get_translation_to_window (widget, window,
-                                                      &x, &y);
+      do_clip = _gtk_widget_get_translation_to_window (widget, window, &x, &y);
       cairo_save (cr);
       cairo_translate (cr, -x, -y);
       _gtk_widget_draw_internal (widget, cr, do_clip, window);
       cairo_restore (cr);
 
-      children = gdk_window_get_children_with_user_data (window, widget);
-      for (l = children; l != NULL; l = l->next)
-       {
-         GdkWindow *child_window = l->data;
-         GdkWindowType type;
-         int wx, wy;
+      children = gdk_window_peek_children (window);
+      for (l = g_list_last (children); l != NULL; l = l->prev)
+        {
+          GdkWindow *child_window = l->data;
+          GdkWindowType type;
+          int wx, wy;
+          GtkWidget *window_widget;
 
-         if (!gdk_window_is_visible (child_window) ||
-             gdk_window_is_input_only (child_window))
-           continue;
+          gdk_window_get_user_data (child_window, (gpointer *)&window_widget);
+          if (window_widget != widget)
+            continue;
 
-         type = gdk_window_get_window_type (child_window);
-         if (type == GDK_WINDOW_OFFSCREEN ||
-             type == GDK_WINDOW_FOREIGN)
-           continue;
+          if (!gdk_window_is_visible (child_window) ||
+              gdk_window_is_input_only (child_window))
+            continue;
 
-         gdk_window_get_position (child_window, &wx, &wy);
-         _gtk_widget_draw_windows (child_window, cr, wx, wy);
-       }
-      g_list_free (children);
+          type = gdk_window_get_window_type (child_window);
+          if (type == GDK_WINDOW_OFFSCREEN ||
+              type == GDK_WINDOW_FOREIGN)
+            continue;
+
+          gdk_window_get_position (child_window, &wx, &wy);
+          _gtk_widget_draw_windows (child_window, cr, wx, wy);
+        }
     }
 
   cairo_restore (cr);
@@ -6961,7 +6966,7 @@ void
 _gtk_widget_draw (GtkWidget *widget,
                  cairo_t   *cr)
 {
-  GdkWindow *window, *child_window;
+  GdkWindow *window;
   GList *children, *l;
   int wx, wy;
   gboolean push_group;
@@ -6999,7 +7004,8 @@ _gtk_widget_draw (GtkWidget *widget,
   if (_gtk_widget_get_has_window (widget))
     {
       /* The widget will be completely contained in its window, so just
-       * expose that (and any child window belonging to the widget) */
+       * expose that (and any child window belonging to the widget)
+       */
       _gtk_widget_draw_windows (window, cr, 0, 0);
     }
   else
@@ -7009,27 +7015,32 @@ _gtk_widget_draw (GtkWidget *widget,
       _gtk_widget_draw_internal (widget, cr, TRUE, window);
 
       /* But, it may also have child windows in the parent which we should
-       * draw (after having drawn on the parent) */
-      children = gdk_window_get_children_with_user_data (window, widget);
-      for (l = children; l != NULL; l = l->next)
+       * draw (after having drawn on the parent)
+       */
+      children = gdk_window_peek_children (window);
+      for (l = g_list_last (children); l != NULL; l = l->prev)
        {
-         child_window = l->data;
+          GdkWindow *child_window = l->data;
+          GtkWidget *window_widget;
 
-         if (!gdk_window_is_visible (child_window) ||
-             gdk_window_is_input_only (child_window))
-           continue;
+          gdk_window_get_user_data (child_window, (gpointer *)&window_widget);
+          if (window_widget != widget)
+            continue;
 
-         type = gdk_window_get_window_type (child_window);
-         if (type == GDK_WINDOW_OFFSCREEN ||
-             type == GDK_WINDOW_FOREIGN)
-           continue;
+          if (!gdk_window_is_visible (child_window) ||
+              gdk_window_is_input_only (child_window))
+            continue;
 
-         gdk_window_get_position (child_window, &wx, &wy);
-         _gtk_widget_draw_windows (child_window, cr,
-                                   wx - widget->priv->allocation.x,
-                                   wy - widget->priv->allocation.y);
-       }
-      g_list_free (children);
+          type = gdk_window_get_window_type (child_window);
+          if (type == GDK_WINDOW_OFFSCREEN ||
+              type == GDK_WINDOW_FOREIGN)
+            continue;
+
+          gdk_window_get_position (child_window, &wx, &wy);
+          _gtk_widget_draw_windows (child_window, cr,
+                                    wx - widget->priv->allocation.x,
+                                    wy - widget->priv->allocation.y);
+        }
     }
 
   if (push_group)


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