From aa873e77090f788e6f231237f729552e42a6edc8 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Sun, 22 Oct 2017 22:57:21 +0200 Subject: [PATCH] GtkWindow: Use cairo_surface_t for icons --- gtk/gtkheaderbar.c | 13 +-- gtk/gtkwindow.c | 179 +++++++++++++++++++++++++++-------------- gtk/gtkwindow.h | 6 +- gtk/gtkwindowprivate.h | 5 +- 4 files changed, 130 insertions(+), 73 deletions(-) diff --git a/gtk/gtkheaderbar.c b/gtk/gtkheaderbar.c index de2501702a..ba8786ded0 100644 --- a/gtk/gtkheaderbar.c +++ b/gtk/gtkheaderbar.c @@ -200,7 +200,7 @@ _gtk_header_bar_update_window_icon (GtkHeaderBar *bar, GtkWindow *window) { GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar); - GdkPixbuf *pixbuf; + cairo_surface_t *surface; gint scale; if (priv->titlebar_icon == NULL) @@ -208,19 +208,14 @@ _gtk_header_bar_update_window_icon (GtkHeaderBar *bar, scale = gtk_widget_get_scale_factor (priv->titlebar_icon); if (GTK_IS_BUTTON (gtk_widget_get_parent (priv->titlebar_icon))) - pixbuf = gtk_window_get_icon_for_size (window, scale * 16); + surface = gtk_window_get_icon_for_size (window, 16, scale); else - pixbuf = gtk_window_get_icon_for_size (window, scale * 20); + surface = gtk_window_get_icon_for_size (window, 20, scale); - if (pixbuf) + if (surface) { - cairo_surface_t *surface; - - surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, gtk_widget_get_window (priv->titlebar_icon)); - gtk_image_set_from_surface (GTK_IMAGE (priv->titlebar_icon), surface); cairo_surface_destroy (surface); - g_object_unref (pixbuf); gtk_widget_show (priv->titlebar_icon); return TRUE; diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index c5d9c17ae3..57cec5da6b 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -24,6 +24,8 @@ #include "config.h" +#include + #include "gtkwindow.h" #include @@ -927,7 +929,7 @@ gtk_window_class_init (GtkWindowClass *klass) g_param_spec_object ("icon", P_("Icon"), P_("Icon for this window"), - GDK_TYPE_PIXBUF, + CAIRO_GOBJECT_TYPE_SURFACE, GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); /** @@ -4415,10 +4417,11 @@ static GList * icon_list_from_theme (GtkWindow *window, const gchar *name) { + GtkWindowPrivate *priv = window->priv; GList *list; GtkIconTheme *icon_theme; - GdkPixbuf *icon; + cairo_surface_t *icon; gint *sizes; gint i; @@ -4437,11 +4440,15 @@ icon_list_from_theme (GtkWindow *window, * fixed size of 48. */ if (sizes[i] == -1) - icon = gtk_icon_theme_load_icon (icon_theme, name, - 48, 0, NULL); + icon = gtk_icon_theme_load_surface (icon_theme, name, + 48, priv->scale, + _gtk_widget_get_window (GTK_WIDGET (window)), + 0, NULL); else - icon = gtk_icon_theme_load_icon (icon_theme, name, - sizes[i], 0, NULL); + icon = gtk_icon_theme_load_surface (icon_theme, name, + sizes[i], priv->scale, + _gtk_widget_get_window (GTK_WIDGET (window)), + 0, NULL); if (icon) list = g_list_append (list, icon); } @@ -4526,43 +4533,90 @@ gtk_window_realize_icon (GtkWindow *window) } } -static GdkPixbuf * -icon_from_list (GList *list, - gint size) +static cairo_surface_t * +icon_from_list (GtkWindow *window, + GList *list, + gint size, + gint scale) { - GdkPixbuf *best; - GdkPixbuf *pixbuf; + cairo_surface_t *best; + cairo_surface_t *surface; GList *l; best = NULL; + /* Look for exact match */ for (l = list; l; l = l->next) { - pixbuf = list->data; - if (gdk_pixbuf_get_width (pixbuf) <= size) - { - best = g_object_ref (pixbuf); + surface = list->data; + double x_scale; + + cairo_surface_get_device_scale (surface, &x_scale, NULL); + + if (cairo_image_surface_get_width (surface) == size && + x_scale == scale) + { + best = cairo_surface_reference (surface); break; - } + } } - if (best == NULL) - best = gdk_pixbuf_scale_simple (GDK_PIXBUF (list->data), size, size, GDK_INTERP_BILINEAR); + if (best != NULL) + return best; + + /* Ignore scale */ + for (l = list; l; l = l->next) + { + surface = list->data; + double x_scale; + + cairo_surface_get_device_scale (surface, &x_scale, NULL); + + if (cairo_image_surface_get_width (surface) * x_scale <= size) + { + best = cairo_surface_reference (surface); + break; + } + } + + if (best == NULL && list != NULL) + best = (cairo_surface_t *)list->data; + + + if (best) + { + cairo_t *cr; + surface = + gdk_window_create_similar_image_surface (_gtk_widget_get_window (GTK_WIDGET(window)), + CAIRO_FORMAT_ARGB32, + size, size, scale); + cr = cairo_create (surface); + cairo_set_source_surface (cr, best, 0, 0); + cairo_scale (cr, + size / cairo_image_surface_get_width (best), + size / cairo_image_surface_get_height (best)); + cairo_paint (cr); + cairo_destroy (cr); + } return best; } -static GdkPixbuf * -icon_from_name (const gchar *name, - gint size) +static cairo_surface_t * +icon_from_name (GtkWindow *window, + const gchar *name, + gint size, + gint scale) { - return gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), - name, size, - GTK_ICON_LOOKUP_FORCE_SIZE, NULL); + return gtk_icon_theme_load_surface (gtk_icon_theme_get_default (), + name, size, scale, + _gtk_widget_get_window (GTK_WIDGET(window)), + GTK_ICON_LOOKUP_FORCE_SIZE, NULL); } -GdkPixbuf * +cairo_surface_t * gtk_window_get_icon_for_size (GtkWindow *window, - gint size) + int size, + int scale) { GtkWindowPrivate *priv = window->priv; GtkWindowIconInfo *info; @@ -4571,24 +4625,24 @@ gtk_window_get_icon_for_size (GtkWindow *window, info = ensure_icon_info (window); if (info->icon_list != NULL) - return icon_from_list (info->icon_list, size); + return icon_from_list (window, info->icon_list, size, scale); name = gtk_window_get_icon_name (window); if (name != NULL) - return icon_from_name (name, size); + return icon_from_name (window, name, size, scale); if (priv->transient_parent != NULL) { info = ensure_icon_info (priv->transient_parent); if (info->icon_list) - return icon_from_list (info->icon_list, size); + return icon_from_list (window, info->icon_list, size, scale); } if (default_icon_list != NULL) - return icon_from_list (default_icon_list, size); + return icon_from_list (window, default_icon_list, size, scale); if (default_icon_name != NULL) - return icon_from_name (default_icon_name, size); + return icon_from_name (window, default_icon_name, size, scale); return NULL; } @@ -4614,7 +4668,7 @@ gtk_window_unrealize_icon (GtkWindow *window) /** * gtk_window_set_icon_list: * @window: a #GtkWindow - * @list: (element-type GdkPixbuf): list of #GdkPixbuf + * @list: (element-type cairo_surface_t): list of image surfaces * * Sets up the icon representing a #GtkWindow. The icon is used when * the window is minimized (also known as iconified). Some window @@ -4683,7 +4737,7 @@ gtk_window_set_icon_list (GtkWindow *window, * The list is copied, but the reference count on each * member won’t be incremented. * - * Returns: (element-type GdkPixbuf) (transfer container): copy of window’s icon list + * Returns: (element-type cairo_surface_t) (transfer container): copy of window’s icon list **/ GList* gtk_window_get_icon_list (GtkWindow *window) @@ -4727,12 +4781,12 @@ gtk_window_get_icon_list (GtkWindow *window) **/ void gtk_window_set_icon (GtkWindow *window, - GdkPixbuf *icon) + cairo_surface_t *icon) { GList *list; g_return_if_fail (GTK_IS_WINDOW (window)); - g_return_if_fail (icon == NULL || GDK_IS_PIXBUF (icon)); + g_return_if_fail (icon == NULL); list = NULL; @@ -4829,7 +4883,7 @@ gtk_window_get_icon_name (GtkWindow *window) * * Returns: (transfer none): icon for window **/ -GdkPixbuf* +cairo_surface_t * gtk_window_get_icon (GtkWindow *window) { GtkWindowIconInfo *info; @@ -4838,19 +4892,21 @@ gtk_window_get_icon (GtkWindow *window) info = get_icon_info (window); if (info && info->icon_list) - return GDK_PIXBUF (info->icon_list->data); + return (cairo_surface_t *) (info->icon_list->data); else return NULL; } -/* Load pixbuf, printing warning on failure if error == NULL +/* Load surface, printing warning on failure if error == NULL */ -static GdkPixbuf * -load_pixbuf_verbosely (const char *filename, - GError **err) +static cairo_surface_t * +load_surface_verbosely (GdkWindow *window, + const char *filename, + GError **err) { GError *local_err = NULL; GdkPixbuf *pixbuf; + cairo_surface_t *surface = NULL; pixbuf = gdk_pixbuf_new_from_file (filename, &local_err); @@ -4865,8 +4921,13 @@ load_pixbuf_verbosely (const char *filename, g_error_free (local_err); } } + else + { + surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, window); + g_object_unref (pixbuf); + } - return pixbuf; + return surface; } /** @@ -4879,7 +4940,7 @@ load_pixbuf_verbosely (const char *filename, * Warns on failure if @err is %NULL. * * This function is equivalent to calling gtk_window_set_icon() - * with a pixbuf created by loading the image from @filename. + * with a surface created by loading the image from @filename. * * Returns: %TRUE if setting the icon succeeded. * @@ -4890,12 +4951,12 @@ gtk_window_set_icon_from_file (GtkWindow *window, const gchar *filename, GError **err) { - GdkPixbuf *pixbuf = load_pixbuf_verbosely (filename, err); + cairo_surface_t *surface = load_surface_verbosely (_gtk_widget_get_window (GTK_WIDGET (window)), filename, err); - if (pixbuf) + if (surface) { - gtk_window_set_icon (window, pixbuf); - g_object_unref (pixbuf); + gtk_window_set_icon (window, surface); + cairo_surface_destroy (surface); return TRUE; } @@ -4905,7 +4966,7 @@ gtk_window_set_icon_from_file (GtkWindow *window, /** * gtk_window_set_default_icon_list: - * @list: (element-type GdkPixbuf) (transfer container): a list of #GdkPixbuf + * @list: (element-type cairo_surface_t) (transfer container): a list of #cairo_surface_t image surfaces * * Sets an icon list to be used as fallback for windows that haven't * had gtk_window_set_icon_list() called on them to set up a @@ -4928,9 +4989,9 @@ gtk_window_set_default_icon_list (GList *list) default_icon_serial++; g_list_foreach (list, - (GFunc) g_object_ref, NULL); + (GFunc) cairo_surface_reference, NULL); - g_list_free_full (default_icon_list, g_object_unref); + g_list_free_full (default_icon_list, (GDestroyNotify)cairo_surface_destroy); default_icon_list = g_list_copy (list); @@ -4960,16 +5021,16 @@ gtk_window_set_default_icon_list (GList *list) * @icon: the icon * * Sets an icon to be used as fallback for windows that haven't - * had gtk_window_set_icon() called on them from a pixbuf. + * had gtk_window_set_icon() called on them from a surface. * * Since: 2.4 **/ void -gtk_window_set_default_icon (GdkPixbuf *icon) +gtk_window_set_default_icon (cairo_surface_t *icon) { GList *list; - g_return_if_fail (GDK_IS_PIXBUF (icon)); + g_return_if_fail (cairo_surface_get_type (icon) == CAIRO_SURFACE_TYPE_IMAGE); list = g_list_prepend (NULL, icon); gtk_window_set_default_icon_list (list); @@ -5059,12 +5120,12 @@ gboolean gtk_window_set_default_icon_from_file (const gchar *filename, GError **err) { - GdkPixbuf *pixbuf = load_pixbuf_verbosely (filename, err); + cairo_surface_t *surface = load_surface_verbosely (NULL, filename, err); - if (pixbuf) + if (surface) { - gtk_window_set_default_icon (pixbuf); - g_object_unref (pixbuf); + gtk_window_set_default_icon (surface); + cairo_surface_destroy (surface); return TRUE; } @@ -5077,10 +5138,10 @@ gtk_window_set_default_icon_from_file (const gchar *filename, * * Gets the value set by gtk_window_set_default_icon_list(). * The list is a copy and should be freed with g_list_free(), - * but the pixbufs in the list have not had their reference count + * but the surfaces in the list have not had their reference count * incremented. * - * Returns: (element-type GdkPixbuf) (transfer container): copy of default icon list + * Returns: (element-type cairo_surface_t) (transfer container): copy of default icon list **/ GList* gtk_window_get_default_icon_list (void) diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h index 0f247e0349..05e86d28e1 100644 --- a/gtk/gtkwindow.h +++ b/gtk/gtkwindow.h @@ -277,7 +277,7 @@ GDK_AVAILABLE_IN_ALL GList* gtk_window_get_icon_list (GtkWindow *window); GDK_AVAILABLE_IN_ALL void gtk_window_set_icon (GtkWindow *window, - GdkPixbuf *icon); + cairo_surface_t *icon); GDK_AVAILABLE_IN_ALL void gtk_window_set_icon_name (GtkWindow *window, const gchar *name); @@ -286,7 +286,7 @@ gboolean gtk_window_set_icon_from_file (GtkWindow *window, const gchar *filename, GError **err); GDK_AVAILABLE_IN_ALL -GdkPixbuf* gtk_window_get_icon (GtkWindow *window); +cairo_surface_t * gtk_window_get_icon (GtkWindow *window); GDK_AVAILABLE_IN_ALL const gchar * gtk_window_get_icon_name (GtkWindow *window); GDK_AVAILABLE_IN_ALL @@ -294,7 +294,7 @@ void gtk_window_set_default_icon_list (GList *list); GDK_AVAILABLE_IN_ALL GList* gtk_window_get_default_icon_list (void); GDK_AVAILABLE_IN_ALL -void gtk_window_set_default_icon (GdkPixbuf *icon); +void gtk_window_set_default_icon (cairo_surface_t *icon); GDK_AVAILABLE_IN_ALL void gtk_window_set_default_icon_name (const gchar *name); GDK_AVAILABLE_IN_ALL diff --git a/gtk/gtkwindowprivate.h b/gtk/gtkwindowprivate.h index 7c37ff3db0..fc6bde7cc3 100644 --- a/gtk/gtkwindowprivate.h +++ b/gtk/gtkwindowprivate.h @@ -110,8 +110,9 @@ GtkWidget * _gtk_window_get_popover_parent (GtkWindow *window, gboolean _gtk_window_is_popover_widget (GtkWindow *window, GtkWidget *popover); -GdkPixbuf *gtk_window_get_icon_for_size (GtkWindow *window, - gint size); +cairo_surface_t *gtk_window_get_icon_for_size (GtkWindow *window, + int size, + int scale); void gtk_window_set_use_subsurface (GtkWindow *window, gboolean use_subsurface);