Re: gtk_widget_queue_resize() forgetting allocation
- From: Tim Janik <timj gtk org>
- To: Owen Taylor <otaylor redhat com>
- Cc: Gtk+ Developers <gtk-devel-list gnome org>, 9sjb qlink queensu ca, Gtk+ MList <gtk-list gnome org>
- Subject: Re: gtk_widget_queue_resize() forgetting allocation
- Date: Tue, 5 Oct 2004 17:54:30 +0200 (CEST)
On Mon, 27 Sep 2004, Owen Taylor wrote:
I'm not *completely* sure this should be considered a GTK+ bug, since
what you are doing is fairly marginal. But there is a fairly easy
fix, which would be, in gtk_widget_size_allocate(), do:
alloc_needed = GTK_WIDGET_ALLOC_NEEDED (widget);
- GTK_PRIVATE_UNSET_FLAG (widget, GTK_ALLOC_NEEDED);
+ /* Preserve request/allocate ordering */
+ if (!GTK_WIDGET_REQUEST_NEEDED (widget))
+ GTK_PRIVATE_UNSET_FLAG (widget, GTK_ALLOC_NEEDED);
So, I'd actually appreciate it if you could file a bug in bugzilla
with your test case as an attachment and a link to this analysis
in the mail.gnome.org archives.
that is: #153896.
i've run into REQUEST_NEEDED still being set upon ::size-allocate while
debugging another scenario. unfortunately, the exact setup to reproduce
the bug i'm talking about is fairly complicated, it involves a lot of
widgets, a bunch of signal connections, size groups and a scrolled window.
here, siblings of a scrolled window (grouped together with the scrolled
window in a GtkSizeGroup) end up size requested but not properly size
allocated, with flags !REQUEST_NEEDED && ALLOC_NEEDED or with both
flags unset, but the last size-allocate left out.
the actual problem is that gtk_widget_size_request() may be called
during size-allocation. with scrolled windows, this is actually not
uncommon, since size-allocate on a scrolled window changes the scroll
adjustments, and that in turn may change scrollbar visibility (which
queues a resize).
but if queue_resize is called during the size-allocation phase, for
some selected widgets inside a hirachy, the following state changes can
occour (widget and sibling don't need to share the same immediate parent,
but they have a common container in their ancestry and share a size-group):
queue_resize:
REQUEST_NEEDED ALLOC_NEEDED
ancestry * *
widget * *
sibling * *
size_request:
REQUEST_NEEDED ALLOC_NEEDED
ancestry *
widget *
sibling *
start of size_allocate phase:
REQUEST_NEEDED ALLOC_NEEDED
ancestry (got allocated)
widget (currently being allocated)
sibling *
widget calls queue_resize from size_allocate, which causes
queue_resize(sibling) (due to the GtkSizeGroup):
REQUEST_NEEDED ALLOC_NEEDED
ancestry * *
widget * *
sibling * *
end of first size_allocate phase:
REQUEST_NEEDED ALLOC_NEEDED
ancestry * *
widget * *
sibling * (got allocated)
after another size_request and size_allocate round, this will lead to
ancestry and widget being allocated new sizes, but will leave sibling
unallocated (though it was requested a new size).
calling gtk_widget_size_request() on a widget basically means:
1) call size_request on this widget (REQUEST_NEEDED set)
2) call size-allocate on this widget (ALLOC_NEEDED set)
and having REQUEST_NEEDED and/or ALLOC_NEEDED set on a widget requires
3) all its ancestry up to its resize-container have those flags set as well,
4) its resize-container must be in the idle-sizer queue.
so, doing just:
- GTK_PRIVATE_UNSET_FLAG (widget, GTK_ALLOC_NEEDED);
+ /* Preserve request/allocate ordering */
+ if (!GTK_WIDGET_REQUEST_NEEDED (widget))
+ GTK_PRIVATE_UNSET_FLAG (widget, GTK_ALLOC_NEEDED);
in gtk_widget_size_allocate() isn't good enough.
only calling gtk_widget_size_allocate() will cause proper size
requisition on GtkSizeGroup siblings and care of the ancestry
invariants (3) and (4).
so CVS head now contains:
+Tue Oct 5 17:06:26 2004 Tim Janik <timj gtk org>
+
+ * gtk/gtkwidget.c (gtk_widget_size_allocate): if REQUEST_NEEDED is still
+ set on ::size-allocate, another size-request has been queued since
+ ::size-request and needs to be requeued.
+
--- gtk/gtkwidget.c 16 Aug 2004 18:38:55 -0000 1.380
+++ gtk/gtkwidget.c 5 Oct 2004 15:08:14 -0000
@@ -2705,7 +2705,13 @@ gtk_widget_size_allocate (GtkWidget *wid
old_allocation.y != real_allocation.y);
if (!alloc_needed && !size_changed && !position_changed)
- return;
+ {
+ if (GTK_WIDGET_REQUEST_NEEDED (widget))
+ { /* another resize has been queued */
+ gtk_widget_queue_resize (widget);
+ }
+ return;
+ }
g_signal_emit (widget, widget_signals[SIZE_ALLOCATE], 0, &real_allocation);
@@ -2743,6 +2749,11 @@ gtk_widget_size_allocate (GtkWidget *wid
GdkRegion *invalidate = gdk_region_rectangle (&widget->parent->allocation);
gtk_widget_invalidate_widget_windows (widget->parent, invalidate);
gdk_region_destroy (invalidate);
+ }
+
+ if (GTK_WIDGET_REQUEST_NEEDED (widget))
+ { /* another resize has been queued */
+ gtk_widget_queue_resize (widget);
}
}
and i want to merge this into 2.4, but thought i'd ask for review first.
(this should also fix the issue reported in #153896)
---
ciaoTJ
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]