This repository has been archived on 2020-04-11. You can view files and clone it, but cannot push or open issues or pull requests.
gnoemoe/gnoemoe/gm-pixbuf.c

309 lines
6.6 KiB
C

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gtk/gtk.h>
#include <glib.h>
#include <string.h>
#include <strings.h>
#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();
}