[rhythmbox] audioscrobbler: ensure RBAudioscrobblerUserData stays alive for image download
- From: Jamie Nicol <jamien src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [rhythmbox] audioscrobbler: ensure RBAudioscrobblerUserData stays alive for image download
- Date: Sun, 14 Aug 2011 12:14:29 +0000 (UTC)
commit a967a90eb6af16cd480d7f8dd187c1e34f433f4c
Author: Jamie Nicol <jamie thenicols net>
Date: Mon Jun 20 13:13:08 2011 +0100
audioscrobbler: ensure RBAudioscrobblerUserData stays alive for image download
Make RBAudioscrobblerUserData refcounted and give the download map a reference.
Also make download maps responsible for unreffing their keys and values, and
fix a couple leaks.
https://bugzilla.gnome.org/show_bug.cgi?id=645015
plugins/audioscrobbler/rb-audioscrobbler-user.c | 130 ++++++++++++-----------
plugins/audioscrobbler/rb-audioscrobbler-user.h | 2 +
2 files changed, 69 insertions(+), 63 deletions(-)
---
diff --git a/plugins/audioscrobbler/rb-audioscrobbler-user.c b/plugins/audioscrobbler/rb-audioscrobbler-user.c
index cd9f619..5865d53 100644
--- a/plugins/audioscrobbler/rb-audioscrobbler-user.c
+++ b/plugins/audioscrobbler/rb-audioscrobbler-user.c
@@ -47,31 +47,18 @@
#define RECOMMENDED_ARTISTS_LIFETIME 86400 /* 24 hours */
static RBAudioscrobblerUserData *
-rb_audioscrobbler_user_data_copy (RBAudioscrobblerUserData *data)
-{
- RBAudioscrobblerUserData *d = g_slice_new0 (RBAudioscrobblerUserData);
+rb_audioscrobbler_user_data_new () {
+ RBAudioscrobblerUserData *data = g_slice_new0 (RBAudioscrobblerUserData);
- d->type = data->type;
- if (data->image != NULL) {
- d->image = g_object_ref (data->image);
- }
- d->url = g_strdup (data->url);
-
- switch (d->type) {
- case RB_AUDIOSCROBBLER_USER_DATA_TYPE_USER_INFO:
- d->user_info.username = g_strdup (data->user_info.username);
- d->user_info.playcount = g_strdup (data->user_info.playcount);
- break;
- case RB_AUDIOSCROBBLER_USER_DATA_TYPE_TRACK:
- d->track.title = g_strdup (data->track.title);
- d->track.artist = g_strdup (data->track.artist);
- break;
- case RB_AUDIOSCROBBLER_USER_DATA_TYPE_ARTIST:
- d->artist.name = g_strdup (data->artist.name);
- break;
- }
+ data->refcount = 1;
+ return data;
+}
- return d;
+static RBAudioscrobblerUserData *
+rb_audioscrobbler_user_data_ref (RBAudioscrobblerUserData *data)
+{
+ data->refcount++;
+ return data;
}
static void
@@ -99,6 +86,13 @@ rb_audioscrobbler_user_data_free (RBAudioscrobblerUserData *data)
g_slice_free (RBAudioscrobblerUserData, data);
}
+static void
+rb_audioscrobbler_user_data_unref (RBAudioscrobblerUserData *data) {
+ if (--data->refcount == 0) {
+ rb_audioscrobbler_user_data_free (data);
+ }
+}
+
GType
rb_audioscrobbler_user_data_get_type (void)
{
@@ -106,8 +100,8 @@ rb_audioscrobbler_user_data_get_type (void)
if (G_UNLIKELY (type == 0)) {
type = g_boxed_type_register_static ("RBAudioscrobblerUserData",
- (GBoxedCopyFunc)rb_audioscrobbler_user_data_copy,
- (GBoxedFreeFunc)rb_audioscrobbler_user_data_free);
+ (GBoxedCopyFunc)rb_audioscrobbler_user_data_ref,
+ (GBoxedFreeFunc)rb_audioscrobbler_user_data_unref);
}
return type;
@@ -354,8 +348,14 @@ rb_audioscrobbler_user_init (RBAudioscrobblerUser *user)
SOUP_TYPE_GNOME_FEATURES_2_26,
NULL);
- user->priv->file_to_data_map = g_hash_table_new (g_direct_hash, g_direct_equal);
- user->priv->file_to_cancellable_map = g_hash_table_new (g_direct_hash, g_direct_equal);
+ user->priv->file_to_data_map = g_hash_table_new_full (g_file_hash,
+ (GEqualFunc) g_file_equal,
+ g_object_unref,
+ (GDestroyNotify) rb_audioscrobbler_user_data_unref);
+ user->priv->file_to_cancellable_map = g_hash_table_new_full (g_file_hash,
+ (GEqualFunc) g_file_equal,
+ NULL,
+ g_object_unref);
}
static void
@@ -380,7 +380,7 @@ rb_audioscrobbler_user_dispose (GObject* object)
}
if (user->priv->user_info != NULL) {
- g_boxed_free (RB_TYPE_AUDIOSCROBBLER_USER_DATA, user->priv->user_info);
+ rb_audioscrobbler_user_data_unref (user->priv->user_info);
user->priv->user_info = NULL;
}
@@ -409,11 +409,7 @@ rb_audioscrobbler_user_dispose (GObject* object)
user->priv->recommended_artists = NULL;
}
- if (user->priv->file_to_data_map != NULL) {
- g_hash_table_unref (user->priv->file_to_data_map);
- user->priv->file_to_data_map = NULL;
- }
-
+ /* free this map first because file_to_data_map owns the file reference */
if (user->priv->file_to_cancellable_map != NULL) {
GList *key;
@@ -422,13 +418,17 @@ rb_audioscrobbler_user_dispose (GObject* object)
key = g_list_next (key)) {
GCancellable *cancellable = g_hash_table_lookup (user->priv->file_to_cancellable_map, key->data);
g_cancellable_cancel (cancellable);
- g_object_unref (cancellable);
}
g_list_free (key);
g_hash_table_unref (user->priv->file_to_cancellable_map);
user->priv->file_to_cancellable_map = NULL;
}
+
+ if (user->priv->file_to_data_map != NULL) {
+ g_hash_table_unref (user->priv->file_to_data_map);
+ user->priv->file_to_data_map = NULL;
+ }
}
static void
@@ -557,7 +557,7 @@ load_from_cache (RBAudioscrobblerUser *user)
{
/* delete old data */
if (user->priv->user_info != NULL) {
- g_boxed_free (RB_TYPE_AUDIOSCROBBLER_USER_DATA, user->priv->user_info);
+ rb_audioscrobbler_user_data_unref (user->priv->user_info);
user->priv->user_info = NULL;
}
@@ -679,7 +679,7 @@ parse_track_array (RBAudioscrobblerUser *user, JsonArray *track_array)
GPtrArray *tracks;
int i;
- tracks = g_ptr_array_new_with_free_func ((GDestroyNotify)rb_audioscrobbler_user_data_free);
+ tracks = g_ptr_array_new_with_free_func ((GDestroyNotify)rb_audioscrobbler_user_data_unref);
for (i = 0; i < json_array_get_length (track_array); i++) {
JsonObject *track_object;
@@ -689,7 +689,7 @@ parse_track_array (RBAudioscrobblerUser *user, JsonArray *track_array)
track_object = json_array_get_object_element (track_array, i);
- track = g_slice_new0 (RBAudioscrobblerUserData);
+ track = rb_audioscrobbler_user_data_new ();
track->type = RB_AUDIOSCROBBLER_USER_DATA_TYPE_TRACK;
track->track.title = g_strdup (json_object_get_string_member (track_object, "name"));
@@ -732,7 +732,7 @@ parse_artist_array (RBAudioscrobblerUser *user, JsonArray *artist_array)
GPtrArray *artists;
int i;
- artists = g_ptr_array_new_with_free_func ((GDestroyNotify)rb_audioscrobbler_user_data_free);
+ artists = g_ptr_array_new_with_free_func ((GDestroyNotify)rb_audioscrobbler_user_data_unref);
for (i = 0; i < json_array_get_length (artist_array); i++) {
JsonObject *artist_object;
@@ -741,7 +741,7 @@ parse_artist_array (RBAudioscrobblerUser *user, JsonArray *artist_array)
artist_object = json_array_get_object_element (artist_array, i);
- artist = g_slice_new0 (RBAudioscrobblerUserData);
+ artist = rb_audioscrobbler_user_data_new ();
artist->type = RB_AUDIOSCROBBLER_USER_DATA_TYPE_ARTIST;
artist->artist.name = g_strdup (json_object_get_string_member (artist_object, "name"));
artist->url = g_strdup (json_object_get_string_member (artist_object, "url"));
@@ -778,7 +778,7 @@ load_cached_user_info (RBAudioscrobblerUser *user)
/* delete old data */
if (user->priv->user_info != NULL) {
- g_boxed_free (RB_TYPE_AUDIOSCROBBLER_USER_DATA, user->priv->user_info);
+ rb_audioscrobbler_user_data_unref (user->priv->user_info);
user->priv->user_info = NULL;
}
@@ -833,7 +833,7 @@ user_info_response_cb (SoupSession *session,
rb_debug ("user info request was successful");
if (user->priv->user_info != NULL) {
- g_boxed_free (RB_TYPE_AUDIOSCROBBLER_USER_DATA, user->priv->user_info);
+ rb_audioscrobbler_user_data_unref (user->priv->user_info);
}
user->priv->user_info = user_info;
@@ -864,7 +864,7 @@ parse_user_info (RBAudioscrobblerUser *user, const char *data)
user_object = json_object_get_object_member (root_object, "user");
char *image_path;
- user_info = g_slice_new0 (RBAudioscrobblerUserData);
+ user_info = rb_audioscrobbler_user_data_new ();
user_info->type = RB_AUDIOSCROBBLER_USER_DATA_TYPE_USER_INFO;
user_info->user_info.username = g_strdup (json_object_get_string_member (user_object, "name"));
user_info->user_info.playcount = g_strdup (json_object_get_string_member (user_object, "playcount"));
@@ -1553,7 +1553,9 @@ download_image (RBAudioscrobblerUser *user, const char *image_url, RBAudioscrobb
GFile *dest_file;
/* add data to map */
- g_hash_table_insert (user->priv->file_to_data_map, src_file, data);
+ g_hash_table_insert (user->priv->file_to_data_map,
+ src_file,
+ rb_audioscrobbler_user_data_ref (data));
/* create a cancellable for this download */
cancellable = g_cancellable_new ();
@@ -1576,46 +1578,45 @@ download_image (RBAudioscrobblerUser *user, const char *image_url, RBAudioscrobb
} else {
rb_debug ("not downloading image: error creating dest dir");
g_error_free (error);
+ g_object_unref (src_file);
}
g_free (dest_filename);
g_free (dest_file_uri);
+ } else {
+ g_object_unref (src_file);
}
}
static void
image_download_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
+ RBAudioscrobblerUser *user = RB_AUDIOSCROBBLER_USER (user_data);
GFile *src_file = G_FILE (source_object);
+ RBAudioscrobblerUserData *data;
- if (g_file_copy_finish (src_file, res, NULL)) {
- RBAudioscrobblerUser *user;
- GCancellable *cancellable;
- RBAudioscrobblerUserData *data;
- char *dest_file_path;
-
- user = RB_AUDIOSCROBBLER_USER (user_data);
+ /* free the cancellable */
+ g_hash_table_remove (user->priv->file_to_cancellable_map, src_file);
- /* free the cancellable */
- cancellable = g_hash_table_lookup (user->priv->file_to_cancellable_map, src_file);
- g_hash_table_remove (user->priv->file_to_cancellable_map, src_file);
- g_object_unref (cancellable);
+ data = g_hash_table_lookup (user->priv->file_to_data_map, src_file);
- /* update the data */
- data = g_hash_table_lookup (user->priv->file_to_data_map, src_file);
- g_hash_table_remove (user->priv->file_to_data_map, src_file);
+ /* It is only worthwhile continuing if the data's refcount is greater
+ * than 1. Otherwise nobody else cares about it. */
+ if (g_file_copy_finish (src_file, res, NULL) && data->refcount > 1) {
+ char *dest_file_path;
- dest_file_path = calculate_cached_image_path (user, data);
if (data->image != NULL) {
g_object_unref (data->image);
}
/* load image at correct size for the data type */
+ dest_file_path = calculate_cached_image_path (user, data);
if (data->type == RB_AUDIOSCROBBLER_USER_DATA_TYPE_USER_INFO) {
data->image = gdk_pixbuf_new_from_file_at_size (dest_file_path, USER_PROFILE_IMAGE_SIZE, -1, NULL);
} else {
data->image = gdk_pixbuf_new_from_file_at_size (dest_file_path, LIST_ITEM_IMAGE_SIZE, LIST_ITEM_IMAGE_SIZE, NULL);
}
+ g_free (dest_file_path);
/* emit appropriate signal - quite ugly, surely this could be done in a nicer way */
if (data->type == RB_AUDIOSCROBBLER_USER_DATA_TYPE_USER_INFO) {
@@ -1627,7 +1628,7 @@ image_download_cb (GObject *source_object, GAsyncResult *res, gpointer user_data
for (i = 0; i < user->priv->recent_tracks->len; i++) {
if (g_ptr_array_index (user->priv->recent_tracks, i) == data) {
g_signal_emit (user, rb_audioscrobbler_user_signals[RECENT_TRACKS_UPDATED],
- 0, user->priv->recent_tracks);
+ 0, user->priv->recent_tracks);
}
}
}
@@ -1635,7 +1636,7 @@ image_download_cb (GObject *source_object, GAsyncResult *res, gpointer user_data
for (i = 0; i < user->priv->top_tracks->len; i++) {
if (g_ptr_array_index (user->priv->top_tracks, i) == data) {
g_signal_emit (user, rb_audioscrobbler_user_signals[TOP_TRACKS_UPDATED],
- 0, user->priv->top_tracks);
+ 0, user->priv->top_tracks);
}
}
}
@@ -1643,7 +1644,7 @@ image_download_cb (GObject *source_object, GAsyncResult *res, gpointer user_data
for (i = 0; i < user->priv->loved_tracks->len; i++) {
if (g_ptr_array_index (user->priv->loved_tracks, i) == data) {
g_signal_emit (user, rb_audioscrobbler_user_signals[LOVED_TRACKS_UPDATED],
- 0, user->priv->loved_tracks);
+ 0, user->priv->loved_tracks);
}
}
}
@@ -1653,7 +1654,7 @@ image_download_cb (GObject *source_object, GAsyncResult *res, gpointer user_data
for (i = 0; i < user->priv->top_artists->len; i++) {
if (g_ptr_array_index (user->priv->top_artists, i) == data) {
g_signal_emit (user, rb_audioscrobbler_user_signals[TOP_ARTISTS_UPDATED],
- 0, user->priv->top_artists);
+ 0, user->priv->top_artists);
}
}
}
@@ -1661,7 +1662,7 @@ image_download_cb (GObject *source_object, GAsyncResult *res, gpointer user_data
for (i = 0; i < user->priv->recommended_artists->len; i++) {
if (g_ptr_array_index (user->priv->recommended_artists, i) == data) {
g_signal_emit (user, rb_audioscrobbler_user_signals[RECOMMENDED_ARTISTS_UPDATED],
- 0, user->priv->recommended_artists);
+ 0, user->priv->recommended_artists);
}
}
}
@@ -1669,6 +1670,9 @@ image_download_cb (GObject *source_object, GAsyncResult *res, gpointer user_data
} else {
rb_debug ("error downloading image. possibly due to cancellation");
}
+
+ /* cleanup the file and data */
+ g_hash_table_remove (user->priv->file_to_data_map, src_file);
}
void
diff --git a/plugins/audioscrobbler/rb-audioscrobbler-user.h b/plugins/audioscrobbler/rb-audioscrobbler-user.h
index d8dcaac..4869262 100644
--- a/plugins/audioscrobbler/rb-audioscrobbler-user.h
+++ b/plugins/audioscrobbler/rb-audioscrobbler-user.h
@@ -39,6 +39,8 @@ G_BEGIN_DECLS
#define RB_AUDIOSCROBBLER_USER_DATA(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_AUDIOSCROBBLER_USER_DATA, RBAudioscrobblerUserData))
#define RB_IS_AUDIOSCROBBLER_USER_DATA(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_AUDIOSCROBBLER_USER_DATA))
typedef struct {
+ unsigned int refcount;
+
enum {
RB_AUDIOSCROBBLER_USER_DATA_TYPE_USER_INFO,
RB_AUDIOSCROBBLER_USER_DATA_TYPE_TRACK,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]