Re: gtk_widget_queue_resize() forgetting allocation
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 [EMAIL PROTECTED] + + * 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 - 1.380 +++ gtk/gtkwidget.c 5 Oct 2004 15:08:14 - @@ -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
Re: gtk_widget_queue_resize() forgetting allocation
On Tue, 2004-10-05 at 17:54 +0200, Tim Janik wrote: 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. The way I'd think of this is that calling gtk_widget_size_request() sets the REQUEST_NEEDED flag, and we have a set of invariants: 1) If REQUEST_NEEDED is set on a widget, REQUEST_NEEDED is set on all parents up to the resize container 2) If REQUEST_NEEDED is set on the resize container, the resize container has an idle queued on it. 3) If REQUEST_NEEDED is set on a widget, ALLOC_NEEDED will be set on a widget. With the idle sizer behavior of calling request() than allocate() on the toplevel, I think this gives the correct behavior that queue_resize(widget) ensures ::request followed by ::allocate on the widget. As far as I can see, calls to gtk_widget_size_request() during size_allocate() still will handle 1) and 2) fine. The only problem comes with 3), which my patch should fix up. Regards, Owen signature.asc Description: This is a digitally signed message part ___ gtk-list mailing list [EMAIL PROTECTED] http://mail.gnome.org/mailman/listinfo/gtk-list
Re: gtk_widget_queue_resize() forgetting allocation
On Tue, 5 Oct 2004, Owen Taylor wrote: The way I'd think of this is that calling gtk_widget_size_request() sets the REQUEST_NEEDED flag, and we have a set of invariants: 1) If REQUEST_NEEDED is set on a widget, REQUEST_NEEDED is set on all parents up to the resize container 2) If REQUEST_NEEDED is set on the resize container, the resize container has an idle queued on it. 3) If REQUEST_NEEDED is set on a widget, ALLOC_NEEDED will be set on a widget. With the idle sizer behavior of calling request() than allocate() on the toplevel, I think this gives the correct behavior that queue_resize(widget) ensures ::request followed by ::allocate on the widget. As far as I can see, calls to gtk_widget_size_request() during size_allocate() still will handle 1) and 2) fine. The only problem comes with 3), which my patch should fix up. ok, i tried hard, but after my initial example fell apart (idle sizer without size-request as discussed on irc), i can't come up with a scenrio to break the invariants with your patch at the moment. and since your patch does indeed fix my resizing bug, i gave you the benfit of a doubt and applied your patch. you agree on merging it down to 2.4? Regards, Owen --- ciaoTJ ___ gtk-list mailing list [EMAIL PROTECTED] http://mail.gnome.org/mailman/listinfo/gtk-list
Re: gtk_widget_queue_resize() forgetting allocation
On Tue, 2004-10-05 at 21:10 +0200, Tim Janik wrote: On Tue, 5 Oct 2004, Owen Taylor wrote: The way I'd think of this is that calling gtk_widget_size_request() sets the REQUEST_NEEDED flag, and we have a set of invariants: 1) If REQUEST_NEEDED is set on a widget, REQUEST_NEEDED is set on all parents up to the resize container 2) If REQUEST_NEEDED is set on the resize container, the resize container has an idle queued on it. 3) If REQUEST_NEEDED is set on a widget, ALLOC_NEEDED will be set on a widget. With the idle sizer behavior of calling request() than allocate() on the toplevel, I think this gives the correct behavior that queue_resize(widget) ensures ::request followed by ::allocate on the widget. As far as I can see, calls to gtk_widget_size_request() during size_allocate() still will handle 1) and 2) fine. The only problem comes with 3), which my patch should fix up. ok, i tried hard, but after my initial example fell apart (idle sizer without size-request as discussed on irc), i can't come up with a scenrio to break the invariants with your patch at the moment. and since your patch does indeed fix my resizing bug, i gave you the benfit of a doubt and applied your patch. you agree on merging it down to 2.4? Yes, I think it's a pretty safe change. Regards, Owen signature.asc Description: This is a digitally signed message part ___ gtk-list mailing list [EMAIL PROTECTED] http://mail.gnome.org/mailman/listinfo/gtk-list
Re: gtk_widget_queue_resize() forgetting allocation
On Mon, Sep 27, 2004 at 12:35:54PM -0400, Owen Taylor wrote: 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. Done. Two easy workarounds for your problem you might want to try: - Change the resize mode on the Viewport to PARENT after creating it. - Do your label_resize in a handler for 'size-allocate' on the toplevel rather than '::configure-event'. I went with a modified version of the second one, and all is well. Thanks -- your input was invaluable. Stephen ___ gtk-list mailing list [EMAIL PROTECTED] http://mail.gnome.org/mailman/listinfo/gtk-list
Re: gtk_widget_queue_resize() forgetting allocation
For posterity: I isolated the issue to the GtkViewport widget. I found that if I packed the label/vbox into a GtkLayout and packed that into the GtkScrolledWindow, the size negotiations worked the way they should. I don't know if the problem is caused by some function of the viewport that I don't understand, but I'm not going to spend any more time on it. Using a layout works, though it requires a little more massaging. The only problem I have now is that the step_increment field of the vertical GtkAdjustment in the scrolled window doesn't update itself upon resize, and indeed sits at zero. But I can deal with that. On Sun, Sep 19, 2004 at 12:02:48PM -0400, Stephen Bach wrote: stuff ___ gtk-list mailing list [EMAIL PROTECTED] http://mail.gnome.org/mailman/listinfo/gtk-list
Re: gtk_widget_queue_resize() forgetting allocation
No one has any insight here? It seems to me that a call to gtk_widget_size_request() should be followed by a gtk_widget_size_allocate() when generated by a gtk_widget_queue_resize(), especially if the program goes idle. Is there something about the size negotiation process that I'm misunderstanding? Thanks On Sun, Sep 19, 2004 at 12:02:48PM -0400, Stephen Bach wrote: Hello, I've run into an issue in a program I'm writing where sometimes a call to gtk_widget_queue_resize() ends in a request rather than an allocate. I've put together a short test case (tested in GTK+ 2.4.4) which keeps the spirit of the program intact (see below). First, a little context -- connecting to the toplevel window's configure-event to queue a resize on one of its grandchildren probably seems unconventional and even redundant, but it's a requirement of my program (not this test case) because the request function of that grandchild optimizes itself to the window's width (i.e. the grandchild needs more information than just the size requests of its children). In the real program the change in the window's width is passed on and then the queue_resize is made. All of that is beside the point. Here is the problem: _sometimes_ when the window is resized, there is no allocation of the grandchild label after a request. If the window is resized again, _then_ the allocation happens (usually followed by another unfulfilled size request). One thing that's kind-of strange is that if the label is added directly to the scrolledwindow (without being added to the vbox, which then gets put into the scrolledwindow), everything works as it should -- every size request is followed by a size allocate. I also tried using a table instead of a vbox, but the result is the same. Insight welcome. Thanks, Stephen = #include gtk/gtk.h static void allocate_callback(GtkWidget *label, GtkAllocation *allocation, gpointer data) { g_print((allocate)); } static void request_callback(GtkWidget *label, GtkRequisition *requisition, gpointer data) { g_print((request)); } static gboolean configure_callback(GtkWidget* window, GdkEventConfigure* event, gpointer data) { GtkWidget* label = data; /* Only queue resize if the width is changed */ if (event-width != window-allocation.width) gtk_widget_queue_resize(label); return FALSE; } int main(int argc, char* argv[]) { GtkWidget* window; GtkWidget* scrolled_window; GtkWidget* vbox; GtkWidget* label; gtk_init (argc, argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); scrolled_window = gtk_scrolled_window_new(NULL, NULL); vbox = gtk_vbox_new(FALSE, 0); label = gtk_label_new(Testing); g_signal_connect(G_OBJECT(label), size-allocate, G_CALLBACK(allocate_callback), NULL); g_signal_connect(G_OBJECT(label), size-request, G_CALLBACK(request_callback), NULL); g_signal_connect(G_OBJECT(window), configure-event, G_CALLBACK(configure_callback), label); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(scrolled_window), vbox); gtk_container_add(GTK_CONTAINER(window), scrolled_window); gtk_widget_show(label); gtk_widget_show(vbox); gtk_widget_show(scrolled_window); gtk_widget_show(window); gtk_main(); return 0; } ___ gtk-list mailing list [EMAIL PROTECTED] http://mail.gnome.org/mailman/listinfo/gtk-list ___ gtk-list mailing list [EMAIL PROTECTED] http://mail.gnome.org/mailman/listinfo/gtk-list
gtk_widget_queue_resize() forgetting allocation
Hello, I've run into an issue in a program I'm writing where sometimes a call to gtk_widget_queue_resize() ends in a request rather than an allocate. I've put together a short test case (tested in GTK+ 2.4.4) which keeps the spirit of the program intact (see below). First, a little context -- connecting to the toplevel window's configure-event to queue a resize on one of its grandchildren probably seems unconventional and even redundant, but it's a requirement of my program (not this test case) because the request function of that grandchild optimizes itself to the window's width (i.e. the grandchild needs more information than just the size requests of its children). In the real program the change in the window's width is passed on and then the queue_resize is made. All of that is beside the point. Here is the problem: _sometimes_ when the window is resized, there is no allocation of the grandchild label after a request. If the window is resized again, _then_ the allocation happens (usually followed by another unfulfilled size request). One thing that's kind-of strange is that if the label is added directly to the scrolledwindow (without being added to the vbox, which then gets put into the scrolledwindow), everything works as it should -- every size request is followed by a size allocate. I also tried using a table instead of a vbox, but the result is the same. Insight welcome. Thanks, Stephen = #include gtk/gtk.h static void allocate_callback(GtkWidget *label, GtkAllocation *allocation, gpointer data) { g_print((allocate)); } static void request_callback(GtkWidget *label, GtkRequisition *requisition, gpointer data) { g_print((request)); } static gboolean configure_callback(GtkWidget* window, GdkEventConfigure* event, gpointer data) { GtkWidget* label = data; /* Only queue resize if the width is changed */ if (event-width != window-allocation.width) gtk_widget_queue_resize(label); return FALSE; } int main(int argc, char* argv[]) { GtkWidget* window; GtkWidget* scrolled_window; GtkWidget* vbox; GtkWidget* label; gtk_init (argc, argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); scrolled_window = gtk_scrolled_window_new(NULL, NULL); vbox = gtk_vbox_new(FALSE, 0); label = gtk_label_new(Testing); g_signal_connect(G_OBJECT(label), size-allocate, G_CALLBACK(allocate_callback), NULL); g_signal_connect(G_OBJECT(label), size-request, G_CALLBACK(request_callback), NULL); g_signal_connect(G_OBJECT(window), configure-event, G_CALLBACK(configure_callback), label); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(scrolled_window), vbox); gtk_container_add(GTK_CONTAINER(window), scrolled_window); gtk_widget_show(label); gtk_widget_show(vbox); gtk_widget_show(scrolled_window); gtk_widget_show(window); gtk_main(); return 0; } ___ gtk-list mailing list [EMAIL PROTECTED] http://mail.gnome.org/mailman/listinfo/gtk-list