From: Alexander Larsson Date: Mon, 27 Jan 2020 12:59:34 +0000 (+0100) Subject: GtkIconInfo: Implement paintable X-Git-Tag: archive/raspbian/4.4.1+ds1-2+rpi1^2~18^2~20^2~126^2~36 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=b96ab7453b0cad6705ca0720ffbd692b1afa9b51;p=gtk4.git GtkIconInfo: Implement paintable This makes GtkIconInfo directly implement paintable by loading the icon as needed. This is done in a blocking fashion for now, but could be made more async in the future. It also means we can't return errors to the called, but I doubt anyone actually does anything useful with them other than showing nothing (which we already do). This also changes a fringe behaviour for unthemed icons. They used to be never scaled down, but that means we can't tell without i/o the size of the paintable. Since this is the only case we can't know the size i took an executive decision and removed that behaviour. I don't think picking some arbitrary much larger than requested size is ever right, nor do i think using GtkIconTheme with unthemed icons is overly useful. If you want to display some random non-iconish image, use GtkImage instead. --- diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c index 12d6eeaaaf..c8c4cbf40f 100644 --- a/gtk/gtkicontheme.c +++ b/gtk/gtkicontheme.c @@ -48,6 +48,7 @@ #include "gtksettingsprivate.h" #include "gtkstylecontextprivate.h" #include "gtkprivate.h" +#include "gtksnapshot.h" #include "gdkpixbufutilsprivate.h" #include "gdk/gdktextureprivate.h" #include "gdk/gdkprofilerprivate.h" @@ -293,6 +294,7 @@ struct _GtkIconInfo */ gint desired_size; gint desired_scale; + gint rendered_size; gdouble unscaled_scale; guint forced_size : 1; guint is_svg : 1; @@ -386,6 +388,7 @@ static IconSuffix theme_dir_get_icon_suffix (IconThemeDir *dir, static GtkIconInfo *icon_info_new (IconThemeDirType type, gint dir_size, gint dir_scale); +static void icon_info_compute_rendered_size (GtkIconInfo *icon_info); static IconSuffix suffix_from_name (const gchar *name); static gboolean icon_info_ensure_scale_and_texture__locked (GtkIconInfo* icon_info); static void unset_display (GtkIconTheme *self); @@ -1883,6 +1886,8 @@ real_choose_icon (GtkIconTheme *self, } } + icon_info_compute_rendered_size (icon_info); + icon_info->key.icon_names = g_strdupv ((char **)icon_names); icon_info->key.size = size; icon_info->key.scale = scale; @@ -3317,7 +3322,12 @@ theme_subdir_load (GtkIconTheme *self, * GtkIconInfo */ -G_DEFINE_TYPE (GtkIconInfo, gtk_icon_info, G_TYPE_OBJECT) +static void icon_info_paintable_init (GdkPaintableInterface *iface); + + +G_DEFINE_TYPE_WITH_CODE (GtkIconInfo, gtk_icon_info, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE, + icon_info_paintable_init)) static void gtk_icon_info_init (GtkIconInfo *icon_info) @@ -3341,10 +3351,50 @@ icon_info_new (IconThemeDirType type, icon_info->unscaled_scale = 1.0; icon_info->is_svg = FALSE; icon_info->is_resource = FALSE; + icon_info->rendered_size = -1; return icon_info; } +static void +icon_info_compute_rendered_size (GtkIconInfo *icon_info) +{ + int rendered_size; + + if (icon_info->forced_size || + icon_info->dir_type == ICON_THEME_DIR_UNTHEMED) + { + rendered_size = icon_info->desired_size; + } + else if (icon_info->dir_type == ICON_THEME_DIR_FIXED || + icon_info->dir_type == ICON_THEME_DIR_THRESHOLD) + { + rendered_size = icon_info->dir_size * icon_info->dir_scale * icon_info->unscaled_scale / icon_info->desired_scale; + } + else /* Scalable */ + { + gdouble dir_scale = icon_info->dir_scale; + gint scaled_desired_size; + + scaled_desired_size = icon_info->desired_size * icon_info->desired_scale; + + /* See icon_info_ensure_scale_and_texture() comment for why we do this */ + if (icon_info->is_svg) + dir_scale = icon_info->desired_scale; + + if (scaled_desired_size < icon_info->min_size * dir_scale) + rendered_size = icon_info->min_size * dir_scale; + else if (scaled_desired_size > icon_info->max_size * dir_scale) + rendered_size = icon_info->max_size * dir_scale; + else + rendered_size = scaled_desired_size; + + rendered_size /= icon_info->desired_scale; + } + + icon_info->rendered_size = rendered_size; +} + /* This only copies whatever is needed to load the pixbuf, * so that we can do a load in a thread without affecting * the original IconInfo from the thread. @@ -3369,6 +3419,7 @@ icon_info_dup (GtkIconInfo *icon_info) dup->desired_size = icon_info->desired_size; dup->desired_scale = icon_info->desired_scale; dup->forced_size = icon_info->forced_size; + dup->rendered_size = icon_info->rendered_size; dup->is_resource = icon_info->is_resource; dup->min_size = icon_info->min_size; dup->max_size = icon_info->max_size; @@ -3756,10 +3807,6 @@ icon_info_ensure_scale_and_texture__locked (GtkIconInfo *icon_info) icon_info->scale = (gdouble)scaled_desired_size / (gdouble)image_size; else icon_info->scale = 1.0; - - if (icon_info->dir_type == ICON_THEME_DIR_UNTHEMED && - !icon_info->forced_size) - icon_info->scale = MIN (icon_info->scale, 1.0); } if (icon_info->is_svg || @@ -3785,6 +3832,76 @@ icon_info_ensure_scale_and_texture__locked (GtkIconInfo *icon_info) return TRUE; } + +static void +icon_info_paintable_snapshot (GdkPaintable *paintable, + GdkSnapshot *snapshot, + double width, + double height) +{ + GtkIconInfo *icon_info = GTK_ICON_INFO (paintable); + GdkTexture *texture = NULL; + + g_mutex_lock (&icon_info->cache_lock); + + if (!icon_info->texture) + icon_info_ensure_scale_and_texture__locked (icon_info); + + if (icon_info->texture) + texture = g_object_ref (icon_info->texture); + + g_mutex_unlock (&icon_info->cache_lock); + + if (texture) + { + if (icon_info->desired_scale != 1) + { + gtk_snapshot_save (snapshot); + gtk_snapshot_scale (snapshot, 1.0 / icon_info->desired_scale, 1.0 / icon_info->desired_scale); + } + + gtk_snapshot_append_texture (snapshot, texture, + &GRAPHENE_RECT_INIT (0, 0, width * icon_info->desired_scale, height * icon_info->desired_scale)); + + if (icon_info->desired_scale != 1) + gtk_snapshot_restore (snapshot); + + g_object_unref (texture); + } +} + +static GdkPaintableFlags +icon_info_paintable_get_flags (GdkPaintable *paintable) +{ + return GDK_PAINTABLE_STATIC_SIZE | GDK_PAINTABLE_STATIC_CONTENTS; +} + +static int +icon_info_paintable_get_intrinsic_width (GdkPaintable *paintable) +{ + GtkIconInfo *icon_info = GTK_ICON_INFO (paintable); + + return icon_info->rendered_size; +} + +static int +icon_info_paintable_get_intrinsic_height (GdkPaintable *paintable) +{ + GtkIconInfo *icon_info = GTK_ICON_INFO (paintable); + + return icon_info->rendered_size; +} + +static void +icon_info_paintable_init (GdkPaintableInterface *iface) +{ + iface->snapshot = icon_info_paintable_snapshot; + iface->get_flags = icon_info_paintable_get_flags; + iface->get_intrinsic_width = icon_info_paintable_get_intrinsic_width; + iface->get_intrinsic_height = icon_info_paintable_get_intrinsic_height; +} + + /** * gtk_icon_info_load_icon: * @self: a #GtkIconInfo from gtk_icon_theme_lookup_icon() @@ -4684,6 +4801,8 @@ gtk_icon_info_new_for_file (GFile *file, info->desired_scale = scale; info->forced_size = FALSE; + info->rendered_size = size; + return info; } @@ -4692,10 +4811,18 @@ gtk_icon_info_new_for_pixbuf (GtkIconTheme *icon_theme, GdkPixbuf *pixbuf) { GtkIconInfo *info; + gint width, height, max; + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + max = MAX (width, height); info = icon_info_new (ICON_THEME_DIR_UNTHEMED, 0, 1); info->texture = gdk_texture_new_for_pixbuf (pixbuf); + info->desired_size = max; + info->desired_scale = 1.0; info->scale = 1.0; + info->rendered_size = max; return info; }