Fixed hangs in TextView and ToolPalette

Fixed the hangs by adding a ->inside_allocation flag and avoiding to
queue resizes while inside the allocation loop. The extra queue'd resizes
were causing the scrolled window size_allocate() to perform the guess
again and again thus causing an infinite loop.
This commit is contained in:
Tristan Van Berkom 2010-10-30 23:10:43 +09:00
parent 338001ae48
commit ae71cf7209

View File

@ -134,6 +134,7 @@ struct _GtkScrolledWindowPrivate
guint vscrollbar_visible : 1;
guint window_placement : 2;
guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
guint inside_allocate : 1;
gint min_content_width;
gint min_content_height;
@ -1444,6 +1445,30 @@ gtk_scrolled_window_relative_allocation (GtkWidget *widget,
}
}
static void
gtk_scrolled_window_allocate_child (GtkScrolledWindow *swindow,
GtkAllocation *relative_allocation)
{
GtkScrolledWindowPrivate *priv = swindow->priv;
GtkWidget *widget = GTK_WIDGET (swindow), *child;
GtkAllocation allocation;
GtkAllocation child_allocation;
child = gtk_bin_get_child (GTK_BIN (widget));
gtk_widget_get_allocation (widget, &allocation);
gtk_scrolled_window_relative_allocation (widget, relative_allocation);
child_allocation.x = relative_allocation->x + allocation.x;
child_allocation.y = relative_allocation->y + allocation.y;
child_allocation.width = relative_allocation->width;
child_allocation.height = relative_allocation->height;
priv->inside_allocate = TRUE;
gtk_widget_size_allocate (child, &child_allocation);
priv->inside_allocate = FALSE;
}
static void
gtk_scrolled_window_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
@ -1495,15 +1520,6 @@ gtk_scrolled_window_size_allocate (GtkWidget *widget,
gboolean previous_vvis;
guint count = 0;
/* In the case that both scrollbars are visible in the previous round,
* we dont do our guess-work before hand because it's possible some
* infinite recursion was detected (leave it up to the child scrollable
* widget in this case to drive the scrollbar visibility completely
* with the adjustment values).
*/
if (!priv->vscrollbar_visible || !priv->hscrollbar_visible)
{
/* Determine scrollbar visibility first via hfw apis */
if (gtk_widget_get_request_mode (child) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
{
@ -1627,7 +1643,6 @@ gtk_scrolled_window_size_allocate (GtkWidget *widget,
priv->vscrollbar_visible = priv->vscrollbar_policy != GTK_POLICY_NEVER;
}
}
}
/* Now after guessing scrollbar visibility; fall back on the allocation loop which
* observes the adjustments to detect scrollbar visibility and also avoids
@ -1635,17 +1650,9 @@ gtk_scrolled_window_size_allocate (GtkWidget *widget,
*/
do
{
gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
child_allocation.x = relative_allocation.x + allocation->x;
child_allocation.y = relative_allocation.y + allocation->y;
child_allocation.width = relative_allocation.width;
child_allocation.height = relative_allocation.height;
previous_hvis = priv->hscrollbar_visible;
previous_vvis = priv->vscrollbar_visible;
gtk_widget_size_allocate (child, &child_allocation);
gtk_scrolled_window_allocate_child (scrolled_window, &relative_allocation);
/* If, after the first iteration, the hscrollbar and the
* vscrollbar flip visiblity, then we need both.
@ -1657,10 +1664,9 @@ gtk_scrolled_window_size_allocate (GtkWidget *widget,
priv->hscrollbar_visible = TRUE;
priv->vscrollbar_visible = TRUE;
/* a new resize is already queued at this point,
* so we will immediatedly get reinvoked
*/
return;
gtk_scrolled_window_allocate_child (scrolled_window, &relative_allocation);
break;
}
count++;
@ -1864,7 +1870,7 @@ gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
visible = priv->hscrollbar_visible;
priv->hscrollbar_visible = (adjustment->upper - adjustment->lower >
adjustment->page_size);
if (priv->hscrollbar_visible != visible)
if (!priv->inside_allocate && priv->hscrollbar_visible != visible)
gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
}
}
@ -1878,7 +1884,7 @@ gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
visible = priv->vscrollbar_visible;
priv->vscrollbar_visible = (adjustment->upper - adjustment->lower >
adjustment->page_size);
if (priv->vscrollbar_visible != visible)
if (!priv->inside_allocate && priv->vscrollbar_visible != visible)
gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
}
}