* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "defs.h"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#include "claws-features.h"
+#endif
+
#include <glib.h>
#include <gtk/gtk.h>
#include <string.h>
#include <dirent.h>
+#ifdef HAVE_SVG
+#include <librsvg/rsvg.h>
+#include <math.h>
+#endif
-#include "config.h"
+#include "defs.h"
#include "stock_pixmap.h"
#include "gtkutils.h"
#include "utils.h"
#include "pixmaps/down_arrow.xpm"
#include "pixmaps/up_arrow.xpm"
#include "pixmaps/exec.xpm"
-#include "pixmaps/mail.xpm"
+#include "pixmaps/mail_draft.xpm"
#include "pixmaps/mail_attach.xpm"
#include "pixmaps/mail_compose.xpm"
#include "pixmaps/mail_forward.xpm"
+#include "pixmaps/mail_privacy_encrypted.xpm"
+#include "pixmaps/mail_privacy_signed.xpm"
#include "pixmaps/mail_receive.xpm"
#include "pixmaps/mail_receive_all.xpm"
#include "pixmaps/mail_reply.xpm"
#include "pixmaps/mime_calendar.xpm"
#include "pixmaps/mime_pgpsig.xpm"
#include "pixmaps/printer.xpm"
+#include "pixmaps/printer_btn.xpm"
#include "pixmaps/privacy_signed.xpm"
#include "pixmaps/privacy_passed.xpm"
#include "pixmaps/privacy_failed.xpm"
{linewrapcurrent_xpm , NULL, NULL, "linewrapcurrent", NULL, NULL},
{linewrap_xpm , NULL, NULL, "linewrap", NULL, NULL},
{locked_xpm , NULL, NULL, "locked", NULL, NULL},
- {mail_xpm , NULL, NULL, "mail", NULL, NULL},
+ {mail_draft_xpm , NULL, NULL, "mail_draft", NULL, NULL},
{mail_attach_xpm , NULL, NULL, "mail_attach", NULL, NULL},
{mail_compose_xpm , NULL, NULL, "mail_compose", NULL, NULL},
{mail_forward_xpm , NULL, NULL, "mail_forward", NULL, NULL},
+ {mail_privacy_encrypted_xpm , NULL, NULL, "mail_privacy_encrypted", NULL, NULL},
+ {mail_privacy_signed_xpm , NULL, NULL, "mail_privacy_signed", NULL, NULL},
{mail_receive_xpm , NULL, NULL, "mail_receive", NULL, NULL},
{mail_receive_all_xpm , NULL, NULL, "mail_receive_all", NULL, NULL},
{mail_reply_xpm , NULL, NULL, "mail_reply", NULL, NULL},
{mime_ps_xpm , NULL, NULL, "mime_ps", NULL, NULL},
{mime_calendar_xpm , NULL, NULL, "mime_calendar", NULL, NULL},
{mime_pgpsig_xpm , NULL, NULL, "mime_pgpsig", NULL, NULL},
+ {printer_btn_xpm , NULL, NULL, "printer_btn", NULL, NULL},
{printer_xpm , NULL, NULL, "printer", NULL, NULL},
{privacy_signed_xpm , NULL, NULL, "privacy_signed", NULL, NULL},
{privacy_passed_xpm , NULL, NULL, "privacy_passed", NULL, NULL},
static const char *extension[] = {
".png",
".xpm",
+#ifdef HAVE_SVG
+ ".svg",
+#endif
NULL
};
return NULL;
}
+#ifdef HAVE_SVG
+/*
+ * Renders a SVG into a Cairo context at the given dimensions keeping
+ * the aspect ratio.
+ *
+ * Adapted from https://developer.gnome.org/rsvg/2.40/RsvgHandle.html
+ * #rsvg-handle-set-size-callback
+ */
+void render_scaled_proportionally(RsvgHandle *handle, cairo_t *cr, int width, int height)
+{
+ RsvgDimensionData dimensions;
+ double x_factor, y_factor;
+ double scale_factor;
+
+ rsvg_handle_get_dimensions(handle, &dimensions);
+
+ x_factor = (double) width / dimensions.width;
+ y_factor = (double) height / dimensions.height;
+
+ scale_factor = MIN(x_factor, y_factor);
+
+ cairo_scale(cr, scale_factor, scale_factor);
+
+ rsvg_handle_render_cairo(handle, cr);
+}
+
+/*
+ * Generates a new Pixbuf from a Cairo context of the given dimensions.
+ *
+ * Adapted from https://gist.github.com/bert/985903
+ */
+GdkPixbuf *pixbuf_from_cairo(cairo_t *cr, gboolean alpha, int width, int height)
+{
+ gint p_stride, /* Pixbuf stride value */
+ p_n_channels, /* RGB -> 3, RGBA -> 4 */
+ s_stride; /* Surface stride value */
+ guchar *p_pixels, /* Pixbuf's pixel data */
+ *s_pixels; /* Surface's pixel data */
+ cairo_surface_t *surface; /* Temporary image surface */
+ GdkPixbuf *pixbuf; /* Returned pixbuf */
+
+ /* Create pixbuf */
+ pixbuf = gdk_pixbuf_new
+ (GDK_COLORSPACE_RGB, alpha, 8, width, height);
+ if (pixbuf == NULL) {
+ g_warning("failed to create a new %d x %d pixbuf", width, height);
+ return NULL;
+ }
+ /* Obtain surface from where pixel values will be copied */
+ surface = cairo_get_target(cr);
+ if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
+ g_warning("invalid cairo surface for copying");
+ return NULL;
+ }
+ /* Inspect pixbuf */
+ g_object_get(G_OBJECT(pixbuf),
+ "rowstride", &p_stride,
+ "n-channels", &p_n_channels,
+ "pixels", &p_pixels,
+ NULL);
+ /* and surface */
+ s_stride = cairo_image_surface_get_stride(surface);
+ s_pixels = cairo_image_surface_get_data(surface);
+
+ /* Copy pixel data from surface to pixbuf */
+ while (height--) {
+ gint i;
+ guchar *p_iter = p_pixels, *s_iter = s_pixels;
+ for (i = 0; i < width; i++) {
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ /* Pixbuf: RGB(A) - Surface: BGRA */
+ gdouble alpha_factor = (gdouble)0xff / s_iter[3];
+ p_iter[0] = (guchar)( s_iter[2] * alpha_factor + .5 );
+ p_iter[1] = (guchar)( s_iter[1] * alpha_factor + .5 );
+ p_iter[2] = (guchar)( s_iter[0] * alpha_factor + .5 );
+ if (p_n_channels == 4)
+ p_iter[3] = s_iter[3];
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+ /* Pixbuf: RGB(A) - Surface: ARGB */
+ gdouble alpha_factor = (gdouble)0xff / s_iter[0];
+ p_iter[0] = (guchar)( s_iter[1] * alpha_factor + .5 );
+ p_iter[1] = (guchar)( s_iter[2] * alpha_factor + .5 );
+ p_iter[2] = (guchar)( s_iter[3] * alpha_factor + .5 );
+ if (p_n_channels == 4)
+ p_iter[3] = s_iter[0];
+#else /* PDP endianness */
+ /* Pixbuf: RGB(A) - Surface: RABG */
+ gdouble alpha_factor = (gdouble)0xff / s_iter[1];
+ p_iter[0] = (guchar)( s_iter[0] * alpha_factor + .5 );
+ p_iter[1] = (guchar)( s_iter[3] * alpha_factor + .5 );
+ p_iter[2] = (guchar)( s_iter[2] * alpha_factor + .5 );
+ if (p_n_channels == 4)
+ p_iter[3] = s_iter[1];
+#endif
+ s_iter += 4;
+ p_iter += p_n_channels;
+ }
+ s_pixels += s_stride;
+ p_pixels += p_stride;
+ }
+ /* Destroy context */
+ cairo_destroy(cr);
+
+ return pixbuf;
+}
+
+/*
+ * Renders a SVG file into a pixbuf with the dimensions of the
+ * given pixmap data (optionally with alpha channel).
+ */
+GdkPixbuf *pixbuf_from_svg_like_icon(char *filename, GError **error, StockPixmapData *icondata, gboolean alpha)
+{
+ int width, height;
+ cairo_surface_t *surface;
+ cairo_t *context;
+ RsvgHandle *handle;
+
+ cm_return_val_if_fail(filename != NULL, NULL);
+ cm_return_val_if_fail(icondata != NULL, NULL);
+
+ /* load SVG file */
+ handle = rsvg_handle_new_from_file(filename, error);
+ if (handle == NULL) {
+ g_warning("failed loading SVG '%s': %s (%d)", filename,
+ (*error)->message, (*error)->code);
+ return NULL;
+ }
+
+ /* scale dimensions */
+ if (prefs_common.enable_pixmap_scaling) {
+ /* default is pixmap icon size */
+ if (sscanf((icondata->data)[0], "%d %d ", &width, &height) != 2) {
+ g_warning("failed reading icondata width and height");
+ return NULL;
+ }
+ /* which can be modified by some factor */
+ if (prefs_common.pixmap_scaling_ppi > 0) {
+ gdouble factor = (gdouble) prefs_common.pixmap_scaling_ppi / MIN_PPI;
+ width = (int) floor(factor * width);
+ height = (int) floor(factor * height);
+ }
+ } else { /* render using SVG size */
+ RsvgDimensionData dimension;
+
+ rsvg_handle_get_dimensions (handle, &dimension);
+ width = dimension.width;
+ height = dimension.height;
+ }
+
+ /* create drawing context */
+ surface = cairo_image_surface_create(
+ alpha? CAIRO_FORMAT_ARGB32: CAIRO_FORMAT_RGB24,
+ width, height);
+ if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
+ g_warning("failed to create a cairo surface: %s",
+ cairo_status_to_string(cairo_surface_status(surface)));
+ g_object_unref(handle);
+ return NULL;
+ }
+ context = cairo_create(surface);
+ cairo_surface_destroy(surface);
+ if (cairo_status(context) != CAIRO_STATUS_SUCCESS) {
+ g_warning("failed to create a cairo context: %s",
+ cairo_status_to_string(cairo_status(context)));
+ cairo_destroy(context);
+ return NULL;
+ }
+ /* render SVG */
+ render_scaled_proportionally(handle, context, width, height);
+ /* build result and destroy context */
+ return pixbuf_from_cairo(context, alpha, width, height);
+}
+#endif
+
/*!
*\brief
*/
NULL);
if (is_file_exist(icon_file_name)) {
GError *err = NULL;
+#ifdef HAVE_SVG
+ if (!strncmp(extension[i], ".svg", 4)) {
+ pix = pixbuf_from_svg_like_icon(icon_file_name, &err, pix_d,
+ prefs_common.enable_alpha_svg);
+ } else {
+ pix = gdk_pixbuf_new_from_file(icon_file_name, &err);
+ }
+#else
pix = gdk_pixbuf_new_from_file(icon_file_name, &err);
+#endif
if (err) g_error_free(err);
}
if (pix) {
{
GList *ptr;
+ cm_return_if_fail(list != NULL);
+
for (ptr = g_list_first(list); ptr != NULL; ptr = g_list_next(ptr))
g_free(ptr->data);
g_list_free(list);
}
+void stock_pixmap_invalidate_all_icons(void)
+{
+ StockPixmapData *pix_d;
+ int i = 0;
+
+ while (i < N_STOCK_PIXMAPS) {
+ pix_d = &pixmaps[i];
+ if (pix_d->pixbuf) {
+ g_object_unref(G_OBJECT(pix_d->pixbuf));
+ pix_d->pixbuf = NULL;
+ }
+ if (pix_d->pixmap) {
+ g_object_unref(G_OBJECT(pix_d->pixmap));
+ pix_d->pixmap = NULL;
+ }
+ i++;
+ }
+}
+
gchar *stock_pixmap_get_name (StockPixmap icon)
{
if (icon >= N_STOCK_PIXMAPS)