Re: gtk_widget_queue_resize() forgetting allocation

2004-10-05 Thread Tim Janik
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

2004-10-05 Thread Owen Taylor
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

2004-10-05 Thread Tim Janik
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

2004-10-05 Thread Owen Taylor
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

2004-09-27 Thread Stephen Bach
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

2004-09-25 Thread Stephen Bach
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

2004-09-22 Thread Stephen Bach
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

2004-09-19 Thread Stephen Bach
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