[Rawstudio-commit] r2068 - trunk/src

Anders Brander anders at brander.dk
Mon Oct 13 21:58:20 CEST 2008


Author: abrander
Date: 2008-10-13 21:58:20 +0200 (Mon, 13 Oct 2008)
New Revision: 2068

Modified:
   trunk/src/rs-store.c
Log:
Enabled background loading of thumbnails and metadata.

Modified: trunk/src/rs-store.c
===================================================================
--- trunk/src/rs-store.c	2008-10-13 19:50:12 UTC (rev 2067)
+++ trunk/src/rs-store.c	2008-10-13 19:58:20 UTC (rev 2068)
@@ -96,6 +96,18 @@
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
+typedef struct _worker_job {
+	RSStore *store;
+	gchar *filename;
+	gint priority;
+	gboolean exported;
+	GtkTreeModel *model;
+	GtkTreePath *path;
+} WORKER_JOB;
+
+static GAsyncQueue *loader_queue = NULL;
+static gpointer worker_thread(gpointer data);
+
 /* FIXME: Remember to remove stores from this too! */
 static GList *all_stores = NULL;
 
@@ -123,9 +135,6 @@
 static void icon_get_selected_names(GtkIconView *iconview, GtkTreePath *path, gpointer user_data);
 static gboolean tree_foreach_names(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data);
 static gboolean tree_find_filename(GtkTreeModel *store, const gchar *filename, GtkTreeIter *iter, GtkTreePath **path);
-static void cancel_clicked(GtkButton *button, gpointer user_data);
-GList *find_loadable(const gchar *path, gboolean load_8bit, gboolean load_recursive);
-void load_loadable(RSStore *store, GList *loadable, RS_PROGRESS *rsp);
 void cairo_draw_thumbnail(cairo_t *cr, GdkPixbuf *pixbuf, gint x, gint y, gint width, gint height, gdouble alphas);
 GdkPixbuf * store_group_update_pixbufs(GdkPixbuf *pixbuf, GdkPixbuf *pixbuf_clean);
 void store_group_select_n(GtkListStore *store, GtkTreeIter iter, guint n);
@@ -181,6 +190,16 @@
 		icon_priority_D = gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/pixmaps/" PACKAGE "/overlay_deleted.png", NULL);
 		icon_exported = gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/pixmaps/" PACKAGE "/overlay_exported.png", NULL);
 	}
+
+	if (!loader_queue)
+	{
+		gint i = (rs_get_number_of_processor_cores()*3)/2;
+		loader_queue = g_async_queue_new();
+		while(i--)
+		{
+			g_thread_create(worker_thread, NULL, FALSE, NULL);
+		}
+	}
 }
 
 /**
@@ -493,7 +512,7 @@
 					METADATA_COLUMN, &metadata,
 					-1);
 
-				switch(type)
+				if (metadata) switch(type)
 				{
 					case RS_STORE_TYPE_GROUP:
 						g_string_printf(store->tooltip_text, "<big>FIXME: group</big>");
@@ -631,9 +650,17 @@
 
 	gtk_tree_model_get(model, tia, METADATA_COLUMN, &a, -1);
 	gtk_tree_model_get(model, tib, METADATA_COLUMN, &b, -1);
-	ret = a->timestamp - b->timestamp;
-	g_object_unref(a);
-	g_object_unref(b);
+
+	if ((a!=NULL) && (b!=NULL) && (a->timestamp != b->timestamp))
+		ret = a->timestamp - b->timestamp;
+	else
+		ret = model_sort_name(model, tia, tib, userdata);
+
+	if (a!=NULL)
+		g_object_unref(a);
+	if (b!=NULL)
+		g_object_unref(b);
+
 	return(ret);
 }
 
@@ -645,9 +672,17 @@
 
 	gtk_tree_model_get(model, tia, METADATA_COLUMN, &a, -1);
 	gtk_tree_model_get(model, tib, METADATA_COLUMN, &b, -1);
-	ret = a->iso - b->iso;
-	g_object_unref(a);
-	g_object_unref(b);
+
+	if ((a!=NULL) && (b!=NULL) && (a->iso != b->iso))
+		ret = a->iso - b->iso;
+	else
+		ret = model_sort_name(model, tia, tib, userdata);
+
+	if (a!=NULL)
+		g_object_unref(a);
+	if (b!=NULL)
+		g_object_unref(b);
+
 	return(ret);
 }
 
@@ -659,9 +694,17 @@
 
 	gtk_tree_model_get(model, tia, METADATA_COLUMN, &a, -1);
 	gtk_tree_model_get(model, tib, METADATA_COLUMN, &b, -1);
-	ret = a->aperture*10.0 - b->aperture*10.0;
-	g_object_unref(a);
-	g_object_unref(b);
+
+	if ((a!=NULL) && (b!=NULL) && (a->aperture != b->aperture))
+		ret = a->aperture*10.0 - b->aperture*10.0;
+	else
+		ret = model_sort_name(model, tia, tib, userdata);
+
+	if (a!=NULL)
+		g_object_unref(a);
+	if (b!=NULL)
+		g_object_unref(b);
+
 	return(ret);
 }
 
@@ -673,9 +716,17 @@
 
 	gtk_tree_model_get(model, tia, METADATA_COLUMN, &a, -1);
 	gtk_tree_model_get(model, tib, METADATA_COLUMN, &b, -1);
-	ret = a->focallength*10.0 - b->focallength*10.0;
-	g_object_unref(a);
-	g_object_unref(b);
+
+	if ((a!=NULL) && (b!=NULL) && (a->focallength != b->focallength))
+		ret = a->focallength*10.0 - b->focallength*10.0;
+	else
+		ret = model_sort_name(model, tia, tib, userdata);
+
+	if (a!=NULL)
+		g_object_unref(a);
+	if (b!=NULL)
+		g_object_unref(b);
+
 	return(ret);
 }
 
@@ -688,8 +739,17 @@
 	gtk_tree_model_get(model, tia, METADATA_COLUMN, &a, -1);
 	gtk_tree_model_get(model, tib, METADATA_COLUMN, &b, -1);
 	ret = b->shutterspeed*10.0 - a->shutterspeed*10.0;
-	g_object_unref(a);
-	g_object_unref(b);
+
+	if ((a!=NULL) && (b!=NULL) && (a->shutterspeed != b->shutterspeed))
+		ret = b->shutterspeed*10.0 - a->shutterspeed*10.0;
+	else
+		ret = model_sort_name(model, tia, tib, userdata);
+
+	if (a!=NULL)
+		g_object_unref(a);
+	if (b!=NULL)
+		g_object_unref(b);
+
 	return(ret);
 }
 
@@ -915,12 +975,75 @@
 	return ret;
 }
 
+static gint
+load_directory(RSStore *store, const gchar *path, const gboolean load_8bit, const gboolean load_recursive)
+{
+	const gchar *name;
+	gchar *fullname;
+	GDir *dir;
+	GdkPixbuf *pixbuf;
+	gint count = 0;
+	GtkTreeIter iter;
+	gboolean exported;
+	gint priority;
 
-static void
-cancel_clicked(GtkButton *button, gpointer user_data)
-{
-	RSStore *store = RS_STORE(user_data);
-	store->cancelled = TRUE;
+	pixbuf = gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/icons/" PACKAGE ".png", NULL);
+
+	dir = g_dir_open(path, 0, NULL); /* FIXME: check errors */
+
+	while((name = g_dir_read_name(dir)))
+	{
+		/* Ignore "hidden" files and directories */
+		if (name[0] == '.')
+			continue;
+
+		fullname = g_build_filename(path, name, NULL);
+
+		if (rs_filetype_can_load(fullname))
+		{
+			WORKER_JOB *job;
+
+			/* Sane defaults */
+			priority = PRIO_U;
+			exported = FALSE;
+
+			/* Load flags from XML cache */
+			rs_cache_load_quick(fullname, &priority, &exported);
+
+			/* Add thumbnail to store */
+			gtk_list_store_prepend (store->store, &iter);
+			gtk_list_store_set (store->store, &iter,
+				METADATA_COLUMN, NULL,
+				PIXBUF_COLUMN, pixbuf,
+				PIXBUF_CLEAN_COLUMN, pixbuf,
+				TEXT_COLUMN, name,
+				FULLNAME_COLUMN, fullname,
+				PRIORITY_COLUMN, priority,
+				EXPORTED_COLUMN, exported,
+				-1);
+
+			/* Push an asynchronous job for loading the thumbnail */
+			job = g_new(WORKER_JOB, 1);
+			job->store = g_object_ref(store);
+			job->filename = g_strdup(fullname);
+			job->priority = priority;
+			job->exported = exported;
+			job->model = g_object_ref(GTK_TREE_MODEL(store->store));
+			job->path = gtk_tree_model_get_path(GTK_TREE_MODEL(store->store), &iter);
+			g_async_queue_push(loader_queue, job);
+
+			count++;
+		}
+		else if (load_recursive && g_file_test(fullname, G_FILE_TEST_IS_DIR))
+			count += load_directory(store, fullname, load_8bit, load_recursive);
+
+		g_free(fullname);
+	}
+
+	g_object_unref(pixbuf);
+	g_dir_close(dir);
+
+	return count;
 }
 
 /* Public functions */
@@ -946,6 +1069,11 @@
 {
 	GtkTreeIter i;
 
+	/* Empty the loader queue */
+	g_async_queue_lock(loader_queue);
+	while(g_async_queue_try_pop_unlocked(loader_queue));
+	g_async_queue_unlock(loader_queue);
+
 	/* If we got no store, iterate though all */
 	if (!store)
 	{
@@ -970,144 +1098,12 @@
 	/* If both are NULL, remove everything */
 	if ((filename == NULL) && (iter == NULL))
 		gtk_list_store_clear(store->store);
-}
 
-/**
- * Load thumbnails from a directory into the store
- * @param path The path to load
- * @param load_8bit Boolean
- * @param load_recursive Boolean
- * @return GList containing paths to loadable files
- */
-GList *
-find_loadable(const gchar *path, gboolean load_8bit, gboolean load_recursive)
-{
-	gchar *name;
-	GString *fullname;
-	GList *loadable = NULL;
-	GDir *dir = g_dir_open(path, 0, NULL);
-
-	if (dir == NULL)
-		return loadable;
-
-	while ((name = (gchar *) g_dir_read_name(dir)))
-	{
-		fullname = g_string_new(path);
-		fullname = g_string_append(fullname, G_DIR_SEPARATOR_S);
-		fullname = g_string_append(fullname, name);
-
-		/* FIXME: deal with 8-bit-switch! */
-		if (rs_filetype_can_load(name))
-			loadable = g_list_append(loadable, fullname->str);
-
-		if (load_recursive)
-		{
-			if (g_file_test(fullname->str, G_FILE_TEST_IS_DIR))
-			{
-				/* We don't load hidden directories */
-				if (name[0] != '.')
-				{
-					GList *temp_loadable;
-					temp_loadable = find_loadable(fullname->str, load_8bit, load_recursive);
-					loadable = g_list_concat(loadable, temp_loadable);
-				}
-			}
-		}
-		g_string_free(fullname, FALSE);
-	}
-
-	if (dir)
-		g_dir_close(dir);
-
-	return loadable;
 }
 
 /**
  * Load thumbnails from a directory into the store
  * @param store A RSStore
- * @param loadable A GList containing paths to loadable files
- * @param rsp A progress bar
- */
-void
-load_loadable(RSStore *store, GList *loadable, RS_PROGRESS *rsp)
-{
-	gchar *name;
-	GdkPixbuf *pixbuf;
-	GdkPixbuf *pixbuf_clean;
-	GdkPixbuf *missing_thumb;
-	gint priority;
-	gboolean exported = FALSE;
-	GtkTreeIter iter;
-	gchar *fullname;
-	gint n;
-
-	/* We will use this, if no thumbnail can be loaded */
-	missing_thumb = gtk_widget_render_icon(GTK_WIDGET(store),
-		GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_DIALOG, NULL);
-
-	for(n = 0; n < g_list_length(loadable); n++)
-	{
-		if (store->cancelled)
-			break;
-		fullname = g_list_nth_data(loadable, n);
-		name = g_path_get_basename(fullname);
-
-		if (rs_filetype_can_load(name))
-		{
-			RSMetadata *metadata = rs_metadata_new_from_file(fullname);
-
-			pixbuf = rs_metadata_get_thumbnail(metadata);
-
-			if (pixbuf==NULL)
-			{
-				pixbuf = gdk_pixbuf_copy(missing_thumb);
-				g_object_ref (pixbuf);
-			}
-
-			/* Save a clean copy of the thumbnail for later use */
-			pixbuf_clean = gdk_pixbuf_copy(pixbuf);
-
-			/* Sane defaults */
-			priority = PRIO_U;
-			exported = FALSE;
-
-			/* Load flags from XML cache */
-			rs_cache_load_quick(fullname, &priority, &exported);
-
-			/* Update thumbnail */
-			thumbnail_update(pixbuf, pixbuf_clean, priority, exported);
-
-			/* Add thumbnail to store */
-			gtk_list_store_prepend (store->store, &iter);
-			gtk_list_store_set (store->store, &iter,
-				PIXBUF_COLUMN, pixbuf,
-				PIXBUF_CLEAN_COLUMN, pixbuf_clean,
-				TEXT_COLUMN, name,
-				FULLNAME_COLUMN, fullname,
-				PRIORITY_COLUMN, priority,
-				EXPORTED_COLUMN, exported,
-				METADATA_COLUMN, metadata,
-				-1);
-
-			/* We can safely unref by now, store holds a reference */
-			g_object_unref (metadata);
-			g_object_unref (pixbuf);
-			g_object_unref (pixbuf_clean);
-
-			/* Move our progress bar */
-			gui_progress_advance_one(rsp);
-		}
-		g_free(name);
-	}
-
-	g_object_unref(missing_thumb);
-
-	return;
-}
-
-/**
- * Load thumbnails from a directory into the store
- * @param store A RSStore
  * @param path The path to load
  * @return The number of files loaded or -1
  */
@@ -1117,14 +1113,12 @@
 	static gboolean running = FALSE;
 	GStaticMutex lock = G_STATIC_MUTEX_INIT;
 
-	RS_PROGRESS *rsp;
-	GtkWidget *cancel;
+	GtkTreeSortable *sortable;
 	gboolean load_8bit = FALSE;
 	gboolean load_recursive = DEFAULT_CONF_LOAD_RECURSIVE;
 	gint items=0, n;
 	GtkTreePath *treepath;
 	GtkTreeIter iter;
-	GList *loadable = NULL;
 
 	g_return_val_if_fail(RS_IS_STORE(store), -1);
 	if (!path)
@@ -1151,10 +1145,9 @@
 	rs_conf_get_boolean(CONF_LOAD_GDK, &load_8bit);
 	rs_conf_get_boolean(CONF_LOAD_RECURSIVE, &load_recursive);
 
-	/* find loadable files */
-	loadable = find_loadable(path, load_8bit, load_recursive);
-	loadable = g_list_first(loadable);
-	items = g_list_length(loadable);
+	/* Block the priority count */
+	g_signal_handler_block(store->store, store->counthandler);
+	items = load_directory(store, path, load_8bit, load_recursive);
 
 	/* unset model and make sure we have enough columns */
 	for (n=0;n<NUM_VIEWS;n++)
@@ -1163,21 +1156,15 @@
 		gtk_icon_view_set_columns(GTK_ICON_VIEW (store->iconview[n]), items);
 	}
 
-	/* Block the priority count */
-	g_signal_handler_block(store->store, store->counthandler);
+	/* Sort the store */
+	sortable = GTK_TREE_SORTABLE(store->store);
+	gtk_tree_sortable_set_sort_func(sortable,
+		TEXT_COLUMN,
+		model_sort_name,
+		NULL,
+		NULL);
+	gtk_tree_sortable_set_sort_column_id(sortable, TEXT_COLUMN, GTK_SORT_ASCENDING);
 
-	/* Add a progress bar */
-	store->cancelled = FALSE;
-	cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
-	g_signal_connect (G_OBJECT(cancel), "clicked", G_CALLBACK(cancel_clicked), store);
-	rsp = gui_progress_new_with_delay(_("Opening directory..."), items, 200);
-	gui_progress_add_widget(rsp, cancel);
-
-	/* load all loadable items */
-	load_loadable(store, loadable, rsp);
-	g_list_foreach (loadable, (GFunc)g_free, NULL);
-	g_list_free(loadable);
-
 	/* unblock the priority count */
 	g_signal_handler_unblock(store->store, store->counthandler);
 
@@ -1203,9 +1190,6 @@
 	store_load_groups(store->store);
 #endif
 
-	/* Free the progress bar */
-	gui_progress_free(rsp);
-
 	/* Start the preloader */
 	predict_preload(store, TRUE);
 
@@ -2340,3 +2324,59 @@
 						GROUP_LIST_COLUMN, members,
 						-1);
 }
+
+static gpointer
+worker_thread(gpointer data)
+{
+	WORKER_JOB *job;
+	GdkPixbuf *pixbuf, *pixbuf_clean;
+	GtkTreeIter iter;
+	RSMetadata *metadata;
+
+	while((job = g_async_queue_pop(loader_queue)))
+	{
+		metadata = rs_metadata_new_from_file(job->filename);
+		g_assert(RS_IS_METADATA(metadata));
+
+		pixbuf = rs_metadata_get_thumbnail(metadata);
+
+		if (pixbuf==NULL)
+			/* We will use this, if no thumbnail can be loaded */
+			pixbuf = gtk_widget_render_icon(GTK_WIDGET(job->store),
+				GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_DIALOG, NULL);
+
+		pixbuf_clean = gdk_pixbuf_copy(pixbuf);
+
+		/* Update thumbnail */
+		thumbnail_update(pixbuf, pixbuf_clean, job->priority, job->exported);
+
+		g_assert(pixbuf != NULL);
+		g_assert(pixbuf_clean != NULL);
+
+		/* Add the new thumbnail to the store */
+		gdk_threads_enter();
+		if (tree_find_filename(job->model, job->filename, &iter, NULL))
+		{
+			gtk_list_store_set(GTK_LIST_STORE(job->model), &iter,
+				METADATA_COLUMN, metadata,
+				PIXBUF_COLUMN, pixbuf,
+				PIXBUF_CLEAN_COLUMN, pixbuf_clean,
+				-1);
+		}
+		gdk_threads_leave();
+
+		/* The GtkListStore should have ref'ed these */
+		g_object_unref(pixbuf);
+		g_object_unref(pixbuf_clean);
+
+		/* Clean up the job */
+		g_free(job->filename);
+		gtk_tree_path_free(job->path);
+		g_object_unref(job->store);
+		g_object_unref(job->model);
+		g_free(job);
+	}
+
+	/* This is only to stop gcc from complaining, we will never return */
+	return NULL;
+}




More information about the Rawstudio-commit mailing list