Size allocation and redrawing issues



Hi Tim,

Could you please review the following: it describes some things I'd
like to improve with allocation and redrawing, gives a list of
"invariants" that I think we need to maintain, and proposes a few
changes to the way we do allocation and redrawing.

Thanks,
                                        Owen

====

There are essentially  issues that I'd like to address:
 
 * We need to get rid of hysteresis. This is the phenomena where
   if a widget's requisitions shrinks, it won't be allocated
   smaller, until something happens to cause gtk_widget_size_allocate()
   on the toplevel.

 * There are some optimizations that we are missing. For example,
   if you are resizing a toplevel, it should not be necessary to redraw
   no-window widgets that don't change size.

 * It should be possible to write a widget that can change size
   without it being completely redrawn. This is important for smooth
   resizing in a situation where you are displaying a portion of a
   large "canvas".

   An example inside GTK+ is GtkTreeView - if you resize a GtkTreeView
   larger, all columns are redrawn, not just the last visible column.

The important things that must be maintained:

 * If you call gtk_widget_queue_resize() on a widget, that must result
   in:
  
    - a call to gtk_widget_size_request() on the widget
    - a call to gtk_widget_size_allocate() on the widget
    - the widget being redrawn
  
   Currently, all three of these will propagate to descendents
   of the widget, but I don't think there is actually any real
   requirement that the second two propagate (except as required
   by changing allocations, and propagation of exposes to NO_WINDOW
   children.)

 * If a NO_WINDOW widget is allocated with a different 
   allocation->x, allocation->y, then we must invalidate all of
   the new and old widget->allocation in widget->window. There is 
   no need to invalidate in other windows owned by the widget.

 * By default, if a widget is allocated with a different size,
   we must invalidate all of the new and old allocation in
   widget->window and any descendent windows owned by the widget.

   We do not need to invalidate in descendent windows not 
   owned by the widget.

   It may be desirable to add a widget flag to turn off this behavior.

 * If widget->allocation changes in any way and the reallocate_redraws
   flag is set on the widget's parent, then the parent must be redrawn
   in its entirety.

 * When a NO_WINDOW widget is mapped, widget->allocation must
   be invalidated in widget->window. !NO_WINDOW widgets and 
   descendent windows owned by the widget do not need to be
   invalidated. (It's useful to invalidate them to prevent round
   trips to the server; this should be done in GDK, however.)

 * When a NO_WINDOW widget is unmapped, widget->allocation must
   be invalidated in widget->window.

The scheme I have for achieving the first three goals while maintaining
the above facts (some of the stuff below is already done, but included
for clarity.)

 * Add a flag:

     void gtk_widget_set_redraw_on_allocate (GtkWidget widget, gboolean redraw_on_allocate);

   Defaulting to TRUE, where TRUE means "If I get a new size, redraw all of me".
   If FALSE, then the only invalidation GTK+ will do on size change is the
   new part of the allocation, and any invalidation from GdkWindows changing
   size.

   This is unfortunately close in name to gtk_container_set_reallocate_redraws(),
   but nothing much we can do about that - set_reallocate_redraws() should have
   been named "set_child_reallocate_redraws()" or something.
 
 * In gtk_widget_queue_resize(), invalidate the allocation of the widget
   in widget->window and all descendent windows owned by the widget.

 * Use the following algorithm in gtk_container_resize_children():

    Set a private ALLOCATE_NEEDED flag for all widgets in 
     resize_widgets, and all intermediate widgets between those
     widgets and the container.

    Call gtk_widget_size_allocate() on the container.

 * In gtk_widget_size_allocate():

    Clear the allocate_needed flag.

    If the allocate_needed flag was not set and the new allocation is
     equal to widget->allocation, return.

    Call size_allocate() on the widget

    If the allocation->x,y changed and its a NO_WINDOW widget, invalidate
    the union of the old and new allocation.

    If allocation->width,height changes:
      If redraw_on_allocate is not set:
        Invalidate difference of old and new allocation in widget->window
        if it's A NO_WINDOW widget, otherwise do nothing
      Iif redraw_on_allocate is set:
        Invalidate the union of the old and new allocation in widget->window
        and in all descendents of widget->window owned by the widget.

 * On map and unmap:

    If the widget is NO_WINDOW, invalidate the widget's allocation.




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]