diff --git a/ChangeLog b/ChangeLog index ec47b7bbb4..620483d825 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,47 @@ +Sun Nov 4 16:02:08 2001 Owen Taylor + + * gdk/gdkwindow.[ch]: Add a function gdk_window_invalidate_maybe_recurse() + for use in "shallow invalidation" of a widget. (Windows belonging + to the widget, but not to the widget's children) + + * gtk/gtkprivate.h gtk/gtkwidget.c gtk/gtksizegroup.c: Add private + flags GTK_ALLOC_NEEDED, GTK_REQUEST_NEEDED. These flags are set + up on ancestors up to the resize container on queue_resize. Size + requests only actually take place if GTK_REQUEST_NEEDED, size + allocations only take place if GTK_ALLOC_NEEDED or the size + changed. + + * gtk/gtkcontainer.c gtk/gtkwidget.c: Remove + container->resize_widgets and the RESIZE_NEEDED flag since the + above flags are sufficient to figure out what needs to be + resized/reallocated. Remove code manipulating + container->resize_widget. + + * gtk/gtkwidget.[ch]: Add gtk_widget_set_redraw_on_alloc(); this + allows widgets to turn off being automatically invalidated is when + they are resized. + + * gtk/gtkwidget.[ch] (gtk_widget_size_allocate): Invalidation when + a widget is resized or moved is "shallow" as described above - + only the windows that need to be invalidated are invalidated. + + * gtk/gtkbox.c gtk/gtktable.c gtk/gtkalignment.c docs/Changes-2.0.txt: + Make these widget's init functions call + gtk_widget_set_redraw_on_allocate(widget,FALSE). + + * gtk/gtkwindow.c (gtk_window_configure_event): Call + _gtk_container_queue_resize(), since we don't want + redrawing. (Probably could be done for other + calls to gtk_widget_queue_resize() in gtkwindow.c, + but this is the most important one.) + + * gtk/gtkwindow.c (gtk_window_move_resize): Don't call + gtk_widget_queue_draw() - size_allocate() handles + that as appropriate. + + * gtk/gtkframe.c (gtk_frame_size_allocate): Invalidate instead + of queue_clear() to avoid invalidating children. + 2001-11-04 jacob berkman * gtk/gtkmain.c (find_module): don't free the module name until diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index ec47b7bbb4..620483d825 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,47 @@ +Sun Nov 4 16:02:08 2001 Owen Taylor + + * gdk/gdkwindow.[ch]: Add a function gdk_window_invalidate_maybe_recurse() + for use in "shallow invalidation" of a widget. (Windows belonging + to the widget, but not to the widget's children) + + * gtk/gtkprivate.h gtk/gtkwidget.c gtk/gtksizegroup.c: Add private + flags GTK_ALLOC_NEEDED, GTK_REQUEST_NEEDED. These flags are set + up on ancestors up to the resize container on queue_resize. Size + requests only actually take place if GTK_REQUEST_NEEDED, size + allocations only take place if GTK_ALLOC_NEEDED or the size + changed. + + * gtk/gtkcontainer.c gtk/gtkwidget.c: Remove + container->resize_widgets and the RESIZE_NEEDED flag since the + above flags are sufficient to figure out what needs to be + resized/reallocated. Remove code manipulating + container->resize_widget. + + * gtk/gtkwidget.[ch]: Add gtk_widget_set_redraw_on_alloc(); this + allows widgets to turn off being automatically invalidated is when + they are resized. + + * gtk/gtkwidget.[ch] (gtk_widget_size_allocate): Invalidation when + a widget is resized or moved is "shallow" as described above - + only the windows that need to be invalidated are invalidated. + + * gtk/gtkbox.c gtk/gtktable.c gtk/gtkalignment.c docs/Changes-2.0.txt: + Make these widget's init functions call + gtk_widget_set_redraw_on_allocate(widget,FALSE). + + * gtk/gtkwindow.c (gtk_window_configure_event): Call + _gtk_container_queue_resize(), since we don't want + redrawing. (Probably could be done for other + calls to gtk_widget_queue_resize() in gtkwindow.c, + but this is the most important one.) + + * gtk/gtkwindow.c (gtk_window_move_resize): Don't call + gtk_widget_queue_draw() - size_allocate() handles + that as appropriate. + + * gtk/gtkframe.c (gtk_frame_size_allocate): Invalidate instead + of queue_clear() to avoid invalidating children. + 2001-11-04 jacob berkman * gtk/gtkmain.c (find_module): don't free the module name until diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index ec47b7bbb4..620483d825 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,47 @@ +Sun Nov 4 16:02:08 2001 Owen Taylor + + * gdk/gdkwindow.[ch]: Add a function gdk_window_invalidate_maybe_recurse() + for use in "shallow invalidation" of a widget. (Windows belonging + to the widget, but not to the widget's children) + + * gtk/gtkprivate.h gtk/gtkwidget.c gtk/gtksizegroup.c: Add private + flags GTK_ALLOC_NEEDED, GTK_REQUEST_NEEDED. These flags are set + up on ancestors up to the resize container on queue_resize. Size + requests only actually take place if GTK_REQUEST_NEEDED, size + allocations only take place if GTK_ALLOC_NEEDED or the size + changed. + + * gtk/gtkcontainer.c gtk/gtkwidget.c: Remove + container->resize_widgets and the RESIZE_NEEDED flag since the + above flags are sufficient to figure out what needs to be + resized/reallocated. Remove code manipulating + container->resize_widget. + + * gtk/gtkwidget.[ch]: Add gtk_widget_set_redraw_on_alloc(); this + allows widgets to turn off being automatically invalidated is when + they are resized. + + * gtk/gtkwidget.[ch] (gtk_widget_size_allocate): Invalidation when + a widget is resized or moved is "shallow" as described above - + only the windows that need to be invalidated are invalidated. + + * gtk/gtkbox.c gtk/gtktable.c gtk/gtkalignment.c docs/Changes-2.0.txt: + Make these widget's init functions call + gtk_widget_set_redraw_on_allocate(widget,FALSE). + + * gtk/gtkwindow.c (gtk_window_configure_event): Call + _gtk_container_queue_resize(), since we don't want + redrawing. (Probably could be done for other + calls to gtk_widget_queue_resize() in gtkwindow.c, + but this is the most important one.) + + * gtk/gtkwindow.c (gtk_window_move_resize): Don't call + gtk_widget_queue_draw() - size_allocate() handles + that as appropriate. + + * gtk/gtkframe.c (gtk_frame_size_allocate): Invalidate instead + of queue_clear() to avoid invalidating children. + 2001-11-04 jacob berkman * gtk/gtkmain.c (find_module): don't free the module name until diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index ec47b7bbb4..620483d825 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,47 @@ +Sun Nov 4 16:02:08 2001 Owen Taylor + + * gdk/gdkwindow.[ch]: Add a function gdk_window_invalidate_maybe_recurse() + for use in "shallow invalidation" of a widget. (Windows belonging + to the widget, but not to the widget's children) + + * gtk/gtkprivate.h gtk/gtkwidget.c gtk/gtksizegroup.c: Add private + flags GTK_ALLOC_NEEDED, GTK_REQUEST_NEEDED. These flags are set + up on ancestors up to the resize container on queue_resize. Size + requests only actually take place if GTK_REQUEST_NEEDED, size + allocations only take place if GTK_ALLOC_NEEDED or the size + changed. + + * gtk/gtkcontainer.c gtk/gtkwidget.c: Remove + container->resize_widgets and the RESIZE_NEEDED flag since the + above flags are sufficient to figure out what needs to be + resized/reallocated. Remove code manipulating + container->resize_widget. + + * gtk/gtkwidget.[ch]: Add gtk_widget_set_redraw_on_alloc(); this + allows widgets to turn off being automatically invalidated is when + they are resized. + + * gtk/gtkwidget.[ch] (gtk_widget_size_allocate): Invalidation when + a widget is resized or moved is "shallow" as described above - + only the windows that need to be invalidated are invalidated. + + * gtk/gtkbox.c gtk/gtktable.c gtk/gtkalignment.c docs/Changes-2.0.txt: + Make these widget's init functions call + gtk_widget_set_redraw_on_allocate(widget,FALSE). + + * gtk/gtkwindow.c (gtk_window_configure_event): Call + _gtk_container_queue_resize(), since we don't want + redrawing. (Probably could be done for other + calls to gtk_widget_queue_resize() in gtkwindow.c, + but this is the most important one.) + + * gtk/gtkwindow.c (gtk_window_move_resize): Don't call + gtk_widget_queue_draw() - size_allocate() handles + that as appropriate. + + * gtk/gtkframe.c (gtk_frame_size_allocate): Invalidate instead + of queue_clear() to avoid invalidating children. + 2001-11-04 jacob berkman * gtk/gtkmain.c (find_module): don't free the module name until diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index ec47b7bbb4..620483d825 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,47 @@ +Sun Nov 4 16:02:08 2001 Owen Taylor + + * gdk/gdkwindow.[ch]: Add a function gdk_window_invalidate_maybe_recurse() + for use in "shallow invalidation" of a widget. (Windows belonging + to the widget, but not to the widget's children) + + * gtk/gtkprivate.h gtk/gtkwidget.c gtk/gtksizegroup.c: Add private + flags GTK_ALLOC_NEEDED, GTK_REQUEST_NEEDED. These flags are set + up on ancestors up to the resize container on queue_resize. Size + requests only actually take place if GTK_REQUEST_NEEDED, size + allocations only take place if GTK_ALLOC_NEEDED or the size + changed. + + * gtk/gtkcontainer.c gtk/gtkwidget.c: Remove + container->resize_widgets and the RESIZE_NEEDED flag since the + above flags are sufficient to figure out what needs to be + resized/reallocated. Remove code manipulating + container->resize_widget. + + * gtk/gtkwidget.[ch]: Add gtk_widget_set_redraw_on_alloc(); this + allows widgets to turn off being automatically invalidated is when + they are resized. + + * gtk/gtkwidget.[ch] (gtk_widget_size_allocate): Invalidation when + a widget is resized or moved is "shallow" as described above - + only the windows that need to be invalidated are invalidated. + + * gtk/gtkbox.c gtk/gtktable.c gtk/gtkalignment.c docs/Changes-2.0.txt: + Make these widget's init functions call + gtk_widget_set_redraw_on_allocate(widget,FALSE). + + * gtk/gtkwindow.c (gtk_window_configure_event): Call + _gtk_container_queue_resize(), since we don't want + redrawing. (Probably could be done for other + calls to gtk_widget_queue_resize() in gtkwindow.c, + but this is the most important one.) + + * gtk/gtkwindow.c (gtk_window_move_resize): Don't call + gtk_widget_queue_draw() - size_allocate() handles + that as appropriate. + + * gtk/gtkframe.c (gtk_frame_size_allocate): Invalidate instead + of queue_clear() to avoid invalidating children. + 2001-11-04 jacob berkman * gtk/gtkmain.c (find_module): don't free the module name until diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index ec47b7bbb4..620483d825 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,47 @@ +Sun Nov 4 16:02:08 2001 Owen Taylor + + * gdk/gdkwindow.[ch]: Add a function gdk_window_invalidate_maybe_recurse() + for use in "shallow invalidation" of a widget. (Windows belonging + to the widget, but not to the widget's children) + + * gtk/gtkprivate.h gtk/gtkwidget.c gtk/gtksizegroup.c: Add private + flags GTK_ALLOC_NEEDED, GTK_REQUEST_NEEDED. These flags are set + up on ancestors up to the resize container on queue_resize. Size + requests only actually take place if GTK_REQUEST_NEEDED, size + allocations only take place if GTK_ALLOC_NEEDED or the size + changed. + + * gtk/gtkcontainer.c gtk/gtkwidget.c: Remove + container->resize_widgets and the RESIZE_NEEDED flag since the + above flags are sufficient to figure out what needs to be + resized/reallocated. Remove code manipulating + container->resize_widget. + + * gtk/gtkwidget.[ch]: Add gtk_widget_set_redraw_on_alloc(); this + allows widgets to turn off being automatically invalidated is when + they are resized. + + * gtk/gtkwidget.[ch] (gtk_widget_size_allocate): Invalidation when + a widget is resized or moved is "shallow" as described above - + only the windows that need to be invalidated are invalidated. + + * gtk/gtkbox.c gtk/gtktable.c gtk/gtkalignment.c docs/Changes-2.0.txt: + Make these widget's init functions call + gtk_widget_set_redraw_on_allocate(widget,FALSE). + + * gtk/gtkwindow.c (gtk_window_configure_event): Call + _gtk_container_queue_resize(), since we don't want + redrawing. (Probably could be done for other + calls to gtk_widget_queue_resize() in gtkwindow.c, + but this is the most important one.) + + * gtk/gtkwindow.c (gtk_window_move_resize): Don't call + gtk_widget_queue_draw() - size_allocate() handles + that as appropriate. + + * gtk/gtkframe.c (gtk_frame_size_allocate): Invalidate instead + of queue_clear() to avoid invalidating children. + 2001-11-04 jacob berkman * gtk/gtkmain.c (find_module): don't free the module name until diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index ec47b7bbb4..620483d825 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,47 @@ +Sun Nov 4 16:02:08 2001 Owen Taylor + + * gdk/gdkwindow.[ch]: Add a function gdk_window_invalidate_maybe_recurse() + for use in "shallow invalidation" of a widget. (Windows belonging + to the widget, but not to the widget's children) + + * gtk/gtkprivate.h gtk/gtkwidget.c gtk/gtksizegroup.c: Add private + flags GTK_ALLOC_NEEDED, GTK_REQUEST_NEEDED. These flags are set + up on ancestors up to the resize container on queue_resize. Size + requests only actually take place if GTK_REQUEST_NEEDED, size + allocations only take place if GTK_ALLOC_NEEDED or the size + changed. + + * gtk/gtkcontainer.c gtk/gtkwidget.c: Remove + container->resize_widgets and the RESIZE_NEEDED flag since the + above flags are sufficient to figure out what needs to be + resized/reallocated. Remove code manipulating + container->resize_widget. + + * gtk/gtkwidget.[ch]: Add gtk_widget_set_redraw_on_alloc(); this + allows widgets to turn off being automatically invalidated is when + they are resized. + + * gtk/gtkwidget.[ch] (gtk_widget_size_allocate): Invalidation when + a widget is resized or moved is "shallow" as described above - + only the windows that need to be invalidated are invalidated. + + * gtk/gtkbox.c gtk/gtktable.c gtk/gtkalignment.c docs/Changes-2.0.txt: + Make these widget's init functions call + gtk_widget_set_redraw_on_allocate(widget,FALSE). + + * gtk/gtkwindow.c (gtk_window_configure_event): Call + _gtk_container_queue_resize(), since we don't want + redrawing. (Probably could be done for other + calls to gtk_widget_queue_resize() in gtkwindow.c, + but this is the most important one.) + + * gtk/gtkwindow.c (gtk_window_move_resize): Don't call + gtk_widget_queue_draw() - size_allocate() handles + that as appropriate. + + * gtk/gtkframe.c (gtk_frame_size_allocate): Invalidate instead + of queue_clear() to avoid invalidating children. + 2001-11-04 jacob berkman * gtk/gtkmain.c (find_module): don't free the module name until diff --git a/docs/Changes-2.0.txt b/docs/Changes-2.0.txt index efe9dc5e8c..a5953d5235 100644 --- a/docs/Changes-2.0.txt +++ b/docs/Changes-2.0.txt @@ -508,3 +508,9 @@ Incompatible Changes from GTK+-1.2 to GTK+-2.0: are deprecated, as GdkRgb works on any colormap and visual. You no longer need to gtk_widget_push_cmap (gtk_preview_get_cmap ()) in your code. + +* The GtkBox, GtkTable, and GtkAlignment widgets now call + gtk_widget_set_redraw_on_allocate (widget, FALSE); on themselves. + If you want to actually draw contents in a widget derived from + one of these widgets, you'll probably want to change this + in your init() function. diff --git a/docs/reference/gtk/tmpl/gtkimcontext.sgml b/docs/reference/gtk/tmpl/gtkimcontext.sgml index 74f19bb38f..36a2a28073 100644 --- a/docs/reference/gtk/tmpl/gtkimcontext.sgml +++ b/docs/reference/gtk/tmpl/gtkimcontext.sgml @@ -100,6 +100,16 @@ GtkIMContext @imcontext: the object which received the signal. @arg1: + + + + + +@imcontext: the object which received the signal. +@arg1: +@arg2: +@Returns: + @@ -121,3 +131,11 @@ GtkIMContext @imcontext: the object which received the signal. + + + + + +@imcontext: the object which received the signal. +@Returns: + diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index b8729093d0..e171edc2fa 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -2152,10 +2152,12 @@ gdk_window_invalidate_rect (GdkWindow *window, } /** - * gdk_window_invalidate_region: + * gdk_window_invalidate_maybe_recurse: * @window: a #GdkWindow * @region: a #GdkRegion - * @invalidate_children: %TRUE to also invalidate child windows + * @child_func: function to use to decide if to recurse to a child, + * %NULL means never recurse. + * @child_func_data: data passed to @child_func * * Adds @region to the update area for @window. The update area is the * region that needs to be redrawn, or "dirty region." The call @@ -2169,16 +2171,16 @@ gdk_window_invalidate_rect (GdkWindow *window, * normally there's no need to do that manually, you just need to * invalidate regions that you know should be redrawn. * - * The @invalidate_children parameter controls whether the region of + * The @child_func parameter controls whether the region of * each child window that intersects @region will also be invalidated. - * If %FALSE, then the update area for child windows will remain - * unaffected. - * + * Only children for whic @child_func returns TRUE will have the area + * invalidated. **/ void -gdk_window_invalidate_region (GdkWindow *window, - GdkRegion *region, - gboolean invalidate_children) +gdk_window_invalidate_maybe_recurse (GdkWindow *window, + GdkRegion *region, + gboolean (*child_func) (GdkWindow *, gpointer), + gpointer user_data) { GdkWindowObject *private = (GdkWindowObject *)window; GdkRegion *visible_region; @@ -2233,7 +2235,7 @@ gdk_window_invalidate_region (GdkWindow *window, gdk_window_update_idle, NULL, NULL); } - if (invalidate_children) + if (child_func) { GList *tmp_list; @@ -2242,8 +2244,8 @@ gdk_window_invalidate_region (GdkWindow *window, { GdkWindowObject *child = tmp_list->data; tmp_list = tmp_list->next; - - if (!child->input_only) + + if (!child->input_only && (*child_func) ((GdkWindow *)child, user_data)) { GdkRegion *child_region; gint x, y; @@ -2265,6 +2267,48 @@ gdk_window_invalidate_region (GdkWindow *window, gdk_region_destroy (visible_region); } +static gboolean +true_predicate (GdkWindow *window, + gpointer user_data) +{ + return TRUE; +} + +/** + * gdk_window_invalidate_region: + * @window: a #GdkWindow + * @region: a #GdkRegion + * @invalidate_children: %TRUE to also invalidate child windows + * + * Adds @region to the update area for @window. The update area is the + * region that needs to be redrawn, or "dirty region." The call + * gdk_window_process_updates() sends one or more expose events to the + * window, which together cover the entire update area. An + * application would normally redraw the contents of @window in + * response to those expose events. + * + * GDK will call gdk_window_process_all_updates() on your behalf + * whenever your program returns to the main loop and becomes idle, so + * normally there's no need to do that manually, you just need to + * invalidate regions that you know should be redrawn. + * + * The @invalidate_children parameter controls whether the region of + * each child window that intersects @region will also be invalidated. + * If %FALSE, then the update area for child windows will remain + * unaffected. See gdk_window_invalidate_maybe_recurse if you need + * fine grained control over which children are invalidated. + **/ +void +gdk_window_invalidate_region (GdkWindow *window, + GdkRegion *region, + gboolean invalidate_children) +{ + gdk_window_invalidate_maybe_recurse (window, region, + invalidate_children ? + true_predicate : (gboolean (*) (GdkWindow *, gpointer))NULL, + NULL); +} + /** * gdk_window_get_update_area: * @window: a #GdkWindow diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h index e4d0138fd3..bca2b065d3 100644 --- a/gdk/gdkwindow.h +++ b/gdk/gdkwindow.h @@ -491,12 +491,16 @@ void gdk_window_begin_move_drag (GdkWindow *window, guint32 timestamp); /* Interface for dirty-region queueing */ -void gdk_window_invalidate_rect (GdkWindow *window, - GdkRectangle *rect, - gboolean invalidate_children); -void gdk_window_invalidate_region (GdkWindow *window, - GdkRegion *region, - gboolean invalidate_children); +void gdk_window_invalidate_rect (GdkWindow *window, + GdkRectangle *rect, + gboolean invalidate_children); +void gdk_window_invalidate_region (GdkWindow *window, + GdkRegion *region, + gboolean invalidate_children); +void gdk_window_invalidate_maybe_recurse (GdkWindow *window, + GdkRegion *region, + gboolean (*child_func) (GdkWindow *, gpointer), + gpointer user_data); GdkRegion *gdk_window_get_update_area (GdkWindow *window); void gdk_window_freeze_updates (GdkWindow *window); diff --git a/gtk/gtkalignment.c b/gtk/gtkalignment.c index 5db7589c72..9c33fd3077 100644 --- a/gtk/gtkalignment.c +++ b/gtk/gtkalignment.c @@ -139,6 +139,7 @@ static void gtk_alignment_init (GtkAlignment *alignment) { GTK_WIDGET_SET_FLAGS (alignment, GTK_NO_WINDOW); + gtk_widget_set_redraw_on_allocate (GTK_WIDGET (alignment), FALSE); alignment->xalign = 0.5; alignment->yalign = 0.5; diff --git a/gtk/gtkbox.c b/gtk/gtkbox.c index add75ec91d..4c50b1137f 100644 --- a/gtk/gtkbox.c +++ b/gtk/gtkbox.c @@ -168,7 +168,8 @@ static void gtk_box_init (GtkBox *box) { GTK_WIDGET_SET_FLAGS (box, GTK_NO_WINDOW); - + gtk_widget_set_redraw_on_allocate (GTK_WIDGET (box), FALSE); + box->children = NULL; box->spacing = 0; box->homogeneous = FALSE; diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c index c25802253b..a6b553da28 100644 --- a/gtk/gtkcontainer.c +++ b/gtk/gtkcontainer.c @@ -698,7 +698,6 @@ gtk_container_init (GtkContainer *container) container->need_resize = FALSE; container->resize_mode = GTK_RESIZE_PARENT; container->reallocate_redraws = FALSE; - container->resize_widgets = NULL; } static void @@ -713,8 +712,6 @@ gtk_container_destroy (GtkObject *object) if (GTK_CONTAINER_RESIZE_PENDING (container)) _gtk_container_dequeue_resize_handler (container); - if (container->resize_widgets) - _gtk_container_clear_resize_widgets (container); /* do this before walking child widgets, to avoid * removing children from focus chain one by one. @@ -899,28 +896,6 @@ _gtk_container_dequeue_resize_handler (GtkContainer *container) GTK_PRIVATE_UNSET_FLAG (container, GTK_RESIZE_PENDING); } -void -_gtk_container_clear_resize_widgets (GtkContainer *container) -{ - GSList *node; - - g_return_if_fail (container != NULL); - g_return_if_fail (GTK_IS_CONTAINER (container)); - - node = container->resize_widgets; - - while (node) - { - GtkWidget *widget = node->data; - - GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED); - node = node->next; - } - - g_slist_free (container->resize_widgets); - container->resize_widgets = NULL; -} - void gtk_container_set_resize_mode (GtkContainer *container, GtkResizeMode resize_mode) @@ -940,14 +915,8 @@ gtk_container_set_resize_mode (GtkContainer *container, { container->resize_mode = resize_mode; - if (resize_mode == GTK_RESIZE_IMMEDIATE) - gtk_container_check_resize (container); - else - { - _gtk_container_clear_resize_widgets (container); - gtk_widget_queue_resize (GTK_WIDGET (container)); - } - g_object_notify (G_OBJECT (container), "resize_mode"); + gtk_widget_queue_resize (GTK_WIDGET (container)); + g_object_notify (G_OBJECT (container), "resize_mode"); } } @@ -987,7 +956,7 @@ gtk_container_get_resize_container (GtkContainer *container) while (widget->parent) { widget = widget->parent; - if (GTK_IS_RESIZE_CONTAINER (widget) && !GTK_WIDGET_RESIZE_NEEDED (widget)) + if (GTK_IS_RESIZE_CONTAINER (widget)) break; } @@ -997,32 +966,52 @@ gtk_container_get_resize_container (GtkContainer *container) static gboolean gtk_container_idle_sizer (gpointer data) { + static gboolean initialized = 0; + static GTimeVal last_time; + GTimeVal current_time; + GDK_THREADS_ENTER (); - /* we may be invoked with a container_resize_queue of NULL, because - * queue_resize could have been adding an extra idle function while - * the queue still got processed. we better just ignore such case - * than trying to explicitely work around them with some extra flags, - * since it doesn't cause any actual harm. - */ - while (container_resize_queue) + if (container_resize_queue) { - GSList *slist; - GtkWidget *widget; - - slist = container_resize_queue; - container_resize_queue = slist->next; - widget = slist->data; - g_slist_free_1 (slist); - - GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_PENDING); - gtk_container_check_resize (GTK_CONTAINER (widget)); + /* we may be invoked with a container_resize_queue of NULL, because + * queue_resize could have been adding an extra idle function while + * the queue still got processed. we better just ignore such case + * than trying to explicitely work around them with some extra flags, + * since it doesn't cause any actual harm. + */ + while (container_resize_queue) + { + GSList *slist; + GtkWidget *widget; + + slist = container_resize_queue; + container_resize_queue = slist->next; + widget = slist->data; + g_slist_free_1 (slist); + + GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_PENDING); + gtk_container_check_resize (GTK_CONTAINER (widget)); + } + + gdk_window_process_all_updates (); + + g_get_current_time (¤t_time); + + if (initialized) + { + gdouble diff = ((current_time.tv_usec - last_time.tv_usec) / 1000. + + (current_time.tv_sec - last_time.tv_sec) * 1000.); + /* g_print ("Frame time: %g msec\n", diff); */ + } + else + initialized = TRUE; + + last_time = current_time; + + GDK_THREADS_LEAVE (); } - gdk_window_process_all_updates (); - - GDK_THREADS_LEAVE (); - return FALSE; } @@ -1034,21 +1023,22 @@ _gtk_container_queue_resize (GtkContainer *container) g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_CONTAINER (container)); - /* clear resize widgets for resize containers - * before aborting prematurely. this is especially - * important for toplevels which may need imemdiate - * processing or their resize handler to be queued. - */ - if (GTK_IS_RESIZE_CONTAINER (container)) - _gtk_container_clear_resize_widgets (container); - if (GTK_OBJECT_DESTROYED (container) || - GTK_WIDGET_RESIZE_NEEDED (container)) - return; - resize_container = gtk_container_get_resize_container (container); if (resize_container) { + GtkWidget *widget = GTK_WIDGET (container); + + while (!GTK_WIDGET_ALLOC_NEEDED (widget) || !GTK_WIDGET_REQUEST_NEEDED (widget)) + { + GTK_PRIVATE_SET_FLAG (widget, GTK_ALLOC_NEEDED); + GTK_PRIVATE_SET_FLAG (widget, GTK_REQUEST_NEEDED); + if (widget == GTK_WIDGET (resize_container)) + break; + + widget = widget->parent; + } + if (GTK_WIDGET_VISIBLE (resize_container) && (GTK_WIDGET_TOPLEVEL (resize_container) || GTK_WIDGET_DRAWABLE (resize_container))) { @@ -1064,16 +1054,9 @@ _gtk_container_queue_resize (GtkContainer *container) NULL); container_resize_queue = g_slist_prepend (container_resize_queue, resize_container); } - - GTK_PRIVATE_SET_FLAG (container, GTK_RESIZE_NEEDED); - resize_container->resize_widgets = - g_slist_prepend (resize_container->resize_widgets, container); break; case GTK_RESIZE_IMMEDIATE: - GTK_PRIVATE_SET_FLAG (container, GTK_RESIZE_NEEDED); - resize_container->resize_widgets = - g_slist_prepend (resize_container->resize_widgets, container); gtk_container_check_resize (resize_container); break; @@ -1134,135 +1117,24 @@ gtk_container_real_check_resize (GtkContainer *container) * queued a resize request. Which means that the allocation * is not sufficient for the requisition of some child. * We've already performed a size request at this point, - * so we simply need to run through the list of resize - * widgets and reallocate their sizes appropriately. We - * make the optimization of not performing reallocation - * for a widget who also has a parent in the resize widgets - * list. GTK_RESIZE_NEEDED is used for flagging those - * parents inside this function. + * so we simply need to reallocate and let the allocation + * trickle down via GTK_WIDGET_ALLOC_NEEDED flags. */ void gtk_container_resize_children (GtkContainer *container) { GtkWidget *widget; - GtkWidget *resize_container; - GSList *resize_widgets; - GSList *resize_containers; - GSList *node; /* resizing invariants: * toplevels have *always* resize_mode != GTK_RESIZE_PARENT set. - * containers with resize_mode==GTK_RESIZE_PARENT have to have resize_widgets - * set to NULL. - * containers that are flagged RESIZE_NEEDED must have resize_widgets set to - * NULL, or are toplevels (thus have ->parent set to NULL). - * widgets that are in some container->resize_widgets list must be flagged with - * RESIZE_NEEDED. - * widgets that have RESIZE_NEEDED set must be referenced in some - * GTK_IS_RESIZE_CONTAINER (container)->resize_widgets list. * containers that have an idle sizer pending must be flagged with * RESIZE_PENDING. */ - g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_CONTAINER (container)); - /* we first check out if we actually need to perform a resize, - * which is not the case if we got another container queued for - * a resize in our ancestry. also we can skip the whole - * resize_widgets checks if we are a toplevel and NEED_RESIZE. - * this code assumes that our allocation is sufficient for our - * requisition, since otherwise we would NEED_RESIZE. - */ - resize_container = GTK_WIDGET (container); - while (resize_container) - { - if (GTK_WIDGET_RESIZE_NEEDED (resize_container)) - break; - resize_container = resize_container->parent; - } - if (resize_container) - { - /* queue_resize and size_allocate both clear our - * resize_widgets list. - */ - if (resize_container->parent) - _gtk_container_queue_resize (container); - else - gtk_widget_size_allocate (GTK_WIDGET (container), - >K_WIDGET (container)->allocation); - return; - } - - resize_container = GTK_WIDGET (container); - - /* we now walk the ancestry for all resize widgets as long - * as they are our children and as long as their allocation - * is insufficient, since we don't need to reallocate below that. - */ - resize_widgets = container->resize_widgets; - container->resize_widgets = NULL; - for (node = resize_widgets; node; node = node->next) - { - widget = node->data; - - GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED); - - while (widget->parent != resize_container && - ((widget->allocation.width < widget->requisition.width) || - (widget->allocation.height < widget->requisition.height))) - widget = widget->parent; - - GTK_PRIVATE_SET_FLAG (widget, GTK_RESIZE_NEEDED); - node->data = widget; - } - - /* for the newly setup resize_widgets list, we now walk each widget's - * ancestry to sort those widgets out that have RESIZE_NEEDED parents. - * we can safely stop the walk if we are the parent, since we checked - * our own ancestry already. - */ - resize_containers = NULL; - for (node = resize_widgets; node; node = node->next) - { - GtkWidget *parent; - - widget = node->data; - - if (!GTK_WIDGET_RESIZE_NEEDED (widget)) - continue; - - parent = widget->parent; - - while (parent != resize_container) - { - if (GTK_WIDGET_RESIZE_NEEDED (parent)) - { - GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED); - widget = parent; - } - parent = parent->parent; - } - - if (!g_slist_find (resize_containers, widget)) - { - resize_containers = g_slist_prepend (resize_containers, widget); - gtk_widget_ref (widget); - } - } - g_slist_free (resize_widgets); - - for (node = resize_containers; node; node = node->next) - { - widget = node->data; - - GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED); - - gtk_widget_size_allocate (widget, &widget->allocation); - - gtk_widget_unref (widget); - } - g_slist_free (resize_containers); + widget = GTK_WIDGET (container); + gtk_widget_size_allocate (widget, &widget->allocation); } /** @@ -1630,8 +1502,6 @@ get_allocation_coords (GtkContainer *container, GtkWidget *widget, GdkRectangle *allocation) { - GtkWidget *toplevel = gtk_widget_get_toplevel (widget); - *allocation = widget->allocation; return gtk_widget_translate_coordinates (widget, GTK_WIDGET (container), diff --git a/gtk/gtkcontainer.h b/gtk/gtkcontainer.h index 98f7be851d..ae8095aee2 100644 --- a/gtk/gtkcontainer.h +++ b/gtk/gtkcontainer.h @@ -63,10 +63,6 @@ struct _GtkContainer guint resize_mode : 2; guint reallocate_redraws : 1; guint has_focus_chain : 1; - - /* The list of children that requested a resize - */ - GSList *resize_widgets; }; struct _GtkContainerClass diff --git a/gtk/gtkframe.c b/gtk/gtkframe.c index 7efc069a52..95287ae2dd 100644 --- a/gtk/gtkframe.c +++ b/gtk/gtkframe.c @@ -613,7 +613,7 @@ gtk_frame_size_allocate (GtkWidget *widget, new_allocation.y != frame->child_allocation.y || new_allocation.width != frame->child_allocation.width || new_allocation.height != frame->child_allocation.height)) - gtk_widget_queue_clear (widget); + gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE); if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) gtk_widget_size_allocate (bin->child, &new_allocation); diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h index 0de6707cf7..86935ee1bb 100644 --- a/gtk/gtkprivate.h +++ b/gtk/gtkprivate.h @@ -43,14 +43,16 @@ typedef enum { PRIVATE_GTK_USER_STYLE = 1 << 0, PRIVATE_GTK_RESIZE_PENDING = 1 << 2, - PRIVATE_GTK_RESIZE_NEEDED = 1 << 3, PRIVATE_GTK_LEAVE_PENDING = 1 << 4, PRIVATE_GTK_HAS_SHAPE_MASK = 1 << 5, PRIVATE_GTK_IN_REPARENT = 1 << 6, PRIVATE_GTK_DIRECTION_SET = 1 << 7, /* If the reading direction is not DIR_NONE */ PRIVATE_GTK_DIRECTION_LTR = 1 << 8, /* If the reading direction is DIR_LTR */ PRIVATE_GTK_ANCHORED = 1 << 9, /* If widget has a GtkWindow ancestor */ - PRIVATE_GTK_CHILD_VISIBLE = 1 << 10 /* If widget should be mapped when parent is mapped */ + PRIVATE_GTK_CHILD_VISIBLE = 1 << 10, /* If widget should be mapped when parent is mapped */ + PRIVATE_GTK_REDRAW_ON_ALLOC = 1 << 11, /* If we should queue a draw on the entire widget when it is reallocated */ + PRIVATE_GTK_ALLOC_NEEDED = 1 << 12, /* If we we should allocate even if the allocation is the same */ + PRIVATE_GTK_REQUEST_NEEDED = 1 << 13 /* Whether we need to call gtk_widget_size_request */ } GtkPrivateFlags; /* Macros for extracting a widgets private_flags from GtkWidget. @@ -58,7 +60,6 @@ typedef enum #define GTK_PRIVATE_FLAGS(wid) (GTK_WIDGET (wid)->private_flags) #define GTK_WIDGET_USER_STYLE(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_USER_STYLE) != 0) #define GTK_CONTAINER_RESIZE_PENDING(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_RESIZE_PENDING) != 0) -#define GTK_WIDGET_RESIZE_NEEDED(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_RESIZE_NEEDED) != 0) #define GTK_WIDGET_LEAVE_PENDING(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_LEAVE_PENDING) != 0) #define GTK_WIDGET_HAS_SHAPE_MASK(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_HAS_SHAPE_MASK) != 0) #define GTK_WIDGET_IN_REPARENT(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_IN_REPARENT) != 0) @@ -66,6 +67,9 @@ typedef enum #define GTK_WIDGET_DIRECTION_LTR(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_DIRECTION_LTR) != 0) #define GTK_WIDGET_ANCHORED(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_ANCHORED) != 0) #define GTK_WIDGET_CHILD_VISIBLE(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_CHILD_VISIBLE) != 0) +#define GTK_WIDGET_REDRAW_ON_ALLOC(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_REDRAW_ON_ALLOC) != 0) +#define GTK_WIDGET_ALLOC_NEEDED(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_ALLOC_NEEDED) != 0) +#define GTK_WIDGET_REQUEST_NEEDED(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_REQUEST_NEEDED) != 0) /* Macros for setting and clearing private widget flags. * we use a preprocessor string concatenation here for a clear diff --git a/gtk/gtksizegroup.c b/gtk/gtksizegroup.c index 3116183ae4..2ceca3c4d8 100644 --- a/gtk/gtksizegroup.c +++ b/gtk/gtksizegroup.c @@ -20,6 +20,7 @@ #include "gtkcontainer.h" #include "gtkintl.h" +#include "gtkprivate.h" #include "gtksignal.h" #include "gtksizegroup.h" @@ -116,8 +117,8 @@ add_widget_to_closure (GtkWidget *widget, static void real_queue_resize (GtkWidget *widget) { - if (GTK_IS_RESIZE_CONTAINER (widget)) - _gtk_container_clear_resize_widgets (GTK_CONTAINER (widget)); + GTK_PRIVATE_SET_FLAG (widget, GTK_ALLOC_NEEDED); + GTK_PRIVATE_SET_FLAG (widget, GTK_REQUEST_NEEDED); if (widget->parent) _gtk_container_queue_resize (GTK_CONTAINER (widget->parent)); @@ -476,12 +477,23 @@ get_base_dimension (GtkWidget *widget, } } +static void +do_size_request (GtkWidget *widget) +{ + if (GTK_WIDGET_REQUEST_NEEDED (widget)) + { + gtk_widget_ensure_style (widget); + gtk_signal_emit_by_name (GTK_OBJECT (widget), "size_request", &widget->requisition); + + GTK_PRIVATE_UNSET_FLAG (widget, GTK_REQUEST_NEEDED); + } +} + static gint compute_base_dimension (GtkWidget *widget, GtkSizeGroupMode mode) { - gtk_widget_ensure_style (widget); - gtk_signal_emit_by_name (GTK_OBJECT (widget), "size_request", &widget->requisition); + do_size_request (widget); return get_base_dimension (widget, mode); } @@ -658,9 +670,8 @@ _gtk_size_group_compute_requisition (GtkWidget *widget, } else { - gtk_widget_ensure_style (widget); - gtk_signal_emit_by_name (GTK_OBJECT (widget), "size_request", &widget->requisition); - + do_size_request (widget); + if (requisition) get_fast_child_requisition (widget, requisition); } diff --git a/gtk/gtktable.c b/gtk/gtktable.c index 86b8edb90c..18c697f550 100644 --- a/gtk/gtktable.c +++ b/gtk/gtktable.c @@ -452,6 +452,7 @@ static void gtk_table_init (GtkTable *table) { GTK_WIDGET_SET_FLAGS (table, GTK_NO_WINDOW); + gtk_widget_set_redraw_on_allocate (GTK_WIDGET (table), FALSE); table->children = NULL; table->rows = NULL; diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 20da6016c2..6ee796b394 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -213,6 +213,9 @@ static void gtk_widget_aux_info_destroy (GtkWidgetAuxInfo *aux_info); static AtkObject* gtk_widget_real_get_accessible (GtkWidget *widget); static void gtk_widget_accessible_interface_init (AtkImplementorIface *iface); static AtkObject* gtk_widget_ref_accessible (AtkImplementor *implementor); +static void gtk_widget_invalidate_widget_windows (GtkWidget *widget, + GdkRegion *region); + /* --- variables --- */ static gpointer parent_class = NULL; @@ -1248,6 +1251,8 @@ gtk_widget_init (GtkWidget *widget) (composite_child_stack ? GTK_COMPOSITE_CHILD : 0) | GTK_DOUBLE_BUFFERED); + GTK_PRIVATE_SET_FLAG (widget, GTK_REDRAW_ON_ALLOC); + widget->style = gtk_widget_get_default_style (); g_object_ref (widget->style); } @@ -1412,7 +1417,6 @@ gtk_widget_unparent (GtkWidget *widget) { GObjectNotifyQueue *nqueue; GtkWidget *toplevel; - GtkWidget *ancestor; GtkWidget *old_parent; g_return_if_fail (GTK_IS_WIDGET (widget)); @@ -1469,64 +1473,6 @@ gtk_widget_unparent (GtkWidget *widget) else toplevel = NULL; - if (GTK_IS_RESIZE_CONTAINER (widget)) - _gtk_container_clear_resize_widgets (GTK_CONTAINER (widget)); - - /* Remove the widget and all its children from any ->resize_widgets list - * of all the parents in our branch. This code should move into gtkcontainer.c - * somwhen, since we mess around with ->resize_widgets, which is - * actually not of our business. - * - * Two ways to make this prettier: - * Write a g_slist_conditional_remove (GSList, gboolean (*)(gpointer)) - * Change resize_widgets to a GList - */ - ancestor = widget->parent; - while (ancestor) - { - GSList *slist; - GSList *prev; - - if (!GTK_CONTAINER (ancestor)->resize_widgets) - { - ancestor = ancestor->parent; - continue; - } - - prev = NULL; - slist = GTK_CONTAINER (ancestor)->resize_widgets; - while (slist) - { - GtkWidget *child; - GtkWidget *parent; - GSList *last; - - last = slist; - slist = last->next; - child = last->data; - - parent = child; - while (parent && (parent != widget)) - parent = parent->parent; - - if (parent == widget) - { - GTK_PRIVATE_UNSET_FLAG (child, GTK_RESIZE_NEEDED); - - if (prev) - prev->next = slist; - else - GTK_CONTAINER (ancestor)->resize_widgets = slist; - - g_slist_free_1 (last); - } - else - prev = last; - } - - ancestor = ancestor->parent; - } - gtk_widget_queue_clear_child (widget); /* Reset the width and height here, to force reallocation if we @@ -1831,7 +1777,7 @@ gtk_widget_map (GtkWidget *widget) gtk_signal_emit (GTK_OBJECT (widget), widget_signals[MAP]); if (GTK_WIDGET_NO_WINDOW (widget)) - gtk_widget_queue_draw (widget); + gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE); } } @@ -1851,7 +1797,7 @@ gtk_widget_unmap (GtkWidget *widget) if (GTK_WIDGET_MAPPED (widget)) { if (GTK_WIDGET_NO_WINDOW (widget)) - gtk_widget_queue_clear_child (widget); + gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE); gtk_signal_emit (GTK_OBJECT (widget), widget_signals[UNMAP]); } } @@ -2135,10 +2081,17 @@ gtk_widget_queue_clear (GtkWidget *widget) void gtk_widget_queue_resize (GtkWidget *widget) { + GdkRegion *region; + g_return_if_fail (GTK_IS_WIDGET (widget)); - gtk_widget_queue_clear (widget); - + if (GTK_WIDGET_REALIZED (widget)) + { + region = gdk_region_rectangle (&widget->allocation); + gtk_widget_invalidate_widget_windows (widget, region); + gdk_region_destroy (region); + } + _gtk_size_group_queue_resize (widget); } @@ -2208,13 +2161,6 @@ gtk_widget_size_request (GtkWidget *widget, #endif /* G_ENABLE_DEBUG */ _gtk_size_group_compute_requisition (widget, requisition); - -#if 0 - if (requisition) - gtk_widget_get_child_requisition (widget, requisition); - - gtk_widget_unref (widget); -#endif } /** @@ -2247,6 +2193,38 @@ gtk_widget_get_child_requisition (GtkWidget *widget, _gtk_size_group_get_child_requisition (widget, requisition); } +static gboolean +invalidate_predicate (GdkWindow *window, + gpointer data) +{ + gpointer user_data; + + gdk_window_get_user_data (window, &user_data); + + return (user_data == data); +} + +/* Invalidate @region in widget->window and all children + * of widget->window owned by widget. @region is in the + * same coordinates as widget->allocation and will be + * modified by this call. + */ +static void +gtk_widget_invalidate_widget_windows (GtkWidget *widget, + GdkRegion *region) +{ + if (!GTK_WIDGET_NO_WINDOW (widget)) + { + int x, y; + + gdk_window_get_position (widget->window, &x, &y); + gdk_region_offset (region, -x, -y); + } + + gdk_window_invalidate_maybe_recurse (widget->window, region, + invalidate_predicate, widget); +} + /** * gtk_widget_size_allocate: * @widget: a #GtkWidget @@ -2261,11 +2239,18 @@ gtk_widget_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { GtkWidgetAuxInfo *aux_info; - GtkAllocation real_allocation; - gboolean needs_draw = FALSE; + GdkRectangle real_allocation; + GdkRectangle old_allocation; + gboolean alloc_needed; + gboolean size_changed; + gboolean position_changed; g_return_if_fail (GTK_IS_WIDGET (widget)); - + + alloc_needed = GTK_WIDGET_ALLOC_NEEDED (widget); + GTK_PRIVATE_UNSET_FLAG (widget, GTK_ALLOC_NEEDED); + + old_allocation = widget->allocation; real_allocation = *allocation; aux_info =_gtk_widget_get_aux_info (widget, FALSE); @@ -2287,33 +2272,50 @@ gtk_widget_size_allocate (GtkWidget *widget, real_allocation.width = MAX (real_allocation.width, 1); real_allocation.height = MAX (real_allocation.height, 1); - if (GTK_WIDGET_NO_WINDOW (widget)) - { - if (widget->allocation.x != real_allocation.x || - widget->allocation.y != real_allocation.y || - widget->allocation.width != real_allocation.width || - widget->allocation.height != real_allocation.height) - { - gtk_widget_queue_clear_child (widget); - needs_draw = TRUE; - } - } - else if (widget->allocation.width != real_allocation.width || - widget->allocation.height != real_allocation.height) - { - needs_draw = TRUE; - } - - if (GTK_IS_RESIZE_CONTAINER (widget)) - _gtk_container_clear_resize_widgets (GTK_CONTAINER (widget)); + size_changed = (old_allocation.width != real_allocation.width || + old_allocation.height != real_allocation.height); + position_changed = (old_allocation.x != real_allocation.x || + old_allocation.y != real_allocation.y); + if (!alloc_needed && !size_changed && !position_changed) + return; + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[SIZE_ALLOCATE], &real_allocation); - if (needs_draw) + if (GTK_WIDGET_MAPPED (widget)) { - gtk_widget_queue_draw (widget); - if (widget->parent && GTK_CONTAINER (widget->parent)->reallocate_redraws) - gtk_widget_queue_draw (widget->parent); + if (GTK_WIDGET_NO_WINDOW (widget) && GTK_WIDGET_REDRAW_ON_ALLOC (widget) && position_changed) + { + /* Invalidate union(old_allaction,widget->allocation) in widget->window + */ + GdkRegion *invalidate = gdk_region_rectangle (&widget->allocation); + gdk_region_union_with_rect (invalidate, &old_allocation); + + gdk_window_invalidate_region (widget->window, invalidate, FALSE); + gdk_region_destroy (invalidate); + } + + if (size_changed) + { + if (GTK_WIDGET_REDRAW_ON_ALLOC (widget)) + { + /* Invalidate union(old_allaction,widget->allocation) in widget->window and descendents owned by widget + */ + 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); + } + } + } + + if ((size_changed || position_changed) && widget->parent && + GTK_WIDGET_REALIZED (widget->parent) && GTK_CONTAINER (widget->parent)->reallocate_redraws) + { + GdkRegion *invalidate = gdk_region_rectangle (&widget->parent->allocation); + gtk_widget_invalidate_widget_windows (widget->parent, invalidate); + gdk_region_destroy (invalidate); } } @@ -3455,6 +3457,40 @@ gtk_widget_set_double_buffered (GtkWidget *widget, GTK_WIDGET_UNSET_FLAGS (widget, GTK_DOUBLE_BUFFERED); } +/** + * gtk_widget_set_redraw_on_allocate: + * @widget: a #GtkWidget + * @redraw_on_allocate: if %TRUE, the entire widget will be redrawn + * when it is allocated to a new size. Otherwise, only the + * new portion of the widget will be redrawn. + * + * Sets whether a when a widgets size allocation changes, the entire + * widget is queued for drawing. By default, this setting is %TRUE and + * the entire widget is redrawn on every size change. If your widget + * leaves the upper left are unchanged when made bigger, turning this + * setting on will improve performance. + + * Note that for NO_WINDOW widgets setting this flag to %FALSE turns + * off all allocation on resizing: the widget will not even redraw if + * its position changes; this is to allow containers that don't draw + * anything to avoid excess invalidations. If you set this flag on a + * NO_WINDOW widget that _does_ draw on widget->window, you are + * responsible for invalidating both the old and new allocation of the + * widget when the widget is moved and responsible for invalidating + * regions newly when the widget increases size. + **/ +void +gtk_widget_set_redraw_on_allocate (GtkWidget *widget, + gboolean redraw_on_allocate) +{ + g_return_if_fail (GTK_IS_WIDGET (widget)); + + if (redraw_on_allocate) + GTK_PRIVATE_SET_FLAG (widget, GTK_REDRAW_ON_ALLOC); + else + GTK_PRIVATE_UNSET_FLAG (widget, GTK_REDRAW_ON_ALLOC); +} + /** * gtk_widget_set_sensitive: * @widget: a @widget diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h index 111c779268..3d9969a249 100644 --- a/gtk/gtkwidget.h +++ b/gtk/gtkwidget.h @@ -539,25 +539,27 @@ gboolean gtk_widget_is_focus (GtkWidget *widget); void gtk_widget_grab_focus (GtkWidget *widget); void gtk_widget_grab_default (GtkWidget *widget); -void gtk_widget_set_name (GtkWidget *widget, - const gchar *name); -G_CONST_RETURN gchar* gtk_widget_get_name (GtkWidget *widget); -void gtk_widget_set_state (GtkWidget *widget, - GtkStateType state); -void gtk_widget_set_sensitive (GtkWidget *widget, - gboolean sensitive); -void gtk_widget_set_app_paintable (GtkWidget *widget, - gboolean app_paintable); -void gtk_widget_set_double_buffered (GtkWidget *widget, - gboolean double_buffered); -void gtk_widget_set_parent (GtkWidget *widget, - GtkWidget *parent); -void gtk_widget_set_parent_window (GtkWidget *widget, - GdkWindow *parent_window); -void gtk_widget_set_child_visible (GtkWidget *widget, - gboolean is_visible); -gboolean gtk_widget_get_child_visible (GtkWidget *widget); - +void gtk_widget_set_name (GtkWidget *widget, + const gchar *name); +G_CONST_RETURN gchar* gtk_widget_get_name (GtkWidget *widget); +void gtk_widget_set_state (GtkWidget *widget, + GtkStateType state); +void gtk_widget_set_sensitive (GtkWidget *widget, + gboolean sensitive); +void gtk_widget_set_app_paintable (GtkWidget *widget, + gboolean app_paintable); +void gtk_widget_set_double_buffered (GtkWidget *widget, + gboolean double_buffered); +void gtk_widget_set_redraw_on_allocate (GtkWidget *widget, + gboolean redraw_on_allocate); +void gtk_widget_set_parent (GtkWidget *widget, + GtkWidget *parent); +void gtk_widget_set_parent_window (GtkWidget *widget, + GdkWindow *parent_window); +void gtk_widget_set_child_visible (GtkWidget *widget, + gboolean is_visible); +gboolean gtk_widget_get_child_visible (GtkWidget *widget); + GtkWidget *gtk_widget_get_parent (GtkWidget *widget); GdkWindow *gtk_widget_get_parent_window (GtkWidget *widget); gboolean gtk_widget_child_focus (GtkWidget *widget, diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 6bedb3aabe..412a57f891 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -3366,7 +3366,7 @@ gtk_window_configure_event (GtkWidget *widget, widget->allocation.width = event->width; widget->allocation.height = event->height; - gtk_widget_queue_resize (widget); + _gtk_container_queue_resize (GTK_CONTAINER (widget)); return TRUE; } @@ -4144,7 +4144,6 @@ gtk_window_move_resize (GtkWindow *window) /* gtk_window_configure_event() filled in widget->allocation */ allocation = widget->allocation; gtk_widget_size_allocate (widget, &allocation); - gtk_widget_queue_draw (widget); /* If the configure request changed, it means that * we either: @@ -4284,8 +4283,7 @@ gtk_window_move_resize (GtkWindow *window) /* And run the resize queue. */ - if (container->resize_widgets) - gtk_container_resize_children (container); + gtk_container_resize_children (container); } }