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