diff --git a/js/ui/notificationDaemon.js b/js/ui/notificationDaemon.js index 51044f1ac..fef31f3c3 100644 --- a/js/ui/notificationDaemon.js +++ b/js/ui/notificationDaemon.js @@ -1,6 +1,7 @@ /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ const DBus = imports.dbus; +const GLib = imports.gi.GLib; const Lang = imports.lang; const Shell = imports.gi.Shell; const Mainloop = imports.mainloop; @@ -81,16 +82,7 @@ NotificationDaemon.prototype = { if (source == null) { id = nextNotificationId++; - source = new MessageTray.Source(this._sourceId(id), Lang.bind(this, - function (size) { - if (icon != '') - return Shell.TextureCache.get_default().load_icon_name(icon, size); - else { - // FIXME: load icon data from hints - // FIXME: better fallback icon - return Shell.TextureCache.get_default().load_icon_name('gtk-dialog-info', size); - } - })); + source = new Source(this._sourceId(id), icon, hints); Main.messageTray.add(source); source.connect('clicked', Lang.bind(this, @@ -143,3 +135,39 @@ NotificationDaemon.prototype = { DBus.conformExport(NotificationDaemon.prototype, NotificationDaemonIface); +function Source(sourceId, icon, hints) { + this._init(sourceId, icon, hints); +} + +Source.prototype = { + __proto__: MessageTray.Source.prototype, + + _init: function(sourceId, icon, hints) { + MessageTray.Source.prototype._init.call(this, sourceId); + + this._icon = icon; + this._iconData = hints.icon_data; + }, + + createIcon: function(size) { + let textureCache = Shell.TextureCache.get_default(); + + if (this._icon) { + if (this._icon.substr(0, 7) == 'file://') + return textureCache.load_uri_async(this._icon, size, size); + else if (this._icon[0] == '/') { + let uri = GLib.filename_to_uri(this._icon, null); + return textureCache.load_uri_async(uri, size, size); + } else + return textureCache.load_icon_name(this._icon, size); + } else if (this._iconData) { + let [width, height, rowStride, hasAlpha, + bitsPerSample, nChannels, data] = this._iconData; + return textureCache.load_from_raw(data, data.length, hasAlpha, + width, height, rowStride, size); + } else { + // FIXME: fallback icon? + return textureCache.load_icon_name('gtk-dialog-info', size); + } + } +}; diff --git a/src/shell-texture-cache.c b/src/shell-texture-cache.c index d85ca84ef..9b022baed 100644 --- a/src/shell-texture-cache.c +++ b/src/shell-texture-cache.c @@ -1154,7 +1154,7 @@ shell_texture_cache_load_uri_sync (ShellTextureCache *cache, /** * shell_texture_cache_load_from_data: * @cache: The texture cache instance - * @data: Raw image data + * @data: Image data in PNG, GIF, etc format * @len: length of @data * @size: Size in pixels to use for the resulting texture * @error: Return location for error @@ -1192,7 +1192,6 @@ shell_texture_cache_load_from_data (ShellTextureCache *cache, texdata = g_hash_table_lookup (cache->priv->keyed_cache, &key); if (texdata == NULL) { - g_debug ("creating new pixbuf"); pixbuf = impl_load_pixbuf_data (data, len, size, size, error); if (!pixbuf) { @@ -1207,12 +1206,70 @@ shell_texture_cache_load_from_data (ShellTextureCache *cache, g_hash_table_insert (cache->priv->keyed_cache, cache_key_dup (&key), texdata); } - else + + g_free (key.checksum); + + set_texture_cogl_texture (texture, texdata); + return CLUTTER_ACTOR (texture); +} + +/** + * shell_texture_cache_load_from_raw: + * @cache: a #ShellTextureCache + * @data: raw pixel data + * @len: the length of @data + * @has_alpha: whether @data includes an alpha channel + * @width: width in pixels of @data + * @height: width in pixels of @data + * @rowstride: rowstride of @data + * @size: size of icon to return + * + * Creates (or retrieves from cache) an icon based on raw pixel data. + * + * Return value: (transfer none): a new #ClutterActor displaying a + * pixbuf created from @data and the other parameters. + **/ +ClutterActor * +shell_texture_cache_load_from_raw (ShellTextureCache *cache, + const guchar *data, + gsize len, + gboolean has_alpha, + int width, + int height, + int rowstride, + int size, + GError **error) +{ + ClutterTexture *texture; + CoglHandle texdata; + CacheKey key; + gchar *checksum; + + texture = create_default_texture (cache); + clutter_actor_set_size (CLUTTER_ACTOR (texture), size, size); + + /* In theory, two images of different size could have the same + * pixel data. We ignore that theory. + */ + checksum = g_compute_checksum_for_data (G_CHECKSUM_SHA1, data, len); + + memset (&key, 0, sizeof(key)); + key.size = size; + key.checksum = checksum; + + texdata = g_hash_table_lookup (cache->priv->keyed_cache, &key); + if (texdata == NULL) { - g_debug ("using texture from cache"); - set_texture_cogl_texture (texture, texdata); + texdata = cogl_texture_new_from_data (width, height, COGL_TEXTURE_NONE, + has_alpha ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888, + COGL_PIXEL_FORMAT_ANY, + rowstride, data); + g_hash_table_insert (cache->priv->keyed_cache, cache_key_dup (&key), texdata); } + g_free (key.checksum); + + set_texture_cogl_texture (texture, texdata); return CLUTTER_ACTOR (texture); } diff --git a/src/shell-texture-cache.h b/src/shell-texture-cache.h index 14d132e72..d7280c465 100644 --- a/src/shell-texture-cache.h +++ b/src/shell-texture-cache.h @@ -85,6 +85,15 @@ ClutterActor *shell_texture_cache_load_from_data (ShellTextureCache *cache, gsize len, int size, GError **error); +ClutterActor *shell_texture_cache_load_from_raw (ShellTextureCache *cache, + const guchar *data, + gsize len, + gboolean has_alpha, + int width, + int height, + int rowstride, + int size, + GError **error); gboolean shell_texture_cache_pixbuf_equal (ShellTextureCache *cache, GdkPixbuf *a, GdkPixbuf *b);