]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellrendererpixbuf.c
Merge branch 'master' into broadway
[~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 (widget,
485                                                priv->stock_id,
486                                                priv->stock_size,
487                                                priv->stock_detail);
488
489   g_object_notify (G_OBJECT (cellpixbuf), "pixbuf");
490 }
491
492 static void 
493 gtk_cell_renderer_pixbuf_create_themed_pixbuf (GtkCellRendererPixbuf *cellpixbuf,
494                                                GtkWidget             *widget)
495 {
496   GtkCellRendererPixbufPrivate *priv = cellpixbuf->priv;
497   GdkScreen *screen;
498   GtkIconTheme *icon_theme;
499   GtkSettings *settings;
500   gint width, height;
501   GtkIconInfo *info;
502
503   if (priv->pixbuf)
504     {
505       g_object_unref (priv->pixbuf);
506       priv->pixbuf = NULL;
507     }
508
509   screen = gtk_widget_get_screen (GTK_WIDGET (widget));
510   icon_theme = gtk_icon_theme_get_for_screen (screen);
511   settings = gtk_settings_get_for_screen (screen);
512
513   if (!gtk_icon_size_lookup_for_settings (settings,
514                                           priv->stock_size,
515                                           &width, &height))
516     {
517       g_warning ("Invalid icon size %u\n", priv->stock_size);
518       width = height = 24;
519     }
520
521   if (priv->icon_name)
522     info = gtk_icon_theme_lookup_icon (icon_theme,
523                                        priv->icon_name,
524                                        MIN (width, height),
525                                        GTK_ICON_LOOKUP_USE_BUILTIN);
526   else if (priv->gicon)
527     info = gtk_icon_theme_lookup_by_gicon (icon_theme,
528                                            priv->gicon,
529                                            MIN (width, height),
530                                            GTK_ICON_LOOKUP_USE_BUILTIN);
531   else
532     info = NULL;
533
534   if (info)
535     {
536       GtkStyleContext *context;
537
538       context = gtk_widget_get_style_context (GTK_WIDGET (widget));
539       priv->pixbuf = gtk_icon_info_load_symbolic_for_context (info,
540                                                               context,
541                                                               NULL,
542                                                               NULL);
543       gtk_icon_info_free (info);
544     }
545
546   g_object_notify (G_OBJECT (cellpixbuf), "pixbuf");
547 }
548
549 static GdkPixbuf *
550 create_symbolic_pixbuf (GtkCellRendererPixbuf *cellpixbuf,
551                         GtkWidget             *widget,
552                         GtkStateType           state)
553 {
554   GtkCellRendererPixbufPrivate *priv = cellpixbuf->priv;
555   GdkScreen *screen;
556   GtkIconTheme *icon_theme;
557   GtkSettings *settings;
558   gint width, height;
559   GtkIconInfo *info;
560   GdkPixbuf *pixbuf;
561
562   /* Not a named symbolic icon? */
563   if (priv->icon_name) {
564     if (!g_str_has_suffix (priv->icon_name, "-symbolic"))
565       return NULL;
566   } else if (priv->gicon) {
567     const gchar * const *names;
568     if (!G_IS_THEMED_ICON (priv->gicon))
569       return NULL;
570     names = g_themed_icon_get_names (G_THEMED_ICON (priv->gicon));
571     if (names == NULL || !g_str_has_suffix (names[0], "-symbolic"))
572       return NULL;
573   } else {
574     return NULL;
575   }
576
577   screen = gtk_widget_get_screen (GTK_WIDGET (widget));
578   icon_theme = gtk_icon_theme_get_for_screen (screen);
579   settings = gtk_settings_get_for_screen (screen);
580
581   if (!gtk_icon_size_lookup_for_settings (settings,
582                                           priv->stock_size,
583                                           &width, &height))
584     {
585       g_warning ("Invalid icon size %u\n", priv->stock_size);
586       width = height = 24;
587     }
588
589
590   if (priv->icon_name)
591     info = gtk_icon_theme_lookup_icon (icon_theme,
592                                        priv->icon_name,
593                                        MIN (width, height),
594                                        GTK_ICON_LOOKUP_USE_BUILTIN);
595   else if (priv->gicon)
596     info = gtk_icon_theme_lookup_by_gicon (icon_theme,
597                                            priv->gicon,
598                                            MIN (width, height),
599                                            GTK_ICON_LOOKUP_USE_BUILTIN);
600   else
601     return NULL;
602
603   if (info)
604     {
605       GtkStyleContext *context;
606
607       context = gtk_widget_get_style_context (GTK_WIDGET (widget));
608       pixbuf = gtk_icon_info_load_symbolic_for_context (info,
609                                                         context,
610                                                         NULL,
611                                                         NULL);
612       gtk_icon_info_free (info);
613       return pixbuf;
614     }
615
616   return NULL;
617 }
618
619 static GdkPixbuf *
620 create_colorized_pixbuf (GdkPixbuf *src, 
621                          GdkColor  *new_color)
622 {
623   gint i, j;
624   gint width, height, has_alpha, src_row_stride, dst_row_stride;
625   gint red_value, green_value, blue_value;
626   guchar *target_pixels;
627   guchar *original_pixels;
628   guchar *pixsrc;
629   guchar *pixdest;
630   GdkPixbuf *dest;
631   
632   red_value = new_color->red / 255.0;
633   green_value = new_color->green / 255.0;
634   blue_value = new_color->blue / 255.0;
635   
636   dest = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src),
637                          gdk_pixbuf_get_has_alpha (src),
638                          gdk_pixbuf_get_bits_per_sample (src),
639                          gdk_pixbuf_get_width (src),
640                          gdk_pixbuf_get_height (src));
641   
642   has_alpha = gdk_pixbuf_get_has_alpha (src);
643   width = gdk_pixbuf_get_width (src);
644   height = gdk_pixbuf_get_height (src);
645   src_row_stride = gdk_pixbuf_get_rowstride (src);
646   dst_row_stride = gdk_pixbuf_get_rowstride (dest);
647   target_pixels = gdk_pixbuf_get_pixels (dest);
648   original_pixels = gdk_pixbuf_get_pixels (src);
649   
650   for (i = 0; i < height; i++) {
651     pixdest = target_pixels + i*dst_row_stride;
652     pixsrc = original_pixels + i*src_row_stride;
653     for (j = 0; j < width; j++) {               
654       *pixdest++ = (*pixsrc++ * red_value) >> 8;
655       *pixdest++ = (*pixsrc++ * green_value) >> 8;
656       *pixdest++ = (*pixsrc++ * blue_value) >> 8;
657       if (has_alpha) {
658         *pixdest++ = *pixsrc++;
659       }
660     }
661   }
662   return dest;
663 }
664
665
666 static void
667 gtk_cell_renderer_pixbuf_get_size (GtkCellRenderer    *cell,
668                                    GtkWidget          *widget,
669                                    const GdkRectangle *cell_area,
670                                    gint               *x_offset,
671                                    gint               *y_offset,
672                                    gint               *width,
673                                    gint               *height)
674 {
675   GtkCellRendererPixbuf *cellpixbuf = (GtkCellRendererPixbuf *) cell;
676   GtkCellRendererPixbufPrivate *priv = cellpixbuf->priv;
677   gint pixbuf_width  = 0;
678   gint pixbuf_height = 0;
679   gint calc_width;
680   gint calc_height;
681   gint xpad, ypad;
682
683   if (!priv->pixbuf)
684     {
685       if (priv->stock_id)
686         gtk_cell_renderer_pixbuf_create_stock_pixbuf (cellpixbuf, widget);
687       else if (priv->icon_name || priv->gicon)
688         gtk_cell_renderer_pixbuf_create_themed_pixbuf (cellpixbuf, widget);
689     }
690   
691   if (priv->pixbuf)
692     {
693       pixbuf_width  = gdk_pixbuf_get_width (priv->pixbuf);
694       pixbuf_height = gdk_pixbuf_get_height (priv->pixbuf);
695     }
696   if (priv->pixbuf_expander_open)
697     {
698       pixbuf_width  = MAX (pixbuf_width, gdk_pixbuf_get_width (priv->pixbuf_expander_open));
699       pixbuf_height = MAX (pixbuf_height, gdk_pixbuf_get_height (priv->pixbuf_expander_open));
700     }
701   if (priv->pixbuf_expander_closed)
702     {
703       pixbuf_width  = MAX (pixbuf_width, gdk_pixbuf_get_width (priv->pixbuf_expander_closed));
704       pixbuf_height = MAX (pixbuf_height, gdk_pixbuf_get_height (priv->pixbuf_expander_closed));
705     }
706
707   gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
708   calc_width  = (gint) xpad * 2 + pixbuf_width;
709   calc_height = (gint) ypad * 2 + pixbuf_height;
710   
711   if (cell_area && pixbuf_width > 0 && pixbuf_height > 0)
712     {
713       gfloat xalign, yalign;
714
715       gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
716       if (x_offset)
717         {
718           *x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
719                         (1.0 - xalign) : xalign) *
720                        (cell_area->width - calc_width));
721           *x_offset = MAX (*x_offset, 0);
722         }
723       if (y_offset)
724         {
725           *y_offset = (yalign *
726                        (cell_area->height - calc_height));
727           *y_offset = MAX (*y_offset, 0);
728         }
729     }
730   else
731     {
732       if (x_offset) *x_offset = 0;
733       if (y_offset) *y_offset = 0;
734     }
735
736   if (width)
737     *width = calc_width;
738   
739   if (height)
740     *height = calc_height;
741 }
742
743 static void
744 gtk_cell_renderer_pixbuf_render (GtkCellRenderer      *cell,
745                                  cairo_t              *cr,
746                                  GtkWidget            *widget,
747                                  const GdkRectangle   *background_area,
748                                  const GdkRectangle   *cell_area,
749                                  GtkCellRendererState  flags)
750
751 {
752   GtkCellRendererPixbuf *cellpixbuf = (GtkCellRendererPixbuf *) cell;
753   GtkCellRendererPixbufPrivate *priv = cellpixbuf->priv;
754   GdkPixbuf *pixbuf;
755   GdkPixbuf *invisible = NULL;
756   GdkPixbuf *colorized = NULL;
757   GdkPixbuf *symbolic = NULL;
758   GdkRectangle pix_rect;
759   GdkRectangle draw_rect;
760   gboolean is_expander;
761   gint xpad, ypad;
762
763   gtk_cell_renderer_pixbuf_get_size (cell, widget, (GdkRectangle *) cell_area,
764                                      &pix_rect.x,
765                                      &pix_rect.y,
766                                      &pix_rect.width,
767                                      &pix_rect.height);
768
769   gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
770   pix_rect.x += cell_area->x + xpad;
771   pix_rect.y += cell_area->y + ypad;
772   pix_rect.width  -= xpad * 2;
773   pix_rect.height -= ypad * 2;
774
775   if (!gdk_rectangle_intersect (cell_area, &pix_rect, &draw_rect))
776     return;
777
778   pixbuf = priv->pixbuf;
779
780   g_object_get (cell, "is-expander", &is_expander, NULL);
781   if (is_expander)
782     {
783       gboolean is_expanded;
784
785       g_object_get (cell, "is-expanded", &is_expanded, NULL);
786
787       if (is_expanded &&
788           priv->pixbuf_expander_open != NULL)
789         pixbuf = priv->pixbuf_expander_open;
790       else if (!is_expanded &&
791                priv->pixbuf_expander_closed != NULL)
792         pixbuf = priv->pixbuf_expander_closed;
793     }
794
795   if (!pixbuf)
796     return;
797
798   if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE ||
799       !gtk_cell_renderer_get_sensitive (cell))
800     {
801       GtkIconSource *source;
802       
803       source = gtk_icon_source_new ();
804       gtk_icon_source_set_pixbuf (source, pixbuf);
805       /* The size here is arbitrary; since size isn't
806        * wildcarded in the source, it isn't supposed to be
807        * scaled by the engine function
808        */
809       gtk_icon_source_set_size (source, GTK_ICON_SIZE_SMALL_TOOLBAR);
810       gtk_icon_source_set_size_wildcarded (source, FALSE);
811
812      invisible = gtk_style_render_icon (gtk_widget_get_style (widget),
813                                         source,
814                                         gtk_widget_get_direction (widget),
815                                         GTK_STATE_INSENSITIVE,
816                                         /* arbitrary */
817                                         (GtkIconSize)-1,
818                                         widget,
819                                         "gtkcellrendererpixbuf");
820      
821      gtk_icon_source_free (source);
822      
823      pixbuf = invisible;
824     }
825   else if (priv->follow_state && 
826            (flags & (GTK_CELL_RENDERER_SELECTED|GTK_CELL_RENDERER_PRELIT)) != 0)
827     {
828       GtkStateType state;
829
830       if ((flags & GTK_CELL_RENDERER_SELECTED) != 0)
831         {
832           if (gtk_widget_has_focus (widget))
833             state = GTK_STATE_SELECTED;
834           else
835             state = GTK_STATE_ACTIVE;
836         }
837       else
838         state = GTK_STATE_PRELIGHT;
839
840       symbolic = create_symbolic_pixbuf (cellpixbuf, widget, state);
841       if (!symbolic) {
842         colorized = create_colorized_pixbuf (pixbuf,
843                                              &gtk_widget_get_style (widget)->base[state]);
844
845         pixbuf = colorized;
846       } else {
847         pixbuf = symbolic;
848       }
849     }
850
851   gdk_cairo_set_source_pixbuf (cr, pixbuf, pix_rect.x, pix_rect.y);
852   gdk_cairo_rectangle (cr, &draw_rect);
853   cairo_fill (cr);
854
855   if (invisible)
856     g_object_unref (invisible);
857
858   if (colorized)
859     g_object_unref (colorized);
860
861   if (symbolic)
862     g_object_unref (symbolic);
863 }