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
This commit is contained in:
parent
374fd35476
commit
3aea09b614
@ -158,7 +158,7 @@ AppPanelMenu.prototype = {
|
|||||||
this._container.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
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('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||||
this._container.connect('allocate', Lang.bind(this, this._allocate));
|
this._container.connect('allocate', Lang.bind(this, this._allocate));
|
||||||
this._sourceIcon = null;
|
|
||||||
this._iconBox = new Shell.Slicer({ name: 'appMenuIcon' });
|
this._iconBox = new Shell.Slicer({ name: 'appMenuIcon' });
|
||||||
this._container.add_actor(this._iconBox);
|
this._container.add_actor(this._iconBox);
|
||||||
this._label = new TextShadower();
|
this._label = new TextShadower();
|
||||||
@ -271,7 +271,7 @@ AppPanelMenu.prototype = {
|
|||||||
this._label.setText('');
|
this._label.setText('');
|
||||||
let icon;
|
let icon;
|
||||||
if (this._focusedApp != null) {
|
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());
|
this._label.setText(this._focusedApp.get_name());
|
||||||
} else if (this._activeSequence != null) {
|
} else if (this._activeSequence != null) {
|
||||||
icon = this._activeSequence.create_icon(AppDisplay.APPICON_SIZE);
|
icon = this._activeSequence.create_icon(AppDisplay.APPICON_SIZE);
|
||||||
@ -281,21 +281,7 @@ AppPanelMenu.prototype = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (icon != null) {
|
if (icon != null) {
|
||||||
if (this._sourceIcon != null)
|
this._iconBox.set_child(icon);
|
||||||
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.show();
|
this._iconBox.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1021,7 +1021,16 @@ themed_icon_from_name (const char *iconname)
|
|||||||
return icon;
|
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)
|
shell_app_info_get_icon (ShellAppInfo *info)
|
||||||
{
|
{
|
||||||
char *iconname = NULL;
|
char *iconname = NULL;
|
||||||
@ -1120,6 +1129,21 @@ shell_app_info_create_icon_texture (ShellAppInfo *info, float size)
|
|||||||
return ret;
|
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:
|
* shell_app_info_launch_full:
|
||||||
* @timestamp: Event timestamp, or 0 for current event timestamp
|
* @timestamp: Event timestamp, or 0 for current event timestamp
|
||||||
|
@ -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_description (ShellAppInfo *info);
|
||||||
char *shell_app_info_get_executable (ShellAppInfo *info);
|
char *shell_app_info_get_executable (ShellAppInfo *info);
|
||||||
char *shell_app_info_get_desktop_file_path (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);
|
ClutterActor *shell_app_info_create_icon_texture (ShellAppInfo *info, float size);
|
||||||
GSList *shell_app_info_get_categories (ShellAppInfo *info);
|
GSList *shell_app_info_get_categories (ShellAppInfo *info);
|
||||||
gboolean shell_app_info_get_is_nodisplay (ShellAppInfo *info);
|
gboolean shell_app_info_get_is_nodisplay (ShellAppInfo *info);
|
||||||
gboolean shell_app_info_is_transient (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,
|
gboolean shell_app_info_launch_full (ShellAppInfo *info,
|
||||||
guint timestamp,
|
guint timestamp,
|
||||||
GList *uris,
|
GList *uris,
|
||||||
|
144
src/shell-app.c
144
src/shell-app.c
@ -4,6 +4,9 @@
|
|||||||
|
|
||||||
#include "shell-app-private.h"
|
#include "shell-app-private.h"
|
||||||
#include "shell-global.h"
|
#include "shell-global.h"
|
||||||
|
#include "st.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION:shell-app
|
* SECTION:shell-app
|
||||||
@ -22,6 +25,7 @@ struct _ShellApp
|
|||||||
|
|
||||||
gboolean window_sort_stale;
|
gboolean window_sort_stale;
|
||||||
GSList *windows;
|
GSList *windows;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE (ShellApp, shell_app, G_TYPE_OBJECT);
|
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);
|
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 *
|
char *
|
||||||
shell_app_get_name (ShellApp *app)
|
shell_app_get_name (ShellApp *app)
|
||||||
|
@ -30,6 +30,7 @@ GType shell_app_get_type (void) G_GNUC_CONST;
|
|||||||
const char *shell_app_get_id (ShellApp *app);
|
const char *shell_app_get_id (ShellApp *app);
|
||||||
|
|
||||||
ClutterActor *shell_app_create_icon_texture (ShellApp *app, float size);
|
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_name (ShellApp *app);
|
||||||
char *shell_app_get_description (ShellApp *app);
|
char *shell_app_get_description (ShellApp *app);
|
||||||
gboolean shell_app_is_transient (ShellApp *app);
|
gboolean shell_app_is_transient (ShellApp *app);
|
||||||
|
@ -49,70 +49,6 @@ shell_draw_clock (StDrawingArea *area,
|
|||||||
cairo_stroke (cr);
|
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
|
void
|
||||||
shell_draw_box_pointer (StDrawingArea *area,
|
shell_draw_box_pointer (StDrawingArea *area,
|
||||||
ShellPointerDirection direction,
|
ShellPointerDirection direction,
|
||||||
|
@ -24,8 +24,6 @@ void shell_draw_clock (StDrawingArea *area,
|
|||||||
int hour,
|
int hour,
|
||||||
int minute);
|
int minute);
|
||||||
|
|
||||||
ClutterTexture * shell_fade_app_icon (ClutterTexture *source);
|
|
||||||
|
|
||||||
guint shell_add_hook_paint_red_border (ClutterActor *actor);
|
guint shell_add_hook_paint_red_border (ClutterActor *actor);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
Loading…
Reference in New Issue
Block a user