Conor Curran has proposed merging lp:~cjcurran/indicator-sound/remote-art-handling into lp:indicator-sound.
Requested reviews: Indicator Applet Developers (indicator-applet-developers) Related bugs: #627505 Crashes if Rhythmbox is playing from Last.FM https://bugs.launchpad.net/bugs/627505 - Deals with last fm plugin for rhythmbox which uses remote artwork. Dynamically remote artwork will now be fetched asynchronously, rounded and exposed. -- https://code.launchpad.net/~cjcurran/indicator-sound/remote-art-handling/+merge/34396 Your team ayatana-commits is subscribed to branch lp:indicator-sound.
=== modified file 'src/Makefile.am' --- src/Makefile.am 2010-08-27 11:25:47 +0000 +++ src/Makefile.am 2010-09-02 10:31:05 +0000 @@ -67,7 +67,9 @@ player-controller.vala \ mpris2-controller.vala \ player-item.vala \ - familiar-players-db.vala + familiar-players-db.vala \ + fetch-file.vala + music_bridge_VALAFLAGS = \ --ccode \ @@ -81,7 +83,9 @@ --pkg Dbusmenu-Glib-0.2 \ --pkg common-defs \ --pkg dbus-glib-1 \ - --pkg gio-unix-2.0 + --pkg gio-unix-2.0 \ + --pkg gdk-pixbuf-2.0 + $(MAINTAINER_VALAFLAGS) === modified file 'src/common-defs.h' --- src/common-defs.h 2010-08-24 15:22:35 +0000 +++ src/common-defs.h 2010-09-02 10:31:05 +0000 @@ -25,6 +25,7 @@ #define SIGNAL_SINK_AVAILABLE_UPDATE "SinkAvailableUpdate" #define DBUSMENU_PROPERTY_EMPTY -1 +#define DBUSMENU_PLAYER_ITEM_REMOTE_FILEPATH "/tmp/indicator-sound-downloaded-album-art" /* DBUS Custom Items */ #define DBUSMENU_VOLUME_MENUITEM_TYPE "x-canonical-ido-volume-type" === added file 'src/fetch-file.vala' --- src/fetch-file.vala 1970-01-01 00:00:00 +0000 +++ src/fetch-file.vala 2010-09-02 10:31:05 +0000 @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2010 Canonical, Ltd. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License + * version 3.0 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3.0 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors + * Gordon Allott <[email protected]> + * Conor Curran <[email protected]> + */ + +public class FetchFile : Object +{ + /* public variables */ + public string uri {get; construct;} + public string intended_property {get; construct;} + + /* private variables */ + private DataInputStream stream; + private File? file; + private ByteArray data; + + /* public signals */ + public signal void failed (); + public signal void completed (ByteArray data, string property); + + public FetchFile (string uri, string prop) + { + Object (uri: uri, intended_property: prop); + } + + construct + { + this.file = File.new_for_uri(this.uri); + this.data = new ByteArray (); + } + + public async void fetch_data () + { + try { + this.stream = new DataInputStream(this.file.read(null)); + this.stream.set_byte_order (DataStreamByteOrder.LITTLE_ENDIAN); + } catch (GLib.Error e) { + this.failed (); + } + this.read_something_async (); + } + + private async void read_something_async () + { + ssize_t size = 1024; + uint8[] buffer = new uint8[size]; + + ssize_t bufsize = 1; + do { + try { + bufsize = yield this.stream.read_async (buffer, size, GLib.Priority.DEFAULT, null); + if (bufsize < 1) { break;} + + if (bufsize != size) + { + uint8[] cpybuf = new uint8[bufsize]; + Memory.copy (cpybuf, buffer, bufsize); + this.data.append (cpybuf); + } + else + { + this.data.append (buffer); + } + } catch (Error e) { + this.failed (); + } + } while (bufsize > 0); + this.completed (this.data, this.intended_property); + } +} === modified file 'src/metadata-menu-item.vala' --- src/metadata-menu-item.vala 2010-08-24 16:59:15 +0000 +++ src/metadata-menu-item.vala 2010-09-02 10:31:05 +0000 @@ -17,7 +17,6 @@ with this program. If not, see <http://www.gnu.org/licenses/>. */ -using Dbusmenu; using Gee; using DbusmenuMetadata; === modified file 'src/metadata-widget.c' --- src/metadata-widget.c 2010-08-25 19:29:39 +0000 +++ src/metadata-widget.c 2010-09-02 10:31:05 +0000 @@ -36,6 +36,7 @@ GtkWidget* album_art; GString* image_path; GString* old_image_path; + GString* remote_image_path; GtkWidget* artist_label; GtkWidget* piece_label; GtkWidget* container_label; @@ -69,7 +70,7 @@ MetadataWidget* metadata, GdkPixbuf *source); - +static void draw_album_art_placeholder(GtkWidget *metadata); G_DEFINE_TYPE (MetadataWidget, metadata_widget, GTK_TYPE_MENU_ITEM); @@ -104,6 +105,7 @@ priv->album_art = gtk_image_new(); priv->image_path = g_string_new(dbusmenu_menuitem_property_get(twin_item, DBUSMENU_METADATA_MENUITEM_ARTURL)); priv->old_image_path = g_string_new(""); + priv->remote_image_path = g_string_new(DBUSMENU_PLAYER_ITEM_REMOTE_FILEPATH); g_debug("Metadata::At startup and image path = %s", priv->image_path->str); g_signal_connect(priv->album_art, "expose-event", @@ -178,7 +180,7 @@ /** * We override the expose method to enable primitive drawing of the - * empty album art image (and soon rounded rectangles on the album art) + * empty album art image and rounded rectangles on the album art. */ static gboolean metadata_image_expose (GtkWidget *metadata, GdkEventExpose *event, gpointer user_data) @@ -186,24 +188,37 @@ g_return_val_if_fail(IS_METADATA_WIDGET(user_data), FALSE); MetadataWidget* widget = METADATA_WIDGET(user_data); MetadataWidgetPrivate * priv = METADATA_WIDGET_GET_PRIVATE(widget); - + g_debug("expose"); if(priv->image_path->len > 0){ - - if(g_string_equal(priv->image_path, priv->old_image_path) == FALSE){ + if(g_string_equal(priv->image_path, priv->old_image_path) == FALSE || + (g_string_equal(priv->image_path, priv->remote_image_path) == TRUE && + g_string_equal(priv->old_image_path, priv->remote_image_path) == FALSE)){ + g_debug("and we are in"); GdkPixbuf* pixbuf; pixbuf = gdk_pixbuf_new_from_file(priv->image_path->str, NULL); - g_debug("metadata_widget_expose, album art update -> pixbuf from %s", - priv->image_path->str); + g_debug("metadata_load_new_image -> pixbuf from %s", + priv->image_path->str); + if(GDK_IS_PIXBUF(pixbuf) == FALSE){ + g_debug("problem loading the downloaded image just use the placeholder instead"); + draw_album_art_placeholder(metadata); + return TRUE; + } pixbuf = gdk_pixbuf_scale_simple(pixbuf,60, 60, GDK_INTERP_BILINEAR); image_set_from_pixbuf (metadata, widget, pixbuf); g_string_erase(priv->old_image_path, 0, -1); g_string_overwrite(priv->old_image_path, 0, priv->image_path->str); - g_object_unref(pixbuf); + g_object_unref(pixbuf); } return FALSE; } - + draw_album_art_placeholder(metadata); + return TRUE; +} + +static void draw_album_art_placeholder(GtkWidget *metadata) +{ + cairo_t *cr; cr = gdk_cairo_create (metadata->window); GtkAllocation alloc; @@ -255,8 +270,7 @@ g_object_unref(pcontext); g_string_free (string, TRUE); cairo_destroy (cr); - - return TRUE; + } /* Suppress/consume keyevents */ @@ -315,6 +329,12 @@ else if(g_ascii_strcasecmp(DBUSMENU_METADATA_MENUITEM_ARTURL, property) == 0){ g_string_erase(priv->image_path, 0, -1); g_string_overwrite(priv->image_path, 0, g_value_get_string (value)); + // Basically force expose the reload the image because we have an image update + // but we are using remote images i.e. the same file path but different images + if(g_string_equal(priv->image_path, priv->remote_image_path) == TRUE){ + g_string_erase(priv->old_image_path, 0, -1); + gtk_widget_queue_draw(GTK_WIDGET(mitem)); + } } } === modified file 'src/player-item.vala' --- src/player-item.vala 2010-08-24 16:59:15 +0000 +++ src/player-item.vala 2010-09-02 10:31:05 +0000 @@ -19,13 +19,16 @@ using Dbusmenu; using Gee; +using Gdk; +using DbusmenuPlayer; public class PlayerItem : Dbusmenu.Menuitem { public PlayerController owner {get; construct;} public string item_type { get; construct; } private const int EMPTY = -1; - + private FetchFile fetcher; + public PlayerItem(string type) { Object(item_type: type); @@ -61,14 +64,23 @@ debug("with value : %s", update); // Special case for the arturl URI's. if(property.contains("mpris:artUrl")){ - try{ - update = Filename.from_uri(update.strip()); + if(update.has_prefix("http://")){ + // This is asyncronous so handle it offline + this.fetch_remote_art(update.strip(), property); + continue; } - catch(ConvertError e){ - warning("Problem converting URI %s to file path", update); + else{ + // The file is local, just parse the string + try{ + update = Filename.from_uri(update.strip()); + } + catch(ConvertError e){ + warning("Problem converting URI %s to file path", + update); + } } } - this.property_set(property, update); + this.property_set(property, update); } else if (v.holds (typeof (int))){ debug("with value : %i", v.get_int()); @@ -101,5 +113,34 @@ } return false; } + + public void fetch_remote_art(string uri, string prop) + { + this.fetcher = new FetchFile (uri, prop); + this.fetcher.failed.connect (() => { this.on_fetcher_failed ();}); + this.fetcher.completed.connect (this.on_fetcher_completed); + this.fetcher.fetch_data (); + } + + private void on_fetcher_failed () + { + warning("on_fetcher_failed -> could not fetch artwork"); + } + + private void on_fetcher_completed(ByteArray update, string property) + { + try{ + PixbufLoader loader = new PixbufLoader (); + loader.write (update.data, update.len); + loader.close (); + Pixbuf icon = loader.get_pixbuf (); + icon.save (ITEM_REMOTE_FILEPATH, loader.get_format().get_name()); + this.property_set(property, ITEM_REMOTE_FILEPATH); + } + catch(GLib.Error e){ + warning("Problem fetching file from the interweb - error: %s", + e.message); + } + } } === modified file 'src/sound-service.c' --- src/sound-service.c 2010-08-25 19:33:25 +0000 +++ src/sound-service.c 2010-09-02 10:31:05 +0000 @@ -40,14 +40,13 @@ { if (mainloop != NULL) { g_debug("Service shutdown !"); - // TODO: uncomment for release !! + //TODO: uncomment for release !! close_pulse_activites(); g_main_loop_quit(mainloop); } return; } - /** main: **/ === modified file 'vapi/common-defs.vapi' --- vapi/common-defs.vapi 2010-07-21 09:56:15 +0000 +++ vapi/common-defs.vapi 2010-09-02 10:31:05 +0000 @@ -1,6 +1,6 @@ /* Copyright 2010 Canonical Ltd. - + Authors: Conor Curran <[email protected]> @@ -27,6 +27,11 @@ } [CCode (cheader_filename = "common-defs.h")] +namespace DbusmenuPlayer{ + public const string ITEM_REMOTE_FILEPATH; +} + +[CCode (cheader_filename = "common-defs.h")] namespace DbusmenuTransport{ public const string MENUITEM_TYPE; public const string MENUITEM_PLAY_STATE;
_______________________________________________ Mailing list: https://launchpad.net/~ayatana-commits Post to : [email protected] Unsubscribe : https://launchpad.net/~ayatana-commits More help : https://help.launchpad.net/ListHelp

