--- a/libpurple/image-store.c Wed Apr 09 20:20:21 2014 +0200 +++ b/libpurple/image-store.c Thu Apr 10 00:32:00 2014 +0200 @@ -21,36 +21,145 @@ #include "image-store.h" +#include "eventloop.h" +#include "glibcompat.h" + +#define TEMP_IMAGE_TIMEOUT 5 + +static GHashTable *id_to_image; +static guint last_id = 0; + +/* keys: timeout handle */ +static GHashTable *temp_images = NULL; + +/* keys: img id */ +static GSList *perm_images = NULL; + +static guint +image_set_id(PurpleImage *image) +{ + /* Use the next unused id number. We do it in a loop on the off chance + * that next id wraps back around to 0 and the hash table still contains + * entries from the first time around. + */ + while (TRUE) { + last_id++; + + if (G_UNLIKELY(last_id == 0)) + continue; + + if (purple_image_store_get(last_id) == NULL) + break; + } + + g_object_set_data(G_OBJECT(image), "purple-image-store-id", + GINT_TO_POINTER(last_id)); + g_hash_table_insert(id_to_image, GINT_TO_POINTER(last_id), image); + /* TODO: hook map removal after object destruction */ + return last_id; +} + +static guint +image_get_id(PurpleImage *image) +{ + return GPOINTER_TO_INT(g_object_get_data(G_OBJECT(image), + "purple-image-store-id")); +} + guint purple_image_store_add(PurpleImage *image) { - return 0; + guint id; + + g_return_val_if_fail(PURPLE_IS_IMAGE(image), 0); + + id = image_get_id(image); + if (id > 0) + return id; + + id = image_set_id(image); + + g_object_ref(image); + perm_images = g_slist_prepend(perm_images, image); + + return id; } guint purple_image_store_add_weak(PurpleImage *image) { - return 0; + guint id; + + g_return_val_if_fail(PURPLE_IS_IMAGE(image), 0); + + id = image_get_id(image); + if (id > 0) + return id; + + return image_set_id(image); +} + +static gboolean +remove_temporary(gpointer _image) +{ + PurpleImage *image = _image; + guint handle; + + handle = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(image), + "purple-image-store-handle")); + + g_hash_table_remove(temp_images, GINT_TO_POINTER(handle)); + + return G_SOURCE_REMOVE; } guint purple_image_store_add_temporary(PurpleImage *image) { - return 0; + guint id; + guint handle; + + g_return_val_if_fail(PURPLE_IS_IMAGE(image), 0); + + id = image_get_id(image); + if (id > 0) + return id; + + id = image_set_id(image); + + g_object_ref(image); + handle = purple_timeout_add_seconds(TEMP_IMAGE_TIMEOUT, + remove_temporary, image); + g_object_set_data(G_OBJECT(image), "purple-image-store-handle", + GINT_TO_POINTER(handle)); + g_hash_table_insert(temp_images, GINT_TO_POINTER(handle), image); + + return id; } PurpleImage * purple_image_store_get(guint id) { - return NULL; + return g_hash_table_lookup(id_to_image, GINT_TO_POINTER(id)); } void _purple_image_store_init(void) { + id_to_image = g_hash_table_new(g_direct_hash, g_direct_equal); + temp_images = g_hash_table_new_full(g_direct_hash, g_direct_equal, + NULL, g_object_unref); } void _purple_image_store_uninit(void) { + g_slist_free_full(perm_images, g_object_unref); + perm_images = NULL; + + g_hash_table_destroy(temp_images); + temp_images = NULL; + + g_hash_table_destroy(id_to_image); + id_to_image = NULL; }