source: trunk/third/bonobo/bonobo/bonobo-ui-toolbar-icon.c @ 17169

Revision 17169, 45.1 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17168, which included commits to RCS files with non-trunk default branches.
Line 
1/*  -*- Mode: C; c-set-style: linux; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2
3   Copyright (C) 1999 Red Hat, Inc.
4   All rights reserved.
5   
6   The Gnome Library is free software; you can redistribute it and/or
7   modify it under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10
11   The Gnome Library is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   Library General Public License for more details.
15
16   You should have received a copy of the GNU Library General Public
17   License along with the Gnome Library; see the file COPYING.LIB.  If not,
18   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19   Boston, MA 02111-1307, USA.
20
21   GnomePixmap authors: Havoc Pennington, Jonathan Blandford
22   I (Ettore) just renamed it to BonoboUIToolbarIcon.
23*/
24/*
25  @NOTATION@
26*/
27
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31
32#include "bonobo-ui-toolbar-icon.h"
33#include "bonobo-ui-toolbar-button-item.h"
34
35#include <stdio.h>
36
37#include "libart_lgpl/art_affine.h"
38#include "libart_lgpl/art_rgb_affine.h"
39#include "libart_lgpl/art_rgb_rgba_affine.h"
40
41static void bonobo_ui_toolbar_icon_class_init    (BonoboUIToolbarIconClass *class);
42static void bonobo_ui_toolbar_icon_init          (BonoboUIToolbarIcon      *gpixmap);
43static void bonobo_ui_toolbar_icon_destroy       (GtkObject        *object);
44static gint bonobo_ui_toolbar_icon_expose        (GtkWidget        *widget,
45                                                  GdkEventExpose   *event);
46static void bonobo_ui_toolbar_icon_size_request  (GtkWidget        *widget,
47                                                  GtkRequisition    *requisition);
48static void bonobo_ui_toolbar_icon_set_arg       (GtkObject *object,
49                                                  GtkArg *arg,
50                                                  guint arg_id);
51static void bonobo_ui_toolbar_icon_get_arg       (GtkObject *object,
52                                                  GtkArg *arg,
53                                                  guint arg_id);
54
55static void clear_provided_state_image (BonoboUIToolbarIcon *gpixmap,
56                                        GtkStateType state);
57static void clear_generated_state_image(BonoboUIToolbarIcon *gpixmap,
58                                        GtkStateType state);
59static void clear_provided_image       (BonoboUIToolbarIcon *gpixmap);
60static void clear_scaled_image         (BonoboUIToolbarIcon *gpixmap);
61static void clear_all_images           (BonoboUIToolbarIcon *gpixmap);
62static void clear_generated_images     (BonoboUIToolbarIcon *gpixmap);
63static void generate_image             (BonoboUIToolbarIcon *gpixmap,
64                                        GtkStateType state);
65static void set_size                   (BonoboUIToolbarIcon *gpixmap,
66                                        gint width, gint height);
67
68static GdkPixbuf* saturate_and_pixelate(GdkPixbuf *pixbuf,
69                                        gfloat saturation, gboolean pixelate);
70
71static GdkBitmap* create_mask(BonoboUIToolbarIcon *gpixmap, GdkPixbuf *pixbuf);
72
73static GtkMiscClass *parent_class = NULL;
74
75#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
76
77enum {
78        ARG_0,
79        ARG_PIXBUF,
80        ARG_PIXBUF_WIDTH,
81        ARG_PIXBUF_HEIGHT,
82        ARG_FILE,
83        ARG_XPM_D,
84        ARG_DRAW_MODE,
85        ARG_ALPHA_THRESHOLD
86};
87
88/*
89 * Widget functions
90 */
91
92/**
93 * bonobo_ui_toolbar_icon_get_type:
94 *
95 * Registers the &BonoboUIToolbarIcon class if necessary, and returns the type ID
96 * associated to it.
97 *
98 * Returns: the type ID of the &BonoboUIToolbarIcon class.
99 */
100guint
101bonobo_ui_toolbar_icon_get_type (void)
102{
103        static guint pixmap_type = 0;
104
105        if (!pixmap_type) {
106                GtkTypeInfo pixmap_info = {
107                        "BonoboUIToolbarIcon",
108                        sizeof (BonoboUIToolbarIcon),
109                        sizeof (BonoboUIToolbarIconClass),
110                        (GtkClassInitFunc) bonobo_ui_toolbar_icon_class_init,
111                        (GtkObjectInitFunc) bonobo_ui_toolbar_icon_init,
112                        NULL,
113                        NULL,
114                        NULL
115                };
116
117                pixmap_type = gtk_type_unique (gtk_misc_get_type (), &pixmap_info);
118        }
119
120        return pixmap_type;
121}
122
123static void
124bonobo_ui_toolbar_icon_init (BonoboUIToolbarIcon *gpixmap)
125{
126        guint i;
127
128        GTK_WIDGET_SET_FLAGS(GTK_WIDGET(gpixmap), GTK_NO_WINDOW);
129
130        gpixmap->provided_image = NULL;
131        gpixmap->generated_scaled_image = NULL;
132        gpixmap->generated_scaled_mask = NULL;
133
134        gpixmap->width = -1;
135        gpixmap->height = -1;
136        gpixmap->alpha_threshold = 128;
137        gpixmap->mode = BONOBO_UI_TOOLBAR_ICON_COLOR;
138
139        for (i = 0; i < 5; i ++) {
140                gpixmap->generated[i].pixbuf = NULL;
141                gpixmap->generated[i].mask = NULL;
142
143                gpixmap->provided[i].pixbuf = NULL;
144                gpixmap->provided[i].mask = NULL;
145                gpixmap->provided[i].saturation = 1.0;
146                gpixmap->provided[i].pixelate = FALSE;
147
148                if (i == GTK_STATE_INSENSITIVE) {
149                        gpixmap->provided[i].saturation = 0.8;
150                        gpixmap->provided[i].pixelate = TRUE;
151                }
152        }
153}
154
155static void
156bonobo_ui_toolbar_icon_class_init (BonoboUIToolbarIconClass *class)
157{
158        GtkObjectClass *object_class;
159        GtkWidgetClass *widget_class;
160
161        object_class = (GtkObjectClass *) class;
162        widget_class = (GtkWidgetClass *) class;
163
164        object_class->destroy = bonobo_ui_toolbar_icon_destroy;
165
166        parent_class = gtk_type_class (gtk_misc_get_type ());
167
168        gtk_object_add_arg_type("BonoboUIToolbarIcon::pixbuf",
169                                GTK_TYPE_POINTER,
170                                GTK_ARG_READWRITE,
171                                ARG_PIXBUF);
172        gtk_object_add_arg_type("BonoboUIToolbarIcon::pixbuf_width",
173                                GTK_TYPE_INT,
174                                GTK_ARG_READWRITE,
175                                ARG_PIXBUF_WIDTH);
176        gtk_object_add_arg_type("BonoboUIToolbarIcon::pixbuf_height",
177                                GTK_TYPE_INT,
178                                GTK_ARG_READWRITE,
179                                ARG_PIXBUF_HEIGHT);
180        gtk_object_add_arg_type("BonoboUIToolbarIcon::file",
181                                GTK_TYPE_STRING,
182                                GTK_ARG_WRITABLE,
183                                ARG_FILE);
184        gtk_object_add_arg_type("BonoboUIToolbarIcon::xpm_d",
185                                GTK_TYPE_POINTER,
186                                GTK_ARG_WRITABLE,
187                                ARG_XPM_D);
188        gtk_object_add_arg_type("BonoboUIToolbarIcon::draw_mode",
189                                GTK_TYPE_ENUM,
190                                GTK_ARG_READWRITE,
191                                ARG_PIXBUF_HEIGHT);
192        gtk_object_add_arg_type("BonoboUIToolbarIcon::alpha_threshold",
193                                GTK_TYPE_INT,
194                                GTK_ARG_READWRITE,
195                                ARG_PIXBUF_HEIGHT);
196       
197        widget_class->expose_event = bonobo_ui_toolbar_icon_expose;
198        widget_class->size_request = bonobo_ui_toolbar_icon_size_request;
199        object_class->get_arg = bonobo_ui_toolbar_icon_get_arg;
200        object_class->set_arg = bonobo_ui_toolbar_icon_set_arg;
201
202        /* We are going to be using gdk_pixbuf_render_* */
203        gdk_rgb_init ();
204}
205
206static void
207bonobo_ui_toolbar_icon_set_arg (GtkObject *object,
208                      GtkArg *arg,
209                      guint arg_id)
210{
211        BonoboUIToolbarIcon *self;
212
213        self = BONOBO_UI_TOOLBAR_ICON (object);
214
215        switch (arg_id) {
216        case ARG_PIXBUF:
217                bonobo_ui_toolbar_icon_set_pixbuf (self, GTK_VALUE_POINTER (*arg));
218                break;
219        case ARG_PIXBUF_WIDTH:
220                bonobo_ui_toolbar_icon_set_pixbuf_size (self, GTK_VALUE_INT (*arg),
221                                              self->height);
222                break;
223        case ARG_PIXBUF_HEIGHT:
224                bonobo_ui_toolbar_icon_set_pixbuf_size (self, self->width,
225                                              GTK_VALUE_INT (*arg));
226                break;
227        case ARG_FILE: {
228                GdkPixbuf *pixbuf;
229                pixbuf = gdk_pixbuf_new_from_file (GTK_VALUE_STRING (*arg));
230                if (pixbuf != NULL) {
231                        bonobo_ui_toolbar_icon_set_pixbuf (self, pixbuf);
232                        gdk_pixbuf_unref (pixbuf);
233                }
234                break;
235        }
236        case ARG_XPM_D: {
237                GdkPixbuf *pixbuf;
238                pixbuf = gdk_pixbuf_new_from_xpm_data (GTK_VALUE_POINTER (*arg));
239                if (pixbuf != NULL) {
240                        bonobo_ui_toolbar_icon_set_pixbuf (self, pixbuf);
241                        gdk_pixbuf_unref (pixbuf);
242                }
243                break;
244        }
245        case ARG_DRAW_MODE:
246                bonobo_ui_toolbar_icon_set_draw_mode (self, GTK_VALUE_ENUM (*arg));
247                break;
248        case ARG_ALPHA_THRESHOLD:
249                bonobo_ui_toolbar_icon_set_alpha_threshold (self, GTK_VALUE_INT (*arg));
250                break;
251        default:
252                break;
253        }
254}
255
256static void
257bonobo_ui_toolbar_icon_get_arg (GtkObject *object,
258                      GtkArg *arg,
259                      guint arg_id)
260{
261        BonoboUIToolbarIcon *self;
262
263        self = BONOBO_UI_TOOLBAR_ICON (object);
264
265        switch (arg_id) {
266        case ARG_PIXBUF:
267                GTK_VALUE_POINTER (*arg) = bonobo_ui_toolbar_icon_get_pixbuf (self);
268                break;
269        case ARG_PIXBUF_WIDTH:
270                GTK_VALUE_INT (*arg) = self->width;
271                break;
272        case ARG_PIXBUF_HEIGHT:
273                GTK_VALUE_INT (*arg) = self->height;
274                break;
275        case ARG_DRAW_MODE:
276                GTK_VALUE_ENUM (*arg) = bonobo_ui_toolbar_icon_get_draw_mode (self);
277                break;
278        case ARG_ALPHA_THRESHOLD:
279                GTK_VALUE_INT (*arg) = bonobo_ui_toolbar_icon_get_alpha_threshold (self);
280                break;
281        default:
282                break;
283        }
284}
285
286static void
287bonobo_ui_toolbar_icon_destroy (GtkObject *object)
288{
289        BonoboUIToolbarIcon *gpixmap;
290
291        /* remember, destroy can be run multiple times! */
292
293        g_return_if_fail (object != NULL);
294        g_return_if_fail (BONOBO_IS_UI_TOOLBAR_ICON (object));
295
296        gpixmap = BONOBO_UI_TOOLBAR_ICON (object);
297
298        clear_all_images(gpixmap);
299
300        if (GTK_OBJECT_CLASS (parent_class)->destroy)
301                (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
302}
303
304static void
305bonobo_ui_toolbar_icon_size_request  (GtkWidget      *widget,
306                                      GtkRequisition *requisition)
307{
308        /* We base size on the max of all provided images if w,h are -1
309           else the scaled "main" image size (gpixmap->width, gpixmap->height) */
310        gint maxwidth = 0;
311        gint maxheight = 0;
312        int i;
313        BonoboUIToolbarIcon *gpixmap;
314
315        gpixmap = BONOBO_UI_TOOLBAR_ICON(widget);
316       
317        if (gpixmap->width >= 0 &&
318            gpixmap->height >= 0) {
319                /* shortcut if both sizes are set */
320                maxwidth = gpixmap->width;
321                maxheight = gpixmap->height;
322        } else {
323                if (gpixmap->provided_image != NULL) {
324                        maxwidth = MAX(maxwidth, gdk_pixbuf_get_width(gpixmap->provided_image));
325                        maxheight = MAX(maxheight, gdk_pixbuf_get_height(gpixmap->provided_image));
326                }
327               
328                i = 0;
329               
330                while (i < 5) {
331                        GdkPixbuf *pix = gpixmap->provided[i].pixbuf;
332                       
333                        if (pix != NULL) {
334                                maxwidth = MAX(maxwidth, gdk_pixbuf_get_width(pix));
335                                maxheight = MAX(maxheight, gdk_pixbuf_get_height(pix));
336                        }
337                       
338                        ++i;
339                }
340
341                /* fix the size that was specified, if one was. */
342                if (gpixmap->width >= 0)
343                        maxwidth = gpixmap->width;
344               
345                if (gpixmap->height >= 0)
346                        maxheight = gpixmap->height;
347        }
348
349        requisition->width = maxwidth + GTK_MISC (gpixmap)->xpad * 2;
350        requisition->height = maxheight + GTK_MISC (gpixmap)->ypad * 2;
351}
352
353static void
354paint_with_pixbuf (BonoboUIToolbarIcon *gpixmap, GdkRectangle *area)
355{
356        GtkWidget *widget;
357        GdkPixbuf *draw_source;
358        GdkBitmap *draw_mask;
359        GtkMisc   *misc;
360        gint x_off, y_off;
361        gint top_clip, bottom_clip, left_clip, right_clip;
362
363        g_return_if_fail (GTK_WIDGET_DRAWABLE(gpixmap));
364
365        misc = GTK_MISC (gpixmap);
366        widget = GTK_WIDGET (gpixmap);
367
368        /* Ensure we have this state, if we can think of a way to have
369           it */
370        generate_image (gpixmap, GTK_WIDGET_STATE (widget));
371       
372        draw_source = gpixmap->generated[GTK_WIDGET_STATE (widget)].pixbuf;
373        draw_mask = gpixmap->generated[GTK_WIDGET_STATE (widget)].mask;
374       
375        if (draw_source == NULL)
376                return;
377
378        /* Now we actually want to draw the image */
379        /* The first thing we do for that, is write the images coords in the
380         * drawable's coordinate system. */
381        x_off = (widget->allocation.x * (1.0 - misc->xalign) +
382                 (widget->allocation.x + widget->allocation.width
383                  - (widget->requisition.width - misc->xpad * 2)) *
384                 misc->xalign) + 0.5;
385        y_off = (widget->allocation.y * (1.0 - misc->yalign) +
386                 (widget->allocation.y + widget->allocation.height
387                  - (widget->requisition.height - misc->ypad * 2)) *
388                 misc->yalign) + 0.5;
389
390        /* next, we want to do clipping, to find the coordinates in image space of
391         * the region to be drawn.  */
392        left_clip = (x_off < area->x)?area->x - x_off:0;
393        top_clip = (y_off < area->y)?area->y - y_off:0;
394        if (x_off + gdk_pixbuf_get_width (draw_source) > area->x + area->width)
395                right_clip = x_off + gdk_pixbuf_get_width (draw_source) - (area->x + area->width);
396        else
397                right_clip = 0;
398        if (y_off + gdk_pixbuf_get_height (draw_source) > area->y + area->height)
399                bottom_clip = y_off + gdk_pixbuf_get_height (draw_source) - (area->y + area->height);
400        else
401                bottom_clip = 0;
402
403        /* it's in the allocation, but not the image, so we return */
404        if (right_clip + left_clip >= gdk_pixbuf_get_width (draw_source)||
405            top_clip + bottom_clip >= gdk_pixbuf_get_height (draw_source))
406                return;
407
408#if 0
409        g_print ("width=%d\theight=%d\n", gdk_pixbuf_get_width (draw_source), gdk_pixbuf_get_height (draw_source));
410        g_print ("area->x=%d\tarea->y=%d\tarea->width=%d\tarea->height=%d\nx_off=%d\ty_off=%d\nright=%d\tleft=%d\ttop=%d\tbottom=%d\n\n", area->x, area->y, area->width, area->height, x_off, y_off, right_clip, left_clip, top_clip, bottom_clip);
411#endif
412        if (gpixmap->mode == BONOBO_UI_TOOLBAR_ICON_SIMPLE || !gdk_pixbuf_get_has_alpha (draw_source)) {
413                if (draw_mask) {
414                        gdk_gc_set_clip_mask (widget->style->black_gc, draw_mask);
415                        gdk_gc_set_clip_origin (widget->style->black_gc, x_off, y_off);
416                }
417
418                gdk_pixbuf_render_to_drawable (draw_source,
419                                               widget->window,
420                                               widget->style->black_gc,
421                                               left_clip, top_clip,
422                                               x_off + left_clip, y_off + top_clip,
423                                               gdk_pixbuf_get_width (draw_source) - left_clip - right_clip,
424                                               gdk_pixbuf_get_height (draw_source) - top_clip - bottom_clip,
425                                               GDK_RGB_DITHER_NORMAL,
426                                               0, 0); /* FIXME -- get the right offset */
427
428                if (draw_mask) {
429                        gdk_gc_set_clip_mask (widget->style->black_gc, NULL);
430                        gdk_gc_set_clip_origin (widget->style->black_gc, 0, 0);
431                }
432        } else if (gpixmap->mode == BONOBO_UI_TOOLBAR_ICON_COLOR) {
433                GdkPixbuf *dest_source;
434                gint i, j, height, width, rowstride, dest_rowstride;
435                gint r, g, b;
436                guchar *dest_pixels, *c, *a, *original_pixels;
437
438
439                dest_source = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
440                                              FALSE,
441                                              gdk_pixbuf_get_bits_per_sample (draw_source),
442                                              gdk_pixbuf_get_width (draw_source) - left_clip - right_clip,
443                                              gdk_pixbuf_get_height (draw_source) - top_clip - bottom_clip);
444
445
446                gdk_gc_set_clip_mask (widget->style->black_gc, draw_mask);
447                gdk_gc_set_clip_origin (widget->style->black_gc, x_off, y_off);
448
449                r = widget->style->bg[GTK_WIDGET_STATE (widget)].red >> 8;
450                g = widget->style->bg[GTK_WIDGET_STATE (widget)].green >> 8;
451                b = widget->style->bg[GTK_WIDGET_STATE (widget)].blue >> 8;
452                height = gdk_pixbuf_get_height (dest_source);
453                width = gdk_pixbuf_get_width (dest_source);
454                rowstride = gdk_pixbuf_get_rowstride (draw_source);
455                dest_rowstride = gdk_pixbuf_get_rowstride (dest_source);
456                dest_pixels = gdk_pixbuf_get_pixels (dest_source);
457                original_pixels = gdk_pixbuf_get_pixels (draw_source);
458                for (i = 0; i < height; i++) {
459                        for (j = 0; j < width; j++) {
460                                c = original_pixels + (i + top_clip)*rowstride + (j + left_clip)*4;
461                                a = c + 3;
462                                *(dest_pixels + i*dest_rowstride + j*3) = r + (((*c - r) * (*a) + 0x80) >> 8);
463                                c++;
464                                *(dest_pixels + i*dest_rowstride + j*3 + 1) = g + (((*c - g) * (*a) + 0x80) >> 8);
465                                c++;
466                                *(dest_pixels + i*dest_rowstride + j*3 + 2) = b + (((*c - b) * (*a) + 0x80) >> 8);
467                        }
468                }
469
470                gdk_pixbuf_render_to_drawable (dest_source,
471                                               widget->window,
472                                               widget->style->black_gc,
473                                               0, 0,
474                                               x_off + left_clip, y_off + top_clip,
475                                               width, height,
476                                               GDK_RGB_DITHER_NORMAL,
477                                               0, 0); /* FIXME -- get the right offset */
478
479                gdk_gc_set_clip_mask (widget->style->black_gc, NULL);
480                gdk_gc_set_clip_origin (widget->style->black_gc, 0, 0);
481
482                gdk_pixbuf_unref (dest_source);
483        }
484}
485
486static gint
487bonobo_ui_toolbar_icon_expose (GtkWidget *widget, GdkEventExpose *event)
488{
489        g_return_val_if_fail (widget != NULL, FALSE);
490        g_return_val_if_fail (BONOBO_IS_UI_TOOLBAR_ICON (widget), FALSE);
491        g_return_val_if_fail (event != NULL, FALSE);
492
493        if (GTK_WIDGET_DRAWABLE (widget))
494                paint_with_pixbuf (BONOBO_UI_TOOLBAR_ICON (widget), &event->area);
495
496        return FALSE;
497}
498
499
500/*
501 * Set image data, create with image data
502 */
503
504static void
505set_state_pixbuf(BonoboUIToolbarIcon* gpixmap, GtkStateType state, GdkPixbuf* pixbuf, GdkBitmap* mask)
506{
507        clear_generated_state_image(gpixmap, state);
508        clear_provided_state_image(gpixmap, state);
509
510        g_return_if_fail(gpixmap->provided[state].pixbuf == NULL);
511        g_return_if_fail(gpixmap->provided[state].mask == NULL);
512
513        gpixmap->provided[state].pixbuf = pixbuf;
514        if (pixbuf)
515                gdk_pixbuf_ref(pixbuf);
516
517        gpixmap->provided[state].mask = mask;
518        if (mask)
519                gdk_bitmap_ref(mask);
520
521        if (GTK_WIDGET_VISIBLE(gpixmap)) {
522                gtk_widget_queue_resize(GTK_WIDGET(gpixmap));
523                gtk_widget_queue_clear(GTK_WIDGET(gpixmap));
524        }
525}
526
527static void
528set_state_pixbufs(BonoboUIToolbarIcon* gpixmap, GdkPixbuf* pixbufs[5], GdkBitmap* masks[5])
529{
530        guint i;
531
532        i = 0;
533        while (i < 5) {
534
535                set_state_pixbuf(gpixmap,
536                                 i,
537                                 pixbufs ? pixbufs[i] : NULL,
538                                 masks ? masks[i] : NULL);
539                ++i;
540        }
541}
542
543static void
544set_pixbuf (BonoboUIToolbarIcon* gpixmap, GdkPixbuf *pixbuf)
545{
546        if (pixbuf == gpixmap->provided_image)
547                return;
548       
549        clear_generated_images(gpixmap);
550        clear_provided_image(gpixmap);
551
552        g_return_if_fail(gpixmap->provided_image == NULL);
553
554        gpixmap->provided_image = pixbuf;
555
556        if (pixbuf)
557                gdk_pixbuf_ref(pixbuf);
558
559        if (GTK_WIDGET_VISIBLE(gpixmap)) {
560                gtk_widget_queue_resize(GTK_WIDGET(gpixmap));
561                gtk_widget_queue_clear(GTK_WIDGET(gpixmap));
562        }
563}
564
565
566
567/*
568 * Public functions
569 */
570
571
572/**
573 * bonobo_ui_toolbar_icon_new:
574 * @void:
575 *
576 * Creates a new empty @BonoboUIToolbarIcon.
577 *
578 * Return value: A newly-created @BonoboUIToolbarIcon
579 **/
580GtkWidget*
581bonobo_ui_toolbar_icon_new (void)
582{
583        GtkWidget* widget;
584
585        widget = gtk_type_new(bonobo_ui_toolbar_icon_get_type());
586
587        return widget;
588}
589
590/**
591 * bonobo_ui_toolbar_icon_new_from_file:
592 * @filename: The filename of the file to be loaded.
593 *
594 * Note that the new_from_file functions give you no way to detect errors;
595 * if the file isn't found/loaded, you get an empty widget.
596 * to detect errors just do:
597 *
598 * <programlisting>
599 * gdk_pixbuf_new_from_file (filename);
600 * if (pixbuf != NULL) {
601 *         gpixmap = bonobo_ui_toolbar_icon_new_from_pixbuf (pixbuf);
602 * } else {
603 *         // handle your error...
604 * }
605 * </programlisting>
606 *
607 * Return value: A newly allocated @BonoboUIToolbarIcon with the file at @filename loaded.
608 **/
609GtkWidget*
610bonobo_ui_toolbar_icon_new_from_file          (const char *filename)
611{
612        GtkWidget *retval = NULL;
613        GdkPixbuf *pixbuf;
614        g_return_val_if_fail (filename != NULL, NULL);
615
616        pixbuf = gdk_pixbuf_new_from_file (filename);
617        if (pixbuf != NULL) {
618                retval = bonobo_ui_toolbar_icon_new_from_pixbuf (pixbuf);
619                gdk_pixbuf_unref (pixbuf);
620        } else {
621                retval = bonobo_ui_toolbar_icon_new ();
622        }
623
624        return retval;
625}
626
627/**
628 * bonobo_ui_toolbar_icon_new_from_file_at_size:
629 * @filename: The filename of the file to be loaded.
630 * @width: The width to scale the image to.
631 * @height: The height to scale the image to.
632 *
633 * Loads a new @BonoboUIToolbarIcon from a file, and scales it (if necessary) to the
634 * size indicated by @height and @width.  If either are set to -1, then the
635 * "natural" dimension of the image is used in place.  See
636 * @bonobo_ui_toolbar_icon_new_from_file for information on error handling.
637 *
638 * Return value: value: A newly allocated @BonoboUIToolbarIcon with the file at @filename loaded.
639 **/
640GtkWidget*
641bonobo_ui_toolbar_icon_new_from_file_at_size          (const gchar *filename, gint width, gint height)
642{
643        GtkWidget *retval = NULL;
644
645        g_return_val_if_fail (filename != NULL, NULL);
646        g_return_val_if_fail (width >= -1, NULL);
647        g_return_val_if_fail (height >= -1, NULL);
648
649        retval = bonobo_ui_toolbar_icon_new_from_file (filename);
650        bonobo_ui_toolbar_icon_set_pixbuf_size (BONOBO_UI_TOOLBAR_ICON (retval), width, height);
651
652        return retval;
653}
654
655/**
656 * bonobo_ui_toolbar_icon_new_from_file_at_size:
657 * @xpm_data: The xpm data to be loaded.
658 * @width: The width to scale the image to.
659 * @height: The height to scale the image to.
660 *
661 * Loads a new @BonoboUIToolbarIcon from the @xpm_data, and scales it (if necessary) to
662 * the size indicated by @height and @width.  If either are set to -1, then the
663 * "natural" dimension of the image is used in place.
664 *
665 * Return value: value: A newly allocated @BonoboUIToolbarIcon with the image from @xpm_data loaded.
666 **/
667GtkWidget*
668bonobo_ui_toolbar_icon_new_from_xpm_d         (const char **xpm_data)
669{
670        GtkWidget *retval = NULL;
671        GdkPixbuf *pixbuf;
672
673        g_return_val_if_fail (xpm_data != NULL, NULL);
674
675        pixbuf = gdk_pixbuf_new_from_xpm_data (xpm_data);
676        if (pixbuf != NULL) {
677                retval = bonobo_ui_toolbar_icon_new_from_pixbuf (pixbuf);
678                gdk_pixbuf_unref (pixbuf);
679        } else {
680                retval = bonobo_ui_toolbar_icon_new ();
681        }
682
683        return retval;
684}
685
686/**
687 * bonobo_ui_toolbar_icon_new_from_file_at_size:
688 * @xpm_data: The xpm data to be loaded.
689 * @width: The width to scale the image to.
690 * @height: The height to scale the image to.
691 *
692 * Loads a new @BonoboUIToolbarIcon from the @xpm_data, and scales it (if necessary) to
693 * the size indicated by @height and @width.  If either are set to -1, then the
694 * "natural" dimension of the image is used in place.
695 *
696 * Return value: value: A newly allocated @BonoboUIToolbarIcon with the image from @xpm_data loaded.
697 **/
698GtkWidget*
699bonobo_ui_toolbar_icon_new_from_xpm_d_at_size (const char **xpm_data, int width, int height)
700{
701        GtkWidget *retval = NULL;
702
703        g_return_val_if_fail (xpm_data != NULL, NULL);
704        g_return_val_if_fail (width >= -1, NULL);
705        g_return_val_if_fail (height >= -1, NULL);
706
707        retval = bonobo_ui_toolbar_icon_new_from_xpm_d (xpm_data);
708        bonobo_ui_toolbar_icon_set_pixbuf_size (BONOBO_UI_TOOLBAR_ICON (retval), width, height);
709
710        return retval;
711}
712
713
714/**
715 * bonobo_ui_toolbar_icon_new_from_file_at_size:
716 * @pixbuf: The pixbuf to be loaded.
717 *
718 * Loads a new @BonoboUIToolbarIcon from the @pixbuf.
719 *
720 * Return value: value: A newly allocated @BonoboUIToolbarIcon with the image from @pixbuf loaded.
721 **/
722GtkWidget*
723bonobo_ui_toolbar_icon_new_from_pixbuf          (GdkPixbuf *pixbuf)
724{
725        BonoboUIToolbarIcon *retval;
726
727        retval = gtk_type_new (bonobo_ui_toolbar_icon_get_type ());
728
729        g_return_val_if_fail (pixbuf != NULL, GTK_WIDGET (retval));
730
731        set_pixbuf(retval, pixbuf);
732
733        return GTK_WIDGET (retval);
734        /*return bonobo_ui_toolbar_icon_new_from_pixbuf_at_size(pixbuf, -1, -1);*/
735}
736
737/**
738 * bonobo_ui_toolbar_icon_new_from_file_at_size:
739 * @pixbuf: The pixbuf be loaded.
740 * @width: The width to scale the image to.
741 * @height: The height to scale the image to.
742 *
743 * Loads a new @BonoboUIToolbarIcon from the @pixbuf, and scales it (if necessary) to
744 * the size indicated by @height and @width.  If either are set to -1, then the
745 * "natural" dimension of the image is used in place.
746 *
747 * Return value: value: A newly allocated @BonoboUIToolbarIcon with the image from @pixbuf loaded.
748 **/
749GtkWidget*
750bonobo_ui_toolbar_icon_new_from_pixbuf_at_size  (GdkPixbuf *pixbuf, gint width, gint height)
751{
752        GtkWidget *retval = NULL;
753
754        g_return_val_if_fail (pixbuf != NULL, NULL);
755        g_return_val_if_fail (width >= -1, NULL);
756        g_return_val_if_fail (height >= -1, NULL);
757
758        retval = bonobo_ui_toolbar_icon_new_from_pixbuf (pixbuf);
759        bonobo_ui_toolbar_icon_set_pixbuf_size (BONOBO_UI_TOOLBAR_ICON (retval), width, height);
760
761        return retval;
762}
763
764/**
765 * bonobo_ui_toolbar_icon_set_pixbuf_size:
766 * @gpixmap: A @BonoboUIToolbarIcon.
767 * @width: The new width.
768 * @height: The new height.
769 *
770 * Sets the current size of the image displayed.  If there were custom "state"
771 * pixbufs set, as a side effect, they are discarded and must be re set at the
772 * new size.
773 *
774 **/
775/* Setters and getters */
776void
777bonobo_ui_toolbar_icon_set_pixbuf_size (BonoboUIToolbarIcon      *gpixmap,
778                              gint              width,
779                              gint              height)
780{
781        g_return_if_fail (gpixmap != NULL);
782        g_return_if_fail (BONOBO_IS_UI_TOOLBAR_ICON (gpixmap));
783       
784        set_size(gpixmap, width, height);
785}
786
787/**
788 * bonobo_ui_toolbar_icon_get_pixbuf_size:
789 * @gpixmap: A @BonoboUIToolbarIcon
790 * @width: A pointer to place the width in.
791 * @height: A pointer to place the height in.
792 *
793 * Sets @width and @height to be the widgets current dimensions.  They will
794 * return the width or height of the image, or -1, -1 if the image's "natural"
795 * dimensions are used.  Either or both dimension arguments may be NULL, as
796 * necessary.
797 *
798 **/
799void
800bonobo_ui_toolbar_icon_get_pixbuf_size (BonoboUIToolbarIcon      *gpixmap,
801                              gint             *width,
802                              gint             *height)
803{
804        g_return_if_fail (gpixmap != NULL);
805        g_return_if_fail (BONOBO_IS_UI_TOOLBAR_ICON (gpixmap));
806
807        if (width)
808                *width = gpixmap->width;
809        if (height)
810                *height = gpixmap->height;
811}
812
813
814/**
815 * bonobo_ui_toolbar_icon_set_pixbuf:
816 * @gpixmap: A @BonoboUIToolbarIcon.
817 * @pixbuf: The new pixbuf.
818 *
819 * Sets the image shown to be that of the pixbuf.  If there is a current image
820 * used by the @gpixmap, it is discarded along with any pixmaps at a particular
821 * state.  However, the @gpixmap will keep the same geometry as the old image,
822 * or if the width or height are set to -1, it will inherit the new image's
823 * geometry.
824 *
825 **/
826void
827bonobo_ui_toolbar_icon_set_pixbuf (BonoboUIToolbarIcon *gpixmap,
828                         GdkPixbuf *pixbuf)
829{
830        g_return_if_fail (gpixmap != NULL);
831        g_return_if_fail (BONOBO_IS_UI_TOOLBAR_ICON (gpixmap));
832        g_return_if_fail (pixbuf != NULL);
833
834        set_pixbuf(gpixmap, pixbuf);
835}
836
837
838/**
839 * bonobo_ui_toolbar_icon_get_pixbuf:
840 * @gpixmap: A @BonoboUIToolbarIcon.
841 *
842 * Gets the current image used by @gpixmap, if you have set the
843 * pixbuf. If you've only set the value for particular states,
844 * then this won't return anything.
845 *
846 * Return value: A pixbuf.
847 **/
848GdkPixbuf *
849bonobo_ui_toolbar_icon_get_pixbuf (BonoboUIToolbarIcon      *gpixmap)
850{
851        g_return_val_if_fail (gpixmap != NULL, NULL);
852        g_return_val_if_fail (BONOBO_IS_UI_TOOLBAR_ICON (gpixmap), NULL);
853
854        return gpixmap->provided_image;
855}
856
857
858/**
859 * bonobo_ui_toolbar_icon_set_pixbuf_at_state:
860 * @gpixmap: A @BonoboUIToolbarIcon.
861 * @state: The state being set.
862 * @pixbuf: The new image for the state.
863 * @mask: The mask for the new image.
864 *
865 * Sets a custom image for the image at @state.  For example, you can set the
866 * prelighted appearance to a different image from the normal one.  If
867 * necessary, the image will be scaled to the appropriate size.  The mask can
868 * also be optionally NULL.  The image set will be modified by the draw vals as
869 * normal.
870 *
871 **/
872void
873bonobo_ui_toolbar_icon_set_pixbuf_at_state (BonoboUIToolbarIcon *gpixmap,
874                                  GtkStateType state,
875                                  GdkPixbuf *pixbuf,
876                                  GdkBitmap *mask)
877{
878        g_return_if_fail (gpixmap != NULL);
879        g_return_if_fail (BONOBO_IS_UI_TOOLBAR_ICON (gpixmap));
880       
881        set_state_pixbuf (gpixmap, state, pixbuf, mask);
882}
883
884/**
885 * bonobo_ui_toolbar_icon_set_state_pixbufs
886 * @gpixmap: A @BonoboUIToolbarIcon.
887 * @pixbufs: The images.
888 * @masks: The masks.
889 *
890 * Sets a custom image for all the possible states of the image.  Both @pixbufs
891 * and @masks are indexed by a GtkStateType.  Any or all of the images can be
892 * NULL, as necessary.  The image set will be modified by the draw vals as
893 * normal.
894 *
895 **/
896void
897bonobo_ui_toolbar_icon_set_state_pixbufs (BonoboUIToolbarIcon *gpixmap,
898                                GdkPixbuf   *pixbufs[5],
899                                GdkBitmap   *masks[5])
900{
901        g_return_if_fail(gpixmap != NULL);
902        g_return_if_fail(BONOBO_IS_UI_TOOLBAR_ICON (gpixmap));
903       
904        set_state_pixbufs(gpixmap, pixbufs, masks);
905}
906
907/**
908 * bonobo_ui_toolbar_icon_clear:
909 * @gpixmap: A @BonoboUIToolbarIcon.
910 *
911 * Removes any images from @gpixmap.  If still visible, the image will appear empty.
912 *
913 **/
914void
915bonobo_ui_toolbar_icon_clear (BonoboUIToolbarIcon *gpixmap)
916{
917        g_return_if_fail(gpixmap != NULL);
918        g_return_if_fail(BONOBO_IS_UI_TOOLBAR_ICON (gpixmap));
919
920        clear_all_images(gpixmap);
921
922        if (GTK_WIDGET_VISIBLE(gpixmap)) {
923                gtk_widget_queue_resize(GTK_WIDGET(gpixmap));
924                gtk_widget_queue_clear(GTK_WIDGET(gpixmap));
925        }
926}
927
928/**
929 * bonobo_ui_toolbar_icon_set_draw_vals:
930 * @gpixmap: A @BonoboUIToolbarIcon.
931 * @state: The the state to set the modifications to
932 * @saturation: The saturtion offset.
933 * @pixelate: Draw the insensitive stipple.
934 *
935 * Sets the modification parameters for a particular state.  The saturation
936 * level determines the amount of color in the image.  The default level of 1.0
937 * leaves the color unchanged while a level of 0.0 means the image is fully
938 * saturated, and has no color.  @saturation can be set to values greater then 1.0,
939 * or less then 0.0, but this produces less meaningful results.  If @pixelate is
940 * set to TRUE, then in adition to any saturation, a light stipple is overlayed
941 * over the image.
942 *
943 **/
944void
945bonobo_ui_toolbar_icon_set_draw_vals (BonoboUIToolbarIcon *gpixmap,
946                                      GtkStateType state,
947                                      gfloat saturation,
948                                      gboolean pixelate)
949{
950        g_return_if_fail (gpixmap != NULL);
951        g_return_if_fail (BONOBO_IS_UI_TOOLBAR_ICON (gpixmap));
952        g_return_if_fail (state >= 0 && state < 5);
953
954        gpixmap->provided[state].saturation = saturation;
955        gpixmap->provided[state].pixelate = pixelate;
956
957        if (GTK_WIDGET_VISIBLE(gpixmap)) {
958                gtk_widget_queue_clear(GTK_WIDGET(gpixmap));
959        }
960}
961
962/**
963 * bonobo_ui_toolbar_icon_get_draw_vals:
964 * @gpixmap: A @BonoboUIToolbarIcon.
965 * @state: The the state to set the modifications to
966 * @saturation: return location for the saturation offset
967 * @pixelate: return value for whether to draw the insensitive stipple
968 *
969 * Retrieve the values set by bonobo_ui_toolbar_icon_set_draw_vals(). Either
970 * return location can be NULL if you don't care about it.
971 *
972 **/
973void
974bonobo_ui_toolbar_icon_get_draw_vals (BonoboUIToolbarIcon      *gpixmap,
975                                      GtkStateType      state,
976                                      gfloat           *saturation,
977                                      gboolean         *pixelate)
978{
979        g_return_if_fail (gpixmap != NULL);
980        g_return_if_fail (BONOBO_IS_UI_TOOLBAR_ICON (gpixmap));
981        g_return_if_fail (state >= 0 && state < 5);
982
983        if (saturation)
984                *saturation = gpixmap->provided[state].saturation;
985        if (pixelate)
986                *pixelate = gpixmap->provided[state].pixelate;
987}
988
989/**
990 * bonobo_ui_toolbar_icon_set_draw_mode:
991 * @gpixmap: A @BonoboUIToolbarIcon.
992 * @mode: The new drawing mode.
993 *
994 * This sets the drawing mode of the image to be @mode.  The image
995 * must have an alpha channel if @BONOBO_UI_TOOLBAR_ICON_COLOR is to be used.
996 **/
997void
998bonobo_ui_toolbar_icon_set_draw_mode (BonoboUIToolbarIcon *gpixmap,
999                                      BonoboUIToolbarIconDrawMode mode)
1000{
1001        g_return_if_fail (gpixmap != NULL);
1002        g_return_if_fail (BONOBO_IS_UI_TOOLBAR_ICON (gpixmap));
1003
1004        if (gpixmap->mode == mode)
1005                return;
1006       
1007        gpixmap->mode = mode;
1008        clear_generated_images (gpixmap);
1009
1010        if (GTK_WIDGET_VISIBLE (gpixmap)) {
1011                gtk_widget_queue_resize (GTK_WIDGET (gpixmap));
1012                gtk_widget_queue_clear (GTK_WIDGET (gpixmap));
1013        }
1014}
1015
1016/**
1017 * bonobo_ui_toolbar_icon_get_draw_mode:
1018 * @gpixmap: A @BonoboUIToolbarIcon.
1019 *
1020 * Gets the current draw mode.
1021 *
1022 * Return value: The current @BonoboUIToolbarIconDrawMode setting.
1023 **/
1024BonoboUIToolbarIconDrawMode
1025bonobo_ui_toolbar_icon_get_draw_mode (BonoboUIToolbarIcon *gpixmap)
1026{
1027        g_return_val_if_fail (gpixmap != NULL, BONOBO_UI_TOOLBAR_ICON_SIMPLE);
1028        g_return_val_if_fail (BONOBO_IS_UI_TOOLBAR_ICON (gpixmap), BONOBO_UI_TOOLBAR_ICON_SIMPLE);
1029
1030        return gpixmap->mode;
1031}
1032
1033/**
1034 * bonobo_ui_toolbar_icon_set_alpha_threshold:
1035 * @gpixmap: A @BonoboUIToolbarIcon.
1036 * @alpha_threshold: The alpha threshold
1037 *
1038 * Sets the alpha threshold for @gpixmap.  It is used to determine which pixels
1039 * are shown when the image has an alpha channel, and is only used if no mask is
1040 * set.
1041 *
1042 **/
1043void
1044bonobo_ui_toolbar_icon_set_alpha_threshold (BonoboUIToolbarIcon *gpixmap,
1045                                            gint alpha_threshold)
1046{
1047        g_return_if_fail (gpixmap != NULL);
1048        g_return_if_fail (BONOBO_IS_UI_TOOLBAR_ICON (gpixmap));
1049        g_return_if_fail (alpha_threshold >= 0 || alpha_threshold <= 255);
1050
1051        if (alpha_threshold == gpixmap->alpha_threshold)
1052                return;
1053
1054        gpixmap->alpha_threshold = alpha_threshold;
1055
1056        clear_generated_images (gpixmap);
1057       
1058        if (GTK_WIDGET_VISIBLE (gpixmap))
1059                gtk_widget_queue_clear (GTK_WIDGET (gpixmap));
1060}
1061
1062/**
1063 * bonobo_ui_toolbar_icon_get_alpha_threshold:
1064 * @gpixmap: A @BonoboUIToolbarIcon.
1065 *
1066 * Gets the current alpha threshold.
1067 *
1068 * Return value: The alpha threshold
1069 **/
1070gint
1071bonobo_ui_toolbar_icon_get_alpha_threshold (BonoboUIToolbarIcon *gpixmap)
1072{
1073        g_return_val_if_fail (gpixmap != NULL, 0);
1074        g_return_val_if_fail (BONOBO_IS_UI_TOOLBAR_ICON (gpixmap), 0);
1075
1076        return gpixmap->alpha_threshold;
1077}
1078
1079/*
1080 * Internal functions
1081 */
1082
1083static void
1084clear_provided_state_image (BonoboUIToolbarIcon *gpixmap,
1085                            GtkStateType state)
1086{
1087        if (gpixmap->provided[state].pixbuf != NULL) {
1088                gdk_pixbuf_unref(gpixmap->provided[state].pixbuf);
1089                gpixmap->provided[state].pixbuf = NULL;
1090        }
1091       
1092        if (gpixmap->provided[state].mask != NULL) {
1093                gdk_bitmap_unref(gpixmap->provided[state].mask);
1094                gpixmap->provided[state].mask = NULL;
1095        }
1096}
1097
1098static void
1099clear_generated_state_image (BonoboUIToolbarIcon *gpixmap,
1100                             GtkStateType state)
1101{
1102        if (gpixmap->generated[state].pixbuf != NULL) {
1103                gdk_pixbuf_unref(gpixmap->generated[state].pixbuf);
1104                gpixmap->generated[state].pixbuf = NULL;
1105        }
1106
1107        if (gpixmap->generated[state].mask != NULL) {
1108                gdk_bitmap_unref(gpixmap->generated[state].mask);
1109                gpixmap->generated[state].mask = NULL;
1110        }
1111}
1112       
1113static void
1114clear_provided_image (BonoboUIToolbarIcon *gpixmap)
1115{
1116        if (gpixmap->provided_image) {
1117                gdk_pixbuf_unref(gpixmap->provided_image);
1118                gpixmap->provided_image = NULL;
1119        }
1120}
1121
1122static void
1123clear_scaled_image (BonoboUIToolbarIcon *gpixmap)
1124{
1125        if (gpixmap->generated_scaled_image) {
1126                gdk_pixbuf_unref(gpixmap->generated_scaled_image);
1127                gpixmap->generated_scaled_image = NULL;
1128        }
1129        if (gpixmap->generated_scaled_mask) {
1130                gdk_bitmap_unref(gpixmap->generated_scaled_mask);
1131                gpixmap->generated_scaled_mask = NULL;
1132        }
1133}
1134
1135static void
1136clear_all_images (BonoboUIToolbarIcon *gpixmap)
1137{
1138        guint i;
1139
1140        i = 0;
1141        while (i < 5) {
1142
1143                clear_provided_state_image(gpixmap, i);
1144
1145                ++i;
1146        }
1147       
1148        clear_generated_images(gpixmap);
1149        clear_provided_image(gpixmap);
1150}
1151
1152static void
1153clear_generated_images (BonoboUIToolbarIcon *gpixmap)
1154{
1155        guint i;
1156
1157        i = 0;
1158        while (i < 5) {
1159
1160                clear_generated_state_image(gpixmap, i);
1161
1162                ++i;
1163        }
1164
1165        clear_scaled_image(gpixmap);
1166}
1167
1168static void
1169generate_image (BonoboUIToolbarIcon *gpixmap,
1170                GtkStateType state)
1171{
1172        /* See if this image is already generated */
1173        if (gpixmap->generated[state].pixbuf != NULL)
1174                return;
1175
1176        g_return_if_fail(gpixmap->generated[state].pixbuf == NULL);
1177        g_return_if_fail(gpixmap->generated[state].mask == NULL);
1178       
1179        /* To generate an image, we first use the provided image for a given
1180           state, if any; if not we use the gpixmap->provided_image; if that
1181           doesn't exist then we bail out. */
1182           
1183        if (gpixmap->provided[state].pixbuf != NULL) {
1184                gint width = gpixmap->width;
1185                gint height = gpixmap->height;
1186                GdkPixbuf *scaled;
1187                GdkPixbuf *generated;
1188
1189                if (width >= 0 || height >= 0) {
1190                        if (width < 0)
1191                                width = gdk_pixbuf_get_width(gpixmap->provided[state].pixbuf);
1192
1193                        if (height < 0)
1194                                height = gdk_pixbuf_get_height(gpixmap->provided[state].pixbuf);
1195                       
1196                        scaled = gdk_pixbuf_scale_simple (gpixmap->provided[state].pixbuf,
1197                                                          gpixmap->width,
1198                                                          gpixmap->height,
1199                                                          ART_FILTER_BILINEAR);
1200                } else {
1201                        /* just copy */
1202                        scaled = gpixmap->provided[state].pixbuf;
1203                        gdk_pixbuf_ref(scaled);
1204                }
1205                       
1206                generated = saturate_and_pixelate(scaled,
1207                                                  gpixmap->provided[state].saturation,
1208                                                  gpixmap->provided[state].pixelate);
1209               
1210                gpixmap->generated[state].pixbuf = generated;
1211
1212                if ((scaled == gpixmap->provided[state].pixbuf) &&
1213                    gpixmap->provided[state].mask) {
1214                        /* use provided mask if it exists
1215                           and we did not have to scale */
1216                        gpixmap->generated[state].mask =
1217                                gpixmap->provided[state].mask;
1218                        gdk_bitmap_ref(gpixmap->generated[state].mask);
1219                } else {
1220                        /* create mask */
1221                        gpixmap->generated[state].mask =
1222                                create_mask(gpixmap, generated);
1223                }
1224
1225                /* Drop intermediate image */
1226                gdk_pixbuf_unref(scaled);
1227        }
1228       
1229        /* Ensure we've generated the scaled image
1230           if we have an original image */
1231        if (gpixmap->provided_image != NULL &&
1232            gpixmap->generated_scaled_image == NULL) {
1233                gint width = gpixmap->width;
1234                gint height = gpixmap->height;
1235               
1236                if (width < 0)
1237                        width = gdk_pixbuf_get_width(gpixmap->provided_image);
1238                if (height < 0)
1239                        height = gdk_pixbuf_get_height(gpixmap->provided_image);
1240               
1241                if (gpixmap->width < 0 && /* orig w/h, not the "fixed" ones */
1242                    gpixmap->height < 0) {
1243                        /* Just copy */
1244                        gpixmap->generated_scaled_image = gpixmap->provided_image;
1245                        gdk_pixbuf_ref(gpixmap->generated_scaled_image);
1246                } else {
1247                        gpixmap->generated_scaled_image =
1248                                gdk_pixbuf_scale_simple (gpixmap->provided_image,
1249                                                         width,
1250                                                         height,
1251                                                         ART_FILTER_BILINEAR);
1252                }
1253
1254                gpixmap->generated_scaled_mask =
1255                        create_mask(gpixmap, gpixmap->generated_scaled_image);
1256        }
1257
1258        /* Now we generate the per-state image from the scaled
1259           copy of the provided image */
1260        if (gpixmap->generated_scaled_image != NULL) {
1261                GdkPixbuf *generated;
1262
1263                g_return_if_fail(gpixmap->generated_scaled_mask);
1264               
1265                generated = saturate_and_pixelate(gpixmap->generated_scaled_image,
1266                                                  gpixmap->provided[state].saturation,
1267                                                  gpixmap->provided[state].pixelate);
1268               
1269                gpixmap->generated[state].pixbuf = generated;
1270
1271                if (gpixmap->provided[state].mask) {
1272                        /* use provided mask if it exists */
1273                        gpixmap->generated[state].mask =
1274                                gpixmap->provided[state].mask;
1275                        gdk_bitmap_ref(gpixmap->generated[state].mask);
1276                } else {
1277                        /* If we just copied the generated_scaled_image
1278                           then also copy the mask */
1279                        if (generated == gpixmap->generated_scaled_image) {
1280                                gpixmap->generated[state].mask =
1281                                        gpixmap->generated_scaled_mask;
1282                                gdk_bitmap_ref(gpixmap->generated_scaled_mask);
1283                        } else {
1284                                /* create mask */
1285                                gpixmap->generated[state].mask =
1286                                        create_mask(gpixmap, generated);
1287                        }
1288                }
1289        }
1290
1291        /* If we didn't have a provided_image or a provided image for the
1292           particular state, then we have no way to generate an image.
1293        */
1294}
1295
1296static void
1297set_size (BonoboUIToolbarIcon *gpixmap,
1298          gint width, gint height)
1299{
1300        if (gpixmap->width == width &&
1301            gpixmap->height == height)
1302                return;
1303       
1304        /* FIXME: if old_width == -1 and pixbuf->width == width, we can just set
1305         * the values and return as an optomization step. */
1306       
1307        clear_generated_images(gpixmap);
1308       
1309        gpixmap->width = width;
1310        gpixmap->height = height;
1311       
1312        if (GTK_WIDGET_VISIBLE (gpixmap)) {
1313                if ((GTK_WIDGET (gpixmap)->requisition.width != width) ||
1314                    (GTK_WIDGET (gpixmap)->requisition.height != height))
1315                        gtk_widget_queue_resize (GTK_WIDGET (gpixmap));
1316                else
1317                        gtk_widget_queue_clear (GTK_WIDGET (gpixmap));
1318        }
1319}
1320
1321static GdkBitmap*
1322create_mask(BonoboUIToolbarIcon *gpixmap, GdkPixbuf *pixbuf)
1323{
1324        GdkBitmap *mask;
1325        gint width = gdk_pixbuf_get_width(pixbuf);
1326        gint height = gdk_pixbuf_get_height(pixbuf);
1327       
1328        mask = gdk_pixmap_new (NULL, width, height, 1);
1329
1330        gdk_pixbuf_render_threshold_alpha(pixbuf,
1331                                          mask,
1332                                          0, 0, 0, 0,
1333                                          width, height,
1334                                          gpixmap->alpha_threshold);
1335               
1336       
1337        return mask;
1338}
1339 
1340static GdkPixbuf*
1341saturate_and_pixelate(GdkPixbuf *pixbuf, gfloat saturation, gboolean pixelate)
1342{
1343        if (saturation == 1.0) {
1344                gdk_pixbuf_ref(pixbuf);
1345                return pixbuf;
1346        } else {
1347                GdkPixbuf *target;
1348                gint i, j;
1349                gint width, height, has_alpha, rowstride;
1350                guchar *target_pixels;
1351                guchar *original_pixels;
1352                guchar *current_pixel;
1353                guchar intensity;
1354
1355                has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
1356                width = gdk_pixbuf_get_width (pixbuf);
1357                height = gdk_pixbuf_get_height (pixbuf);
1358                rowstride = gdk_pixbuf_get_rowstride (pixbuf);
1359               
1360                target = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
1361                                         has_alpha,
1362                                         gdk_pixbuf_get_bits_per_sample (pixbuf),
1363                                         width, height);
1364               
1365                target_pixels = gdk_pixbuf_get_pixels (target);
1366                original_pixels = gdk_pixbuf_get_pixels (pixbuf);
1367
1368                for (i = 0; i < height; i++) {
1369                        for (j = 0; j < width; j++) {
1370                                current_pixel = original_pixels + i*rowstride + j*(has_alpha?4:3);
1371                                intensity = INTENSITY (*(current_pixel), *(current_pixel + 1), *(current_pixel + 2));
1372                                if (pixelate && (i+j)%2 == 0) {
1373                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3)) = intensity/2 + 127;
1374                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 1) = intensity/2 + 127;
1375                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 2) = intensity/2 + 127;
1376                                } else if (pixelate) {
1377#define DARK_FACTOR 0.7
1378                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3)) =
1379                                                (guchar) (((1.0 - saturation) * intensity
1380                                                           + saturation * (*(current_pixel)))) * DARK_FACTOR;
1381                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 1) =
1382                                                (guchar) (((1.0 - saturation) * intensity
1383                                                           + saturation * (*(current_pixel + 1)))) * DARK_FACTOR;
1384                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 2) =
1385                                                (guchar) (((1.0 - saturation) * intensity
1386                                                           + saturation * (*(current_pixel + 2)))) * DARK_FACTOR;
1387                                } else {
1388                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3)) =
1389                                                (guchar) ((1.0 - saturation) * intensity
1390                                                          + saturation * (*(current_pixel)));
1391                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 1) =
1392                                                (guchar) ((1.0 - saturation) * intensity
1393                                                          + saturation * (*(current_pixel + 1)));
1394                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 2) =
1395                                                (guchar) ((1.0 - saturation) * intensity
1396                                                          + saturation * (*(current_pixel + 2)));
1397                                }
1398                                if (has_alpha)
1399                                        *(target_pixels + i*rowstride + j*(has_alpha?4:3) + 3) = *(original_pixels + i*rowstride + j*(has_alpha?4:3) + 3);
1400                        }
1401                }
1402
1403                return target;
1404        }
1405}
Note: See TracBrowser for help on using the repository browser.