Fixed GtkExtendedLayout interaction with sizegroups plus cleanups

Fixed GtkExtendedLayout to interact with sizegroups, "size-requsts"
and caching the values all in the same code segment.

Migrated the cache code to be internal to gtkextendedlayout.c
This commit is contained in:
Tristan Van Berkom 2010-04-17 01:51:10 -04:00
parent 46fe9c3f00
commit 9247bc8d6d
2 changed files with 192 additions and 269 deletions

View File

@ -31,6 +31,28 @@
#define DEBUG_EXTENDED_LAYOUT 0
/* With extended layout, a widget may be requested
* its width for 2 or 3 heights in one resize
*/
#define N_CACHED_SIZES 3
typedef struct
{
guint age;
gint for_size;
gint minimum_size;
gint natural_size;
} DesiredSize;
typedef struct {
DesiredSize desired_widths[N_CACHED_SIZES];
DesiredSize desired_heights[N_CACHED_SIZES];
guint cached_width_age;
guint cached_height_age;
} ExtendedLayoutCache;
static GQuark quark_cache = 0;
GType
gtk_extended_layout_get_type (void)
@ -45,28 +67,27 @@ gtk_extended_layout_get_type (void)
NULL, 0, NULL, 0);
g_type_interface_add_prerequisite (extended_layout_type, GTK_TYPE_WIDGET);
quark_cache = g_quark_from_static_string ("gtk-extended-layout-cache");
}
return extended_layout_type;
}
/* looks for a cached size request for this for_size. If not
* found, returns the oldest entry so it can be overwritten */
static gboolean
_gtk_extended_layout_get_cached_desired_size (gfloat for_size,
GtkDesiredSize *cached_sizes,
GtkDesiredSize **result)
get_cached_desired_size (gfloat for_size,
DesiredSize *cached_sizes,
DesiredSize **result)
{
guint i;
*result = &cached_sizes[0];
for (i = 0; i < GTK_N_CACHED_SIZES; i++)
for (i = 0; i < N_CACHED_SIZES; i++)
{
GtkDesiredSize *cs;
DesiredSize *cs;
cs = &cached_sizes[i];
@ -85,6 +106,165 @@ _gtk_extended_layout_get_cached_desired_size (gfloat for_size,
return FALSE;
}
static void
destroy_cache (ExtendedLayoutCache *cache)
{
g_slice_free (ExtendedLayoutCache, cache);
}
ExtendedLayoutCache *
get_cache (GtkExtendedLayout *layout, gboolean create)
{
ExtendedLayoutCache *cache;
cache = g_object_get_qdata (G_OBJECT (layout), quark_cache);
if (!cache && create)
{
cache = g_slice_new0 (ExtendedLayoutCache);
cache->cached_width_age = 1;
cache->cached_height_age = 1;
g_object_set_qdata_full (G_OBJECT (layout), quark_cache, cache,
(GDestroyNotify)destroy_cache);
}
return cache;
}
static void
do_size_request (GtkWidget *widget)
{
if (GTK_WIDGET_REQUEST_NEEDED (widget))
{
gtk_widget_ensure_style (widget);
GTK_PRIVATE_UNSET_FLAG (widget, GTK_REQUEST_NEEDED);
g_signal_emit_by_name (widget,
"size-request",
&widget->requisition);
}
}
static void
compute_size_for_orientation (GtkExtendedLayout *layout,
GtkSizeGroupMode orientation,
gint for_size,
gint *minimum_size,
gint *natural_size)
{
ExtendedLayoutCache *cache;
DesiredSize *cached_size;
GtkWidget *widget;
gboolean found_in_cache = FALSE;
g_return_if_fail (GTK_IS_EXTENDED_LAYOUT (layout));
g_return_if_fail (minimum_size != NULL || natural_size != NULL);
widget = GTK_WIDGET (layout);
cache = get_cache (layout, TRUE);
if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
{
cached_size = &cache->desired_widths[0];
if (GTK_WIDGET_WIDTH_REQUEST_NEEDED (layout) == FALSE)
found_in_cache = get_cached_desired_size (for_size, cache->desired_widths, &cached_size);
}
else
{
cached_size = &cache->desired_heights[0];
if (GTK_WIDGET_WIDTH_REQUEST_NEEDED (layout) == FALSE)
found_in_cache = get_cached_desired_size (for_size, cache->desired_heights, &cached_size);
}
if (!found_in_cache)
{
gint min_size = 0, nat_size = 0;
gint group_size, requisition_size;
/* Unconditional size request runs but is often unhandled. */
do_size_request (widget);
if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
{
requisition_size = widget->requisition.width;
if (for_size < 0)
GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->
get_desired_width (layout, &min_size, &nat_size);
else
GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->
get_width_for_height (layout, for_size, &min_size, &nat_size);
}
else
{
requisition_size = widget->requisition.height;
if (for_size < 0)
GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->
get_desired_height (layout, &min_size, &nat_size);
else
GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->
get_height_for_width (layout, for_size, &min_size, &nat_size);
}
/* Support for dangling "size-request" signals and forward derived
* classes that will not default to a ->get_desired_width() that
* returns the values in the ->requisition cache.
*/
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;
if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
{
cached_size->age = cache->cached_width_age;
cache->cached_width_age++;
GTK_PRIVATE_UNSET_FLAG (layout, GTK_WIDTH_REQUEST_NEEDED);
}
else
{
cached_size->age = cache->cached_height_age;
cache->cached_height_age++;
GTK_PRIVATE_UNSET_FLAG (layout, GTK_HEIGHT_REQUEST_NEEDED);
}
/* Get size groups to compute the base requisition once one of the values have been cached,
* then go ahead and update the cache with the sizegroup computed value.
*/
group_size =
_gtk_size_group_bump_requisition (GTK_WIDGET (layout),
orientation, cached_size->minimum_size);
cached_size->minimum_size = MAX (cached_size->minimum_size, group_size);
cached_size->natural_size = MAX (cached_size->natural_size, group_size);
}
/* Output the MAX()s of the cached size and the size computed by GtkSizeGroup. */
if (minimum_size)
*minimum_size = cached_size->minimum_size;
if (natural_size)
*natural_size = cached_size->natural_size;
g_assert (cached_size->minimum_size <= cached_size->natural_size);
#if DEBUG_EXTENDED_LAYOUT
g_message ("%s size for orientation %s: %d is minimum %d and natural: %d",
G_OBJECT_TYPE_NAME (layout),
orientation == GTK_SIZE_GROUP_HORIZONTAL ? "horizontal" : "vertical",
height,
cached_size->minimum_size,
cached_size->natural_size);
#endif
}
/**
* gtk_extended_layout_is_height_for_width:
* @layout: a #GtkExtendedLayout instance
@ -127,66 +307,7 @@ gtk_extended_layout_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_width,
gint *natural_width)
{
GtkWidgetAuxInfo *aux_info;
gboolean found_in_cache = FALSE;
GtkDesiredSize *cached_size;
g_return_if_fail (GTK_IS_EXTENDED_LAYOUT (layout));
g_return_if_fail (minimum_width != NULL || natural_width != NULL);
aux_info = _gtk_widget_get_aux_info (GTK_WIDGET (layout), TRUE);
cached_size = &aux_info->desired_widths[0];
if (GTK_WIDGET_WIDTH_REQUEST_NEEDED (layout) == FALSE)
found_in_cache = _gtk_extended_layout_get_cached_desired_size (-1, aux_info->desired_widths,
&cached_size);
if (!found_in_cache)
{
GtkRequisition requisition;
gint minimum_width = 0, natural_width = 0;
/* Unconditionally envoke size-request and use those return values as
* the base end of our values */
_gtk_size_group_compute_requisition (GTK_WIDGET (layout), &requisition);
/* Envoke this after, default GtkWidgetClass will simply copy over widget->requisition
*/
GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_desired_width (layout,
&minimum_width,
&natural_width);
minimum_width = MAX (minimum_width, requisition.width);
natural_width = MAX (natural_width, requisition.width);
/* XXX Possibly we should update this with minimum values instead */
_gtk_size_group_bump_requisition (GTK_WIDGET (layout), GTK_SIZE_GROUP_HORIZONTAL, natural_width);
cached_size->minimum_size = minimum_width;
cached_size->natural_size = natural_width;
cached_size->for_size = -1;
cached_size->age = aux_info->cached_width_age;
aux_info->cached_width_age ++;
GTK_PRIVATE_UNSET_FLAG (layout, GTK_WIDTH_REQUEST_NEEDED);
}
if (minimum_width)
*minimum_width = cached_size->minimum_size;
if (natural_width)
*natural_width = cached_size->natural_size;
g_assert (!minimum_width || !natural_width || *minimum_width <= *natural_width);
#if DEBUG_EXTENDED_LAYOUT
g_message ("%s returning minimum width: %d and natural width: %d",
G_OBJECT_TYPE_NAME (layout),
cached_size->minimum_size,
cached_size->natural_size);
#endif
compute_size_for_orientation (layout, GTK_SIZE_GROUP_HORIZONTAL, -1, minimum_width, natural_width);
}
@ -205,66 +326,7 @@ gtk_extended_layout_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_height,
gint *natural_height)
{
GtkWidgetAuxInfo *aux_info;
gboolean found_in_cache = FALSE;
GtkDesiredSize *cached_size;
g_return_if_fail (GTK_IS_EXTENDED_LAYOUT (layout));
g_return_if_fail (minimum_height != NULL || natural_height != NULL);
aux_info = _gtk_widget_get_aux_info (GTK_WIDGET (layout), TRUE);
cached_size = &aux_info->desired_heights[0];
if (GTK_WIDGET_HEIGHT_REQUEST_NEEDED (layout) == FALSE)
found_in_cache = _gtk_extended_layout_get_cached_desired_size (-1, aux_info->desired_heights,
&cached_size);
if (!found_in_cache)
{
GtkRequisition requisition;
gint minimum_height = 0, natural_height = 0;
/* Unconditionally envoke size-request and use those return values as
* the base end of our values */
_gtk_size_group_compute_requisition (GTK_WIDGET (layout), &requisition);
/* Envoke this after, default GtkWidgetClass will simply copy over widget->requisition
*/
GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_desired_height (layout,
&minimum_height,
&natural_height);
minimum_height = MAX (minimum_height, requisition.height);
natural_height = MAX (natural_height, requisition.height);
/* XXX Possibly we should update this with minimum values instead */
_gtk_size_group_bump_requisition (GTK_WIDGET (layout), GTK_SIZE_GROUP_VERTICAL, natural_height);
cached_size->minimum_size = minimum_height;
cached_size->natural_size = natural_height;
cached_size->for_size = -1;
cached_size->age = aux_info->cached_height_age;
aux_info->cached_height_age ++;
GTK_PRIVATE_UNSET_FLAG (layout, GTK_HEIGHT_REQUEST_NEEDED);
}
if (minimum_height)
*minimum_height = cached_size->minimum_size;
if (natural_height)
*natural_height = cached_size->natural_size;
g_assert (!minimum_height || !natural_height || *minimum_height <= *natural_height);
#if DEBUG_EXTENDED_LAYOUT
g_message ("%s returning minimum height: %d and natural height: %d",
G_OBJECT_TYPE_NAME (layout),
cached_size->minimum_size,
cached_size->natural_size);
#endif
compute_size_for_orientation (layout, GTK_SIZE_GROUP_VERTICAL, -1, minimum_height, natural_height);
}
@ -287,67 +349,7 @@ gtk_extended_layout_get_width_for_height (GtkExtendedLayout *layout,
gint *minimum_width,
gint *natural_width)
{
GtkWidgetAuxInfo *aux_info;
gboolean found_in_cache = FALSE;
GtkDesiredSize *cached_size;
g_return_if_fail (GTK_IS_EXTENDED_LAYOUT (layout));
g_return_if_fail (minimum_width != NULL || natural_width != NULL);
aux_info = _gtk_widget_get_aux_info (GTK_WIDGET (layout), TRUE);
cached_size = &aux_info->desired_widths[0];
if (GTK_WIDGET_WIDTH_REQUEST_NEEDED (layout) == FALSE)
found_in_cache = _gtk_extended_layout_get_cached_desired_size (height, aux_info->desired_widths,
&cached_size);
if (!found_in_cache)
{
GtkRequisition requisition;
gint minimum_width = 0, natural_width = 0;
/* Unconditionally envoke size-request and use those return values as
* the base end of our values */
_gtk_size_group_compute_requisition (GTK_WIDGET (layout), &requisition);
GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_width_for_height (layout,
height,
&minimum_width,
&natural_width);
minimum_width = MAX (minimum_width, requisition.width);
natural_width = MAX (natural_width, requisition.width);
/* XXX Possibly we should update this with minimum values instead */
_gtk_size_group_bump_requisition (GTK_WIDGET (layout), GTK_SIZE_GROUP_HORIZONTAL, natural_width);
cached_size->minimum_size = minimum_width;
cached_size->natural_size = natural_width;
cached_size->for_size = height;
cached_size->age = aux_info->cached_width_age;
aux_info->cached_width_age++;
GTK_PRIVATE_UNSET_FLAG (layout, GTK_WIDTH_REQUEST_NEEDED);
}
if (minimum_width)
*minimum_width = cached_size->minimum_size;
if (natural_width)
*natural_width = cached_size->natural_size;
g_assert (!minimum_width || !natural_width || *minimum_width <= *natural_width);
#if DEBUG_EXTENDED_LAYOUT
g_message ("%s width for height: %d is minimum %d and natural: %d",
G_OBJECT_TYPE_NAME (layout), height,
cached_size->minimum_size,
cached_size->natural_size);
#endif
compute_size_for_orientation (layout, GTK_SIZE_GROUP_HORIZONTAL, height, minimum_width, natural_width);
}
/**
@ -368,71 +370,9 @@ gtk_extended_layout_get_height_for_width (GtkExtendedLayout *layout,
gint *minimum_height,
gint *natural_height)
{
GtkWidgetAuxInfo *aux_info;
gboolean found_in_cache = FALSE;
GtkDesiredSize *cached_size;
g_return_if_fail (GTK_IS_EXTENDED_LAYOUT (layout));
g_return_if_fail (minimum_height != NULL || natural_height != NULL);
aux_info = _gtk_widget_get_aux_info (GTK_WIDGET (layout), TRUE);
cached_size = &aux_info->desired_heights[0];
if (GTK_WIDGET_HEIGHT_REQUEST_NEEDED (layout) == FALSE)
found_in_cache = _gtk_extended_layout_get_cached_desired_size (width, aux_info->desired_heights,
&cached_size);
if (!found_in_cache)
{
GtkRequisition requisition;
gint minimum_height = 0, natural_height = 0;
/* Unconditionally envoke size-request and use those return values as
* the base end of our values */
_gtk_size_group_compute_requisition (GTK_WIDGET (layout), &requisition);
GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_height_for_width (layout,
width,
&minimum_height,
&natural_height);
minimum_height = MAX (minimum_height, requisition.height);
natural_height = MAX (natural_height, requisition.height);
/* XXX Possibly we should update this with minimum values instead */
_gtk_size_group_bump_requisition (GTK_WIDGET (layout), GTK_SIZE_GROUP_VERTICAL, natural_height);
cached_size->minimum_size = minimum_height;
cached_size->natural_size = natural_height;
cached_size->for_size = width;
cached_size->age = aux_info->cached_height_age;
aux_info->cached_height_age++;
GTK_PRIVATE_UNSET_FLAG (layout, GTK_HEIGHT_REQUEST_NEEDED);
}
if (minimum_height)
*minimum_height = cached_size->minimum_size;
if (natural_height)
*natural_height = cached_size->natural_size;
g_assert (!minimum_height || !natural_height || *minimum_height <= *natural_height);
#if DEBUG_EXTENDED_LAYOUT
g_message ("%s height for width: %d is minimum %d and natural: %d",
G_OBJECT_TYPE_NAME (layout), width,
cached_size->minimum_size,
cached_size->natural_size);
#endif
compute_size_for_orientation (layout, GTK_SIZE_GROUP_VERTICAL, width, minimum_height, natural_height);
}
/**
* gtk_extended_layout_get_desired_size:
* @layout: a #GtkExtendedLayout instance

View File

@ -459,16 +459,12 @@ typedef enum
#define GTK_TYPE_REQUISITION (gtk_requisition_get_type ())
/* Size of the width-for-height/height-for-width caches */
#define GTK_N_CACHED_SIZES 3
/* forward declaration to avoid excessive includes (and concurrent includes)
*/
typedef struct _GtkRequisition GtkRequisition;
typedef struct _GtkSelectionData GtkSelectionData;
typedef struct _GtkWidgetClass GtkWidgetClass;
typedef struct _GtkWidgetAuxInfo GtkWidgetAuxInfo;
typedef struct _GtkDesiredSize GtkDesiredSize;
typedef struct _GtkWidgetShapeInfo GtkWidgetShapeInfo;
typedef struct _GtkClipboard GtkClipboard;
typedef struct _GtkTooltip GtkTooltip;
@ -804,14 +800,6 @@ struct _GtkWidgetClass
void (*_gtk_reserved7) (void);
};
struct _GtkDesiredSize
{
guint age;
gint for_size;
gint minimum_size;
gint natural_size;
};
struct _GtkWidgetAuxInfo
{
gint x;
@ -821,11 +809,6 @@ struct _GtkWidgetAuxInfo
guint x_set : 1;
guint y_set : 1;
GtkDesiredSize desired_widths[GTK_N_CACHED_SIZES];
GtkDesiredSize desired_heights[GTK_N_CACHED_SIZES];
guint cached_width_age;
guint cached_height_age;
};
struct _GtkWidgetShapeInfo