gdkwindow: Avoid list allocation and object refs during repaint
There is no need to ref the windows we're ignoring, so collect and ref only the affected child windows. Also, use a on-stack array rather than allocating a linked list. Also, we don't need to ref during the event emissions too, as we already hold a ref. https://bugzilla.gnome.org/show_bug.cgi?id=754687
This commit is contained in:
@ -3541,7 +3541,10 @@ _gdk_window_process_updates_recurse_helper (GdkWindow *window,
|
|||||||
{
|
{
|
||||||
GdkWindow *child;
|
GdkWindow *child;
|
||||||
cairo_region_t *clipped_expose_region;
|
cairo_region_t *clipped_expose_region;
|
||||||
GList *l, *children;
|
GdkWindow **children;
|
||||||
|
GdkWindow **free_children = NULL;
|
||||||
|
int i, n_children;
|
||||||
|
GList *l;
|
||||||
|
|
||||||
if (window->destroyed)
|
if (window->destroyed)
|
||||||
return;
|
return;
|
||||||
@ -3575,23 +3578,23 @@ _gdk_window_process_updates_recurse_helper (GdkWindow *window,
|
|||||||
GdkEvent event;
|
GdkEvent event;
|
||||||
|
|
||||||
event.expose.type = GDK_EXPOSE;
|
event.expose.type = GDK_EXPOSE;
|
||||||
event.expose.window = g_object_ref (window);
|
event.expose.window = window; /* we already hold a ref */
|
||||||
event.expose.send_event = FALSE;
|
event.expose.send_event = FALSE;
|
||||||
event.expose.count = 0;
|
event.expose.count = 0;
|
||||||
event.expose.region = clipped_expose_region;
|
event.expose.region = clipped_expose_region;
|
||||||
cairo_region_get_extents (clipped_expose_region, &event.expose.area);
|
cairo_region_get_extents (clipped_expose_region, &event.expose.area);
|
||||||
|
|
||||||
_gdk_event_emit (&event);
|
_gdk_event_emit (&event);
|
||||||
|
|
||||||
g_object_unref (window);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make this reentrancy safe for expose handlers freeing windows */
|
n_children = g_list_length (window->children);
|
||||||
children = g_list_copy (window->children);
|
children = g_newa (GdkWindow *, n_children);
|
||||||
g_list_foreach (children, (GFunc)g_object_ref, NULL);
|
if (children == NULL)
|
||||||
|
children = free_children = g_new (GdkWindow *, n_children);
|
||||||
|
|
||||||
|
n_children = 0;
|
||||||
/* Iterate over children, starting at bottommost */
|
/* Iterate over children, starting at bottommost */
|
||||||
for (l = g_list_last (children); l != NULL; l = l->prev)
|
for (l = g_list_last (window->children); l != NULL; l = l->prev)
|
||||||
{
|
{
|
||||||
child = l->data;
|
child = l->data;
|
||||||
|
|
||||||
@ -3605,10 +3608,22 @@ _gdk_window_process_updates_recurse_helper (GdkWindow *window,
|
|||||||
|
|
||||||
/* Client side child, expose */
|
/* Client side child, expose */
|
||||||
if (child->impl == window->impl)
|
if (child->impl == window->impl)
|
||||||
_gdk_window_process_updates_recurse_helper ((GdkWindow *)child, clipped_expose_region);
|
{
|
||||||
|
/* ref the child to make this reentrancy safe for expose
|
||||||
|
handlers freeing other windows */
|
||||||
|
children[n_children++] = g_object_ref (child);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_list_free_full (children, g_object_unref);
|
for (i = 0; i < n_children; i++)
|
||||||
|
{
|
||||||
|
_gdk_window_process_updates_recurse_helper ((GdkWindow *)children[i],
|
||||||
|
clipped_expose_region);
|
||||||
|
g_object_unref (children[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
g_free (free_children);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
cairo_region_destroy (clipped_expose_region);
|
cairo_region_destroy (clipped_expose_region);
|
||||||
|
|||||||
Reference in New Issue
Block a user