diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 7ed75b32a8..7b130e3cf3 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -561,7 +561,8 @@ gtk_private_h_sources = \ gtkwidgetprivate.h \ gtkwin32themeprivate.h \ gtkwindowprivate.h \ - gtktreemenu.h + gtktreemenu.h \ + gdkpixbufutilsprivate.h # GTK+ C sources to build the library from gtk_base_c_sources = \ @@ -916,7 +917,8 @@ gtk_base_c_sources = \ gtkwidgetpath.c \ gtkwindow.c \ gtkwindowgroup.c \ - gtkwin32theme.c + gtkwin32theme.c \ + gdkpixbufutils.c if USE_QUARTZ gtk_base_c_sources += \ diff --git a/gtk/gdkpixbufutils.c b/gtk/gdkpixbufutils.c new file mode 100644 index 0000000000..3da0323623 --- /dev/null +++ b/gtk/gdkpixbufutils.c @@ -0,0 +1,132 @@ +/* Copyright (C) 2016 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gdkpixbufutilsprivate.h" + +static GdkPixbuf * +load_from_stream (GdkPixbufLoader *loader, + GInputStream *stream, + GCancellable *cancellable, + GError **error) +{ + GdkPixbuf *pixbuf; + gssize n_read; + guchar buffer[65536]; + gboolean res; + + res = TRUE; + while (1) + { + n_read = g_input_stream_read (stream, buffer, sizeof (buffer), cancellable, error); + if (n_read < 0) + { + res = FALSE; + error = NULL; /* Ignore further errors */ + break; + } + + if (n_read == 0) + break; + + if (!gdk_pixbuf_loader_write (loader, buffer, n_read, error)) + { + res = FALSE; + error = NULL; + break; + } + } + + if (!gdk_pixbuf_loader_close (loader, error)) + { + res = FALSE; + error = NULL; + } + + pixbuf = NULL; + + if (res) + { + pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); + if (pixbuf) + g_object_ref (pixbuf); + } + + return pixbuf; +} + +static void +size_prepared_cb (GdkPixbufLoader *loader, + gint width, + gint height, + gpointer data) +{ + gdouble *scale = data; + + width = MAX (*scale * width, 1); + height = MAX (*scale * height, 1); + + gdk_pixbuf_loader_set_size (loader, width, height); +} + +/* Like gdk_pixbuf_new_from_stream_at_scale, but + * load the image at its original size times the + * given scale. + */ +GdkPixbuf * +_gdk_pixbuf_new_from_stream_scaled (GInputStream *stream, + gdouble scale, + GCancellable *cancellable, + GError **error) +{ + GdkPixbufLoader *loader; + GdkPixbuf *pixbuf; + + loader = gdk_pixbuf_loader_new (); + + g_signal_connect (loader, "size-prepared", + G_CALLBACK (size_prepared_cb), &scale); + + pixbuf = load_from_stream (loader, stream, cancellable, error); + + g_object_unref (loader); + + return pixbuf; +} + +/* Like gdk_pixbuf_new_from_resource_at_scale, but + * load the image at its original size times the + * given scale. + */ +GdkPixbuf * +_gdk_pixbuf_new_from_resource_scaled (const gchar *resource_path, + gdouble scale, + GError **error) +{ + GInputStream *stream; + GdkPixbuf *pixbuf; + + stream = g_resources_open_stream (resource_path, 0, error); + if (stream == NULL) + return NULL; + + pixbuf = _gdk_pixbuf_new_from_stream_scaled (stream, scale, NULL, error); + g_object_unref (stream); + + return pixbuf; +} + diff --git a/gtk/gdkpixbufutilsprivate.h b/gtk/gdkpixbufutilsprivate.h new file mode 100644 index 0000000000..f01f1774b6 --- /dev/null +++ b/gtk/gdkpixbufutilsprivate.h @@ -0,0 +1,35 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2016 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef __GDK_PIXBUF_UTILS_PRIVATE_H__ +#define __GDK_PIXBUF_UTILS_PRIVATE_H__ + +#include + +G_BEGIN_DECLS + +GdkPixbuf *_gdk_pixbuf_new_from_stream_scaled (GInputStream *stream, + gdouble scale, + GCancellable *cancellable, + GError **error); +GdkPixbuf *_gdk_pixbuf_new_from_resource_scaled (const gchar *resource_path, + gdouble scale, + GError **error); + +G_END_DECLS + +#endif /* __GDK_PIXBUF_UTILS_PRIVATE_H__ */ diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c index 6de7f33179..0a0425829b 100644 --- a/gtk/gtkicontheme.c +++ b/gtk/gtkicontheme.c @@ -49,6 +49,7 @@ #include "gtksettingsprivate.h" #include "gtkstylecontextprivate.h" #include "gtkprivate.h" +#include "gdkpixbufutilsprivate.h" #undef GDK_DEPRECATED #undef GDK_DEPRECATED_FOR @@ -3880,9 +3881,15 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info) size = scaled_desired_size; else size = icon_info->dir_size * dir_scale * icon_info->scale; - source_pixbuf = gdk_pixbuf_new_from_resource_at_scale (icon_info->filename, - size, size, TRUE, - &icon_info->load_error); + + if (size == 0) + source_pixbuf = _gdk_pixbuf_new_from_resource_scaled (icon_info->filename, + icon_info->desired_scale, + &icon_info->load_error); + else + source_pixbuf = gdk_pixbuf_new_from_resource_at_scale (icon_info->filename, + size, size, TRUE, + &icon_info->load_error); } else source_pixbuf = gdk_pixbuf_new_from_resource (icon_info->filename, @@ -3910,10 +3917,16 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info) size = scaled_desired_size; else size = icon_info->dir_size * dir_scale * icon_info->scale; - source_pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream, - size, size, - TRUE, NULL, - &icon_info->load_error); + if (size == 0) + source_pixbuf = _gdk_pixbuf_new_from_stream_scaled (stream, + icon_info->desired_scale, + NULL, + &icon_info->load_error); + else + source_pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream, + size, size, + TRUE, NULL, + &icon_info->load_error); } else source_pixbuf = gdk_pixbuf_new_from_stream (stream,