+/*! Merges two image sets, destroying one, and returning the other. */
+RrImageSet* RrImageSetMergeSets(RrImageSet *b, RrImageSet *a)
+{
+ gint a_i, b_i, merged_i;
+ RrImagePic **original, **resized;
+ gint n_original, n_resized, tmp;
+ GSList *it;
+
+ const gint max_resized = a->cache->max_resized_saved;
+
+ if (!a)
+ return b;
+ if (!b)
+ return a;
+ if (a == b)
+ return b;
+
+ /* the original and resized picture lists in an RrImageSet are kept ordered
+ as newest to oldest. we don't have timestamps for them, so we cannot
+ preserve this in the merged RrImageSet exactly. a decent approximation,
+ i think, is to add them in alternating order (one from a, one from b,
+ repeat). this way, the newest from each will be near the front at
+ least, and in the resized list, when we drop an old picture, we will
+ not always only drop from a or b only, but from each of them equally (or
+ from whichever has more resized pictures.
+ */
+
+ g_assert(b->cache == a->cache);
+
+ a_i = b_i = merged_i = 0;
+ n_original = a->n_original + b->n_original;
+ original = g_new(RrImagePic*, n_original);
+ while (merged_i < n_original) {
+ if (a_i < a->n_original)
+ original[merged_i++] = a->original[a_i++];
+ if (b_i < b->n_original)
+ original[merged_i++] = b->original[b_i++];
+ }
+
+ a_i = b_i = merged_i = 0;
+ n_resized = MIN(max_resized, a->n_resized + b->n_resized);
+ resized = g_new(RrImagePic*, n_resized);
+ while (merged_i < n_resized) {
+ if (a_i < a->n_resized)
+ resized[merged_i++] = a->resized[a_i++];
+ if (b_i < b->n_resized && merged_i < n_resized)
+ resized[merged_i++] = b->resized[b_i++];
+ }
+
+ /* if there are any RrImagePic objects left over in a->resized or
+ b->resized, they need to be disposed of, and removed from the cache.
+
+ updates the size of the list, as we want to remember which pointers
+ were merged from which list (and don't want to remember the ones we
+ did not merge and have freed).
+ */
+ tmp = a_i;
+ for (; a_i < a->n_resized; ++a_i) {
+ g_hash_table_remove(a->cache->pic_table, a->resized[a_i]);
+ RrImagePicFree(a->resized[a_i]);
+ }
+ a->n_resized = tmp;
+
+ tmp = b_i;
+ for (; b_i < b->n_resized; ++b_i) {
+ g_hash_table_remove(a->cache->pic_table, b->resized[b_i]);
+ RrImagePicFree(b->resized[b_i]);
+ }
+ b->n_resized = tmp;
+
+ /* we will use the a object as the merge destination, so things in b will
+ be moving.
+
+ the cache's name_table will point to b for all the names in b->names,
+ so these need to be updated to point at a instead.
+ also, the cache's pic_table will point to b for all the pictures in b,
+ so these need to be updated to point at a as well.
+
+ any RrImage objects that were using b should now use a instead.
+
+ the names and images will be all moved into a, and the merged picture
+ lists will be placed in a. the pictures in a and b are moved to new
+ arrays, so the arrays in a and b need to be freed explicitly (the
+ RrImageSetFree function would free the picture data too which we do not
+ want here). then b can be freed.
+ */
+
+ for (it = b->names; it; it = g_slist_next(it))
+ g_hash_table_insert(a->cache->name_table, it->data, a);
+ for (b_i = 0; b_i < b->n_original; ++b_i)
+ g_hash_table_insert(a->cache->pic_table, b->original[b_i], a);
+ for (b_i = 0; b_i < b->n_resized; ++b_i)
+ g_hash_table_insert(a->cache->pic_table, b->resized[b_i], a);
+
+ for (it = b->images; it; it = g_slist_next(it))
+ ((RrImage*)it->data)->set = a;
+
+ a->images = g_slist_concat(a->images, b->images);
+ b->images = NULL;
+ a->names = g_slist_concat(a->names, b->names);
+ b->names = NULL;
+
+ a->n_original = a->n_resized = 0;
+ g_free(a->original);
+ g_free(a->resized);
+ a->original = a->resized = NULL;
+ b->n_original = b->n_resized = 0;
+ g_free(b->original);
+ g_free(b->resized);
+ b->original = b->resized = NULL;
+
+ a->n_original = n_original;
+ a->original = original;
+ a->n_resized = n_resized;
+ a->resized = resized;
+
+ RrImageSetFree(b);
+
+ return a;
+}
+
+static void RrImageSetAddName(RrImageSet *set, const gchar *name)
+{
+ gchar *n;
+
+ n = g_strdup(name);
+ set->names = g_slist_prepend(set->names, n);
+
+ /* add the new name to the hash table */
+ g_assert(g_hash_table_lookup(set->cache->name_table, n) == NULL);
+ g_hash_table_insert(set->cache->name_table, n, set);
+}
+
+
+/************************************************************************
+ RrImage functions.
+**************************************************************************/
+
+
+void RrImageRef(RrImage *self)