[gnome-shell] Fix app icon fading



commit 3aea09b614035ba3d80c5d8dbdda0df8d17177be
Author: Colin Walters <walters verbum org>
Date:   Fri Mar 12 15:57:01 2010 -0500

    Fix app icon fading
    
    The way we were loading data into a CoglTexture, then pulling it out
    and manipulating it on the CPU, then loading it back into a texture
    was a bit lame.
    
    Clean things up a bit here by loading directly into the CPU, doing
    the fading, then creating a texture.
    
    Also cache the faded data in StTextureCache.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=612759

 js/ui/panel.js         |   20 +------
 src/shell-app-system.c |   26 ++++++++-
 src/shell-app-system.h |    4 +
 src/shell-app.c        |  144 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/shell-app.h        |    1 +
 src/shell-drawing.c    |   64 ---------------------
 src/shell-drawing.h    |    2 -
 7 files changed, 177 insertions(+), 84 deletions(-)
---
diff --git a/js/ui/panel.js b/js/ui/panel.js
index 6cce4c6..7046bec 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -158,7 +158,7 @@ AppPanelMenu.prototype = {
         this._container.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
         this._container.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
         this._container.connect('allocate', Lang.bind(this, this._allocate));
-        this._sourceIcon = null;
+
         this._iconBox = new Shell.Slicer({ name: 'appMenuIcon' });
         this._container.add_actor(this._iconBox);
         this._label = new TextShadower();
@@ -271,7 +271,7 @@ AppPanelMenu.prototype = {
         this._label.setText('');
         let icon;
         if (this._focusedApp != null) {
-            icon = this._focusedApp.create_icon_texture(AppDisplay.APPICON_SIZE);
+            icon = this._focusedApp.get_faded_icon(AppDisplay.APPICON_SIZE);
             this._label.setText(this._focusedApp.get_name());
         } else if (this._activeSequence != null) {
             icon = this._activeSequence.create_icon(AppDisplay.APPICON_SIZE);
@@ -281,21 +281,7 @@ AppPanelMenu.prototype = {
         }
 
         if (icon != null) {
-            if (this._sourceIcon != null)
-                this._sourceIcon.destroy();
-            this._sourceIcon = icon;
-            let faded = Shell.fade_app_icon(icon);
-            // Because loading the texture is async, we may not have it yet.
-            // If we don't, just create an empty one for now.
-            if (faded == null)
-                faded = new Clutter.Texture({ width: this._sourceIcon.width,
-                                              height: this._sourceIcon.height });
-            this._sourceIcon.connect('notify::cogl-texture', Lang.bind(this, function () {
-                // TODO should be caching this
-                faded = Shell.fade_app_icon(icon);
-                this._iconBox.set_child(faded);
-            }));
-            this._iconBox.set_child(faded);
+            this._iconBox.set_child(icon);
             this._iconBox.show();
         }
 
diff --git a/src/shell-app-system.c b/src/shell-app-system.c
index be07df7..2d0d3db 100644
--- a/src/shell-app-system.c
+++ b/src/shell-app-system.c
@@ -1021,7 +1021,16 @@ themed_icon_from_name (const char *iconname)
   return icon;
 }
 
-static GIcon *
+/**
+ * shell_app_info_get_icon:
+ * @info: A #ShellAppInfo
+ *
+ * Get the #GIcon associated with this app; for apps "faked" from a #MetaWindow,
+ * return %NULL.
+ *
+ * Returns: (transfer full): The icon for @info, or %NULL
+ */
+GIcon *
 shell_app_info_get_icon (ShellAppInfo *info)
 {
   char *iconname = NULL;
@@ -1121,6 +1130,21 @@ shell_app_info_create_icon_texture (ShellAppInfo *info, float size)
 }
 
 /**
+ * shell_app_info_get_source_window:
+ * @info: A #ShellAppInfo
+ *
+ * If @info is tracking a #MetaWindow, return that window.
+ * Otherwise, return %NULL.
+ */
+MetaWindow *
+shell_app_info_get_source_window (ShellAppInfo *info)
+{
+  if (info->type == SHELL_APP_INFO_TYPE_WINDOW)
+    return info->window;
+  return NULL;
+}
+
+/**
  * shell_app_info_launch_full:
  * @timestamp: Event timestamp, or 0 for current event timestamp
  * @uris: List of uris to pass to application
diff --git a/src/shell-app-system.h b/src/shell-app-system.h
index a02cfb7..be7efeb 100644
--- a/src/shell-app-system.h
+++ b/src/shell-app-system.h
@@ -50,10 +50,14 @@ char *shell_app_info_get_name (ShellAppInfo *info);
 char *shell_app_info_get_description (ShellAppInfo *info);
 char *shell_app_info_get_executable (ShellAppInfo *info);
 char *shell_app_info_get_desktop_file_path (ShellAppInfo *info);
+GIcon *shell_app_info_get_icon (ShellAppInfo *info);
 ClutterActor *shell_app_info_create_icon_texture (ShellAppInfo *info, float size);
 GSList *shell_app_info_get_categories (ShellAppInfo *info);
 gboolean shell_app_info_get_is_nodisplay (ShellAppInfo *info);
 gboolean shell_app_info_is_transient (ShellAppInfo *info);
+
+MetaWindow *shell_app_info_get_source_window (ShellAppInfo *info);
+
 gboolean shell_app_info_launch_full (ShellAppInfo *info,
                             guint         timestamp,
                             GList        *uris,
diff --git a/src/shell-app.c b/src/shell-app.c
index 7630cd0..08e80c2 100644
--- a/src/shell-app.c
+++ b/src/shell-app.c
@@ -4,6 +4,9 @@
 
 #include "shell-app-private.h"
 #include "shell-global.h"
+#include "st.h"
+
+#include <string.h>
 
 /**
  * SECTION:shell-app
@@ -22,6 +25,7 @@ struct _ShellApp
 
   gboolean window_sort_stale;
   GSList *windows;
+
 };
 
 G_DEFINE_TYPE (ShellApp, shell_app, G_TYPE_OBJECT);
@@ -53,6 +57,146 @@ shell_app_create_icon_texture (ShellApp   *app,
 {
   return shell_app_info_create_icon_texture (app->info, size);
 }
+typedef struct {
+  ShellApp *app;
+  int size;
+} CreateFadedIconData;
+
+static CoglHandle
+shell_app_create_faded_icon_cpu (StTextureCache *cache,
+                                 const char     *key,
+                                 void           *datap,
+                                 GError        **error)
+{
+  CreateFadedIconData *data = datap;
+  ShellApp *app;
+  GdkPixbuf *pixbuf;
+  int size;
+  CoglHandle texture;
+  gint width, height, rowstride;
+  guint8 n_channels;
+  gint fade_start;
+  gint fade_range;
+  guint i, j;
+  guint pixbuf_byte_size;
+  guint8 *orig_pixels;
+  guint8 *pixels;
+  GIcon *icon;
+  GtkIconInfo *info;
+
+  app = data->app;
+  size = data->size;
+
+  icon = shell_app_info_get_icon (app->info);
+  if (icon == NULL)
+    return COGL_INVALID_HANDLE;
+
+  info = gtk_icon_theme_lookup_by_gicon (gtk_icon_theme_get_default (),
+                                         icon, (int) (size + 0.5),
+                                         GTK_ICON_LOOKUP_FORCE_SIZE);
+  g_object_unref (icon);
+  if (info == NULL)
+    return COGL_INVALID_HANDLE;
+
+  pixbuf = gtk_icon_info_load_icon (info, NULL);
+  gtk_icon_info_free (info);
+
+  if (pixbuf == NULL)
+    return COGL_INVALID_HANDLE;
+
+  width = gdk_pixbuf_get_width (pixbuf);
+  height = gdk_pixbuf_get_height (pixbuf);
+  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+  n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+  orig_pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+  pixbuf_byte_size = (height - 1) * rowstride +
+    + width * ((n_channels * gdk_pixbuf_get_bits_per_sample (pixbuf) + 7) / 8);
+
+  pixels = g_malloc0 (rowstride * height);
+  memcpy (pixels, orig_pixels, pixbuf_byte_size);
+
+  fade_start = width / 2;
+  fade_range = width - fade_start;
+  for (i = fade_start; i < width; i++)
+    {
+      for (j = 0; j < height; j++)
+        {
+          guchar *pixel = &pixels[j * rowstride + i * n_channels];
+          float fade = 1.0 - ((float) i - fade_start) / fade_range;
+          pixel[0] = 0.5 + pixel[0] * fade;
+          pixel[1] = 0.5 + pixel[1] * fade;
+          pixel[2] = 0.5 + pixel[2] * fade;
+          pixel[3] = 0.5 + pixel[3] * fade;
+        }
+    }
+
+  texture = cogl_texture_new_from_data (width,
+                                        height,
+                                        COGL_TEXTURE_NONE,
+                                        gdk_pixbuf_get_has_alpha (pixbuf) ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888,
+                                        COGL_PIXEL_FORMAT_ANY,
+                                        rowstride,
+                                        pixels);
+  g_free (pixels);
+  g_object_unref (pixbuf);
+
+  return texture;
+}
+
+/**
+ * shell_app_get_faded_icon:
+ * @app: A #ShellApp
+ * @size: Size in pixels
+ *
+ * Return an actor with a horizontally faded look.
+ *
+ * Return value: (transfer none): A floating #ClutterActor, or %NULL if no icon
+ */
+ClutterActor *
+shell_app_get_faded_icon (ShellApp *app, float size)
+{
+  MetaWindow *window;
+  CoglHandle texture;
+  ClutterActor *result;
+  char *cache_key;
+  CreateFadedIconData data;
+
+  /* Punt for WINDOW types for now...easier to reuse the property tracking bits,
+   * and this helps us visually distinguish app-tracked from not.
+   */
+  window = shell_app_info_get_source_window (app->info);
+  if (window)
+    {
+      return st_texture_cache_bind_pixbuf_property (st_texture_cache_get_default (),
+                                                    G_OBJECT (window),
+                                                    "icon");
+    }
+
+  cache_key = g_strdup_printf ("faded-icon:%s,size=%f", shell_app_get_id (app), size);
+  data.app = app;
+  data.size = (int) (0.5 + size);
+  texture = st_texture_cache_load (st_texture_cache_get_default (),
+                                   cache_key,
+                                   ST_TEXTURE_CACHE_POLICY_FOREVER,
+                                   shell_app_create_faded_icon_cpu,
+                                   &data,
+                                   NULL);
+  g_free (cache_key);
+
+  if (texture != COGL_INVALID_HANDLE)
+    {
+      result = clutter_texture_new ();
+      clutter_texture_set_cogl_texture (CLUTTER_TEXTURE (result), texture);
+    }
+  else
+    {
+      result = clutter_texture_new ();
+      g_object_set (result, "opacity", 0, "width", size, "height", size, NULL);
+
+    }
+  return result;
+}
 
 char *
 shell_app_get_name (ShellApp *app)
diff --git a/src/shell-app.h b/src/shell-app.h
index f6e2f71..0e25161 100644
--- a/src/shell-app.h
+++ b/src/shell-app.h
@@ -30,6 +30,7 @@ GType shell_app_get_type (void) G_GNUC_CONST;
 const char *shell_app_get_id (ShellApp *app);
 
 ClutterActor *shell_app_create_icon_texture (ShellApp *app, float size);
+ClutterActor *shell_app_get_faded_icon (ShellApp *app, float size);
 char *shell_app_get_name (ShellApp *app);
 char *shell_app_get_description (ShellApp *app);
 gboolean shell_app_is_transient (ShellApp *app);
diff --git a/src/shell-drawing.c b/src/shell-drawing.c
index 01055c9..616c800 100644
--- a/src/shell-drawing.c
+++ b/src/shell-drawing.c
@@ -49,70 +49,6 @@ shell_draw_clock (StDrawingArea       *area,
   cairo_stroke (cr);
 }
 
-/**
- * shell_fade_app_icon:
- * @source: Source #ClutterTexture
- *
- * Create a new texture by modifying the alpha channel of the
- * source texture, adding a horizontal gradient fade.
- *
- * Returns: (transfer none): A new #ClutterTexture
- */
-ClutterTexture *
-shell_fade_app_icon (ClutterTexture *source)
-{
-  CoglHandle  texture;
-  guchar     *pixels;
-  gint        width, height, rowstride;
-  gint        fade_start;
-  gint        fade_range;
-  guint       i, j;
-  ClutterTexture *result;
-
-  texture = clutter_texture_get_cogl_texture (source);
-  if (texture == COGL_INVALID_HANDLE)
-    return NULL;
-
-  width  = cogl_texture_get_width  (texture);
-  height = cogl_texture_get_height (texture);
-  rowstride = (width * 4 + 3) & ~3;
-
-  pixels = g_malloc0 (rowstride * height);
-
-  cogl_texture_get_data (texture, COGL_PIXEL_FORMAT_RGBA_8888_PRE,
-                         rowstride, pixels);
-  
-  fade_start = width / 2;
-  fade_range = width - fade_start;
-  for (i = fade_start; i < width; i++)
-    {
-      for (j = 0; j < height; j++)
-        {
-          guchar *pixel = &pixels[j * rowstride + i * 4];
-          float fade = 1.0 - ((float) i - fade_start) / fade_range;
-          pixel[0] = 0.5 + pixel[0] * fade;
-          pixel[1] = 0.5 + pixel[1] * fade;
-          pixel[2] = 0.5 + pixel[2] * fade;
-          pixel[3] = 0.5 + pixel[3] * fade;
-        }   
-    }
-
-  texture = cogl_texture_new_from_data (width,
-                                        height,
-                                        COGL_TEXTURE_NONE,
-                                        COGL_PIXEL_FORMAT_RGBA_8888_PRE,
-                                        COGL_PIXEL_FORMAT_ANY,
-                                        rowstride,
-                                        pixels);
-  g_free (pixels);
-    
-  result = (ClutterTexture*)clutter_texture_new ();
-  clutter_texture_set_cogl_texture (result, texture);
-  cogl_handle_unref (texture);
-  
-  return result;
-}
-
 void
 shell_draw_box_pointer (StDrawingArea         *area,
                         ShellPointerDirection  direction,
diff --git a/src/shell-drawing.h b/src/shell-drawing.h
index ac6edf9..feaa580 100644
--- a/src/shell-drawing.h
+++ b/src/shell-drawing.h
@@ -24,8 +24,6 @@ void shell_draw_clock (StDrawingArea       *area,
 	               int                  hour,
 	               int                  minute);
 
-ClutterTexture * shell_fade_app_icon (ClutterTexture *source);
-
 guint shell_add_hook_paint_red_border (ClutterActor *actor);
 
 G_END_DECLS



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]