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)
{
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;

View File

@ -24,6 +24,8 @@
#include "config.h"
#include <cairo-gobject.h>
#include "gtkwindow.h"
#include <string.h>
@ -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 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*
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)

View File

@ -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

View File

@ -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);