GNOME Bugzilla – Bug 155190
Invalidate widget areas if it needs allocation
Last modified: 2005-01-20 19:24:33 UTC
A friend of mine encountered a strange behavior (probably bug) in GTK+-2.4.x The problem description: There's a container w/ one or several GtkImage's in it. After performing 'hide' on the container, the entire window becomes smaller. 'show'ing the container restores window size, BUT 'expose' event is delivered only to parts of the GtkImage(s) (which would be shown if window size wasn't changed). This behaviour can be observed if the window has resizable = false. Here's the demostration program (pygtk) URL: http://dfo.antex.ru/files/unix/gtkbug.py
Created attachment 36198 [details] The same in the C (much easier to debug)
Created attachment 36199 [details] Another testcase This test is closer to the problem, it just logs "allocate" and "expose" events. Here is the example of it's output: ** Message: Allocate event recieved for GtkWindow ** Message: Rectangle 0 0 48 92 ** Message: Expose event recieved 3 rects for GtkWindow ** Message: Rectangle 0 0 48 16 ** Message: Rectangle 41 16 7 1 ** Message: Rectangle 0 17 48 75 Note that instead of 1 rectangle window gets region that is intersection of 3 rectanges. More interesting is that width of 2-nd rectangle is always the spacing of VBox. So, probably, there are vbox problems :)
Created attachment 36250 [details] [review] Patch to CVS I've found the reasons of such behaviour. The situation is following - after widget hide/show it's GTK_ALLOC_NEEDED flag becomes true, but allocation remains the same. After show, the whole widget tree is reallocated but since allocation of widget is not changed, the corresponding area is not invalidated (currently gtk check only that size of position changed). Gtk redraws only areas that was under widgets in hidded state and since in that place there was no widgets (there was vbox spacing) this area is not redrawn. The proposed patch should fix that issue. It just check for ALLOC_NEEDED flag of a widget and invalidates it's rectangle.
I think the problem/fix is likely deeper than this .. your patch probably breaks gtk_widget_set_redraw_on_allocate().
Here is the code that I'd like to see: if (size_changed || need_alloc) { if (GTK_WIDGET_REDRAW_ON_ALLOC (widget)) { /* Invalidate union(old_allaction,widget->allocation) in widget->w */ GdkRegion *invalidate = gdk_region_rectangle (&widget->allocation) gdk_region_union_with_rect (invalidate, &old_allocation); gtk_widget_invalidate_widget_windows (widget, invalidate); gdk_region_destroy (invalidate); } } It's clear that if redraw_on_allocate will be false, nothing will be changed. Even more, problem is exactly in that place. I think it's possible to write an example that will illustrate it more precisely. The only problem that after show/hide no invalidate occurs.
The second interesting question there is implementation of gtk_widget_queue_resize void gtk_widget_queue_resize (GtkWidget *widget) { g_return_if_fail (GTK_IS_WIDGET (widget)); if (GTK_WIDGET_REALIZED (widget)) { gtk_widget_queue_shallow_draw (widget); } _gtk_size_group_queue_resize (widget); } What is gtk_widget_queue_shallow_draw is doing here? I thought that redraws should be queued only in size_allocation. The call above is just unneeded resource loss.
gtk_widget_queue_resize() is guaranteed to cause a redraw on the widget ... usually it is called when some internal state of the widget changes that affects the appearance and possibly the size. See gtk_widget_queue_resize_no_redraw().
Comment on attachment 36250 [details] [review] Patch to CVS Now I see that patch above breaks exactly that function (gtk_widget_queue_resize_no_redraw). In every resize ALLOC_NEEDED is set, and with patch it causes redraw on widget.
Actually it's just an duplicate of older bug, so marking it so. *** This bug has been marked as a duplicate of 135903 ***