X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkcontainer.c;h=ce16fe4df42e224471754b0886415b08b200e474;hb=HEAD;hp=962afdeb9d1ee7e05f8dcf343df79fea14db4668;hpb=97dc45f8a503819ad833b6ea35fdafc58fc02bae;p=~andy%2Fgtk diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c index 962afdeb9..ce16fe4df 100644 --- a/gtk/gtkcontainer.c +++ b/gtk/gtkcontainer.c @@ -42,6 +42,7 @@ #include "gtkmain.h" #include "gtkmarshalers.h" #include "gtksizerequest.h" +#include "gtksizerequestcacheprivate.h" #include "gtkwidgetprivate.h" #include "gtkwindow.h" #include "gtkassistant.h" @@ -235,10 +236,15 @@ struct _GtkContainerPrivate { GtkWidget *focus_child; + guint resize_handler; + GdkFrameClock *resize_clock; + guint border_width : 16; guint has_focus_chain : 1; guint reallocate_redraws : 1; + guint resize_pending : 1; + guint restyle_pending : 1; guint resize_mode : 2; guint request_mode : 2; }; @@ -341,7 +347,6 @@ static const gchar vadjustment_key[] = "gtk-vadjustment"; static guint vadjustment_key_id = 0; static const gchar hadjustment_key[] = "gtk-hadjustment"; static guint hadjustment_key_id = 0; -static GSList *container_resize_queue = NULL; static guint container_signals[LAST_SIGNAL] = { 0 }; static GtkWidgetClass *parent_class = NULL; extern GParamSpecPool *_gtk_widget_child_property_pool; @@ -1351,9 +1356,12 @@ gtk_container_destroy (GtkWidget *widget) GtkContainer *container = GTK_CONTAINER (widget); GtkContainerPrivate *priv = container->priv; - if (_gtk_widget_get_resize_pending (GTK_WIDGET (container))) + if (priv->resize_pending) _gtk_container_dequeue_resize_handler (container); + if (priv->restyle_pending) + priv->restyle_pending = FALSE; + if (priv->focus_child) { g_object_unref (priv->focus_child); @@ -1542,10 +1550,9 @@ void _gtk_container_dequeue_resize_handler (GtkContainer *container) { g_return_if_fail (GTK_IS_CONTAINER (container)); - g_return_if_fail (_gtk_widget_get_resize_pending (GTK_WIDGET (container))); + g_return_if_fail (container->priv->resize_pending); - container_resize_queue = g_slist_remove (container_resize_queue, container); - _gtk_widget_set_resize_pending (GTK_WIDGET (container), FALSE); + container->priv->resize_pending = FALSE; } /** @@ -1621,11 +1628,36 @@ gtk_container_set_reallocate_redraws (GtkContainer *container, container->priv->reallocate_redraws = needs_redraws ? TRUE : FALSE; } -static gboolean -gtk_container_idle_sizer (gpointer data) +static void +gtk_container_idle_sizer (GdkFrameClock *clock, + GtkContainer *container) { - GSList *slist; - gint64 current_time; + /* We validate the style contexts in a single loop before even trying + * to handle resizes instead of doing validations inline. + * This is mostly necessary for compatibility reasons with old code, + * because both style_updated and size_allocate functions often change + * styles and so could cause infinite loops in this function. + * + * It's important to note that even an invalid style context returns + * sane values. So the result of an invalid style context will never be + * a program crash, but only a wrong layout or rendering. + */ + if (container->priv->restyle_pending) + { + GtkBitmask *empty; + gint64 current_time; + + empty = _gtk_bitmask_new (); + current_time = g_get_monotonic_time (); + + container->priv->restyle_pending = FALSE; + _gtk_style_context_validate (gtk_widget_get_style_context (GTK_WIDGET (container)), + current_time, + 0, + empty); + + _gtk_bitmask_free (empty); + } /* we may be invoked with a container_resize_queue of NULL, because * queue_resize could have been adding an extra idle function while @@ -1633,41 +1665,56 @@ gtk_container_idle_sizer (gpointer data) * than trying to explicitely work around them with some extra flags, * since it doesn't cause any actual harm. */ - - /* We validate the style contexts in a single loop before even trying - * to handle resizes instead of doing validations inline. - * This is mostly necessary for compatibility reasons with old code, - * because size_allocate functions often change styles and so could - * cause infinite loops in this function. - */ - current_time = g_get_monotonic_time (); - for (slist = container_resize_queue; slist; slist = slist->next) + if (container->priv->resize_pending) { - _gtk_style_context_validate (gtk_widget_get_style_context (slist->data), - current_time, - 0); + container->priv->resize_pending = FALSE; + gtk_container_check_resize (container); } - while (container_resize_queue) + if (!container->priv->restyle_pending && !container->priv->resize_pending) + { + _gtk_container_stop_idle_sizer (container); + } + else { - GtkWidget *widget; + gdk_frame_clock_request_phase (clock, + GDK_FRAME_CLOCK_PHASE_LAYOUT); + } +} - slist = container_resize_queue; - container_resize_queue = slist->next; - widget = slist->data; - g_slist_free_1 (slist); +static void +gtk_container_start_idle_sizer (GtkContainer *container) +{ + GdkFrameClock *clock; - _gtk_widget_set_resize_pending (widget, FALSE); - gtk_container_check_resize (GTK_CONTAINER (widget)); - } + if (container->priv->resize_handler != 0) + return; - gdk_window_process_all_updates (); + clock = gtk_widget_get_frame_clock (GTK_WIDGET (container)); + if (clock == NULL) + return; - return FALSE; + container->priv->resize_clock = clock; + container->priv->resize_handler = g_signal_connect (clock, "layout", + G_CALLBACK (gtk_container_idle_sizer), container); + gdk_frame_clock_request_phase (clock, + GDK_FRAME_CLOCK_PHASE_LAYOUT); } void -_gtk_container_queue_resize_handler (GtkContainer *container) +_gtk_container_stop_idle_sizer (GtkContainer *container) +{ + if (container->priv->resize_handler == 0) + return; + + g_signal_handler_disconnect (container->priv->resize_clock, + container->priv->resize_handler); + container->priv->resize_handler = 0; + container->priv->resize_clock = NULL; +} + +static void +gtk_container_queue_resize_handler (GtkContainer *container) { GtkWidget *widget; @@ -1682,22 +1729,16 @@ _gtk_container_queue_resize_handler (GtkContainer *container) switch (container->priv->resize_mode) { case GTK_RESIZE_QUEUE: - if (!_gtk_widget_get_resize_pending (widget)) + if (!container->priv->resize_pending) { - _gtk_widget_set_resize_pending (widget, TRUE); - if (container_resize_queue == NULL) - gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE, - gtk_container_idle_sizer, - NULL, NULL); - container_resize_queue = g_slist_prepend (container_resize_queue, container); + container->priv->resize_pending = TRUE; + gtk_container_start_idle_sizer (container); } break; case GTK_RESIZE_IMMEDIATE: - _gtk_style_context_validate (gtk_widget_get_style_context (widget), - g_get_monotonic_time (), - 0); gtk_container_check_resize (container); + break; case GTK_RESIZE_PARENT: default: @@ -1720,8 +1761,7 @@ _gtk_container_queue_resize_internal (GtkContainer *container, do { _gtk_widget_set_alloc_needed (widget, TRUE); - _gtk_widget_set_width_request_needed (widget, TRUE); - _gtk_widget_set_height_request_needed (widget, TRUE); + _gtk_size_request_cache_clear (_gtk_widget_peek_request_cache (widget)); if (GTK_IS_RESIZE_CONTAINER (widget)) break; @@ -1731,7 +1771,23 @@ _gtk_container_queue_resize_internal (GtkContainer *container, while (widget); if (widget && !invalidate_only) - _gtk_container_queue_resize_handler (GTK_CONTAINER (widget)); + gtk_container_queue_resize_handler (GTK_CONTAINER (widget)); +} + +void +_gtk_container_queue_restyle (GtkContainer *container) +{ + GtkContainerPrivate *priv; + + g_return_if_fail (GTK_CONTAINER (container)); + + priv = container->priv; + + if (priv->restyle_pending) + return; + + gtk_container_start_idle_sizer (container); + priv->restyle_pending = TRUE; } /** @@ -1764,6 +1820,13 @@ _gtk_container_resize_invalidate (GtkContainer *container) _gtk_container_queue_resize_internal (container, TRUE); } +void +_gtk_container_maybe_start_idle_sizer (GtkContainer *container) +{ + if (container->priv->restyle_pending || container->priv->resize_pending) + gtk_container_start_idle_sizer (container); +} + void gtk_container_check_resize (GtkContainer *container) { @@ -1867,32 +1930,11 @@ gtk_container_adjust_size_allocation (GtkWidget *widget, container = GTK_CONTAINER (widget); - if (!GTK_CONTAINER_GET_CLASS (widget)->_handle_border_width) + if (GTK_CONTAINER_GET_CLASS (widget)->_handle_border_width) { - parent_class->adjust_size_allocation (widget, orientation, - minimum_size, natural_size, allocated_pos, - allocated_size); - return; - } - - border_width = container->priv->border_width; - - *allocated_size -= border_width * 2; - - /* If we get a pathological too-small allocation to hold - * even the border width, leave all allocation to the actual - * widget, and leave x,y unchanged. (GtkWidget's min size is - * 1x1 if you're wondering why <1 and not <0) - * - * As long as we have space, set x,y properly. - */ + border_width = container->priv->border_width; - if (*allocated_size < 1) - { - *allocated_size += border_width * 2; - } - else - { + *allocated_size -= border_width * 2; *allocated_pos += border_width; *minimum_size -= border_width * 2; *natural_size -= border_width * 2; @@ -1938,27 +1980,17 @@ count_request_modes (GtkWidget *widget, static GtkSizeRequestMode gtk_container_get_request_mode (GtkWidget *widget) { - GtkContainer *container = GTK_CONTAINER (widget); - GtkContainerPrivate *priv = container->priv; - - /* Recalculate the request mode of the children by majority - * vote whenever the internal content changes */ - if (_gtk_widget_get_width_request_needed (widget) || - _gtk_widget_get_height_request_needed (widget)) - { - RequestModeCount count = { 0, 0 }; - - gtk_container_forall (container, (GtkCallback)count_request_modes, &count); + GtkContainer *container = GTK_CONTAINER (widget); + RequestModeCount count = { 0, 0 }; - if (!count.hfw && !count.wfh) - priv->request_mode = GTK_SIZE_REQUEST_CONSTANT_SIZE; - else - priv->request_mode = count.wfh > count.hfw ? - GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT : - GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH; - } + gtk_container_forall (container, (GtkCallback)count_request_modes, &count); - return priv->request_mode; + if (!count.hfw && !count.wfh) + return GTK_SIZE_REQUEST_CONSTANT_SIZE; + else + return count.wfh > count.hfw ? + GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT : + GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH; } /**