summaryrefslogtreecommitdiff
path: root/gtk/gtkextendedlayout.c
diff options
context:
space:
mode:
Diffstat (limited to 'gtk/gtkextendedlayout.c')
-rw-r--r--gtk/gtkextendedlayout.c444
1 files changed, 192 insertions, 252 deletions
diff --git a/gtk/gtkextendedlayout.c b/gtk/gtkextendedlayout.c
index dcc3e6ca4e..0ca1658aa3 100644
--- a/gtk/gtkextendedlayout.c
+++ b/gtk/gtkextendedlayout.c
@@ -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