diff --git a/js/ui/panel.js b/js/ui/panel.js index 6cce4c62e..7046bec84 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 be07df7d3..2d0d3db41 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; @@ -1120,6 +1129,21 @@ shell_app_info_create_icon_texture (ShellAppInfo *info, float size) return ret; } +/** + * 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 diff --git a/src/shell-app-system.h b/src/shell-app-system.h index a02cfb7c5..be7efebce 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 7630cd0c3..08e80c25e 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 /** * 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 f6e2f713e..0e2516162 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 01055c99b..616c80078 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 ac6edf90a..feaa580bf 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