diff --git a/lib/Icon.vala b/lib/Icon.vala index 152799afd..cd44528e4 100644 --- a/lib/Icon.vala +++ b/lib/Icon.vala @@ -6,6 +6,34 @@ */ public class Gala.Icon : Clutter.Actor { + private class GIconSource : Object, IconSource { + private static Gtk.IconTheme icon_theme = new Gtk.IconTheme () { + theme_name = "elementary" + }; + + public GLib.Icon gicon { get; construct; } + + public GIconSource (GLib.Icon gicon) { + Object (gicon: gicon); + } + + public string? get_cache_key (int size, float scale) { + var gicon_str = gicon.to_string (); + return gicon_str != null ? "gicon-%s-%d-%f".printf (gicon_str, size, scale) : null; + } + + public Gdk.Pixbuf create_pixbuf (int size, float scale) throws Error { + var icon_paintable = icon_theme.lookup_by_gicon (gicon, size, (int) Math.ceilf (scale), NONE, 0); + + var file = icon_paintable?.file; + if (file == null) { + throw new IOError.FAILED ("Icon paintable has no file"); + } + + return new Gdk.Pixbuf.from_stream_at_scale (file.read (), -1, get_texture_size (size, scale), true); + } + } + private class ResourceIconSource : Object, IconSource { public string path { get; construct; } @@ -41,6 +69,7 @@ public class Gala.Icon : Clutter.Actor { public float monitor_scale { get; construct set; } public string resource_path { set { source = new ResourceIconSource (value); } } + public GLib.Icon gicon { set { source = new GIconSource (value); } } private IconSource _source; private IconSource source { @@ -51,6 +80,10 @@ public class Gala.Icon : Clutter.Actor { } } + public Icon (int icon_size, float monitor_scale) { + Object (icon_size: icon_size, monitor_scale: monitor_scale); + } + public Icon.from_resource (int icon_size, float monitor_scale, string resource_path) { Object (icon_size: icon_size, monitor_scale: monitor_scale, resource_path: resource_path); } diff --git a/lib/Utils.vala b/lib/Utils.vala index f0107951c..b1f7138c4 100644 --- a/lib/Utils.vala +++ b/lib/Utils.vala @@ -19,17 +19,9 @@ namespace Gala { public class Utils { public const int BUTTON_SIZE = 36; - private struct CachedIcon { - public Gdk.Pixbuf icon; - public int icon_size; - public int scale; - } - private static Gee.HashMap? resize_pixbufs = null; - private static Gee.HashMultiMap icon_cache; private static Gee.HashMap window_to_desktop_cache; - private static Gee.ArrayList unknown_icon_cache; private static AppCache app_cache; @@ -40,27 +32,24 @@ namespace Gala { theme_name = "elementary" }; - icon_cache = new Gee.HashMultiMap (); window_to_desktop_cache = new Gee.HashMap (); - unknown_icon_cache = new Gee.ArrayList (); app_cache = new AppCache (); app_cache.changed.connect (() => { - icon_cache.clear (); window_to_desktop_cache.clear (); }); } - public static Gdk.Pixbuf get_icon_for_window (Meta.Window window, int icon_size, int scale) { + public static GLib.Icon get_icon_for_window (Meta.Window window) { var transient_for = window.get_transient_for (); if (transient_for != null) { - return get_icon_for_window (transient_for, icon_size, scale); + return get_icon_for_window (transient_for); } GLib.DesktopAppInfo? desktop_app = null; desktop_app = window_to_desktop_cache[window]; if (desktop_app != null) { - var icon = get_icon_for_desktop_app_info (desktop_app, icon_size, scale); + var icon = desktop_app.get_icon (); if (icon != null) { return icon; } @@ -71,7 +60,7 @@ namespace Gala { var wm_instance = window.get_wm_class_instance (); desktop_app = app_cache.lookup_startup_wmclass (wm_instance); if (desktop_app != null && check_app_prefix (desktop_app, sandbox_id)) { - var icon = get_icon_for_desktop_app_info (desktop_app, icon_size, scale); + var icon = desktop_app.get_icon (); if (icon != null) { window_to_desktop_cache[window] = desktop_app; return icon; @@ -81,7 +70,7 @@ namespace Gala { var wm_class = window.get_wm_class (); desktop_app = app_cache.lookup_startup_wmclass (wm_class); if (desktop_app != null && check_app_prefix (desktop_app, sandbox_id)) { - var icon = get_icon_for_desktop_app_info (desktop_app, icon_size, scale); + var icon = desktop_app.get_icon (); if (icon != null) { window_to_desktop_cache[window] = desktop_app; return icon; @@ -90,7 +79,7 @@ namespace Gala { desktop_app = lookup_desktop_wmclass (wm_instance); if (desktop_app != null && check_app_prefix (desktop_app, sandbox_id)) { - var icon = get_icon_for_desktop_app_info (desktop_app, icon_size, scale); + var icon = desktop_app.get_icon (); if (icon != null) { window_to_desktop_cache[window] = desktop_app; return icon; @@ -99,7 +88,7 @@ namespace Gala { desktop_app = lookup_desktop_wmclass (wm_class); if (desktop_app != null && check_app_prefix (desktop_app, sandbox_id)) { - var icon = get_icon_for_desktop_app_info (desktop_app, icon_size, scale); + var icon = desktop_app.get_icon (); if (icon != null) { window_to_desktop_cache[window] = desktop_app; return icon; @@ -108,7 +97,7 @@ namespace Gala { desktop_app = get_app_from_id (sandbox_id); if (desktop_app != null) { - var icon = get_icon_for_desktop_app_info (desktop_app, icon_size, scale); + var icon = desktop_app.get_icon (); if (icon != null) { window_to_desktop_cache[window] = desktop_app; return icon; @@ -118,7 +107,7 @@ namespace Gala { var gapplication_id = window.get_gtk_application_id (); desktop_app = get_app_from_id (gapplication_id); if (desktop_app != null) { - var icon = get_icon_for_desktop_app_info (desktop_app, icon_size, scale); + var icon = desktop_app.get_icon (); if (icon != null) { window_to_desktop_cache[window] = desktop_app; return icon; @@ -144,7 +133,7 @@ namespace Gala { }); if (desktop_app != null) { - var icon = get_icon_for_desktop_app_info (desktop_app, icon_size, scale); + var icon = desktop_app.get_icon (); if (icon != null) { window_to_desktop_cache[window] = desktop_app; return icon; @@ -153,34 +142,9 @@ namespace Gala { } } - // Haven't been able to get an icon for the window at this point, look to see - // if we've already cached "application-default-icon" at this size - foreach (var icon in unknown_icon_cache) { - if (icon.icon_size == icon_size && icon.scale == scale) { - return icon.icon; - } - } - - // Construct a new "application-default-icon" and store it in the cache - try { - var icon_paintable = icon_theme.lookup_icon ( - "application-default-icon", - null, - icon_size, - scale, - Gtk.TextDirection.NONE, - 0 - ); - - var pixbuf = new Gdk.Pixbuf.from_file (icon_paintable.get_file ().get_path ()); - - unknown_icon_cache.add (CachedIcon () { icon = pixbuf, icon_size = icon_size, scale = scale }); - return pixbuf; - } catch (Error e) { - var icon = new Gdk.Pixbuf (Gdk.Colorspace.RGB, true, 8, icon_size * scale, icon_size * scale); - icon.fill (0x00000000); - return icon; - } + // Haven't been able to get an icon for the window at this point, + // return a default icon + return new ThemedIcon ("application-default-icon"); } private static bool check_app_prefix (GLib.DesktopAppInfo app, string? sandbox_id) { @@ -200,7 +164,6 @@ namespace Gala { public static void clear_window_cache (Meta.Window window) { var desktop = window_to_desktop_cache[window]; if (desktop != null) { - icon_cache.remove_all (desktop); window_to_desktop_cache.unset (window); } } @@ -229,52 +192,6 @@ namespace Gala { return get_app_from_id (canonicalized); } - private static Gdk.Pixbuf? get_icon_for_desktop_app_info (GLib.DesktopAppInfo desktop, int icon_size, int scale) { - if (icon_cache.contains (desktop)) { - foreach (var icon in icon_cache[desktop]) { - if (icon.icon_size == icon_size && icon.scale == scale) { - return icon.icon; - } - } - } - - var icon = desktop.get_icon (); - - if (icon is GLib.ThemedIcon) { - var icon_names = ((GLib.ThemedIcon)icon).get_names (); - if (icon_names.length == 0) { - return null; - } - - var icon_paintable = icon_theme.lookup_icon (icon_names[0], icon_names[1:], icon_size, scale, NONE, 0); - - var path = icon_paintable.get_file ()?.get_path (); - if (path == null) { - return null; - } - - try { - var pixbuf = new Gdk.Pixbuf.from_file (path); - icon_cache.@set (desktop, CachedIcon () { icon = pixbuf, icon_size = icon_size, scale = scale }); - return pixbuf; - } catch (Error e) { - return null; - } - } else if (icon is GLib.FileIcon) { - var file = ((GLib.FileIcon)icon).file; - var size_with_scale = icon_size * scale; - try { - var pixbuf = new Gdk.Pixbuf.from_stream_at_scale (file.read (), size_with_scale, size_with_scale, true); - icon_cache.@set (desktop, CachedIcon () { icon = pixbuf, icon_size = icon_size, scale = scale }); - return pixbuf; - } catch (Error e) { - return null; - } - } - - return null; - } - /** * Multiplies an integer by a floating scaling factor, and then * returns the result rounded to the nearest integer diff --git a/lib/WindowIcon.vala b/lib/WindowIcon.vala index aef6567fd..5a2fd5b27 100644 --- a/lib/WindowIcon.vala +++ b/lib/WindowIcon.vala @@ -15,6 +15,8 @@ public class Gala.WindowIcon : Clutter.Actor { public int icon_size { get; construct; } public int scale { get; construct; } + private Icon icon; + /** * Creates a new WindowIcon * @@ -29,6 +31,9 @@ public class Gala.WindowIcon : Clutter.Actor { } construct { + icon = new Icon (icon_size, scale); + add_child (icon); + /** * Sometimes a WindowIcon is constructed on Meta.Display::window_created. * In this case it can happen that we don't have any info about the app yet so we can't get the @@ -42,11 +47,6 @@ public class Gala.WindowIcon : Clutter.Actor { } private void reload_icon () { - width = icon_size * scale; - height = icon_size * scale; - - var pixbuf = Gala.Utils.get_icon_for_window (window, icon_size, scale); - var image = new Gala.Image.from_pixbuf (pixbuf); - set_content (image); + icon.gicon = Utils.get_icon_for_window (window); } }