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"
28 #include "gtkprivate.h"
31 static void gtk_cell_area_iter_finalize (GObject *object);
32 static void gtk_cell_area_iter_dispose (GObject *object);
33 static void gtk_cell_area_iter_get_property (GObject *object,
37 static void gtk_cell_area_iter_set_property (GObject *object,
42 /* GtkCellAreaIterClass */
43 static void gtk_cell_area_iter_real_flush_preferred_width (GtkCellAreaIter *iter);
44 static void gtk_cell_area_iter_real_flush_preferred_height_for_width (GtkCellAreaIter *iter,
46 static void gtk_cell_area_iter_real_flush_preferred_height (GtkCellAreaIter *iter);
47 static void gtk_cell_area_iter_real_flush_preferred_width_for_height (GtkCellAreaIter *iter,
49 static void gtk_cell_area_iter_real_flush_allocation (GtkCellAreaIter *iter);
50 static void gtk_cell_area_iter_real_allocate_width (GtkCellAreaIter *iter,
52 static void gtk_cell_area_iter_real_allocate_height (GtkCellAreaIter *iter,
55 /* CachedSize management */
61 static CachedSize *cached_size_new (gint min_size, gint nat_size);
62 static void cached_size_free (CachedSize *size);
64 struct _GtkCellAreaIterPrivate
66 GtkCellArea *cell_area;
90 SIGNAL_HEIGHT_CHANGED,
94 static guint cell_area_iter_signals[LAST_SIGNAL] = { 0 };
96 G_DEFINE_TYPE (GtkCellAreaIter, gtk_cell_area_iter, G_TYPE_OBJECT);
99 gtk_cell_area_iter_init (GtkCellAreaIter *iter)
101 GtkCellAreaIterPrivate *priv;
103 iter->priv = G_TYPE_INSTANCE_GET_PRIVATE (iter,
104 GTK_TYPE_CELL_AREA_ITER,
105 GtkCellAreaIterPrivate);
108 priv->min_width = -1;
109 priv->nat_width = -1;
110 priv->min_height = -1;
111 priv->nat_height = -1;
112 priv->widths = g_hash_table_new_full (g_direct_hash, g_direct_equal,
113 NULL, (GDestroyNotify)cached_size_free);
114 priv->heights = g_hash_table_new_full (g_direct_hash, g_direct_equal,
115 NULL, (GDestroyNotify)cached_size_free);
119 gtk_cell_area_iter_class_init (GtkCellAreaIterClass *class)
121 GObjectClass *object_class = G_OBJECT_CLASS (class);
124 object_class->finalize = gtk_cell_area_iter_finalize;
125 object_class->dispose = gtk_cell_area_iter_dispose;
126 object_class->get_property = gtk_cell_area_iter_get_property;
127 object_class->set_property = gtk_cell_area_iter_set_property;
129 class->flush_preferred_width = gtk_cell_area_iter_real_flush_preferred_width;
130 class->flush_preferred_height_for_width = gtk_cell_area_iter_real_flush_preferred_height_for_width;
131 class->flush_preferred_height = gtk_cell_area_iter_real_flush_preferred_height;
132 class->flush_preferred_width_for_height = gtk_cell_area_iter_real_flush_preferred_width_for_height;
133 class->flush_allocation = gtk_cell_area_iter_real_flush_allocation;
135 class->allocate_width = gtk_cell_area_iter_real_allocate_width;
136 class->allocate_height = gtk_cell_area_iter_real_allocate_height;
138 class->sum_preferred_width = NULL;
139 class->sum_preferred_height_for_width = NULL;
140 class->sum_preferred_height = NULL;
141 class->sum_preferred_width_for_height = NULL;
143 class->allocate_width = NULL;
144 class->allocate_height = NULL;
146 cell_area_iter_signals[SIGNAL_HEIGHT_CHANGED] =
147 g_signal_new (I_("height-changed"),
148 G_TYPE_FROM_CLASS (object_class),
150 0, /* Class offset (just a notification, no class handler) */
152 _gtk_marshal_VOID__INT_INT_INT,
154 G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
156 cell_area_iter_signals[SIGNAL_WIDTH_CHANGED] =
157 g_signal_new (I_("width-changed"),
158 G_TYPE_FROM_CLASS (object_class),
160 0, /* Class offset (just a notification, no class handler) */
162 _gtk_marshal_VOID__INT_INT_INT,
164 G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
166 g_object_class_install_property (object_class,
168 g_param_spec_object ("area",
170 P_("The Cell Area this iter was created for"),
172 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
174 g_object_class_install_property (object_class,
176 g_param_spec_int ("minimum-width",
178 P_("Minimum cached width"),
184 g_object_class_install_property (object_class,
186 g_param_spec_int ("natural-width",
188 P_("Minimum cached width"),
194 g_object_class_install_property (object_class,
196 g_param_spec_int ("minimum-height",
197 P_("Minimum Height"),
198 P_("Minimum cached height"),
204 g_object_class_install_property (object_class,
206 g_param_spec_int ("natural-height",
207 P_("Minimum Height"),
208 P_("Minimum cached height"),
214 g_type_class_add_private (object_class, sizeof (GtkCellAreaIterPrivate));
219 /*************************************************************
221 *************************************************************/
223 cached_size_new (gint min_size,
226 CachedSize *size = g_slice_new (CachedSize);
228 size->min_size = min_size;
229 size->nat_size = nat_size;
235 cached_size_free (CachedSize *size)
237 g_slice_free (CachedSize, size);
240 /*************************************************************
242 *************************************************************/
244 gtk_cell_area_iter_finalize (GObject *object)
246 GtkCellAreaIter *iter = GTK_CELL_AREA_ITER (object);
247 GtkCellAreaIterPrivate *priv = iter->priv;
249 g_hash_table_destroy (priv->widths);
250 g_hash_table_destroy (priv->heights);
252 G_OBJECT_CLASS (gtk_cell_area_iter_parent_class)->finalize (object);
256 gtk_cell_area_iter_dispose (GObject *object)
258 GtkCellAreaIter *iter = GTK_CELL_AREA_ITER (object);
259 GtkCellAreaIterPrivate *priv = iter->priv;
263 g_object_unref (priv->cell_area);
265 priv->cell_area = NULL;
268 G_OBJECT_CLASS (gtk_cell_area_iter_parent_class)->dispose (object);
272 gtk_cell_area_iter_set_property (GObject *object,
277 GtkCellAreaIter *iter = GTK_CELL_AREA_ITER (object);
278 GtkCellAreaIterPrivate *priv = iter->priv;
283 priv->cell_area = g_value_dup_object (value);
286 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
292 gtk_cell_area_iter_get_property (GObject *object,
297 GtkCellAreaIter *iter = GTK_CELL_AREA_ITER (object);
298 GtkCellAreaIterPrivate *priv = iter->priv;
303 g_value_set_object (value, priv->cell_area);
306 g_value_set_int (value, priv->min_width);
309 g_value_set_int (value, priv->nat_width);
311 case PROP_MIN_HEIGHT:
312 g_value_set_int (value, priv->min_height);
314 case PROP_NAT_HEIGHT:
315 g_value_set_int (value, priv->nat_height);
318 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
323 /*************************************************************
324 * GtkCellAreaIterClass *
325 *************************************************************/
327 gtk_cell_area_iter_real_flush_preferred_width (GtkCellAreaIter *iter)
329 GtkCellAreaIterPrivate *priv = iter->priv;
331 priv->min_width = -1;
332 priv->nat_width = -1;
334 g_object_freeze_notify (G_OBJECT (iter));
335 g_object_notify (G_OBJECT (iter), "minimum-width");
336 g_object_notify (G_OBJECT (iter), "natural-width");
337 g_object_thaw_notify (G_OBJECT (iter));
341 notify_invalid_height (gpointer width_ptr,
343 GtkCellAreaIter *iter)
345 gint width = GPOINTER_TO_INT (width_ptr);
347 /* Notify size invalidated */
348 g_signal_emit (iter, cell_area_iter_signals[SIGNAL_HEIGHT_CHANGED],
353 gtk_cell_area_iter_real_flush_preferred_height_for_width (GtkCellAreaIter *iter,
356 GtkCellAreaIterPrivate *priv = iter->priv;
358 /* Flush all sizes for special -1 value */
361 g_hash_table_foreach (priv->heights, (GHFunc)notify_invalid_height, iter);
362 g_hash_table_remove_all (priv->heights);
366 g_hash_table_remove (priv->heights, GINT_TO_POINTER (width));
368 /* Notify size invalidated */
369 g_signal_emit (iter, cell_area_iter_signals[SIGNAL_HEIGHT_CHANGED],
375 gtk_cell_area_iter_real_flush_preferred_height (GtkCellAreaIter *iter)
377 GtkCellAreaIterPrivate *priv = iter->priv;
379 priv->min_height = -1;
380 priv->nat_height = -1;
382 g_object_freeze_notify (G_OBJECT (iter));
383 g_object_notify (G_OBJECT (iter), "minimum-height");
384 g_object_notify (G_OBJECT (iter), "natural-height");
385 g_object_thaw_notify (G_OBJECT (iter));
389 notify_invalid_width (gpointer height_ptr,
391 GtkCellAreaIter *iter)
393 gint height = GPOINTER_TO_INT (height_ptr);
395 /* Notify size invalidated */
396 g_signal_emit (iter, cell_area_iter_signals[SIGNAL_WIDTH_CHANGED],
401 gtk_cell_area_iter_real_flush_preferred_width_for_height (GtkCellAreaIter *iter,
404 GtkCellAreaIterPrivate *priv = iter->priv;
406 /* Flush all sizes for special -1 value */
409 g_hash_table_foreach (priv->widths, (GHFunc)notify_invalid_width, iter);
410 g_hash_table_remove_all (priv->widths);
414 g_hash_table_remove (priv->widths, GINT_TO_POINTER (height));
416 /* Notify size invalidated */
417 g_signal_emit (iter, cell_area_iter_signals[SIGNAL_WIDTH_CHANGED],
423 gtk_cell_area_iter_real_flush_allocation (GtkCellAreaIter *iter)
425 GtkCellAreaIterPrivate *priv = iter->priv;
427 priv->alloc_width = 0;
428 priv->alloc_height = 0;
432 gtk_cell_area_iter_real_allocate_width (GtkCellAreaIter *iter,
435 GtkCellAreaIterPrivate *priv = iter->priv;
437 priv->alloc_width = width;
441 gtk_cell_area_iter_real_allocate_height (GtkCellAreaIter *iter,
444 GtkCellAreaIterPrivate *priv = iter->priv;
446 priv->alloc_height = height;
450 /*************************************************************
452 *************************************************************/
454 gtk_cell_area_iter_get_area (GtkCellAreaIter *iter)
456 GtkCellAreaIterPrivate *priv;
458 g_return_val_if_fail (GTK_IS_CELL_AREA_ITER (iter), NULL);
462 return priv->cell_area;
466 gtk_cell_area_iter_flush (GtkCellAreaIter *iter)
468 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
470 gtk_cell_area_iter_flush_preferred_width (iter);
471 gtk_cell_area_iter_flush_preferred_height_for_width (iter, -1);
472 gtk_cell_area_iter_flush_preferred_height (iter);
473 gtk_cell_area_iter_flush_preferred_width_for_height (iter, -1);
474 gtk_cell_area_iter_flush_allocation (iter);
478 gtk_cell_area_iter_flush_preferred_width (GtkCellAreaIter *iter)
480 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
482 GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_width (iter);
486 gtk_cell_area_iter_flush_preferred_height_for_width (GtkCellAreaIter *iter,
489 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
491 GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_height_for_width (iter, for_width);
495 gtk_cell_area_iter_flush_preferred_height (GtkCellAreaIter *iter)
497 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
499 GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_height (iter);
503 gtk_cell_area_iter_flush_preferred_width_for_height (GtkCellAreaIter *iter,
506 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
508 GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_width_for_height (iter, for_height);
512 gtk_cell_area_iter_flush_allocation (GtkCellAreaIter *iter)
514 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
516 GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_allocation (iter);
520 gtk_cell_area_iter_sum_preferred_width (GtkCellAreaIter *iter)
522 GtkCellAreaIterClass *class;
524 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
526 class = GTK_CELL_AREA_ITER_GET_CLASS (iter);
528 if (class->sum_preferred_width)
529 class->sum_preferred_width (iter);
533 gtk_cell_area_iter_sum_preferred_height_for_width (GtkCellAreaIter *iter,
536 GtkCellAreaIterClass *class;
538 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
540 class = GTK_CELL_AREA_ITER_GET_CLASS (iter);
542 if (class->sum_preferred_height_for_width)
543 class->sum_preferred_height_for_width (iter, for_width);
547 gtk_cell_area_iter_sum_preferred_height (GtkCellAreaIter *iter)
549 GtkCellAreaIterClass *class;
551 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
553 class = GTK_CELL_AREA_ITER_GET_CLASS (iter);
555 if (class->sum_preferred_height)
556 class->sum_preferred_height (iter);
560 gtk_cell_area_iter_sum_preferred_width_for_height (GtkCellAreaIter *iter,
563 GtkCellAreaIterClass *class;
565 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
567 class = GTK_CELL_AREA_ITER_GET_CLASS (iter);
569 if (class->sum_preferred_width_for_height)
570 class->sum_preferred_width_for_height (iter, for_height);
574 gtk_cell_area_iter_allocate_width (GtkCellAreaIter *iter,
577 GtkCellAreaIterClass *class;
579 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
581 class = GTK_CELL_AREA_ITER_GET_CLASS (iter);
583 class->allocate_width (iter, width);
587 gtk_cell_area_iter_allocate_height (GtkCellAreaIter *iter,
590 GtkCellAreaIterClass *class;
592 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
594 class = GTK_CELL_AREA_ITER_GET_CLASS (iter);
596 class->allocate_height (iter, height);
600 gtk_cell_area_iter_get_preferred_width (GtkCellAreaIter *iter,
604 GtkCellAreaIterPrivate *priv;
606 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
611 *minimum_width = priv->min_width;
614 *natural_width = priv->nat_width;
618 gtk_cell_area_iter_get_preferred_height_for_width (GtkCellAreaIter *iter,
620 gint *minimum_height,
621 gint *natural_height)
623 GtkCellAreaIterPrivate *priv;
626 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
630 size = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
635 *minimum_height = size->min_size;
638 *natural_height = size->nat_size;
643 *minimum_height = -1;
646 *natural_height = -1;
651 gtk_cell_area_iter_get_preferred_height (GtkCellAreaIter *iter,
652 gint *minimum_height,
653 gint *natural_height)
655 GtkCellAreaIterPrivate *priv;
657 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
662 *minimum_height = priv->min_height;
665 *natural_height = priv->nat_height;
669 gtk_cell_area_iter_get_preferred_width_for_height (GtkCellAreaIter *iter,
674 GtkCellAreaIterPrivate *priv;
677 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
681 size = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
686 *minimum_width = size->min_size;
689 *natural_width = size->nat_size;
702 gtk_cell_area_iter_get_allocation (GtkCellAreaIter *iter,
706 GtkCellAreaIterPrivate *priv;
708 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
713 *width = priv->alloc_width;
716 *height = priv->alloc_height;
720 gtk_cell_area_iter_push_preferred_width (GtkCellAreaIter *iter,
724 GtkCellAreaIterPrivate *priv;
726 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
730 g_object_freeze_notify (G_OBJECT (iter));
732 if (minimum_width > priv->min_width)
734 priv->min_width = minimum_width;
736 g_object_notify (G_OBJECT (iter), "minimum-width");
739 if (natural_width > priv->nat_width)
741 priv->nat_width = natural_width;
743 g_object_notify (G_OBJECT (iter), "natural-width");
746 g_object_thaw_notify (G_OBJECT (iter));
750 gtk_cell_area_iter_push_preferred_height_for_width (GtkCellAreaIter *iter,
755 GtkCellAreaIterPrivate *priv;
757 gboolean changed = FALSE;
759 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
763 size = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
767 size = cached_size_new (minimum_height, natural_height);
769 g_hash_table_insert (priv->heights, GINT_TO_POINTER (for_width), size);
775 if (minimum_height > size->min_size)
777 size->min_size = minimum_height;
781 if (natural_height > size->nat_size)
783 size->nat_size = natural_height;
789 g_signal_emit (iter, cell_area_iter_signals[SIGNAL_HEIGHT_CHANGED], 0,
790 for_width, size->min_size, size->nat_size);
794 gtk_cell_area_iter_push_preferred_height (GtkCellAreaIter *iter,
798 GtkCellAreaIterPrivate *priv;
800 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
804 g_object_freeze_notify (G_OBJECT (iter));
806 if (minimum_height > priv->min_height)
808 priv->min_height = minimum_height;
810 g_object_notify (G_OBJECT (iter), "minimum-height");
813 if (natural_height > priv->nat_height)
815 priv->nat_height = natural_height;
817 g_object_notify (G_OBJECT (iter), "natural-height");
820 g_object_thaw_notify (G_OBJECT (iter));
824 gtk_cell_area_iter_push_preferred_width_for_height (GtkCellAreaIter *iter,
829 GtkCellAreaIterPrivate *priv;
831 gboolean changed = FALSE;
833 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
837 size = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
841 size = cached_size_new (minimum_width, natural_width);
843 g_hash_table_insert (priv->widths, GINT_TO_POINTER (for_height), size);
849 if (minimum_width > size->min_size)
851 size->min_size = minimum_width;
855 if (natural_width > size->nat_size)
857 size->nat_size = natural_width;
863 g_signal_emit (iter, cell_area_iter_signals[SIGNAL_WIDTH_CHANGED], 0,
864 for_height, size->min_size, size->nat_size);