3 * Copyright (C) 2010 Openismus GmbH
6 * Tristan Van Berkom <tristanvb@openismus.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
26 #include "gtkmarshalers.h"
27 #include "gtkcellareaiter.h"
30 static void gtk_cell_area_iter_finalize (GObject *object);
31 static void gtk_cell_area_iter_get_property (GObject *object,
36 /* GtkCellAreaIterClass */
37 static void gtk_cell_area_iter_real_flush_preferred_width (GtkCellAreaIter *iter);
38 static void gtk_cell_area_iter_real_flush_preferred_height_for_width (GtkCellAreaIter *iter,
40 static void gtk_cell_area_iter_real_flush_preferred_height (GtkCellAreaIter *iter);
41 static void gtk_cell_area_iter_real_flush_preferred_width_for_height (GtkCellAreaIter *iter,
44 /* CachedSize management */
50 static CachedSize *cached_size_new (gint min_size, gint nat_size);
51 static void cached_size_free (CachedSize *size);
53 struct _GtkCellAreaIterPrivate
74 SIGNAL_HEIGHT_CHANGED,
78 static guint cell_area_iter_signals[LAST_SIGNAL] = { 0 };
80 G_DEFINE_TYPE (GtkCellAreaIter, gtk_cell_area_iter, G_TYPE_OBJECT);
83 gtk_cell_area_iter_init (GtkCellAreaIter *iter)
85 GtkCellAreaIterPrivate *priv;
87 iter->priv = G_TYPE_INSTANCE_GET_PRIVATE (iter,
88 GTK_TYPE_CELL_AREA_ITER,
89 GtkCellAreaIterPrivate);
94 priv->min_height = -1;
95 priv->nat_height = -1;
96 priv->widths = g_hash_table_new_full (g_direct_hash, g_direct_equal,
97 NULL, (GDestroyNotify)cached_size_free);
98 priv->heights = g_hash_table_new_full (g_direct_hash, g_direct_equal,
99 NULL, (GDestroyNotify)cached_size_free);
103 gtk_cell_area_iter_class_init (GtkCellAreaIterClass *class)
105 GObjectClass *object_class = G_OBJECT_CLASS (class);
108 object_class->finalize = gtk_cell_area_iter_finalize;
109 object_class->get_property = gtk_cell_area_iter_get_property;
111 class->flush_preferred_width = gtk_cell_area_iter_real_flush_preferred_width;
112 class->flush_preferred_height_for_width = gtk_cell_area_iter_real_flush_preferred_height_for_width;
113 class->flush_preferred_height = gtk_cell_area_iter_real_flush_preferred_height;
114 class->flush_preferred_width_for_height = gtk_cell_area_iter_real_flush_preferred_width_for_height;
116 cell_area_iter_signals[SIGNAL_HEIGHT_CHANGED] =
117 g_signal_new (I_("height-changed"),
118 G_TYPE_FROM_CLASS (object_class),
120 0, /* Class offset (just a notification, no class handler) */
122 _gtk_marshal_VOID__INT_INT_INT,
124 G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
126 cell_area_iter_signals[SIGNAL_WIDTH_CHANGED] =
127 g_signal_new (I_("width-changed"),
128 G_TYPE_FROM_CLASS (object_class),
130 0, /* Class offset (just a notification, no class handler) */
132 _gtk_marshal_VOID__INT_INT_INT,
134 G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
136 g_object_class_install_property (object_class,
138 g_param_spec_int ("minimum-width",
140 P_("Minimum cached width"),
146 g_object_class_install_property (object_class,
148 g_param_spec_int ("natural-width",
150 P_("Minimum cached width"),
156 g_object_class_install_property (object_class,
158 g_param_spec_int ("minimum-height",
159 P_("Minimum Height"),
160 P_("Minimum cached height"),
166 g_object_class_install_property (object_class,
168 g_param_spec_int ("natural-height",
169 P_("Minimum Height"),
170 P_("Minimum cached height"),
176 g_type_class_add_private (object_class, sizeof (GtkCellAreaIterPrivate));
181 /*************************************************************
183 *************************************************************/
185 cached_size_new (gint min_size,
188 CachedSize *size = g_slice_new (CachedSize);
190 size->min_size = min_size;
191 size->nat_size = nat_size;
197 cached_size_free (CachedSize *size)
199 g_slice_free (CachedSize, size);
202 /*************************************************************
204 *************************************************************/
206 gtk_cell_area_iter_finalize (GObject *object)
208 GtkCellAreaIter *iter = GTK_CELL_AREA_ITER (object);
209 GtkCellAreaIterPrivate *priv = iter->priv;
211 g_hash_table_destroy (priv->widths);
212 g_hash_table_destroy (priv->heights);
214 G_OBJECT_CLASS (gtk_cell_area_iter_parent_class)->finalize (object);
218 gtk_cell_area_iter_get_property (GObject *object,
223 GtkCellAreaIter *iter = GTK_CELL_AREA_ITER (object);
224 GtkCellAreaIterPrivate *priv = iter->priv;
229 g_value_set_int (value, priv->min_width);
232 g_value_set_int (value, priv->nat_width);
234 case PROP_MIN_HEIGHT:
235 g_value_set_int (value, priv->min_height);
237 case PROP_NAT_HEIGHT:
238 g_value_set_int (value, priv->nat_height);
241 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
246 /*************************************************************
247 * GtkCellAreaIterClass *
248 *************************************************************/
250 gtk_cell_area_iter_real_flush_preferred_width (GtkCellAreaIter *iter)
252 GtkCellAreaIterPrivate *priv = iter->priv;
254 priv->min_width = -1;
255 priv->nat_width = -1;
257 g_object_freeze_notify (G_OBJECT (iter));
258 g_object_notify (G_OBJECT (iter), "minimum-width");
259 g_object_notify (G_OBJECT (iter), "natural-width");
260 g_object_thaw_notify (G_OBJECT (iter));
264 gtk_cell_area_iter_real_flush_preferred_height_for_width (GtkCellAreaIter *iter,
267 GtkCellAreaIterPrivate *priv = iter->priv;
269 /* Flush all sizes for special -1 value */
271 g_hash_table_remove_all (priv->heights);
273 g_hash_table_remove (priv->heights, GINT_TO_POINTER (width));
275 /* XXX Should we bother signalling removed values as "size-changed" signals ? */
279 gtk_cell_area_iter_real_flush_preferred_height (GtkCellAreaIter *iter)
281 GtkCellAreaIterPrivate *priv = iter->priv;
283 priv->min_height = -1;
284 priv->nat_height = -1;
286 g_object_freeze_notify (G_OBJECT (iter));
287 g_object_notify (G_OBJECT (iter), "minimum-height");
288 g_object_notify (G_OBJECT (iter), "natural-height");
289 g_object_thaw_notify (G_OBJECT (iter));
293 gtk_cell_area_iter_real_flush_preferred_width_for_height (GtkCellAreaIter *iter,
296 GtkCellAreaIterPrivate *priv = iter->priv;
298 /* Flush all sizes for special -1 value */
300 g_hash_table_remove_all (priv->widths);
302 g_hash_table_remove (priv->widths, GINT_TO_POINTER (height));
304 /* XXX Should we bother signalling removed values as "size-changed" signals ? */
307 /*************************************************************
309 *************************************************************/
312 gtk_cell_area_iter_get_preferred_width (GtkCellAreaIter *iter,
316 GtkCellAreaIterPrivate *priv;
318 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
323 *minimum_width = priv->min_width;
326 *natural_width = priv->nat_width;
330 gtk_cell_area_iter_get_preferred_height_for_width (GtkCellAreaIter *iter,
332 gint *minimum_height,
333 gint *natural_height)
335 GtkCellAreaIterPrivate *priv;
338 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
342 size = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
347 *minimum_height = size->min_size;
350 *natural_height = size->nat_size;
355 *minimum_height = -1;
358 *natural_height = -1;
363 gtk_cell_area_iter_get_preferred_height (GtkCellAreaIter *iter,
364 gint *minimum_height,
365 gint *natural_height)
367 GtkCellAreaIterPrivate *priv;
369 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
374 *minimum_height = priv->min_height;
377 *natural_height = priv->nat_height;
381 gtk_cell_area_iter_get_preferred_width_for_height (GtkCellAreaIter *iter,
386 GtkCellAreaIterPrivate *priv;
389 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
393 size = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
398 *minimum_width = size->min_size;
401 *natural_width = size->nat_size;
415 gtk_cell_area_iter_push_preferred_width (GtkCellAreaIter *iter,
419 GtkCellAreaIterPrivate *priv;
421 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
425 g_object_freeze_notify (G_OBJECT (iter));
427 if (minimum_width > priv->min_width)
429 priv->min_width = minimum_width;
431 g_object_notify (G_OBJECT (iter), "minimum-width");
434 if (natural_width > priv->nat_width)
436 priv->nat_width = natural_width;
438 g_object_notify (G_OBJECT (iter), "natural-width");
441 g_object_thaw_notify (G_OBJECT (iter));
445 gtk_cell_area_iter_push_preferred_height_for_width (GtkCellAreaIter *iter,
450 GtkCellAreaIterPrivate *priv;
452 gboolean changed = FALSE;
454 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
458 size = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
462 size = cached_size_new (minimum_height, natural_height);
464 g_hash_table_insert (priv->heights, GINT_TO_POINTER (for_width), size);
470 if (minimum_height > size->min_size)
472 size->min_size = minimum_height;
476 if (natural_height > size->nat_size)
478 size->nat_size = natural_height;
484 g_signal_emit (iter, cell_area_iter_signals[SIGNAL_HEIGHT_CHANGED], 0,
485 for_width, size->min_size, size->nat_size);
489 gtk_cell_area_iter_push_preferred_height (GtkCellAreaIter *iter,
493 GtkCellAreaIterPrivate *priv;
495 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
499 g_object_freeze_notify (G_OBJECT (iter));
501 if (minimum_height > priv->min_height)
503 priv->min_height = minimum_height;
505 g_object_notify (G_OBJECT (iter), "minimum-height");
508 if (natural_height > priv->nat_height)
510 priv->nat_height = natural_height;
512 g_object_notify (G_OBJECT (iter), "natural-height");
515 g_object_thaw_notify (G_OBJECT (iter));
519 gtk_cell_area_iter_push_preferred_width_for_height (GtkCellAreaIter *iter,
524 GtkCellAreaIterPrivate *priv;
526 gboolean changed = FALSE;
528 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
532 size = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
536 size = cached_size_new (minimum_width, natural_width);
538 g_hash_table_insert (priv->widths, GINT_TO_POINTER (for_height), size);
544 if (minimum_width > size->min_size)
546 size->min_size = minimum_width;
550 if (natural_width > size->nat_size)
552 size->nat_size = natural_width;
558 g_signal_emit (iter, cell_area_iter_signals[SIGNAL_WIDTH_CHANGED], 0,
559 for_height, size->min_size, size->nat_size);
563 gtk_cell_area_iter_flush (GtkCellAreaIter *iter)
565 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
567 gtk_cell_area_iter_flush_preferred_width (iter);
568 gtk_cell_area_iter_flush_preferred_height_for_width (iter, -1);
569 gtk_cell_area_iter_flush_preferred_height (iter);
570 gtk_cell_area_iter_flush_preferred_width_for_height (iter, -1);
574 gtk_cell_area_iter_flush_preferred_width (GtkCellAreaIter *iter)
576 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
578 GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_width (iter);
582 gtk_cell_area_iter_flush_preferred_height_for_width (GtkCellAreaIter *iter,
585 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
587 GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_height_for_width (iter, for_width);
591 gtk_cell_area_iter_flush_preferred_height (GtkCellAreaIter *iter)
593 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
595 GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_height (iter);
599 gtk_cell_area_iter_flush_preferred_width_for_height (GtkCellAreaIter *iter,
602 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
604 GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_width_for_height (iter, for_height);