]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellrendererpixbuf.c
cellrendererpix: use gtk_render_icon()
[~andy/gtk] / gtk / gtkcellrendererpixbuf.c
1 /* gtkcellrendererpixbuf.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21 #include <stdlib.h>
22 #include "gtkcellrendererpixbuf.h"
23 #include "gtkiconfactory.h"
24 #include "gtkicontheme.h"
25 #include "gtkintl.h"
26 #include "gtkprivate.h"
27
28
29 /**
30  * SECTION:gtkcellrendererpixbuf
31  * @Short_description: Renders a pixbuf in a cell
32  * @Title: GtkCellRendererPixbuf
33  *
34  * A #GtkCellRendererPixbuf can be used to render an image in a cell. It allows
35  * to render either a given #GdkPixbuf (set via the
36  * #GtkCellRendererPixbuf:pixbuf property) or a stock icon (set via the
37  * #GtkCellRendererPixbuf:stock-id property).
38  *
39  * To support the tree view, #GtkCellRendererPixbuf also supports rendering two
40  * alternative pixbufs, when the #GtkCellRenderer:is-expander property is %TRUE.
41  * If the #GtkCellRenderer:is-expanded property is %TRUE and the
42  * #GtkCellRendererPixbuf:pixbuf-expander-open property is set to a pixbuf, it
43  * renders that pixbuf, if the #GtkCellRenderer:is-expanded property is %FALSE
44  * and the #GtkCellRendererPixbuf:pixbuf-expander-closed property is set to a
45  * pixbuf, it renders that one.
46  */
47
48
49 static void gtk_cell_renderer_pixbuf_get_property  (GObject                    *object,
50                                                     guint                       param_id,
51                                                     GValue                     *value,
52                                                     GParamSpec                 *pspec);
53 static void gtk_cell_renderer_pixbuf_set_property  (GObject                    *object,
54                                                     guint                       param_id,
55                                                     const GValue               *value,
56                                                     GParamSpec                 *pspec);
57 static void gtk_cell_renderer_pixbuf_finalize   (GObject                    *object);
58 static void gtk_cell_renderer_pixbuf_create_stock_pixbuf (GtkCellRendererPixbuf *cellpixbuf,
59                                                           GtkWidget             *widget);
60 static void gtk_cell_renderer_pixbuf_get_size   (GtkCellRenderer            *cell,
61                                                  GtkWidget                  *widget,
62                                                  const GdkRectangle         *rectangle,
63                                                  gint                       *x_offset,
64                                                  gint                       *y_offset,
65                                                  gint                       *width,
66                                                  gint                       *height);
67 static void gtk_cell_renderer_pixbuf_render     (GtkCellRenderer            *cell,
68                                                  cairo_t                    *cr,
69                                                  GtkWidget                  *widget,
70                                                  const GdkRectangle         *background_area,
71                                                  const GdkRectangle         *cell_area,
72                                                  GtkCellRendererState        flags);
73
74
75 enum {
76   PROP_0,
77   PROP_PIXBUF,
78   PROP_PIXBUF_EXPANDER_OPEN,
79   PROP_PIXBUF_EXPANDER_CLOSED,
80   PROP_STOCK_ID,
81   PROP_STOCK_SIZE,
82   PROP_STOCK_DETAIL,
83   PROP_FOLLOW_STATE,
84   PROP_ICON_NAME,
85   PROP_GICON
86 };
87
88
89 struct _GtkCellRendererPixbufPrivate
90 {
91   GdkPixbuf *pixbuf;
92   GdkPixbuf *pixbuf_expander_open;
93   GdkPixbuf *pixbuf_expander_closed;
94
95   GIcon *gicon;
96
97   GtkIconSize stock_size;
98
99   gboolean follow_state;
100
101   gchar *stock_id;
102   gchar *stock_detail;
103   gchar *icon_name;
104 };
105
106
107 G_DEFINE_TYPE (GtkCellRendererPixbuf, gtk_cell_renderer_pixbuf, GTK_TYPE_CELL_RENDERER)
108
109
110 static void
111 gtk_cell_renderer_pixbuf_init (GtkCellRendererPixbuf *cellpixbuf)
112 {
113   GtkCellRendererPixbufPrivate *priv;
114
115   cellpixbuf->priv = G_TYPE_INSTANCE_GET_PRIVATE (cellpixbuf,
116                                                   GTK_TYPE_CELL_RENDERER_PIXBUF,
117                                                   GtkCellRendererPixbufPrivate);
118   priv = cellpixbuf->priv;
119
120   priv->stock_size = GTK_ICON_SIZE_MENU;
121 }
122
123 static void
124 gtk_cell_renderer_pixbuf_class_init (GtkCellRendererPixbufClass *class)
125 {
126   GObjectClass *object_class = G_OBJECT_CLASS (class);
127   GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class);
128
129   object_class->finalize = gtk_cell_renderer_pixbuf_finalize;
130
131   object_class->get_property = gtk_cell_renderer_pixbuf_get_property;
132   object_class->set_property = gtk_cell_renderer_pixbuf_set_property;
133
134   cell_class->get_size = gtk_cell_renderer_pixbuf_get_size;
135   cell_class->render = gtk_cell_renderer_pixbuf_render;
136
137   g_object_class_install_property (object_class,
138                                    PROP_PIXBUF,
139                                    g_param_spec_object ("pixbuf",
140                                                         P_("Pixbuf Object"),
141                                                         P_("The pixbuf to render"),
142                                                         GDK_TYPE_PIXBUF,
143                                                         GTK_PARAM_READWRITE));
144
145   g_object_class_install_property (object_class,
146                                    PROP_PIXBUF_EXPANDER_OPEN,
147                                    g_param_spec_object ("pixbuf-expander-open",
148                                                         P_("Pixbuf Expander Open"),
149                                                         P_("Pixbuf for open expander"),
150                                                         GDK_TYPE_PIXBUF,
151                                                         GTK_PARAM_READWRITE));
152
153   g_object_class_install_property (object_class,
154                                    PROP_PIXBUF_EXPANDER_CLOSED,
155                                    g_param_spec_object ("pixbuf-expander-closed",
156                                                         P_("Pixbuf Expander Closed"),
157                                                         P_("Pixbuf for closed expander"),
158                                                         GDK_TYPE_PIXBUF,
159                                                         GTK_PARAM_READWRITE));
160
161   g_object_class_install_property (object_class,
162                                    PROP_STOCK_ID,
163                                    g_param_spec_string ("stock-id",
164                                                         P_("Stock ID"),
165                                                         P_("The stock ID of the stock icon to render"),
166                                                         NULL,
167                                                         GTK_PARAM_READWRITE));
168
169   g_object_class_install_property (object_class,
170                                    PROP_STOCK_SIZE,
171                                    g_param_spec_uint ("stock-size",
172                                                       P_("Size"),
173                                                       P_("The GtkIconSize value that specifies the size of the rendered icon"),
174                                                       0,
175                                                       G_MAXUINT,
176                                                       GTK_ICON_SIZE_MENU,
177                                                       GTK_PARAM_READWRITE));
178
179   g_object_class_install_property (object_class,
180                                    PROP_STOCK_DETAIL,
181                                    g_param_spec_string ("stock-detail",
182                                                         P_("Detail"),
183                                                         P_("Render detail to pass to the theme engine"),
184                                                         NULL,
185                                                         GTK_PARAM_READWRITE));
186
187   
188   /**
189    * GtkCellRendererPixbuf:icon-name:
190    *
191    * The name of the themed icon to display.
192    * This property only has an effect if not overridden by "stock_id" 
193    * or "pixbuf" properties.
194    *
195    * Since: 2.8 
196    */
197   g_object_class_install_property (object_class,
198                                    PROP_ICON_NAME,
199                                    g_param_spec_string ("icon-name",
200                                                         P_("Icon Name"),
201                                                         P_("The name of the icon from the icon theme"),
202                                                         NULL,
203                                                         GTK_PARAM_READWRITE));
204
205   /**
206    * GtkCellRendererPixbuf:follow-state:
207    *
208    * Specifies whether the rendered pixbuf should be colorized
209    * according to the #GtkCellRendererState.
210    *
211    * Since: 2.8
212    */
213   g_object_class_install_property (object_class,
214                                    PROP_FOLLOW_STATE,
215                                    g_param_spec_boolean ("follow-state",
216                                                          P_("Follow State"),
217                                                          P_("Whether the rendered pixbuf should be "
218                                                             "colorized according to the state"),
219                                                          FALSE,
220                                                          GTK_PARAM_READWRITE));
221
222   /**
223    * GtkCellRendererPixbuf:gicon:
224    *
225    * The GIcon representing the icon to display.
226    * If the icon theme is changed, the image will be updated
227    * automatically.
228    *
229    * Since: 2.14
230    */
231   g_object_class_install_property (object_class,
232                                    PROP_GICON,
233                                    g_param_spec_object ("gicon",
234                                                         P_("Icon"),
235                                                         P_("The GIcon being displayed"),
236                                                         G_TYPE_ICON,
237                                                         GTK_PARAM_READWRITE));
238
239
240
241   g_type_class_add_private (object_class, sizeof (GtkCellRendererPixbufPrivate));
242 }
243
244 static void
245 gtk_cell_renderer_pixbuf_finalize (GObject *object)
246 {
247   GtkCellRendererPixbuf *cellpixbuf = GTK_CELL_RENDERER_PIXBUF (object);
248   GtkCellRendererPixbufPrivate *priv = cellpixbuf->priv;
249
250   if (priv->pixbuf)
251     g_object_unref (priv->pixbuf);
252   if (priv->pixbuf_expander_open)
253     g_object_unref (priv->pixbuf_expander_open);
254   if (priv->pixbuf_expander_closed)
255     g_object_unref (priv->pixbuf_expander_closed);
256
257   g_free (priv->stock_id);
258   g_free (priv->stock_detail);
259   g_free (priv->icon_name);
260
261   if (priv->gicon)
262     g_object_unref (priv->gicon);
263
264   G_OBJECT_CLASS (gtk_cell_renderer_pixbuf_parent_class)->finalize (object);
265 }
266
267 static void
268 gtk_cell_renderer_pixbuf_get_property (GObject        *object,
269                                        guint           param_id,
270                                        GValue         *value,
271                                        GParamSpec     *pspec)
272 {
273   GtkCellRendererPixbuf *cellpixbuf = GTK_CELL_RENDERER_PIXBUF (object);
274   GtkCellRendererPixbufPrivate *priv = cellpixbuf->priv;
275
276   switch (param_id)
277     {
278     case PROP_PIXBUF:
279       g_value_set_object (value, priv->pixbuf);
280       break;
281     case PROP_PIXBUF_EXPANDER_OPEN:
282       g_value_set_object (value, priv->pixbuf_expander_open);
283       break;
284     case PROP_PIXBUF_EXPANDER_CLOSED:
285       g_value_set_object (value, priv->pixbuf_expander_closed);
286       break;
287     case PROP_STOCK_ID:
288       g_value_set_string (value, priv->stock_id);
289       break;
290     case PROP_STOCK_SIZE:
291       g_value_set_uint (value, priv->stock_size);
292       break;
293     case PROP_STOCK_DETAIL:
294       g_value_set_string (value, priv->stock_detail);
295       break;
296     case PROP_FOLLOW_STATE:
297       g_value_set_boolean (value, priv->follow_state);
298       break;
299     case PROP_ICON_NAME:
300       g_value_set_string (value, priv->icon_name);
301       break;
302     case PROP_GICON:
303       g_value_set_object (value, priv->gicon);
304       break;
305     default:
306       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
307       break;
308     }
309 }
310
311 static void
312 gtk_cell_renderer_pixbuf_set_property (GObject      *object,
313                                        guint         param_id,
314                                        const GValue *value,
315                                        GParamSpec   *pspec)
316 {
317   GtkCellRendererPixbuf *cellpixbuf = GTK_CELL_RENDERER_PIXBUF (object);
318   GtkCellRendererPixbufPrivate *priv = cellpixbuf->priv;
319
320   switch (param_id)
321     {
322     case PROP_PIXBUF:
323       if (priv->pixbuf)
324         g_object_unref (priv->pixbuf);
325       priv->pixbuf = (GdkPixbuf*) g_value_dup_object (value);
326       if (priv->pixbuf)
327         {
328           if (priv->stock_id)
329             {
330               g_free (priv->stock_id);
331               priv->stock_id = NULL;
332               g_object_notify (object, "stock-id");
333             }
334           if (priv->icon_name)
335             {
336               g_free (priv->icon_name);
337               priv->icon_name = NULL;
338               g_object_notify (object, "icon-name");
339             }
340           if (priv->gicon)
341             {
342               g_object_unref (priv->gicon);
343               priv->gicon = NULL;
344               g_object_notify (object, "gicon");
345             }
346         }
347       break;
348     case PROP_PIXBUF_EXPANDER_OPEN:
349       if (priv->pixbuf_expander_open)
350         g_object_unref (priv->pixbuf_expander_open);
351       priv->pixbuf_expander_open = (GdkPixbuf*) g_value_dup_object (value);
352       break;
353     case PROP_PIXBUF_EXPANDER_CLOSED:
354       if (priv->pixbuf_expander_closed)
355         g_object_unref (priv->pixbuf_expander_closed);
356       priv->pixbuf_expander_closed = (GdkPixbuf*) g_value_dup_object (value);
357       break;
358     case PROP_STOCK_ID:
359       if (priv->stock_id)
360         {
361           if (priv->pixbuf)
362             {
363               g_object_unref (priv->pixbuf);
364               priv->pixbuf = NULL;
365               g_object_notify (object, "pixbuf");
366             }
367           g_free (priv->stock_id);
368         }
369       priv->stock_id = g_value_dup_string (value);
370       if (priv->stock_id)
371         {
372           if (priv->pixbuf)
373             {
374               g_object_unref (priv->pixbuf);
375               priv->pixbuf = NULL;
376               g_object_notify (object, "pixbuf");
377             }
378           if (priv->icon_name)
379             {
380               g_free (priv->icon_name);
381               priv->icon_name = NULL;
382               g_object_notify (object, "icon-name");
383             }
384           if (priv->gicon)
385             {
386               g_object_unref (priv->gicon);
387               priv->gicon = NULL;
388               g_object_notify (object, "gicon");
389             }
390         }
391       break;
392     case PROP_STOCK_SIZE:
393       priv->stock_size = g_value_get_uint (value);
394       break;
395     case PROP_STOCK_DETAIL:
396       g_free (priv->stock_detail);
397       priv->stock_detail = g_value_dup_string (value);
398       break;
399     case PROP_ICON_NAME:
400       if (priv->icon_name)
401         {
402           if (priv->pixbuf)
403             {
404               g_object_unref (priv->pixbuf);
405               priv->pixbuf = NULL;
406               g_object_notify (object, "pixbuf");
407             }
408           g_free (priv->icon_name);
409         }
410       priv->icon_name = g_value_dup_string (value);
411       if (priv->icon_name)
412         {
413           if (priv->pixbuf)
414             {
415               g_object_unref (priv->pixbuf);
416               priv->pixbuf = NULL;
417               g_object_notify (object, "pixbuf");
418             }
419           if (priv->stock_id)
420             {
421               g_free (priv->stock_id);
422               priv->stock_id = NULL;
423               g_object_notify (object, "stock-id");
424             }
425           if (priv->gicon)
426             {
427               g_object_unref (priv->gicon);
428               priv->gicon = NULL;
429               g_object_notify (object, "gicon");
430             }
431         }
432       break;
433     case PROP_FOLLOW_STATE:
434       priv->follow_state = g_value_get_boolean (value);
435       break;
436     case PROP_GICON:
437       if (priv->gicon)
438         {
439           if (priv->pixbuf)
440             {
441               g_object_unref (priv->pixbuf);
442               priv->pixbuf = NULL;
443               g_object_notify (object, "pixbuf");
444             }
445           g_object_unref (priv->gicon);
446         }
447       priv->gicon = (GIcon *) g_value_dup_object (value);
448       if (priv->gicon)
449         {
450           if (priv->pixbuf)
451             {
452               g_object_unref (priv->pixbuf);
453               priv->pixbuf = NULL;
454               g_object_notify (object, "pixbuf");
455             }
456           if (priv->stock_id)
457             {
458               g_free (priv->stock_id);
459               priv->stock_id = NULL;
460               g_object_notify (object, "stock-id");
461             }
462           if (priv->icon_name)
463             {
464               g_free (priv->icon_name);
465               priv->icon_name = NULL;
466               g_object_notify (object, "icon-name");
467             }
468         }
469       break;
470     default:
471       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
472       break;
473     }
474 }
475
476 /**
477  * gtk_cell_renderer_pixbuf_new:
478  * 
479  * Creates a new #GtkCellRendererPixbuf. Adjust rendering
480  * parameters using object properties. Object properties can be set
481  * globally (with g_object_set()). Also, with #GtkTreeViewColumn, you
482  * can bind a property to a value in a #GtkTreeModel. For example, you
483  * can bind the "pixbuf" property on the cell renderer to a pixbuf value
484  * in the model, thus rendering a different image in each row of the
485  * #GtkTreeView.
486  * 
487  * Return value: the new cell renderer
488  **/
489 GtkCellRenderer *
490 gtk_cell_renderer_pixbuf_new (void)
491 {
492   return g_object_new (GTK_TYPE_CELL_RENDERER_PIXBUF, NULL);
493 }
494
495 static void
496 gtk_cell_renderer_pixbuf_create_stock_pixbuf (GtkCellRendererPixbuf *cellpixbuf,
497                                               GtkWidget             *widget)
498 {
499   GtkCellRendererPixbufPrivate *priv = cellpixbuf->priv;
500
501   if (priv->pixbuf)
502     g_object_unref (priv->pixbuf);
503
504   priv->pixbuf = gtk_widget_render_icon_pixbuf (widget,
505                                                 priv->stock_id,
506                                                 priv->stock_size);
507
508   g_object_notify (G_OBJECT (cellpixbuf), "pixbuf");
509 }
510
511 static void 
512 gtk_cell_renderer_pixbuf_create_themed_pixbuf (GtkCellRendererPixbuf *cellpixbuf,
513                                                GtkWidget             *widget)
514 {
515   GtkCellRendererPixbufPrivate *priv = cellpixbuf->priv;
516   GdkScreen *screen;
517   GtkIconTheme *icon_theme;
518   GtkSettings *settings;
519   gint width, height;
520   GtkIconInfo *info;
521
522   if (priv->pixbuf)
523     {
524       g_object_unref (priv->pixbuf);
525       priv->pixbuf = NULL;
526     }
527
528   screen = gtk_widget_get_screen (GTK_WIDGET (widget));
529   icon_theme = gtk_icon_theme_get_for_screen (screen);
530   settings = gtk_settings_get_for_screen (screen);
531
532   if (!gtk_icon_size_lookup_for_settings (settings,
533                                           priv->stock_size,
534                                           &width, &height))
535     {
536       g_warning ("Invalid icon size %u\n", priv->stock_size);
537       width = height = 24;
538     }
539
540   if (priv->icon_name)
541     info = gtk_icon_theme_lookup_icon (icon_theme,
542                                        priv->icon_name,
543                                        MIN (width, height),
544                                        GTK_ICON_LOOKUP_USE_BUILTIN);
545   else if (priv->gicon)
546     info = gtk_icon_theme_lookup_by_gicon (icon_theme,
547                                            priv->gicon,
548                                            MIN (width, height),
549                                            GTK_ICON_LOOKUP_USE_BUILTIN);
550   else
551     info = NULL;
552
553   if (info)
554     {
555       GtkStyleContext *context;
556
557       context = gtk_widget_get_style_context (GTK_WIDGET (widget));
558       priv->pixbuf = gtk_icon_info_load_symbolic_for_context (info,
559                                                               context,
560                                                               NULL,
561                                                               NULL);
562       gtk_icon_info_free (info);
563     }
564
565   g_object_notify (G_OBJECT (cellpixbuf), "pixbuf");
566 }
567
568 static GdkPixbuf *
569 create_symbolic_pixbuf (GtkCellRendererPixbuf *cellpixbuf,
570                         GtkWidget             *widget,
571                         GtkStateFlags          state)
572 {
573   GtkCellRendererPixbufPrivate *priv = cellpixbuf->priv;
574   GdkScreen *screen;
575   GtkIconTheme *icon_theme;
576   GtkSettings *settings;
577   gint width, height;
578   GtkIconInfo *info;
579   GdkPixbuf *pixbuf;
580   gboolean is_symbolic;
581
582   screen = gtk_widget_get_screen (GTK_WIDGET (widget));
583   icon_theme = gtk_icon_theme_get_for_screen (screen);
584   settings = gtk_settings_get_for_screen (screen);
585
586   if (!gtk_icon_size_lookup_for_settings (settings,
587                                           priv->stock_size,
588                                           &width, &height))
589     {
590       g_warning ("Invalid icon size %u\n", priv->stock_size);
591       width = height = 24;
592     }
593
594
595   if (priv->icon_name)
596     info = gtk_icon_theme_lookup_icon (icon_theme,
597                                        priv->icon_name,
598                                        MIN (width, height),
599                                        GTK_ICON_LOOKUP_USE_BUILTIN);
600   else if (priv->gicon)
601     info = gtk_icon_theme_lookup_by_gicon (icon_theme,
602                                            priv->gicon,
603                                            MIN (width, height),
604                                            GTK_ICON_LOOKUP_USE_BUILTIN);
605   else
606     return NULL;
607
608   if (info)
609     {
610       GtkStyleContext *context;
611
612       context = gtk_widget_get_style_context (GTK_WIDGET (widget));
613
614       gtk_style_context_save (context);
615       gtk_style_context_set_state (context, state);
616       pixbuf = gtk_icon_info_load_symbolic_for_context (info,
617                                                         context,
618                                                         &is_symbolic,
619                                                         NULL);
620
621       gtk_style_context_restore (context);
622       gtk_icon_info_free (info);
623
624       if (!is_symbolic)
625         g_clear_object (&pixbuf);
626
627       return pixbuf;
628     }
629
630   return NULL;
631 }
632
633 static void
634 gtk_cell_renderer_pixbuf_get_size (GtkCellRenderer    *cell,
635                                    GtkWidget          *widget,
636                                    const GdkRectangle *cell_area,
637                                    gint               *x_offset,
638                                    gint               *y_offset,
639                                    gint               *width,
640                                    gint               *height)
641 {
642   GtkCellRendererPixbuf *cellpixbuf = (GtkCellRendererPixbuf *) cell;
643   GtkCellRendererPixbufPrivate *priv = cellpixbuf->priv;
644   gint pixbuf_width  = 0;
645   gint pixbuf_height = 0;
646   gint calc_width;
647   gint calc_height;
648   gint xpad, ypad;
649
650   if (!priv->pixbuf)
651     {
652       if (priv->stock_id)
653         gtk_cell_renderer_pixbuf_create_stock_pixbuf (cellpixbuf, widget);
654       else if (priv->icon_name || priv->gicon)
655         gtk_cell_renderer_pixbuf_create_themed_pixbuf (cellpixbuf, widget);
656     }
657   
658   if (priv->pixbuf)
659     {
660       pixbuf_width  = gdk_pixbuf_get_width (priv->pixbuf);
661       pixbuf_height = gdk_pixbuf_get_height (priv->pixbuf);
662     }
663   if (priv->pixbuf_expander_open)
664     {
665       pixbuf_width  = MAX (pixbuf_width, gdk_pixbuf_get_width (priv->pixbuf_expander_open));
666       pixbuf_height = MAX (pixbuf_height, gdk_pixbuf_get_height (priv->pixbuf_expander_open));
667     }
668   if (priv->pixbuf_expander_closed)
669     {
670       pixbuf_width  = MAX (pixbuf_width, gdk_pixbuf_get_width (priv->pixbuf_expander_closed));
671       pixbuf_height = MAX (pixbuf_height, gdk_pixbuf_get_height (priv->pixbuf_expander_closed));
672     }
673
674   gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
675   calc_width  = (gint) xpad * 2 + pixbuf_width;
676   calc_height = (gint) ypad * 2 + pixbuf_height;
677   
678   if (cell_area && pixbuf_width > 0 && pixbuf_height > 0)
679     {
680       gfloat xalign, yalign;
681
682       gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
683       if (x_offset)
684         {
685           *x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
686                         (1.0 - xalign) : xalign) *
687                        (cell_area->width - calc_width));
688           *x_offset = MAX (*x_offset, 0);
689         }
690       if (y_offset)
691         {
692           *y_offset = (yalign *
693                        (cell_area->height - calc_height));
694           *y_offset = MAX (*y_offset, 0);
695         }
696     }
697   else
698     {
699       if (x_offset) *x_offset = 0;
700       if (y_offset) *y_offset = 0;
701     }
702
703   if (width)
704     *width = calc_width;
705   
706   if (height)
707     *height = calc_height;
708 }
709
710 static GdkPixbuf *
711 transform_pixbuf_state (GdkPixbuf *pixbuf,
712                         GtkStyleContext *context)
713 {
714   GtkIconSource *source;
715   GdkPixbuf *retval;
716
717   source = gtk_icon_source_new ();
718   gtk_icon_source_set_pixbuf (source, pixbuf);
719   /* The size here is arbitrary; since size isn't
720    * wildcarded in the source, it isn't supposed to be
721    * scaled by the engine function
722    */
723   gtk_icon_source_set_size (source, GTK_ICON_SIZE_SMALL_TOOLBAR);
724   gtk_icon_source_set_size_wildcarded (source, FALSE);
725
726   retval = gtk_render_icon_pixbuf (context, source,
727                                    (GtkIconSize) -1);
728
729   gtk_icon_source_free (source);
730
731   return retval;
732 }
733
734 static void
735 gtk_cell_renderer_pixbuf_render (GtkCellRenderer      *cell,
736                                  cairo_t              *cr,
737                                  GtkWidget            *widget,
738                                  const GdkRectangle   *background_area,
739                                  const GdkRectangle   *cell_area,
740                                  GtkCellRendererState  flags)
741
742 {
743   GtkCellRendererPixbuf *cellpixbuf = (GtkCellRendererPixbuf *) cell;
744   GtkCellRendererPixbufPrivate *priv = cellpixbuf->priv;
745   GtkStyleContext *context;
746   GdkPixbuf *pixbuf, *stated;
747   GdkRectangle pix_rect;
748   GdkRectangle draw_rect;
749   gboolean is_expander;
750   gint xpad, ypad;
751   gint x, y;
752   GtkStateFlags state;
753
754   gtk_cell_renderer_pixbuf_get_size (cell, widget, (GdkRectangle *) cell_area,
755                                      &x, &y, NULL, NULL);
756
757   gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
758   x += cell_area->x + xpad;
759   y += cell_area->y + ypad;
760
761   if (!gdk_rectangle_intersect (cell_area, &pix_rect, &draw_rect))
762     return;
763
764   pixbuf = priv->pixbuf;
765
766   g_object_get (cell, "is-expander", &is_expander, NULL);
767   if (is_expander)
768     {
769       gboolean is_expanded;
770
771       g_object_get (cell, "is-expanded", &is_expanded, NULL);
772
773       if (is_expanded &&
774           priv->pixbuf_expander_open != NULL)
775         pixbuf = priv->pixbuf_expander_open;
776       else if (!is_expanded &&
777                priv->pixbuf_expander_closed != NULL)
778         pixbuf = priv->pixbuf_expander_closed;
779     }
780
781   if (!pixbuf)
782     return;
783
784   g_object_ref (pixbuf);
785
786   context = gtk_widget_get_style_context (widget);
787   gtk_style_context_save (context);
788
789   state = GTK_STATE_FLAG_NORMAL;
790
791   if (!gtk_widget_get_sensitive (widget) ||
792       !gtk_cell_renderer_get_sensitive (cell))
793     state |= GTK_STATE_FLAG_INSENSITIVE;
794   else if (priv->follow_state && 
795            (flags & (GTK_CELL_RENDERER_SELECTED |
796                      GTK_CELL_RENDERER_PRELIT)) != 0)
797     state = gtk_cell_renderer_get_state (cell, widget, flags);
798
799   if (state != GTK_STATE_FLAG_NORMAL)
800     {
801       stated = create_symbolic_pixbuf (cellpixbuf, widget, state);
802
803       if (!stated)
804         stated = transform_pixbuf_state (pixbuf, context);
805
806       g_object_unref (pixbuf);
807       pixbuf = stated;
808     }
809
810   gtk_render_icon (context, cr, pixbuf, x, y);
811
812   gtk_style_context_restore (context);
813   g_object_unref (pixbuf);
814 }