]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellareaiter.c
Added the majority of the allocate machinery to GtkCellAreaIter[Box].
[~andy/gtk] / gtk / gtkcellareaiter.c
1 /* gtkcellareaiter.c
2  *
3  * Copyright (C) 2010 Openismus GmbH
4  *
5  * Authors:
6  *      Tristan Van Berkom <tristanvb@openismus.com>
7  *
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.
12  *
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.
17  *
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.
22  */
23
24 #include "config.h"
25 #include "gtkintl.h"
26 #include "gtkmarshalers.h"
27 #include "gtkcellareaiter.h"
28 #include "gtkprivate.h"
29
30 /* GObjectClass */
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,
34                                                                    guint               prop_id,
35                                                                    GValue             *value,
36                                                                    GParamSpec         *pspec);
37 static void      gtk_cell_area_iter_set_property                  (GObject            *object,
38                                                                    guint               prop_id,
39                                                                    const GValue       *value,
40                                                                    GParamSpec         *pspec);
41
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,
45                                                                            gint             width);
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,
48                                                                            gint             height);
49 static void      gtk_cell_area_iter_real_flush_allocation                 (GtkCellAreaIter *iter);
50 static void      gtk_cell_area_iter_real_allocate_width                   (GtkCellAreaIter *iter,
51                                                                            gint             width);
52 static void      gtk_cell_area_iter_real_allocate_height                  (GtkCellAreaIter *iter,
53                                                                            gint             height);
54
55 /* CachedSize management */
56 typedef struct {
57   gint min_size;
58   gint nat_size;
59 } CachedSize;
60
61 static CachedSize *cached_size_new  (gint min_size, gint nat_size);
62 static void        cached_size_free (CachedSize *size);
63
64 struct _GtkCellAreaIterPrivate
65 {
66   GtkCellArea *cell_area;
67
68   gint         min_width;
69   gint         nat_width;
70   gint         min_height;
71   gint         nat_height;
72   gint         alloc_width;
73   gint         alloc_height;
74
75   GHashTable  *widths;
76   GHashTable  *heights;
77 };
78
79 enum {
80   PROP_0,
81   PROP_CELL_AREA,
82   PROP_MIN_WIDTH,
83   PROP_NAT_WIDTH,
84   PROP_MIN_HEIGHT,
85   PROP_NAT_HEIGHT
86 };
87
88 enum {
89   SIGNAL_WIDTH_CHANGED,
90   SIGNAL_HEIGHT_CHANGED,
91   LAST_SIGNAL
92 };
93
94 static guint cell_area_iter_signals[LAST_SIGNAL] = { 0 };
95
96 G_DEFINE_TYPE (GtkCellAreaIter, gtk_cell_area_iter, G_TYPE_OBJECT);
97
98 static void
99 gtk_cell_area_iter_init (GtkCellAreaIter *iter)
100 {
101   GtkCellAreaIterPrivate *priv;
102
103   iter->priv = G_TYPE_INSTANCE_GET_PRIVATE (iter,
104                                             GTK_TYPE_CELL_AREA_ITER,
105                                             GtkCellAreaIterPrivate);
106   priv = iter->priv;
107
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);
116 }
117
118 static void 
119 gtk_cell_area_iter_class_init (GtkCellAreaIterClass *class)
120 {
121   GObjectClass     *object_class = G_OBJECT_CLASS (class);
122
123   /* GObjectClass */
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;
128
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;
134
135   class->allocate_width  = gtk_cell_area_iter_real_allocate_width;
136   class->allocate_height = gtk_cell_area_iter_real_allocate_height;
137
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;
142
143   class->allocate_width  = NULL;
144   class->allocate_height = NULL;
145
146   cell_area_iter_signals[SIGNAL_HEIGHT_CHANGED] =
147     g_signal_new (I_("height-changed"),
148                   G_TYPE_FROM_CLASS (object_class),
149                   G_SIGNAL_RUN_LAST,
150                   0, /* Class offset (just a notification, no class handler) */
151                   NULL, NULL,
152                   _gtk_marshal_VOID__INT_INT_INT,
153                   G_TYPE_NONE, 3,
154                   G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
155
156   cell_area_iter_signals[SIGNAL_WIDTH_CHANGED] =
157     g_signal_new (I_("width-changed"),
158                   G_TYPE_FROM_CLASS (object_class),
159                   G_SIGNAL_RUN_LAST,
160                   0, /* Class offset (just a notification, no class handler) */
161                   NULL, NULL,
162                   _gtk_marshal_VOID__INT_INT_INT,
163                   G_TYPE_NONE, 3,
164                   G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
165
166   g_object_class_install_property (object_class,
167                                    PROP_CELL_AREA,
168                                    g_param_spec_object ("area",
169                                                         P_("Area"),
170                                                         P_("The Cell Area this iter was created for"),
171                                                         GTK_TYPE_CELL_AREA,
172                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
173
174   g_object_class_install_property (object_class,
175                                    PROP_MIN_WIDTH,
176                                    g_param_spec_int ("minimum-width",
177                                                      P_("Minimum Width"),
178                                                      P_("Minimum cached width"),
179                                                      -1,
180                                                      G_MAXINT,
181                                                      -1,
182                                                      G_PARAM_READABLE));
183
184   g_object_class_install_property (object_class,
185                                    PROP_NAT_WIDTH,
186                                    g_param_spec_int ("natural-width",
187                                                      P_("Minimum Width"),
188                                                      P_("Minimum cached width"),
189                                                      -1,
190                                                      G_MAXINT,
191                                                      -1,
192                                                      G_PARAM_READABLE));
193
194   g_object_class_install_property (object_class,
195                                    PROP_MIN_HEIGHT,
196                                    g_param_spec_int ("minimum-height",
197                                                      P_("Minimum Height"),
198                                                      P_("Minimum cached height"),
199                                                      -1,
200                                                      G_MAXINT,
201                                                      -1,
202                                                      G_PARAM_READABLE));
203
204   g_object_class_install_property (object_class,
205                                    PROP_NAT_HEIGHT,
206                                    g_param_spec_int ("natural-height",
207                                                      P_("Minimum Height"),
208                                                      P_("Minimum cached height"),
209                                                      -1,
210                                                      G_MAXINT,
211                                                      -1,
212                                                      G_PARAM_READABLE));
213
214   g_type_class_add_private (object_class, sizeof (GtkCellAreaIterPrivate));
215 }
216
217
218
219 /*************************************************************
220  *                      Cached Sizes                         *
221  *************************************************************/
222 static CachedSize *
223 cached_size_new (gint min_size, 
224                  gint nat_size)
225 {
226   CachedSize *size = g_slice_new (CachedSize);
227
228   size->min_size = min_size;
229   size->nat_size = nat_size;
230
231   return size;
232 }
233
234 static void
235 cached_size_free (CachedSize *size)
236 {
237   g_slice_free (CachedSize, size);
238 }
239
240 /*************************************************************
241  *                      GObjectClass                         *
242  *************************************************************/
243 static void
244 gtk_cell_area_iter_finalize (GObject *object)
245 {
246   GtkCellAreaIter        *iter = GTK_CELL_AREA_ITER (object);
247   GtkCellAreaIterPrivate *priv = iter->priv;
248
249   g_hash_table_destroy (priv->widths);
250   g_hash_table_destroy (priv->heights);
251
252   G_OBJECT_CLASS (gtk_cell_area_iter_parent_class)->finalize (object);
253 }
254
255 static void
256 gtk_cell_area_iter_dispose (GObject *object)
257 {
258   GtkCellAreaIter        *iter = GTK_CELL_AREA_ITER (object);
259   GtkCellAreaIterPrivate *priv = iter->priv;
260
261   if (priv->cell_area)
262     {
263       g_object_unref (priv->cell_area);
264
265       priv->cell_area = NULL;
266     }
267
268   G_OBJECT_CLASS (gtk_cell_area_iter_parent_class)->dispose (object);
269 }
270
271 static void
272 gtk_cell_area_iter_set_property (GObject      *object,
273                                  guint         prop_id,
274                                  const GValue *value,
275                                  GParamSpec   *pspec)
276 {
277   GtkCellAreaIter        *iter = GTK_CELL_AREA_ITER (object);
278   GtkCellAreaIterPrivate *priv = iter->priv;
279
280   switch (prop_id)
281     {
282     case PROP_CELL_AREA:
283       priv->cell_area = g_value_dup_object (value);
284       break;
285     default:
286       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
287       break;
288     }
289 }
290
291 static void
292 gtk_cell_area_iter_get_property (GObject     *object,
293                                  guint        prop_id,
294                                  GValue      *value,
295                                  GParamSpec  *pspec)
296 {
297   GtkCellAreaIter        *iter = GTK_CELL_AREA_ITER (object);
298   GtkCellAreaIterPrivate *priv = iter->priv;
299
300   switch (prop_id)
301     {
302     case PROP_CELL_AREA:
303       g_value_set_object (value, priv->cell_area);
304       break;
305     case PROP_MIN_WIDTH:
306       g_value_set_int (value, priv->min_width);
307       break;
308     case PROP_NAT_WIDTH:
309       g_value_set_int (value, priv->nat_width);
310       break;
311     case PROP_MIN_HEIGHT:
312       g_value_set_int (value, priv->min_height);
313       break;
314     case PROP_NAT_HEIGHT:
315       g_value_set_int (value, priv->nat_height);
316       break;
317     default:
318       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
319       break;
320     }
321 }
322
323 /*************************************************************
324  *                    GtkCellAreaIterClass                   *
325  *************************************************************/
326 static void
327 gtk_cell_area_iter_real_flush_preferred_width (GtkCellAreaIter *iter)
328 {
329   GtkCellAreaIterPrivate *priv = iter->priv;
330   
331   priv->min_width = -1;
332   priv->nat_width = -1;
333
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));
338 }
339
340 static void
341 notify_invalid_height (gpointer         width_ptr,
342                        CachedSize      *size,
343                        GtkCellAreaIter *iter)
344 {
345   gint width = GPOINTER_TO_INT (width_ptr);
346
347   /* Notify size invalidated */
348   g_signal_emit (iter, cell_area_iter_signals[SIGNAL_HEIGHT_CHANGED], 
349                  0, width, -1, -1);
350 }
351
352 static void
353 gtk_cell_area_iter_real_flush_preferred_height_for_width (GtkCellAreaIter *iter,
354                                                           gint             width)
355 {
356   GtkCellAreaIterPrivate *priv = iter->priv;
357
358   /* Flush all sizes for special -1 value */
359   if (width < 0)
360     {
361       g_hash_table_foreach (priv->heights, (GHFunc)notify_invalid_height, iter);
362       g_hash_table_remove_all (priv->heights);
363     }
364   else
365     {
366       g_hash_table_remove (priv->heights, GINT_TO_POINTER (width));
367
368       /* Notify size invalidated */
369       g_signal_emit (iter, cell_area_iter_signals[SIGNAL_HEIGHT_CHANGED], 
370                      0, width, -1, -1);
371     }
372 }
373
374 static void
375 gtk_cell_area_iter_real_flush_preferred_height (GtkCellAreaIter *iter)
376 {
377   GtkCellAreaIterPrivate *priv = iter->priv;
378   
379   priv->min_height = -1;
380   priv->nat_height = -1;
381
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));
386 }
387
388 static void
389 notify_invalid_width (gpointer         height_ptr,
390                       CachedSize      *size,
391                       GtkCellAreaIter *iter)
392 {
393   gint height = GPOINTER_TO_INT (height_ptr);
394
395   /* Notify size invalidated */
396   g_signal_emit (iter, cell_area_iter_signals[SIGNAL_WIDTH_CHANGED], 
397                  0, height, -1, -1);
398 }
399
400 static void
401 gtk_cell_area_iter_real_flush_preferred_width_for_height (GtkCellAreaIter *iter,
402                                                           gint             height)
403 {
404   GtkCellAreaIterPrivate *priv = iter->priv;
405
406   /* Flush all sizes for special -1 value */
407   if (height < 0)
408     {
409       g_hash_table_foreach (priv->widths, (GHFunc)notify_invalid_width, iter);
410       g_hash_table_remove_all (priv->widths);
411     }
412   else
413     {
414       g_hash_table_remove (priv->widths, GINT_TO_POINTER (height));
415
416       /* Notify size invalidated */
417       g_signal_emit (iter, cell_area_iter_signals[SIGNAL_WIDTH_CHANGED], 
418                      0, height, -1, -1);
419     }
420 }
421
422 static void
423 gtk_cell_area_iter_real_flush_allocation (GtkCellAreaIter *iter)
424 {
425   GtkCellAreaIterPrivate *priv = iter->priv;
426
427   priv->alloc_width  = 0;
428   priv->alloc_height = 0;
429 }
430
431 static void
432 gtk_cell_area_iter_real_allocate_width (GtkCellAreaIter *iter,
433                                         gint             width)
434 {
435   GtkCellAreaIterPrivate *priv = iter->priv;
436
437   priv->alloc_width = width;
438 }
439
440 static void
441 gtk_cell_area_iter_real_allocate_height (GtkCellAreaIter *iter,
442                                          gint             height)
443 {
444   GtkCellAreaIterPrivate *priv = iter->priv;
445
446   priv->alloc_height = height;
447 }
448
449
450 /*************************************************************
451  *                            API                            *
452  *************************************************************/
453 GtkCellArea *
454 gtk_cell_area_iter_get_area (GtkCellAreaIter *iter)
455 {
456   GtkCellAreaIterPrivate *priv;
457
458   g_return_val_if_fail (GTK_IS_CELL_AREA_ITER (iter), NULL);
459
460   priv = iter->priv;
461
462   return priv->cell_area;
463 }
464
465 void
466 gtk_cell_area_iter_flush (GtkCellAreaIter *iter)
467 {
468   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
469
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);
475 }
476
477 void
478 gtk_cell_area_iter_flush_preferred_width (GtkCellAreaIter *iter)
479 {
480   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
481
482   GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_width (iter);
483 }
484
485 void
486 gtk_cell_area_iter_flush_preferred_height_for_width (GtkCellAreaIter *iter,
487                                                      gint             for_width)
488 {
489   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
490
491   GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_height_for_width (iter, for_width);
492 }
493
494 void
495 gtk_cell_area_iter_flush_preferred_height (GtkCellAreaIter *iter)
496 {
497   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
498
499   GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_height (iter);
500 }
501
502 void
503 gtk_cell_area_iter_flush_preferred_width_for_height (GtkCellAreaIter *iter,
504                                                      gint             for_height)
505 {
506   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
507
508   GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_width_for_height (iter, for_height);
509 }
510
511 void
512 gtk_cell_area_iter_flush_allocation (GtkCellAreaIter *iter)
513 {
514   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
515
516   GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_allocation (iter);
517 }
518
519 void
520 gtk_cell_area_iter_sum_preferred_width (GtkCellAreaIter *iter)
521 {
522   GtkCellAreaIterClass *class;
523
524   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
525
526   class = GTK_CELL_AREA_ITER_GET_CLASS (iter);
527
528   if (class->sum_preferred_width)
529     class->sum_preferred_width (iter);
530 }
531
532 void
533 gtk_cell_area_iter_sum_preferred_height_for_width (GtkCellAreaIter *iter,
534                                                    gint             for_width)
535 {
536   GtkCellAreaIterClass *class;
537
538   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
539
540   class = GTK_CELL_AREA_ITER_GET_CLASS (iter);
541
542   if (class->sum_preferred_height_for_width)
543     class->sum_preferred_height_for_width (iter, for_width);
544 }
545
546 void
547 gtk_cell_area_iter_sum_preferred_height (GtkCellAreaIter *iter)
548 {
549   GtkCellAreaIterClass *class;
550
551   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
552
553   class = GTK_CELL_AREA_ITER_GET_CLASS (iter);
554
555   if (class->sum_preferred_height)
556     class->sum_preferred_height (iter);
557 }
558
559 void
560 gtk_cell_area_iter_sum_preferred_width_for_height (GtkCellAreaIter *iter,
561                                                    gint             for_height)
562 {
563   GtkCellAreaIterClass *class;
564
565   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
566
567   class = GTK_CELL_AREA_ITER_GET_CLASS (iter);
568
569   if (class->sum_preferred_width_for_height)
570     class->sum_preferred_width_for_height (iter, for_height);
571 }
572
573 void
574 gtk_cell_area_iter_allocate_width (GtkCellAreaIter *iter,
575                                    gint             width)
576 {
577   GtkCellAreaIterClass *class;
578
579   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
580
581   class = GTK_CELL_AREA_ITER_GET_CLASS (iter);
582
583   class->allocate_width (iter, width);
584 }
585
586 void
587 gtk_cell_area_iter_allocate_height (GtkCellAreaIter *iter,
588                                     gint             height)
589 {
590   GtkCellAreaIterClass *class;
591
592   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
593
594   class = GTK_CELL_AREA_ITER_GET_CLASS (iter);
595
596   class->allocate_height (iter, height);
597 }
598
599 void
600 gtk_cell_area_iter_get_preferred_width (GtkCellAreaIter *iter,
601                                         gint            *minimum_width,
602                                         gint            *natural_width)
603 {
604   GtkCellAreaIterPrivate *priv;
605
606   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
607
608   priv = iter->priv;
609
610   if (minimum_width)
611     *minimum_width = priv->min_width;
612
613   if (natural_width)
614     *natural_width = priv->nat_width;
615 }
616
617 void
618 gtk_cell_area_iter_get_preferred_height_for_width (GtkCellAreaIter *iter,
619                                                    gint             for_width,
620                                                    gint            *minimum_height,
621                                                    gint            *natural_height)
622 {
623   GtkCellAreaIterPrivate *priv;
624   CachedSize             *size;
625
626   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
627
628   priv = iter->priv;
629
630   size = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
631
632   if (size)
633     {
634       if (minimum_height)
635         *minimum_height = size->min_size;
636
637       if (natural_height)
638         *natural_height = size->nat_size;
639     }
640   else
641     {
642       if (minimum_height)
643         *minimum_height = -1;
644
645       if (natural_height)
646         *natural_height = -1;
647     }
648 }
649
650 void
651 gtk_cell_area_iter_get_preferred_height (GtkCellAreaIter *iter,
652                                          gint            *minimum_height,
653                                          gint            *natural_height)
654 {
655   GtkCellAreaIterPrivate *priv;
656
657   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
658
659   priv = iter->priv;
660
661   if (minimum_height)
662     *minimum_height = priv->min_height;
663
664   if (natural_height)
665     *natural_height = priv->nat_height;
666 }
667
668 void
669 gtk_cell_area_iter_get_preferred_width_for_height (GtkCellAreaIter *iter,
670                                                    gint             for_height,
671                                                    gint            *minimum_width,
672                                                    gint            *natural_width)
673 {
674   GtkCellAreaIterPrivate *priv;
675   CachedSize             *size;
676
677   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
678
679   priv = iter->priv;
680
681   size = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
682
683   if (size)
684     {
685       if (minimum_width)
686         *minimum_width = size->min_size;
687
688       if (natural_width)
689         *natural_width = size->nat_size;
690     }
691   else
692     {
693       if (minimum_width)
694         *minimum_width = -1;
695
696       if (natural_width)
697         *natural_width = -1;
698     }
699 }
700
701 void
702 gtk_cell_area_iter_get_allocation (GtkCellAreaIter *iter,
703                                    gint            *width,
704                                    gint            *height)
705 {
706   GtkCellAreaIterPrivate *priv;
707
708   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
709
710   priv = iter->priv;
711
712   if (width)
713     *width = priv->alloc_width;
714
715   if (height)
716     *height = priv->alloc_height;
717 }
718
719 void
720 gtk_cell_area_iter_push_preferred_width (GtkCellAreaIter *iter,
721                                          gint             minimum_width,
722                                          gint             natural_width)
723 {
724   GtkCellAreaIterPrivate *priv;
725
726   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
727
728   priv = iter->priv;
729
730   g_object_freeze_notify (G_OBJECT (iter));
731
732   if (minimum_width > priv->min_width)
733     {
734       priv->min_width = minimum_width;
735
736       g_object_notify (G_OBJECT (iter), "minimum-width");
737     }
738
739   if (natural_width > priv->nat_width)
740     {
741       priv->nat_width = natural_width;
742
743       g_object_notify (G_OBJECT (iter), "natural-width");
744     }
745
746   g_object_thaw_notify (G_OBJECT (iter));
747 }
748
749 void
750 gtk_cell_area_iter_push_preferred_height_for_width (GtkCellAreaIter *iter,
751                                                     gint             for_width,
752                                                     gint             minimum_height,
753                                                     gint             natural_height)
754 {
755   GtkCellAreaIterPrivate *priv;
756   CachedSize             *size;
757   gboolean                changed = FALSE;
758
759   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
760
761   priv = iter->priv;
762
763   size = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
764
765   if (!size)
766     {
767       size = cached_size_new (minimum_height, natural_height);
768
769       g_hash_table_insert (priv->heights, GINT_TO_POINTER (for_width), size);
770
771       changed = TRUE;
772     }
773   else
774     {
775       if (minimum_height > size->min_size)
776         {
777           size->min_size = minimum_height;
778           changed = TRUE;
779         }
780
781       if (natural_height > size->nat_size)
782         {
783           size->nat_size = natural_height;
784           changed = TRUE;
785         }
786     }
787   
788   if (changed)
789     g_signal_emit (iter, cell_area_iter_signals[SIGNAL_HEIGHT_CHANGED], 0, 
790                    for_width, size->min_size, size->nat_size);
791 }
792
793 void
794 gtk_cell_area_iter_push_preferred_height (GtkCellAreaIter *iter,
795                                           gint             minimum_height,
796                                           gint             natural_height)
797 {
798   GtkCellAreaIterPrivate *priv;
799   
800   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
801
802   priv = iter->priv;
803
804   g_object_freeze_notify (G_OBJECT (iter));
805
806   if (minimum_height > priv->min_height)
807     {
808       priv->min_height = minimum_height;
809
810       g_object_notify (G_OBJECT (iter), "minimum-height");
811     }
812
813   if (natural_height > priv->nat_height)
814     {
815       priv->nat_height = natural_height;
816
817       g_object_notify (G_OBJECT (iter), "natural-height");
818     }
819
820   g_object_thaw_notify (G_OBJECT (iter));
821 }
822
823 void
824 gtk_cell_area_iter_push_preferred_width_for_height (GtkCellAreaIter *iter,
825                                                     gint             for_height,
826                                                     gint             minimum_width,
827                                                     gint             natural_width)
828 {
829   GtkCellAreaIterPrivate *priv;
830   CachedSize             *size;
831   gboolean                changed = FALSE;
832
833   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
834
835   priv = iter->priv;
836
837   size = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
838
839   if (!size)
840     {
841       size = cached_size_new (minimum_width, natural_width);
842
843       g_hash_table_insert (priv->widths, GINT_TO_POINTER (for_height), size);
844
845       changed = TRUE;
846     }
847   else
848     {
849       if (minimum_width > size->min_size)
850         {
851           size->min_size = minimum_width;
852           changed = TRUE;
853         }
854
855       if (natural_width > size->nat_size)
856         {
857           size->nat_size = natural_width;
858           changed = TRUE;
859         }
860     }
861   
862   if (changed)
863     g_signal_emit (iter, cell_area_iter_signals[SIGNAL_WIDTH_CHANGED], 0, 
864                    for_height, size->min_size, size->nat_size);
865 }