[maemo-commits] [maemo-commits] r16213 - in projects/haf/trunk/hildon-thumbnail: . daemon daemon/plugins debian thumbs

From: subversion at stage.maemo.org subversion at stage.maemo.org
Date: Wed Sep 24 17:42:36 EEST 2008
Author: marivoll
Date: 2008-09-24 17:42:35 +0300 (Wed, 24 Sep 2008)
New Revision: 16213

Modified:
   projects/haf/trunk/hildon-thumbnail/ChangeLog
   projects/haf/trunk/hildon-thumbnail/daemon/hildon-thumbnail-daemon.c
   projects/haf/trunk/hildon-thumbnail/daemon/manager.c
   projects/haf/trunk/hildon-thumbnail/daemon/plugin-runner.c
   projects/haf/trunk/hildon-thumbnail/daemon/plugins/exec-plugin.c
   projects/haf/trunk/hildon-thumbnail/daemon/plugins/gdkpixbuf-plugin.c
   projects/haf/trunk/hildon-thumbnail/daemon/plugins/gstreamer-video-plugin.c
   projects/haf/trunk/hildon-thumbnail/daemon/thumbnailer.c
   projects/haf/trunk/hildon-thumbnail/debian/changelog
   projects/haf/trunk/hildon-thumbnail/thumbs/hildon-thumbnail-factory.c
Log:
Merged daemonize branch.

  [ Philip Van Hoof ]
  * Completed API in the daemon.
  * Monitor plugin directory.
  * Avoid D-Bus roundtrip for existing thumbnails when using the
    HildonThumbnailFactory API.
  * Handle large requests in a separate thread so that small
    requests are not starved.


Modified: projects/haf/trunk/hildon-thumbnail/ChangeLog
===================================================================
--- projects/haf/trunk/hildon-thumbnail/ChangeLog	2008-09-24 13:48:05 UTC (rev 16212)
+++ projects/haf/trunk/hildon-thumbnail/ChangeLog	2008-09-24 14:42:35 UTC (rev 16213)
@@ -1,5 +1,44 @@
+2008-09-24  Philip Van Hoof  <pvanhoof at gnome.org>
+
+	* thumbs/hildon-thumbnail-factory.c: Performance improvement when a
+	thumbnail already exists (avoiding a dbus call)
+
+2008-09-23  Philip Van Hoof  <pvanhoof at gnome.org>
+
+	* daemon/manager.c: Fixed a crash
+
+2008-09-23  Philip Van Hoof  <pvanhoof at gnome.org>
+
+	* daemon/thumbnailer.c: Adding a thread for large tasks
+
+2008-09-20  Philip Van Hoof  <pvanhoof at gnome.org>
+
+	* thumbs/hildon-thumbnail-factory.c
+	* daemon/plugin-runner.c
+	* daemon/manager.c
+	* daemon/thumbnailer.c: Various comments and leak fixes
+
+2008-09-18  Philip Van Hoof  <pvanhoof at gnome.org>
+
+	* daemon/hildon-thumbnail-daemon.c: File monitoring the plugins
+
+	* daemon/hildon-thumbnail-daemon.c
+	* daemon/manager.c: Using the right kinds of file monitors (dir monitors)
+
 2008-09-17  Philip Van Hoof  <pvanhoof at gnome.org>
 
+	* daemon/plugins/gdkpixbuf-plugin.c:
+	* daemon/plugins/exec-plugin.c:
+	* daemon/plugins/gstreamer-video-plugin.c: Fixed memory leaks when errors occur
+
+	* daemon/thumbnailer.c: Implemented the move, copy, delete hint handlers
+
+2008-09-17  Marius Vollmer  <marius.vollmer at nokia.com>
+
+	Released 3.0.0
+
+2008-09-17  Philip Van Hoof  <pvanhoof at gnome.org>
+
 	* daemon/plugins/exec-plugin.c
 	* daemon/manager.c: Respecting the override file
 

Modified: projects/haf/trunk/hildon-thumbnail/daemon/hildon-thumbnail-daemon.c
===================================================================
--- projects/haf/trunk/hildon-thumbnail/daemon/hildon-thumbnail-daemon.c	2008-09-24 13:48:05 UTC (rev 16212)
+++ projects/haf/trunk/hildon-thumbnail/daemon/hildon-thumbnail-daemon.c	2008-09-24 14:42:35 UTC (rev 16213)
@@ -25,12 +25,14 @@
 
 #include <glib.h>
 #include <dbus/dbus-glib-bindings.h>
+#include <gio/gio.h>
 
 #include "hildon-thumbnail-plugin.h"
 
 #include "thumbnailer.h"
 #include "manager.h"
 
+static GHashTable *registrations;
 static gboolean do_shut_down_next_time = TRUE;
 
 void
@@ -54,11 +56,117 @@
 	return shut;
 }
 
+
+static GHashTable*
+init_plugins (DBusGConnection *connection, Thumbnailer *thumbnailer)
+{
+	GHashTable *regs;
+	GModule *module;
+	GError *error = NULL;
+	GDir *dir;
+	const gchar *plugin;
+
+	regs = g_hash_table_new_full (g_str_hash, g_str_equal,
+				      (GDestroyNotify) g_free, 
+				      (GDestroyNotify) NULL);
+
+
+	/* TODO: Monitor this directory for plugin removals and additions */
+
+	dir = g_dir_open (PLUGINS_DIR, 0, &error);
+
+	if (dir) {
+	  while ((plugin = g_dir_read_name (dir)) != NULL) {
+		gboolean cropping;
+
+		if (!g_str_has_suffix (plugin, "." G_MODULE_SUFFIX)) {
+			continue;
+		}
+		
+		module = hildon_thumbnail_plugin_load (plugin);
+		hildon_thumbnail_plugin_do_init (module, &cropping,
+						 (register_func) thumbnailer_register_plugin,
+						 thumbnailer,
+						 &error);
+		if (error) {
+			g_warning ("Can't load plugin [%s]: %s\n", plugin, 
+				   error->message);
+			g_error_free (error);
+		} else
+			g_hash_table_replace (regs, g_strdup (plugin),
+					      module);
+	  }
+	  g_dir_close (dir);
+	}
+
+	return regs;
+}
+
+static void
+stop_plugins (GHashTable *regs, Thumbnailer *thumbnailer)
+{
+	GHashTableIter iter;
+	gpointer key, value;
+
+	g_hash_table_iter_init (&iter, regs);
+
+	while (g_hash_table_iter_next (&iter, &key, &value))  {
+		thumbnailer_unregister_plugin (thumbnailer, value);
+		hildon_thumbnail_plugin_do_stop (value);
+	}
+}
+
+
+static void
+on_plugin_changed (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, gpointer user_data)
+{
+	Thumbnailer *thumbnailer = user_data;
+	GModule *module = NULL;
+	gchar *path = g_file_get_path (other_file);
+
+	if (path) {
+		switch (event_type)  {
+			case G_FILE_MONITOR_EVENT_DELETED: {
+				GModule *module = g_hash_table_lookup (registrations, path);
+				if (module) {
+					thumbnailer_unregister_plugin (thumbnailer, module);
+					hildon_thumbnail_plugin_do_stop (module);
+				}
+			}
+			case G_FILE_MONITOR_EVENT_CREATED: {
+				GModule *module = hildon_thumbnail_plugin_load (path);
+				gboolean cropping = FALSE;
+
+				if (module) {
+					GError *error = NULL;
+
+					hildon_thumbnail_plugin_do_init (module, &cropping,
+							 (register_func) thumbnailer_register_plugin,
+							 thumbnailer,
+							 &error);
+					if (error) {
+						g_warning ("Can't load plugin [%s]: %s\n", path, 
+							   error->message);
+						g_error_free (error);
+					} else
+						g_hash_table_replace (registrations, g_strdup (path),
+								      module);
+				}
+			}
+			break;
+			default:
+			break;
+		}
+	}
+
+	g_free (path);
+}
+
+
 int 
 main (int argc, char **argv) 
 {
 	DBusGConnection *connection;
-	GModule *module;
 	GError *error = NULL;
 	
 	g_type_init ();
@@ -77,12 +185,8 @@
 		Manager *manager;
 		Thumbnailer *thumbnailer;
 		DBusGProxy *manager_proxy;
-		gboolean cropping;
-		GDir *dir;
-		const gchar *plugin;
-		GHashTable *registrations;
-		GHashTableIter iter;
-		gpointer key, value;
+		GFile *file;
+		GFileMonitor *monitor;
 
 		manager_do_init (connection, &manager, &error);
 		thumbnailer_do_init (connection, manager, &thumbnailer, &error);
@@ -92,32 +196,13 @@
 					   MANAGER_PATH,
 					   MANAGER_INTERFACE);
 
-		registrations = g_hash_table_new_full (g_str_hash, g_str_equal,
-						       (GDestroyNotify) g_free, 
-						       (GDestroyNotify) NULL);
+		registrations = init_plugins (connection, thumbnailer);
 
-		/* TODO: Monitor this directory for plugin removals and additions */
-		
-		dir = g_dir_open (PLUGINS_DIR, 0, &error);
+		file = g_file_new_for_path (PLUGINS_DIR);
+		monitor =  g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
+		g_signal_connect (G_OBJECT (monitor), "changed", 
+				  G_CALLBACK (on_plugin_changed), thumbnailer);
 
-		if (dir) {
-		  while ((plugin = g_dir_read_name (dir)) != NULL) {
-
-			if (!g_str_has_suffix (plugin, "." G_MODULE_SUFFIX)) {
-				continue;
-			}
-			
-			module = hildon_thumbnail_plugin_load (plugin);
-			hildon_thumbnail_plugin_do_init (module, &cropping,
-							 (register_func) thumbnailer_register_plugin,
-							 thumbnailer,
-							 &error);
-			g_hash_table_replace (registrations, g_strdup (plugin),
-					      module);
-		  }
-		  g_dir_close (dir);
-		}
-
 		main_loop = g_main_loop_new (NULL, FALSE);
 
 		g_timeout_add_seconds (600, 
@@ -126,12 +211,10 @@
 
 		g_main_loop_run (main_loop);
 
-		g_hash_table_iter_init (&iter, registrations);
+		g_object_unref (monitor);
+		g_object_unref (file);
 
-		while (g_hash_table_iter_next (&iter, &key, &value))  {
-			thumbnailer_unregister_plugin (thumbnailer, value);
-			hildon_thumbnail_plugin_do_stop (value);
-		}
+		stop_plugins (registrations, thumbnailer);
 
 		g_hash_table_unref (registrations);
 

Modified: projects/haf/trunk/hildon-thumbnail/daemon/manager.c
===================================================================
--- projects/haf/trunk/hildon-thumbnail/daemon/manager.c	2008-09-24 13:48:05 UTC (rev 16212)
+++ projects/haf/trunk/hildon-thumbnail/daemon/manager.c	2008-09-24 14:42:35 UTC (rev 16213)
@@ -32,6 +32,9 @@
 #include "dbus-utils.h"
 #include "thumbnailer.h"
 
+static GFile *homedir, *thumbdir;
+static GFileMonitor *homemon, *thumbmon;
+
 #define MANAGER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TYPE_MANAGER, ManagerPrivate))
 
 G_DEFINE_TYPE (Manager, manager, G_TYPE_OBJECT)
@@ -325,7 +328,7 @@
 			gchar *path = g_file_get_path (file);
 			gboolean override = (strcmp (THUMBNAILERS_DIR, path) == 0);
 
-			/* We override when it's the one in the user's homedir*/
+			/* We override when it's the dir in the user's homedir*/
 			manager_check_dir (MANAGER (user_data), path, override);
 
 			g_free (path);
@@ -341,7 +344,6 @@
 {
 	ManagerPrivate *priv = MANAGER_GET_PRIVATE (object);
 	GFileMonitor *monitor;
-	GFile *file;
 
 	gchar *home_thumbnlrs = g_build_filename (g_get_user_data_dir (), 
 		"thumbnailers", NULL);
@@ -353,25 +355,19 @@
 	manager_check_dir (object, home_thumbnlrs, TRUE);
 
 	/* Monitor the dir for changes */
-	file = g_file_new_for_path (home_thumbnlrs);
-	monitor =  g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
-	g_signal_connect (G_OBJECT (monitor), "changed", 
+	homedir = g_file_new_for_path (home_thumbnlrs);
+	homemon =  g_file_monitor_directory (homedir, G_FILE_MONITOR_NONE, NULL, NULL);
+	g_signal_connect (G_OBJECT (homemon), "changed", 
 			  G_CALLBACK (on_dir_changed), NULL);
 
-	// g_object_unref (file)
-	// g_object_unref (monitor)
-
 	/* Monitor the dir for changes */
-	file = g_file_new_for_path (THUMBNAILERS_DIR);
-	monitor =  g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
-	g_signal_connect (G_OBJECT (monitor), "changed", 
+	thumbdir = g_file_new_for_path (THUMBNAILERS_DIR);
+	thumbmon =  g_file_monitor_directory (thumbdir, G_FILE_MONITOR_NONE, NULL, NULL);
+	g_signal_connect (G_OBJECT (thumbmon), "changed", 
 			  G_CALLBACK (on_dir_changed), NULL);
 
 	g_mutex_unlock (priv->mutex);
 
-	// g_object_unref (file)
-	// g_object_unref (monitor)
-
 	g_free (home_thumbnlrs);
 }
 
@@ -600,6 +596,10 @@
 void 
 manager_do_stop (void)
 {
+	g_object_unref (homemon);
+	g_object_unref (thumbmon);
+	g_object_unref (homedir);
+	g_object_unref (thumbdir);
 }
 
 void 

Modified: projects/haf/trunk/hildon-thumbnail/daemon/plugin-runner.c
===================================================================
--- projects/haf/trunk/hildon-thumbnail/daemon/plugin-runner.c	2008-09-24 13:48:05 UTC (rev 16212)
+++ projects/haf/trunk/hildon-thumbnail/daemon/plugin-runner.c	2008-09-24 14:42:35 UTC (rev 16213)
@@ -67,11 +67,38 @@
 
 #define plugin_runner_create daemon_create
 
+
+static gboolean do_shut_down_next_time = TRUE;
+
+static void
+keep_alive (void) 
+{
+	do_shut_down_next_time = FALSE;
+}
+
+static gboolean
+shut_down_after_timeout (gpointer user_data)
+{
+	GMainLoop *main_loop =  user_data;
+	gboolean shut = FALSE;
+
+	if (do_shut_down_next_time) {
+		g_main_loop_quit (main_loop);
+		shut = TRUE;
+	} else
+		do_shut_down_next_time = TRUE;
+
+	return shut;
+}
+
 void 
 daemon_create (Daemon *object, GStrv uris, DBusGMethodInvocation *context)
 {
 	DaemonPrivate *priv = DAEMON_GET_PRIVATE (object);
 	GError *error = NULL;
+
+	keep_alive ();
+
 	hildon_thumbnail_plugin_do_create (priv->module, uris, &error);
 	if (error) {
 		dbus_g_method_return_error (context, error);
@@ -230,6 +257,7 @@
 static gboolean dynamic_register = FALSE;
 static gchar *bus_name;
 static gchar *bus_path;
+static gint timeout = 600;
 
 static GOptionEntry entries_daemon[] = {
 	{ "module-name", 'm', G_OPTION_FLAG_REVERSE|G_OPTION_FLAG_OPTIONAL_ARG, 
@@ -240,6 +268,10 @@
 	  G_OPTION_ARG_STRING, &bus_name, 
 	  "Busname to use (eg. com.company.Thumbnailer) ", 
 	  NULL },
+	{ "timeout", 't', 0, 
+	  G_OPTION_ARG_INT, &timeout, 
+	  "Timeout before the specialized thumbnailer dies (use -1 for inlimited)", 
+	  NULL },
 	{ "bus-path", 'p', 0, 
 	  G_OPTION_ARG_STRING, &bus_path, 
 	  "Buspath to use (eg. /com/company/Thumbnailer) ", 
@@ -316,6 +348,11 @@
 
 	daemon_start (DAEMON (object), dynamic_register);
 
+	if (timeout > -1)
+		g_timeout_add_seconds (timeout, 
+				       shut_down_after_timeout,
+				       main_loop);
+
 	main_loop = g_main_loop_new (NULL, FALSE);
 	g_main_loop_run (main_loop);
 

Modified: projects/haf/trunk/hildon-thumbnail/daemon/plugins/exec-plugin.c
===================================================================
--- projects/haf/trunk/hildon-thumbnail/daemon/plugins/exec-plugin.c	2008-09-24 13:48:05 UTC (rev 16212)
+++ projects/haf/trunk/hildon-thumbnail/daemon/plugins/exec-plugin.c	2008-09-24 14:42:35 UTC (rev 16213)
@@ -293,15 +293,17 @@
 
 		g_free (r_exec);
 
-// TODO
-//		if (on_error) {
-//			if (!errors)
-//				errors = g_string_new ("");
-//			g_string_append_printf (errors, "error msg")
-//		}
+		nerror_handler:
 
 
-		nerror_handler:
+		if (nerror) {
+			if (!errors)
+				errors = g_string_new ("");
+			g_string_append_printf (errors, "[`%s': %s] ", 
+								    uri, nerror->message);
+			g_error_free (nerror);
+			nerror = NULL;
+		}
 
 		if (file)
 			g_object_unref (file);

Modified: projects/haf/trunk/hildon-thumbnail/daemon/plugins/gdkpixbuf-plugin.c
===================================================================
--- projects/haf/trunk/hildon-thumbnail/daemon/plugins/gdkpixbuf-plugin.c	2008-09-24 13:48:05 UTC (rev 16212)
+++ projects/haf/trunk/hildon-thumbnail/daemon/plugins/gdkpixbuf-plugin.c	2008-09-24 14:42:35 UTC (rev 16213)
@@ -333,8 +333,9 @@
 			if (!errors)
 				errors = g_string_new ("");
 			g_string_append_printf (errors, "[`%s': %s] ", 
-						uri,
-						nerror->message);
+								    uri, nerror->message);
+			g_error_free (nerror);
+			nerror = NULL;
 		}
 
 		if (stream)

Modified: projects/haf/trunk/hildon-thumbnail/daemon/plugins/gstreamer-video-plugin.c
===================================================================
--- projects/haf/trunk/hildon-thumbnail/daemon/plugins/gstreamer-video-plugin.c	2008-09-24 13:48:05 UTC (rev 16212)
+++ projects/haf/trunk/hildon-thumbnail/daemon/plugins/gstreamer-video-plugin.c	2008-09-24 14:42:35 UTC (rev 16213)
@@ -460,8 +460,9 @@
 			if (!errors)
 				errors = g_string_new ("");
 			g_string_append_printf (errors, "[`%s': %s] ", 
-						uris[i],
-						nerror->message);
+						uris[i], nerror->message);
+			g_error_free (nerror);
+			nerror = NULL;
 		}
 
 		g_free (large);

Modified: projects/haf/trunk/hildon-thumbnail/daemon/thumbnailer.c
===================================================================
--- projects/haf/trunk/hildon-thumbnail/daemon/thumbnailer.c	2008-09-24 13:48:05 UTC (rev 16212)
+++ projects/haf/trunk/hildon-thumbnail/daemon/thumbnailer.c	2008-09-24 14:42:35 UTC (rev 16213)
@@ -39,6 +39,9 @@
 #include "dbus-utils.h"
 #include "utils.h"
 
+#define THUMB_ERROR_DOMAIN	"HildonThumbnailer"
+#define THUMB_ERROR		g_quark_from_static_string (THUMB_ERROR_DOMAIN)
+
 #define THUMBNAILER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TYPE_THUMBNAILER, ThumbnailerPrivate))
 
 G_DEFINE_TYPE (Thumbnailer, thumbnailer, G_TYPE_OBJECT)
@@ -49,7 +52,8 @@
 typedef struct {
 	Manager *manager;
 	GHashTable *plugins;
-	GThreadPool *pool;
+	GThreadPool *large_pool;
+	GThreadPool *normal_pool;
 	GMutex *mutex;
 	GList *tasks;
 } ThumbnailerPrivate;
@@ -74,11 +78,12 @@
 {
 	ThumbnailerPrivate *priv = THUMBNAILER_GET_PRIVATE (object);
 
+	g_mutex_lock (priv->mutex);
 	g_hash_table_insert (priv->plugins, 
 			     g_strdup (mime_type), 
 			     plugin);
 	manager_i_have (priv->manager, mime_type);
-
+	g_mutex_unlock (priv->mutex);
 }
 
 static gboolean 
@@ -94,9 +99,11 @@
 {
 	ThumbnailerPrivate *priv = THUMBNAILER_GET_PRIVATE (object);
 
+	g_mutex_lock (priv->mutex);
 	g_hash_table_foreach_remove (priv->plugins, 
 				     do_delete_or_not, 
 				     plugin);
+	g_mutex_unlock (priv->mutex);
 }
 
 
@@ -140,6 +147,7 @@
 	Thumbnailer *object;
 	GStrv urls;
 	guint num;
+	gboolean poolmax;
 	gboolean unqueued;
 } WorkTask;
 
@@ -189,11 +197,16 @@
 	task->num = ++num;
 	task->object = g_object_ref (object);
 	task->urls = g_strdupv (urls);
+	task->poolmax = FALSE;
 
+
 	g_mutex_lock (priv->mutex);
 	g_list_foreach (priv->tasks, (GFunc) mark_unqueued, (gpointer) handle_to_unqueue);
 	priv->tasks = g_list_prepend (priv->tasks, task);
-	g_thread_pool_push (priv->pool, task, NULL);
+	if (g_strv_length (urls) > 10)
+		g_thread_pool_push (priv->large_pool, task, NULL);
+	else
+		g_thread_pool_push (priv->normal_pool, task, NULL);
 	g_mutex_unlock (priv->mutex);
 
 	dbus_g_method_return (context, num);
@@ -342,7 +355,12 @@
 		 * plugin have a go at it */
 
 		} else {
-			GModule *module = g_hash_table_lookup (priv->plugins, key);
+			GModule *module;
+
+			g_mutex_lock (priv->mutex);
+			module = g_hash_table_lookup (priv->plugins, key);
+			g_mutex_unlock (priv->mutex);
+
 			if (module) {
 				GError *error = NULL;
 
@@ -393,39 +411,219 @@
 void
 thumbnailer_move (Thumbnailer *object, GStrv from_urls, GStrv to_urls, DBusGMethodInvocation *context)
 {
+	guint i = 0;
+	GString *errors = NULL;
+	GError *error = NULL;
+
 	dbus_async_return_if_fail (from_urls != NULL, context);
 	dbus_async_return_if_fail (to_urls != NULL, context);
 
 	keep_alive ();
 
-	// TODO
-	
-	dbus_g_method_return (context);
+	while (from_urls[i] != NULL && to_urls[i] != NULL) {
+
+		const gchar *from_uri = from_urls[i];
+		const gchar *to_uri = to_urls[i];
+		GError *nerror = NULL;
+		gchar *from_normal = NULL, 
+		      *from_large = NULL, 
+		      *from_cropped = NULL;
+		gchar *to_normal = NULL, 
+		      *to_large = NULL,
+		      *to_cropped = NULL;
+
+		hildon_thumbnail_util_get_thumb_paths (from_uri, &from_large, 
+						       &from_normal, 
+						       &from_cropped, &error);
+
+		if (nerror)
+			goto nerror_handler;
+
+		hildon_thumbnail_util_get_thumb_paths (from_uri, &to_large, 
+						       &to_normal, 
+						       &to_cropped, &error);
+
+		if (nerror)
+			goto nerror_handler;
+
+
+		g_rename (from_large, to_large);
+		g_rename (from_normal, to_normal);
+		g_rename (from_cropped, to_cropped);
+
+		nerror_handler:
+
+		if (nerror) {
+			if (!errors)
+				errors = g_string_new ("");
+			g_string_append_printf (errors, "[`%s': %s] ", 
+						from_urls[i],
+						nerror->message);
+			g_error_free (nerror);
+			nerror = NULL;
+		}
+
+		g_free (from_normal);
+		g_free (from_large);
+		g_free (from_cropped);
+		g_free (to_normal);
+		g_free (to_large);
+		g_free (to_cropped);
+
+		i++;
+	}
+
+	if (errors) {
+		g_set_error (&error, THUMB_ERROR, 0,
+			     errors->str);
+		g_string_free (errors, TRUE);
+		dbus_g_method_return_error (context, error);
+		g_error_free (error);
+	} else
+		dbus_g_method_return (context);
 }
 
 void
 thumbnailer_copy (Thumbnailer *object, GStrv from_urls, GStrv to_urls, DBusGMethodInvocation *context)
 {
+	guint i = 0;
+	GString *errors = NULL;
+	GError *error = NULL;
+
 	dbus_async_return_if_fail (from_urls != NULL, context);
 	dbus_async_return_if_fail (to_urls != NULL, context);
 
 	keep_alive ();
 
-	// TODO
-	
-	dbus_g_method_return (context);
+	while (from_urls[i] != NULL && to_urls[i] != NULL) {
+
+		const gchar *from_uri = from_urls[i];
+		const gchar *to_uri = to_urls[i];
+		GError *nerror = NULL;
+		gchar *from_s[3] = { NULL, NULL, NULL };
+		gchar *to_s[3] = { NULL, NULL, NULL };
+		guint n;
+
+		hildon_thumbnail_util_get_thumb_paths (from_uri, &from_s[0], 
+						       &from_s[1], 
+						       &from_s[2], &error);
+
+		if (nerror)
+			goto nerror_handler;
+
+		hildon_thumbnail_util_get_thumb_paths (from_uri, &to_s[0], 
+						       &to_s[1], 
+						       &to_s[2], &error);
+
+		for (n = 0; n<3; n++) {
+			GFile *from, *to;
+
+			if (!from_s[n] || !to_s[n])
+				continue;
+			
+			from = g_file_new_for_path (from_s[n]);
+			to = g_file_new_for_path (to_s[n]);
+
+			/* We indeed ignore copy errors here */
+
+			g_file_copy (from, to, 
+				     G_FILE_COPY_NONE|G_FILE_COPY_OVERWRITE|G_FILE_COPY_ALL_METADATA,
+				     NULL, NULL, NULL,
+				     NULL);
+
+			g_object_unref (from);
+			g_object_unref (to);
+
+		}
+
+		nerror_handler:
+
+		if (nerror) {
+			if (!errors)
+				errors = g_string_new ("");
+			g_string_append_printf (errors, "[`%s': %s] ", 
+						from_urls[i],
+						nerror->message);
+			g_error_free (nerror);
+			nerror = NULL;
+		}
+
+		for (n = 0; n<3; n++) {
+			/* These can be NULL, but that's ok for g_free */
+			g_free (from_s[n]);
+			g_free (to_s[n]);
+		}
+
+		i++;
+	}
+
+	if (errors) {
+		g_set_error (&error, THUMB_ERROR, 0,
+			     errors->str);
+		g_string_free (errors, TRUE);
+		dbus_g_method_return_error (context, error);
+		g_error_free (error);
+	} else
+		dbus_g_method_return (context);
 }
 
 void
 thumbnailer_delete (Thumbnailer *object, GStrv urls, DBusGMethodInvocation *context)
 {
+	guint i = 0;
+	GString *errors = NULL;
+	GError *error = NULL;
+
 	dbus_async_return_if_fail (urls != NULL, context);
 
 	keep_alive ();
 
-	// TODO
-	
-	dbus_g_method_return (context);
+	while (urls[i] != NULL) {
+
+		const gchar *uri = urls[i];
+		GError *nerror = NULL;
+		gchar *normal = NULL, 
+		      *large = NULL, 
+		      *cropped = NULL;
+
+		hildon_thumbnail_util_get_thumb_paths (uri, &large, 
+						       &normal, 
+						       &cropped, &error);
+
+		if (nerror)
+			goto nerror_handler;
+
+		g_unlink (large);
+		g_unlink (normal);
+		g_unlink (cropped);
+
+		nerror_handler:
+
+		if (nerror) {
+			if (!errors)
+				errors = g_string_new ("");
+			g_string_append_printf (errors, "[`%s': %s] ", 
+						urls[i],
+						nerror->message);
+			g_error_free (nerror);
+			nerror = NULL;
+		}
+
+		g_free (normal);
+		g_free (large);
+		g_free (cropped);
+
+		i++;
+	}
+
+	if (errors) {
+		g_set_error (&error, THUMB_ERROR, 0,
+			     errors->str);
+		g_string_free (errors, TRUE);
+		dbus_g_method_return_error (context, error);
+		g_error_free (error);
+	} else
+		dbus_g_method_return (context);
 }
 
 static void
@@ -433,7 +631,8 @@
 {
 	ThumbnailerPrivate *priv = THUMBNAILER_GET_PRIVATE (object);
 
-	g_thread_pool_free (priv->pool, TRUE, TRUE);
+	g_thread_pool_free (priv->normal_pool, TRUE, TRUE);
+	g_thread_pool_free (priv->large_pool, TRUE, TRUE);
 
 	g_object_unref (priv->manager);
 	g_hash_table_unref (priv->plugins);
@@ -567,11 +766,14 @@
 
 	/* We could increase the amount of threads to add some parallelism */
 
-	priv->pool = g_thread_pool_new ((GFunc) do_the_work,NULL,1,TRUE,NULL);
+	priv->large_pool = g_thread_pool_new ((GFunc) do_the_work,NULL,1,TRUE,NULL);
+	priv->normal_pool = g_thread_pool_new ((GFunc) do_the_work,NULL,1,TRUE,NULL);
 
 	/* This sort function makes the pool a LIFO */
 
-	g_thread_pool_set_sort_function (priv->pool, pool_sort_compare, NULL);
+	g_thread_pool_set_sort_function (priv->large_pool, pool_sort_compare, NULL);
+	g_thread_pool_set_sort_function (priv->normal_pool, pool_sort_compare, NULL);
+
 }
 
 

Modified: projects/haf/trunk/hildon-thumbnail/debian/changelog
===================================================================
--- projects/haf/trunk/hildon-thumbnail/debian/changelog	2008-09-24 13:48:05 UTC (rev 16212)
+++ projects/haf/trunk/hildon-thumbnail/debian/changelog	2008-09-24 14:42:35 UTC (rev 16213)
@@ -1,3 +1,15 @@
+hildon-thumbnail (3.0.1~unreleased) unstable; urgency=low
+
+  [ Philip Van Hoof ]
+  * Completed API in the daemon.
+  * Monitor plugin directory.
+  * Avoid D-Bus roundtrip for existing thumbnails when using the
+    HildonThumbnailFactory API.
+  * Handle large requests in a separate thread so that small
+    requests are not starved.
+
+ -- Marius Vollmer <marius.vollmer at nokia.com>  Wed, 24 Sep 2008 17:35:38 +0300
+
 hildon-thumbnail (3.0.0) unstable; urgency=low
 
   [ Philip Van Hoof ]

Modified: projects/haf/trunk/hildon-thumbnail/thumbs/hildon-thumbnail-factory.c
===================================================================
--- projects/haf/trunk/hildon-thumbnail/thumbs/hildon-thumbnail-factory.c	2008-09-24 13:48:05 UTC (rev 16212)
+++ projects/haf/trunk/hildon-thumbnail/thumbs/hildon-thumbnail-factory.c	2008-09-24 14:42:35 UTC (rev 16213)
@@ -101,26 +101,16 @@
 }
 
 static void
-on_task_finished (DBusGProxy *proxy,
-		  guint       handle,
-		  gpointer    user_data)
+create_pixbuf_and_callback (ThumbsItem *item, gchar *large, gchar *normal, gchar *cropped)
 {
-	gchar *key = g_strdup_printf ("%d", handle);
-	ThumbsItem *item = g_hash_table_lookup (tasks, key);
-
-	if (item) {
+		GFile *filei = NULL;
+		GInputStream *stream = NULL;
 		GdkPixbuf *pixbuf = NULL;
-		gchar *large = NULL, *normal = NULL, *cropped = NULL;
+		gchar *path;
 		GError *error = NULL;
-		gchar *path = NULL;
-		GFile *filei = NULL;
-		GInputStream *stream = NULL;
 
-		hildon_thumbnail_util_get_thumb_paths (item->uri, &large, &normal, &cropped, &error);
+		/* Determine the exact type of thumbnail being requested */
 
-		if (error)
-			goto error_handler;
-
 		if (item->flags & HILDON_THUMBNAIL_FLAG_CROP) {
 			path = g_strdup (cropped);
 		} else if (item->width > 128) {
@@ -129,20 +119,26 @@
 			path = g_strdup (normal);
 		}
 
+		/* Open the original thumbnail as a stream */
 		filei = g_file_new_for_path (path);
 		stream = G_INPUT_STREAM (g_file_read (filei, NULL, &error));
+		g_free (path);
 
 		if (error)
 			goto error_handler;
 
+		/* Read the stream as a pixbuf at the requested exact scale */
 		pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream,
 			item->width, item->height, TRUE, 
 			NULL, &error);
 
 		error_handler:
 
+		/* Callback user function, passing the pixbuf and error */
+
 		item->callback (item, item->user_data, pixbuf, error);
 
+		/* Cleanup */
 		if (filei)
 			g_object_unref (filei);
 
@@ -156,11 +152,40 @@
 
 		if (pixbuf)
 			gdk_pixbuf_unref (pixbuf);
+}
 
+static void
+on_task_finished (DBusGProxy *proxy,
+		  guint       handle,
+		  gpointer    user_data)
+{
+	gchar *key = g_strdup_printf ("%d", handle);
+	ThumbsItem *item = g_hash_table_lookup (tasks, key);
+
+	if (item) {
+		gchar *large = NULL, *normal = NULL, *cropped = NULL;
+		GError *error = NULL;
+
+		/* Get the large small and cropped path for the original
+		 * URI */
+		
+		hildon_thumbnail_util_get_thumb_paths (item->uri, &large, 
+											   &normal, &cropped, 
+											   &error);
+
+		if (error)
+			goto error_handler;
+
+		create_pixbuf_and_callback (item, large, normal, cropped);
+
+		error_handler:
+
 		g_free (cropped);
 		g_free (normal);
 		g_free (large);
 
+		/* Remove the key from the hash, which means that we declare it 
+		 * handled. */
 		g_hash_table_remove (tasks, key);
 	}
 
@@ -185,10 +210,10 @@
 			GError *error = NULL;
 			guint64 mtime, size;
 
-			file_path = g_build_filename(path, file, NULL);
+			file_path = g_build_filename (path, file, NULL);
 
 			if(file[0] == '.' || !g_file_test(file_path, G_FILE_TEST_IS_REGULAR)) {
-				g_free(file_path);
+				g_free (file_path);
 				continue;
 			}
 
@@ -202,6 +227,7 @@
 			if (error) {
 				g_error_free (error);
 				g_object_unref (filei);
+				g_free (file_path);
 				continue;
 			}
 
@@ -226,15 +252,15 @@
 static void
 cache_file_free(ThumbsCacheFile *item)
 {
-	g_free(item->file);
-	g_free(item);
+	g_free (item->file);
+	g_free (item);
 }
 
 static gint 
 cache_file_compare(gconstpointer a, gconstpointer b)
 {
 	ThumbsCacheFile *f1 = *(ThumbsCacheFile**)a,
-			*f2 = *(ThumbsCacheFile**)b;
+			        *f2 = *(ThumbsCacheFile**)b;
 
 	/* Sort in descending order */
 	if(f2->mtime == f1->mtime) {
@@ -251,10 +277,8 @@
 void 
 hildon_thumbnail_factory_clean_cache(gint max_size, time_t min_mtime)
 {
-
 	GPtrArray *files;
 	int i, size = 0;
-	gboolean deleting = FALSE;
 	gchar *large_dir = g_build_filename (g_get_home_dir (), ".thumbnails", "large", NULL);
 	gchar *normal_dir = g_build_filename (g_get_home_dir (), ".thumbnails", "normal", NULL);
 	gchar *cropped_dir = g_build_filename (g_get_home_dir (), ".thumbnails", "cropped", NULL);
@@ -264,30 +288,25 @@
 
 	files = g_ptr_array_new();
 
-	read_cache_dir(fail_dir, files);
-	read_cache_dir(large_dir, files);
-	read_cache_dir(normal_dir, files);
-	read_cache_dir(cropped_dir, files);
+	read_cache_dir (fail_dir, files);
+	read_cache_dir (large_dir, files);
+	read_cache_dir (normal_dir, files);
+	read_cache_dir (cropped_dir, files);
 
-	g_ptr_array_sort(files, cache_file_compare);
+	g_ptr_array_sort (files, cache_file_compare);
 
 	for(i = 0; i < files->len; i++) {
-		ThumbsCacheFile *item = g_ptr_array_index(files, i);
+		ThumbsCacheFile *item = g_ptr_array_index (files, i);
 
 		size += item->size;
-
-		if((max_size >= 0 && size >= max_size) || item->mtime < min_mtime) {
-			deleting = TRUE;
+		if ((max_size >= 0 && size >= max_size) || item->mtime < min_mtime) {
+			unlink (item->file);
 		}
-
-		if(deleting) {
-			unlink(item->file);
-		}
 	}
 
-	g_ptr_array_foreach(files, (GFunc)cache_file_free, NULL);
+	g_ptr_array_foreach (files, (GFunc)cache_file_free, NULL);
+	g_ptr_array_free (files, TRUE);
 
-	g_ptr_array_free(files, TRUE);
 	g_free (fail_dir);
 	g_free (normal_dir);
 	g_free (large_dir);
@@ -300,9 +319,37 @@
 	ThumbsItem *item = userdata;
 	gchar *key = g_strdup_printf ("%d", OUT_handle);
 	item->handle_id = OUT_handle;
+
+	/* Register the item as being handled */
 	g_hash_table_replace (tasks, key, item);
 }
 
+typedef struct {
+	gchar *large, *normal, *cropped;
+	ThumbsItem *item;
+} ThumbsItemAndPaths;
+
+static void
+free_thumbsitem_and_paths (ThumbsItemAndPaths *info) 
+{
+	g_free (info->large);
+	g_free (info->normal);
+	g_free (info->cropped);
+	thumb_item_free (info->item);
+	g_slice_free (ThumbsItemAndPaths, info);
+}
+
+static gboolean
+have_all_cb (gpointer user_data)
+{
+	ThumbsItemAndPaths *info = user_data;
+	ThumbsItem *item = info->item;
+
+	create_pixbuf_and_callback (item, info->large, info->normal, info->cropped);
+
+	return FALSE;
+}
+
 HildonThumbnailFactoryHandle hildon_thumbnail_factory_load_custom(
 				const gchar *uri, const gchar *mime_type,
 				guint width, guint height,
@@ -310,35 +357,43 @@
 				gpointer user_data, 
 				HildonThumbnailFlags flags, ...)
 {
+	gchar *large, *normal, *cropped;
+	GError *error = NULL;
 	ThumbsItem *item;
-	GStrv uris = (GStrv) g_malloc0 (sizeof (gchar *) * 2);
+	GStrv uris;
+	gboolean have_all = FALSE;
 
 	g_return_val_if_fail(uri != NULL && mime_type != NULL && callback != NULL,
 			     NULL);
 
-	init ();
+	hildon_thumbnail_util_get_thumb_paths (uri, &large, &normal, 
+						       &cropped, &error);
 
 	if (flags & HILDON_THUMBNAIL_FLAG_RECREATE) {
-		gchar *large, *normal, *cropped;
-		GError *error = NULL;
-
-		hildon_thumbnail_util_get_thumb_paths (uri, &large, &normal, 
-						       &cropped, &error);
-
 		if (!error) {
 			g_unlink (large);
 			g_unlink (normal);
 			g_unlink (cropped);
-		} else
-			g_error_free (error);
-
-		g_free (large);
-		g_free (normal);
-		g_free (cropped);
+		}
+	} else {
+		gchar *path;
+		if (item->flags & HILDON_THUMBNAIL_FLAG_CROP) {
+			path = cropped;
+		} else if (item->width > 128) {
+			path = large;
+		} else {
+			path = normal;
+		}
+		have_all = g_file_test (path, G_FILE_TEST_EXISTS);
 	}
 
-	item = g_new(ThumbsItem, 1);
+	if (error)
+		g_error_free (error);
+	else
+		have_all = FALSE;
 
+	item = g_new (ThumbsItem, 1);
+
 	item->uri = g_strdup(uri);
 	item->mime_type = g_strdup(mime_type);
 	item->width = width;
@@ -349,13 +404,35 @@
 	item->canceled = FALSE;
 	item->handle_id = 0;
 
-	uris[0] = g_strdup (uri);
+	if (have_all) {
+		ThumbsItemAndPaths *info = g_slice_new (ThumbsItemAndPaths);
 
-	org_freedesktop_thumbnailer_Generic_queue_async (proxy, (const char **) uris, 0, 
-							 on_got_handle, item);
+		info->item = item;
+		info->normal = g_strdup (normal);
+		info->large = g_strdup (large);
+		info->cropped = g_strdup (cropped);
 
-	g_strfreev (uris);
+		g_idle_add_full (G_PRIORITY_DEFAULT, have_all_cb, info,
+						 (GDestroyNotify) free_thumbsitem_and_paths);
 
+		return;
+	}
+
+	g_free (large);
+	g_free (normal);
+	g_free (cropped);
+
+	if (!have_all) {
+
+		init ();
+		uris = (GStrv) g_malloc0 (sizeof (gchar *) * 2);
+		uris[0] = g_strdup (uri);
+		org_freedesktop_thumbnailer_Generic_queue_async (proxy, (const char **) uris, 0, 
+								 on_got_handle, item);
+
+		g_strfreev (uris);
+	}
+
 	return THUMBS_HANDLE (item);
 }
 
@@ -374,6 +451,8 @@
 {
 	ThumbsItem *item = userdata;
 	gchar *key = g_strdup_printf ("%d", item->handle_id);
+
+	/* Unregister the item */
 	g_hash_table_remove (tasks, key);
 	g_free (key);
 }
@@ -387,6 +466,7 @@
 	if (item->handle_id == 0)
 		return;
 
+	/* We don't do real canceling, we just do unqueing */
 	org_freedesktop_thumbnailer_Generic_unqueue_async (proxy, item->handle_id, 
 							   on_cancelled, item);
 


More information about the maemo-commits mailing list