gnome-desktop r5252 - in trunk: . libgnome-desktop libgnome-desktop/libgnome libgnome-desktop/libgnomeui



Author: alexl
Date: Tue Oct  7 19:12:18 2008
New Revision: 5252
URL: http://svn.gnome.org/viewvc/gnome-desktop?rev=5252&view=rev

Log:
2008-10-07  Alexander Larsson  <alexl redhat com>

	Removes the dependency on libgnome* by removing some
	ancient code that uses it and pulling in some code from
	libgnome that we need internally and that other apps that
	don't want to require libgnome needs.
	
        * gnome-desktop-thumbnail.c: Added.
        * gnome-thumbnail-pixbuf-utils.c: Added.
        * libgnomeui/gnome-desktop-thumbnail.h: Added.
	Added a copy of gnome-thumbnail from libgnomeui, renamed
	to GnomeDesktopThumbnail.
	
        * gnome-desktop-utils.c: Added.
        * libgnome/gnome-desktop-utils.h: Added.
	Add gnome_desktop_prepend_terminal_to_vector (from libgnome).
	Used internally and by nautilus.
	
        * gnome-ditem-edit.c:
        * gnome-hint.c: 
	* test-hint.c:
	* test-ditem-edit.c:
        * libgnomeui/gnome-ditem-edit.h: Removed.
        * libgnomeui/gnome-hint.h: Removed.
	Remove gnome-ditem-edit and gnome-hint.
	
        * gnome-bg.c:
        * libgnomeui/gnome-bg.h:
	Use GnomeDesktopThumbnail instead of GnomeThumbnail
	
        * gnome-desktop-2.0.pc.in:
	Remove libgnomeui dependency
	
        * gnome-desktop-item.c:
        * libgnome/gnome-desktop-item.h:
	Don't use libgnome* stuff.
	If needed, instead use the new copies from gnome-desktop.
	This drops backwards compat for really old gnome1 and kde2 icons
	in desktop files...
	
        * test-ditem.c:
	Don't use gnome-program.

        * Makefile.am:
        * libgnome/Makefile.am:
        * libgnomeui/Makefile.am:
	Update for removed/added files

2008-10-07  Alexander Larsson  <alexl redhat com>

        * configure.in:
	Bump version to 2.25.1
	Remove dependencies on libgnome*
	


Added:
   trunk/libgnome-desktop/gnome-desktop-thumbnail.c
   trunk/libgnome-desktop/gnome-desktop-utils.c
   trunk/libgnome-desktop/gnome-thumbnail-pixbuf-utils.c
   trunk/libgnome-desktop/libgnome/gnome-desktop-utils.h
   trunk/libgnome-desktop/libgnomeui/gnome-desktop-thumbnail.h
Removed:
   trunk/libgnome-desktop/gnome-ditem-edit.c
   trunk/libgnome-desktop/gnome-hint.c
   trunk/libgnome-desktop/libgnomeui/gnome-ditem-edit.h
   trunk/libgnome-desktop/libgnomeui/gnome-hint.h
   trunk/libgnome-desktop/test-ditem-edit.c
   trunk/libgnome-desktop/test-hint.c
Modified:
   trunk/ChangeLog
   trunk/configure.in
   trunk/libgnome-desktop/ChangeLog
   trunk/libgnome-desktop/Makefile.am
   trunk/libgnome-desktop/gnome-bg.c
   trunk/libgnome-desktop/gnome-desktop-2.0.pc.in
   trunk/libgnome-desktop/gnome-desktop-item.c
   trunk/libgnome-desktop/libgnome/Makefile.am
   trunk/libgnome-desktop/libgnome/gnome-desktop-item.h
   trunk/libgnome-desktop/libgnomeui/Makefile.am
   trunk/libgnome-desktop/libgnomeui/gnome-bg.h
   trunk/libgnome-desktop/test-ditem.c

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Tue Oct  7 19:12:18 2008
@@ -1,4 +1,4 @@
-AC_INIT([gnome-desktop], [2.24.1],
+AC_INIT([gnome-desktop], [2.25.1],
         [http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-desktop])
 AC_CONFIG_SRCDIR([libgnome-desktop])
 
@@ -69,21 +69,17 @@
 dnl If you add a version number here, you *must* add an AC_SUBST line for
 dnl it too, or it will never make it into the spec file!
 
-LIBXML_REQUIRED=2.4.20
 GDK_PIXBUF_REQUIRED=2.4.0
 GTK_REQUIRED=2.11.3
 GLIB_REQUIRED=2.15.4
 GCONF_REQUIRED=2.0.0
-LIBGNOMEUI_REQUIRED=2.6.0
 STARTUP_NOTIFICATION_REQUIRED=0.5
 XRANDR_REQUIRED=1.2
 
-AC_SUBST(LIBXML_REQUIRED)
 AC_SUBST(GTK_REQUIRED)
 AC_SUBST(GLIB_REQUIRED)
 AC_SUBST(GDK_PIXBUF_REQUIRED)
 AC_SUBST(GCONF_REQUIRED)
-AC_SUBST(LIBGNOMEUI_REQUIRED)
 AC_SUBST(STARTUP_NOTIFICATION_REQUIRED)
 AC_SUBST(XRANDR_REQUIRED)
 
@@ -119,7 +115,7 @@
 
 dnl pkg-config dependency checks
 
-PKG_CHECK_MODULES(GNOME_DESKTOP, libxml-2.0 >= $LIBXML_REQUIRED gdk-pixbuf-2.0 >= $GDK_PIXBUF_REQUIRED gtk+-2.0 >= $GTK_REQUIRED glib-2.0 >= $GLIB_REQUIRED gio-2.0 >= $GLIB_REQUIRED libgnomeui-2.0 >= $LIBGNOMEUI_REQUIRED gconf-2.0 >= $GCONF_REQUIRED $STARTUP_NOTIFICATION_PACKAGE)
+PKG_CHECK_MODULES(GNOME_DESKTOP, gdk-pixbuf-2.0 >= $GDK_PIXBUF_REQUIRED gtk+-2.0 >= $GTK_REQUIRED glib-2.0 >= $GLIB_REQUIRED gio-2.0 >= $GLIB_REQUIRED gconf-2.0 >= $GCONF_REQUIRED $STARTUP_NOTIFICATION_PACKAGE)
 
 dnl for gnome-about
 AM_PATH_PYTHON

Modified: trunk/libgnome-desktop/Makefile.am
==============================================================================
--- trunk/libgnome-desktop/Makefile.am	(original)
+++ trunk/libgnome-desktop/Makefile.am	Tue Oct  7 19:12:18 2008
@@ -14,12 +14,13 @@
 
 lib_LTLIBRARIES = libgnome-desktop-2.la
 
-noinst_PROGRAMS = test-ditem test-hint test-ditem-edit
+noinst_PROGRAMS = test-ditem
 
 libgnome_desktop_2_la_SOURCES = \
 	gnome-desktop-item.c	\
-	gnome-ditem-edit.c	\
-	gnome-hint.c		\
+	gnome-desktop-utils.c	\
+	gnome-desktop-thumbnail.c \
+	gnome-thumbnail-pixbuf-utils.c \
 	gnome-bg.c		\
 	display-name.c		\
 	gnome-rr.c		\
@@ -44,21 +45,6 @@
 	$(XLIB_LIBS)			\
 	$(GNOME_DESKTOP_LIBS)
 
-test_hint_SOURCES = \
-        test-hint.c
-
-test_hint_LDADD = \
-        libgnome-desktop-2.la           \
-	$(XLIB_LIBS)			\
-        $(GNOME_DESKTOP_LIBS)
-
-test_ditem_edit_SOURCES = test-ditem-edit.c
-
-test_ditem_edit_LDADD =		\
-	libgnome-desktop-2.la	\
-	$(XLIB_LIBS)		\
-	$(GNOME_DESKTOP_LIBS)
-
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = gnome-desktop-2.0.pc
 

Modified: trunk/libgnome-desktop/gnome-bg.c
==============================================================================
--- trunk/libgnome-desktop/gnome-bg.c	(original)
+++ trunk/libgnome-desktop/gnome-bg.c	Tue Oct  7 19:12:18 2008
@@ -30,6 +30,7 @@
 #include <string.h>
 #include <math.h>
 #include <stdarg.h>
+#include <stdlib.h>
 
 #include <gio/gio.h>
 
@@ -38,7 +39,6 @@
 #include <X11/Xatom.h>
 
 #include <gconf/gconf-client.h>
-#include <libgnomeui/libgnomeui.h>
 
 #define GNOME_DESKTOP_USE_UNSTABLE_API
 #include <libgnomeui/gnome-bg.h>
@@ -151,7 +151,7 @@
 					double      alpha);
 
 /* Thumbnail utilities */
-static GdkPixbuf *create_thumbnail_for_filename (GnomeThumbnailFactory *factory,
+static GdkPixbuf *create_thumbnail_for_filename (GnomeDesktopThumbnailFactory *factory,
 						 const char            *filename);
 static gboolean   get_thumb_annotations (GdkPixbuf             *thumb,
 					 int                   *orig_width,
@@ -164,7 +164,7 @@
 					const char            *filename);
 static time_t     get_mtime            (const char            *filename);
 static GdkPixbuf *create_img_thumbnail (GnomeBG               *bg,
-					GnomeThumbnailFactory *factory,
+					GnomeDesktopThumbnailFactory *factory,
 					GdkScreen             *screen,
 					int                    dest_width,
 					int                    dest_height);
@@ -934,7 +934,7 @@
 
 gboolean
 gnome_bg_get_image_size (GnomeBG	       *bg,
-			 GnomeThumbnailFactory *factory,
+			 GnomeDesktopThumbnailFactory *factory,
 			 int		       *width,
 			 int		       *height)
 {
@@ -987,7 +987,7 @@
 
 GdkPixbuf *
 gnome_bg_create_thumbnail (GnomeBG               *bg,
-			   GnomeThumbnailFactory *factory,
+			   GnomeDesktopThumbnailFactory *factory,
 			   GdkScreen             *screen,
 			   int                    dest_width,
 			   int                    dest_height)
@@ -1315,7 +1315,7 @@
 }
 
 static GdkPixbuf *
-get_as_thumbnail (GnomeBG *bg, GnomeThumbnailFactory *factory, const char *filename)
+get_as_thumbnail (GnomeBG *bg, GnomeDesktopThumbnailFactory *factory, const char *filename)
 {
 	const FileCacheEntry *ent;
 	if ((ent = file_cache_lookup (bg, THUMBNAIL, filename))) {
@@ -1458,7 +1458,7 @@
 
 static GdkPixbuf *
 create_img_thumbnail (GnomeBG               *bg,
-		      GnomeThumbnailFactory *factory,
+		      GnomeDesktopThumbnailFactory *factory,
 		      GdkScreen             *screen,
 		      int                    dest_width,
 		      int                    dest_height)
@@ -2251,7 +2251,7 @@
 
 /* Thumbnail utilities */
 static GdkPixbuf *
-create_thumbnail_for_filename (GnomeThumbnailFactory *factory,
+create_thumbnail_for_filename (GnomeDesktopThumbnailFactory *factory,
 			       const char            *filename)
 {
 	char *thumb;
@@ -2266,7 +2266,7 @@
 	
 	uri = g_filename_to_uri (filename, NULL, NULL);
 	
-	thumb = gnome_thumbnail_factory_lookup (factory, uri, mtime);
+	thumb = gnome_desktop_thumbnail_factory_lookup (factory, uri, mtime);
 	
 	if (thumb) {
 		result = gdk_pixbuf_new_from_file (thumb, NULL);
@@ -2287,10 +2287,10 @@
 			
 			g_object_unref (orig);
 			
-			gnome_thumbnail_factory_save_thumbnail (factory, result, uri, mtime);
+			gnome_desktop_thumbnail_factory_save_thumbnail (factory, result, uri, mtime);
 		}
 		else {
-			gnome_thumbnail_factory_create_failed_thumbnail (factory, uri, mtime);
+			gnome_desktop_thumbnail_factory_create_failed_thumbnail (factory, uri, mtime);
 		}
 	}
 

Modified: trunk/libgnome-desktop/gnome-desktop-2.0.pc.in
==============================================================================
--- trunk/libgnome-desktop/gnome-desktop-2.0.pc.in	(original)
+++ trunk/libgnome-desktop/gnome-desktop-2.0.pc.in	Tue Oct  7 19:12:18 2008
@@ -5,7 +5,7 @@
 
 Name: gnome-desktop-2.0
 Description: Utility library for loading .desktop files
-Requires: gtk+-2.0 libgnomeui-2.0 @STARTUP_NOTIFICATION_PACKAGE@
+Requires: gtk+-2.0 @STARTUP_NOTIFICATION_PACKAGE@
 Version: @VERSION@
 Libs: -L${libdir} -lgnome-desktop-2
 Cflags: -I${includedir}/gnome-desktop-2.0

Modified: trunk/libgnome-desktop/gnome-desktop-item.c
==============================================================================
--- trunk/libgnome-desktop/gnome-desktop-item.c	(original)
+++ trunk/libgnome-desktop/gnome-desktop-item.c	Tue Oct  7 19:12:18 2008
@@ -39,11 +39,8 @@
 #include <time.h>
 #include <string.h>
 #include <glib/gi18n-lib.h>
-#include <libgnome/gnome-util.h>
-#include <libgnome/gnome-exec.h>
-#include <libgnome/gnome-url.h>
 #include <locale.h>
-#include <popt.h>
+#include <stdlib.h>
 
 #include <gio/gio.h>
 
@@ -57,8 +54,10 @@
 
 #define sure_string(s) ((s)!=NULL?(s):"")
 
+#define GNOME_DESKTOP_USE_UNSTABLE_API
 #undef GNOME_DISABLE_DEPRECATED
 #include <libgnome/gnome-desktop-item.h>
+#include <libgnome/gnome-desktop-utils.h>
 
 struct _GnomeDesktopItem {
 	int refcount;
@@ -1788,7 +1787,7 @@
 			/* ignore errors */
 		}
 
-		gnome_prepend_terminal_to_vector (&term_argc, &term_argv);
+		gnome_desktop_prepend_terminal_to_vector (&term_argc, &term_argv);
 	}
 
 	args = make_args (file_list);
@@ -2068,7 +2067,10 @@
 			return -1;
 		}
 
-		retval = gnome_url_show (url, error);
+		retval = gtk_show_uri  (screen,
+					url,
+					GDK_CURRENT_TIME,
+					error);
 		return retval ? 0 : -1;
 	}
 
@@ -2449,178 +2451,6 @@
 	return retval;
 }
 
-static char *kde_icondir = NULL;
-static GSList *hicolor_kde_48 = NULL;
-static GSList *hicolor_kde_32 = NULL;
-static GSList *hicolor_kde_22 = NULL;
-static GSList *hicolor_kde_16 = NULL;
-/* XXX: maybe we don't care about locolor
-static GSList *locolor_kde_48 = NULL;
-static GSList *locolor_kde_32 = NULL;
-static GSList *locolor_kde_22 = NULL;
-static GSList *locolor_kde_16 = NULL;
-*/
-
-static GSList *
-add_dirs (GSList *list, const char *dirname)
-{
-	DIR *dir;
-	struct dirent *dent;
-
-	dir = opendir (dirname);
-	if (dir == NULL)
-		return list;
-
-	list = g_slist_prepend (list, g_strdup (dirname));
-
-	while ((dent = readdir (dir)) != NULL) {
-		char *full;
-
-		/* skip hidden and self/parent references */
-		if (dent->d_name[0] == '.')
-			continue;
-
-		full = g_build_filename (dirname, dent->d_name, NULL);
-		if (g_file_test (full, G_FILE_TEST_IS_DIR)) {
-			list = g_slist_prepend (list, full);
-			list = add_dirs (list, full);
-		} else {
-			g_free (full);
-		}
-	}
-	closedir (dir);
-
-	return list;
-}
-
-static void
-init_kde_dirs (void)
-{
-	char *dirname;
-
-	if (kde_icondir == NULL)
-		return;
-
-#define ADD_DIRS(color,size) \
-	dirname = g_build_filename (kde_icondir, #color,	\
-				    #size "x" #size , NULL);	\
-	color ## _kde_ ## size = add_dirs (NULL, dirname);	\
-	g_free (dirname);
-
-	ADD_DIRS (hicolor, 48);
-	ADD_DIRS (hicolor, 32);
-	ADD_DIRS (hicolor, 22);
-	ADD_DIRS (hicolor, 16);
-
-/* XXX: maybe we don't care about locolor
-	ADD_DIRS (locolor, 48);
-	ADD_DIRS (locolor, 32);
-	ADD_DIRS (locolor, 22);
-	*/
-
-#undef ADD_DIRS
-}
-
-static GSList *
-get_kde_dirs (int size)
-{
-	GSList *list = NULL;
-
-	if (kde_icondir == NULL)
-		return NULL;
-
-	if (size > 32) {
-		/* 48-inf */
-		list = g_slist_concat (g_slist_copy (hicolor_kde_48),
-				       g_slist_copy (hicolor_kde_32));
-		list = g_slist_concat (list,
-				       g_slist_copy (hicolor_kde_22));
-		list = g_slist_concat (list,
-				       g_slist_copy (hicolor_kde_16));
-	} else if (size > 22) {
-		/* 23-32 */
-		list = g_slist_concat (g_slist_copy (hicolor_kde_32),
-				       g_slist_copy (hicolor_kde_48));
-		list = g_slist_concat (list,
-				       g_slist_copy (hicolor_kde_22));
-		list = g_slist_concat (list,
-				       g_slist_copy (hicolor_kde_16));
-	} else if (size > 16) {
-		/* 17-22 */
-		list = g_slist_concat (g_slist_copy (hicolor_kde_22),
-				       g_slist_copy (hicolor_kde_32));
-		list = g_slist_concat (list,
-				       g_slist_copy (hicolor_kde_48));
-		list = g_slist_concat (list,
-				       g_slist_copy (hicolor_kde_16));
-	} else {
-		/* 1-16 */
-		list = g_slist_concat (g_slist_copy (hicolor_kde_16),
-				       g_slist_copy (hicolor_kde_22));
-		list = g_slist_concat (list,
-				       g_slist_copy (hicolor_kde_32));
-		list = g_slist_concat (list,
-				       g_slist_copy (hicolor_kde_48));
-	}
-
-	list = g_slist_append (list, kde_icondir);
-
-	return list;
-}
-
-/* similar function is in panel/main.c */
-static void
-find_kde_directory (void)
-{
-	int i;
-	const char *kdedir;
-	char *try_prefixes[] = {
-		"/usr",
-		"/opt/kde",
-		"/opt/kde2",
-		"/usr/local",
-		"/kde",
-		"/kde2",
-		NULL
-	};
-
-	if (kde_icondir != NULL)
-		return;
-
-	kdedir = g_getenv ("KDEDIR");
-
-	if (kdedir != NULL) {
-		kde_icondir = g_build_filename (kdedir, "share", "icons", NULL);
-		init_kde_dirs ();
-		return;
-	}
-
-	/* if what configure gave us works use that */
-	if (g_file_test (KDE_ICONDIR, G_FILE_TEST_IS_DIR)) {
-		kde_icondir = g_strdup (KDE_ICONDIR);
-		init_kde_dirs ();
-		return;
-	}
-
-	for (i = 0; try_prefixes[i] != NULL; i++) {
-		char *try;
-		try = g_build_filename (try_prefixes[i], "share", "applnk", NULL);
-		if (g_file_test (try, G_FILE_TEST_IS_DIR)) {
-			g_free (try);
-			kde_icondir = g_build_filename (try_prefixes[i], "share", "icons", NULL);
-			init_kde_dirs ();
-			return;
-		}
-		g_free (try);
-	}
-
-	/* absolute fallback, these don't exist, but we're out of options
-	   here */
-	kde_icondir = g_strdup (KDE_ICONDIR);
-
-	init_kde_dirs ();
-}
-
 /**
  * gnome_desktop_item_find_icon:
  * @icon_theme: a #GtkIconTheme
@@ -2640,11 +2470,11 @@
 			      int desired_size,
 			      int flags)
 {
+	GtkIconInfo *info;
 	char *full = NULL;
 
 	g_return_val_if_fail (icon_theme == NULL ||
-			      GTK_IS_ICON_THEME (icon_theme) ||
-			      GNOME_IS_ICON_THEME (icon_theme), NULL);
+			      GTK_IS_ICON_THEME (icon_theme), NULL);
 
 	if (icon == NULL || strcmp(icon,"") == 0) {
 		return NULL;
@@ -2669,82 +2499,22 @@
 		     strcmp (p, ".svg") == 0)) {
 		    *p = 0;
 		}
-
-		/* For backwards compat we support GnomeIconTheme too */
-		if (GNOME_IS_ICON_THEME (icon_theme)) {
-			full = gnome_icon_theme_lookup_icon (icon_theme,
-							     icon_no_extension,
-							     desired_size,
-							     NULL, NULL);
-		} else {
-			GtkIconInfo *info;
-
-			info = gtk_icon_theme_lookup_icon (icon_theme,
-							   icon_no_extension,
-							   desired_size,
-							   0);
-
-			full = NULL;
-			if (info) {
-				full = g_strdup (gtk_icon_info_get_filename (info));
-				gtk_icon_info_free (info);
-			}
-		}
 		
-		g_free (icon_no_extension);
-	}
-
-	if (full == NULL) { /* Fall back on old Gnome/KDE code */
-		GSList *kde_dirs = NULL;
-		GSList *li;
-		const char *exts[] = { ".png", ".xpm", NULL };
-		const char *no_exts[] = { "", NULL };
-		const char **check_exts;
-
-		full = gnome_program_locate_file (NULL,
-						  GNOME_FILE_DOMAIN_PIXMAP,
-						  icon,
-						  TRUE /* only_if_exists */,
-						  NULL /* ret_locations */);
-		if (full == NULL)
-			full = gnome_program_locate_file (NULL,
-							  GNOME_FILE_DOMAIN_APP_PIXMAP,
-							  icon,
-							  TRUE /* only_if_exists */,
-							  NULL /* ret_locations */);
-
-		/* if we found something or no kde, then just return now */
-		if (full != NULL ||
-		    flags & GNOME_DESKTOP_ITEM_ICON_NO_KDE)
-			return full;
-
-		/* If there is an extention don't add any extensions */
-		if (strchr (icon, '.') != NULL) {
-			check_exts = no_exts;
-		} else {
-			check_exts = exts;
-		}
-
-		find_kde_directory ();
-
-		kde_dirs = get_kde_dirs (desired_size);
-
-		for (li = kde_dirs; full == NULL && li != NULL; li = li->next) {
-			int i;
-			for (i = 0; full == NULL && check_exts[i] != NULL; i++) {
-				full = g_strconcat (li->data, G_DIR_SEPARATOR_S, icon,
-						    check_exts[i], NULL);
-				if ( ! g_file_test (full, G_FILE_TEST_EXISTS)) {
-					g_free (full);
-					full = NULL;
-				}
-			}
+		
+		info = gtk_icon_theme_lookup_icon (icon_theme,
+						   icon_no_extension,
+						   desired_size,
+						   0);
+		
+		full = NULL;
+		if (info) {
+			full = g_strdup (gtk_icon_info_get_filename (info));
+			gtk_icon_info_free (info);
 		}
-
-		g_slist_free (kde_dirs);
-
+		g_free (icon_no_extension);
 	}
-	    return full;
+	
+	return full;
 	    
 }
 

Added: trunk/libgnome-desktop/gnome-desktop-thumbnail.c
==============================================================================
--- (empty file)
+++ trunk/libgnome-desktop/gnome-desktop-thumbnail.c	Tue Oct  7 19:12:18 2008
@@ -0,0 +1,1258 @@
+/*
+ * gnome-thumbnail.c: Utilities for handling thumbnails
+ *
+ * Copyright (C) 2002 Red Hat, Inc.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Alexander Larsson <alexl redhat com>
+ */
+
+#include <config.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <time.h>
+#include <math.h>
+#include <string.h>
+#include <glib.h>
+#include <stdio.h>
+
+#define GDK_PIXBUF_ENABLE_BACKEND
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include "libgnomeui/gnome-desktop-thumbnail.h"
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+#include <glib/gstdio.h>
+
+#define SECONDS_BETWEEN_STATS 10
+
+struct _GnomeDesktopThumbnailFactoryPrivate {
+  char *application;
+  GnomeDesktopThumbnailSize size;
+
+  GMutex *lock;
+
+  GHashTable *scripts_hash;
+  guint thumbnailers_notify;
+  guint reread_scheduled;
+};
+
+static void gnome_desktop_thumbnail_factory_init          (GnomeDesktopThumbnailFactory      *factory);
+static void gnome_desktop_thumbnail_factory_class_init    (GnomeDesktopThumbnailFactoryClass *class);
+
+G_DEFINE_TYPE (GnomeDesktopThumbnailFactory,
+	       gnome_desktop_thumbnail_factory,
+	       G_TYPE_OBJECT)
+#define parent_class gnome_desktop_thumbnail_factory_parent_class
+
+typedef struct {
+    gint width;
+    gint height;
+    gint input_width;
+    gint input_height;
+    gboolean preserve_aspect_ratio;
+} SizePrepareContext;
+
+#define LOAD_BUFFER_SIZE 4096
+
+static void
+size_prepared_cb (GdkPixbufLoader *loader, 
+		  int              width,
+		  int              height,
+		  gpointer         data)
+{
+  SizePrepareContext *info = data;
+  
+  g_return_if_fail (width > 0 && height > 0);
+  
+  info->input_width = width;
+  info->input_height = height;
+  
+  if (width < info->width && height < info->height) return;
+  
+  if (info->preserve_aspect_ratio && 
+      (info->width > 0 || info->height > 0)) {
+    if (info->width < 0)
+      {
+	width = width * (double)info->height/(double)height;
+	height = info->height;
+      }
+    else if (info->height < 0)
+      {
+	height = height * (double)info->width/(double)width;
+	width = info->width;
+      }
+    else if ((double)height * (double)info->width >
+	     (double)width * (double)info->height) {
+      width = 0.5 + (double)width * (double)info->height / (double)height;
+      height = info->height;
+    } else {
+      height = 0.5 + (double)height * (double)info->width / (double)width;
+      width = info->width;
+    }
+  } else {
+    if (info->width > 0)
+      width = info->width;
+    if (info->height > 0)
+      height = info->height;
+  }
+  
+  gdk_pixbuf_loader_set_size (loader, width, height);
+}
+
+static GdkPixbuf *
+_gdk_pixbuf_new_from_uri_at_scale (const char *uri,
+				   gint        width,
+				   gint        height,
+				   gboolean    preserve_aspect_ratio)
+{
+    gboolean result;
+    char buffer[LOAD_BUFFER_SIZE];
+    gsize bytes_read;
+    GdkPixbufLoader *loader;
+    GdkPixbuf *pixbuf;	
+    GdkPixbufAnimation *animation;
+    GdkPixbufAnimationIter *iter;
+    gboolean has_frame;
+    SizePrepareContext info;
+    GFile *file;
+    GFileInputStream *file_input_stream;
+
+    g_return_val_if_fail (uri != NULL, NULL);
+
+    file = g_file_new_for_uri (uri);
+    file_input_stream = g_file_read (file, NULL, NULL);
+    if (file_input_stream == NULL) {
+	g_object_unref (file);
+	return NULL;
+    }
+
+    loader = gdk_pixbuf_loader_new ();
+    if (1 <= width || 1 <= height) {
+        info.width = width;
+        info.height = height;
+	info.input_width = info.input_height = 0;
+        info.preserve_aspect_ratio = preserve_aspect_ratio;        
+        g_signal_connect (loader, "size-prepared", G_CALLBACK (size_prepared_cb), &info);
+    }
+
+    has_frame = FALSE;
+
+    result = FALSE;
+    while (!has_frame) {
+
+	bytes_read = g_input_stream_read (G_INPUT_STREAM (file_input_stream),
+					  buffer,
+					  sizeof (buffer),
+					  NULL,
+					  NULL);
+	if (bytes_read == -1) {
+	    break;
+	}
+	result = TRUE;
+	if (bytes_read == 0) {
+	    break;
+	}
+
+	if (!gdk_pixbuf_loader_write (loader,
+				      (unsigned char *)buffer,
+				      bytes_read,
+				      NULL)) {
+	    result = FALSE;
+	    break;
+	}
+
+	animation = gdk_pixbuf_loader_get_animation (loader);
+	if (animation) {
+		iter = gdk_pixbuf_animation_get_iter (animation, NULL);
+		if (!gdk_pixbuf_animation_iter_on_currently_loading_frame (iter)) {
+			has_frame = TRUE;
+		}
+		g_object_unref (iter);
+	}
+    }
+
+    gdk_pixbuf_loader_close (loader, NULL);
+    
+    if (result) {
+	g_object_unref (G_OBJECT (loader));
+	g_input_stream_close (G_INPUT_STREAM (file_input_stream), NULL, NULL);
+	g_object_unref (file_input_stream);
+	g_object_unref (file);
+	return NULL;
+    }
+
+    g_input_stream_close (G_INPUT_STREAM (file_input_stream), NULL, NULL);
+    g_object_unref (file_input_stream);
+    g_object_unref (file);
+
+    pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+    if (pixbuf != NULL) {
+	g_object_ref (G_OBJECT (pixbuf));
+	g_object_set_data (G_OBJECT (pixbuf), "gnome-original-width",
+			   GINT_TO_POINTER (info.input_width));
+	g_object_set_data (G_OBJECT (pixbuf), "gnome-original-height",
+			   GINT_TO_POINTER (info.input_height));
+    }
+    g_object_unref (G_OBJECT (loader));
+
+    return pixbuf;
+}
+
+static void
+gnome_desktop_thumbnail_factory_finalize (GObject *object)
+{
+  GnomeDesktopThumbnailFactory *factory;
+  GnomeDesktopThumbnailFactoryPrivate *priv;
+  GConfClient *client;
+  
+  factory = GNOME_DESKTOP_THUMBNAIL_FACTORY (object);
+
+  priv = factory->priv;
+  
+  g_free (priv->application);
+  priv->application = NULL;
+
+  if (priv->reread_scheduled != 0) {
+    g_source_remove (priv->reread_scheduled);
+    priv->reread_scheduled = 0;
+  }
+
+  if (priv->thumbnailers_notify != 0) {
+    client = gconf_client_get_default ();
+    gconf_client_notify_remove (client, priv->thumbnailers_notify);
+    priv->thumbnailers_notify = 0;
+    g_object_unref (client);
+  }
+  
+  if (priv->scripts_hash)
+    {
+      g_hash_table_destroy (priv->scripts_hash);
+      priv->scripts_hash = NULL;
+    }
+
+  if (priv->lock)
+    {
+      g_mutex_free (priv->lock);
+      priv->lock = NULL;
+    }
+  
+  g_free (priv);
+  factory->priv = NULL;
+  
+  if (G_OBJECT_CLASS (parent_class)->finalize)
+    (* G_OBJECT_CLASS (parent_class)->finalize) (object);
+}
+
+/* Must be called on main thread */
+static GHashTable *
+read_scripts (void)
+{
+  GHashTable *scripts_hash;
+  GConfClient *client;
+  GSList *subdirs, *l;
+  char *subdir, *enable, *escape, *commandkey, *command, *mimetype;
+
+  client = gconf_client_get_default ();
+
+  if (gconf_client_get_bool (client,
+			     "/desktop/gnome/thumbnailers/disable_all",
+			     NULL))
+    {
+      g_object_unref (G_OBJECT (client));
+      return NULL;
+    }
+  
+  scripts_hash = g_hash_table_new_full (g_str_hash,
+					g_str_equal,
+					g_free, g_free);
+
+  
+  subdirs = gconf_client_all_dirs (client, "/desktop/gnome/thumbnailers", NULL);
+
+  for (l = subdirs; l != NULL; l = l->next)
+    {
+      subdir = l->data;
+
+      enable = g_strdup_printf ("%s/enable", subdir);
+      if (gconf_client_get_bool (client,
+				 enable,
+				 NULL))
+	{
+	  commandkey = g_strdup_printf ("%s/command", subdir);
+	  command = gconf_client_get_string (client, commandkey, NULL);
+	  g_free (commandkey);
+
+	  if (command != NULL) {
+	    mimetype = strrchr (subdir, '/');
+	    if (mimetype != NULL)
+	      {
+		mimetype++; /* skip past slash */
+		
+		/* Convert '@' to slash in mimetype */
+		escape = strchr (mimetype, '@');
+		if (escape != NULL)
+		  *escape = '/';
+
+		/* Convert any remaining '@' to '+' in mimetype */
+		while ((escape = strchr (mimetype, '@')) != NULL)
+                  *escape = '+';
+
+		g_hash_table_insert (scripts_hash,
+				     g_strdup (mimetype), command);
+	      }
+	    else
+	      {
+		g_free (command);
+	      }
+	  }
+	}
+      g_free (enable);
+      
+      g_free (subdir);
+    }
+  
+  g_slist_free(subdirs);
+
+  g_object_unref (G_OBJECT (client));
+  
+  return scripts_hash;
+}
+
+
+/* Must be called on main thread */
+static void
+gnome_desktop_thumbnail_factory_reread_scripts (GnomeDesktopThumbnailFactory *factory)
+{
+  GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv;
+  GHashTable *scripts_hash;
+
+  scripts_hash = read_scripts ();
+
+  g_mutex_lock (priv->lock);
+
+  if (priv->scripts_hash != NULL)
+    g_hash_table_destroy (priv->scripts_hash);
+  
+  priv->scripts_hash = scripts_hash;
+  
+  g_mutex_unlock (priv->lock);
+}
+
+static gboolean
+reread_idle_callback (gpointer user_data)
+{
+  GnomeDesktopThumbnailFactory *factory = user_data;
+  GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv;
+
+  gnome_desktop_thumbnail_factory_reread_scripts (factory);
+
+  g_mutex_lock (priv->lock);
+  priv->reread_scheduled = 0;
+  g_mutex_unlock (priv->lock);
+   
+  return FALSE;
+}
+
+static void
+schedule_reread (GConfClient* client,
+		 guint cnxn_id,
+		 GConfEntry *entry,
+		 gpointer user_data)
+{
+  GnomeDesktopThumbnailFactory *factory = user_data;
+  GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv;
+
+  g_mutex_lock (priv->lock);
+
+  if (priv->reread_scheduled == 0)
+    {
+      priv->reread_scheduled = g_idle_add (reread_idle_callback,
+					   factory);
+    }
+  
+  g_mutex_unlock (priv->lock);
+}
+
+
+static void
+gnome_desktop_thumbnail_factory_init (GnomeDesktopThumbnailFactory *factory)
+{
+  GConfClient *client;
+  GnomeDesktopThumbnailFactoryPrivate *priv;
+  
+  factory->priv = g_new0 (GnomeDesktopThumbnailFactoryPrivate, 1);
+
+  priv = factory->priv;
+
+  priv->size = GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL;
+  priv->application = g_strdup ("gnome-thumbnail-factory");
+  
+  priv->scripts_hash = NULL;
+  
+  priv->lock = g_mutex_new ();
+
+  gnome_desktop_thumbnail_factory_reread_scripts (factory);
+
+  client = gconf_client_get_default ();
+  gconf_client_add_dir (client,
+			"/desktop/gnome",
+			GCONF_CLIENT_PRELOAD_NONE, NULL);
+
+  priv->thumbnailers_notify = gconf_client_notify_add (client, "/desktop/gnome/thumbnailers",
+						       schedule_reread, factory, NULL,
+						       NULL);
+
+  g_object_unref (G_OBJECT (client));
+}
+
+static void
+gnome_desktop_thumbnail_factory_class_init (GnomeDesktopThumbnailFactoryClass *class)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (class);
+	
+  gobject_class->finalize = gnome_desktop_thumbnail_factory_finalize;
+}
+
+/**
+ * gnome_desktop_thumbnail_factory_new:
+ * @size: The thumbnail size to use
+ *
+ * Creates a new #GnomeDesktopThumbnailFactory.
+ *
+ * This function must be called on the main thread.
+ * 
+ * Return value: a new #GnomeDesktopThumbnailFactory
+ *
+ * Since: 2.2
+ **/
+GnomeDesktopThumbnailFactory *
+gnome_desktop_thumbnail_factory_new (GnomeDesktopThumbnailSize size)
+{
+  GnomeDesktopThumbnailFactory *factory;
+  
+  factory = g_object_new (GNOME_TYPE_THUMBNAIL_FACTORY, NULL);
+  
+  factory->priv->size = size;
+  
+  return factory;
+}
+
+/**
+ * gnome_desktop_thumbnail_factory_lookup:
+ * @factory: a #GnomeDesktopThumbnailFactory
+ * @uri: the uri of a file
+ * @mtime: the mtime of the file
+ *
+ * Tries to locate an existing thumbnail for the file specified.
+ *
+ * Usage of this function is threadsafe.
+ *
+ * Return value: The absolute path of the thumbnail, or %NULL if none exist.
+ *
+ * Since: 2.2
+ **/
+char *
+gnome_desktop_thumbnail_factory_lookup (GnomeDesktopThumbnailFactory *factory,
+					const char            *uri,
+					time_t                 mtime)
+{
+  GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv;
+  char *path, *file;
+  GChecksum *checksum;
+  guint8 digest[16];
+  gsize digest_len = sizeof (digest);
+  GdkPixbuf *pixbuf;
+  gboolean res;
+
+  g_return_val_if_fail (uri != NULL, NULL);
+
+  res = FALSE;
+
+  checksum = g_checksum_new (G_CHECKSUM_MD5);
+  g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
+
+  g_checksum_get_digest (checksum, digest, &digest_len);
+  g_assert (digest_len == 16);
+
+  file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
+  
+  path = g_build_filename (g_get_home_dir (),
+			   ".thumbnails",
+			   (priv->size == GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL)?"normal":"large",
+			   file,
+			   NULL);
+  g_free (file);
+
+  pixbuf = gdk_pixbuf_new_from_file (path, NULL);
+  if (pixbuf != NULL)
+    {
+      res = gnome_desktop_thumbnail_is_valid (pixbuf, uri, mtime);
+      g_object_unref (pixbuf);
+    }
+
+  g_checksum_free (checksum);
+
+  if (res)
+    return path;
+
+  g_free (path);
+  return FALSE;
+}
+
+/**
+ * gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail:
+ * @factory: a #GnomeDesktopThumbnailFactory
+ * @uri: the uri of a file
+ * @mtime: the mtime of the file
+ *
+ * Tries to locate an failed thumbnail for the file specified. Writing
+ * and looking for failed thumbnails is important to avoid to try to
+ * thumbnail e.g. broken images several times.
+ *
+ * Usage of this function is threadsafe.
+ *
+ * Return value: TRUE if there is a failed thumbnail for the file.
+ *
+ * Since: 2.2
+ **/
+gboolean
+gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (GnomeDesktopThumbnailFactory *factory,
+							    const char            *uri,
+							    time_t                 mtime)
+{
+  char *path, *file;
+  GdkPixbuf *pixbuf;
+  gboolean res;
+  GChecksum *checksum;
+  guint8 digest[16];
+  gsize digest_len = sizeof (digest);
+
+  checksum = g_checksum_new (G_CHECKSUM_MD5);
+  g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
+
+  g_checksum_get_digest (checksum, digest, &digest_len);
+  g_assert (digest_len == 16);
+
+  res = FALSE;
+
+  file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
+
+  path = g_build_filename (g_get_home_dir (),
+			   ".thumbnails/fail",
+			   factory->priv->application,
+			   file,
+			   NULL);
+  g_free (file);
+
+  pixbuf = gdk_pixbuf_new_from_file (path, NULL);
+  g_free (path);
+
+  if (pixbuf)
+    {
+      res = gnome_desktop_thumbnail_is_valid (pixbuf, uri, mtime);
+      g_object_unref (pixbuf);
+    }
+
+  g_checksum_free (checksum);
+
+  return res;
+}
+
+static gboolean
+mimetype_supported_by_gdk_pixbuf (const char *mime_type)
+{
+	guint i;
+	static GHashTable *formats_hash = NULL;
+
+	if (!formats_hash) {
+		GSList *formats, *list;
+		
+		formats_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+		formats = gdk_pixbuf_get_formats ();
+		list = formats;
+		
+		while (list) {
+			GdkPixbufFormat *format = list->data;
+			gchar **mime_types;
+			
+			mime_types = gdk_pixbuf_format_get_mime_types (format);
+
+			for (i = 0; mime_types[i] != NULL; i++)
+				g_hash_table_insert (formats_hash,
+						     (gpointer) g_strdup (mime_types[i]),
+						     GUINT_TO_POINTER (1));	
+				
+			g_strfreev (mime_types);
+			list = list->next;
+		}
+		g_slist_free (formats);
+	}
+
+	if (g_hash_table_lookup (formats_hash, mime_type))
+		return TRUE;
+
+	return FALSE;
+}
+
+/**
+ * gnome_desktop_thumbnail_factory_can_thumbnail:
+ * @factory: a #GnomeDesktopThumbnailFactory
+ * @uri: the uri of a file
+ * @mime_type: the mime type of the file
+ * @mtime: the mtime of the file
+ *
+ * Returns TRUE if this GnomeIconFactory can (at least try) to thumbnail
+ * this file. Thumbnails or files with failed thumbnails won't be thumbnailed.
+ *
+ * Usage of this function is threadsafe.
+ *
+ * Return value: TRUE if the file can be thumbnailed.
+ *
+ * Since: 2.2
+ **/
+gboolean
+gnome_desktop_thumbnail_factory_can_thumbnail (GnomeDesktopThumbnailFactory *factory,
+					       const char            *uri,
+					       const char            *mime_type,
+					       time_t                 mtime)
+{
+  /* Don't thumbnail thumbnails */
+  if (uri &&
+      strncmp (uri, "file:/", 6) == 0 &&
+      strstr (uri, "/.thumbnails/") != NULL)
+    return FALSE;
+  
+  if (mime_type != NULL &&
+      (mimetype_supported_by_gdk_pixbuf (mime_type) ||
+       (factory->priv->scripts_hash != NULL &&
+	g_hash_table_lookup (factory->priv->scripts_hash, mime_type))))
+    {
+      return !gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (factory,
+								  uri,
+								  mtime);
+    }
+  
+  return FALSE;
+}
+
+static char *
+expand_thumbnailing_script (const char *script,
+			    const int   size, 
+			    const char *inuri,
+			    const char *outfile)
+{
+  GString *str;
+  const char *p, *last;
+  char *localfile, *quoted;
+  gboolean got_in;
+
+  str = g_string_new (NULL);
+  
+  got_in = FALSE;
+  last = script;
+  while ((p = strchr (last, '%')) != NULL)
+    {
+      g_string_append_len (str, last, p - last);
+      p++;
+
+      switch (*p) {
+      case 'u':
+	quoted = g_shell_quote (inuri);
+	g_string_append (str, quoted);
+	g_free (quoted);
+	got_in = TRUE;
+	p++;
+	break;
+      case 'i':
+	localfile = g_filename_from_uri (inuri, NULL, NULL);
+	if (localfile)
+	  {
+	    quoted = g_shell_quote (localfile);
+	    g_string_append (str, quoted);
+	    got_in = TRUE;
+	    g_free (quoted);
+	    g_free (localfile);
+	  }
+	p++;
+	break;
+      case 'o':
+	quoted = g_shell_quote (outfile);
+	g_string_append (str, quoted);
+	g_free (quoted);
+	p++;
+	break;
+      case 's':
+	g_string_append_printf (str, "%d", size);
+	p++;
+	break;
+      case '%':
+	g_string_append_c (str, '%');
+	p++;
+	break;
+      case 0:
+      default:
+	break;
+      }
+      last = p;
+    }
+  g_string_append (str, last);
+
+  if (got_in)
+    return g_string_free (str, FALSE);
+
+  g_string_free (str, TRUE);
+  return NULL;
+}
+
+/**
+ * gnome_desktop_thumbnail_factory_generate_thumbnail:
+ * @factory: a #GnomeDesktopThumbnailFactory
+ * @uri: the uri of a file
+ * @mime_type: the mime type of the file
+ *
+ * Tries to generate a thumbnail for the specified file. If it succeeds
+ * it returns a pixbuf that can be used as a thumbnail.
+ *
+ * Usage of this function is threadsafe.
+ *
+ * Return value: thumbnail pixbuf if thumbnailing succeeded, %NULL otherwise.
+ *
+ * Since: 2.2
+ **/
+GdkPixbuf *
+gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory *factory,
+						    const char            *uri,
+						    const char            *mime_type)
+{
+  GdkPixbuf *pixbuf, *scaled, *tmp_pixbuf;
+  char *script, *expanded_script;
+  int width, height, size;
+  int original_width = 0;
+  int original_height = 0;
+  char dimension[12];
+  double scale;
+  int exit_status;
+  char *tmpname;
+
+  g_return_val_if_fail (uri != NULL, NULL);
+  g_return_val_if_fail (mime_type != NULL, NULL);
+
+  /* Doesn't access any volatile fields in factory, so it's threadsafe */
+  
+  size = 128;
+  if (factory->priv->size == GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE)
+    size = 256;
+
+  pixbuf = NULL;
+
+  script = NULL;
+  if (factory->priv->scripts_hash != NULL)
+    script = g_hash_table_lookup (factory->priv->scripts_hash, mime_type);
+  
+  if (script)
+    {
+      int fd;
+      GError *error = NULL;
+
+      fd = g_file_open_tmp (".gnome_desktop_thumbnail.XXXXXX", &tmpname, &error);
+
+      if (fd != -1)
+	{
+	  close (fd);
+
+	  expanded_script = expand_thumbnailing_script (script, size, uri, tmpname);
+	  if (expanded_script != NULL &&
+	      g_spawn_command_line_sync (expanded_script,
+					 NULL, NULL, &exit_status, NULL) &&
+	      exit_status == 0)
+	    {
+	      pixbuf = gdk_pixbuf_new_from_file (tmpname, NULL);
+	    }
+
+	  g_free (expanded_script);
+	  g_unlink(tmpname);
+	}
+      g_free (tmpname);
+    }
+
+  /* Fall back to gdk-pixbuf */
+  if (pixbuf == NULL)
+    {
+      pixbuf = _gdk_pixbuf_new_from_uri_at_scale (uri, size, size, TRUE);
+
+      if (pixbuf != NULL)
+        {
+          original_width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pixbuf),
+                                                               "gnome-original-width"));
+          original_height = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pixbuf),
+                                                                "gnome-original-height"));
+        }
+    }
+      
+  if (pixbuf == NULL)
+    return NULL;
+
+  /* The pixbuf loader may attach an "orientation" option to the pixbuf,
+     if the tiff or exif jpeg file had an orientation tag. Rotate/flip
+     the pixbuf as specified by this tag, if present. */
+  tmp_pixbuf = gdk_pixbuf_apply_embedded_orientation (pixbuf);
+  g_object_unref (pixbuf);
+  pixbuf = tmp_pixbuf;
+
+  width = gdk_pixbuf_get_width (pixbuf);
+  height = gdk_pixbuf_get_height (pixbuf);
+  
+  if (width > size || height > size)
+    {
+      const gchar *orig_width, *orig_height;
+      scale = (double)size / MAX (width, height);
+
+      scaled = gnome_desktop_thumbnail_scale_down_pixbuf (pixbuf,
+						  floor (width * scale + 0.5),
+						  floor (height * scale + 0.5));
+
+      orig_width = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::Image::Width");
+      orig_height = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::Image::Height");
+
+      if (orig_width != NULL) {
+	      gdk_pixbuf_set_option (scaled, "tEXt::Thumb::Image::Width", orig_width);
+      }
+      if (orig_height != NULL) {
+	      gdk_pixbuf_set_option (scaled, "tEXt::Thumb::Image::Height", orig_height);
+      }
+      
+      g_object_unref (pixbuf);
+      pixbuf = scaled;
+    }
+  
+  if (original_width > 0) {
+	  g_snprintf (dimension, sizeof (dimension), "%i", original_width);
+	  gdk_pixbuf_set_option (pixbuf, "tEXt::Thumb::Image::Width", dimension);
+  }
+  if (original_height > 0) {
+	  g_snprintf (dimension, sizeof (dimension), "%i", original_height);
+	  gdk_pixbuf_set_option (pixbuf, "tEXt::Thumb::Image::Height", dimension);
+  }
+
+  return pixbuf;
+}
+
+static gboolean
+make_thumbnail_dirs (GnomeDesktopThumbnailFactory *factory)
+{
+  char *thumbnail_dir;
+  char *image_dir;
+  gboolean res;
+
+  res = FALSE;
+
+  thumbnail_dir = g_build_filename (g_get_home_dir (),
+				    ".thumbnails",
+				    NULL);
+  if (!g_file_test (thumbnail_dir, G_FILE_TEST_IS_DIR))
+    {
+      g_mkdir (thumbnail_dir, 0700);
+      res = TRUE;
+    }
+
+  image_dir = g_build_filename (thumbnail_dir,
+				(factory->priv->size == GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL)?"normal":"large",
+				NULL);
+  if (!g_file_test (image_dir, G_FILE_TEST_IS_DIR))
+    {
+      g_mkdir (image_dir, 0700);
+      res = TRUE;
+    }
+
+  g_free (thumbnail_dir);
+  g_free (image_dir);
+  
+  return res;
+}
+
+static gboolean
+make_thumbnail_fail_dirs (GnomeDesktopThumbnailFactory *factory)
+{
+  char *thumbnail_dir;
+  char *fail_dir;
+  char *app_dir;
+  gboolean res;
+
+  res = FALSE;
+
+  thumbnail_dir = g_build_filename (g_get_home_dir (),
+				    ".thumbnails",
+				    NULL);
+  if (!g_file_test (thumbnail_dir, G_FILE_TEST_IS_DIR))
+    {
+      g_mkdir (thumbnail_dir, 0700);
+      res = TRUE;
+    }
+
+  fail_dir = g_build_filename (thumbnail_dir,
+			       "fail",
+			       NULL);
+  if (!g_file_test (fail_dir, G_FILE_TEST_IS_DIR))
+    {
+      g_mkdir (fail_dir, 0700);
+      res = TRUE;
+    }
+
+  app_dir = g_build_filename (fail_dir,
+			      factory->priv->application,
+			      NULL);
+  if (!g_file_test (app_dir, G_FILE_TEST_IS_DIR))
+    {
+      g_mkdir (app_dir, 0700);
+      res = TRUE;
+    }
+
+  g_free (thumbnail_dir);
+  g_free (fail_dir);
+  g_free (app_dir);
+  
+  return res;
+}
+
+
+/**
+ * gnome_desktop_thumbnail_factory_save_thumbnail:
+ * @factory: a #GnomeDesktopThumbnailFactory
+ * @thumbnail: the thumbnail as a pixbuf 
+ * @uri: the uri of a file
+ * @original_mtime: the modification time of the original file 
+ *
+ * Saves @thumbnail at the right place. If the save fails a
+ * failed thumbnail is written.
+ *
+ * Usage of this function is threadsafe.
+ *
+ * Since: 2.2
+ **/
+void
+gnome_desktop_thumbnail_factory_save_thumbnail (GnomeDesktopThumbnailFactory *factory,
+						GdkPixbuf             *thumbnail,
+						const char            *uri,
+						time_t                 original_mtime)
+{
+  GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv;
+  char *path, *file, *dir;
+  char *tmp_path;
+  const char *width, *height;
+  int tmp_fd;
+  char mtime_str[21];
+  gboolean saved_ok;
+  GChecksum *checksum;
+  guint8 digest[16];
+  gsize digest_len = sizeof (digest);
+
+  checksum = g_checksum_new (G_CHECKSUM_MD5);
+  g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
+
+  g_checksum_get_digest (checksum, digest, &digest_len);
+  g_assert (digest_len == 16);
+
+  file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
+  
+  dir = g_build_filename (g_get_home_dir (),
+			  ".thumbnails",
+			  (priv->size == GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL)?"normal":"large",
+			  NULL);
+  
+  path = g_build_filename (dir,
+			   file,
+			   NULL);
+  g_free (file);
+
+  g_checksum_free (checksum);
+
+  tmp_path = g_strconcat (path, ".XXXXXX", NULL);
+
+  tmp_fd = g_mkstemp (tmp_path);
+  if (tmp_fd == -1 &&
+      make_thumbnail_dirs (factory))
+    {
+      g_free (tmp_path);
+      tmp_path = g_strconcat (path, ".XXXXXX", NULL);
+      tmp_fd = g_mkstemp (tmp_path);
+    }
+
+  if (tmp_fd == -1)
+    {
+      gnome_desktop_thumbnail_factory_create_failed_thumbnail (factory, uri, original_mtime);
+      g_free (dir);
+      g_free (tmp_path);
+      g_free (path);
+      return;
+    }
+  close (tmp_fd);
+  
+  g_snprintf (mtime_str, 21, "%ld",  original_mtime);
+  width = gdk_pixbuf_get_option (thumbnail, "tEXt::Thumb::Image::Width");
+  height = gdk_pixbuf_get_option (thumbnail, "tEXt::Thumb::Image::Height");
+
+  if (width != NULL && height != NULL) 
+    saved_ok  = gdk_pixbuf_save (thumbnail,
+				 tmp_path,
+				 "png", NULL,
+				 "tEXt::Thumb::Image::Width", width,
+				 "tEXt::Thumb::Image::Height", height,
+				 "tEXt::Thumb::URI", uri,
+				 "tEXt::Thumb::MTime", mtime_str,
+				 "tEXt::Software", "GNOME::ThumbnailFactory",
+				 NULL);
+  else
+    saved_ok  = gdk_pixbuf_save (thumbnail,
+				 tmp_path,
+				 "png", NULL,
+				 "tEXt::Thumb::URI", uri,
+				 "tEXt::Thumb::MTime", mtime_str,
+				 "tEXt::Software", "GNOME::ThumbnailFactory",
+				 NULL);
+    
+
+  if (saved_ok)
+    {
+      g_chmod (tmp_path, 0600);
+      g_rename(tmp_path, path);
+    }
+  else
+    {
+      gnome_desktop_thumbnail_factory_create_failed_thumbnail (factory, uri, original_mtime);
+    }
+
+  g_free (dir);
+  g_free (path);
+  g_free (tmp_path);
+}
+
+/**
+ * gnome_desktop_thumbnail_factory_create_failed_thumbnail:
+ * @factory: a #GnomeDesktopThumbnailFactory
+ * @uri: the uri of a file
+ * @mtime: the modification time of the file
+ *
+ * Creates a failed thumbnail for the file so that we don't try
+ * to re-thumbnail the file later.
+ *
+ * Usage of this function is threadsafe.
+ *
+ * Since: 2.2
+ **/
+void
+gnome_desktop_thumbnail_factory_create_failed_thumbnail (GnomeDesktopThumbnailFactory *factory,
+							 const char            *uri,
+							 time_t                 mtime)
+{
+  char *path, *file, *dir;
+  char *tmp_path;
+  int tmp_fd;
+  char mtime_str[21];
+  gboolean saved_ok;
+  GdkPixbuf *pixbuf;
+  GChecksum *checksum;
+  guint8 digest[16];
+  gsize digest_len = sizeof (digest);
+
+  checksum = g_checksum_new (G_CHECKSUM_MD5);
+  g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
+
+  g_checksum_get_digest (checksum, digest, &digest_len);
+  g_assert (digest_len == 16);
+
+  file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
+  
+  dir = g_build_filename (g_get_home_dir (),
+			  ".thumbnails/fail",
+			  factory->priv->application,
+			  NULL);
+  
+  path = g_build_filename (dir,
+			   file,
+			   NULL);
+  g_free (file);
+
+  g_checksum_free (checksum);
+
+  tmp_path = g_strconcat (path, ".XXXXXX", NULL);
+
+  tmp_fd = g_mkstemp (tmp_path);
+  if (tmp_fd == -1 &&
+      make_thumbnail_fail_dirs (factory))
+    {
+      g_free (tmp_path);
+      tmp_path = g_strconcat (path, ".XXXXXX", NULL);
+      tmp_fd = g_mkstemp (tmp_path);
+    }
+
+  if (tmp_fd == -1)
+    {
+      g_free (dir);
+      g_free (tmp_path);
+      g_free (path);
+      return;
+    }
+  close (tmp_fd);
+  
+  g_snprintf (mtime_str, 21, "%ld",  mtime);
+  pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
+  saved_ok  = gdk_pixbuf_save (pixbuf,
+			       tmp_path,
+			       "png", NULL, 
+			       "tEXt::Thumb::URI", uri,
+			       "tEXt::Thumb::MTime", mtime_str,
+			       "tEXt::Software", "GNOME::ThumbnailFactory",
+			       NULL);
+  g_object_unref (pixbuf);
+  if (saved_ok)
+    {
+      g_chmod (tmp_path, 0600);
+      g_rename(tmp_path, path);
+    }
+
+  g_free (dir);
+  g_free (path);
+  g_free (tmp_path);
+}
+
+/**
+ * gnome_desktop_thumbnail_md5:
+ * @uri: an uri
+ *
+ * Calculates the MD5 checksum of the uri. This can be useful
+ * if you want to manually handle thumbnail files.
+ *
+ * Return value: A string with the MD5 digest of the uri string.
+ *
+ * Since: 2.2
+ *
+ * @Deprecated: 2.22: Use #GChecksum instead
+ **/
+char *
+gnome_desktop_thumbnail_md5 (const char *uri)
+{
+  return g_compute_checksum_for_data (G_CHECKSUM_MD5,
+                                      (const guchar *) uri,
+                                      strlen (uri));
+}
+
+/**
+ * gnome_desktop_thumbnail_path_for_uri:
+ * @uri: an uri
+ * @size: a thumbnail size
+ *
+ * Returns the filename that a thumbnail of size @size for @uri would have.
+ *
+ * Return value: an absolute filename
+ *
+ * Since: 2.2
+ **/
+char *
+gnome_desktop_thumbnail_path_for_uri (const char         *uri,
+				      GnomeDesktopThumbnailSize  size)
+{
+  char *md5;
+  char *file;
+  char *path;
+
+  md5 = gnome_desktop_thumbnail_md5 (uri);
+  file = g_strconcat (md5, ".png", NULL);
+  g_free (md5);
+  
+  path = g_build_filename (g_get_home_dir (),
+			   ".thumbnails",
+			   (size == GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL)?"normal":"large",
+			   file,
+			   NULL);
+    
+  g_free (file);
+
+  return path;
+}
+
+/**
+ * gnome_desktop_thumbnail_has_uri:
+ * @pixbuf: an loaded thumbnail pixbuf
+ * @uri: a uri
+ *
+ * Returns whether the thumbnail has the correct uri embedded in the
+ * Thumb::URI option in the png.
+ *
+ * Return value: TRUE if the thumbnail is for @uri
+ *
+ * Since: 2.2
+ **/
+gboolean
+gnome_desktop_thumbnail_has_uri (GdkPixbuf          *pixbuf,
+				 const char         *uri)
+{
+  const char *thumb_uri;
+  
+  thumb_uri = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::URI");
+  if (!thumb_uri)
+    return FALSE;
+
+  return strcmp (uri, thumb_uri) == 0;
+}
+
+/**
+ * gnome_desktop_thumbnail_is_valid:
+ * @pixbuf: an loaded thumbnail #GdkPixbuf
+ * @uri: a uri
+ * @mtime: the mtime
+ *
+ * Returns whether the thumbnail has the correct uri and mtime embedded in the
+ * png options.
+ *
+ * Return value: TRUE if the thumbnail has the right @uri and @mtime
+ *
+ * Since: 2.2
+ **/
+gboolean
+gnome_desktop_thumbnail_is_valid (GdkPixbuf          *pixbuf,
+				  const char         *uri,
+				  time_t              mtime)
+{
+  const char *thumb_uri, *thumb_mtime_str;
+  time_t thumb_mtime;
+  
+  thumb_uri = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::URI");
+  if (!thumb_uri)
+    return FALSE;
+  if (strcmp (uri, thumb_uri) != 0)
+    return FALSE;
+  
+  thumb_mtime_str = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::MTime");
+  if (!thumb_mtime_str)
+    return FALSE;
+  thumb_mtime = atol (thumb_mtime_str);
+  if (mtime != thumb_mtime)
+    return FALSE;
+  
+  return TRUE;
+}

Added: trunk/libgnome-desktop/gnome-desktop-utils.c
==============================================================================
--- (empty file)
+++ trunk/libgnome-desktop/gnome-desktop-utils.c	Tue Oct  7 19:12:18 2008
@@ -0,0 +1,161 @@
+/* -*- Mode: C; c-set-style: linux indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gnome-desktop-utils.c - Utilities for the GNOME Desktop
+
+   Copyright (C) 1998 Tom Tromey
+   All rights reserved.
+
+   This file is part of the Gnome Library.
+
+   The Gnome Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+   
+   The Gnome Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+   
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+/*
+  @NOTATION@
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <gconf/gconf-client.h>
+#include <glib/gi18n-lib.h>
+
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include <libgnome/gnome-desktop-utils.h>
+
+
+/**
+ * gnome_desktop_prepend_terminal_to_vector:
+ * @argc: a pointer to the vector size
+ * @argv: a pointer to the vector
+ *
+ * Description:  Prepends a terminal (either the one configured as default in
+ * the user's GNOME setup, or one of the common xterm emulators) to the passed
+ * in vector, modifying it in the process.  The vector should be allocated with
+ * #g_malloc, as this will #g_free the original vector.  Also all elements must
+ * have been allocated separately.  That is the standard glib/GNOME way of
+ * doing vectors however.  If the integer that @argc points to is negative, the
+ * size will first be computed.  Also note that passing in pointers to a vector
+ * that is empty, will just create a new vector for you.
+ **/
+void
+gnome_desktop_prepend_terminal_to_vector (int *argc, char ***argv)
+{
+#ifndef G_OS_WIN32
+        char **real_argv;
+        int real_argc;
+        int i, j;
+	char **term_argv = NULL;
+	int term_argc = 0;
+	GConfClient *client;
+
+	gchar *terminal = NULL;
+
+	char **the_argv;
+
+        g_return_if_fail (argc != NULL);
+        g_return_if_fail (argv != NULL);
+
+	/* sanity */
+        if(*argv == NULL)
+                *argc = 0;
+
+	the_argv = *argv;
+
+	/* compute size if not given */
+	if (*argc < 0) {
+		for (i = 0; the_argv[i] != NULL; i++)
+			;
+		*argc = i;
+	}
+
+	client = gconf_client_get_default ();
+	terminal = gconf_client_get_string (client, "/desktop/gnome/applications/terminal/exec", NULL);
+	g_object_unref (client);
+	
+	if (terminal) {
+		gchar *command_line;
+		gchar *exec_flag;
+		exec_flag = gconf_client_get_string (client, "/desktop/gnome/applications/terminal/exec_arg", NULL);
+
+		if (exec_flag == NULL)
+			command_line = g_strdup (terminal);
+		else
+			command_line = g_strdup_printf ("%s %s", terminal,
+							exec_flag);
+
+		g_shell_parse_argv (command_line,
+				    &term_argc,
+				    &term_argv,
+				    NULL /* error */);
+
+		g_free (command_line);
+		g_free (exec_flag);
+		g_free (terminal);
+	}
+
+	if (term_argv == NULL) {
+		char *check;
+
+		term_argc = 2;
+		term_argv = g_new0 (char *, 3);
+
+		check = g_find_program_in_path ("gnome-terminal");
+		if (check != NULL) {
+			term_argv[0] = check;
+			/* Note that gnome-terminal takes -x and
+			 * as -e in gnome-terminal is broken we use that. */
+			term_argv[1] = g_strdup ("-x");
+		} else {
+			if (check == NULL)
+				check = g_find_program_in_path ("nxterm");
+			if (check == NULL)
+				check = g_find_program_in_path ("color-xterm");
+			if (check == NULL)
+				check = g_find_program_in_path ("rxvt");
+			if (check == NULL)
+				check = g_find_program_in_path ("xterm");
+			if (check == NULL)
+				check = g_find_program_in_path ("dtterm");
+			if (check == NULL) {
+				g_warning (_("Cannot find a terminal, using "
+					     "xterm, even if it may not work"));
+				check = g_strdup ("xterm");
+			}
+			term_argv[0] = check;
+			term_argv[1] = g_strdup ("-e");
+		}
+	}
+
+        real_argc = term_argc + *argc;
+        real_argv = g_new (char *, real_argc + 1);
+
+        for (i = 0; i < term_argc; i++)
+                real_argv[i] = term_argv[i];
+
+        for (j = 0; j < *argc; j++, i++)
+                real_argv[i] = (char *)the_argv[j];
+
+	real_argv[i] = NULL;
+
+	g_free (*argv);
+	*argv = real_argv;
+	*argc = real_argc;
+
+	/* we use g_free here as we sucked all the inner strings
+	 * out from it into real_argv */
+	g_free (term_argv);
+#else
+	/* FIXME: Implement when needed */
+	g_warning ("gnome_prepend_terminal_to_vector: Not implemented");
+#endif
+}

Added: trunk/libgnome-desktop/gnome-thumbnail-pixbuf-utils.c
==============================================================================
--- (empty file)
+++ trunk/libgnome-desktop/gnome-thumbnail-pixbuf-utils.c	Tue Oct  7 19:12:18 2008
@@ -0,0 +1,172 @@
+/*
+ * gnome-thumbnail-pixbuf-utils.c: Utilities for handling pixbufs when thumbnailing
+ *
+ * Copyright (C) 2002 Red Hat, Inc.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Alexander Larsson <alexl redhat com>
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include "libgnomeui/gnome-desktop-thumbnail.h"
+
+#define LOAD_BUFFER_SIZE 65536
+
+/**
+ * gnome_thumbnail_scale_down_pixbuf:
+ * @pixbuf: a #GdkPixbuf
+ * @dest_width: the desired new width
+ * @dest_height: the desired new height
+ *
+ * Scales the pixbuf to the desired size. This function
+ * is a lot faster than gdk-pixbuf when scaling down by
+ * large amounts.
+ *
+ * Return value: a scaled pixbuf
+ * 
+ * Since: 2.2
+ **/
+GdkPixbuf *
+gnome_desktop_thumbnail_scale_down_pixbuf (GdkPixbuf *pixbuf,
+					   int dest_width,
+					   int dest_height)
+{
+	int source_width, source_height;
+	int s_x1, s_y1, s_x2, s_y2;
+	int s_xfrac, s_yfrac;
+	int dx, dx_frac, dy, dy_frac;
+	div_t ddx, ddy;
+	int x, y;
+	int r, g, b, a;
+	int n_pixels;
+	gboolean has_alpha;
+	guchar *dest, *src, *xsrc, *src_pixels;
+	GdkPixbuf *dest_pixbuf;
+	int pixel_stride;
+	int source_rowstride, dest_rowstride;
+
+	if (dest_width == 0 || dest_height == 0) {
+		return NULL;
+	}
+	
+	source_width = gdk_pixbuf_get_width (pixbuf);
+	source_height = gdk_pixbuf_get_height (pixbuf);
+
+	g_assert (source_width >= dest_width);
+	g_assert (source_height >= dest_height);
+
+	ddx = div (source_width, dest_width);
+	dx = ddx.quot;
+	dx_frac = ddx.rem;
+	
+	ddy = div (source_height, dest_height);
+	dy = ddy.quot;
+	dy_frac = ddy.rem;
+
+	has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
+	source_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+	src_pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+	dest_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, has_alpha, 8,
+				      dest_width, dest_height);
+	dest = gdk_pixbuf_get_pixels (dest_pixbuf);
+	dest_rowstride = gdk_pixbuf_get_rowstride (dest_pixbuf);
+
+	pixel_stride = (has_alpha)?4:3;
+	
+	s_y1 = 0;
+	s_yfrac = -dest_height/2;
+	while (s_y1 < source_height) {
+		s_y2 = s_y1 + dy;
+		s_yfrac += dy_frac;
+		if (s_yfrac > 0) {
+			s_y2++;
+			s_yfrac -= dest_height;
+		}
+
+		s_x1 = 0;
+		s_xfrac = -dest_width/2;
+		while (s_x1 < source_width) {
+			s_x2 = s_x1 + dx;
+			s_xfrac += dx_frac;
+			if (s_xfrac > 0) {
+				s_x2++;
+				s_xfrac -= dest_width;
+			}
+
+			/* Average block of [x1,x2[ x [y1,y2[ and store in dest */
+			r = g = b = a = 0;
+			n_pixels = 0;
+
+			src = src_pixels + s_y1 * source_rowstride + s_x1 * pixel_stride;
+			for (y = s_y1; y < s_y2; y++) {
+				xsrc = src;
+				if (has_alpha) {
+					for (x = 0; x < s_x2-s_x1; x++) {
+						n_pixels++;
+						
+						r += xsrc[3] * xsrc[0];
+						g += xsrc[3] * xsrc[1];
+						b += xsrc[3] * xsrc[2];
+						a += xsrc[3];
+						xsrc += 4;
+					}
+				} else {
+					for (x = 0; x < s_x2-s_x1; x++) {
+						n_pixels++;
+						r += *xsrc++;
+						g += *xsrc++;
+						b += *xsrc++;
+					}
+				}
+				src += source_rowstride;
+			}
+			
+			if (has_alpha) {
+				if (a != 0) {
+					*dest++ = r / a;
+					*dest++ = g / a;
+					*dest++ = b / a;
+					*dest++ = a / n_pixels;
+				} else {
+					*dest++ = 0;
+					*dest++ = 0;
+					*dest++ = 0;
+					*dest++ = 0;
+				}
+			} else {
+				*dest++ = r / n_pixels;
+				*dest++ = g / n_pixels;
+				*dest++ = b / n_pixels;
+			}
+			
+			s_x1 = s_x2;
+		}
+		s_y1 = s_y2;
+		dest += dest_rowstride - dest_width * pixel_stride;
+	}
+	
+	return dest_pixbuf;
+}

Modified: trunk/libgnome-desktop/libgnome/Makefile.am
==============================================================================
--- trunk/libgnome-desktop/libgnome/Makefile.am	(original)
+++ trunk/libgnome-desktop/libgnome/Makefile.am	Tue Oct  7 19:12:18 2008
@@ -1,3 +1,4 @@
 libgnome_desktopdir = $(includedir)/gnome-desktop-2.0/libgnome
 libgnome_desktop_HEADERS = \
+	gnome-desktop-utils.h \
 	gnome-desktop-item.h

Modified: trunk/libgnome-desktop/libgnome/gnome-desktop-item.h
==============================================================================
--- trunk/libgnome-desktop/libgnome/gnome-desktop-item.h	(original)
+++ trunk/libgnome-desktop/libgnome/gnome-desktop-item.h	Tue Oct  7 19:12:18 2008
@@ -33,7 +33,6 @@
 
 #include <gdk/gdk.h>
 #include <gtk/gtk.h>
-#include <libgnomeui/gnome-icon-theme.h>
 
 G_BEGIN_DECLS
 

Added: trunk/libgnome-desktop/libgnome/gnome-desktop-utils.h
==============================================================================
--- (empty file)
+++ trunk/libgnome-desktop/libgnome/gnome-desktop-utils.h	Tue Oct  7 19:12:18 2008
@@ -0,0 +1,47 @@
+/* -*- Mode: C; c-set-style: linux indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gnome-ditem.h - Utilities for the GNOME Desktop
+
+   Copyright (C) 1998 Tom Tromey
+   All rights reserved.
+
+   This file is part of the Gnome Library.
+
+   The Gnome Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+   
+   The Gnome Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+   
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+/*
+  @NOTATION@
+ */
+
+#ifndef GNOME_DESKTOP_UTILS_H
+#define GNOME_DESKTOP_UTILS_H
+
+#ifndef GNOME_DESKTOP_USE_UNSTABLE_API
+#error    gnome-desktop-utils is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including gnome-desktop-utils.h
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+/* prepend the terminal command to a vector */
+void gnome_desktop_prepend_terminal_to_vector (int *argc, char ***argv);
+
+G_END_DECLS
+
+#endif /* GNOME_DITEM_H */

Modified: trunk/libgnome-desktop/libgnomeui/Makefile.am
==============================================================================
--- trunk/libgnome-desktop/libgnomeui/Makefile.am	(original)
+++ trunk/libgnome-desktop/libgnomeui/Makefile.am	Tue Oct  7 19:12:18 2008
@@ -1,8 +1,7 @@
 libgnomeui_desktopdir = $(includedir)/gnome-desktop-2.0/libgnomeui
 libgnomeui_desktop_HEADERS =	\
-	gnome-ditem-edit.h	\
-	gnome-hint.h		\
 	gnome-bg.h		\
+	gnome-desktop-thumbnail.h \
 	gnome-rr.h		\
 	gnome-rr-config.h	\
 	gnome-rr-labeler.h

Modified: trunk/libgnome-desktop/libgnomeui/gnome-bg.h
==============================================================================
--- trunk/libgnome-desktop/libgnomeui/gnome-bg.h	(original)
+++ trunk/libgnome-desktop/libgnomeui/gnome-bg.h	Tue Oct  7 19:12:18 2008
@@ -29,9 +29,9 @@
 #error    GnomeBG is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including gnome-bg.h
 #endif
 
-#include <libgnomeui/libgnomeui.h>
 #include <gdk/gdk.h>
 #include <gconf/gconf-client.h>
+#include <libgnomeui/gnome-desktop-thumbnail.h>
 
 G_BEGIN_DECLS
 
@@ -93,11 +93,11 @@
 						 int                    height,
 						 gboolean               root);
 gboolean         gnome_bg_get_image_size        (GnomeBG               *bg,
-						 GnomeThumbnailFactory *factory,
+						 GnomeDesktopThumbnailFactory *factory,
 						 int                   *width,
 						 int                   *height);
 GdkPixbuf *      gnome_bg_create_thumbnail      (GnomeBG               *bg,
-						 GnomeThumbnailFactory *factory,
+						 GnomeDesktopThumbnailFactory *factory,
 						 GdkScreen             *screen,
 						 int                    dest_width,
 						 int                    dest_height);

Added: trunk/libgnome-desktop/libgnomeui/gnome-desktop-thumbnail.h
==============================================================================
--- (empty file)
+++ trunk/libgnome-desktop/libgnomeui/gnome-desktop-thumbnail.h	Tue Oct  7 19:12:18 2008
@@ -0,0 +1,110 @@
+/*
+ * gnome-thumbnail.h: Utilities for handling thumbnails
+ *
+ * Copyright (C) 2002 Red Hat, Inc.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Alexander Larsson <alexl redhat com>
+ */
+
+#ifndef GNOME_DESKTOP_THUMBNAIL_H
+#define GNOME_DESKTOP_THUMBNAIL_H
+
+#ifndef GNOME_DESKTOP_USE_UNSTABLE_API
+#error    GnomeDesktopThumbnail is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including gnome-desktop-thumbnail.h
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+#include <time.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+  GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL,
+  GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE
+} GnomeDesktopThumbnailSize;
+
+#define GNOME_TYPE_THUMBNAIL_FACTORY		(gnome_desktop_thumbnail_factory_get_type ())
+#define GNOME_DESKTOP_THUMBNAIL_FACTORY(obj)	(G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_THUMBNAIL_FACTORY, GnomeDesktopThumbnailFactory))
+#define GNOME_DESKTOP_THUMBNAIL_FACTORY_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_THUMBNAIL_FACTORY, GnomeDesktopThumbnailFactoryClass))
+#define GNOME_IS_THUMBNAIL_FACTORY(obj)		(G_TYPE_INSTANCE_CHECK_TYPE ((obj), GNOME_TYPE_THUMBNAIL_FACTORY))
+#define GNOME_IS_THUMBNAIL_FACTORY_CLASS(klass)	(G_TYPE_CLASS_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_THUMBNAIL_FACTORY))
+
+typedef struct _GnomeDesktopThumbnailFactory        GnomeDesktopThumbnailFactory;
+typedef struct _GnomeDesktopThumbnailFactoryClass   GnomeDesktopThumbnailFactoryClass;
+typedef struct _GnomeDesktopThumbnailFactoryPrivate GnomeDesktopThumbnailFactoryPrivate;
+
+struct _GnomeDesktopThumbnailFactory {
+	GObject parent;
+	
+	GnomeDesktopThumbnailFactoryPrivate *priv;
+};
+
+struct _GnomeDesktopThumbnailFactoryClass {
+	GObjectClass parent;
+};
+
+GType                  gnome_desktop_thumbnail_factory_get_type (void);
+GnomeDesktopThumbnailFactory *gnome_desktop_thumbnail_factory_new      (GnomeDesktopThumbnailSize     size);
+
+char *                 gnome_desktop_thumbnail_factory_lookup   (GnomeDesktopThumbnailFactory *factory,
+								 const char            *uri,
+								 time_t                 mtime);
+
+gboolean               gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (GnomeDesktopThumbnailFactory *factory,
+										   const char            *uri,
+										   time_t                 mtime);
+gboolean               gnome_desktop_thumbnail_factory_can_thumbnail (GnomeDesktopThumbnailFactory *factory,
+								      const char            *uri,
+								      const char            *mime_type,
+								      time_t                 mtime);
+GdkPixbuf *            gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory *factory,
+									   const char            *uri,
+									   const char            *mime_type);
+void                   gnome_desktop_thumbnail_factory_save_thumbnail (GnomeDesktopThumbnailFactory *factory,
+								       GdkPixbuf             *thumbnail,
+								       const char            *uri,
+								       time_t                 original_mtime);
+void                   gnome_desktop_thumbnail_factory_create_failed_thumbnail (GnomeDesktopThumbnailFactory *factory,
+										const char            *uri,
+										time_t                 mtime);
+
+
+/* Thumbnailing utils: */
+gboolean   gnome_desktop_thumbnail_has_uri           (GdkPixbuf          *pixbuf,
+						      const char         *uri);
+gboolean   gnome_desktop_thumbnail_is_valid          (GdkPixbuf          *pixbuf,
+						      const char         *uri,
+						      time_t              mtime);
+char *     gnome_desktop_thumbnail_md5               (const char         *uri);
+char *     gnome_desktop_thumbnail_path_for_uri      (const char         *uri,
+						      GnomeDesktopThumbnailSize  size);
+
+
+/* Pixbuf utils */
+
+GdkPixbuf *gnome_desktop_thumbnail_scale_down_pixbuf (GdkPixbuf          *pixbuf,
+						      int                 dest_width,
+						      int                 dest_height);
+
+G_END_DECLS
+
+#endif /* GNOME_DESKTOP_THUMBNAIL_H */

Modified: trunk/libgnome-desktop/test-ditem.c
==============================================================================
--- trunk/libgnome-desktop/test-ditem.c	(original)
+++ trunk/libgnome-desktop/test-ditem.c	Tue Oct  7 19:12:18 2008
@@ -18,13 +18,9 @@
 
 #include <config.h>
 #include <string.h>
-#include <libgnome/libgnome.h>
-#include <libgnomeui/libgnomeui.h>
+#include <unistd.h>
 
 #include <libgnome/gnome-desktop-item.h>
-/*
-#include <libgnomeui/gnome-ditem-edit.h>
-*/
 
 #include <locale.h>
 #include <stdlib.h>
@@ -149,9 +145,7 @@
 
 	file = g_strdup (argv[1]);
 
-	gnome_program_init ("test-ditem", "0.01",
-			    LIBGNOMEUI_MODULE,
-			    argc, argv, NULL);
+	gtk_init (&argc, &argv);
 
 	if (launch)
 		launch_item (file);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]