[Commits] [SCM] claws branch, master, updated. 3.14.1-187-g1ef7efb

mones at claws-mail.org mones at claws-mail.org
Tue Feb 7 20:03:11 CET 2017


The branch, master has been updated
       via  1ef7efbc70643f8709b3b8d081fab949b808a296 (commit)
       via  89eb1e67c5e46464e0c12256af6c8b15a3d32bae (commit)
       via  427ba2698e8a780c61597357cbe05a37c0946cff (commit)
       via  db434c2b05aec33ca6c3cc4fda792d40cf34942c (commit)
       via  cdf48fc3e9ce71ef09c0b9ddbdf7057f6d36e6da (commit)
      from  7906fba208f469e0d26e349fab157a1db7a30116 (commit)

Summary of changes:
 claws-features.h.in |    1 +
 configure.ac        |   24 +++++++
 src/Makefile.am     |    2 +
 src/common/defs.h   |    4 ++
 src/gtk/about.c     |   10 +++
 src/prefs_common.c  |   24 +++++++
 src/prefs_common.h  |    6 ++
 src/prefs_themes.c  |  198 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/stock_pixmap.c  |  190 ++++++++++++++++++++++++++++++++++++++++++++++++
 9 files changed, 459 insertions(+)


- Log -----------------------------------------------------------------
commit 1ef7efbc70643f8709b3b8d081fab949b808a296
Author: Ricardo Mones <ricardo at mones.org>
Date:   Tue Feb 7 00:56:29 2017 +0100

    User interface for SVG preferences

diff --git a/src/prefs_themes.c b/src/prefs_themes.c
index 1d24f18..fc81582 100644
--- a/src/prefs_themes.c
+++ b/src/prefs_themes.c
@@ -26,6 +26,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
+#ifdef HAVE_SVG
+#include <math.h>
+#endif
 
 #include <glib.h>
 #include <glib/gi18n.h>
@@ -73,6 +76,14 @@ typedef struct _ThemesPage
 	GtkWidget *btn_remove;
 
 	GdkPixbuf *pixbufs[PREVIEW_ICONS];
+
+#ifdef HAVE_SVG
+	GtkWidget *checkbtn_enable_alpha;
+	GtkWidget *checkbtn_enable_scaling;
+	GtkWidget *checkbtn_scaling_auto;
+	GtkWidget *label_scaling_ppi;
+	GtkWidget *spinbtn_scaling_ppi;
+#endif
 } ThemesPage;
 
 typedef struct _ThemeInfo
@@ -130,6 +141,12 @@ StockPixmap prefs_themes_icons[PREVIEW_ICONS] = {
 static void prefs_themes_btn_remove_clicked_cb	(GtkWidget *widget, gpointer data);
 static void prefs_themes_btn_install_clicked_cb	(GtkWidget *widget, gpointer data);
 static void prefs_themes_menu_item_activated_cb	(GtkWidget *widget, gpointer data);
+#ifdef HAVE_SVG
+static gdouble prefs_themes_compute_ppi(GdkScreen *screen);
+static gdouble prefs_themes_get_adjusted_ppi(void);
+static void prefs_themes_checkbtn_enable_scaling_toggled_cb (GtkWidget *widget, gpointer data);
+static void prefs_themes_checkbtn_scaling_auto_toggled_cb (GtkWidget *widget, gpointer data);
+#endif
 
 static void prefs_themes_update_buttons		(const ThemesData *tdata);
 static void prefs_themes_display_global_stats	(const ThemesData *tdata);
@@ -394,6 +411,10 @@ void prefs_themes_init(void)
 	tpaths = g_list_first(tdata->themes);
 	if (tdata->displayed == NULL)
 		tdata->displayed = (gchar *)(tpaths->data);
+#ifdef HAVE_SVG
+	if (prefs_common.pixmap_scaling_auto)
+		prefs_common.pixmap_scaling_ppi = prefs_themes_get_adjusted_ppi();
+#endif
 }
 
 static void prefs_themes_free_names(ThemesData *tdata)
@@ -598,6 +619,78 @@ static void prefs_themes_menu_item_activated_cb(GtkWidget *widget, gpointer data
 	prefs_themes_get_theme_info(tdata);
 }
 
+#ifdef HAVE_SVG
+#define MM_INCH 0.0393700787402
+static gdouble prefs_themes_compute_ppi(GdkScreen *screen)
+{
+	gdouble wp = gdk_screen_get_width(screen);
+	gdouble hp = gdk_screen_get_height(screen);
+	gdouble wi = gdk_screen_get_width_mm(screen);
+	gdouble hi = gdk_screen_get_height_mm(screen);
+	gdouble dp, di;
+
+	debug_print("screen is %f x %f pixels, %f x %f mm\n", wp, hp, wi, hi);
+
+	/* https://en.wikipedia.org/wiki/Pixel_density */
+	wi *= MM_INCH;
+	hi *= MM_INCH;
+	dp = sqrt(wp * wp + hp * hp);
+	di = sqrt(wi * wi + hi * hi);
+
+	return (di != 0.0)? dp / di: 0.0;
+}
+
+static gdouble prefs_themes_get_adjusted_ppi(void)
+{
+	gdouble ppi, cppi;
+	GdkScreen * screen = gdk_screen_get_default();
+
+	if (screen == NULL) { /* oops! */
+		g_warning("unable to get default GDK screen");
+		return MIN_PPI;
+	}
+
+	ppi = gdk_screen_get_resolution(screen);
+	cppi = prefs_themes_compute_ppi(screen);
+	debug_print("returned PPI: %f / computed PPI: %f\n", ppi, cppi);
+	/*
+	 gdk_screen_get_resolution doesn't seem to work well when running
+	 on a remote display and returns the value of the local display.
+	 height/width functions do this better, so we can compute a PPI
+	 from them and take the highest value.
+	*/
+	return MAX(ppi, cppi);
+}
+
+static void prefs_themes_checkbtn_enable_scaling_toggled_cb (GtkWidget *widget, gpointer data)
+{
+	ThemesPage *page = (ThemesPage *) data;
+	gboolean enabled = gtk_toggle_button_get_active(
+				GTK_TOGGLE_BUTTON (widget));
+	gboolean automatic = gtk_toggle_button_get_active(
+				GTK_TOGGLE_BUTTON (page->checkbtn_scaling_auto));
+
+	gtk_widget_set_sensitive(page->checkbtn_scaling_auto, enabled);
+	gtk_widget_set_sensitive(page->spinbtn_scaling_ppi, enabled && !automatic);
+	gtk_widget_set_sensitive(page->label_scaling_ppi, enabled && !automatic);
+}
+
+static void prefs_themes_checkbtn_scaling_auto_toggled_cb(GtkWidget *widget, gpointer data)
+{
+	ThemesPage *page = (ThemesPage *) data;
+	gboolean automatic = gtk_toggle_button_get_active(
+				GTK_TOGGLE_BUTTON (widget));
+
+	gtk_widget_set_sensitive(page->spinbtn_scaling_ppi, !automatic);
+	gtk_widget_set_sensitive(page->label_scaling_ppi, !automatic);
+
+	if (automatic) /* update PPI value */
+		gtk_spin_button_set_value(
+				GTK_SPIN_BUTTON (page->spinbtn_scaling_ppi),
+				prefs_themes_get_adjusted_ppi());
+}
+#endif
+
 static void prefs_themes_update_buttons(const ThemesData *tdata)
 {
 	ThemesPage *theme = tdata->page;
@@ -809,6 +902,15 @@ static void prefs_themes_create_widget(PrefsPage *page, GtkWindow *window, gpoin
 	GtkWidget *hbuttonbox1;
 	GtkWidget *btn_remove;
 	GtkCellRenderer *renderer;
+#ifdef HAVE_SVG
+	GtkWidget *frame_scaling;
+	GtkWidget *checkbtn_enable_alpha;
+	GtkWidget *checkbtn_enable_scaling;
+	GtkWidget *checkbtn_scaling_auto;
+	GtkWidget *label_scaling_ppi;
+	GtkWidget *spinbtn_scaling_ppi;
+	GtkAdjustment *spinbtn_scaling_ppi_adj;
+#endif
 
 	vbox1 = gtk_vbox_new (FALSE, VSPACING);
 	gtk_container_set_border_width (GTK_CONTAINER (vbox1), VBOX_BORDER);
@@ -960,6 +1062,65 @@ static void prefs_themes_create_widget(PrefsPage *page, GtkWindow *window, gpoin
 	gtk_container_add (GTK_CONTAINER (hbuttonbox1), btn_remove);
 	gtkut_widget_set_can_default (btn_remove, TRUE);
 
+#ifdef HAVE_SVG
+	PACK_FRAME(vbox1, frame_scaling, _("SVG rendering"));
+
+	vbox2 = gtk_vbox_new (FALSE, VSPACING);
+	gtk_widget_show (vbox2);
+	gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5);
+	gtk_container_add (GTK_CONTAINER (frame_scaling), vbox2);
+
+	PACK_CHECK_BUTTON(vbox2, checkbtn_enable_alpha, _("Enable alpha channel"));
+	PACK_CHECK_BUTTON(vbox2, checkbtn_enable_scaling, _("Force scaling"));
+	PACK_CHECK_BUTTON(vbox2, checkbtn_scaling_auto, _("Automatic"));
+
+	hbox3 = gtk_hbox_new (FALSE, 5);
+	gtk_widget_show (hbox3);
+
+	label_scaling_ppi = gtk_label_new (_("Pixels per inch (PPI)"));
+	gtk_widget_show (label_scaling_ppi);
+	gtk_box_pack_start (GTK_BOX (hbox3), label_scaling_ppi,
+			FALSE, FALSE, 5);
+
+	spinbtn_scaling_ppi_adj = GTK_ADJUSTMENT(
+		gtk_adjustment_new (MIN_PPI, MIN_PPI, MAX_PPI, 1, 10, 0));
+	spinbtn_scaling_ppi = gtk_spin_button_new(
+			spinbtn_scaling_ppi_adj, 1.0, 0);
+	gtk_widget_show (spinbtn_scaling_ppi);
+	gtk_box_pack_start (GTK_BOX (hbox3), spinbtn_scaling_ppi,
+			FALSE, FALSE, 5);
+
+	gtk_box_pack_start (GTK_BOX (vbox2), hbox3, FALSE, FALSE, 0);
+
+	/* initialize widget values */
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (checkbtn_enable_alpha),
+			prefs_common.enable_alpha_svg);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (checkbtn_enable_scaling),
+			prefs_common.enable_pixmap_scaling);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (checkbtn_scaling_auto),
+			prefs_common.pixmap_scaling_auto);
+	gtk_spin_button_set_value(GTK_SPIN_BUTTON (spinbtn_scaling_ppi),
+			prefs_common.pixmap_scaling_ppi);
+
+	/* sensitivity */
+	gtk_widget_set_sensitive(checkbtn_scaling_auto,
+			prefs_common.enable_pixmap_scaling);
+	gtk_widget_set_sensitive(spinbtn_scaling_ppi,
+			prefs_common.enable_pixmap_scaling
+				&& !prefs_common.pixmap_scaling_auto);
+	gtk_widget_set_sensitive(label_scaling_ppi,
+			prefs_common.enable_pixmap_scaling
+				&& !prefs_common.pixmap_scaling_auto);
+
+	/* signals */
+	g_signal_connect(G_OBJECT(checkbtn_enable_scaling), "toggled",
+			 G_CALLBACK(prefs_themes_checkbtn_enable_scaling_toggled_cb),
+			 prefs_themes);
+	g_signal_connect(G_OBJECT(checkbtn_scaling_auto), "toggled",
+			 G_CALLBACK(prefs_themes_checkbtn_scaling_auto_toggled_cb),
+			 prefs_themes);
+#endif
+
 	g_signal_connect(G_OBJECT(btn_remove), "clicked",
 			 G_CALLBACK(prefs_themes_btn_remove_clicked_cb),
 			 NULL);
@@ -989,6 +1150,14 @@ static void prefs_themes_create_widget(PrefsPage *page, GtkWindow *window, gpoin
 
 	prefs_themes->op_menu     = menu_themes;
 
+#ifdef HAVE_SVG
+	prefs_themes->checkbtn_enable_alpha   = checkbtn_enable_alpha;
+	prefs_themes->checkbtn_enable_scaling = checkbtn_enable_scaling;
+	prefs_themes->checkbtn_scaling_auto   = checkbtn_scaling_auto;
+	prefs_themes->label_scaling_ppi       = label_scaling_ppi;
+	prefs_themes->spinbtn_scaling_ppi     = spinbtn_scaling_ppi;
+#endif
+
 	prefs_themes->page.widget = vbox1;
 	
 	prefs_themes_set_themes_menu(GTK_COMBO_BOX(menu_themes), tdata);
@@ -1010,6 +1179,22 @@ static void prefs_themes_save(PrefsPage *page)
 {
 	ThemesData *tdata = prefs_themes_data;
 	gchar      *theme_str = tdata->displayed;
+#ifdef HAVE_SVG
+	ThemesPage *tpage = (ThemesPage *) page;
+	gboolean alpha = prefs_common.enable_alpha_svg;
+	gboolean scaling = prefs_common.enable_pixmap_scaling;
+	gboolean scaling_auto = prefs_common.pixmap_scaling_auto;
+	gint scaling_ppi = prefs_common.pixmap_scaling_ppi;
+
+	prefs_common.enable_alpha_svg = gtk_toggle_button_get_active(
+		GTK_TOGGLE_BUTTON (tpage->checkbtn_enable_alpha));
+	prefs_common.enable_pixmap_scaling = gtk_toggle_button_get_active(
+		GTK_TOGGLE_BUTTON (tpage->checkbtn_enable_scaling));
+	prefs_common.pixmap_scaling_auto = gtk_toggle_button_get_active(
+		GTK_TOGGLE_BUTTON (tpage->checkbtn_scaling_auto));
+	prefs_common.pixmap_scaling_ppi = gtk_spin_button_get_value_as_int (
+		GTK_SPIN_BUTTON (tpage->spinbtn_scaling_ppi));
+#endif
 
 	if (!IS_CURRENT_THEME(theme_str)) {
 		debug_print("Changing theme to %s\n", theme_str);
@@ -1023,5 +1208,18 @@ static void prefs_themes_save(PrefsPage *page)
 
 		prefs_themes_update_buttons(tdata);
 	}
+#ifdef HAVE_SVG
+	else if (scaling != prefs_common.enable_pixmap_scaling
+			|| alpha != prefs_common.enable_alpha_svg
+			|| (scaling_auto != prefs_common.pixmap_scaling_auto
+				&& scaling_ppi != prefs_common.pixmap_scaling_ppi)) {
+		/* same theme, different scaling options */
+		debug_print("Updating theme scaling\n");
+
+		main_window_reflect_prefs_all_real(FALSE);
+		compose_reflect_prefs_pixmap_theme();
+		addrcompl_reflect_prefs_pixmap_theme();
+	}
+#endif
 }
 

commit 89eb1e67c5e46464e0c12256af6c8b15a3d32bae
Author: Ricardo Mones <ricardo at mones.org>
Date:   Wed Feb 1 00:27:19 2017 +0100

    Add SVG icon scaling/rendering preferences
    
    • 'enable_alpha_svg' to use alpha channel when rendering
    • 'enable_pixmap_scaling' to bypass SVG's own natural size
    • 'pixmap_scaling_auto' to compute a PPI or use a user defined value
    • 'pixmap_scaling_ppi' to set a user defined value for PPI

diff --git a/src/common/defs.h b/src/common/defs.h
index 4c4fd39..5ab20e6 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -172,6 +172,10 @@
 
 #define DEFAULT_PIXMAP_THEME	"INTERNAL_DEFAULT"
 #define PIXMAP_THEME_DIR		"themes"
+#ifdef HAVE_SVG
+#define MIN_PPI 96
+#define MAX_PPI 300
+#endif
 
 #define AVATAR_NONE	0
 #define AVATAR_XFACE	1
diff --git a/src/prefs_common.c b/src/prefs_common.c
index 7be13c4..66b1b38 100644
--- a/src/prefs_common.c
+++ b/src/prefs_common.c
@@ -121,6 +121,16 @@ static PrefParam param_os_specific[] = {
 	/* Interface */
 	{"pixmap_theme_path", DEFAULT_PIXMAP_THEME, 
 	 &prefs_common.pixmap_theme_path, P_STRING, NULL, NULL, NULL},
+#ifdef HAVE_SVG
+	{"enable_alpha_svg", "TRUE",
+	 &prefs_common.enable_alpha_svg, P_BOOL, NULL, NULL, NULL},
+	{"enable_pixmap_scaling", "TRUE",
+	 &prefs_common.enable_pixmap_scaling, P_BOOL, NULL, NULL, NULL},
+	{"pixmap_scaling_auto", "TRUE",
+	 &prefs_common.pixmap_scaling_auto, P_BOOL, NULL, NULL, NULL},
+	{"pixmap_scaling_ppi", "96",
+	 &prefs_common.pixmap_scaling_ppi, P_INT, NULL, NULL, NULL},
+#endif
 
 	/* Other */
 	{"ext_editor_command", "notepad %s",
@@ -838,6 +848,20 @@ static PrefParam param[] = {
 	{"pixmap_theme_path", DEFAULT_PIXMAP_THEME, 
 	 &SPECIFIC_PREFS.pixmap_theme_path, P_STRING,
 	 NULL, NULL, NULL},
+#ifdef HAVE_SVG
+	{"enable_alpha_svg", "TRUE",
+	 &SPECIFIC_PREFS.enable_alpha_svg, P_BOOL,
+	 NULL, NULL, NULL},
+	{"enable_pixmap_scaling", "TRUE",
+	 &SPECIFIC_PREFS.enable_pixmap_scaling, P_BOOL,
+	 NULL, NULL, NULL},
+	{"pixmap_scaling_auto", "TRUE",
+	 &SPECIFIC_PREFS.pixmap_scaling_auto, P_BOOL,
+	 NULL, NULL, NULL},
+	{"pixmap_scaling_ppi", "96",
+	 &SPECIFIC_PREFS.pixmap_scaling_ppi, P_INT,
+	 NULL, NULL, NULL},
+#endif
 
 	{"ask_mark_all_read", "TRUE", &prefs_common.ask_mark_all_read, P_BOOL,
 	 NULL, NULL, NULL},
diff --git a/src/prefs_common.h b/src/prefs_common.h
index 467ecdd..179e163 100644
--- a/src/prefs_common.h
+++ b/src/prefs_common.h
@@ -385,6 +385,12 @@ struct _PrefsCommon
 	SummaryFromShow summary_from_show;
 	gboolean add_address_by_click;
 	gchar *pixmap_theme_path;
+#ifdef HAVE_SVG
+	gboolean enable_alpha_svg;
+	gboolean enable_pixmap_scaling;
+	gboolean pixmap_scaling_auto;
+	gint pixmap_scaling_ppi;
+#endif
 	int hover_timeout; /* msecs mouse hover timeout */
 	gboolean ask_mark_all_read;
 	gboolean ask_apply_per_account_filtering_rules;
diff --git a/src/stock_pixmap.c b/src/stock_pixmap.c
index 3a59a36..fcaa79e 100644
--- a/src/stock_pixmap.c
+++ b/src/stock_pixmap.c
@@ -26,6 +26,9 @@
 #include <librsvg/rsvg.h>
 #include <string.h>
 #include <dirent.h>
+#ifdef HAVE_SVG
+#include <math.h>
+#endif
 
 #include "defs.h"
 #include "stock_pixmap.h"
@@ -614,11 +617,6 @@ GdkPixbuf *pixbuf_from_svg_like_icon(char *filename, GError **error, StockPixmap
 	cm_return_val_if_fail(filename != NULL, NULL);
 	cm_return_val_if_fail(icondata != NULL, NULL);
 
-	if (sscanf((icondata->data)[0], "%d %d ", &width, &height) != 2) {
-		g_warning("failed reading icondata width and height");
-		return NULL;
-	}
-
 	/* load SVG file */
 	handle = rsvg_handle_new_from_file(filename, error);
 	if (handle == NULL) {
@@ -626,6 +624,28 @@ GdkPixbuf *pixbuf_from_svg_like_icon(char *filename, GError **error, StockPixmap
 				(*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,
@@ -689,7 +709,8 @@ try_next_extension:
 					GError *err = NULL;
 #ifdef HAVE_SVG
 					if (!strncmp(extension[i], ".svg", 4)) {
-						pix = pixbuf_from_svg_like_icon(icon_file_name, &err, pix_d, TRUE);
+						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);
 					}

commit 427ba2698e8a780c61597357cbe05a37c0946cff
Author: Ricardo Mones <ricardo at mones.org>
Date:   Mon Jan 30 23:22:20 2017 +0100

    Render SVG scaled to default icon size
    
    Default icon sizes are parsed from icon data, which is suboptimal
    since these sizes can be known at compile time.

diff --git a/src/stock_pixmap.c b/src/stock_pixmap.c
index 947b2e6..3a59a36 100644
--- a/src/stock_pixmap.c
+++ b/src/stock_pixmap.c
@@ -494,6 +494,163 @@ GtkWidget *stock_pixmap_widget(StockPixmap icon)
 	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);
+
+	if (sscanf((icondata->data)[0], "%d %d ", &width, &height) != 2) {
+		g_warning("failed reading icondata width and height");
+		return 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;
+	}
+	/* 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
  */
@@ -532,7 +689,7 @@ try_next_extension:
 					GError *err = NULL;
 #ifdef HAVE_SVG
 					if (!strncmp(extension[i], ".svg", 4)) {
-						pix = rsvg_pixbuf_from_file(icon_file_name, &err);
+						pix = pixbuf_from_svg_like_icon(icon_file_name, &err, pix_d, TRUE);
 					} else {
 						pix = gdk_pixbuf_new_from_file(icon_file_name, &err);
 					}

commit db434c2b05aec33ca6c3cc4fda792d40cf34942c
Author: Ricardo Mones <ricardo at mones.org>
Date:   Sat Jan 28 21:29:30 2017 +0100

    Load SVG files the deprecated way

diff --git a/src/stock_pixmap.c b/src/stock_pixmap.c
index b401fa7..947b2e6 100644
--- a/src/stock_pixmap.c
+++ b/src/stock_pixmap.c
@@ -23,6 +23,7 @@
 
 #include <glib.h>
 #include <gtk/gtk.h>
+#include <librsvg/rsvg.h>
 #include <string.h>
 #include <dirent.h>
 
@@ -468,6 +469,9 @@ static StockPixmapData pixmaps[] =
 static const char *extension[] = {
 	".png",
 	".xpm",
+#ifdef HAVE_SVG
+	".svg",
+#endif
 	NULL
 };
 
@@ -526,7 +530,15 @@ try_next_extension:
 							     NULL);
 				if (is_file_exist(icon_file_name)) {
 					GError *err = NULL;
+#ifdef HAVE_SVG
+					if (!strncmp(extension[i], ".svg", 4)) {
+						pix = rsvg_pixbuf_from_file(icon_file_name, &err);
+					} 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) {

commit cdf48fc3e9ce71ef09c0b9ddbdf7057f6d36e6da
Author: Ricardo Mones <ricardo at mones.org>
Date:   Fri Jan 27 23:41:15 2017 +0100

    Configure SVG library
    
    • New feature flag HAVE_SVG, enabled by default if dependencies
      are available (librsvg-2.0 >= 2.36.0).
    • New item in About window's Features tab for librSVG.

diff --git a/claws-features.h.in b/claws-features.h.in
index 0d5e8ad..65d71e6 100644
--- a/claws-features.h.in
+++ b/claws-features.h.in
@@ -7,6 +7,7 @@
 #undef HAVE_NETWORKMANAGER_SUPPORT
 #undef HAVE_STARTUP_NOTIFICATION
 #undef HAVE_VALGRIND
+#undef HAVE_SVG
 #undef USE_BOGOFILTER_PLUGIN
 #undef USE_ENCHANT
 #undef USE_GNUTLS
diff --git a/configure.ac b/configure.ac
index e8e4ae4..99cb448 100644
--- a/configure.ac
+++ b/configure.ac
@@ -290,6 +290,10 @@ AC_ARG_ENABLE(gtk3,
 		[  --enable-gtk3                   Build GTK3 support],
 		[enable_gtk3=$enableval], [enable_gtk3=no])
 
+AC_ARG_ENABLE(svg,
+        [  --disable-svg                   Do not build SVG support],
+        [enable_svg=$enableval], [enable_svg=yes])
+
 AC_ARG_ENABLE(deprecated,
 		[  --disable-deprecated            Disable deprecated GTK functions],
 		[GTK_CFLAGS="$GTK_CFLAGS -DG_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED"], [])
@@ -927,6 +931,25 @@ else
 fi
 AM_CONDITIONAL(CLAWS_LIBETPAN, test "x$libetpan_result" = "xyes")
 
+dnl librsvg
+AC_MSG_CHECKING([whether to use librsvg])
+if test x"$enable_svg" = xyes; then
+	AC_MSG_RESULT(yes)
+    PKG_CHECK_MODULES([SVG], [librsvg-2.0 >= 2.36.0 cairo >= 1.0.0],
+    [
+        AC_SUBST(SVG_CFLAGS)
+        AC_SUBST(SVG_LIBS)
+		AC_DEFINE(HAVE_SVG, 1, [Define if librsvg2 is available for SVG support])
+		enable_svg=yes
+	],
+	[
+		AC_MSG_NOTICE([SVG support deactivated as librsvg2 >= 2.36 was not found])
+		enable_svg=no
+	])
+else
+	AC_MSG_RESULT(no)
+fi
+
 AC_MSG_CHECKING([whether to use valgrind])
 if test x$enable_valgrind = xyes; then
 	AC_MSG_RESULT(yes)
@@ -2009,6 +2032,7 @@ echo "DBUS               : $enable_dbus"
 echo "NetworkManager     : $enable_networkmanager"
 echo "Manual             : $enable_manual"
 echo "Generic UMPC code  : $enable_generic_umpc"
+echo "SVG support        : $enable_svg"
 echo "Config dir         : $ac_cv_with_config_dir"
 echo "Password crypto    : $pwd_crypto"
 
diff --git a/src/Makefile.am b/src/Makefile.am
index b78a58d..ba1b837 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -599,6 +599,7 @@ claws_mail_LDADD = \
 	$(STARTUP_NOTIFICATION_LIBS) \
 	$(LIBETPAN_LIBS) \
 	$(DBUS_LIBS) \
+	$(SVG_LIBS) \
 	$(CONTACTS_LIBS)
 
 pixmapdir=$(datadir)/icons/hicolor/48x48/apps
@@ -619,6 +620,7 @@ AM_CPPFLAGS = \
 	$(LIBETPAN_CPPFLAGS) \
 	$(STARTUP_NOTIFICATION_CFLAGS) \
 	$(DBUS_CFLAGS) \
+	$(SVG_CFLAGS) \
 	$(NETWORKMANAGER_SUPPORT_CFLAGS) \
 	$(VALGRIND_CFLAGS) \
 	$(CONTACTS_CFLAGS)
diff --git a/src/gtk/about.c b/src/gtk/about.c
index 86570ac..9809892 100644
--- a/src/gtk/about.c
+++ b/src/gtk/about.c
@@ -510,6 +510,16 @@ static GtkWidget *about_create_child_page_features(void)
 	gtk_text_buffer_insert(buffer, &iter,
 		(gchar *)C_("NetworkManager", "adds support for detection of network connection changes\n"), -1);
 
+#if HAVE_SVG
+	gtk_text_buffer_insert_pixbuf(buffer, &iter, active_pixbuf);
+#else
+	gtk_text_buffer_insert_pixbuf(buffer, &iter, inactive_pixbuf);
+#endif
+	gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, (" librSVG "), -1,
+						 "bold", NULL);
+	gtk_text_buffer_insert(buffer, &iter,
+		(gchar *)C_("librSVG", "adds support for SVG themes\n"), -1);
+
 	return scrolledwin;
 }
 

-----------------------------------------------------------------------


hooks/post-receive
-- 
Claws Mail


More information about the Commits mailing list