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