X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtksizerequest.c;h=0ce86bd66fc95b849c98347619791f28898604b8;hb=HEAD;hp=0d0bb267cad71f4a43f77ef1e4134de71bdfb3e7;hpb=de0428fe520ea0be3c3c612054927d0b78faaa1b;p=~andy%2Fgtk diff --git a/gtk/gtksizerequest.c b/gtk/gtksizerequest.c index 0d0bb267c..0ce86bd66 100644 --- a/gtk/gtksizerequest.c +++ b/gtk/gtksizerequest.c @@ -16,206 +16,29 @@ * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ - -/** - * SECTION:gtksizerequest - * @Short_Description: Height-for-width geometry management - * @Title: GtkWidget - * - * The GtkWidget interface is GTK+'s height-for-width (and width-for-height) - * geometry management system. Height-for-width means that a widget can - * change how much vertical space it needs, depending on the amount - * of horizontal space that it is given (and similar for width-for-height). - * The most common example is a label that reflows to fill up the available - * width, wraps to fewer lines, and therefore needs less height. - * - * GTK+'s traditional two-pass size-allocation - * algorithm does not allow this flexibility. #GtkWidget provides a default - * implementation of the #GtkWidget interface for existing widgets, - * which always requests the same height, regardless of the available width. - * - * - * Implementing GtkWidget - * - * Some important things to keep in mind when implementing - * the GtkWidget interface and when using it in container - * implementations. - * - * The geometry management system will query a logical hierarchy in - * only one orientation at a time. When widgets are initially queried - * for their minimum sizes it is generally done in a dual pass - * in the direction chosen by the toplevel. - * - * For instance when queried in the normal height-for-width mode: - * First the default minimum and natural width for each widget - * in the interface will computed and collectively returned to - * the toplevel by way of gtk_widget_get_preferred_width(). - * Next, the toplevel will use the minimum width to query for the - * minimum height contextual to that width using - * gtk_widget_get_preferred_height_for_width(), which will also - * be a highly recursive operation. This minimum-for-minimum size can - * be used to set the minimum size constraint on the toplevel. - * - * When allocating, each container can use the minimum and natural - * sizes reported by their children to allocate natural sizes and - * expose as much content as possible with the given allocation. - * - * That means that the request operation at allocation time will - * usually fire again in contexts of different allocated sizes than - * the ones originally queried for. #GtkWidget caches a - * small number of results to avoid re-querying for the same - * allocated size in one allocation cycle. - * - * A widget that does not actually do height-for-width - * or width-for-height size negotiations only has to implement - * get_width() and get_height(). - * - * If a widget does move content around to smartly use up the - * allocated size, then it must support the request properly in - * both orientations; even if the request only makes sense in - * one orientation. - * - * For instance, a GtkLabel that does height-for-width word wrapping - * will not expect to have get_height() called because that - * call is specific to a width-for-height request, in this case the - * label must return the heights contextual to its minimum possible - * width. By following this rule any widget that handles height-for-width - * or width-for-height requests will always be allocated at least - * enough space to fit its own content. - * - * Often a widget needs to get its own request during size request or - * allocation, for example when computing height it may need to also - * compute width, or when deciding how to use an allocation the widget may - * need to know its natural size. In these cases, the widget should be - * careful to call its virtual methods directly, like this: - * - * Widget calling its own size request method. - * - * GTK_SIZE_REQUEST_GET_IFACE(widget)->get_width(GTK_SIZE_REQUEST(widget), &min, &natural); - * - * - * - * It will not work to use the wrapper functions, such as - * gtk_size_request_get_width(), inside your own size request - * implementation. These return a request adjusted by #GtkSizeGroup - * and by the GtkWidgetClass::adjust_size_request virtual method. If a - * widget used the wrappers inside its virtual method implementations, - * then the adjustments (such as widget margins) would be applied - * twice. GTK+ therefore does not allow this and will warn if you try - * to do it. - * - * Of course if you are getting the size request for - * another widget, such as a child of a - * container, you must use the wrapper APIs; - * otherwise, you would not properly consider widget margins, - * #GtkSizeGroup, and so forth. - * - * - */ - - #include + #include "gtksizerequest.h" -#include "gtksizegroup.h" + #include "gtkdebug.h" -#include "gtkprivate.h" #include "gtkintl.h" +#include "gtkprivate.h" +#include "gtksizegroup-private.h" +#include "gtksizerequestcacheprivate.h" +#include "gtkwidgetprivate.h" +#include "deprecated/gtkstyle.h" -/* looks for a cached size request for this for_size. If not - * found, returns the oldest entry so it can be overwritten - * - * Note that this caching code was directly derived from - * the Clutter toolkit. - */ -static gboolean -get_cached_size (SizeRequestCache *cache, - GtkSizeGroupMode orientation, - gint for_size, - SizeRequest **result) -{ - guint i, n_sizes; - SizeRequest *cached_sizes; - - if (orientation == GTK_SIZE_GROUP_HORIZONTAL) - { - cached_sizes = cache->widths; - n_sizes = cache->cached_widths; - } - else - { - cached_sizes = cache->heights; - n_sizes = cache->cached_widths; - } - - /* Search for an already cached size */ - for (i = 0; i < n_sizes; i++) - { - if (cached_sizes[i].for_size == for_size) - { - *result = &cached_sizes[i]; - return TRUE; - } - } - - /* If not found, pull a new size from the cache, the returned size cache - * will immediately be used to cache the new computed size so we go ahead - * and increment the last_cached_width/height right away */ - if (orientation == GTK_SIZE_GROUP_HORIZONTAL) - { - if (cache->cached_widths < GTK_SIZE_REQUEST_CACHED_SIZES) - { - cache->cached_widths++; - cache->last_cached_width = cache->cached_widths - 1; - } - else - { - if (++cache->last_cached_width == GTK_SIZE_REQUEST_CACHED_SIZES) - cache->last_cached_width = 0; - } - - *result = &cache->widths[cache->last_cached_width]; - } - else /* GTK_SIZE_GROUP_VERTICAL */ - { - if (cache->cached_heights < GTK_SIZE_REQUEST_CACHED_SIZES) - { - cache->cached_heights++; - cache->last_cached_height = cache->cached_heights - 1; - } - else - { - if (++cache->last_cached_height == GTK_SIZE_REQUEST_CACHED_SIZES) - cache->last_cached_height = 0; - } - - *result = &cache->heights[cache->last_cached_height]; - } - - return FALSE; -} - -static void -do_size_request (GtkWidget *widget, - GtkRequisition *requisition) -{ - /* Now we dont bother caching the deprecated "size-request" returns, - * just unconditionally invoke here just in case we run into legacy stuff */ - gtk_widget_ensure_style (widget); - g_signal_emit_by_name (widget, "size-request", requisition); -} #ifndef G_DISABLE_CHECKS static GQuark recursion_check_quark = 0; #endif /* G_DISABLE_CHECKS */ static void -push_recursion_check (GtkWidget *request, - GtkSizeGroupMode orientation, +push_recursion_check (GtkWidget *widget, + GtkOrientation orientation, gint for_size) { #ifndef G_DISABLE_CHECKS @@ -225,9 +48,9 @@ push_recursion_check (GtkWidget *request, if (recursion_check_quark == 0) recursion_check_quark = g_quark_from_static_string ("gtk-size-request-in-progress"); - previous_method = g_object_get_qdata (G_OBJECT (request), recursion_check_quark); + previous_method = g_object_get_qdata (G_OBJECT (widget), recursion_check_quark); - if (orientation == GTK_SIZE_GROUP_HORIZONTAL) + if (orientation == GTK_ORIENTATION_HORIZONTAL) { method = for_size < 0 ? "get_width" : "get_width_for_height"; } @@ -242,186 +65,249 @@ push_recursion_check (GtkWidget *request, " GtkWidget ::%s implementation. " "Should just invoke GTK_WIDGET_GET_CLASS(widget)->%s " "directly rather than using gtk_widget_%s", - G_OBJECT_TYPE_NAME (request), request, + G_OBJECT_TYPE_NAME (widget), widget, method, previous_method, method, method); } - g_object_set_qdata (G_OBJECT (request), recursion_check_quark, (char*) method); + g_object_set_qdata (G_OBJECT (widget), recursion_check_quark, (char*) method); #endif /* G_DISABLE_CHECKS */ } static void -pop_recursion_check (GtkWidget *request, - GtkSizeGroupMode orientation) +pop_recursion_check (GtkWidget *widget, + GtkOrientation orientation) { #ifndef G_DISABLE_CHECKS - g_object_set_qdata (G_OBJECT (request), recursion_check_quark, NULL); + g_object_set_qdata (G_OBJECT (widget), recursion_check_quark, NULL); #endif } -static void -compute_size_for_orientation (GtkWidget *request, - GtkSizeGroupMode orientation, - gint for_size, - gint *minimum_size, - gint *natural_size) +static const char * +get_vfunc_name (GtkOrientation orientation, + gint for_size) { - SizeRequestCache *cache; - SizeRequest *cached_size; - GtkWidget *widget; - gboolean found_in_cache = FALSE; - int adjusted_min, adjusted_natural; - - g_return_if_fail (GTK_IS_WIDGET (request)); - g_return_if_fail (minimum_size != NULL || natural_size != NULL); - - widget = GTK_WIDGET (request); - cache = _gtk_widget_peek_request_cache (widget); - - if (orientation == GTK_SIZE_GROUP_HORIZONTAL) - { - cached_size = &cache->widths[0]; - - if (!_gtk_widget_get_width_request_needed (widget)) - found_in_cache = get_cached_size (cache, orientation, for_size, &cached_size); - else - { - memset (cache->widths, 0, GTK_SIZE_REQUEST_CACHED_SIZES * sizeof (SizeRequest)); - cache->cached_widths = 1; - cache->last_cached_width = 0; - } - } + if (orientation == GTK_ORIENTATION_HORIZONTAL) + return for_size < 0 ? "get_preferred_width" : "get_preferred_width_for_height"; else - { - cached_size = &cache->heights[0]; - - if (!_gtk_widget_get_height_request_needed (widget)) - found_in_cache = get_cached_size (cache, orientation, for_size, &cached_size); - else - { - memset (cache->heights, 0, GTK_SIZE_REQUEST_CACHED_SIZES * sizeof (SizeRequest)); - cache->cached_heights = 1; - cache->last_cached_height = 0; - } - } + return for_size < 0 ? "get_preferred_height" : "get_preferred_height_for_width"; +} +static void +gtk_widget_query_size_for_orientation (GtkWidget *widget, + GtkOrientation orientation, + gint for_size, + gint *minimum_size, + gint *natural_size) +{ + SizeRequestCache *cache; + gint min_size = 0; + gint nat_size = 0; + gboolean found_in_cache; + + if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_CONSTANT_SIZE) + for_size = -1; + + cache = _gtk_widget_peek_request_cache (widget); + found_in_cache = _gtk_size_request_cache_lookup (cache, + orientation, + for_size, + &min_size, + &nat_size); + if (!found_in_cache) { - GtkRequisition requisition = { 0, 0 }; - gint min_size = 0, nat_size = 0; - gint requisition_size; + gint adjusted_min, adjusted_natural, adjusted_for_size = for_size; - /* Unconditional size request runs but is often unhandled. */ - do_size_request (widget, &requisition); + gtk_widget_ensure_style (widget); - push_recursion_check (request, orientation, for_size); - if (orientation == GTK_SIZE_GROUP_HORIZONTAL) + if (orientation == GTK_ORIENTATION_HORIZONTAL) { - requisition_size = requisition.width; - if (for_size < 0) - GTK_WIDGET_GET_CLASS (request)->get_preferred_width (request, &min_size, &nat_size); + { + push_recursion_check (widget, orientation, for_size); + GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_size, &nat_size); + pop_recursion_check (widget, orientation); + } else - GTK_WIDGET_GET_CLASS (request)->get_preferred_width_for_height (request, for_size, - &min_size, &nat_size); + { + gint ignored_position = 0; + gint minimum_height; + gint natural_height; + + /* Pull the base natural height from the cache as it's needed to adjust + * the proposed 'for_size' */ + gtk_widget_get_preferred_height (widget, &minimum_height, &natural_height); + + /* convert for_size to unadjusted height (for_size is a proposed allocation) */ + GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget, + GTK_ORIENTATION_VERTICAL, + &minimum_height, + &natural_height, + &ignored_position, + &adjusted_for_size); + + push_recursion_check (widget, orientation, for_size); + GTK_WIDGET_GET_CLASS (widget)->get_preferred_width_for_height (widget, + MAX (adjusted_for_size, minimum_height), + &min_size, &nat_size); + pop_recursion_check (widget, orientation); + } } else { - requisition_size = requisition.height; - if (for_size < 0) - GTK_WIDGET_GET_CLASS (request)->get_preferred_height (request, &min_size, &nat_size); + { + push_recursion_check (widget, orientation, for_size); + GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, &min_size, &nat_size); + pop_recursion_check (widget, orientation); + } else - GTK_WIDGET_GET_CLASS (request)->get_preferred_height_for_width (request, for_size, - &min_size, &nat_size); + { + gint ignored_position = 0; + gint minimum_width; + gint natural_width; + + /* Pull the base natural width from the cache as it's needed to adjust + * the proposed 'for_size' */ + gtk_widget_get_preferred_width (widget, &minimum_width, &natural_width); + + /* convert for_size to unadjusted width (for_size is a proposed allocation) */ + GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget, + GTK_ORIENTATION_HORIZONTAL, + &minimum_width, + &natural_width, + &ignored_position, + &adjusted_for_size); + + push_recursion_check (widget, orientation, for_size); + GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width (widget, + MAX (adjusted_for_size, minimum_width), + &min_size, &nat_size); + pop_recursion_check (widget, orientation); + } } - pop_recursion_check (request, orientation); if (min_size > nat_size) { - g_warning ("%s %p reported min size %d and natural size %d; natural size must be >= min size", - G_OBJECT_TYPE_NAME (request), request, min_size, nat_size); + g_warning ("%s %p reported min size %d and natural size %d in %s(); natural size must be >= min size", + G_OBJECT_TYPE_NAME (widget), widget, min_size, nat_size, get_vfunc_name (orientation, for_size)); } - /* Support for dangling "size-request" signal implementations on - * legacy widgets - */ - min_size = MAX (min_size, requisition_size); - nat_size = MAX (nat_size, requisition_size); - - cached_size->minimum_size = min_size; - cached_size->natural_size = nat_size; - cached_size->for_size = for_size; + adjusted_min = min_size; + adjusted_natural = nat_size; + GTK_WIDGET_GET_CLASS (widget)->adjust_size_request (widget, + orientation, + &adjusted_min, + &adjusted_natural); - if (orientation == GTK_SIZE_GROUP_HORIZONTAL) - _gtk_widget_set_width_request_needed (widget, FALSE); - else - _gtk_widget_set_height_request_needed (widget, FALSE); - - adjusted_min = cached_size->minimum_size; - adjusted_natural = cached_size->natural_size; - GTK_WIDGET_GET_CLASS (request)->adjust_size_request (GTK_WIDGET (request), - orientation == GTK_SIZE_GROUP_HORIZONTAL ? - GTK_ORIENTATION_HORIZONTAL : - GTK_ORIENTATION_VERTICAL, - cached_size->for_size, - &adjusted_min, - &adjusted_natural); - - if (adjusted_min < cached_size->minimum_size || - adjusted_natural < cached_size->natural_size) + if (adjusted_min < min_size || + adjusted_natural < nat_size) { g_warning ("%s %p adjusted size %s min %d natural %d must not decrease below min %d natural %d", - G_OBJECT_TYPE_NAME (request), request, - orientation == GTK_SIZE_GROUP_VERTICAL ? "vertical" : "horizontal", + G_OBJECT_TYPE_NAME (widget), widget, + orientation == GTK_ORIENTATION_VERTICAL ? "vertical" : "horizontal", adjusted_min, adjusted_natural, - cached_size->minimum_size, cached_size->natural_size); + min_size, nat_size); /* don't use the adjustment */ } else if (adjusted_min > adjusted_natural) { g_warning ("%s %p adjusted size %s min %d natural %d original min %d natural %d has min greater than natural", - G_OBJECT_TYPE_NAME (request), request, - orientation == GTK_SIZE_GROUP_VERTICAL ? "vertical" : "horizontal", + G_OBJECT_TYPE_NAME (widget), widget, + orientation == GTK_ORIENTATION_VERTICAL ? "vertical" : "horizontal", adjusted_min, adjusted_natural, - cached_size->minimum_size, cached_size->natural_size); + min_size, nat_size); /* don't use the adjustment */ } else { /* adjustment looks good */ - cached_size->minimum_size = adjusted_min; - cached_size->natural_size = adjusted_natural; + min_size = adjusted_min; + nat_size = adjusted_natural; } - /* Update size-groups with our request and update our cached requests - * with the size-group values in a single pass. - */ - _gtk_size_group_bump_requisition (GTK_WIDGET (request), - orientation, - &cached_size->minimum_size, - &cached_size->natural_size); + _gtk_size_request_cache_commit (cache, + orientation, + for_size, + min_size, + nat_size); } if (minimum_size) - *minimum_size = cached_size->minimum_size; + *minimum_size = min_size; if (natural_size) - *natural_size = cached_size->natural_size; + *natural_size = nat_size; - g_assert (cached_size->minimum_size <= cached_size->natural_size); + g_assert (min_size <= nat_size); GTK_NOTE (SIZE_REQUEST, g_print ("[%p] %s\t%s: %d is minimum %d and natural: %d (hit cache: %s)\n", - request, G_OBJECT_TYPE_NAME (request), - orientation == GTK_SIZE_GROUP_HORIZONTAL ? + widget, G_OBJECT_TYPE_NAME (widget), + orientation == GTK_ORIENTATION_HORIZONTAL ? "width for height" : "height for width" , - for_size, - cached_size->minimum_size, - cached_size->natural_size, + for_size, min_size, nat_size, found_in_cache ? "yes" : "no")); +} +/* This is the main function that checks for a cached size and + * possibly queries the widget class to compute the size if it's + * not cached. If the for_size here is -1, then get_preferred_width() + * or get_preferred_height() will be used. + */ +void +_gtk_widget_compute_size_for_orientation (GtkWidget *widget, + GtkOrientation orientation, + gint for_size, + gint *minimum, + gint *natural) +{ + GHashTable *widgets; + GHashTableIter iter; + gpointer key; + gint min_result = 0, nat_result = 0; + + if (!gtk_widget_get_visible (widget) && !gtk_widget_is_toplevel (widget)) + { + if (minimum) + *minimum = 0; + if (natural) + *natural = 0; + return; + } + + if (G_LIKELY (!_gtk_widget_get_sizegroups (widget))) + { + gtk_widget_query_size_for_orientation (widget, orientation, for_size, minimum, natural); + return; + } + + widgets = _gtk_size_group_get_widget_peers (widget, orientation); + + g_hash_table_foreach (widgets, (GHFunc) g_object_ref, NULL); + + g_hash_table_iter_init (&iter, widgets); + while (g_hash_table_iter_next (&iter, &key, NULL)) + { + GtkWidget *tmp_widget = key; + gint min_dimension, nat_dimension; + + gtk_widget_query_size_for_orientation (tmp_widget, orientation, for_size, &min_dimension, &nat_dimension); + + min_result = MAX (min_result, min_dimension); + nat_result = MAX (nat_result, nat_dimension); + } + + g_hash_table_foreach (widgets, (GHFunc) g_object_unref, NULL); + + g_hash_table_destroy (widgets); + + if (minimum) + *minimum = min_result; + + if (natural) + *natural = nat_result; } /** @@ -443,16 +329,19 @@ compute_size_for_orientation (GtkWidget *request, GtkSizeRequestMode gtk_widget_get_request_mode (GtkWidget *widget) { - GtkWidgetClass *klass; + SizeRequestCache *cache; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), GTK_SIZE_REQUEST_CONSTANT_SIZE); - g_return_val_if_fail (GTK_IS_WIDGET (widget), GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH); + cache = _gtk_widget_peek_request_cache (widget); - klass = GTK_WIDGET_GET_CLASS (widget); - if (klass->get_request_mode) - return klass->get_request_mode (widget); + if (!cache->request_mode_valid) + { + cache->request_mode = GTK_WIDGET_GET_CLASS (widget)->get_request_mode (widget); + cache->request_mode_valid = TRUE; + } - /* By default widgets are height-for-width. */ - return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH; + return cache->request_mode; } /** @@ -468,7 +357,7 @@ gtk_widget_get_request_mode (GtkWidget *widget) * * The returned request will be modified by the * GtkWidgetClass::adjust_size_request virtual method and by any - * #GtkSizeGroup that have been applied. That is, the returned request + * #GtkSizeGroups that have been applied. That is, the returned request * is the one that should be used for layout, not necessarily the one * returned by the widget itself. * @@ -479,8 +368,14 @@ gtk_widget_get_preferred_width (GtkWidget *widget, gint *minimum_width, gint *natural_width) { - compute_size_for_orientation (widget, GTK_SIZE_GROUP_HORIZONTAL, - -1, minimum_width, natural_width); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (minimum_width != NULL || natural_width != NULL); + + _gtk_widget_compute_size_for_orientation (widget, + GTK_ORIENTATION_HORIZONTAL, + -1, + minimum_width, + natural_width); } @@ -496,7 +391,7 @@ gtk_widget_get_preferred_width (GtkWidget *widget, * * The returned request will be modified by the * GtkWidgetClass::adjust_size_request virtual method and by any - * #GtkSizeGroup that have been applied. That is, the returned request + * #GtkSizeGroups that have been applied. That is, the returned request * is the one that should be used for layout, not necessarily the one * returned by the widget itself. * @@ -507,8 +402,14 @@ gtk_widget_get_preferred_height (GtkWidget *widget, gint *minimum_height, gint *natural_height) { - compute_size_for_orientation (widget, GTK_SIZE_GROUP_VERTICAL, - -1, minimum_height, natural_height); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (minimum_height != NULL || natural_height != NULL); + + _gtk_widget_compute_size_for_orientation (widget, + GTK_ORIENTATION_VERTICAL, + -1, + minimum_height, + natural_height); } @@ -525,7 +426,7 @@ gtk_widget_get_preferred_height (GtkWidget *widget, * * The returned request will be modified by the * GtkWidgetClass::adjust_size_request virtual method and by any - * #GtkSizeGroup that have been applied. That is, the returned request + * #GtkSizeGroups that have been applied. That is, the returned request * is the one that should be used for layout, not necessarily the one * returned by the widget itself. * @@ -537,8 +438,15 @@ gtk_widget_get_preferred_width_for_height (GtkWidget *widget, gint *minimum_width, gint *natural_width) { - compute_size_for_orientation (widget, GTK_SIZE_GROUP_HORIZONTAL, - height, minimum_width, natural_width); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (minimum_width != NULL || natural_width != NULL); + g_return_if_fail (height >= 0); + + _gtk_widget_compute_size_for_orientation (widget, + GTK_ORIENTATION_HORIZONTAL, + height, + minimum_width, + natural_width); } /** @@ -553,7 +461,7 @@ gtk_widget_get_preferred_width_for_height (GtkWidget *widget, * * The returned request will be modified by the * GtkWidgetClass::adjust_size_request virtual method and by any - * #GtkSizeGroup that have been applied. That is, the returned request + * #GtkSizeGroups that have been applied. That is, the returned request * is the one that should be used for layout, not necessarily the one * returned by the widget itself. * @@ -565,8 +473,15 @@ gtk_widget_get_preferred_height_for_width (GtkWidget *widget, gint *minimum_height, gint *natural_height) { - compute_size_for_orientation (widget, GTK_SIZE_GROUP_VERTICAL, - width, minimum_height, natural_height); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (minimum_height != NULL || natural_height != NULL); + g_return_if_fail (width >= 0); + + _gtk_widget_compute_size_for_orientation (widget, + GTK_ORIENTATION_VERTICAL, + width, + minimum_height, + natural_height); } /** @@ -575,11 +490,18 @@ gtk_widget_get_preferred_height_for_width (GtkWidget *widget, * @minimum_size: (out) (allow-none): location for storing the minimum size, or %NULL * @natural_size: (out) (allow-none): location for storing the natural size, or %NULL * - * Retrieves the minimum and natural size of a widget taking + * Retrieves the minimum and natural size of a widget, taking * into account the widget's preference for height-for-width management. * * This is used to retrieve a suitable size by container widgets which do - * not impose any restrictions on the child placement. + * not impose any restrictions on the child placement. It can be used + * to deduce toplevel window and menu sizes as well as child widgets in + * free-form containers such as GtkLayout. + * + * Handle with care. Note that the natural height of a height-for-width + * widget will generally be a smaller size than the minimum height, since the required + * height for the natural width is generally smaller than the required height for + * the minimum width. * * Since: 3.0 */ @@ -611,7 +533,7 @@ gtk_widget_get_preferred_size (GtkWidget *widget, NULL, &natural_size->height); } } - else /* GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT */ + else /* GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT or CONSTANT_SIZE */ { gtk_widget_get_preferred_height (widget, &min_height, &nat_height); @@ -657,14 +579,14 @@ compare_gap (gconstpointer p1, } /** - * gtk_distribute_natural_allocation: + * gtk_distribute_natural_allocation: * @extra_space: Extra space to redistribute among children after subtracting * minimum sizes and any child padding from the overall allocation * @n_requested_sizes: Number of requests to fit into the allocation * @sizes: An array of structs with a client pointer and a minimum/natural size * in the orientation of the allocation. * - * Distributes @extra_space to child @sizes by bringing up smaller + * Distributes @extra_space to child @sizes by bringing smaller * children up to natural size first. * * The remaining space will be added to the @minimum_size member of the @@ -674,7 +596,7 @@ compare_gap (gconstpointer p1, * Returns: The remainder of @extra_space after redistributing space * to @sizes. */ -gint +gint gtk_distribute_natural_allocation (gint extra_space, guint n_requested_sizes, GtkRequestedSize *sizes) @@ -705,12 +627,12 @@ gtk_distribute_natural_allocation (gint extra_space, * The following code distributes the additional space by following * these rules. */ - + /* Sort descending by gap and position. */ g_qsort_with_data (spreading, n_requested_sizes, sizeof (guint), compare_gap, sizes); - + /* Distribute available space. * This master piece of a loop was conceived by Behdad Esfahbod. */ @@ -723,14 +645,13 @@ gtk_distribute_natural_allocation (gint extra_space, gint glue = (extra_space + i) / (i + 1); gint gap = sizes[(spreading[i])].natural_size - sizes[(spreading[i])].minimum_size; - + gint extra = MIN (glue, gap); - + sizes[spreading[i]].minimum_size += extra; - + extra_space -= extra; } return extra_space; } -