File evince-2.32.0-metadata.patch of Package mingw32-evince

diff -Naur evince-2.32.0/configure.ac evince-2.32.0.new/configure.ac
--- evince-2.32.0/configure.ac	2011-07-26 18:13:18.614571661 +0200
+++ evince-2.32.0.new/configure.ac	2011-07-26 18:13:50.294728757 +0200
@@ -286,6 +286,30 @@
         AC_DEFINE([WITH_KEYRING],[1],[Define if KEYRING support is enabled])
 fi
 
+# *********************
+# Metadata support 
+# *********************
+
+AC_MSG_CHECKING([which metadata backend to use])
+AC_ARG_WITH([metadata],
+  [AS_HELP_STRING([--with-metadata=gvfs|builtin],
+                  [Setting metadata backend ])],
+  [case "$withval" in
+    gvfs|builtin) ;;
+    *) AC_MSG_ERROR([invalid argument "$withval" for --with-metadata]) ;;
+   esac],
+  [case "$host" in
+     *-*-mingw*|*-*-cygwin*) with_metadata="builtin" ;;
+     *) with_metadata=gvfs ;;
+   esac])
+AC_MSG_RESULT([$with_metadata])
+
+if test "$with_metadata" = "builtin"; then
+  AC_DEFINE([WITH_METADATA_BUILTIN],[1],[Define to build builtin metadata support])
+fi
+AM_CONDITIONAL([WITH_METADATA_BUILTIN], [test "$with_metadata" = "builtin"])
+ 
+
 # ****
 # DBUS
 # ****
@@ -877,6 +901,7 @@
         GConf Support......:  $with_gconf
 	GTK+ Unix Print....:  $with_gtk_unix_print
 	Keyring Support....:  $with_keyring
+	Metadata support...:  $with_metadata
 	DBUS Support.......:  $enable_dbus
 	SM client support..:  $with_smclient
 	Help files.........:  $enable_help
diff -Naur evince-2.32.0/configure.ac.orig evince-2.32.0.new/configure.ac.orig
--- evince-2.32.0/configure.ac.orig	2011-07-26 18:13:18.598571586 +0200
+++ evince-2.32.0.new/configure.ac.orig	2011-07-26 18:13:34.958652708 +0200
@@ -505,6 +505,7 @@
 	    AC_CHECK_FUNCS(poppler_page_get_text_layout)
 	    AC_CHECK_FUNCS(poppler_page_get_selected_text)
 	    AC_CHECK_FUNCS(poppler_page_add_annot)
+	    AC_CHECK_FUNCS(poppler_document_is_linearized)
 	    LIBS=$evince_save_LIBS
 	    PKG_CHECK_MODULES(CAIRO_PDF, cairo-pdf, enable_cairo_pdf=yes, enable_cairo_pdf=no)
 	    if test x$enable_cairo_pdf = xyes; then
diff -Naur evince-2.32.0/shell/ev-metadata.c evince-2.32.0.new/shell/ev-metadata.c
--- evince-2.32.0/shell/ev-metadata.c	2010-07-27 17:47:54.000000000 +0200
+++ evince-2.32.0.new/shell/ev-metadata.c	2011-07-26 18:13:50.298728778 +0200
@@ -18,16 +18,24 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
+#include "config.h"
+
 #include <gio/gio.h>
 #include <string.h>
 
 #include "ev-metadata.h"
+#ifdef WITH_METADATA_BUILTIN
+#include "ev-metadata-manager.h"
+#endif
 
 struct _EvMetadata {
 	GObject base;
 
 	GFile      *file;
 	GHashTable *items;
+#ifdef WITH_METADATA_BUILTIN
+	gchar      *uri;
+#endif
 };
 
 struct _EvMetadataClass {
@@ -53,12 +61,24 @@
 		metadata->file = NULL;
 	}
 
+#ifdef WITH_METADATA_BUILTIN
+	if (metadata->uri) {
+		g_free (metadata->uri);
+		metadata->uri = NULL;
+	}
+	ev_metadata_manager_shutdown ();
+#endif
+
 	G_OBJECT_CLASS (ev_metadata_parent_class)->finalize (object);
 }
 
 static void
 ev_metadata_init (EvMetadata *metadata)
 {
+#ifdef WITH_METADATA_BUILTIN
+	ev_metadata_manager_init ();
+	metadata->uri = NULL;
+#endif
 	metadata->items = g_hash_table_new_full (g_str_hash,
 						 g_str_equal,
 						 g_free,
@@ -74,8 +94,28 @@
 }
 
 static void
+hash_metadata_manager_items (const gchar *key, 
+			     const gpointer *data,
+			     GHashTable *items)
+{
+	const GValue *value = (const GValue *)data;
+
+	g_hash_table_insert (items,
+			     g_strdup (key),
+			     g_strdup (g_value_get_string(value)));
+}
+
+static void
 ev_metadata_load (EvMetadata *metadata)
 {
+#ifdef WITH_METADATA_BUILTIN
+	GHashTable *items = ev_metadata_manager_get_items (metadata->uri);
+	if (items == NULL)
+		return;
+
+        g_hash_table_foreach (items, (GHFunc)hash_metadata_manager_items, 
+				metadata->items);
+#else
 	GFileInfo *info;
 	gchar    **attrs;
 	gint       i;
@@ -119,6 +159,7 @@
 	}
 	g_strfreev (attrs);
 	g_object_unref (info);
+#endif
 }
 
 EvMetadata *
@@ -131,6 +172,9 @@
 	metadata = EV_METADATA (g_object_new (EV_TYPE_METADATA, NULL));
 	metadata->file = g_object_ref (file);
 
+#ifdef WITH_METADATA_BUILTIN
+	metadata->uri = g_file_get_uri(file);
+#endif
 	ev_metadata_load (metadata);
 
 	return metadata;
@@ -157,6 +201,7 @@
 	return TRUE;
 }
 
+#ifndef WITH_METADATA_BUILTIN
 static void
 metadata_set_callback (GObject      *file,
 		       GAsyncResult *result,
@@ -169,12 +214,16 @@
 		g_error_free (error);
 	}
 }
+#endif
 
 gboolean
 ev_metadata_set_string (EvMetadata  *metadata,
 			const gchar *key,
 			const gchar *value)
 {
+#ifdef WITH_METADATA_BUILTIN
+	ev_metadata_manager_set_string (metadata->uri, key, value);
+#else
 	GFileInfo *info;
 	gchar     *gio_key;
 
@@ -190,7 +239,6 @@
 	}
 	g_free (gio_key);
 
-	g_hash_table_insert (metadata->items, g_strdup (key), g_strdup (value));
 	g_file_set_attributes_async (metadata->file,
 				     info,
 				     0,
@@ -199,6 +247,9 @@
 				     (GAsyncReadyCallback)metadata_set_callback,
 				     metadata);
 	g_object_unref (info);
+#endif
+
+	g_hash_table_insert (metadata->items, g_strdup (key), g_strdup (value));
 
 	return TRUE;
 }
@@ -292,6 +343,9 @@
 gboolean
 ev_is_metadata_supported_for_file (GFile *file)
 {
+#ifdef WITH_METADATA_BUILTIN
+	return TRUE;
+#else
 	GFileAttributeInfoList *namespaces;
 	gint i;
 	gboolean retval = FALSE;
@@ -310,4 +364,5 @@
 	g_file_attribute_info_list_unref (namespaces);
 
 	return retval;
+#endif
 }
diff -Naur evince-2.32.0/shell/ev-metadata-manager.c evince-2.32.0.new/shell/ev-metadata-manager.c
--- evince-2.32.0/shell/ev-metadata-manager.c	1970-01-01 01:00:00.000000000 +0100
+++ evince-2.32.0.new/shell/ev-metadata-manager.c	2011-07-26 18:13:50.298728778 +0200
@@ -0,0 +1,763 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * ev-metadata-manager.c
+ * This file is part of ev
+ *
+ * Copyright (C) 2003  Paolo Maggi 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, 
+ * Boston, MA 02111-1307, USA. 
+ */
+ 
+/*
+ * Modified by the ev Team, 2003. See the AUTHORS file for a 
+ * list of people on the ev Team.  
+ * See the ChangeLog files for a list of changes. 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <time.h>
+#include <stdlib.h>
+
+#include <libxml/xmlreader.h>
+
+#include "ev-metadata-manager.h"
+#include "ev-application.h"
+#include "ev-file-helpers.h"
+
+#define METADATA_FILE 	"ev-metadata.xml"
+
+#define MAX_ITEMS	50
+
+typedef struct _EvMetadataManager EvMetadataManager;
+
+typedef struct _Item Item;
+
+struct _Item
+{
+	time_t	 	 atime; /* time of last access */
+
+	GHashTable	*values;
+};
+	
+struct _EvMetadataManager
+{
+	guint		 ref;
+	gboolean	 values_loaded; /* It is true if the file 
+					   has been read */
+
+	guint 		 timeout_id;
+
+	GHashTable	*items;
+};
+
+static gboolean ev_metadata_manager_save (gpointer data);
+
+
+static EvMetadataManager *ev_metadata_manager = NULL;
+
+/**
+ * item_free:
+ * @data: a pointer to a #Item data
+ *
+ * It does free the values on the #GHashTable where data points.
+ */
+static void
+item_free (gpointer data)
+{
+	Item *item = (Item *) data;
+
+	if (item->values != NULL)
+		g_hash_table_destroy (item->values);
+
+	g_slice_free (Item, item);
+}
+
+/**
+ * ev_metadata_arm_timeout
+ *
+ * Setup a timeout for saving the metadata to disk.
+ */
+static void
+ev_metadata_arm_timeout(void)
+{
+	if (ev_metadata_manager->timeout_id)
+		return;
+
+	ev_metadata_manager->timeout_id =
+		g_timeout_add_seconds_full (G_PRIORITY_DEFAULT_IDLE,
+					    2,
+					    (GSourceFunc)ev_metadata_manager_save,
+					    NULL,
+					    NULL);
+}
+
+/**
+ * ev_metadata_manager_init:
+ *
+ * Creates an EvMetadataManager with default values.
+ *
+ *  values_loaded   ->  %FALSE.
+ *  timeout_id      ->  the id of the event source.
+ *  items           ->  a new full empty #GHashTable.
+ */
+void
+ev_metadata_manager_init (void)
+{
+	if (ev_metadata_manager != NULL) {
+		ev_metadata_manager->ref++;
+		return;
+	}
+
+	ev_metadata_manager = g_slice_new0 (EvMetadataManager);
+
+	ev_metadata_manager->values_loaded = FALSE;
+
+	ev_metadata_manager->items = 
+		g_hash_table_new_full (g_str_hash, 
+				       g_str_equal, 
+				       g_free,
+				       item_free);
+}
+
+/* This function must be called before exiting ev */
+void
+ev_metadata_manager_shutdown (void)
+{
+	if (ev_metadata_manager == NULL)
+		return;
+
+	ev_metadata_manager->ref--;
+	if (ev_metadata_manager->ref)
+		return;
+
+	if (ev_metadata_manager->timeout_id) {
+		g_source_remove (ev_metadata_manager->timeout_id);
+		ev_metadata_manager->timeout_id = 0;
+		ev_metadata_manager_save (NULL);
+	}
+
+	if (ev_metadata_manager->items != NULL)
+		g_hash_table_destroy (ev_metadata_manager->items);
+
+	g_slice_free (EvMetadataManager, ev_metadata_manager);
+	ev_metadata_manager = NULL;
+}
+
+static void
+value_free (gpointer data)
+{
+	GValue *value = (GValue *)data;
+
+	g_value_unset (value);
+	g_slice_free (GValue, value);
+}
+
+static GValue *
+parse_value (xmlChar *value, xmlChar *type)
+{
+	GType ret_type;
+	GValue *ret;
+
+	ret_type = g_type_from_name ((char *)type);
+	ret = g_slice_new0 (GValue);
+	g_value_init (ret, ret_type);
+
+	switch (ret_type) {
+		case G_TYPE_STRING:
+			g_value_set_string (ret, (char *)value);
+			break;
+		case G_TYPE_INT:
+			g_value_set_int (ret, g_ascii_strtoull ((char *)value, NULL, 0));
+			break;
+		case G_TYPE_DOUBLE:
+			g_value_set_double (ret, g_ascii_strtod ((char *)value, NULL));
+			break;
+		case G_TYPE_BOOLEAN:
+			g_value_set_boolean (ret, g_ascii_strtoull ((char *)value, NULL, 0));
+			break;
+	}
+
+	return ret;
+}
+
+static void
+parseItem (xmlDocPtr doc, xmlNodePtr cur)
+{
+	Item *item;
+	
+	xmlChar *uri;
+	xmlChar *atime;
+	
+	if (xmlStrcmp (cur->name, (const xmlChar *)"document") != 0)
+			return;
+
+	uri = xmlGetProp (cur, (const xmlChar *)"uri");
+	if (uri == NULL)
+		return;
+	
+	atime = xmlGetProp (cur, (const xmlChar *)"atime");
+	if (atime == NULL)
+	{
+		xmlFree (uri);
+		return;
+	}
+
+	item = g_slice_new0 (Item);
+
+	item->atime = g_ascii_strtoull((char*)atime, NULL, 0);
+	
+	item->values = g_hash_table_new_full (g_str_hash, 
+					      g_str_equal, 
+					      g_free, 
+					      value_free);
+
+	cur = cur->xmlChildrenNode;
+		
+	while (cur != NULL)
+	{
+		if (xmlStrcmp (cur->name, (const xmlChar *)"entry") == 0)
+		{
+			xmlChar *key;
+			xmlChar *xml_value;
+			xmlChar *type;
+			GValue  *value;
+			
+			key = xmlGetProp (cur, (const xmlChar *)"key");
+			xml_value = xmlGetProp (cur, (const xmlChar *)"value");
+			type = xmlGetProp (cur, (const xmlChar *)"type");
+			value = parse_value (xml_value, type);
+
+			if ((key != NULL) && (value != NULL))
+				g_hash_table_insert (item->values,
+						     xmlStrdup (key), 
+						     value);
+
+			if (key != NULL)
+				xmlFree (key);
+			if (type != NULL)
+				xmlFree (type);
+			if (xml_value != NULL)
+				xmlFree (xml_value);
+		}
+		
+		cur = cur->next;
+	}
+
+	g_hash_table_insert (ev_metadata_manager->items,
+			     xmlStrdup (uri),
+			     item);
+
+	xmlFree (uri);
+	xmlFree (atime);
+}
+
+static gboolean
+load_values ()
+{
+	xmlDocPtr doc;
+	xmlNodePtr cur;
+	gchar *file_name;
+
+	g_return_val_if_fail (ev_metadata_manager != NULL, FALSE);
+	g_return_val_if_fail (ev_metadata_manager->values_loaded == FALSE, FALSE);
+
+	ev_metadata_manager->values_loaded = TRUE;
+		
+	xmlKeepBlanksDefault (0);
+
+	/* FIXME: file locking - Paolo */
+	file_name = g_build_filename (ev_application_get_dot_dir (EV_APP, TRUE), METADATA_FILE, NULL);
+	if (!g_file_test (file_name, G_FILE_TEST_EXISTS))
+	{
+		g_free (file_name);
+		return FALSE;
+	}
+
+	doc = xmlParseFile (file_name);
+	g_free (file_name);
+
+	if (doc == NULL)
+	{
+		return FALSE;
+	}
+
+	cur = xmlDocGetRootElement (doc);
+	if (cur == NULL) 
+	{
+		g_message ("The metadata file ā€œ%sā€ is empty", METADATA_FILE);
+		xmlFreeDoc (doc);
+	
+		return FALSE;
+	}
+
+	if (xmlStrcmp (cur->name, (const xmlChar *) "metadata")) 
+	{
+		g_message ("File ā€œ%sā€ is of the wrong type", METADATA_FILE);
+		xmlFreeDoc (doc);
+		
+		return FALSE;
+	}
+
+	cur = xmlDocGetRootElement (doc);
+	cur = cur->xmlChildrenNode;
+	
+	while (cur != NULL)
+	{
+		parseItem (doc, cur);
+
+		cur = cur->next;
+	}
+
+	xmlFreeDoc (doc);
+
+	return TRUE;
+}
+
+#define LAST_URI "last-used-value"
+
+static gboolean
+ev_metadata_manager_get_last (const gchar *key,
+		        	 GValue      *value,
+				 gboolean     ignore)
+{
+	Item *item;
+	GValue *ret;
+
+	g_assert (ev_metadata_manager->values_loaded);
+	
+	if (ignore)
+		return FALSE;
+
+	item = (Item *)g_hash_table_lookup (ev_metadata_manager->items,
+					    LAST_URI);
+
+	if (item == NULL)
+		return FALSE;
+
+	item->atime = time (NULL);
+	
+	if (item->values == NULL)
+		return FALSE;
+	
+	ret = (GValue *)g_hash_table_lookup (item->values, key);
+
+	if (ret != NULL) {
+		g_value_init (value, G_VALUE_TYPE (ret));
+		g_value_copy (ret, value);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static void
+ev_metadata_manager_set_last (const gchar *key,
+		              const GValue *value)
+{
+	Item *item;
+	
+	g_assert (ev_metadata_manager->values_loaded);
+
+	item = (Item *)g_hash_table_lookup (ev_metadata_manager->items,
+					    LAST_URI);
+
+	if (item == NULL)
+	{
+		item = g_slice_new0 (Item);
+
+		g_hash_table_insert (ev_metadata_manager->items,
+				     g_strdup (LAST_URI),
+				     item);
+	}
+	
+	if (item->values == NULL)
+		 item->values = g_hash_table_new_full (g_str_hash, 
+				 		       g_str_equal, 
+						       g_free, 
+						       value_free);
+	if (value != NULL) {
+		GValue *new;
+
+		new = g_slice_new0 (GValue);
+	        g_value_init (new, G_VALUE_TYPE (value));
+	        g_value_copy (value, new);
+
+		g_hash_table_insert (item->values,
+				     g_strdup (key),
+				     new);
+	} else {
+		g_hash_table_remove (item->values,
+				     key);
+	}
+
+	item->atime = time (NULL);
+	ev_metadata_arm_timeout ();
+	return;
+}
+				 
+GHashTable *
+ev_metadata_manager_get_items (const gchar *uri)
+{
+	Item *item;
+
+	if (uri == NULL)
+		return NULL;
+
+	if (!ev_metadata_manager->values_loaded) {
+		load_values ();
+	}
+
+	item = (Item *) g_hash_table_lookup (
+		ev_metadata_manager->items, uri);
+	if (item == NULL)
+		return NULL;
+
+	return item->values;
+}
+
+/**
+ * ev_metadata_manager_get:
+ * @uri: Uri to set data for, if @NULL, we return default value
+ * @key: Key to set uri
+ * @value: GValue struct filled up with value
+ * @ignore_last: if @TRUE, default value is ignored
+ * 
+ * Retrieve value for uri in metadata database
+ * 
+ * Returns: @TRUE if value was taken.
+ **/
+gboolean
+ev_metadata_manager_get (const gchar *uri,
+			 const gchar *key,
+			 GValue      *value, 
+			 gboolean     ignore_last)
+{
+	Item *item;
+	GValue *ret;
+	
+	g_return_val_if_fail (key != NULL, FALSE);
+
+	if (ev_metadata_manager == NULL)
+		return FALSE;
+
+	if (!ev_metadata_manager->values_loaded)
+	{
+		gboolean res;
+
+		res = load_values ();
+
+		if (!res)
+			return ev_metadata_manager_get_last (key, value, ignore_last);
+	}
+
+	if (uri == NULL)
+		return ev_metadata_manager_get_last (key, value, ignore_last);
+
+	item = (Item *)g_hash_table_lookup (ev_metadata_manager->items,
+					    uri);
+
+	if (item == NULL)
+		return ev_metadata_manager_get_last (key, value, ignore_last);
+
+	item->atime = time (NULL);
+	
+	if (item->values == NULL)
+		return ev_metadata_manager_get_last (key, value, ignore_last);
+	
+	ret = (GValue *)g_hash_table_lookup (item->values, key);
+
+	if (ret != NULL) {
+		g_value_init (value, G_VALUE_TYPE (ret));
+		g_value_copy (ret, value);
+		return TRUE;
+	}
+
+	return ev_metadata_manager_get_last (key, value, ignore_last);
+}
+
+/**
+ * ev_metadata_manager_set:
+ * @uri: Uri to set data for, if @NULL, we set default value
+ * @key: Key to set uri
+ * @value: GValue struct containing value
+ * 
+ * Set value for key in metadata database
+ **/
+void
+ev_metadata_manager_set (const gchar  *uri,
+			 const gchar  *key,
+			 const GValue *value)
+{
+	Item *item;
+
+	g_return_if_fail (key != NULL);
+
+	if (ev_metadata_manager == NULL)
+		return;
+
+	if (!ev_metadata_manager->values_loaded)
+	{
+		gboolean res;
+
+		res = load_values ();
+
+		if (!res)
+			return;
+	}
+
+	if (uri == NULL)
+	{
+		ev_metadata_manager_set_last (key, value);
+		return;
+	}
+
+	item = (Item *)g_hash_table_lookup (ev_metadata_manager->items,
+					    uri);
+
+	if (item == NULL)
+	{
+		item = g_slice_new0 (Item);
+
+		g_hash_table_insert (ev_metadata_manager->items,
+				     g_strdup (uri),
+				     item);
+	}
+	
+	if (item->values == NULL)
+		 item->values = g_hash_table_new_full (g_str_hash, 
+				 		       g_str_equal, 
+						       g_free, 
+						       value_free);
+	if (value != NULL) {
+		GValue *new;
+
+		new = g_slice_new0 (GValue);
+	        g_value_init (new, G_VALUE_TYPE (value));
+	        g_value_copy (value, new);
+
+		g_hash_table_insert (item->values,
+				     g_strdup (key),
+				     new);
+		ev_metadata_manager_set_last (key, value);
+	} else {
+		g_hash_table_remove (item->values,
+				     key);
+	}
+
+	item->atime = time (NULL);
+
+	ev_metadata_arm_timeout ();
+}
+
+static void
+save_values (const gchar *key, GValue *value, xmlNodePtr parent)
+{
+	char *string_value;
+	xmlNodePtr xml_node;
+	
+	g_return_if_fail (key != NULL);
+	
+	if (value == NULL)
+		return;
+		
+	xml_node = xmlNewChild (parent, NULL, (const xmlChar *)"entry", NULL);
+
+	xmlSetProp (xml_node, (const xmlChar *)"key", (const xmlChar *)key);
+	xmlSetProp (xml_node,
+		    (const xmlChar *)"type",
+		    (const xmlChar *)g_type_name (G_VALUE_TYPE (value)));
+
+	switch (G_VALUE_TYPE (value)) {
+		case G_TYPE_STRING:
+			string_value = g_value_dup_string (value);
+                        break;
+                case G_TYPE_INT:
+			string_value = g_strdup_printf ("%d", g_value_get_int (value));
+                        break;
+                case G_TYPE_DOUBLE:
+            		{
+            			gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
+            			g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, g_value_get_double (value));
+				string_value = g_strdup (buf);
+			}
+            	        break;
+                case G_TYPE_BOOLEAN:
+			string_value = g_strdup_printf ("%d", g_value_get_boolean (value));
+                        break;
+		default:
+			string_value = NULL;
+			g_assert_not_reached ();
+	}
+
+	xmlSetProp (xml_node, (const xmlChar *)"value", (const xmlChar *)string_value);
+
+	g_free (string_value);
+}
+
+static void
+save_item (const gchar *key, const gpointer *data, xmlNodePtr parent)
+{	
+	xmlNodePtr xml_node;
+	const Item *item = (const Item *)data;
+	gchar *atime;
+
+	g_return_if_fail (key != NULL);
+	
+	if (item == NULL)
+		return;
+		
+	xml_node = xmlNewChild (parent, NULL, (const xmlChar *)"document", NULL);
+	
+	xmlSetProp (xml_node, (const xmlChar *)"uri", (const xmlChar *)key);
+
+	atime = g_strdup_printf ("%ld", item->atime);
+	xmlSetProp (xml_node, (const xmlChar *)"atime", (const xmlChar *)atime);
+	g_free (atime);
+
+    	g_hash_table_foreach (item->values,
+			      (GHFunc)save_values, xml_node); 
+}
+
+static void
+get_oldest (const gchar *key, const gpointer value, const gchar ** key_to_remove)
+{
+	const Item *item = (const Item *)value;
+	
+	if (*key_to_remove == NULL)
+	{
+		*key_to_remove = key;
+	}
+	else
+	{
+		const Item *item_to_remove = 
+			g_hash_table_lookup (ev_metadata_manager->items,
+					     *key_to_remove);
+
+		g_return_if_fail (item_to_remove != NULL);
+
+		if (item->atime < item_to_remove->atime)
+		{
+			*key_to_remove = key;
+		}
+	}	
+}
+
+static void
+resize_items ()
+{
+	while (g_hash_table_size (ev_metadata_manager->items) > MAX_ITEMS)
+	{
+		gpointer key_to_remove = NULL;
+
+		g_hash_table_foreach (ev_metadata_manager->items,
+				      (GHFunc)get_oldest,
+				      &key_to_remove);
+
+		g_return_if_fail (key_to_remove != NULL);
+		
+		g_hash_table_remove (ev_metadata_manager->items,
+				     key_to_remove);
+	}
+}
+
+static gboolean
+ev_metadata_manager_save (gpointer data)
+{	
+	xmlDocPtr  doc;
+	xmlNodePtr root;
+	gchar *file_name;
+
+	ev_metadata_manager->timeout_id = 0;
+
+	resize_items ();
+		
+	xmlIndentTreeOutput = TRUE;
+
+	doc = xmlNewDoc ((const xmlChar *)"1.0");
+	if (doc == NULL)
+		return TRUE;
+
+	/* Create metadata root */
+	root = xmlNewDocNode (doc, NULL, (const xmlChar *)"metadata", NULL);
+	xmlDocSetRootElement (doc, root);
+
+    	g_hash_table_foreach (ev_metadata_manager->items,
+			  (GHFunc)save_item, root);        
+
+	/* FIXME: lock file - Paolo */
+	file_name = g_build_filename (ev_application_get_dot_dir (EV_APP, TRUE), METADATA_FILE, NULL);
+	xmlSaveFormatFile (file_name, doc, 1);
+	g_free (file_name);
+	
+	xmlFreeDoc (doc); 
+
+	return FALSE;
+}
+
+void
+ev_metadata_manager_set_int (const gchar *uri, const gchar *key, int value)
+{
+	GValue val = { 0, };
+
+	g_value_init (&val, G_TYPE_INT);
+	g_value_set_int (&val, value);
+
+	ev_metadata_manager_set (uri, key, &val);
+
+	g_value_unset (&val);
+}
+
+void
+ev_metadata_manager_set_double (const gchar *uri, const gchar *key, double value)
+{
+	GValue val = { 0, };
+
+	g_value_init (&val, G_TYPE_DOUBLE);
+	g_value_set_double (&val, value);
+
+	ev_metadata_manager_set (uri, key, &val);
+
+	g_value_unset (&val);
+}
+
+void
+ev_metadata_manager_set_string (const gchar *uri, const gchar *key, const gchar *value)
+{
+	GValue val = { 0, };
+
+	g_value_init (&val, G_TYPE_STRING);
+	g_value_set_static_string (&val, value);
+
+	ev_metadata_manager_set (uri, key, &val);
+
+	g_value_unset (&val);
+}
+
+void
+ev_metadata_manager_set_boolean (const gchar *uri, const gchar *key, gboolean value)
+{
+	GValue val = { 0, };
+
+	g_value_init (&val, G_TYPE_BOOLEAN);
+	g_value_set_boolean (&val, value);
+
+	ev_metadata_manager_set (uri, key, &val);
+
+	g_value_unset (&val);
+}
diff -Naur evince-2.32.0/shell/ev-metadata-manager.h evince-2.32.0.new/shell/ev-metadata-manager.h
--- evince-2.32.0/shell/ev-metadata-manager.h	1970-01-01 01:00:00.000000000 +0100
+++ evince-2.32.0.new/shell/ev-metadata-manager.h	2011-07-26 18:13:50.298728778 +0200
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * ev-metadata-manager.h
+ *
+ * Copyright (C) 2003  Paolo Maggi 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, 
+ * Boston, MA 02111-1307, USA. 
+ */
+ 
+#ifndef __EV_METADATA_MANAGER_H__
+#define __EV_METADATA_MANAGER_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+void		ev_metadata_manager_init	(void);
+GHashTable*	ev_metadata_manager_get_items	(const gchar *uri);
+gboolean	ev_metadata_manager_get		(const gchar  *uri,
+					 	 const gchar  *key,
+					 	 GValue       *value, 
+						 gboolean      ignore_last);
+void		ev_metadata_manager_set		(const gchar  *uri,
+					 	 const gchar  *key,
+					 	 const GValue *value);
+void		ev_metadata_manager_set_int	(const gchar  *uri,
+					 	 const gchar  *key,
+					 	 int           value);
+void		ev_metadata_manager_set_double	(const gchar  *uri,
+						 const gchar  *key,
+						 double        value);
+void		ev_metadata_manager_set_string	(const gchar  *uri,
+						 const gchar  *key,
+						 const gchar  *value);
+void		ev_metadata_manager_set_boolean (const gchar  *uri,
+						 const gchar  *key,
+						 gboolean      value);
+void		ev_metadata_manager_shutdown 	(void);
+
+G_END_DECLS
+
+#endif /* __EV_METADATA_MANAGER_H__ */
diff -Naur evince-2.32.0/shell/Makefile.am evince-2.32.0.new/shell/Makefile.am
--- evince-2.32.0/shell/Makefile.am	2010-09-27 18:54:36.000000000 +0200
+++ evince-2.32.0.new/shell/Makefile.am	2011-07-26 18:13:50.294728757 +0200
@@ -46,8 +46,8 @@
 	ev-marshal.h			\
 	ev-message-area.c		\
 	ev-message-area.h		\
-	ev-metadata.c			\
-	ev-metadata.h			\
+	ev-metadata-manager.c		\
+	ev-metadata-manager.h		\
 	ev-navigation-action.c		\
 	ev-navigation-action.h		\
 	ev-navigation-action-widget.c	\
@@ -86,6 +86,12 @@
 	ev-sidebar-thumbnails.h		\
 	main.c
 
+if WITH_METADATA_BUILTIN
+evince_SOURCES += \
+	ev-metadata.c			\
+	ev-metadata.h
+endif
+
 if ENABLE_DBUS
 evince_SOURCES += \
 	ev-media-player-keys.c \
diff -Naur evince-2.32.0/shell/Makefile.am.orig evince-2.32.0.new/shell/Makefile.am.orig
--- evince-2.32.0/shell/Makefile.am.orig	1970-01-01 01:00:00.000000000 +0100
+++ evince-2.32.0.new/shell/Makefile.am.orig	2011-07-26 18:13:34.890652377 +0200
@@ -0,0 +1,160 @@
+INCLUDES=							\
+	-DEVINCEDATADIR=\"$(pkgdatadir)\"				\
+	-DGNOMEDATADIR=\"$(datadir)\"				\
+	-I$(top_srcdir)						\
+	-I$(top_builddir)					\
+	-I$(top_srcdir)/cut-n-paste/zoom-control/		\
+	-I$(top_srcdir)/cut-n-paste/toolbar-editor/		\
+	-I$(top_srcdir)/cut-n-paste/totem-screensaver/		\
+	-I$(top_srcdir)/cut-n-paste/gimpcellrenderertoggle/	\
+	-I$(top_srcdir)/cut-n-paste/smclient/			\
+	-I$(top_srcdir)/libdocument				\
+	-I$(top_builddir)/libdocument				\
+	-I$(top_srcdir)/libview					\
+	-I$(top_builddir)/libview				\
+	-I$(top_srcdir)/libmisc					\
+	-I$(top_srcdir)/properties				\
+	-DGNOMEICONDIR=\""$(datadir)/pixmaps"\" 		\
+	-DBINDIR=\""$(bindir)"\"				\
+	-DLIBEXECDIR=\""$(libexecdir)"\"			\
+	-DEVINCE_COMPILATION					\
+	$(SHELL_CFLAGS)						\
+	$(WARN_CFLAGS)						\
+	$(DISABLE_DEPRECATED)
+
+bin_PROGRAMS=evince
+
+libexec_PROGRAMS=evince-convert-metadata
+if ENABLE_DBUS
+libexec_PROGRAMS += evinced
+endif
+
+evince_SOURCES=				\
+	eggfindbar.c			\
+	eggfindbar.h			\
+	ev-annotation-properties-dialog.h \
+	ev-annotation-properties-dialog.c \
+	ev-application.c		\
+	ev-application.h		\
+	ev-file-monitor.h		\
+	ev-file-monitor.c		\
+	ev-history.c			\
+	ev-history.h			\
+	ev-keyring.h			\
+	ev-keyring.c			\
+	ev-marshal.c			\
+	ev-marshal.h			\
+	ev-message-area.c		\
+	ev-message-area.h		\
+	ev-metadata.c			\
+	ev-metadata.h			\
+	ev-navigation-action.c		\
+	ev-navigation-action.h		\
+	ev-navigation-action-widget.c	\
+	ev-navigation-action-widget.h	\
+	ev-password-view.h		\
+	ev-password-view.c		\
+	ev-progress-message-area.h	\
+	ev-progress-message-area.c	\
+	ev-properties-dialog.c		\
+	ev-properties-dialog.h		\
+	ev-properties-fonts.c		\
+	ev-properties-fonts.h		\
+	ev-properties-license.c		\
+	ev-properties-license.h		\
+	ev-open-recent-action.c		\
+	ev-open-recent-action.h		\
+	ev-utils.c			\
+	ev-utils.h			\
+	ev-window.c			\
+	ev-window.h			\
+	ev-window-title.c		\
+	ev-window-title.h		\
+	ev-sidebar.c			\
+	ev-sidebar.h			\
+	ev-sidebar-annotations.c	\
+	ev-sidebar-annotations.h	\
+	ev-sidebar-attachments.c	\
+	ev-sidebar-attachments.h	\
+	ev-sidebar-layers.c		\
+	ev-sidebar-layers.h		\
+	ev-sidebar-links.c		\
+	ev-sidebar-links.h		\
+	ev-sidebar-page.c		\
+	ev-sidebar-page.h		\
+	ev-sidebar-thumbnails.c		\
+	ev-sidebar-thumbnails.h		\
+	main.c
+
+if ENABLE_DBUS
+evince_SOURCES += \
+	ev-media-player-keys.c \
+	ev-media-player-keys.h
+endif
+
+
+evince_LDFLAGS = $(AM_LDFLAGS)
+
+if PLATFORM_WIN32
+evince_LDFLAGS += -mwindows
+endif
+
+evince_LDADD=										\
+	$(top_builddir)/cut-n-paste/zoom-control/libephyzoom.la				\
+	$(top_builddir)/cut-n-paste/toolbar-editor/libtoolbareditor.la			\
+	$(top_builddir)/cut-n-paste/totem-screensaver/libtotemscrsaver.la		\
+	$(top_builddir)/cut-n-paste/gimpcellrenderertoggle/libgimpcellrenderertoggle.la	\
+	$(top_builddir)/cut-n-paste/smclient/libsmclient.la				\
+	$(top_builddir)/properties/libevproperties.la					\
+	$(top_builddir)/libdocument/libevdocument.la					\
+	$(top_builddir)/libview/libevview.la						\
+	$(top_builddir)/libmisc/libevmisc.la						\
+	$(SHELL_LIBS)
+
+if PLATFORM_WIN32
+evince_LDADD += evince-icon.o
+
+evince-icon.o: $(srcdir)/evince-icon.rc $(top_srcdir)/data/evince.ico
+	$(WINDRES) $(srcdir)/evince-icon.rc -I $(top_srcdir)/data evince-icon.o
+endif
+
+BUILT_SOURCES = ev-marshal.h ev-marshal.c
+
+evince_convert_metadata_SOURCES=	\
+	ev-convert-metadata.c
+
+evince_convert_metadata_LDADD=		\
+	$(SHELL_LIBS)
+
+if ENABLE_DBUS
+evinced_SOURCES=			\
+	ev-daemon.c
+
+evinced_CFLAGS=				\
+	-DEVINCEDATADIR=\"$(pkgdatadir)\"			\
+	-DGNOMEDATADIR=\"$(datadir)\"				\
+	-I$(top_srcdir)						\
+	-I$(top_builddir)					\
+	-DLIBEXECDIR=\""$(libexecdir)"\"			\
+	-DEVINCE_COMPILATION					\
+	$(EV_DAEMON_CFLAGS)					\
+	$(WARN_CFLAGS)						\
+	$(DISABLE_DEPRECATED)
+
+evinced_LDADD=				\
+	$(EV_DAEMON_LIBS)
+endif
+
+EXTRA_DIST = ev-marshal.list		\
+	evince-icon.rc
+
+ev-marshal.h: $(srcdir)/ev-marshal.list
+	$(AM_V_GEN)$(GLIB_GENMARSHAL) --prefix=ev_marshal $(srcdir)/ev-marshal.list --header > ev-marshal.h
+
+ev-marshal.c: $(srcdir)/ev-marshal.list
+	echo '#include "ev-marshal.h"' > ev-marshal.c
+	$(AM_V_GEN)$(GLIB_GENMARSHAL) --prefix=ev_marshal $(srcdir)/ev-marshal.list --body >> ev-marshal.c
+
+DISTCLEANFILES =
+
+-include $(top_srcdir)/git.mk
openSUSE Build Service is sponsored by