#ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "gm-debug.h" #include "gm-pixbuf.h" static GList *gm_pixbuf_directories = NULL; static GList *gm_pixbufs = NULL; static GtkIconFactory *factory = NULL; GdkPixbuf *gm_pixbuf_create(const gchar * filename, int width, int height); static void on_gm_pixbuf_theme_changed(GtkIconTheme *theme, gpointer user_data); static GdkPixbuf * gm_pixbuf_create_save_close() { GError *error = NULL; GtkIconTheme *icon_theme; GdkPixbuf *pixbuf, *close, *save; gint w1, h1, w2, h2; icon_theme = gtk_icon_theme_get_default(); gtk_icon_size_lookup(GTK_ICON_SIZE_LARGE_TOOLBAR, &w1, &h1); save = gtk_icon_theme_load_icon(icon_theme, GTK_STOCK_SAVE, w1, GTK_ICON_LOOKUP_USE_BUILTIN, &error); if (error) { g_error_free(error); error = NULL; } if (save == NULL) { gm_debug_msg(DEBUG_DEFAULT, "Couldn't find save icon for the save and close composite icon"); return gm_pixbuf_get("saveclose.xpm"); } w1 = gdk_pixbuf_get_width(save); h1 = gdk_pixbuf_get_height(save); pixbuf = gdk_pixbuf_copy(save); g_object_unref(save); w2 = w1 / 2; h2 = h1 / 2; close = gtk_icon_theme_load_icon(icon_theme, GTK_STOCK_CLOSE, w2, 0, &error); if (error) { g_error_free(error); } if (close == NULL) { gm_debug_msg(DEBUG_DEFAULT, "Couldn't find close icon for the save and close composite icon"); return gm_pixbuf_get("saveclose.xpm"); } gdk_pixbuf_composite(close, pixbuf, w1 - w2, 0, w2, h2, w1 - w2, 0, 1, 1, GDK_INTERP_NEAREST, 255); g_object_unref(close); return pixbuf; } void gm_pixbuf_add_directory(const gchar *directory) { gm_pixbuf_directories = g_list_prepend(gm_pixbuf_directories, g_strdup(directory)); } static GtkIconSource * gm_pixbuf_create_stock24(GdkPixbuf *pixbuf) { GtkIconSource *source; GdkPixbuf *scaled; gint w, h; scaled = gdk_pixbuf_new(gdk_pixbuf_get_colorspace(pixbuf), gdk_pixbuf_get_has_alpha(pixbuf), gdk_pixbuf_get_bits_per_sample(pixbuf), 24, 24); gdk_pixbuf_fill(scaled, 0xffffff00); w = gdk_pixbuf_get_width(pixbuf); h = gdk_pixbuf_get_height(pixbuf); gdk_pixbuf_copy_area(pixbuf, 0, 0, w, h, scaled, (24 - w) / 2, (24 - h) / 2); source = gtk_icon_source_new(); gtk_icon_source_set_pixbuf(source, scaled); gtk_icon_source_set_size(source, GTK_ICON_SIZE_LARGE_TOOLBAR); return source; } void gm_pixbuf_populate_factory() { GdkPixbuf *pixbuf = gm_pixbuf_create_save_close(); GtkIconSet *set; GtkIconSource *source; set = gtk_icon_set_new_from_pixbuf(pixbuf); if (gdk_pixbuf_get_width(pixbuf) < 24) { source = gm_pixbuf_create_stock24(pixbuf); gtk_icon_set_add_source(set, source); gtk_icon_source_free(source); } gtk_icon_factory_add(factory, GM_STOCK_SAVE_CLOSE, set); g_object_unref(pixbuf); } void gm_pixbuf_init() { GtkIconTheme *theme; gm_pixbuf_add_directory(PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps"); theme = gtk_icon_theme_get_default(); g_signal_connect(theme, "changed", G_CALLBACK(on_gm_pixbuf_theme_changed), NULL); factory = gtk_icon_factory_new(); gtk_icon_factory_add_default(factory); gm_pixbuf_populate_factory(); } void gm_pixbuf_fini() { GList *l; GmPixbufInfo *i; for (l = gm_pixbuf_directories; l; l = l->next) { g_free(l->data); } g_list_free(gm_pixbuf_directories); for (l = gm_pixbufs; l; l = l->next) { i = (GmPixbufInfo *)(l->data); g_free(i->name); g_object_unref(i->pixbuf); g_free(i); } g_list_free(gm_pixbufs); gtk_icon_factory_remove_default(factory); g_object_unref(factory); } gchar * gm_pixbuf_find(const gchar *filename) { GList *elem; if (filename == NULL) { return NULL; } if (g_file_test(filename, G_FILE_TEST_EXISTS)) { return g_strdup(filename); } for (elem = gm_pixbuf_directories; elem; elem = elem->next) { gchar *pathname = g_strdup_printf("%s%s%s", (gchar *) elem->data, G_DIR_SEPARATOR_S, filename); if (g_file_test(pathname, G_FILE_TEST_EXISTS)) { return pathname; } g_free(pathname); } return NULL; } GdkPixbuf * gm_pixbuf_create(const gchar * filename, int width, int height) { gchar *pathname = NULL, *ext; GdkPixbuf *pixbuf = NULL; GError *error = NULL; if (!filename || *filename == '\0') { return NULL; } pathname = gm_pixbuf_find(filename); if (!pathname) { gm_debug_msg(DEBUG_DEFAULT, "gm_pixbuf_create: couldn't find pixbuf file: %s", filename); return NULL; } ext = rindex(pathname, '.'); if (width < 1 || height < 1) { pixbuf = gdk_pixbuf_new_from_file(pathname, &error); } else { pixbuf = gdk_pixbuf_new_from_file_at_size(pathname, width, height, &error); } if (!pixbuf) { gm_debug_msg(DEBUG_DEFAULT, "gm_pixbuf_create: failed to load pixbuf from file: %s: %s\n", pathname, error->message); g_error_free(error); error = NULL; } g_free(pathname); return pixbuf; } GdkPixbuf * gm_pixbuf_get_at_size(const gchar *filename, int width, int height) { GdkPixbuf *pix; GList *elem; GmPixbufInfo *i; if (filename == NULL || *filename == '\0') { return NULL; } for (elem = gm_pixbufs; elem; elem = elem->next) { i = (GmPixbufInfo *) (elem->data); if (strcmp(i->name, filename) == 0 && i->width == width && i->height == height) { return i->pixbuf; } } // Not found, so create it pix = gm_pixbuf_create(filename, width, height); if (pix) { i = g_new(GmPixbufInfo, 1); i->name = g_strdup(filename); i->width = width; i->height = height; i->pixbuf = pix; gm_pixbufs = g_list_append(gm_pixbufs, i); return pix; } else { return NULL; } } // Returns pixbuf if it is already loaded in pixmaps GdkPixbuf * gm_pixbuf_get(const gchar *filename) { return gm_pixbuf_get_at_size(filename, -1, -1); } void gm_pixbuf_set_alpha(GdkPixbuf **pixs, guchar alpha) { int width, height, n_channels, rowstride, y, x; GdkPixbuf *pix; guchar *pixels, *p; if (!gdk_pixbuf_get_has_alpha(*pixs)) { pix = gdk_pixbuf_add_alpha(*pixs, FALSE, 0, 0, 0); gdk_pixbuf_unref(*pixs); } else { pix = *pixs; } n_channels = gdk_pixbuf_get_n_channels(pix); if (gdk_pixbuf_get_colorspace(pix) != GDK_COLORSPACE_RGB || gdk_pixbuf_get_bits_per_sample(pix) != 8 || !gdk_pixbuf_get_has_alpha(pix) || n_channels != 4) { *pixs = pix; return; } width = gdk_pixbuf_get_width(pix); height = gdk_pixbuf_get_height(pix); rowstride = gdk_pixbuf_get_rowstride(pix); pixels = gdk_pixbuf_get_pixels(pix); p = pixels; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { p[3] = alpha; p = p + n_channels; } } *pixs = pix; } static void on_gm_pixbuf_theme_changed(GtkIconTheme *theme, gpointer user_data) { gm_pixbuf_populate_factory(); }