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