]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellareaiter.c
Remove size_reuqest from GtkImage
[~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
29 /* GObjectClass */
30 static void      gtk_cell_area_iter_finalize                       (GObject            *object);
31 static void      gtk_cell_area_iter_get_property                   (GObject           *object,
32                                                                    guint               prop_id,
33                                                                    GValue             *value,
34                                                                    GParamSpec         *pspec);
35
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,
39                                                                            gint             width);
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,
42                                                                            gint             height);
43
44 /* CachedSize management */
45 typedef struct {
46   gint min_size;
47   gint nat_size;
48 } CachedSize;
49
50 static CachedSize *cached_size_new  (gint min_size, gint nat_size);
51 static void        cached_size_free (CachedSize *size);
52
53 struct _GtkCellAreaIterPrivate
54 {
55   gint        min_width;
56   gint        nat_width;
57   gint        min_height;
58   gint        nat_height;
59
60   GHashTable *widths;
61   GHashTable *heights;
62 };
63
64 enum {
65   PROP_0,
66   PROP_MIN_WIDTH,
67   PROP_NAT_WIDTH,
68   PROP_MIN_HEIGHT,
69   PROP_NAT_HEIGHT
70 };
71
72 enum {
73   SIGNAL_WIDTH_CHANGED,
74   SIGNAL_HEIGHT_CHANGED,
75   LAST_SIGNAL
76 };
77
78 static guint cell_area_iter_signals[LAST_SIGNAL] = { 0 };
79
80 G_DEFINE_TYPE (GtkCellAreaIter, gtk_cell_area_iter, G_TYPE_OBJECT);
81
82 static void
83 gtk_cell_area_iter_init (GtkCellAreaIter *iter)
84 {
85   GtkCellAreaIterPrivate *priv;
86
87   iter->priv = G_TYPE_INSTANCE_GET_PRIVATE (iter,
88                                             GTK_TYPE_CELL_AREA_ITER,
89                                             GtkCellAreaIterPrivate);
90   priv = iter->priv;
91
92   priv->min_width  = -1;
93   priv->nat_width  = -1;
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);
100 }
101
102 static void 
103 gtk_cell_area_iter_class_init (GtkCellAreaIterClass *class)
104 {
105   GObjectClass     *object_class = G_OBJECT_CLASS (class);
106
107   /* GObjectClass */
108   object_class->finalize     = gtk_cell_area_iter_finalize;
109   object_class->get_property = gtk_cell_area_iter_get_property;
110
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;
115
116   cell_area_iter_signals[SIGNAL_HEIGHT_CHANGED] =
117     g_signal_new (I_("height-changed"),
118                   G_TYPE_FROM_CLASS (object_class),
119                   G_SIGNAL_RUN_LAST,
120                   0, /* Class offset (just a notification, no class handler) */
121                   NULL, NULL,
122                   _gtk_marshal_VOID__INT_INT_INT,
123                   G_TYPE_NONE, 3,
124                   G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
125
126   cell_area_iter_signals[SIGNAL_WIDTH_CHANGED] =
127     g_signal_new (I_("width-changed"),
128                   G_TYPE_FROM_CLASS (object_class),
129                   G_SIGNAL_RUN_LAST,
130                   0, /* Class offset (just a notification, no class handler) */
131                   NULL, NULL,
132                   _gtk_marshal_VOID__INT_INT_INT,
133                   G_TYPE_NONE, 3,
134                   G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
135
136   g_object_class_install_property (object_class,
137                                    PROP_MIN_WIDTH,
138                                    g_param_spec_int ("minimum-width",
139                                                      P_("Minimum Width"),
140                                                      P_("Minimum cached width"),
141                                                      -1,
142                                                      G_MAXINT,
143                                                      -1,
144                                                      G_PARAM_READABLE));
145
146   g_object_class_install_property (object_class,
147                                    PROP_NAT_WIDTH,
148                                    g_param_spec_int ("natural-width",
149                                                      P_("Minimum Width"),
150                                                      P_("Minimum cached width"),
151                                                      -1,
152                                                      G_MAXINT,
153                                                      -1,
154                                                      G_PARAM_READABLE));
155
156   g_object_class_install_property (object_class,
157                                    PROP_MIN_HEIGHT,
158                                    g_param_spec_int ("minimum-height",
159                                                      P_("Minimum Height"),
160                                                      P_("Minimum cached height"),
161                                                      -1,
162                                                      G_MAXINT,
163                                                      -1,
164                                                      G_PARAM_READABLE));
165
166   g_object_class_install_property (object_class,
167                                    PROP_NAT_HEIGHT,
168                                    g_param_spec_int ("natural-height",
169                                                      P_("Minimum Height"),
170                                                      P_("Minimum cached height"),
171                                                      -1,
172                                                      G_MAXINT,
173                                                      -1,
174                                                      G_PARAM_READABLE));
175
176   g_type_class_add_private (object_class, sizeof (GtkCellAreaIterPrivate));
177 }
178
179
180
181 /*************************************************************
182  *                      Cached Sizes                         *
183  *************************************************************/
184 static CachedSize *
185 cached_size_new (gint min_size, 
186                  gint nat_size)
187 {
188   CachedSize *size = g_slice_new (CachedSize);
189
190   size->min_size = min_size;
191   size->nat_size = nat_size;
192
193   return size;
194 }
195
196 static void
197 cached_size_free (CachedSize *size)
198 {
199   g_slice_free (CachedSize, size);
200 }
201
202 /*************************************************************
203  *                      GObjectClass                         *
204  *************************************************************/
205 static void
206 gtk_cell_area_iter_finalize (GObject *object)
207 {
208   GtkCellAreaIter        *iter = GTK_CELL_AREA_ITER (object);
209   GtkCellAreaIterPrivate *priv = iter->priv;
210
211   g_hash_table_destroy (priv->widths);
212   g_hash_table_destroy (priv->heights);
213
214   G_OBJECT_CLASS (gtk_cell_area_iter_parent_class)->finalize (object);
215 }
216
217 static void
218 gtk_cell_area_iter_get_property (GObject     *object,
219                                  guint        prop_id,
220                                  GValue      *value,
221                                  GParamSpec  *pspec)
222 {
223   GtkCellAreaIter        *iter = GTK_CELL_AREA_ITER (object);
224   GtkCellAreaIterPrivate *priv = iter->priv;
225
226   switch (prop_id)
227     {
228     case PROP_MIN_WIDTH:
229       g_value_set_int (value, priv->min_width);
230       break;
231     case PROP_NAT_WIDTH:
232       g_value_set_int (value, priv->nat_width);
233       break;
234     case PROP_MIN_HEIGHT:
235       g_value_set_int (value, priv->min_height);
236       break;
237     case PROP_NAT_HEIGHT:
238       g_value_set_int (value, priv->nat_height);
239       break;
240     default:
241       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
242       break;
243     }
244 }
245
246 /*************************************************************
247  *                    GtkCellAreaIterClass                   *
248  *************************************************************/
249 static void
250 gtk_cell_area_iter_real_flush_preferred_width (GtkCellAreaIter *iter)
251 {
252   GtkCellAreaIterPrivate *priv = iter->priv;
253   
254   priv->min_width = -1;
255   priv->nat_width = -1;
256
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));
261 }
262
263 static void
264 gtk_cell_area_iter_real_flush_preferred_height_for_width (GtkCellAreaIter *iter,
265                                                           gint             width)
266 {
267   GtkCellAreaIterPrivate *priv = iter->priv;
268
269   /* Flush all sizes for special -1 value */
270   if (width < 0)
271     g_hash_table_remove_all (priv->heights);
272   else
273     g_hash_table_remove (priv->heights, GINT_TO_POINTER (width));
274
275   /* XXX Should we bother signalling removed values as "size-changed" signals ? */
276 }
277
278 static void
279 gtk_cell_area_iter_real_flush_preferred_height (GtkCellAreaIter *iter)
280 {
281   GtkCellAreaIterPrivate *priv = iter->priv;
282   
283   priv->min_height = -1;
284   priv->nat_height = -1;
285
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));
290 }
291
292 static void
293 gtk_cell_area_iter_real_flush_preferred_width_for_height (GtkCellAreaIter *iter,
294                                                           gint             height)
295 {
296   GtkCellAreaIterPrivate *priv = iter->priv;
297
298   /* Flush all sizes for special -1 value */
299   if (height < 0)
300     g_hash_table_remove_all (priv->widths);
301   else
302     g_hash_table_remove (priv->widths, GINT_TO_POINTER (height));
303
304   /* XXX Should we bother signalling removed values as "size-changed" signals ? */
305 }
306
307 /*************************************************************
308  *                            API                            *
309  *************************************************************/
310
311 void
312 gtk_cell_area_iter_get_preferred_width (GtkCellAreaIter *iter,
313                                         gint            *minimum_width,
314                                         gint            *natural_width)
315 {
316   GtkCellAreaIterPrivate *priv;
317
318   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
319
320   priv = iter->priv;
321
322   if (minimum_width)
323     *minimum_width = priv->min_width;
324
325   if (natural_width)
326     *natural_width = priv->nat_width;
327 }
328
329 void
330 gtk_cell_area_iter_get_preferred_height_for_width (GtkCellAreaIter *iter,
331                                                    gint             for_width,
332                                                    gint            *minimum_height,
333                                                    gint            *natural_height)
334 {
335   GtkCellAreaIterPrivate *priv;
336   CachedSize             *size;
337
338   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
339
340   priv = iter->priv;
341
342   size = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
343
344   if (size)
345     {
346       if (minimum_height)
347         *minimum_height = size->min_size;
348
349       if (natural_height)
350         *natural_height = size->nat_size;
351     }
352   else
353     {
354       if (minimum_height)
355         *minimum_height = -1;
356
357       if (natural_height)
358         *natural_height = -1;
359     }
360 }
361
362 void
363 gtk_cell_area_iter_get_preferred_height (GtkCellAreaIter *iter,
364                                          gint            *minimum_height,
365                                          gint            *natural_height)
366 {
367   GtkCellAreaIterPrivate *priv;
368
369   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
370
371   priv = iter->priv;
372
373   if (minimum_height)
374     *minimum_height = priv->min_height;
375
376   if (natural_height)
377     *natural_height = priv->nat_height;
378 }
379
380 void
381 gtk_cell_area_iter_get_preferred_width_for_height (GtkCellAreaIter *iter,
382                                                    gint             for_height,
383                                                    gint            *minimum_width,
384                                                    gint            *natural_width)
385 {
386   GtkCellAreaIterPrivate *priv;
387   CachedSize             *size;
388
389   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
390
391   priv = iter->priv;
392
393   size = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
394
395   if (size)
396     {
397       if (minimum_width)
398         *minimum_width = size->min_size;
399
400       if (natural_width)
401         *natural_width = size->nat_size;
402     }
403   else
404     {
405       if (minimum_width)
406         *minimum_width = -1;
407
408       if (natural_width)
409         *natural_width = -1;
410     }
411 }
412
413
414 void
415 gtk_cell_area_iter_push_preferred_width (GtkCellAreaIter *iter,
416                                          gint             minimum_width,
417                                          gint             natural_width)
418 {
419   GtkCellAreaIterPrivate *priv;
420
421   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
422
423   priv = iter->priv;
424
425   g_object_freeze_notify (G_OBJECT (iter));
426
427   if (minimum_width > priv->min_width)
428     {
429       priv->min_width = minimum_width;
430
431       g_object_notify (G_OBJECT (iter), "minimum-width");
432     }
433
434   if (natural_width > priv->nat_width)
435     {
436       priv->nat_width = natural_width;
437
438       g_object_notify (G_OBJECT (iter), "natural-width");
439     }
440
441   g_object_thaw_notify (G_OBJECT (iter));
442 }
443
444 void
445 gtk_cell_area_iter_push_preferred_height_for_width (GtkCellAreaIter *iter,
446                                                     gint             for_width,
447                                                     gint             minimum_height,
448                                                     gint             natural_height)
449 {
450   GtkCellAreaIterPrivate *priv;
451   CachedSize             *size;
452   gboolean                changed = FALSE;
453
454   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
455
456   priv = iter->priv;
457
458   size = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
459
460   if (!size)
461     {
462       size = cached_size_new (minimum_height, natural_height);
463
464       g_hash_table_insert (priv->heights, GINT_TO_POINTER (for_width), size);
465
466       changed = TRUE;
467     }
468   else
469     {
470       if (minimum_height > size->min_size)
471         {
472           size->min_size = minimum_height;
473           changed = TRUE;
474         }
475
476       if (natural_height > size->nat_size)
477         {
478           size->nat_size = natural_height;
479           changed = TRUE;
480         }
481     }
482   
483   if (changed)
484     g_signal_emit (iter, cell_area_iter_signals[SIGNAL_HEIGHT_CHANGED], 0, 
485                    for_width, size->min_size, size->nat_size);
486 }
487
488 void
489 gtk_cell_area_iter_push_preferred_height (GtkCellAreaIter *iter,
490                                           gint             minimum_height,
491                                           gint             natural_height)
492 {
493   GtkCellAreaIterPrivate *priv;
494   
495   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
496
497   priv = iter->priv;
498
499   g_object_freeze_notify (G_OBJECT (iter));
500
501   if (minimum_height > priv->min_height)
502     {
503       priv->min_height = minimum_height;
504
505       g_object_notify (G_OBJECT (iter), "minimum-height");
506     }
507
508   if (natural_height > priv->nat_height)
509     {
510       priv->nat_height = natural_height;
511
512       g_object_notify (G_OBJECT (iter), "natural-height");
513     }
514
515   g_object_thaw_notify (G_OBJECT (iter));
516 }
517
518 void
519 gtk_cell_area_iter_push_preferred_width_for_height (GtkCellAreaIter *iter,
520                                                     gint             for_height,
521                                                     gint             minimum_width,
522                                                     gint             natural_width)
523 {
524   GtkCellAreaIterPrivate *priv;
525   CachedSize             *size;
526   gboolean                changed = FALSE;
527
528   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
529
530   priv = iter->priv;
531
532   size = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
533
534   if (!size)
535     {
536       size = cached_size_new (minimum_width, natural_width);
537
538       g_hash_table_insert (priv->widths, GINT_TO_POINTER (for_height), size);
539
540       changed = TRUE;
541     }
542   else
543     {
544       if (minimum_width > size->min_size)
545         {
546           size->min_size = minimum_width;
547           changed = TRUE;
548         }
549
550       if (natural_width > size->nat_size)
551         {
552           size->nat_size = natural_width;
553           changed = TRUE;
554         }
555     }
556   
557   if (changed)
558     g_signal_emit (iter, cell_area_iter_signals[SIGNAL_WIDTH_CHANGED], 0, 
559                    for_height, size->min_size, size->nat_size);
560 }
561
562 void
563 gtk_cell_area_iter_flush (GtkCellAreaIter *iter)
564 {
565   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
566
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);
571 }
572
573 void
574 gtk_cell_area_iter_flush_preferred_width (GtkCellAreaIter *iter)
575 {
576   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
577
578   GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_width (iter);
579 }
580
581 void
582 gtk_cell_area_iter_flush_preferred_height_for_width (GtkCellAreaIter *iter,
583                                                      gint             for_width)
584 {
585   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
586
587   GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_height_for_width (iter, for_width);
588 }
589
590 void
591 gtk_cell_area_iter_flush_preferred_height (GtkCellAreaIter *iter)
592 {
593   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
594
595   GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_height (iter);
596 }
597
598 void
599 gtk_cell_area_iter_flush_preferred_width_for_height (GtkCellAreaIter *iter,
600                                                      gint             for_height)
601 {
602   g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
603
604   GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_width_for_height (iter, for_height);
605 }