summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2015-09-27 00:32:40 -0400
committerMatthias Clasen <mclasen@redhat.com>2015-09-27 00:35:12 -0400
commitff3cb8ac7168da084e49203e835b11dfe751aad8 (patch)
tree28ca150df5eb177ecd24789eb6b73f4a79213dd7
parent001ba79dd61ece16696fed3b8dc0f1dc4a940860 (diff)
downloadgtk+-ff3cb8ac7168da084e49203e835b11dfe751aad8.tar.gz
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.
-rw-r--r--gtk/gtkwidget.c121
1 files changed, 66 insertions, 55 deletions
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 3fa9394d2f..121415010c 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)