]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellrendererpixbuf.c
GailEntry: remove idle if cell editing is canceled
[~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                         GtkStateFlags          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
608       gtk_style_context_save (context);
609       gtk_style_context_set_state (context, state);
610       pixbuf = gtk_icon_info_load_symbolic_for_context (info,
611                                                         context,
612                                                         NULL,
613                                                         NULL);
614
615       gtk_style_context_restore (context);
616       gtk_icon_info_free (info);
617
618       return pixbuf;
619     }
620
621   return NULL;
622 }
623
624 static GdkPixbuf *
625 create_colorized_pixbuf (GdkPixbuf *src,
626                          GdkRGBA   *new_color)
627 {
628   gint i, j;
629   gint width, height, has_alpha, src_row_stride, dst_row_stride;
630   gint red_value, green_value, blue_value;
631   guchar *target_pixels;
632   guchar *original_pixels;
633   guchar *pixsrc;
634   guchar *pixdest;
635   GdkPixbuf *dest;
636
637   red_value = (new_color->red * 65535.0) / 255.0;
638   green_value = (new_color->green * 65535.0) / 255.0;
639   blue_value = (new_color->blue * 65535.0) / 255.0;
640
641   dest = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src),
642                          gdk_pixbuf_get_has_alpha (src),
643                          gdk_pixbuf_get_bits_per_sample (src),
644                          gdk_pixbuf_get_width (src),
645                          gdk_pixbuf_get_height (src));
646   
647   has_alpha = gdk_pixbuf_get_has_alpha (src);
648   width = gdk_pixbuf_get_width (src);
649   height = gdk_pixbuf_get_height (src);
650   src_row_stride = gdk_pixbuf_get_rowstride (src);
651   dst_row_stride = gdk_pixbuf_get_rowstride (dest);
652   target_pixels = gdk_pixbuf_get_pixels (dest);
653   original_pixels = gdk_pixbuf_get_pixels (src);
654   
655   for (i = 0; i < height; i++) {
656     pixdest = target_pixels + i*dst_row_stride;
657     pixsrc = original_pixels + i*src_row_stride;
658     for (j = 0; j < width; j++) {               
659       *pixdest++ = (*pixsrc++ * red_value) >> 8;
660       *pixdest++ = (*pixsrc++ * green_value) >> 8;
661       *pixdest++ = (*pixsrc++ * blue_value) >> 8;
662       if (has_alpha) {
663         *pixdest++ = *pixsrc++;
664       }
665     }
666   }
667   return dest;
668 }
669
670
671 static void
672 gtk_cell_renderer_pixbuf_get_size (GtkCellRenderer    *cell,
673                                    GtkWidget          *widget,
674                                    const GdkRectangle *cell_area,
675                                    gint               *x_offset,
676                                    gint               *y_offset,
677                                    gint               *width,
678                                    gint               *height)
679 {
680   GtkCellRendererPixbuf *cellpixbuf = (GtkCellRendererPixbuf *) cell;
681   GtkCellRendererPixbufPrivate *priv = cellpixbuf->priv;
682   gint pixbuf_width  = 0;
683   gint pixbuf_height = 0;
684   gint calc_width;
685   gint calc_height;
686   gint xpad, ypad;
687
688   if (!priv->pixbuf)
689     {
690       if (priv->stock_id)
691         gtk_cell_renderer_pixbuf_create_stock_pixbuf (cellpixbuf, widget);
692       else if (priv->icon_name || priv->gicon)
693         gtk_cell_renderer_pixbuf_create_themed_pixbuf (cellpixbuf, widget);
694     }
695   
696   if (priv->pixbuf)
697     {
698       pixbuf_width  = gdk_pixbuf_get_width (priv->pixbuf);
699       pixbuf_height = gdk_pixbuf_get_height (priv->pixbuf);
700     }
701   if (priv->pixbuf_expander_open)
702     {
703       pixbuf_width  = MAX (pixbuf_width, gdk_pixbuf_get_width (priv->pixbuf_expander_open));
704       pixbuf_height = MAX (pixbuf_height, gdk_pixbuf_get_height (priv->pixbuf_expander_open));
705     }
706   if (priv->pixbuf_expander_closed)
707     {
708       pixbuf_width  = MAX (pixbuf_width, gdk_pixbuf_get_width (priv->pixbuf_expander_closed));
709       pixbuf_height = MAX (pixbuf_height, gdk_pixbuf_get_height (priv->pixbuf_expander_closed));
710     }
711
712   gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
713   calc_width  = (gint) xpad * 2 + pixbuf_width;
714   calc_height = (gint) ypad * 2 + pixbuf_height;
715   
716   if (cell_area && pixbuf_width > 0 && pixbuf_height > 0)
717     {
718       gfloat xalign, yalign;
719
720       gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
721       if (x_offset)
722         {
723           *x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
724                         (1.0 - xalign) : xalign) *
725                        (cell_area->width - calc_width));
726           *x_offset = MAX (*x_offset, 0);
727         }
728       if (y_offset)
729         {
730           *y_offset = (yalign *
731                        (cell_area->height - calc_height));
732           *y_offset = MAX (*y_offset, 0);
733         }
734     }
735   else
736     {
737       if (x_offset) *x_offset = 0;
738       if (y_offset) *y_offset = 0;
739     }
740
741   if (width)
742     *width = calc_width;
743   
744   if (height)
745     *height = calc_height;
746 }
747
748 static void
749 gtk_cell_renderer_pixbuf_render (GtkCellRenderer      *cell,
750                                  cairo_t              *cr,
751                                  GtkWidget            *widget,
752                                  const GdkRectangle   *background_area,
753                                  const GdkRectangle   *cell_area,
754                                  GtkCellRendererState  flags)
755
756 {
757   GtkCellRendererPixbuf *cellpixbuf = (GtkCellRendererPixbuf *) cell;
758   GtkCellRendererPixbufPrivate *priv = cellpixbuf->priv;
759   GtkStyleContext *context;
760   GdkPixbuf *pixbuf;
761   GdkPixbuf *invisible = NULL;
762   GdkPixbuf *colorized = NULL;
763   GdkPixbuf *symbolic = NULL;
764   GdkRectangle pix_rect;
765   GdkRectangle draw_rect;
766   gboolean is_expander;
767   gint xpad, ypad;
768
769   gtk_cell_renderer_pixbuf_get_size (cell, widget, (GdkRectangle *) cell_area,
770                                      &pix_rect.x,
771                                      &pix_rect.y,
772                                      &pix_rect.width,
773                                      &pix_rect.height);
774
775   gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
776   pix_rect.x += cell_area->x + xpad;
777   pix_rect.y += cell_area->y + ypad;
778   pix_rect.width  -= xpad * 2;
779   pix_rect.height -= ypad * 2;
780
781   if (!gdk_rectangle_intersect (cell_area, &pix_rect, &draw_rect))
782     return;
783
784   pixbuf = priv->pixbuf;
785
786   g_object_get (cell, "is-expander", &is_expander, NULL);
787   if (is_expander)
788     {
789       gboolean is_expanded;
790
791       g_object_get (cell, "is-expanded", &is_expanded, NULL);
792
793       if (is_expanded &&
794           priv->pixbuf_expander_open != NULL)
795         pixbuf = priv->pixbuf_expander_open;
796       else if (!is_expanded &&
797                priv->pixbuf_expander_closed != NULL)
798         pixbuf = priv->pixbuf_expander_closed;
799     }
800
801   if (!pixbuf)
802     return;
803
804   context = gtk_widget_get_style_context (widget);
805
806   if (!gtk_widget_get_sensitive (widget) ||
807       !gtk_cell_renderer_get_sensitive (cell))
808     {
809       GtkIconSource *source;
810       
811       source = gtk_icon_source_new ();
812       gtk_icon_source_set_pixbuf (source, pixbuf);
813       /* The size here is arbitrary; since size isn't
814        * wildcarded in the source, it isn't supposed to be
815        * scaled by the engine function
816        */
817       gtk_icon_source_set_size (source, GTK_ICON_SIZE_SMALL_TOOLBAR);
818       gtk_icon_source_set_size_wildcarded (source, FALSE);
819
820       gtk_style_context_save (context);
821       gtk_style_context_set_state (context, GTK_STATE_FLAG_INSENSITIVE);
822
823       pixbuf = invisible = gtk_render_icon_pixbuf (context, source,
824                                                    (GtkIconSize) -1);
825
826       gtk_style_context_restore (context);
827       gtk_icon_source_free (source);
828     }
829   else if (priv->follow_state && 
830            (flags & (GTK_CELL_RENDERER_SELECTED|GTK_CELL_RENDERER_PRELIT)) != 0)
831     {
832       GtkStateFlags state;
833
834       state = gtk_cell_renderer_get_state (cell, widget, flags);
835       symbolic = create_symbolic_pixbuf (cellpixbuf, widget, state);
836
837       if (!symbolic)
838         {
839           GdkRGBA color;
840
841           gtk_style_context_get_background_color (context, state, &color);
842           pixbuf = colorized = create_colorized_pixbuf (pixbuf, &color);
843         }
844       else
845         pixbuf = symbolic;
846     }
847
848   gdk_cairo_set_source_pixbuf (cr, pixbuf, pix_rect.x, pix_rect.y);
849   gdk_cairo_rectangle (cr, &draw_rect);
850   cairo_fill (cr);
851
852   if (invisible)
853     g_object_unref (invisible);
854
855   if (colorized)
856     g_object_unref (colorized);
857
858   if (symbolic)
859     g_object_unref (symbolic);
860 }