GtkWindow: Use cairo_surface_t for icons

This commit is contained in:
Alexander Larsson 2017-10-22 22:57:21 +02:00
parent d8a4503c53
commit aa873e7709
4 changed files with 130 additions and 73 deletions

View File

@ -200,7 +200,7 @@ _gtk_header_bar_update_window_icon (GtkHeaderBar *bar,
GtkWindow *window) GtkWindow *window)
{ {
GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar); GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar);
GdkPixbuf *pixbuf; cairo_surface_t *surface;
gint scale; gint scale;
if (priv->titlebar_icon == NULL) 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); scale = gtk_widget_get_scale_factor (priv->titlebar_icon);
if (GTK_IS_BUTTON (gtk_widget_get_parent (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 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); gtk_image_set_from_surface (GTK_IMAGE (priv->titlebar_icon), surface);
cairo_surface_destroy (surface); cairo_surface_destroy (surface);
g_object_unref (pixbuf);
gtk_widget_show (priv->titlebar_icon); gtk_widget_show (priv->titlebar_icon);
return TRUE; return TRUE;

View File

@ -24,6 +24,8 @@
#include "config.h" #include "config.h"
#include <cairo-gobject.h>
#include "gtkwindow.h" #include "gtkwindow.h"
#include <string.h> #include <string.h>
@ -927,7 +929,7 @@ gtk_window_class_init (GtkWindowClass *klass)
g_param_spec_object ("icon", g_param_spec_object ("icon",
P_("Icon"), P_("Icon"),
P_("Icon for this window"), P_("Icon for this window"),
GDK_TYPE_PIXBUF, CAIRO_GOBJECT_TYPE_SURFACE,
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
/** /**
@ -4415,10 +4417,11 @@ static GList *
icon_list_from_theme (GtkWindow *window, icon_list_from_theme (GtkWindow *window,
const gchar *name) const gchar *name)
{ {
GtkWindowPrivate *priv = window->priv;
GList *list; GList *list;
GtkIconTheme *icon_theme; GtkIconTheme *icon_theme;
GdkPixbuf *icon; cairo_surface_t *icon;
gint *sizes; gint *sizes;
gint i; gint i;
@ -4437,11 +4440,15 @@ icon_list_from_theme (GtkWindow *window,
* fixed size of 48. * fixed size of 48.
*/ */
if (sizes[i] == -1) if (sizes[i] == -1)
icon = gtk_icon_theme_load_icon (icon_theme, name, icon = gtk_icon_theme_load_surface (icon_theme, name,
48, 0, NULL); 48, priv->scale,
_gtk_widget_get_window (GTK_WIDGET (window)),
0, NULL);
else else
icon = gtk_icon_theme_load_icon (icon_theme, name, icon = gtk_icon_theme_load_surface (icon_theme, name,
sizes[i], 0, NULL); sizes[i], priv->scale,
_gtk_widget_get_window (GTK_WIDGET (window)),
0, NULL);
if (icon) if (icon)
list = g_list_append (list, icon); list = g_list_append (list, icon);
} }
@ -4526,43 +4533,90 @@ gtk_window_realize_icon (GtkWindow *window)
} }
} }
static GdkPixbuf * static cairo_surface_t *
icon_from_list (GList *list, icon_from_list (GtkWindow *window,
gint size) GList *list,
gint size,
gint scale)
{ {
GdkPixbuf *best; cairo_surface_t *best;
GdkPixbuf *pixbuf; cairo_surface_t *surface;
GList *l; GList *l;
best = NULL; best = NULL;
/* Look for exact match */
for (l = list; l; l = l->next) for (l = list; l; l = l->next)
{ {
pixbuf = list->data; surface = list->data;
if (gdk_pixbuf_get_width (pixbuf) <= size) double x_scale;
{
best = g_object_ref (pixbuf); 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; break;
} }
} }
if (best == NULL) if (best != NULL)
best = gdk_pixbuf_scale_simple (GDK_PIXBUF (list->data), size, size, GDK_INTERP_BILINEAR); 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; return best;
} }
static GdkPixbuf * static cairo_surface_t *
icon_from_name (const gchar *name, icon_from_name (GtkWindow *window,
gint size) const gchar *name,
gint size,
gint scale)
{ {
return gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), return gtk_icon_theme_load_surface (gtk_icon_theme_get_default (),
name, size, name, size, scale,
GTK_ICON_LOOKUP_FORCE_SIZE, NULL); _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, gtk_window_get_icon_for_size (GtkWindow *window,
gint size) int size,
int scale)
{ {
GtkWindowPrivate *priv = window->priv; GtkWindowPrivate *priv = window->priv;
GtkWindowIconInfo *info; GtkWindowIconInfo *info;
@ -4571,24 +4625,24 @@ gtk_window_get_icon_for_size (GtkWindow *window,
info = ensure_icon_info (window); info = ensure_icon_info (window);
if (info->icon_list != NULL) 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); name = gtk_window_get_icon_name (window);
if (name != NULL) if (name != NULL)
return icon_from_name (name, size); return icon_from_name (window, name, size, scale);
if (priv->transient_parent != NULL) if (priv->transient_parent != NULL)
{ {
info = ensure_icon_info (priv->transient_parent); info = ensure_icon_info (priv->transient_parent);
if (info->icon_list) 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) 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) 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; return NULL;
} }
@ -4614,7 +4668,7 @@ gtk_window_unrealize_icon (GtkWindow *window)
/** /**
* gtk_window_set_icon_list: * gtk_window_set_icon_list:
* @window: a #GtkWindow * @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 * Sets up the icon representing a #GtkWindow. The icon is used when
* the window is minimized (also known as iconified). Some window * 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 * The list is copied, but the reference count on each
* member wont be incremented. * member wont be incremented.
* *
* Returns: (element-type GdkPixbuf) (transfer container): copy of windows icon list * Returns: (element-type cairo_surface_t) (transfer container): copy of windows icon list
**/ **/
GList* GList*
gtk_window_get_icon_list (GtkWindow *window) gtk_window_get_icon_list (GtkWindow *window)
@ -4727,12 +4781,12 @@ gtk_window_get_icon_list (GtkWindow *window)
**/ **/
void void
gtk_window_set_icon (GtkWindow *window, gtk_window_set_icon (GtkWindow *window,
GdkPixbuf *icon) cairo_surface_t *icon)
{ {
GList *list; GList *list;
g_return_if_fail (GTK_IS_WINDOW (window)); 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; list = NULL;
@ -4829,7 +4883,7 @@ gtk_window_get_icon_name (GtkWindow *window)
* *
* Returns: (transfer none): icon for window * Returns: (transfer none): icon for window
**/ **/
GdkPixbuf* cairo_surface_t *
gtk_window_get_icon (GtkWindow *window) gtk_window_get_icon (GtkWindow *window)
{ {
GtkWindowIconInfo *info; GtkWindowIconInfo *info;
@ -4838,19 +4892,21 @@ gtk_window_get_icon (GtkWindow *window)
info = get_icon_info (window); info = get_icon_info (window);
if (info && info->icon_list) if (info && info->icon_list)
return GDK_PIXBUF (info->icon_list->data); return (cairo_surface_t *) (info->icon_list->data);
else else
return NULL; return NULL;
} }
/* Load pixbuf, printing warning on failure if error == NULL /* Load surface, printing warning on failure if error == NULL
*/ */
static GdkPixbuf * static cairo_surface_t *
load_pixbuf_verbosely (const char *filename, load_surface_verbosely (GdkWindow *window,
GError **err) const char *filename,
GError **err)
{ {
GError *local_err = NULL; GError *local_err = NULL;
GdkPixbuf *pixbuf; GdkPixbuf *pixbuf;
cairo_surface_t *surface = NULL;
pixbuf = gdk_pixbuf_new_from_file (filename, &local_err); pixbuf = gdk_pixbuf_new_from_file (filename, &local_err);
@ -4865,8 +4921,13 @@ load_pixbuf_verbosely (const char *filename,
g_error_free (local_err); 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. * Warns on failure if @err is %NULL.
* *
* This function is equivalent to calling gtk_window_set_icon() * 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. * Returns: %TRUE if setting the icon succeeded.
* *
@ -4890,12 +4951,12 @@ gtk_window_set_icon_from_file (GtkWindow *window,
const gchar *filename, const gchar *filename,
GError **err) 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); gtk_window_set_icon (window, surface);
g_object_unref (pixbuf); cairo_surface_destroy (surface);
return TRUE; return TRUE;
} }
@ -4905,7 +4966,7 @@ gtk_window_set_icon_from_file (GtkWindow *window,
/** /**
* gtk_window_set_default_icon_list: * 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 * 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 * 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++; default_icon_serial++;
g_list_foreach (list, 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); default_icon_list = g_list_copy (list);
@ -4960,16 +5021,16 @@ gtk_window_set_default_icon_list (GList *list)
* @icon: the icon * @icon: the icon
* *
* Sets an icon to be used as fallback for windows that haven't * 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 * Since: 2.4
**/ **/
void void
gtk_window_set_default_icon (GdkPixbuf *icon) gtk_window_set_default_icon (cairo_surface_t *icon)
{ {
GList *list; 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); list = g_list_prepend (NULL, icon);
gtk_window_set_default_icon_list (list); gtk_window_set_default_icon_list (list);
@ -5059,12 +5120,12 @@ gboolean
gtk_window_set_default_icon_from_file (const gchar *filename, gtk_window_set_default_icon_from_file (const gchar *filename,
GError **err) 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); gtk_window_set_default_icon (surface);
g_object_unref (pixbuf); cairo_surface_destroy (surface);
return TRUE; 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(). * Gets the value set by gtk_window_set_default_icon_list().
* The list is a copy and should be freed with g_list_free(), * 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. * 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* GList*
gtk_window_get_default_icon_list (void) gtk_window_get_default_icon_list (void)

View File

@ -277,7 +277,7 @@ GDK_AVAILABLE_IN_ALL
GList* gtk_window_get_icon_list (GtkWindow *window); GList* gtk_window_get_icon_list (GtkWindow *window);
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
void gtk_window_set_icon (GtkWindow *window, void gtk_window_set_icon (GtkWindow *window,
GdkPixbuf *icon); cairo_surface_t *icon);
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
void gtk_window_set_icon_name (GtkWindow *window, void gtk_window_set_icon_name (GtkWindow *window,
const gchar *name); const gchar *name);
@ -286,7 +286,7 @@ gboolean gtk_window_set_icon_from_file (GtkWindow *window,
const gchar *filename, const gchar *filename,
GError **err); GError **err);
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
GdkPixbuf* gtk_window_get_icon (GtkWindow *window); cairo_surface_t * gtk_window_get_icon (GtkWindow *window);
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
const gchar * gtk_window_get_icon_name (GtkWindow *window); const gchar * gtk_window_get_icon_name (GtkWindow *window);
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
@ -294,7 +294,7 @@ void gtk_window_set_default_icon_list (GList *list);
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL
GList* gtk_window_get_default_icon_list (void); GList* gtk_window_get_default_icon_list (void);
GDK_AVAILABLE_IN_ALL 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 GDK_AVAILABLE_IN_ALL
void gtk_window_set_default_icon_name (const gchar *name); void gtk_window_set_default_icon_name (const gchar *name);
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL

View File

@ -110,8 +110,9 @@ GtkWidget * _gtk_window_get_popover_parent (GtkWindow *window,
gboolean _gtk_window_is_popover_widget (GtkWindow *window, gboolean _gtk_window_is_popover_widget (GtkWindow *window,
GtkWidget *popover); GtkWidget *popover);
GdkPixbuf *gtk_window_get_icon_for_size (GtkWindow *window, cairo_surface_t *gtk_window_get_icon_for_size (GtkWindow *window,
gint size); int size,
int scale);
void gtk_window_set_use_subsurface (GtkWindow *window, void gtk_window_set_use_subsurface (GtkWindow *window,
gboolean use_subsurface); gboolean use_subsurface);