diff -Nuarp gtk+/ChangeLog gtk+.recent/ChangeLog
--- gtk+/ChangeLog	2006-03-26 23:44:55.000000000 +0200
+++ gtk+.recent/ChangeLog	2006-03-26 23:56:02.000000000 +0200
@@ -1,3 +1,31 @@
+2006-03-26  Emmanuele Bassi  <ebassi@cvs.gnome.org>
+
+	* configure.in: Require the development version of GLib.
+
+	* gtk/gtk.h:
+	* gtk/Makefile.am:
+	* gtk/gtkrecentchooser.[ch]:
+	* gtk/gtkrecentchooserdefault.[ch]:
+	* gtk/gtkrecentchooserdialog.[ch]:
+	* gtk/gtkrecentchoosermenu.[ch]:
+	* gtk/gtkrecentchooserprivate.h:
+	* gtk/gtkrecentchooserutils.[ch]:
+	* gtk/gtkrecentchooserwidget.[ch]:
+	* gtk/gtkrecentfilter.[ch]:
+	* gtk/gtkrecentmanager.[ch]: Import the new EggRecent code
+	from libegg.
+
+	* tests/Makefile.am:
+	* tests/testrecentchooser.c: Test suite for the GtkRecentChooser
+	widgets.
+
+	* docs/reference/gtk/Makefile.am:
+	* docs/reference/gtk/gtk-docs.sgml:
+	* docs/reference/gtk/gtk-sections.txt:
+	* docs/reference/gtk/migrating-GtkRecentChooser.sgml: Add documentation
+	for the GtkRecent* objects, and a guide for migrating from the old
+	EggRecent code.
+
 2006-03-26  Matthias Clasen  <mclasen@redhat.com>
 
 	* gtk/Makefile.am: Fix a srcdir != builddir build problem.
diff -Nuarp gtk+/configure.in gtk+.recent/configure.in
--- gtk+/configure.in	2006-03-26 23:44:55.000000000 +0200
+++ gtk+.recent/configure.in	2006-03-26 23:47:39.000000000 +0200
@@ -31,7 +31,7 @@ m4_define([gtk_api_version], [2.0])
 m4_define([gtk_binary_version], [2.4.0])
 
 # required versions of other packages
-m4_define([glib_required_version], [2.10.1])
+m4_define([glib_required_version], [2.11.0])
 m4_define([pango_required_version], [1.9.0])
 m4_define([atk_required_version], [1.0.1])
 m4_define([cairo_required_version], [0.9.2])
diff -Nuarp gtk+/docs/reference/gtk/gtk-docs.sgml gtk+.recent/docs/reference/gtk/gtk-docs.sgml
--- gtk+/docs/reference/gtk/gtk-docs.sgml	2006-03-26 23:44:56.000000000 +0200
+++ gtk+.recent/docs/reference/gtk/gtk-docs.sgml	2006-03-26 23:45:28.000000000 +0200
@@ -91,6 +91,12 @@
 <!ENTITY GtkRadioMenuItem SYSTEM "xml/gtkradiomenuitem.xml">
 <!ENTITY GtkRadioToolButton SYSTEM "xml/gtkradiotoolbutton.xml">
 <!ENTITY GtkRange SYSTEM "xml/gtkrange.xml">
+<!ENTITY GtkRecentChooser SYSTEM "xml/gtkrecentchooser.xml">
+<!ENTITY GtkRecentChooserDialog SYSTEM "xml/gtkrecentchooserdialog.xml">
+<!ENTITY GtkRecentChooserMenu SYSTEM "xml/gtkrecentchoosermenu.xml">
+<!ENTITY GtkRecentChooserWidget SYSTEM "xml/gtkrecentchooserwidget.xml">
+<!ENTITY GtkRecentFilter SYSTEM "xml/gtkrecentfilter.xml">
+<!ENTITY GtkRecentManager SYSTEM "xml/gtkrecentmanager.xml">
 <!ENTITY GtkRuler SYSTEM "xml/gtkruler.xml">
 <!ENTITY GtkScale SYSTEM "xml/gtkscale.xml">
 <!ENTITY GtkScrollbar SYSTEM "xml/gtkscrollbar.xml">
@@ -203,6 +209,7 @@
 <!ENTITY gtk-migrating-GtkAboutDialog SYSTEM "xml/migrating-GtkAboutDialog.sgml">
 <!ENTITY gtk-migrating-GtkColorButton SYSTEM "xml/migrating-GtkColorButton.sgml">
 <!ENTITY gtk-migrating-GtkAssistant SYSTEM "xml/migrating-GtkAssistant.sgml">
+<!ENTITY gtk-migrating-GtkRecentChooser SYSTEM "xml/migrating-GtkRecentChooser.sgml">
 <!ENTITY version SYSTEM "version.xml">
 <!ENTITY gtk-query-immodules SYSTEM "gtk-query-immodules-2.0.xml">
 <!ENTITY gtk-update-icon-cache SYSTEM "gtk-update-icon-cache.xml">
@@ -321,6 +328,7 @@ that is, GUI components such as <link li
     &gtk-Clipboards;
     &gtk-Drag-and-Drop;
     &gtk-Named-Icons;
+    &GtkRecentManager;
     &gtk-Stock-Items;
     &gtk-Themeable-Stock-Images;
     &gtk-Resource-Files;   
@@ -472,6 +480,11 @@ that is, GUI components such as <link li
         &GtkFontSelection;
         &GtkFontSelectionDialog;
         &GtkInputDialog;
+	&GtkRecentChooser;
+	&GtkRecentChooserDialog;
+	&GtkRecentChooserMenu;
+	&GtkRecentChooserWidget;
+	&GtkRecentFilter;
     </chapter>
     
     <chapter id="LayoutContainers">
@@ -597,6 +610,7 @@ that is, GUI components such as <link li
     &gtk-migrating-GtkAboutDialog;
     &gtk-migrating-GtkColorButton;
     &gtk-migrating-GtkAssistant;
+    &gtk-migrating-GtkRecentChooser;
   </part>
 
   <part>
diff -Nuarp gtk+/docs/reference/gtk/gtk-sections.txt gtk+.recent/docs/reference/gtk/gtk-sections.txt
--- gtk+/docs/reference/gtk/gtk-sections.txt	2006-03-26 23:44:56.000000000 +0200
+++ gtk+.recent/docs/reference/gtk/gtk-sections.txt	2006-03-26 23:45:28.000000000 +0200
@@ -2747,6 +2747,202 @@ GtkRangeStepTimer
 </SECTION>
 
 <SECTION>
+<FILE>gtkrecentchooser</FILE>
+<TITLE>GtkRecentChooser</TITLE>
+GtkRecentChooser
+GtkRecentChooserIface
+GTK_RECENT_CHOOSER_ERROR
+GtkRecentChooserError
+gtk_recent_chooser_set_show_private
+gtk_recent_chooser_get_show_private
+gtk_recent_chooser_set_show_not_found
+gtk_recent_chooser_get_show_not_found
+gtk_recent_chooser_set_show_icons
+gtk_recent_chooser_get_show_icons
+gtk_recent_chooser_set_select_multiple
+gtk_recent_chooser_get_select_multiple
+gtk_recent_chooser_set_local_only
+gtk_recent_chooser_get_local_only
+gtk_recent_chooser_set_limit
+gtk_recent_chooser_get_limit
+gtk_recent_chooser_set_show_tips
+gtk_recent_chooser_get_show_tips
+gtk_recent_chooser_set_show_numbers
+gtk_recent_chooser_get_show_numbers
+gtk_recent_chooser_set_sort_type
+gtk_recent_chooser_get_sort_type
+gtk_recent_chooser_set_sort_func
+gtk_recent_chooser_set_current_uri
+gtk_recent_chooser_get_current_uri
+gtk_recent_chooser_get_current_item
+gtk_recent_chooser_select_uri
+gtk_recent_chooser_unselect_uri
+gtk_recent_chooser_select_all
+gtk_recent_chooser_unselect_all
+gtk_recent_chooser_get_items
+gtk_recent_chooser_get_uris
+gtk_recent_chooser_add_filter
+gtk_recent_chooser_remove_filter
+gtk_recent_chooser_list_filters
+gtk_recent_chooser_set_filter
+gtk_recent_chooser_get_filter
+<SUBSECTION Standard>
+GTK_RECENT_CHOOSER
+GTK_IS_RECENT_CHOOSER
+GTK_TYPE_RECENT_CHOOSER
+GTK_RECENT_CHOOSER_GET_IFACE
+
+<SUBSECTION Private>
+gtk_recent_chooser_get_type
+gtk_recent_chooser_error_quark
+</SECTION>
+
+<SECTION>
+<FILE>gtkrecentchooserdialog</FILE>
+<TITLE>GtkRecentChooserDialog</TITLE>
+GtkRecentChooserDialog
+gtk_recent_chooser_dialog_new
+gtk_recent_chooser_dialog_new_for_manager
+<SUBSECTION Standard>
+GTK_RECENT_CHOOSER_DIALOG
+GTK_IS_RECENT_CHOOSER_DIALOG
+GTK_TYPE_RECENT_CHOOSER_DIALOG
+GTK_RECENT_CHOOSER_DIALOG_CLASS
+GTK_IS_RECENT_CHOOSER_DIALOG_CLASS
+GTK_RECENT_CHOOSER_DIALOG_GET_CLASS
+
+<SUBSECTION Private>
+gtk_recent_chooser_dialog_get_type
+GtkRecentChooserDialogPrivate
+</SECTION>
+
+<SECTION>
+<FILE>gtkrecentchoosermenu</FILE>
+<TITLE>GtkRecentChooserMenu</TITLE>
+GtkRecentChooserMenu
+gtk_recent_chooser_menu_new
+gtk_recent_chooser_menu_new_for_manager
+gtk_recent_chooser_menu_get_show_numbers
+gtk_recent_chooser_menu_set_show_numbers
+<SUBSECTION Standard>
+GTK_RECENT_CHOOSER_MENU
+GTK_IS_RECENT_CHOOSER_MENU
+GTK_TYPE_RECENT_CHOOSER_MENU
+GTK_RECENT_CHOOSER_MENU_CLASS
+GTK_IS_RECENT_CHOOSER_MENU_CLASS
+GTK_RECENT_CHOOSER_MENU_GET_CLASS
+
+<SUBSECTION Private>
+gtk_recent_chooser_menu_get_type
+GtkRecentChooserMenuPrivate
+</SECTION>
+
+<SECTION>
+<FILE>gtkrecentchooserwidget</FILE>
+<TITLE>GtkRecentChooserWidget</TITLE>
+GtkRecentChooserWidget
+gtk_recent_chooser_widget_new
+gtk_recent_chooser_widget_new_for_manager
+<SUBSECTION Standard>
+GTK_RECENT_CHOOSER_WIDGET
+GTK_IS_RECENT_CHOOSER_WIDGET
+GTK_TYPE_RECENT_CHOOSER_WIDGET
+GTK_RECENT_CHOOSER_WIDGET_CLASS
+GTK_IS_RECENT_CHOOSER_WIDGET_CLASS
+GTK_RECENT_CHOOSER_WIDGET_GET_CLASS
+
+<SUBSECTION Private>
+gtk_recent_chooser_widget_get_type
+GtkRecentChooserWidgetPrivate
+</SECTION>
+
+<SECTION>
+<FILE>gtkrecentfilter</FILE>
+<TITLE>GtkRecentFilter</TITLE>
+GtkRecentFilter
+GtkRecentFilterInfo
+GtkRecentFilterFlags
+GtkRecentFilterFunc
+gtk_recent_filter_new
+gtk_recent_filter_get_name
+gtk_recent_filter_set_name
+gtk_recent_filter_add_mime_type
+gtk_recent_filter_add_pattern
+gtk_recent_filter_add_pixbuf_formats
+gtk_recent_filter_add_application
+gtk_recent_filter_add_group
+gtk_recent_filter_add_age
+gtk_recent_filter_add_custom
+gtk_recent_filter_get_needed
+gtk_recent_filter_filter
+<SUBSECTION Standard>
+GTK_RECENT_FILTER
+GTK_IS_RECENT_FILTER
+GTK_TYPE_RECENT_FILTER
+
+<SUBSECTION Private>
+gtk_recent_filter_get_type
+</SECTION>
+
+<SECTION>
+<FILE>gtkrecentmanager</FILE>
+<TITLE>GtkRecentManager</TITLE>
+GtkRecentManager
+GtkRecentInfo
+GtkRecentData
+GTK_RECENT_MANAGER_ERROR
+GtkRecentManagerError
+gtk_recent_manager_new
+gtk_recent_manager_add_item
+gtk_recent_manager_add_full
+gtk_recent_manager_remove_item
+gtk_recent_manager_lookup_item
+gtk_recent_manager_has_item
+gtk_recent_manager_move_item
+gtk_recent_manager_get_limit
+gtk_recent_manager_set_limit
+gtk_recent_manager_get_items
+gtk_recent_manager_purge_items
+<SUBSECTION>
+gtk_recent_info_ref
+gtk_recent_info_unref
+gtk_recent_info_get_uri
+gtk_recent_info_get_display_name
+gtk_recent_info_get_description
+gtk_recent_info_get_mime_type
+gtk_recent_info_get_added
+gtk_recent_info_get_modified
+gtk_recent_info_get_visited
+gtk_recent_info_get_private_hint
+gtk_recent_info_get_application_info
+gtk_recent_info_get_applications
+gtk_recent_info_last_application
+gtk_recent_info_get_groups
+gtk_recent_info_has_group
+gtk_recent_info_get_icon
+gtk_recent_info_get_short_name
+gtk_recent_info_get_uri_display
+gtk_recent_info_get_age
+gtk_recent_info_is_local
+gtk_recent_info_exists
+gtk_recent_info_match
+<SUBSECTION Standard>
+GTK_RECENT_MANAGER
+GTK_IS_RECENT_MANAGER
+GTK_TYPE_RECENT_MANAGER
+GTK_RECENT_MANAGER_CLASS
+GTK_IS_RECENT_MANAGER_CLASS
+GTK_RECENT_MANAGER_GET_CLASS
+GTK_TYPE_RECENT_INFO
+
+<SUBSECTION Private>
+gtk_recent_manager_get_type
+gtk_recent_info_get_type
+GtkRecentManagerPrivate
+gtk_recent_manager_error_quark
+</SECTION>
+
+<SECTION>
 <FILE>gtkruler</FILE>
 <TITLE>GtkRuler</TITLE>
 GtkRuler
diff -Nuarp gtk+/docs/reference/gtk/Makefile.am gtk+.recent/docs/reference/gtk/Makefile.am
--- gtk+/docs/reference/gtk/Makefile.am	2006-03-26 23:44:56.000000000 +0200
+++ gtk+.recent/docs/reference/gtk/Makefile.am	2006-03-26 23:45:28.000000000 +0200
@@ -130,6 +130,7 @@ expand_content_files = 				\
 	migrating-GtkAboutDialog.sgml		\
 	migrating-GtkColorButton.sgml		\
 	migrating-GtkAssistant.sgml		\
+	migrating-GtkRecentChooser.sgml 	\
 	tree_widget.sgml			\
 	text_widget.sgml			\
 	question_index.sgml
diff -Nuarp gtk+/docs/reference/gtk/migrating-GtkRecentChooser.sgml gtk+.recent/docs/reference/gtk/migrating-GtkRecentChooser.sgml
--- gtk+/docs/reference/gtk/migrating-GtkRecentChooser.sgml	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/docs/reference/gtk/migrating-GtkRecentChooser.sgml	2006-03-26 23:46:04.000000000 +0200
@@ -0,0 +1,318 @@
+<chapter id="gtk-migrating-GtkRecentChooser">
+  <chapterinfo>
+    <author>
+      <firstname>Emmanuele</firstname>
+      <lastname>Bassi</lastname>
+      <affiliation>
+        <address>
+	  <email>ebassi@gmail.com</email>
+	</address>
+      </affiliation>
+    </author>
+  </chapterinfo>
+
+  <title>Migrating from EggRecent to GtkRecentChooser</title>
+
+  <para>
+    Since version 2.10, GTK+ provides a way of handling the recently used
+    documents. It is similar to the code that has lived inside the libegg
+    library and has been incorporated by many applications. The GTK+ version
+    aims to completely replace that code, and offers many distinctive features
+    that improve the registration and visualization of the recently used
+    documents, such as:
+  </para>
+
+  <para>
+    <itemizedlist>
+      <listitem><para>
+        Better performances while reading and writing the list of recently used
+	files
+      </para></listitem>
+      <listitem><para>
+        More meta-data available for each recent document, like the
+	applications that have registered a document inside the list, the last
+	time and the number of times the same application did register a
+	document inside the list, an optional user readable name and
+	description of the document
+      </para></listitem>
+      <listitem><para>
+        Improved the ability to sort and filter the documents, also using
+	custom sorting and filtering functions
+      </para></listitem>
+      <listitem><para>
+        New widgets for displaying the list, and better integration with
+	current #GtkFileChooser and #GtkUIManager widgets
+      </para></listitem>
+    </itemizedlist>
+  </para>
+
+  <section id="gtkrecent-manager">
+    <title>Managing the Recently Used Documents</title>
+
+    <para>
+      #GtkRecentManager is used to manage the Recently Used Documents. To
+      create a new #GtkRecentManager, you simply call gtk_recent_manager_new().
+      Like the <structname>EggRecentModel</structname> inside EggRecent, the
+      #GtkRecentManager loads the list of the recent documents and notifies
+      you of changes inside the list.
+    </para>
+
+    <para>
+      To add a document to the list, you can use gtk_recent_manager_add_item(),
+      like:
+      <informalexample><programlisting>
+        GtkRecentManager *manager;
+        GError *error = NULL;
+
+	manager = gtk_recent_manager_new ();
+
+	gtk_recent_manager_add_item (manager, document_uri, &amp;error);
+	if (error)
+	  {
+	    g_warning ("Unable to add '%s' to the list of recently used documents: %s\n",
+	               document_uri,
+		       error->message);
+            
+	    g_error_free (error);
+	  }
+	
+	g_object_unref (manager);
+      </programlisting></informalexample>
+      The gtk_recent_manager_add_item() function will try and guess some of the
+      meta-data associated to a URI. If you know some of meta-data about the
+      document yourself, set the desired fields of a #GtkRecentData structure
+      and pass it to the gtk_recent_manager_add_full() function instead:
+      <informalexample><programlisting>
+        GtkRecentManager *manager;
+        GtkRecentData *recent_data;
+	GError *error = NULL;
+
+	manager = gtk_recent_manager_new ();
+	
+	recent_data = g_new0 (GtkRecentData, 1);
+	/* the user visible name of the document (maybe its title); should
+	 * be preferred when displaying the item into the list
+	 */
+        recent_data-&gt;display_name = document_name;
+	
+	/* the MIME type is mandatory */
+	recent_data-&gt;mime_type = document_mime_type;
+
+	/* the name of the application that is registering the document
+	 * (also mandatory); usually, the same name you used with
+	 * the g_set_application_name() function.
+	 */
+	recent_data-&amp;app_name = APP_NAME;
+
+	/* the command to open a file; the %u string will be automagically
+	 * expanded to the document's URI when getting the application's
+	 * command line from the GtkRecentInfo object with
+	 * gtk_recent_info_get_application_info()
+	 */
+	recent_data-&amp;app_exec = g_strjoin (" ", g_get_prgname (), "--open-file", "%u", NULL);
+
+	gtk_recent_manager_add_full (manager, document_uri, recent_data, &amp;error);
+	if (error)
+	  {
+	    /* warn about the error */
+	  }
+
+	g_free (recent_data-&gt;app_exec);
+	g_free (recent_data);
+	g_object_unref (manager);
+      </programlisting></informalexample>
+    </para>
+
+    <para>
+      Getting the list of items is also similar to
+      <structname>EggRecentModel</structname>; the GtkRecentInfo data is
+      allocated at look up time in order not to waste memory keeping it
+      around, so you must remember to free the data inside the list and then
+      the list itself when you are done using it:
+      <informalexample><programlisting>
+        GList *recent_items, *l;
+
+	recent_items = gtk_recent_manager_get_items (manager);
+	for (l = recent_items; l != NULL; l = l-&gt;next)
+	  {
+	    GtkRecentInfo *recent_info = l-&gt;data;
+
+	    do_something_with_the_item (recent_info);
+	  }
+	
+	/* free everything and the list */
+	g_list_foreach (recent_items, (GFunc) gtk_recent_info_unref, NULL);
+	g_list_free (recent_items);
+      </programlisting></informalexample>
+      You can also look up a single item:
+      <informalexample><programlisting>
+        GtkRecentInfo *recent_info;
+	GError *error = NULL;
+
+	recent_info = gtk_recent_manager_lookup_item (manager, document_uri, &amp;error);
+	if (error)
+	  {
+	    display_error (error);
+
+	    g_error_free (error);
+	  }
+	else
+	  {
+	    do_something_with_the_item (recent_info);
+
+	    gtk_recent_info_unref (recent_info);
+	  }
+      </programlisting></informalexample>
+      The #GtkRecentInfo is a reference counted boxed type, and it holds all
+      the meta-data of a recently used document, like its display name, its
+      description, the list of each application that has registered the
+      document or the list of groups to which the document belong.
+    </para>
+  
+  </section> <!-- gtkrecent-manager -->
+
+  <section id="gtkrecent-chooser">
+    <title>Displaying the Recently Used Documents</title>
+
+    <para>
+      Displaying the Recently Used Documents list is handled by any widget
+      implementing the #GtkRecentChooser interface. These widgets also handle
+      the sorting and filtering of the list; they will create their own
+      #GtkRecentManager objects by default:
+      <informalexample><programlisting>
+        GtkWidget *chooser;
+	gint response;
+
+	/* create a new dialog with the recently used documents list shown
+	 * using a GtkTreeView widget
+	 */
+	chooser = gtk_recent_chooser_dialog_new ("Recent Documents",
+	                                         parent_window,
+						 GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL,
+						 GTK_STOCK_OPEN, GTK_RESPONSE_OK,
+						 NULL);
+        /* set the sorting order to "most recently used first" */
+	gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (chooser), GTK_RECENT_SORT_MRU);
+	response = gtk_dialog_run (GTK_DIALOG (chooser));
+	if (response == GTK_RESPONSE_OK)
+	  {
+	    GtkRecentInfo *info;
+
+            info = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (chooser));
+	    do_something_with_the_item (info);
+
+	    gtk_recent_info_unref (info);
+	  }
+	
+	gtk_widget_destroy (chooser);
+      </programlisting></informalexample>
+    </para>
+    
+  </section> <!-- gtkrecent-chooser -->
+
+  <section id="gtkrecent-advanced">
+    <title>Advanced usage</title>
+
+    <para>
+      The #GtkRecentChooser widgets might display items sorted and filtered,
+      either with already supplied or custom sorting and filtering functions.
+      The biggest difference from the <structname>EggRecentView</structname>
+      widgets in EggRecent is that the #GtkRecentChooser widgets will use
+      their own copy of the list and will apply the sorting and filtering
+      functions only on the copy; this allows the creation of many viewers
+      with a single controller, like using many #GtkTreeView with a single
+      #GtkTreeModel instance.
+    </para>
+
+    <para>
+      Available sorting methods are:
+      <informalexample><programlisting>
+        /* no sorting */
+	gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (chooser), GTK_RECENT_SORT_NONE);
+	
+        /* most recently used first */
+	gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (chooser), GTK_RECENT_SORT_MRU);
+	
+	/* most recently used last */
+	gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (chooser), GTK_RECENT_SORT_LRU);
+      </programlisting></informalexample>
+      You can create your own sorting function, and the use the
+      GTK_RECENT_SORT_CUSTOM method:
+      <informalexample><programlisting>
+	/* custom sorting function, based on the registration count
+	 * (most used first)
+	 */
+	static void
+	sort_by_usage_count (GtkRecentInfo *a,
+                             GtkRecentInfo *b,
+                             gpointer       data)
+        {
+	  gint count_a, count_b;
+
+	  count_a = count_b = 0;
+
+	  if (gtk_recent_info_has_application (a, APP_NAME))
+	    gtk_recent_info_get_application_info (a, APP_NAME, NULL, &amp;count_a, NULL);
+
+	  if (gtk_recent_info_has_application (b, APP_NAME))
+	    gtk_recent_info_get_application_info (b, APP_NAME, NULL, &amp;count_b, NULL);
+
+	  return count_a &lt; count_b;
+	}
+
+	...
+
+	  /* set custom sorting and set the custom sorting function */
+	  gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (chooser),
+	                                    GTK_RECENT_SORT_CUSTOM);
+	  gtk_recent_chooser_set_sort_func (GTK_RECENT_CHOOSER,
+	                                    sort_by_usage_count,
+			  		    NULL, /* sort function data */
+					    NULL  /* destroy notify for the data */);
+      </programlisting></informalexample>
+    </para>
+
+    <para>
+      Filtering is done using the #GtkRecentFilter object, similar to the
+      #GtkFileFilter object used by the #GtkFileChooser widgets. The
+      #GtkRecentFilter object has a set of pre-defined options based on the
+      meta-data exposed by the #GtkRecentInfo object. It also allows custom
+      filtering function:
+      <informalexample><programlisting>
+        GtkRecentFilter *filter;
+
+	filter = gtk_recent_filter_new ();
+	
+	/* set the user visible name of the filter */
+	gtk_recent_filter_set_name (filter, "Since Last Month");
+
+	/* set the maximum age of a recently used document */
+	gtk_recent_filter_set_age (filter, 31);
+
+	/* the chooser takes the ownership of the object */
+	gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (chooser), filter);
+
+	/* set the currently used filter */
+	gtk_recent_chooser_set_filter (GTK_RECENT_CHOOSER (chooser), filter);
+
+	filter = gtk_recent_filter_new ();
+	gtk_recent_filter_set_name (filter, "Every text file");
+	gtk_recent_filter_set_mime_type (filter, "text/plain");
+
+	gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (chooser), filter);
+      </programlisting></informalexample>
+      The #GtkRecentChooserWidget and #GtkRecentChooserDialog widgets allow
+      multiple filters and the selection of an appropriate one; the
+      #GtkRecentChooserMenu widget allows just a single filter object.
+    </para>
+    
+  </section> <!-- gtkrecent-advanced -->
+  
+</chapter>
+
+<!--
+Local variables:
+mode: sgml
+sgml-parent-document: ("gtk-docs.sgml" "book" "part" "chapter")
+End:
+-->
diff -Nuarp gtk+/gtk/gtk.h gtk+.recent/gtk/gtk.h
--- gtk+/gtk/gtk.h	2006-03-26 23:45:00.000000000 +0200
+++ gtk+.recent/gtk/gtk.h	2006-03-26 23:45:28.000000000 +0200
@@ -140,6 +140,12 @@
 #include <gtk/gtkradiotoolbutton.h>
 #include <gtk/gtkrange.h>
 #include <gtk/gtkrc.h>
+#include <gtk/gtkrecentchooser.h>
+#include <gtk/gtkrecentchooserdialog.h>
+#include <gtk/gtkrecentchoosermenu.h>
+#include <gtk/gtkrecentchooserwidget.h>
+#include <gtk/gtkrecentfilter.h>
+#include <gtk/gtkrecentmanager.h>
 #include <gtk/gtkruler.h>
 #include <gtk/gtkscale.h>
 #include <gtk/gtkscrollbar.h>
diff -Nuarp gtk+/gtk/gtkrecentchooser.c gtk+.recent/gtk/gtkrecentchooser.c
--- gtk+/gtk/gtkrecentchooser.c	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/gtk/gtkrecentchooser.c	2006-03-26 23:46:37.000000000 +0200
@@ -0,0 +1,948 @@
+/* GTK - The GIMP Toolkit
+ * gtkrecentchooser.c - Abstract interface for recent file selectors GUIs
+ *
+ * Copyright (C) 2006, Emmanuele Bassi
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gtkrecentchooser.h"
+#include "gtkrecentchooserprivate.h"
+#include "gtkrecentmanager.h"
+#include "gtkintl.h"
+#include "gtktypebuiltins.h"
+#include "gtkprivate.h"
+#include "gtkmarshalers.h"
+#include "gtkalias.h"
+
+
+enum
+{
+  ITEM_ACTIVATED,
+  SELECTION_CHANGED,
+
+  LAST_SIGNAL
+};
+
+static void gtk_recent_chooser_class_init (gpointer g_iface);
+
+static guint chooser_signals[LAST_SIGNAL] = { 0, };
+
+GType
+gtk_recent_chooser_get_type (void)
+{
+  static GType chooser_type = 0;
+  
+  if (!chooser_type)
+    {
+      static const GTypeInfo chooser_info =
+      {
+        sizeof (GtkRecentChooserIface),
+        NULL, /* base_init */
+        NULL, /* base_finalize */
+        (GClassInitFunc) gtk_recent_chooser_class_init,
+      };
+      
+      chooser_type = g_type_register_static (G_TYPE_INTERFACE,
+      					     I_("GtkRecentChooser"),
+      					     &chooser_info, 0);
+      					     
+      g_type_interface_add_prerequisite (chooser_type, GTK_TYPE_OBJECT);
+    }
+  
+  return chooser_type;
+}
+
+static void
+gtk_recent_chooser_class_init (gpointer g_iface)
+{
+  GType iface_type = G_TYPE_FROM_INTERFACE (g_iface);
+  
+  /**
+   * GtkRecentChooser::selection-changed
+   * @chooser: the object which received the signal
+   *
+   * This signal is emitted when there is a change in the set of
+   * selected recently used resources.  This can happen when a user
+   * modifies the selection with the mouse or the keyboard, or when
+   * explicitely calling functions to change the selection.
+   *
+   * Since: 2.10
+   */
+  chooser_signals[SELECTION_CHANGED] =
+    g_signal_new (I_("selection-changed"),
+                  iface_type,
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GtkRecentChooserIface, selection_changed),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+   
+  /**
+   * GtkRecentChooser::item-activated
+   * @chooser: the object which received the signal
+   *
+   * This signal is emitted when the user "activates" a recent item
+   * in the recent chooser.  This can happen by double-clicking on an item
+   * in the recently used resources list, or by pressing
+   * <keycap>Enter</keycap>.
+   *
+   * Since: 2.10
+   */
+  chooser_signals[ITEM_ACTIVATED] =
+    g_signal_new (I_("item-activated"),
+                  iface_type,
+		  G_SIGNAL_RUN_LAST,
+		  G_STRUCT_OFFSET (GtkRecentChooserIface, item_activated),
+		  NULL, NULL,
+		  g_cclosure_marshal_VOID__VOID,
+		  G_TYPE_NONE, 0);
+ 
+  g_object_interface_install_property (g_iface,
+  				       g_param_spec_object ("recent-manager",
+  				       			    P_("Recent Manager"),
+  				       			    P_("The RecentManager object to use"),
+  				       			    GTK_TYPE_RECENT_MANAGER,
+  				       			    G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+  g_object_interface_install_property (g_iface,
+   				       g_param_spec_boolean ("show-private",
+   							     P_("Show Private"),
+   							     P_("Whether the private items should be displayed"),
+   							     FALSE,
+   							     G_PARAM_READWRITE));
+  g_object_interface_install_property (g_iface,
+  				       g_param_spec_boolean ("show-tips",
+  				       			     P_("Show Tooltips"),
+  				       			     P_("Whether there should be a tooltip on the item"),
+  				       			     FALSE,
+  				       			     G_PARAM_READWRITE));
+  g_object_interface_install_property (g_iface,
+  				       g_param_spec_boolean ("show-icons",
+  				       			     P_("Show Icons"),
+  				       			     P_("Whether there should be an icon near the item"),
+  				       			     TRUE,
+  				       			     G_PARAM_READWRITE));
+  g_object_interface_install_property (g_iface,
+  				       g_param_spec_boolean ("show-not-found",
+  				       			     P_("Show Not Found"),
+  				       			     P_("Whether the items pointing to unavailable resources should be displayed"),
+  				       			     FALSE,
+  				       			     G_PARAM_READWRITE));
+  g_object_interface_install_property (g_iface,
+   				       g_param_spec_boolean ("select-multiple",
+   							     P_("Select Multiple"),
+   							     P_("Whether to allow multiple items to be selected"),
+   							     FALSE,
+   							     G_PARAM_READWRITE));
+  g_object_interface_install_property (g_iface,
+		  		       g_param_spec_boolean ("local-only",
+					       		     P_("Local only"),
+							     P_("Whether the selected resource(s) should be limited to local file: URIs"),
+							     TRUE,
+							     G_PARAM_READWRITE));
+  g_object_interface_install_property (g_iface,
+   				       g_param_spec_int ("limit",
+   							 P_("Limit"),
+   							 P_("The maximum number of items to be displayed"),
+   							 -1,
+   							 G_MAXINT,
+   							 -1,
+   							 G_PARAM_READWRITE));
+  g_object_interface_install_property (g_iface,
+		  		       g_param_spec_enum ("sort-type",
+					       		  P_("Sort Type"),
+							  P_("The sorting order of the items displayed"),
+							  GTK_TYPE_RECENT_SORT_TYPE,
+							  GTK_RECENT_SORT_NONE,
+							  G_PARAM_READWRITE));
+  g_object_interface_install_property (g_iface,
+  				       g_param_spec_object ("filter",
+  				       			    P_("Filter"),
+  				       			    P_("The current filter for selecting which resources are displayed"),
+  				       			    GTK_TYPE_RECENT_FILTER,
+  				       			    G_PARAM_READWRITE));
+}
+
+GQuark
+gtk_recent_chooser_error_quark (void)
+{
+  static GQuark error_quark = 0;
+  if (!error_quark)
+    error_quark = g_quark_from_static_string ("gtk-recent-chooser-error-quark");
+  return error_quark;
+}
+
+/**
+ * _gtk_recent_chooser_get_recent_manager:
+ * @chooser: a #GtkRecentChooser
+ *
+ * Gets the #GtkRecentManager used by @chooser.
+ *
+ * Return value: the recent manager for @chooser.
+ */
+GtkRecentManager *
+_gtk_recent_chooser_get_recent_manager (GtkRecentChooser *chooser)
+{
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER (chooser), NULL);
+  
+  return GTK_RECENT_CHOOSER_GET_IFACE (chooser)->get_recent_manager (chooser);
+}
+
+/**
+ * gtk_recent_chooser_set_show_private:
+ * @chooser: a #GtkRecentChooser
+ * @show_private: %TRUE to show private items, %FALSE otherwise
+ *
+ * Whether to show recently used resources marked registered as private.
+ */
+void
+gtk_recent_chooser_set_show_private (GtkRecentChooser *chooser,
+				     gboolean          show_private)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (chooser));
+  
+  g_object_set (chooser, "show-private", show_private, NULL);
+}
+
+/**
+ * gtk_recent_chooser_get_show_private:
+ * @chooser: a #GtkRecentChooser
+ *
+ * Returns whether @chooser should display recently used resources
+ * registered as private.
+ *
+ * Return value: %TRUE if the recent chooser should show private items,
+ *   %FALSE otherwise.
+ */
+gboolean
+gtk_recent_chooser_get_show_private (GtkRecentChooser *chooser)
+{
+  gboolean show_private;
+  
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER (chooser), FALSE);
+  
+  g_object_get (chooser, "show-private", &show_private, NULL);
+  
+  return show_private;
+}
+
+/**
+ * gtk_recent_chooser_set_show_not_found:
+ * @chooser: a #GtkRecentChooser
+ * @show_not_found: whether to show the local items we didn't find
+ *
+ * Sets whether @chooser should display the recently used resources that
+ * it didn't find.  This only applies to local resources.
+ */
+void
+gtk_recent_chooser_set_show_not_found (GtkRecentChooser *chooser,
+				       gboolean          show_not_found)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (chooser));
+  
+  g_object_set (chooser, "show-not-found", show_not_found, NULL);
+}
+
+/**
+ * gtk_recent_chooser_get_show_not_found:
+ * @chooser: a #GtkRecentChooser
+ *
+ * Retrieves whether @chooser should show the recently used resources that
+ * were not found.
+ *
+ * Return value: %TRUE if the resources not found should be displayed, and
+ *   %FALSE otheriwse.
+ */
+gboolean
+gtk_recent_chooser_get_show_not_found (GtkRecentChooser *chooser)
+{
+  gboolean show_not_found;
+  
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER (chooser), FALSE);
+  
+  g_object_get (chooser, "show-not-found", &show_not_found, NULL);
+  
+  return show_not_found;
+}
+
+/**
+ * gtk_recent_chooser_set_show_icons:
+ * @chooser: a #GtkRecentChooser
+ * @show_icons: whether to show an icon near the resource
+ *
+ * Sets whether @chooser should show an icon near the resource when
+ * displaying it.
+ */
+void
+gtk_recent_chooser_set_show_icons (GtkRecentChooser *chooser,
+				   gboolean          show_icons)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (chooser));
+  
+  g_object_set (chooser, "show-icons", show_icons, NULL);
+}
+
+/**
+ * gtk_recent_chooser_get_show_icons:
+ * @chooser: a #GtkRecentChooser
+ *
+ * Retrieves whether @chooser should show an icon near the resource.
+ *
+ * Return value: %TRUE if the icons should be displayed, %FALSE otherwise.
+ */
+gboolean
+gtk_recent_chooser_get_show_icons (GtkRecentChooser *chooser)
+{
+  gboolean show_icons;
+  
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER (chooser), FALSE);
+  
+  g_object_get (chooser, "show-icons", &show_icons, NULL);
+  
+  return show_icons;
+}
+
+/**
+ * gtk_recent_chooser_set_select_multiple:
+ * @chooser: a #GtkRecentChooser
+ * @select_multiple: %TRUE if @chooser can select more than one item
+ *
+ * Sets whether @chooser can select multiple items.
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_chooser_set_select_multiple (GtkRecentChooser *chooser,
+					gboolean          select_multiple)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (chooser));
+  
+  g_object_set (chooser, "select-multiple", select_multiple, NULL);
+}
+
+/**
+ * gtk_recent_chooser_get_select_multiple:
+ * @chooser: a #GtkRecentChooser
+ *
+ * Gets whether @chooser can select multiple items.
+ *
+ * Return value: %TRUE if @chooser can select more than one item.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_recent_chooser_get_select_multiple (GtkRecentChooser *chooser)
+{
+  gboolean select_multiple;
+  
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER (chooser), FALSE);
+  
+  g_object_get (chooser, "select-multiple", &select_multiple, NULL);
+  
+  return select_multiple;
+}
+
+/**
+ * gtk_recent_chooser_set_local_only:
+ * @chooser: a #GtkRecentChooser
+ * @local_only: %TRUE if only local files can be shown
+ * 
+ * Sets whether only local resources, that is resources using the file:// URI
+ * scheme, should be shown in the recently used resources selector.  If
+ * @local_only is %TRUE (the default) then the shown resources are guaranteed
+ * to be accessible through the operating system native file system.
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_chooser_set_local_only (GtkRecentChooser *chooser,
+				   gboolean          local_only)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (chooser));
+
+  g_object_set (chooser, "local-only", local_only, NULL);
+}
+
+/**
+ * gtk_recent_chooser_get_local_only:
+ * @chooser: a #GtkRecentChooser
+ *
+ * Gets whether only local resources should be shown in the recently used
+ * resources selector.  See gtk_recent_chooser_set_local_only()
+ *
+ * Return value: %TRUE if only local resources should be shown.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_recent_chooser_get_local_only (GtkRecentChooser *chooser)
+{
+  gboolean local_only;
+
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER (chooser), FALSE);
+
+  g_object_get (chooser, "local-only", &local_only, NULL);
+
+  return local_only;
+}
+
+/**
+ * gtk_recent_chooser_set_limit:
+ * @chooser: a #GtkRecentChooser
+ * @limit: a positive integer, or -1 for all items
+ *
+ * Sets the number of items that should be returned by
+ * gtk_recent_chooser_get_items() and gtk_recent_chooser_get_uris().
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_chooser_set_limit (GtkRecentChooser *chooser,
+			      gint              limit)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (chooser));
+  
+  g_object_set (chooser, "limit", limit, NULL);
+}
+
+/**
+ * gtk_recent_chooser_get_limit:
+ * @chooser: a #GtkRecentChooser
+ *
+ * Gets the number of items returned by gtk_recent_chooser_get_items()
+ * and gtk_recent_chooser_get_uris().
+ *
+ * Return value: A positive integer, or -1 meaning that all items are
+ *   returned.
+ *
+ * Since: 2.10
+ */
+gint
+gtk_recent_chooser_get_limit (GtkRecentChooser *chooser)
+{
+  gint limit;
+  
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER (chooser), 10);
+  
+  g_object_get (chooser, "limit", &limit, NULL);
+  
+  return limit;
+}
+
+/**
+ * gtk_recent_chooser_set_show_tips:
+ * @chooser: a #GtkRecentChooser
+ * @show_tips: %TRUE if tooltips should be shown
+ *
+ * Sets whether to show a tooltips on the widget.
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_chooser_set_show_tips (GtkRecentChooser *chooser,
+				  gboolean          show_tips)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (chooser));
+  
+  g_object_set (chooser, "show-tips", show_tips, NULL);
+}
+
+/**
+ * gtk_recent_chooser_get_show_tips:
+ * @chooser: a #GtkRecentChooser
+ *
+ * Gets whether @chooser should display tooltips.
+ *
+ * Return value: %TRUE if the recent chooser should show tooltips,
+ *   %FALSE otherwise.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_recent_chooser_get_show_tips (GtkRecentChooser *chooser)
+{
+  gboolean show_tips;
+  
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER (chooser), FALSE);
+  
+  g_object_get (chooser, "show-tips", &show_tips, NULL);
+  
+  return show_tips;
+}
+
+/**
+ * gtk_recent_chooser_set_show_numbers:
+ * @chooser: a #GtkRecentChooser
+ * @show_private: %TRUE to show numbers, %FALSE otherwise
+ *
+ * Whether to show recently used resources prepended by a unique number.
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_chooser_set_show_numbers (GtkRecentChooser *chooser,
+				     gboolean          show_numbers)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (chooser));
+  
+  g_object_set (chooser, "show-numbers", show_numbers, NULL);
+}
+
+/**
+ * gtk_recent_chooser_get_show_numbers:
+ * @chooser: a #GtkRecentChooser
+ *
+ * Returns whether @chooser should display recently used resources
+ * prepended by a unique number.
+ *
+ * Return value: %TRUE if the recent chooser should show display numbers,
+ *   %FALSE otherwise.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_recent_chooser_get_show_numbers (GtkRecentChooser *chooser)
+{
+  gboolean show_numbers;
+  
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER (chooser), FALSE);
+  
+  g_object_get (chooser, "show-numbers", &show_numbers, NULL);
+  
+  return show_numbers;
+}
+
+
+/**
+ * gtk_recent_chooser_set_sort_type:
+ * @chooser: a #GtkRecentChooser
+ * @sort_type: sort order that the chooser should use
+ *
+ * Changes the sorting order of the recently used resources list displayed by
+ * @chooser.
+ */
+void
+gtk_recent_chooser_set_sort_type (GtkRecentChooser  *chooser,
+				  GtkRecentSortType  sort_type)
+{  
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (chooser));
+  
+  g_object_set (chooser, "sort-type", sort_type, NULL);
+}
+
+/**
+ * gtk_recent_chooser_get_sort_type:
+ * @chooser: a #GtkRecentChooser
+ *
+ * Gets the value set by gtk_recent_chooser_set_sort_type().
+ *
+ * Return value: the sorting order of the @chooser.
+ *
+ * Since: 2.10
+ */
+GtkRecentSortType
+gtk_recent_chooser_get_sort_type (GtkRecentChooser *chooser)
+{
+  GtkRecentSortType sort_type;
+  
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER (chooser), GTK_RECENT_SORT_NONE);
+  
+  g_object_get (chooser, "sort-type", &sort_type, NULL);
+
+  return sort_type;
+}
+
+/**
+ * gtk_recent_chooser_set_sort_func:
+ * @chooser: a #GtkRecentChooser
+ * @sort_func: the comparison function
+ * @sort_data: user data to pass to @sort_func, or %NULL
+ * @destroy_data: destroy notifier for @sort_data, or %NULL
+ *
+ * Sets the comparison function used when sorting to be @sort_func.  If
+ * the @chooser has the sort type set to #GTK_RECENT_SORT_CUSTOM then
+ * the chooser will sort using this function.
+ *
+ * To the comparison function will be passed two #GtkRecentInfo structs and
+ * @sort_data;  @sort_func should return a positive integer if the first
+ * item comes before the second, zero if the two items are equal and
+ * a negative integer if the first item comes after the second.
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_chooser_set_sort_func  (GtkRecentChooser  *chooser,
+				   GtkRecentSortFunc  sort_func,
+				   gpointer           sort_data,
+				   GDestroyNotify     data_destroy)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (chooser));
+  
+  GTK_RECENT_CHOOSER_GET_IFACE (chooser)->set_sort_func (chooser,
+  							 sort_func,
+  							 sort_data,
+  							 data_destroy);
+}
+
+/**
+ * gtk_recent_chooser_set_current_uri:
+ * @chooser: a #GtkRecentChooser
+ * @uri: a URI
+ * @error: return location for a #GError, or %NULL
+ *
+ * Sets @uri as the current URI for @chooser.
+ *
+ * Return value: %TRUE if the URI was found.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_recent_chooser_set_current_uri (GtkRecentChooser  *chooser,
+				    const gchar       *uri,
+				    GError           **error)
+{
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER (chooser), FALSE);
+  
+  return GTK_RECENT_CHOOSER_GET_IFACE (chooser)->set_current_uri (chooser, uri, error);
+}
+
+/**
+ * gtk_recent_chooser_get_current_uri:
+ * @chooser: a #GtkRecentChooser
+ *
+ * Gets the URI currently selected by @chooser.
+ *
+ * Return value: a newly allocated string holding a URI.
+ */
+gchar *
+gtk_recent_chooser_get_current_uri (GtkRecentChooser *chooser)
+{
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER (chooser), NULL);
+  
+  return GTK_RECENT_CHOOSER_GET_IFACE (chooser)->get_current_uri (chooser);
+}
+
+/**
+ * gtk_recent_chooser_get_current_item:
+ * @chooser: a #GtkRecentChooser
+ * 
+ * Gets the #GtkRecentInfo currently selected by @chooser.
+ *
+ * Return value: a #GtkRecentInfo.  Use gtk_recent_info_unref() when
+ *   when you have finished using it.
+ *
+ * Since: 2.10
+ */
+GtkRecentInfo *
+gtk_recent_chooser_get_current_item (GtkRecentChooser *chooser)
+{
+  GtkRecentManager *manager;
+  GtkRecentInfo *retval;
+  gchar *uri;
+  
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER (chooser), NULL);
+  
+  uri = gtk_recent_chooser_get_current_uri (chooser);
+  if (!uri)
+    return NULL;
+  
+  manager = _gtk_recent_chooser_get_recent_manager (chooser);
+  retval = gtk_recent_manager_lookup_item (manager, uri, NULL);
+  g_free (uri);
+  
+  return retval;
+}
+
+/**
+ * gtk_recent_chooser_select_uri:
+ * @chooser: a #GtkRecentChooser
+ * @uri: a URI
+ * @error: return location for a #GError, or %NULL
+ *
+ * Selects @uri inside @chooser.
+ *
+ * Return value: %TRUE if @uri was found.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_recent_chooser_select_uri (GtkRecentChooser  *chooser,
+			       const gchar       *uri,
+			       GError           **error)
+{
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER (chooser), FALSE);
+  
+  return GTK_RECENT_CHOOSER_GET_IFACE (chooser)->select_uri (chooser, uri, error);
+}
+
+/**
+ * gtk_recent_chooser_unselect_uri:
+ * @chooser: a #GtkRecentChooser
+ * @uri: a URI
+ *
+ * Unselects @uri inside @chooser.
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_chooser_unselect_uri (GtkRecentChooser *chooser,
+				 const gchar      *uri)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (chooser));
+  
+  GTK_RECENT_CHOOSER_GET_IFACE (chooser)->unselect_uri (chooser, uri);
+}
+
+/**
+ * gtk_recent_chooser_select_all:
+ * @chooser: a #GtkRecentChooser
+ *
+ * Selects all the items inside @chooser, if the @chooser supports
+ * multiple selection.
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_chooser_select_all (GtkRecentChooser *chooser)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (chooser));
+  
+  GTK_RECENT_CHOOSER_GET_IFACE (chooser)->select_all (chooser);
+}
+
+/**
+ * gtk_recent_chooser_unselect_all:
+ * @chooser: a #GtkRecentChooser
+ *
+ * Unselects all the items inside @chooser.
+ * 
+ * Since: 2.10
+ */
+void
+gtk_recent_chooser_unselect_all (GtkRecentChooser *chooser)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (chooser));
+  
+  GTK_RECENT_CHOOSER_GET_IFACE (chooser)->unselect_all (chooser);
+}
+
+/**
+ * gtk_recent_chooser_get_items:
+ * @chooser: a #GtkRecentChooser
+ *
+ * Gets the list of recently used resources in form of #GtkRecentInfo objects.
+ *
+ * The return value of this function is affected by the "sort-type" and
+ * "limit" properties of @chooser.
+ *
+ * Return value: A newly allocated list of #GtkRecentInfo objects.  You should
+ *   use gtk_recent_info_unref() on every item of the list, and then free
+ *   the list itself using g_list_free().
+ *
+ * Since: 2.10
+ */
+GList *
+gtk_recent_chooser_get_items (GtkRecentChooser *chooser)
+{
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER (chooser), NULL);
+  
+  return GTK_RECENT_CHOOSER_GET_IFACE (chooser)->get_items (chooser);
+}
+
+/**
+ * gtk_recent_chooser_get_uris:
+ * @chooser: a #GtkRecentChooser
+ * @length: return location for a the length of the URI list, or %NULL
+ *
+ * Gets the URI of the recently used resources.
+ *
+ * The return value of this function is affected by the "sort-type" and "limit"
+ * properties of @chooser.
+ *
+ * Since the returned array is %NULL terminated, @length may be %NULL.
+ * 
+ * Return value: A newly allocated, %NULL terminated array of strings. Use
+ *   g_strfreev() to free it.
+ *
+ * Since: 2.10
+ */
+gchar **
+gtk_recent_chooser_get_uris (GtkRecentChooser *chooser,
+                             gsize            *length)
+{
+  GList *items, *l;
+  gchar **retval;
+  gsize n_items, i;
+  
+  items = gtk_recent_chooser_get_items (chooser);
+  if (!items)
+    return NULL;
+  
+  n_items = g_list_length (items);
+  retval = g_new0 (gchar *, n_items + 1);
+  
+  for (l = items, i = 0; l != NULL; l = l->next)
+    {
+      GtkRecentInfo *info = (GtkRecentInfo *) l->data;
+      const gchar *uri;
+      
+      g_assert (info != NULL);
+      
+      uri = gtk_recent_info_get_uri (info);
+      g_assert (uri != NULL);
+      
+      retval[i++] = g_strdup (uri);
+    }
+  retval[i] = NULL;
+  
+  if (length)
+    *length = i;
+  
+  g_list_foreach (items,
+  		  (GFunc) gtk_recent_info_unref,
+  		  NULL);
+  g_list_free (items);
+  
+  return retval;
+}
+
+/**
+ * gtk_recent_chooser_add_filter:
+ * @chooser: a #GtkRecentChooser
+ * @filter: a #GtkRecentFilter
+ *
+ * Adds @filter to the list of #GtkRecentFilter objects held by @chooser.
+ *
+ * If no previous filter objects were defined, this function will call
+ * gtk_recent_chooser_set_filter().
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_chooser_add_filter (GtkRecentChooser *chooser,
+			       GtkRecentFilter  *filter)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (chooser));
+  
+  GTK_RECENT_CHOOSER_GET_IFACE (chooser)->add_filter (chooser, filter);
+}
+
+/**
+ * gtk_recent_chooser_remove_filter:
+ * @chooser: a #GtkRecentChooser
+ * @filter: a #GtkRecentFilter
+ *
+ * Removes @filter from the list of #GtkRecentFilter objects held by @chooser.
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_chooser_remove_filter (GtkRecentChooser *chooser,
+				  GtkRecentFilter  *filter)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (chooser));
+  
+  GTK_RECENT_CHOOSER_GET_IFACE (chooser)->remove_filter (chooser, filter);
+}
+
+/**
+ * gtk_recent_chooser_list_filters:
+ * @chooser: a #GtkRecentChooser
+ *
+ * Gets the #GtkRecentFilter objects held by @chooser.
+ *
+ * Return value: A singly linked list of #GtkRecentFilter objects.  You
+ *   should just free the returned list using g_slist_free().
+ *
+ * Since: 2.10
+ */
+GSList *
+gtk_recent_chooser_list_filters (GtkRecentChooser *chooser)
+{
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER (chooser), NULL);
+  
+  return GTK_RECENT_CHOOSER_GET_IFACE (chooser)->list_filters (chooser);
+}
+
+/**
+ * gtk_recent_chooser_set_filter:
+ * @chooser: a #GtkRecentChooser
+ * @filter: a #GtkRecentFilter
+ *
+ * Sets @filter as the current #GtkRecentFilter object used by @chooser
+ * to affect the displayed recently used resources.
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_chooser_set_filter (GtkRecentChooser *chooser,
+			       GtkRecentFilter  *filter)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (chooser));
+  
+  g_object_set (G_OBJECT (chooser), "filter", filter, NULL);
+}
+
+/**
+ * gtk_recent_chooser_get_filter:
+ * @chooser: a #GtkRecentChooser
+ *
+ * Gets the #GtkRecentFilter object currently used by @chooser to affect
+ * the display of the recently used resources.
+ *
+ * Return value: a #GtkRecentFilter object.
+ *
+ * Since: 2.10
+ */
+GtkRecentFilter *
+gtk_recent_chooser_get_filter (GtkRecentChooser *chooser)
+{
+  GtkRecentFilter *filter;
+  
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER (chooser), NULL);
+  
+  g_object_get (G_OBJECT (chooser), "filter", &filter, NULL);
+  
+  /* we need this hack because g_object_get() increases the refcount
+   * of the returned object; see also gtk_file_chooser_get_filter()
+   * inside gtkfilechooser.c
+   */
+  if (filter)
+    g_object_unref (filter);
+  
+  return filter;
+}
+
+void
+_gtk_recent_chooser_item_activated (GtkRecentChooser *chooser)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (chooser));
+  
+  g_signal_emit (chooser, chooser_signals[ITEM_ACTIVATED], 0);
+}
+
+void
+_gtk_recent_chooser_selection_changed (GtkRecentChooser *chooser)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (chooser));
+
+  g_signal_emit (chooser, chooser_signals[SELECTION_CHANGED], 0);
+}
+
+#define __GTK_RECENT_CHOOSER_H__
+#include "gtkaliasdef.c"
diff -Nuarp gtk+/gtk/gtkrecentchooserdefault.c gtk+.recent/gtk/gtkrecentchooserdefault.c
--- gtk+/gtk/gtkrecentchooserdefault.c	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/gtk/gtkrecentchooserdefault.c	2006-03-26 23:46:37.000000000 +0200
@@ -0,0 +1,2094 @@
+/* GTK - The GIMP Toolkit
+ * gtkrecentchooserdefault.c
+ * Copyright (C) 2005-2006, Emmanuele Bassi
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <gdk/gdkscreen.h>
+
+#include "gtkstock.h"
+#include "gtkicontheme.h"
+#include "gtkiconfactory.h"
+#include "gtksettings.h"
+#include "gtktreeview.h"
+#include "gtkliststore.h"
+#include "gtkbutton.h"
+#include "gtkcelllayout.h"
+#include "gtkcellrendererpixbuf.h"
+#include "gtkcellrenderertext.h"
+#include "gtkcheckmenuitem.h"
+#include "gtkclipboard.h"
+#include "gtkcombobox.h"
+#include "gtkentry.h"
+#include "gtkeventbox.h"
+#include "gtkexpander.h"
+#include "gtkframe.h"
+#include "gtkhbox.h"
+#include "gtkhpaned.h"
+#include "gtkimage.h"
+#include "gtkimagemenuitem.h"
+#include "gtkintl.h"
+#include "gtklabel.h"
+#include "gtkmenuitem.h"
+#include "gtkmessagedialog.h"
+#include "gtkscrolledwindow.h"
+#include "gtkseparatormenuitem.h"
+#include "gtksizegroup.h"
+#include "gtktable.h"
+#include "gtktreeview.h"
+#include "gtktreemodelsort.h"
+#include "gtktreemodelfilter.h"
+#include "gtktreeselection.h"
+#include "gtktreestore.h"
+#include "gtktooltips.h"
+#include "gtktypebuiltins.h"
+#include "gtkvbox.h"
+#include "gtkalias.h"
+
+#include "gtkrecentmanager.h"
+#include "gtkrecentfilter.h"
+#include "gtkrecentchooser.h"
+#include "gtkrecentchooserprivate.h"
+#include "gtkrecentchooserutils.h"
+#include "gtkrecentchooserdefault.h"
+
+
+
+struct _GtkRecentChooserDefault
+{
+  GtkVBox parent_instance;
+  
+  GtkRecentManager *manager;
+  gulong manager_changed_id;
+  
+  gint icon_size;
+
+  /* RecentChooser properties */
+  gint limit;  
+  GtkRecentSortType sort_type;
+  guint show_private : 1;
+  guint show_not_found : 1;
+  guint select_multiple : 1;
+  guint show_numbers : 1;
+  guint show_tips : 1;
+  guint show_icons : 1;
+  guint local_only : 1;
+  
+  GSList *filters;
+  GtkRecentFilter *current_filter;
+  GtkWidget *filter_combo_hbox;
+  GtkWidget *filter_combo;
+  
+  GtkRecentSortFunc sort_func;
+  gpointer sort_data;
+  GDestroyNotify sort_data_destroy;
+
+  GtkTooltips *tooltips;
+
+  GtkIconTheme *icon_theme;
+  
+  GtkWidget *recent_view;
+  GtkListStore *recent_store;
+  GtkTreeModel *recent_store_filter;
+  GtkTreeViewColumn *icon_column;
+  GtkTreeViewColumn *meta_column;
+  GtkCellRenderer *meta_renderer;
+  GtkTreeSelection *selection;
+  
+  GtkWidget *recent_popup_menu;
+  GtkWidget *recent_popup_menu_copy_item;
+  GtkWidget *recent_popup_menu_remove_item;
+  GtkWidget *recent_popup_menu_clear_item;
+  GtkWidget *recent_popup_menu_show_private_item;
+ 
+  guint load_id;
+  GList *recent_items;
+  gint n_recent_items;
+  gint loaded_items;
+  guint load_state;
+};
+
+typedef struct _GtkRecentChooserDefaultClass
+{
+  GtkVBoxClass parent_class;
+} GtkRecentChooserDefaultClass;
+
+enum {
+  RECENT_URI_COLUMN,
+  RECENT_DISPLAY_NAME_COLUMN,
+  RECENT_INFO_COLUMN,
+    
+  N_RECENT_COLUMNS
+};
+
+enum {
+  LOAD_EMPTY,    /* initial state: the model is empty */
+  LOAD_PRELOAD,  /* the model is loading and not inserted in the tree yet */
+  LOAD_LOADING,  /* the model is fully loaded but not inserted */
+  LOAD_FINISHED  /* the model is fully loaded and inserted */
+};
+
+enum {
+  TEXT_URI_LIST
+};
+
+/* Target types for DnD from the file list */
+static const GtkTargetEntry recent_list_source_targets[] = {
+  { "text/uri-list", 0, TEXT_URI_LIST }
+};
+
+static const int num_recent_list_source_targets = (sizeof (recent_list_source_targets)
+                                                   / sizeof (recent_list_source_targets[0]));
+
+/* Icon size for if we can't get it from the theme */
+#define FALLBACK_ICON_SIZE  48
+#define FALLBACK_ITEM_LIMIT 20
+
+#define NUM_CHARS 40
+#define NUM_LINES 9
+
+
+
+/* GObject */
+static void     gtk_recent_chooser_default_class_init   (GtkRecentChooserDefaultClass *klass);
+static void     gtk_recent_chooser_default_init         (GtkRecentChooserDefault      *impl);
+static GObject *gtk_recent_chooser_default_constructor  (GType                         type,
+						         guint                         n_construct_prop,
+						         GObjectConstructParam        *construct_params);
+static void     gtk_recent_chooser_default_finalize     (GObject                      *object);
+static void     gtk_recent_chooser_default_set_property (GObject                      *object,
+						         guint                         prop_id,
+						         const GValue                 *value,
+						         GParamSpec                   *pspec);
+static void     gtk_recent_chooser_default_get_property (GObject                      *object,
+						         guint                         prop_id,
+						         GValue                       *value,
+						         GParamSpec                   *pspec);
+
+/* GtkRecentChooserIface */
+static void              gtk_recent_chooser_iface_init                 (GtkRecentChooserIface  *iface);
+static gboolean          gtk_recent_chooser_default_set_current_uri    (GtkRecentChooser       *chooser,
+								        const gchar            *uri,
+								        GError                **error);
+static gchar *           gtk_recent_chooser_default_get_current_uri    (GtkRecentChooser       *chooser);
+static gboolean          gtk_recent_chooser_default_select_uri         (GtkRecentChooser       *chooser,
+								        const gchar            *uri,
+								        GError                **error);
+static void              gtk_recent_chooser_default_unselect_uri       (GtkRecentChooser       *chooser,
+								        const gchar            *uri);
+static void              gtk_recent_chooser_default_select_all         (GtkRecentChooser       *chooser);
+static void              gtk_recent_chooser_default_unselect_all       (GtkRecentChooser       *chooser);
+static GList *           gtk_recent_chooser_default_get_items          (GtkRecentChooser       *chooser);
+static GtkRecentManager *gtk_recent_chooser_default_get_recent_manager (GtkRecentChooser       *chooser);
+static void              gtk_recent_chooser_default_set_sort_func      (GtkRecentChooser       *chooser,
+									GtkRecentSortFunc       sort_func,
+									gpointer                sort_data,
+									GDestroyNotify          data_destroy);
+static void              gtk_recent_chooser_default_add_filter         (GtkRecentChooser       *chooser,
+								        GtkRecentFilter        *filter);
+static void              gtk_recent_chooser_default_remove_filter      (GtkRecentChooser       *chooser,
+								        GtkRecentFilter        *filter);
+static GSList *          gtk_recent_chooser_default_list_filters       (GtkRecentChooser       *chooser);
+
+
+static void gtk_recent_chooser_default_map      (GtkWidget *widget);
+static void gtk_recent_chooser_default_show_all (GtkWidget *widget);
+
+static void set_current_filter        (GtkRecentChooserDefault *impl,
+				       GtkRecentFilter         *filter);
+
+static GtkIconTheme *get_icon_theme_for_widget (GtkWidget   *widget);
+static gint          get_icon_size_for_widget  (GtkWidget   *widget,
+						GtkIconSize  icon_size);
+
+static void reload_recent_items (GtkRecentChooserDefault *impl);
+static void chooser_set_model   (GtkRecentChooserDefault *impl);
+
+static void set_recent_manager (GtkRecentChooserDefault *impl,
+				GtkRecentManager        *manager);
+
+static void chooser_set_sort_type (GtkRecentChooserDefault *impl,
+				   GtkRecentSortType        sort_type);
+
+static gboolean recent_store_filter_func (GtkTreeModel *model,
+					  GtkTreeIter  *iter,
+					  gpointer      user_data);
+
+static void recent_manager_changed_cb (GtkRecentManager  *manager,
+			               gpointer           user_data);
+static void recent_icon_data_func     (GtkTreeViewColumn *tree_column,
+				       GtkCellRenderer   *cell,
+				       GtkTreeModel      *model,
+				       GtkTreeIter       *iter,
+				       gpointer           user_data);
+static void recent_meta_data_func     (GtkTreeViewColumn *tree_column,
+				       GtkCellRenderer   *cell,
+				       GtkTreeModel      *model,
+				       GtkTreeIter       *iter,
+				       gpointer           user_data);
+
+static void selection_changed_cb      (GtkTreeSelection  *z,
+				       gpointer           user_data);
+static void row_activated_cb          (GtkTreeView       *tree_view,
+				       GtkTreePath       *tree_path,
+				       GtkTreeViewColumn *tree_column,
+				       gpointer           user_data);
+static void filter_combo_changed_cb   (GtkComboBox       *combo_box,
+				       gpointer           user_data);
+
+static void remove_all_activated_cb   (GtkMenuItem       *menu_item,
+				       gpointer           user_data);
+static void remove_item_activated_cb  (GtkMenuItem       *menu_item,
+				       gpointer           user_data);
+static void show_private_toggled_cb   (GtkCheckMenuItem  *menu_item,
+				       gpointer           user_data);
+
+static gboolean recent_view_popup_menu_cb   (GtkWidget      *widget,
+					     gpointer        user_data);
+static gboolean recent_view_button_press_cb (GtkWidget      *widget,
+					     GdkEventButton *event,
+					     gpointer        user_data);
+
+static void     recent_view_drag_begin_cb         (GtkWidget        *widget,
+						   GdkDragContext   *context,
+						   gpointer          user_data);
+static void     recent_view_drag_data_get_cb      (GtkWidget        *widget,
+						   GdkDragContext   *context,
+						   GtkSelectionData *selection_data,
+						   guint             info,
+						   guint32           time_,
+						   gpointer          data);
+
+G_DEFINE_TYPE_WITH_CODE (GtkRecentChooserDefault,
+			 gtk_recent_chooser_default,
+			 GTK_TYPE_VBOX,
+			 G_IMPLEMENT_INTERFACE (GTK_TYPE_RECENT_CHOOSER,
+				 		gtk_recent_chooser_iface_init));
+
+
+
+
+static void
+gtk_recent_chooser_iface_init (GtkRecentChooserIface *iface)
+{
+  iface->set_current_uri = gtk_recent_chooser_default_set_current_uri;
+  iface->get_current_uri = gtk_recent_chooser_default_get_current_uri;
+  iface->select_uri = gtk_recent_chooser_default_select_uri;
+  iface->unselect_uri = gtk_recent_chooser_default_unselect_uri;
+  iface->select_all = gtk_recent_chooser_default_select_all;
+  iface->unselect_all = gtk_recent_chooser_default_unselect_all;
+  iface->get_items = gtk_recent_chooser_default_get_items;
+  iface->get_recent_manager = gtk_recent_chooser_default_get_recent_manager;
+  iface->set_sort_func = gtk_recent_chooser_default_set_sort_func;
+  iface->add_filter = gtk_recent_chooser_default_add_filter;
+  iface->remove_filter = gtk_recent_chooser_default_remove_filter;
+  iface->list_filters = gtk_recent_chooser_default_list_filters;
+}
+
+static void
+gtk_recent_chooser_default_class_init (GtkRecentChooserDefaultClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  gobject_class->constructor = gtk_recent_chooser_default_constructor;  
+  gobject_class->finalize = gtk_recent_chooser_default_finalize;
+  gobject_class->set_property = gtk_recent_chooser_default_set_property;
+  gobject_class->get_property = gtk_recent_chooser_default_get_property;
+  
+  widget_class->map = gtk_recent_chooser_default_map;
+  widget_class->show_all = gtk_recent_chooser_default_show_all;
+  
+  _gtk_recent_chooser_install_properties (gobject_class);
+}
+
+static void
+gtk_recent_chooser_default_init (GtkRecentChooserDefault *impl)
+{
+  gtk_box_set_spacing (GTK_BOX (impl), 12);
+  
+  impl->limit = FALLBACK_ITEM_LIMIT;
+  impl->sort_type = GTK_RECENT_SORT_NONE;
+  impl->show_private = FALSE;
+  impl->show_not_found = FALSE;
+  impl->show_tips = TRUE;
+  impl->select_multiple = FALSE;
+  impl->local_only = TRUE;
+  
+  impl->icon_size = FALLBACK_ICON_SIZE;
+  impl->icon_theme = NULL;
+  
+  impl->current_filter = NULL;
+
+  impl->tooltips = gtk_tooltips_new ();
+  g_object_ref_sink (impl->tooltips);
+  
+  impl->recent_items = NULL;
+  impl->n_recent_items = 0;
+  impl->loaded_items = 0;
+  
+  impl->load_state = LOAD_EMPTY;
+}
+
+static GObject *
+gtk_recent_chooser_default_constructor (GType                  type,
+				        guint                  n_construct_prop,
+				        GObjectConstructParam *construct_params)
+{
+  GtkRecentChooserDefault *impl;
+  GObject *object;
+  
+  GtkWidget *scrollw;
+  GtkCellRenderer *renderer;
+  
+  object = G_OBJECT_CLASS (gtk_recent_chooser_default_parent_class)->constructor (type, n_construct_prop, construct_params);
+
+  impl = GTK_RECENT_CHOOSER_DEFAULT (object);
+  
+  g_assert (impl->manager);
+  
+  gtk_widget_push_composite_child ();
+  
+  scrollw = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollw),
+  				       GTK_SHADOW_IN);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollw),
+  				  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+  gtk_box_pack_start (GTK_BOX (impl), scrollw, TRUE, TRUE, 0);
+  gtk_widget_show (scrollw);
+  
+  impl->recent_view = gtk_tree_view_new ();
+  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (impl->recent_view), FALSE);
+  g_signal_connect (impl->recent_view, "row-activated",
+                    G_CALLBACK (row_activated_cb), impl);
+  g_signal_connect (impl->recent_view, "popup-menu",
+  		    G_CALLBACK (recent_view_popup_menu_cb), impl);
+  g_signal_connect (impl->recent_view, "button-press-event",
+  		    G_CALLBACK (recent_view_button_press_cb), impl);
+  g_signal_connect (impl->recent_view, "drag-begin",
+		    G_CALLBACK (recent_view_drag_begin_cb), impl);
+  g_signal_connect (impl->recent_view, "drag-data-get",
+		    G_CALLBACK (recent_view_drag_data_get_cb), impl);
+
+  g_object_set_data (G_OBJECT (impl->recent_view), "GtkRecentChooserDefault", impl);
+  
+  gtk_container_add (GTK_CONTAINER (scrollw), impl->recent_view);
+  gtk_widget_show (impl->recent_view);
+  
+  impl->icon_column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_expand (impl->icon_column, FALSE);
+  gtk_tree_view_column_set_resizable (impl->icon_column, FALSE);
+  
+  renderer = gtk_cell_renderer_pixbuf_new ();
+  gtk_tree_view_column_pack_start (impl->icon_column, renderer, FALSE);
+  gtk_tree_view_column_set_cell_data_func (impl->icon_column,
+  					   renderer,
+  					   recent_icon_data_func,
+  					   impl,
+  					   NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (impl->recent_view),
+                               impl->icon_column);
+  
+  impl->meta_column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_expand (impl->meta_column, TRUE);
+  gtk_tree_view_column_set_resizable (impl->meta_column, FALSE);
+  
+  impl->meta_renderer = gtk_cell_renderer_text_new ();
+  g_object_set (G_OBJECT (impl->meta_renderer),
+                "ellipsize", PANGO_ELLIPSIZE_END,
+                NULL);
+  gtk_tree_view_column_pack_start (impl->meta_column, impl->meta_renderer, TRUE);
+  gtk_tree_view_column_set_cell_data_func (impl->meta_column,
+  					   impl->meta_renderer,
+  					   recent_meta_data_func,
+  					   impl,
+  					   NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (impl->recent_view),
+                               impl->meta_column);
+  
+  impl->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->recent_view));
+  gtk_tree_selection_set_mode (impl->selection, GTK_SELECTION_SINGLE);
+  g_signal_connect (impl->selection, "changed", G_CALLBACK (selection_changed_cb), impl);
+
+  /* drag and drop */
+  gtk_drag_source_set (impl->recent_view,
+		       GDK_BUTTON1_MASK,
+		       recent_list_source_targets,
+		       num_recent_list_source_targets,
+		       GDK_ACTION_COPY);
+
+  impl->filter_combo_hbox = gtk_hbox_new (FALSE, 12);
+  
+  impl->filter_combo = gtk_combo_box_new_text ();
+  gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (impl->filter_combo), FALSE);
+  g_signal_connect (impl->filter_combo, "changed",
+                    G_CALLBACK (filter_combo_changed_cb), impl);
+  gtk_tooltips_set_tip (impl->tooltips,
+			impl->filter_combo,
+		        _("Select which type of documents are shown"),
+			NULL);
+  
+  gtk_box_pack_end (GTK_BOX (impl->filter_combo_hbox),
+                    impl->filter_combo,
+                    FALSE, FALSE, 0);
+  gtk_widget_show (impl->filter_combo);
+  
+  gtk_box_pack_end (GTK_BOX (impl), impl->filter_combo_hbox, FALSE, FALSE, 0);
+  
+  gtk_widget_pop_composite_child ();
+  
+  impl->recent_store = gtk_list_store_new (N_RECENT_COLUMNS,
+  					   G_TYPE_STRING,       /* uri */
+  					   G_TYPE_STRING,       /* display_name */
+  					   GTK_TYPE_RECENT_INFO /* info */);
+  
+  return object;
+}
+
+static void
+gtk_recent_chooser_default_set_property (GObject      *object,
+				         guint         prop_id,
+					 const GValue *value,
+					 GParamSpec   *pspec)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (object);
+  
+  switch (prop_id)
+    {
+    case GTK_RECENT_CHOOSER_PROP_RECENT_MANAGER:
+      set_recent_manager (impl, g_value_get_object (value));
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_PRIVATE:
+      impl->show_private = g_value_get_boolean (value);
+      
+      if (impl->recent_store && impl->recent_store_filter)
+        gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->recent_store_filter));
+
+      if (impl->recent_popup_menu_show_private_item)
+	{
+          GtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM (impl->recent_popup_menu_show_private_item);
+	  g_signal_handlers_block_by_func (item, G_CALLBACK (show_private_toggled_cb), impl);
+          gtk_check_menu_item_set_active (item, impl->show_private);
+	  g_signal_handlers_unblock_by_func (item, G_CALLBACK (show_private_toggled_cb), impl);
+        }
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_NOT_FOUND:
+      impl->show_not_found = g_value_get_boolean (value);
+      
+      if (impl->recent_store && impl->recent_store_filter)
+        gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->recent_store_filter));
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_TIPS:
+      impl->show_tips = g_value_get_boolean (value);
+
+      if (impl->show_tips)
+        gtk_tooltips_enable (impl->tooltips);
+      else
+        gtk_tooltips_disable (impl->tooltips);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_ICONS:
+      impl->show_icons = g_value_get_boolean (value);
+      gtk_tree_view_column_set_visible (impl->icon_column, impl->show_icons);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SELECT_MULTIPLE:
+      impl->select_multiple = g_value_get_boolean (value);
+      
+      if (impl->select_multiple)
+        gtk_tree_selection_set_mode (impl->selection, GTK_SELECTION_MULTIPLE);
+      else
+        gtk_tree_selection_set_mode (impl->selection, GTK_SELECTION_SINGLE);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_LOCAL_ONLY:
+      impl->local_only = g_value_get_boolean (value);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_LIMIT:
+      impl->limit = g_value_get_int (value);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SORT_TYPE:
+      chooser_set_sort_type (impl, g_value_get_enum (value));
+      break;
+    case GTK_RECENT_CHOOSER_PROP_FILTER:
+      set_current_filter (impl, g_value_get_object (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_recent_chooser_default_get_property (GObject    *object,
+					 guint       prop_id,
+					 GValue     *value,
+					 GParamSpec *pspec)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (object);
+  
+  switch (prop_id)
+    {
+    case GTK_RECENT_CHOOSER_PROP_LIMIT:
+      g_value_set_int (value, impl->limit);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SORT_TYPE:
+      g_value_set_enum (value, impl->sort_type);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_PRIVATE:
+      g_value_set_boolean (value, impl->show_private);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_ICONS:
+      g_value_set_boolean (value, impl->show_icons);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_NOT_FOUND:
+      g_value_set_boolean (value, impl->show_not_found);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_TIPS:
+      g_value_set_boolean (value, impl->show_tips);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_LOCAL_ONLY:
+      g_value_set_boolean (value, impl->local_only);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SELECT_MULTIPLE:
+      g_value_set_boolean (value, impl->select_multiple);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_FILTER:
+      g_value_set_object (value, impl->current_filter);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_recent_chooser_default_finalize (GObject *object)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (object);
+
+  if (impl->recent_items)
+    {
+      g_list_foreach (impl->recent_items,
+		      (GFunc) gtk_recent_info_unref,
+		      NULL);
+      g_list_free (impl->recent_items);
+      impl->recent_items = NULL;
+    }
+
+  if (impl->manager_changed_id)
+    {
+      g_signal_handler_disconnect (impl->manager, impl->manager_changed_id);
+      impl->manager_changed_id = 0;
+    }
+
+  if (impl->manager)
+    g_object_unref (impl->manager);
+  
+  if (impl->sort_data_destroy)
+    {
+      impl->sort_data_destroy (impl->sort_data);
+      
+      impl->sort_data_destroy = NULL;
+      impl->sort_data = NULL;
+      impl->sort_func = NULL;
+    }
+    
+  if (impl->filters)
+    {
+      g_slist_foreach (impl->filters,
+      		       (GFunc) g_object_unref,
+      		       NULL);
+      g_slist_free (impl->filters);    
+    }
+  
+  if (impl->current_filter)
+    g_object_unref (impl->current_filter);
+
+  if (impl->recent_store_filter)
+    g_object_unref (impl->recent_store_filter);
+
+  if (impl->recent_store)
+    g_object_unref (impl->recent_store);
+
+  if (impl->tooltips)
+    g_object_unref (impl->tooltips);
+  
+  G_OBJECT_CLASS (gtk_recent_chooser_default_parent_class)->finalize (object);
+}
+
+/* override GtkWidget::show_all since we have internal widgets we wish to keep
+ * hidden unless we decide otherwise, like the filter combo box.
+ */
+static void
+gtk_recent_chooser_default_show_all (GtkWidget *widget)
+{
+  gtk_widget_show (widget);
+}
+
+
+
+/* Shows an error dialog set as transient for the specified window */
+static void
+error_message_with_parent (GtkWindow   *parent,
+			   const gchar *msg,
+			   const gchar *detail)
+{
+  GtkWidget *dialog;
+
+  dialog = gtk_message_dialog_new (parent,
+				   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+				   GTK_MESSAGE_ERROR,
+				   GTK_BUTTONS_OK,
+				   "%s",
+				   msg);
+  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+					    "%s", detail);
+
+  if (parent->group)
+    gtk_window_group_add_window (parent->group, GTK_WINDOW (dialog));
+
+  gtk_dialog_run (GTK_DIALOG (dialog));
+  gtk_widget_destroy (dialog);
+}
+
+/* Returns a toplevel GtkWindow, or NULL if none */
+static GtkWindow *
+get_toplevel (GtkWidget *widget)
+{
+  GtkWidget *toplevel;
+
+  toplevel = gtk_widget_get_toplevel (widget);
+  if (!GTK_WIDGET_TOPLEVEL (toplevel))
+    return NULL;
+  else
+    return GTK_WINDOW (toplevel);
+}
+
+/* Shows an error dialog for the file chooser */
+static void
+error_message (GtkRecentChooserDefault *impl,
+	       const gchar             *msg,
+	       const gchar             *detail)
+{
+  error_message_with_parent (get_toplevel (GTK_WIDGET (impl)), msg, detail);
+}
+
+static void
+set_busy_cursor (GtkRecentChooserDefault *impl,
+		 gboolean                 show_busy_cursor)
+{
+  GtkWindow *toplevel;
+  GdkDisplay *display;
+  GdkCursor *cursor;
+
+  toplevel = get_toplevel (GTK_WIDGET (impl));
+  if (!toplevel || !GTK_WIDGET_REALIZED (toplevel))
+    return;
+  
+  display = gtk_widget_get_display (GTK_WIDGET (toplevel));
+  
+  cursor = NULL;
+  if (show_busy_cursor)
+    cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
+
+  gdk_window_set_cursor (GTK_WIDGET (toplevel)->window, cursor);
+  gdk_display_flush (display);
+
+  if (cursor)
+    gdk_cursor_unref (cursor);
+}
+
+static void
+chooser_set_model (GtkRecentChooserDefault *impl)
+{
+  g_assert (impl->recent_store != NULL);
+  g_assert (impl->recent_store_filter == NULL);
+  g_assert (impl->load_state == LOAD_LOADING);
+  
+  impl->recent_store_filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (impl->recent_store), NULL);
+  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (impl->recent_store_filter),
+		  			  recent_store_filter_func,
+					  impl,
+					  NULL);
+  
+  gtk_tree_view_set_model (GTK_TREE_VIEW (impl->recent_view),
+      			   impl->recent_store_filter);
+  gtk_tree_view_columns_autosize (GTK_TREE_VIEW (impl->recent_view));
+  gtk_tree_view_set_enable_search (GTK_TREE_VIEW (impl->recent_view), TRUE);
+  gtk_tree_view_set_search_column (GTK_TREE_VIEW (impl->recent_view),
+  				   RECENT_DISPLAY_NAME_COLUMN);
+
+  impl->load_state = LOAD_FINISHED;
+}
+
+static gboolean
+load_recent_items (gpointer user_data)
+{
+  GtkRecentChooserDefault *impl;
+  GtkRecentInfo *info;
+  GtkTreeIter iter;
+  const gchar *uri, *name;
+  gboolean retval;
+  
+  GDK_THREADS_ENTER ();
+  
+  impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
+  
+  g_assert ((impl->load_state == LOAD_EMPTY) ||
+            (impl->load_state == LOAD_PRELOAD));
+  
+  /* store the items for multiple runs */
+  if (!impl->recent_items)
+    {
+      impl->recent_items = gtk_recent_chooser_get_items (GTK_RECENT_CHOOSER (impl));
+      if (!impl->recent_items)
+        {
+          GDK_THREADS_LEAVE ();
+
+	  impl->load_state = LOAD_FINISHED;
+          
+          return FALSE;
+        }
+        
+      impl->n_recent_items = g_list_length (impl->recent_items);
+      impl->loaded_items = 0;
+      impl->load_state = LOAD_PRELOAD;
+    }
+  
+  info = (GtkRecentInfo *) g_list_nth_data (impl->recent_items,
+                                            impl->loaded_items);
+  g_assert (info);
+
+  uri = gtk_recent_info_get_uri (info);
+  name = gtk_recent_info_get_display_name (info);
+  
+  /* at this point, everything goes inside the model; operations on the
+   * visualization of items inside the model are done in the cell data
+   * funcs (remember that there are two of those: one for the icon and
+   * one for the text), while the filtering is done only when a filter
+   * is actually loaded. */
+  gtk_list_store_append (impl->recent_store, &iter);
+  gtk_list_store_set (impl->recent_store, &iter,
+  		      RECENT_URI_COLUMN, uri,           /* uri  */
+  		      RECENT_DISPLAY_NAME_COLUMN, name, /* display_name */
+  		      RECENT_INFO_COLUMN, info,         /* info */
+  		      -1);
+  
+  impl->loaded_items += 1;
+
+  if (impl->loaded_items == impl->n_recent_items)
+    {
+      /* we have finished loading, so we remove the items cache */
+      impl->load_state = LOAD_LOADING;
+      
+      g_list_foreach (impl->recent_items,
+      		      (GFunc) gtk_recent_info_unref,
+      		      NULL);
+      g_list_free (impl->recent_items);
+      
+      impl->recent_items = NULL;
+      impl->n_recent_items = 0;
+      impl->loaded_items = 0;
+      
+      if (impl->recent_store_filter)
+        {
+          g_object_unref (impl->recent_store_filter);
+	  impl->recent_store_filter = NULL;
+	}
+      
+      /* load the filled up model */
+      chooser_set_model (impl);
+
+      retval = FALSE;
+    }
+  else
+    {
+      /* we did not finish, so continue loading */
+      retval = TRUE;
+    }
+  
+  GDK_THREADS_LEAVE ();
+  
+  return retval;
+}
+
+static void
+cleanup_after_load (gpointer user_data)
+{
+  GtkRecentChooserDefault *impl;
+  
+  GDK_THREADS_ENTER ();
+  
+  impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
+
+  if (impl->load_id != 0)
+    {
+      g_assert ((impl->load_state == LOAD_PRELOAD) ||
+		(impl->load_state == LOAD_LOADING) ||
+		(impl->load_state == LOAD_FINISHED));
+      
+      /* we have officialy finished loading all the items,
+       * so we can reset the state machine
+       */
+      g_source_remove (impl->load_id);
+      impl->load_id = 0;
+      impl->load_state = LOAD_EMPTY;
+    }
+  else
+    g_assert ((impl->load_state == LOAD_EMPTY) ||
+	      (impl->load_state == LOAD_LOADING) ||
+	      (impl->load_state == LOAD_FINISHED));
+
+  set_busy_cursor (impl, FALSE);
+  
+  GDK_THREADS_LEAVE ();
+}
+
+/* clears the current model and reloads the recently used resources */
+static void
+reload_recent_items (GtkRecentChooserDefault *impl)
+{
+  /* reload is already in progress - do not disturb */
+  if (impl->load_id)
+    return;
+  
+  gtk_tree_view_set_model (GTK_TREE_VIEW (impl->recent_view), NULL);
+  gtk_list_store_clear (impl->recent_store);
+  
+  if (!impl->icon_theme)
+    impl->icon_theme = get_icon_theme_for_widget (GTK_WIDGET (impl));
+
+  impl->icon_size = get_icon_size_for_widget (GTK_WIDGET (impl),
+		  			      GTK_ICON_SIZE_BUTTON);
+
+  set_busy_cursor (impl, TRUE);
+
+  impl->load_state = LOAD_EMPTY;
+  impl->load_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 30,
+		      		   load_recent_items,
+				   impl,
+				   cleanup_after_load);
+}
+
+/* taken form gtkfilechooserdialog.c */
+static void
+set_default_size (GtkRecentChooserDefault *impl)
+{
+  GtkWidget *widget;
+  gint width, height;
+  gint font_size;
+  GdkScreen *screen;
+  gint monitor_num;
+  GtkRequisition req;
+  GdkRectangle monitor;
+
+  widget = GTK_WIDGET (impl);
+
+  /* Size based on characters and the icon size */
+  font_size = pango_font_description_get_size (widget->style->font_desc);
+  font_size = PANGO_PIXELS (font_size);
+
+  width = impl->icon_size + font_size * NUM_CHARS;
+  height = (impl->icon_size + font_size) * NUM_LINES;
+
+  /* Use at least the requisition size... */
+  gtk_widget_size_request (widget, &req);
+  width = MAX (width, req.width);
+  height = MAX (height, req.height);
+
+  /* ... but no larger than the monitor */
+  screen = gtk_widget_get_screen (widget);
+  monitor_num = gdk_screen_get_monitor_at_window (screen, widget->window);
+
+  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+
+  width = MIN (width, monitor.width * 3 / 4);
+  height = MIN (height, monitor.height * 3 / 4);
+
+  /* Set size */
+  gtk_widget_set_size_request (impl->recent_view, width, height);
+}
+
+static void
+gtk_recent_chooser_default_map (GtkWidget *widget)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (widget);
+  
+  if (GTK_WIDGET_CLASS (gtk_recent_chooser_default_parent_class)->map)
+    GTK_WIDGET_CLASS (gtk_recent_chooser_default_parent_class)->map (widget);
+
+  /* reloads everything */
+  reload_recent_items (impl);
+
+  set_default_size (impl);
+}
+
+static void
+recent_icon_data_func (GtkTreeViewColumn *tree_column,
+		       GtkCellRenderer   *cell,
+		       GtkTreeModel      *model,
+		       GtkTreeIter       *iter,
+		       gpointer           user_data)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
+  GtkRecentInfo *info = NULL;
+  GdkPixbuf *pixbuf;
+  
+  gtk_tree_model_get (model, iter,
+                      RECENT_INFO_COLUMN, &info,
+                      -1);
+  g_assert (info != NULL);
+  
+  pixbuf = gtk_recent_info_get_icon (info, impl->icon_size);
+  
+  g_object_set (cell,
+                "pixbuf", pixbuf,
+                NULL);
+  
+  if (pixbuf)  
+    g_object_unref (pixbuf);
+}
+
+static void
+recent_meta_data_func (GtkTreeViewColumn *tree_column,
+		       GtkCellRenderer   *cell,
+		       GtkTreeModel      *model,
+		       GtkTreeIter       *iter,
+		       gpointer           user_data)
+{
+  GtkRecentInfo *info = NULL;
+  gchar *uri;
+  gchar *name;
+  GString *data;
+  
+  data = g_string_new (NULL);
+  
+  gtk_tree_model_get (model, iter,
+                      RECENT_DISPLAY_NAME_COLUMN, &name,
+                      RECENT_INFO_COLUMN, &info,
+                      -1);
+  g_assert (info != NULL);
+  
+  uri = gtk_recent_info_get_uri_display (info);
+  
+  if (!name)
+    name = gtk_recent_info_get_short_name (info);
+ 
+  g_string_append_printf (data,
+  			  "<b>%s</b>\n"
+  			  "<small>Location: %s</small>",
+  			  name,
+  			  uri);
+  
+  g_object_set (cell,
+                "markup", data->str,
+                "sensitive", gtk_recent_info_exists (info),
+                NULL);
+  
+  g_string_free (data, TRUE);
+  g_free (uri);
+  g_free (name);
+  gtk_recent_info_unref (info);
+}
+
+
+static gchar *
+gtk_recent_chooser_default_get_current_uri (GtkRecentChooser *chooser)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
+  
+  g_assert (impl->selection != NULL);
+  
+  if (!impl->select_multiple)
+    {
+      GtkTreeModel *model;
+      GtkTreeIter iter;
+      gchar *uri = NULL;
+      
+      if (!gtk_tree_selection_get_selected (impl->selection, &model, &iter))
+        return NULL;
+      
+      gtk_tree_model_get (model, &iter, RECENT_URI_COLUMN, &uri, -1);
+      
+      return uri;
+    }
+  
+  return NULL;
+}
+
+typedef struct
+{
+  guint found : 1;
+  guint do_select : 1;
+  guint do_activate : 1;
+  
+  gchar *uri;
+  
+  GtkRecentChooserDefault *impl;
+} SelectURIData;
+
+static gboolean
+scan_for_uri_cb (GtkTreeModel *model,
+		 GtkTreePath  *path,
+		 GtkTreeIter  *iter,
+		 gpointer      user_data)
+{
+  SelectURIData *select_data = (SelectURIData *) user_data;
+  gchar *uri;
+  
+  if (!select_data)
+    return TRUE;
+  
+  if (select_data->found)
+    return TRUE;
+  
+  gtk_tree_model_get (model, iter, RECENT_URI_COLUMN, &uri, -1);
+  if (uri && (0 == strcmp (uri, select_data->uri)))
+    {
+      select_data->found = TRUE;
+      
+      if (select_data->do_activate)
+        {
+          gtk_tree_view_row_activated (GTK_TREE_VIEW (select_data->impl->recent_view),
+        				       path,
+        				       select_data->impl->meta_column);
+          
+          return TRUE;
+        }
+      
+      if (select_data->do_select)
+        gtk_tree_selection_select_iter (select_data->impl->selection, iter);
+      else
+        gtk_tree_selection_unselect_iter (select_data->impl->selection, iter);
+      
+      return TRUE;
+    }
+  
+  return FALSE;
+}
+
+static gboolean
+gtk_recent_chooser_default_set_current_uri (GtkRecentChooser  *chooser,
+					    const gchar       *uri,
+					    GError           **error)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
+  SelectURIData *data;
+  
+  data = g_new0 (SelectURIData, 1);
+  data->uri = g_strdup (uri);
+  data->impl = impl;
+  data->found = FALSE;
+  data->do_activate = TRUE;
+  data->do_select = TRUE;
+  
+  gtk_tree_model_foreach (GTK_TREE_MODEL (impl->recent_store),
+  			  scan_for_uri_cb,
+  			  data);
+  
+  if (!data->found)
+    {
+      g_free (data->uri);
+      g_free (data);
+      
+      g_set_error (error, GTK_RECENT_CHOOSER_ERROR,
+      		   GTK_RECENT_CHOOSER_ERROR_NOT_FOUND,
+      		   _("No item for URI '%s' found"),
+      		   uri);
+      return FALSE;
+    }
+  
+  g_free (data->uri);
+  g_free (data);
+
+  return TRUE;
+}
+
+static gboolean
+gtk_recent_chooser_default_select_uri (GtkRecentChooser  *chooser,
+				       const gchar       *uri,
+				       GError           **error)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
+  SelectURIData *data;
+  
+  data = g_new0 (SelectURIData, 1);
+  data->uri = g_strdup (uri);
+  data->impl = impl;
+  data->found = FALSE;
+  data->do_activate = FALSE;
+  data->do_select = TRUE;
+  
+  gtk_tree_model_foreach (GTK_TREE_MODEL (impl->recent_store),
+  			  scan_for_uri_cb,
+  			  data);
+  
+  if (!data->found)
+    {
+      g_free (data->uri);
+      g_free (data);
+      
+      g_set_error (error, GTK_RECENT_CHOOSER_ERROR,
+      		   GTK_RECENT_CHOOSER_ERROR_NOT_FOUND,
+      		   _("No item for URI '%s' found"),
+      		   uri);
+      return FALSE;
+    }
+  
+  g_free (data->uri);
+  g_free (data);
+
+  return TRUE;
+}
+
+static void
+gtk_recent_chooser_default_unselect_uri (GtkRecentChooser *chooser,
+					 const gchar      *uri)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
+  SelectURIData *data;
+  
+  data = g_new0 (SelectURIData, 1);
+  data->uri = g_strdup (uri);
+  data->impl = impl;
+  data->found = FALSE;
+  data->do_activate = FALSE;
+  data->do_select = FALSE;
+  
+  gtk_tree_model_foreach (GTK_TREE_MODEL (impl->recent_store),
+  			  scan_for_uri_cb,
+  			  data);
+  
+  g_free (data->uri);
+  g_free (data);
+}
+
+static void
+gtk_recent_chooser_default_select_all (GtkRecentChooser *chooser)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
+  
+  if (!impl->select_multiple)
+    return;
+  
+  gtk_tree_selection_select_all (impl->selection);
+}
+
+static void
+gtk_recent_chooser_default_unselect_all (GtkRecentChooser *chooser)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
+  
+  gtk_tree_selection_unselect_all (impl->selection);
+}
+
+static void
+gtk_recent_chooser_default_set_sort_func (GtkRecentChooser  *chooser,
+					  GtkRecentSortFunc  sort_func,
+					  gpointer           sort_data,
+					  GDestroyNotify     data_destroy)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
+  
+  if (impl->sort_data_destroy)
+    {
+      impl->sort_data_destroy (impl->sort_data);
+      
+      impl->sort_func = NULL;
+      impl->sort_data = NULL;
+      impl->sort_data_destroy = NULL;
+    }
+  
+  if (sort_func)
+    {
+      impl->sort_func = sort_func;
+      impl->sort_data = sort_data;
+      impl->sort_data_destroy = data_destroy;
+    }
+}
+
+static gint
+sort_recent_items_mru (GtkRecentInfo *a,
+		       GtkRecentInfo *b,
+		       gpointer       unused)
+{
+  g_assert (a != NULL && b != NULL);
+  
+  return (gtk_recent_info_get_modified (a) < gtk_recent_info_get_modified (b));
+}
+
+static gint
+sort_recent_items_lru (GtkRecentInfo *a,
+		       GtkRecentInfo *b,
+		       gpointer       unused)
+{
+  g_assert (a != NULL && b != NULL);
+  
+  return (gtk_recent_info_get_modified (a) > gtk_recent_info_get_modified (b));
+}
+
+/* our proxy sorting function */
+static gint
+sort_recent_items_proxy (gpointer *a,
+			 gpointer *b,
+			 gpointer  user_data)
+{
+  GtkRecentInfo *info_a = (GtkRecentInfo *) a;
+  GtkRecentInfo *info_b = (GtkRecentInfo *) b;
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
+
+  if (impl->sort_func)
+    return (* impl->sort_func) (info_a,
+    				info_b,
+      				impl->sort_data);
+  
+  /* fallback */
+  return 0;
+}
+
+static void
+chooser_set_sort_type (GtkRecentChooserDefault *impl,
+		       GtkRecentSortType        sort_type)
+{
+  if (impl->sort_type == sort_type)
+    return;
+
+  impl->sort_type = sort_type;
+}
+
+static GList *
+gtk_recent_chooser_default_get_items (GtkRecentChooser *chooser)
+{
+  GtkRecentChooserDefault *impl;
+  gint limit;
+  GtkRecentSortType sort_type;
+  GList *items;
+  GCompareDataFunc compare_func;
+  gint length;
+  
+  impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
+  
+  if (!impl->manager)
+    return NULL;
+
+  items = gtk_recent_manager_get_items (impl->manager);
+  if (!items)
+    return NULL;
+ 
+  limit = gtk_recent_chooser_get_limit (chooser);
+  sort_type = gtk_recent_chooser_get_sort_type (chooser);
+
+  switch (sort_type)
+    {
+    case GTK_RECENT_SORT_NONE:
+      compare_func = NULL;
+      break;
+    case GTK_RECENT_SORT_MRU:
+      compare_func = (GCompareDataFunc) sort_recent_items_mru;
+      break;
+    case GTK_RECENT_SORT_LRU:
+      compare_func = (GCompareDataFunc) sort_recent_items_lru;
+      break;
+    case GTK_RECENT_SORT_CUSTOM:
+      compare_func = (GCompareDataFunc) sort_recent_items_proxy;
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+  
+  /* sort the items; the filtering will be dealt with using
+   * the treeview's own filter object
+   */
+  if (compare_func)
+    items = g_list_sort_with_data (items, compare_func, impl);
+  
+  length = g_list_length (items);
+  if ((limit != -1) && (length > limit))
+    {
+      GList *clamp, *l;
+      
+      clamp = g_list_nth (items, limit - 1);
+      
+      if (!clamp)
+        return items;
+      
+      l = clamp->next;
+      clamp->next = NULL;
+    
+      g_list_foreach (l, (GFunc) gtk_recent_info_unref, NULL);
+      g_list_free (l);
+    }
+  
+  return items;
+}
+
+static GtkRecentManager *
+gtk_recent_chooser_default_get_recent_manager (GtkRecentChooser *chooser)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
+  
+  return impl->manager;
+}
+
+static void
+show_filters (GtkRecentChooserDefault *impl,
+              gboolean                 show)
+{
+  if (show)
+    gtk_widget_show (impl->filter_combo_hbox);
+  else
+    gtk_widget_hide (impl->filter_combo_hbox);
+}
+
+static void
+gtk_recent_chooser_default_add_filter (GtkRecentChooser *chooser,
+				       GtkRecentFilter  *filter)
+{
+  GtkRecentChooserDefault *impl;
+  const gchar *name;
+
+  impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
+  
+  if (g_slist_find (impl->filters, filter))
+    {
+      g_warning ("gtk_recent_chooser_add_filter() called on filter already in list\n");
+      return;
+    }
+  
+  g_object_ref_sink (filter);
+  impl->filters = g_slist_append (impl->filters, filter);
+  
+  /* display new filter */
+  name = gtk_recent_filter_get_name (filter);
+  if (!name)
+    name = "Untitled filter";
+    
+  gtk_combo_box_append_text (GTK_COMBO_BOX (impl->filter_combo), name);
+  
+  if (!g_slist_find (impl->filters, impl->current_filter))
+    set_current_filter (impl, filter);
+  
+  show_filters (impl, TRUE);
+}
+
+static void
+gtk_recent_chooser_default_remove_filter (GtkRecentChooser *chooser,
+					  GtkRecentFilter  *filter)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  gint filter_idx;
+  
+  filter_idx = g_slist_index (impl->filters, filter);
+  
+  if (filter_idx < 0)
+    {
+      g_warning ("gtk_recent_chooser_remove_filter() called on filter not in list\n");
+      return;  
+    }
+  
+  impl->filters = g_slist_remove (impl->filters, filter);
+  
+  if (filter == impl->current_filter)
+    {
+      if (impl->filters)
+        set_current_filter (impl, impl->filters->data);
+      else
+        set_current_filter (impl, NULL);
+    }
+  
+  model = gtk_combo_box_get_model (GTK_COMBO_BOX (impl->filter_combo));
+  gtk_tree_model_iter_nth_child (model, &iter, NULL, filter_idx);
+  gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+  
+  g_object_unref (filter);
+  
+  if (!impl->filters)
+    show_filters (impl, FALSE);
+}
+
+static GSList *
+gtk_recent_chooser_default_list_filters (GtkRecentChooser *chooser)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (chooser);
+  
+  return g_slist_copy (impl->filters);
+}
+
+static gboolean
+get_is_recent_filtered (GtkRecentChooserDefault *impl,
+			GtkRecentInfo           *info)
+{
+  GtkRecentFilter *current_filter;
+  GtkRecentFilterInfo filter_info;
+  GtkRecentFilterFlags needed;
+  gboolean retval;
+
+  g_assert (info != NULL);
+  
+  if (!impl->current_filter)
+    return FALSE;
+  
+  current_filter = impl->current_filter;
+  needed = gtk_recent_filter_get_needed (current_filter);
+  
+  filter_info.contains = GTK_RECENT_FILTER_URI | GTK_RECENT_FILTER_MIME_TYPE;
+  
+  filter_info.uri = gtk_recent_info_get_uri (info);
+  filter_info.mime_type = gtk_recent_info_get_mime_type (info);
+  
+  if (needed & GTK_RECENT_FILTER_DISPLAY_NAME)
+    {
+      filter_info.display_name = gtk_recent_info_get_display_name (info);
+      filter_info.contains |= GTK_RECENT_FILTER_DISPLAY_NAME;
+    }
+  else
+    filter_info.uri = NULL;
+  
+  if (needed & GTK_RECENT_FILTER_APPLICATION)
+    {
+      filter_info.applications = (const gchar **) gtk_recent_info_get_applications (info, NULL);
+      filter_info.contains |= GTK_RECENT_FILTER_APPLICATION;
+    }
+  else
+    filter_info.applications = NULL;
+
+  if (needed & GTK_RECENT_FILTER_GROUP)
+    {
+      filter_info.groups = (const gchar **) gtk_recent_info_get_groups (info, NULL);
+      filter_info.contains |= GTK_RECENT_FILTER_GROUP;
+    }
+  else
+    filter_info.groups = NULL;
+
+  if (needed & GTK_RECENT_FILTER_AGE)
+    {
+      filter_info.age = gtk_recent_info_get_age (info);
+      filter_info.contains |= GTK_RECENT_FILTER_AGE;
+    }
+  else
+    filter_info.age = -1;
+  
+  retval = gtk_recent_filter_filter (current_filter, &filter_info);
+  
+  /* this we own */
+  if (filter_info.applications)
+    g_strfreev ((gchar **) filter_info.applications);
+  
+  return !retval;
+}
+
+static gboolean
+recent_store_filter_func (GtkTreeModel *model,
+                          GtkTreeIter  *iter,
+                          gpointer      user_data)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
+  GtkRecentInfo *info = NULL;
+
+  if (!impl->current_filter)
+    return TRUE;
+  
+  gtk_tree_model_get (model, iter,
+                      RECENT_INFO_COLUMN, &info,
+                      -1);
+  if (!info)
+    return TRUE;
+    
+  if (get_is_recent_filtered (impl, info))
+    return FALSE;
+  
+  if (impl->local_only && !gtk_recent_info_is_local (info))
+    return FALSE;
+  
+  if ((!impl->show_private) && gtk_recent_info_get_private_hint (info))
+    return FALSE;
+  
+  if ((!impl->show_not_found) && !gtk_recent_info_exists (info))
+    return FALSE;
+      
+  return TRUE;
+}
+
+static void
+set_current_filter (GtkRecentChooserDefault *impl,
+		    GtkRecentFilter         *filter)
+{
+  if (impl->current_filter != filter)
+    {
+      gint filter_idx;
+      
+      filter_idx = g_slist_index (impl->filters, filter);
+      if (impl->filters && filter && filter_idx < 0)
+        return;
+      
+      if (impl->current_filter)
+        g_object_unref (impl->current_filter);
+      
+      impl->current_filter = filter;
+      
+      if (impl->current_filter)     
+        {
+          g_object_ref_sink (impl->current_filter);
+        }
+      
+      if (impl->filters)
+        gtk_combo_box_set_active (GTK_COMBO_BOX (impl->filter_combo),
+                                  filter_idx);
+      
+      if (impl->recent_store && impl->recent_store_filter)
+        {
+          gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->recent_store_filter));
+        }
+      
+      g_object_notify (G_OBJECT (impl), "filter");
+    }
+}
+
+static GtkIconTheme *
+get_icon_theme_for_widget (GtkWidget *widget)
+{
+  if (gtk_widget_has_screen (widget))
+    return gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
+
+  return gtk_icon_theme_get_default ();
+}
+
+static gint
+get_icon_size_for_widget (GtkWidget   *widget,
+			  GtkIconSize  icon_size)
+{
+  GtkSettings *settings;
+  gint width, height;
+
+  if (gtk_widget_has_screen (widget))
+    settings = gtk_settings_get_for_screen (gtk_widget_get_screen (widget));
+  else
+    settings = gtk_settings_get_default ();
+
+  if (gtk_icon_size_lookup_for_settings (settings, icon_size,
+                                         &width, &height))
+    return MAX (width, height);
+
+  return FALLBACK_ICON_SIZE;
+}
+
+
+static void
+recent_manager_changed_cb (GtkRecentManager *manager,
+			   gpointer          user_data)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
+
+  reload_recent_items (impl);
+}
+
+static void
+selection_changed_cb (GtkTreeSelection *selection,
+		      gpointer          user_data)
+{
+  _gtk_recent_chooser_selection_changed (GTK_RECENT_CHOOSER (user_data));
+}
+
+static void
+row_activated_cb (GtkTreeView       *tree_view,
+		  GtkTreePath       *tree_path,
+		  GtkTreeViewColumn *tree_column,
+		  gpointer           user_data)
+{
+  _gtk_recent_chooser_item_activated (GTK_RECENT_CHOOSER (user_data));
+}
+
+static void
+filter_combo_changed_cb (GtkComboBox *combo_box,
+			 gpointer     user_data)
+{
+  GtkRecentChooserDefault *impl;
+  gint new_index;
+  GtkRecentFilter *filter;
+  
+  impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
+  
+  new_index = gtk_combo_box_get_active (combo_box);
+  filter = g_slist_nth_data (impl->filters, new_index);
+  
+  set_current_filter (impl, filter);
+}
+
+static GdkPixbuf *
+get_drag_pixbuf (GtkRecentChooserDefault *impl)
+{
+  GtkRecentInfo *info;
+  GdkPixbuf *retval;
+  gint size;
+  
+  g_assert (GTK_IS_RECENT_CHOOSER_DEFAULT (impl));
+
+  info = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (impl));
+  if (!info)
+    return NULL;
+
+  size = get_icon_size_for_widget (GTK_WIDGET (impl), GTK_ICON_SIZE_DND);
+
+  retval = gtk_recent_info_get_icon (info, size);
+  gtk_recent_info_unref (info);
+
+  return retval;
+}
+
+static void
+recent_view_drag_begin_cb (GtkWidget      *widget,
+			   GdkDragContext *context,
+			   gpointer        user_data)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
+  GdkPixbuf *pixbuf;
+
+  pixbuf = get_drag_pixbuf (impl);
+  if (pixbuf)
+    {
+      gtk_drag_set_icon_pixbuf (context, pixbuf, 0, 0);
+      g_object_unref (pixbuf);
+    }
+  else
+    gtk_drag_set_icon_default (context);
+}
+
+typedef struct
+{
+  gchar **uri_list;
+  gsize next_pos;
+} DragData;
+
+static void
+append_uri_to_urilist (GtkTreeModel *model,
+		       GtkTreePath  *path,
+		       GtkTreeIter  *iter,
+		       gpointer      user_data)
+{
+  DragData *drag_data = (DragData *) user_data;
+  GtkTreeModel *child_model;
+  GtkTreeIter child_iter;
+  gchar *uri = NULL;
+  gsize pos;
+
+  child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
+  gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model),
+  						    &child_iter,
+  						    iter);
+  gtk_tree_model_get (child_model, &child_iter,
+  		      RECENT_URI_COLUMN, &uri,
+  		      -1);
+  g_assert (uri != NULL);
+
+  pos = drag_data->next_pos;
+  drag_data->uri_list[pos] = g_strdup (uri);
+  drag_data->next_pos = pos + 1;
+}
+
+static void
+recent_view_drag_data_get_cb (GtkWidget        *widget,
+			      GdkDragContext   *context,
+			      GtkSelectionData *selection_data,
+			      guint             info,
+			      guint32           time_,
+			      gpointer          data)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (data);
+  DragData *drag_data;
+  gsize n_uris;
+  
+  n_uris = gtk_tree_selection_count_selected_rows (impl->selection);
+  if (n_uris == 0)
+	  return;
+
+  drag_data = g_new (DragData, 1);
+  drag_data->uri_list = g_new0 (gchar *, n_uris + 1);
+  drag_data->next_pos = 0;
+  
+  gtk_tree_selection_selected_foreach (impl->selection,
+      				       append_uri_to_urilist,
+      				       drag_data);
+  
+  gtk_selection_data_set_uris (selection_data, drag_data->uri_list);
+
+  g_strfreev (drag_data->uri_list);
+  g_free (drag_data);
+}
+
+
+
+static void
+remove_selected_from_list (GtkRecentChooserDefault *impl)
+{
+  gchar *uri;
+  GError *err;
+  
+  if (impl->select_multiple)
+    return;
+  
+  uri = gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (impl));
+  if (!uri)
+    return;
+  
+  err = NULL;
+  if (!gtk_recent_manager_remove_item (impl->manager, uri, &err))
+    {
+      gchar *msg;
+   
+      msg = strdup (_("Could not remove item"));
+      error_message (impl, msg, err->message);
+      
+      g_free (msg);
+      g_error_free (err);
+    }
+  
+  g_free (uri);
+}
+
+static void
+copy_activated_cb (GtkMenuItem *menu_item,
+		   gpointer     user_data)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
+  GtkRecentInfo *info;
+  gchar *utf8_uri;
+
+  info = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (impl));
+  if (!info)
+    return;
+
+  utf8_uri = gtk_recent_info_get_uri_display (info);
+  
+  gtk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (impl),
+			  			    GDK_SELECTION_CLIPBOARD),
+                          utf8_uri, -1);
+
+  g_free (utf8_uri);
+}
+
+static void
+remove_all_activated_cb (GtkMenuItem *menu_item,
+			 gpointer     user_data)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
+  GError *err = NULL;
+  
+  gtk_recent_manager_purge_items (impl->manager, &err);
+  if (err)
+    {
+       gchar *msg;
+
+       msg = g_strdup (_("Could not clear list"));
+
+       error_message (impl, msg, err->message);
+       
+       g_free (msg);
+       g_error_free (err);
+    }
+}
+
+static void
+remove_item_activated_cb (GtkMenuItem *menu_item,
+			  gpointer     user_data)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
+  
+  remove_selected_from_list (impl);
+}
+
+static void
+show_private_toggled_cb (GtkCheckMenuItem *menu_item,
+			 gpointer          user_data)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
+  
+  g_object_set (G_OBJECT (impl),
+  		"show-private", gtk_check_menu_item_get_active (menu_item),
+  		NULL);
+}
+
+static void
+recent_popup_menu_detach_cb (GtkWidget *attach_widget,
+			     GtkMenu   *menu)
+{
+  GtkRecentChooserDefault *impl;
+  
+  impl = g_object_get_data (G_OBJECT (attach_widget), "GtkRecentChooserDefault");
+  g_assert (GTK_IS_RECENT_CHOOSER_DEFAULT (impl));
+  
+  impl->recent_popup_menu = NULL;
+  impl->recent_popup_menu_remove_item = NULL;
+  impl->recent_popup_menu_copy_item = NULL;
+  impl->recent_popup_menu_clear_item = NULL;
+  impl->recent_popup_menu_show_private_item = NULL;
+}
+
+static void
+recent_view_menu_ensure_state (GtkRecentChooserDefault *impl)
+{
+  gint count;
+  
+  g_assert (GTK_IS_RECENT_CHOOSER_DEFAULT (impl));
+  g_assert (impl->recent_popup_menu != NULL);
+
+  if (!impl->manager)
+    count = 0;
+  else
+    g_object_get (G_OBJECT (impl->manager), "size", &count, NULL);
+
+  if (count == 0)
+    {
+      gtk_widget_set_sensitive (impl->recent_popup_menu_remove_item, FALSE);
+      gtk_widget_set_sensitive (impl->recent_popup_menu_copy_item, FALSE);
+      gtk_widget_set_sensitive (impl->recent_popup_menu_clear_item, FALSE);
+      gtk_widget_set_sensitive (impl->recent_popup_menu_show_private_item, FALSE);
+    }
+}
+
+static void
+recent_view_menu_build (GtkRecentChooserDefault *impl)
+{
+  GtkWidget *item;
+  
+  if (impl->recent_popup_menu)
+    {
+      recent_view_menu_ensure_state (impl);
+      
+      return;
+    }
+  
+  impl->recent_popup_menu = gtk_menu_new ();
+  gtk_menu_attach_to_widget (GTK_MENU (impl->recent_popup_menu),
+  			     impl->recent_view,
+  			     recent_popup_menu_detach_cb);
+  
+  item = gtk_image_menu_item_new_with_mnemonic (_("Copy _Location"));
+  impl->recent_popup_menu_copy_item = item;
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
+		  		 gtk_image_new_from_stock (GTK_STOCK_COPY, GTK_ICON_SIZE_MENU));
+  g_signal_connect (item, "activate",
+		    G_CALLBACK (copy_activated_cb), impl);
+  gtk_widget_show (item);
+  gtk_menu_shell_append (GTK_MENU_SHELL (impl->recent_popup_menu), item);
+
+  item = gtk_separator_menu_item_new ();
+  gtk_widget_show (item);
+  gtk_menu_shell_append (GTK_MENU_SHELL (impl->recent_popup_menu), item);
+  
+  item = gtk_image_menu_item_new_with_mnemonic (_("_Remove From List"));
+  impl->recent_popup_menu_remove_item = item;
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
+  				 gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU));
+  g_signal_connect (item, "activate",
+  		    G_CALLBACK (remove_item_activated_cb), impl);
+  gtk_widget_show (item);
+  gtk_menu_shell_append (GTK_MENU_SHELL (impl->recent_popup_menu), item);
+
+  item = gtk_image_menu_item_new_with_mnemonic (_("_Clear List"));
+  impl->recent_popup_menu_clear_item = item;
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
+  				 gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU));
+  g_signal_connect (item, "activate",
+		    G_CALLBACK (remove_all_activated_cb), impl);
+  
+  gtk_widget_show (item);
+  gtk_menu_shell_append (GTK_MENU_SHELL (impl->recent_popup_menu), item);
+  
+  item = gtk_separator_menu_item_new ();
+  gtk_widget_show (item);
+  gtk_menu_shell_append (GTK_MENU_SHELL (impl->recent_popup_menu), item);
+  
+  item = gtk_check_menu_item_new_with_mnemonic (_("Show _Private Resources"));
+  impl->recent_popup_menu_show_private_item = item;
+  gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), impl->show_private);
+  g_signal_connect (item, "toggled",
+  		    G_CALLBACK (show_private_toggled_cb), impl);
+  gtk_widget_show (item);
+  gtk_menu_shell_append (GTK_MENU_SHELL (impl->recent_popup_menu), item);
+  
+  recent_view_menu_ensure_state (impl);
+}
+
+/* taken from gtkfilechooserdefault.c */
+static void
+popup_position_func (GtkMenu   *menu,
+                     gint      *x,
+                     gint      *y,
+                     gboolean  *push_in,
+                     gpointer	user_data)
+{
+  GtkWidget *widget = GTK_WIDGET (user_data);
+  GdkScreen *screen = gtk_widget_get_screen (widget);
+  GtkRequisition req;
+  gint monitor_num;
+  GdkRectangle monitor;
+
+  if (G_UNLIKELY (!GTK_WIDGET_REALIZED (widget)))
+    return;
+
+  gdk_window_get_origin (widget->window, x, y);
+
+  gtk_widget_size_request (GTK_WIDGET (menu), &req);
+
+  *x += (widget->allocation.width - req.width) / 2;
+  *y += (widget->allocation.height - req.height) / 2;
+
+  monitor_num = gdk_screen_get_monitor_at_point (screen, *x, *y);
+  gtk_menu_set_monitor (menu, monitor_num);
+  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+
+  *x = CLAMP (*x, monitor.x, monitor.x + MAX (0, monitor.width - req.width));
+  *y = CLAMP (*y, monitor.y, monitor.y + MAX (0, monitor.height - req.height));
+
+  *push_in = FALSE;
+}
+
+
+static void
+recent_view_menu_popup (GtkRecentChooserDefault *impl,
+			GdkEventButton          *event)
+{
+  recent_view_menu_build (impl);
+  
+  if (event)
+    gtk_menu_popup (GTK_MENU (impl->recent_popup_menu),
+    		    NULL, NULL, NULL, NULL,
+    		    event->button, event->time);
+  else
+    {
+      gtk_menu_popup (GTK_MENU (impl->recent_popup_menu),
+      		      NULL, NULL,
+      		      popup_position_func, impl->recent_view,
+      		      0, GDK_CURRENT_TIME);
+      gtk_menu_shell_select_first (GTK_MENU_SHELL (impl->recent_popup_menu),
+      				   FALSE);
+    }
+}
+
+static gboolean
+recent_view_popup_menu_cb (GtkWidget *widget,
+			   gpointer   user_data)
+{
+  recent_view_menu_popup (GTK_RECENT_CHOOSER_DEFAULT (user_data), NULL);
+  return TRUE;
+}
+
+static gboolean
+recent_view_button_press_cb (GtkWidget      *widget,
+			     GdkEventButton *event,
+			     gpointer        user_data)
+{
+  GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
+  
+  if (event->button == 3)
+    {
+      GtkTreePath *path;
+      gboolean res;
+
+      if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (impl->recent_view)))
+        return FALSE;
+
+      res = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (impl->recent_view),
+		      			   event->x, event->y,
+					   &path,
+					   NULL, NULL, NULL);
+      if (!res)
+        return FALSE;
+
+      /* select the path before creating the popup menu */
+      gtk_tree_selection_select_path (impl->selection, path);
+      gtk_tree_path_free (path);
+      
+      recent_view_menu_popup (impl, event);
+
+      return TRUE;
+    }
+  
+  return FALSE;
+}
+
+static void
+set_recent_manager (GtkRecentChooserDefault *impl,
+		    GtkRecentManager        *manager)
+{
+  if (impl->manager)
+    {
+      g_signal_handler_disconnect (impl, impl->manager_changed_id);
+      impl->manager_changed_id = 0;
+
+      g_object_unref (impl->manager);
+      impl->manager = NULL;
+    }
+  
+  if (manager)
+    {
+      impl->manager = manager;
+      g_object_ref (impl->manager);
+    }
+  else
+    {
+      GdkScreen *screen = gdk_screen_get_default ();
+      GtkRecentManager *default_manager = NULL;
+      
+      default_manager = g_object_get_data (screen, GTK_DEFAULT_RECENT_MANAGER);
+      
+      if (default_manager)
+        impl->manager = g_object_ref (default_manager);
+    }
+  
+  /* create a new recent manager object if none was passed, and attach
+   * it to the GdkScreen
+   */
+  if (!impl->manager)
+    {
+      GdkScreen *screen = gdk_screen_get_default ();
+      
+      impl->manager = gtk_recent_manager_new ();
+      g_object_set_data_full (screen, GTK_DEFAULT_RECENT_MANAGER,
+			      impl->manager,
+			      (GDestroyNotify) g_object_unref);
+    }
+      
+  
+  if (impl->manager)
+    impl->manager_changed_id = g_signal_connect (impl->manager, "changed",
+      						 G_CALLBACK (recent_manager_changed_cb),
+      						 impl);
+}
+
+GtkWidget *
+_gtk_recent_chooser_default_new (GtkRecentManager *manager)
+{
+  return g_object_new (GTK_TYPE_RECENT_CHOOSER_DEFAULT,
+  		       "recent-manager", manager,
+  		       NULL);
+}
+
+#define __GTK_RECENT_CHOOSER_DEFAULT_C__
+#include "gtkaliasdef.c"
diff -Nuarp gtk+/gtk/gtkrecentchooserdefault.h gtk+.recent/gtk/gtkrecentchooserdefault.h
--- gtk+/gtk/gtkrecentchooserdefault.h	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/gtk/gtkrecentchooserdefault.h	2006-03-26 23:46:37.000000000 +0200
@@ -0,0 +1,42 @@
+/* GTK - The GIMP Toolkit
+ * gtkrecentchooserdefault.h
+ * Copyright (C) 2006 Emmanuele Bassi
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_RECENT_CHOOSER_DEFAULT_H__
+#define __GTK_RECENT_CHOOSER_DEFAULT_H__
+
+#include <gtk/gtkwidget.h>
+
+G_BEGIN_DECLS
+
+
+#define GTK_TYPE_RECENT_CHOOSER_DEFAULT    (gtk_recent_chooser_default_get_type ())
+#define GTK_RECENT_CHOOSER_DEFAULT(obj)    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_RECENT_CHOOSER_DEFAULT, GtkRecentChooserDefault))
+#define GTK_IS_RECENT_CHOOSER_DEFAULT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_RECENT_CHOOSER_DEFAULT))
+
+
+typedef struct _GtkRecentChooserDefault GtkRecentChooserDefault;
+
+GType      _gtk_recent_chooser_default_get_type (void) G_GNUC_CONST;
+GtkWidget *_gtk_recent_chooser_default_new      (GtkRecentManager *recent_manager);
+
+
+G_END_DECLS
+
+#endif /* __GTK_RECENT_CHOOSER_DEFAULT_H__ */
diff -Nuarp gtk+/gtk/gtkrecentchooserdialog.c gtk+.recent/gtk/gtkrecentchooserdialog.c
--- gtk+/gtk/gtkrecentchooserdialog.c	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/gtk/gtkrecentchooserdialog.c	2006-03-26 23:46:37.000000000 +0200
@@ -0,0 +1,382 @@
+/* GTK - The GIMP Toolkit
+ * gtkrecentchooserdialog.c: Recent files selector dialog
+ * Copyright (C) 2006 Emmanuele Bassi
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include "gtkrecentchooserdialog.h"
+#include "gtkrecentchooserwidget.h"
+#include "gtkrecentchooserutils.h"
+#include "gtkrecentmanager.h"
+#include "gtktypebuiltins.h"
+#include "gtkalias.h"
+
+#include <stdarg.h>
+
+struct _GtkRecentChooserDialogPrivate
+{
+  GtkRecentManager *manager;
+  
+  GtkWidget *chooser;
+};
+
+#define GTK_RECENT_CHOOSER_DIALOG_GET_PRIVATE(obj)	(GTK_RECENT_CHOOSER_DIALOG (obj)->priv)
+
+static void gtk_recent_chooser_dialog_class_init (GtkRecentChooserDialogClass *klass);
+static void gtk_recent_chooser_dialog_init       (GtkRecentChooserDialog      *dialog);
+static void gtk_recent_chooser_dialog_finalize   (GObject                     *object);
+
+static GObject *gtk_recent_chooser_dialog_constructor (GType                  type,
+						       guint                  n_construct_properties,
+						       GObjectConstructParam *construct_params);
+
+static void gtk_recent_chooser_dialog_set_property (GObject      *object,
+						    guint         prop_id,
+						    const GValue *value,
+						    GParamSpec   *pspec);
+static void gtk_recent_chooser_dialog_get_property (GObject      *object,
+						    guint         prop_id,
+						    GValue       *value,
+						    GParamSpec   *pspec);
+
+static void gtk_recent_chooser_dialog_map       (GtkWidget *widget);
+static void gtk_recent_chooser_dialog_unmap     (GtkWidget *widget);
+static void gtk_recent_chooser_dialog_style_set (GtkWidget *widget,
+						 GtkStyle  *old_style);
+
+
+G_DEFINE_TYPE_WITH_CODE (GtkRecentChooserDialog,
+			 gtk_recent_chooser_dialog,
+			 GTK_TYPE_DIALOG,
+			 G_IMPLEMENT_INTERFACE (GTK_TYPE_RECENT_CHOOSER,
+		       				_gtk_recent_chooser_delegate_iface_init));
+
+static void
+gtk_recent_chooser_dialog_class_init (GtkRecentChooserDialogClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  
+  gobject_class->set_property = gtk_recent_chooser_dialog_set_property;
+  gobject_class->get_property = gtk_recent_chooser_dialog_get_property;
+  gobject_class->constructor = gtk_recent_chooser_dialog_constructor;
+  gobject_class->finalize = gtk_recent_chooser_dialog_finalize;
+  
+  widget_class->map = gtk_recent_chooser_dialog_map;
+  widget_class->unmap = gtk_recent_chooser_dialog_unmap;
+  widget_class->style_set = gtk_recent_chooser_dialog_style_set;
+  
+  _gtk_recent_chooser_install_properties (gobject_class);
+  
+  g_type_class_add_private (klass, sizeof (GtkRecentChooserDialogPrivate));
+}
+
+static void
+gtk_recent_chooser_dialog_init (GtkRecentChooserDialog *dialog)
+{
+  GtkRecentChooserDialogPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (dialog,
+  								     GTK_TYPE_RECENT_CHOOSER_DIALOG,
+  								     GtkRecentChooserDialogPrivate);
+  
+  dialog->priv = priv;
+  
+  gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+}
+
+/* we intercept the GtkRecentChooser::item_activated signal and try to
+ * make the dialog emit a valid response signal
+ */
+static void
+gtk_recent_chooser_item_activated_cb (GtkRecentChooser *chooser,
+				      gpointer          user_data)
+{
+  GtkRecentChooserDialog *dialog;
+  GList *children, *l;
+
+  dialog = GTK_RECENT_CHOOSER_DIALOG (user_data);
+
+  if (gtk_window_activate_default (GTK_WINDOW (dialog)))
+    return;
+  
+  children = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
+  
+  for (l = children; l; l = l->next)
+    {
+      GtkWidget *widget;
+      gint response_id;
+      
+      widget = GTK_WIDGET (l->data);
+      response_id = gtk_dialog_get_response_for_widget (GTK_DIALOG (dialog), widget);
+      
+      if (response_id == GTK_RESPONSE_ACCEPT ||
+          response_id == GTK_RESPONSE_OK     ||
+          response_id == GTK_RESPONSE_YES    ||
+          response_id == GTK_RESPONSE_APPLY)
+        {
+          g_list_free (children);
+	  
+          gtk_dialog_response (GTK_DIALOG (dialog), response_id);
+
+          return;
+        }
+    }
+  
+  g_list_free (children);
+}
+
+static GObject *
+gtk_recent_chooser_dialog_constructor (GType                  type,
+				       guint                  n_construct_properties,
+				       GObjectConstructParam *construct_params)
+{
+  GObject *object;
+  GtkRecentChooserDialogPrivate *priv;
+  
+  object = G_OBJECT_CLASS (gtk_recent_chooser_dialog_parent_class)->constructor (type,
+		  							         n_construct_properties,
+										 construct_params);
+  priv = GTK_RECENT_CHOOSER_DIALOG_GET_PRIVATE (object);
+  
+  gtk_widget_push_composite_child ();
+  
+  if (priv->manager)
+    priv->chooser = g_object_new (GTK_TYPE_RECENT_CHOOSER_WIDGET,
+  				  "recent-manager", priv->manager,
+  				  NULL);
+  else
+    priv->chooser = g_object_new (GTK_TYPE_RECENT_CHOOSER_WIDGET, NULL);
+  
+  g_signal_connect (priv->chooser, "item-activated",
+  		    G_CALLBACK (gtk_recent_chooser_item_activated_cb),
+  		    object);
+  
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (object)->vbox),
+                      priv->chooser, TRUE, TRUE, 0);
+  gtk_widget_show (priv->chooser);
+  
+  _gtk_recent_chooser_set_delegate (GTK_RECENT_CHOOSER (object),
+  				    GTK_RECENT_CHOOSER (priv->chooser));
+  
+  gtk_widget_pop_composite_child ();
+  
+  return object;
+}
+
+static void
+gtk_recent_chooser_dialog_set_property (GObject      *object,
+					guint         prop_id,
+					const GValue *value,
+					GParamSpec   *pspec)
+{
+  GtkRecentChooserDialogPrivate *priv;
+  
+  priv = GTK_RECENT_CHOOSER_DIALOG_GET_PRIVATE (object);
+  
+  switch (prop_id)
+    {
+    case GTK_RECENT_CHOOSER_PROP_RECENT_MANAGER:
+      if (priv->manager)
+        g_object_unref (priv->manager);
+      priv->manager = g_value_get_object (value);
+      if (priv->manager)
+        g_object_ref (priv->manager);
+      break;
+    default:
+      g_object_set_property (G_OBJECT (priv->chooser), pspec->name, value);
+      break;
+    }
+}
+
+static void
+gtk_recent_chooser_dialog_get_property (GObject      *object,
+					guint         prop_id,
+					GValue       *value,
+					GParamSpec   *pspec)
+{
+  GtkRecentChooserDialogPrivate *priv;
+  
+  priv = GTK_RECENT_CHOOSER_DIALOG_GET_PRIVATE (object);
+  
+  g_object_get_property (G_OBJECT (priv->chooser), pspec->name, value);
+}
+
+static void
+gtk_recent_chooser_dialog_finalize (GObject *object)
+{
+  GtkRecentChooserDialog *dialog = GTK_RECENT_CHOOSER_DIALOG (object);
+  
+  if (dialog->priv->manager)
+    g_object_unref (G_OBJECT (dialog->priv->manager));
+  
+  G_OBJECT_CLASS (gtk_recent_chooser_dialog_parent_class)->finalize (object);
+}
+
+static void
+gtk_recent_chooser_dialog_map (GtkWidget *widget)
+{
+  GtkRecentChooserDialog *dialog = GTK_RECENT_CHOOSER_DIALOG (widget);
+  GtkRecentChooserDialogPrivate *priv = dialog->priv;
+  
+  if (!GTK_WIDGET_MAPPED (priv->chooser))
+    gtk_widget_map (priv->chooser);
+
+  GTK_WIDGET_CLASS (gtk_recent_chooser_dialog_parent_class)->map (widget);
+}
+
+static void
+gtk_recent_chooser_dialog_unmap (GtkWidget *widget)
+{
+  GtkRecentChooserDialog *dialog = GTK_RECENT_CHOOSER_DIALOG (widget);
+  GtkRecentChooserDialogPrivate *priv = dialog->priv;
+  
+  GTK_WIDGET_CLASS (gtk_recent_chooser_dialog_parent_class)->unmap (widget);
+  
+  gtk_widget_unmap (priv->chooser);
+}
+
+/* taken from gtkfilechooserdialog.c */
+static void
+gtk_recent_chooser_dialog_style_set (GtkWidget *widget,
+				     GtkStyle  *old_style)
+{
+  GtkDialog *dialog;
+
+  dialog = GTK_DIALOG (widget);
+
+  /* Override the style properties with HIG-compliant spacings.  Ugh.
+   * http://developer.gnome.org/projects/gup/hig/1.0/layout.html#layout-dialogs
+   * http://developer.gnome.org/projects/gup/hig/1.0/windows.html#alert-spacing
+   */
+
+  gtk_container_set_border_width (GTK_CONTAINER (dialog->vbox), 12);
+  gtk_box_set_spacing (GTK_BOX (dialog->vbox), 24);
+
+  gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 0);
+  gtk_box_set_spacing (GTK_BOX (dialog->action_area), 6);
+  
+  if (GTK_WIDGET_CLASS (gtk_recent_chooser_dialog_parent_class)->style_set)
+    GTK_WIDGET_CLASS (gtk_recent_chooser_dialog_parent_class)->style_set (widget, old_style);
+}
+
+static GtkWidget *
+gtk_recent_chooser_dialog_new_valist (const gchar      *title,
+				      GtkWindow        *parent,
+				      GtkRecentManager *manager,
+				      const gchar      *first_button_text,
+				      va_list           varargs)
+{
+  GtkWidget *result;
+  const char *button_text = first_button_text;
+  gint response_id;
+  
+  result = g_object_new (GTK_TYPE_RECENT_CHOOSER_DIALOG,
+                         "title", title,
+                         "recent-manager", manager,
+                         NULL);
+  
+  if (parent)
+    gtk_window_set_transient_for (GTK_WINDOW (result), parent);
+  
+  while (button_text)
+    {
+      response_id = va_arg (varargs, gint);
+      gtk_dialog_add_button (GTK_DIALOG (result), button_text, response_id);
+      button_text = va_arg (varargs, const gchar *);
+    }
+  
+  return result;
+}
+
+/**
+ * gtk_recent_chooser_dialog_new:
+ * @title: Title of the dialog, or %NULL
+ * @parent: Transient parent of the dialog, or %NULL,
+ * @first_button_text: stock ID or text to go in the first button, or %NULL
+ * @Varargs: response ID for the first button, then additional (button, id)
+ *   pairs, ending with %NULL
+ *
+ * Creates a new #GtkRecentChooserDialog.  This function is analogous to
+ * gtk_dialog_new_with_buttons().
+ *
+ * Return value: a new #GtkRecentChooserDialog
+ *
+ * Since: 2.10
+ */
+GtkWidget *
+gtk_recent_chooser_dialog_new (const gchar *title,
+			       GtkWindow   *parent,
+			       const gchar *first_button_text,
+			       ...)
+{
+  GtkWidget *result;
+  va_list varargs;
+  
+  va_start (varargs, first_button_text);
+  result = gtk_recent_chooser_dialog_new_valist (title,
+  						 parent,
+  						 NULL,
+  						 first_button_text,
+  						 varargs);
+  va_end (varargs);
+  
+  return result;
+}
+
+/**
+ * gtk_recent_chooser_dialog_new_for_manager:
+ * @title: Title of the dialog, or %NULL
+ * @parent: Transient parent of the dialog, or %NULL,
+ * @manager: a #GtkRecentManager
+ * @first_button_text: stock ID or text to go in the first button, or %NULL
+ * @Varargs: response ID for the first button, then additional (button, id)
+ *   pairs, ending with %NULL
+ *
+ * Creates a new #GtkRecentChooserDialog with a specified recent manager.
+ *
+ * This is useful if you have implemented your own recent manager, or if you
+ * have a customized instance of a #GtkRecentManager object (e.g. with your
+ * own sorting and/or filtering functions).
+ *
+ * Return value: a new #GtkRecentChooserDialog
+ *
+ * Since: 2.10
+ */
+GtkWidget *
+gtk_recent_chooser_dialog_new_for_manager (const gchar      *title,
+			                   GtkWindow        *parent,
+			                   GtkRecentManager *manager,
+			                   const gchar      *first_button_text,
+			                   ...)
+{
+  GtkWidget *result;
+  va_list varargs;
+  
+  va_start (varargs, first_button_text);
+  result = gtk_recent_chooser_dialog_new_valist (title,
+  						 parent,
+  						 manager,
+  						 first_button_text,
+  						 varargs);
+  va_end (varargs);
+  
+  return result;
+}
+
+#define __GTK_RECENT_CHOOSER_DIALOG_C__
+#include "gtkaliasdef.c"
diff -Nuarp gtk+/gtk/gtkrecentchooserdialog.h gtk+.recent/gtk/gtkrecentchooserdialog.h
--- gtk+/gtk/gtkrecentchooserdialog.h	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/gtk/gtkrecentchooserdialog.h	2006-03-26 23:46:37.000000000 +0200
@@ -0,0 +1,70 @@
+/* GTK - The GIMP Toolkit
+ * gtkrecentchooserdialog.h: Recent files selector dialog
+ * Copyright (C) 2006 Emmanuele Bassi
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_RECENT_CHOOSER_DIALOG_H__
+#define __GTK_RECENT_CHOOSER_DIALOG_H__
+
+#include <gtk/gtkdialog.h>
+#include "gtkrecentchooser.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_RECENT_CHOOSER_DIALOG		  (gtk_recent_chooser_dialog_get_type ())
+#define GTK_RECENT_CHOOSER_DIALOG(obj)		  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_RECENT_CHOOSER_DIALOG, GtkRecentChooserDialog))
+#define GTK_IS_RECENT_CHOOSER_DIALOG(obj)	  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_RECENT_CHOOSER_DIALOG))
+#define GTK_RECENT_CHOOSER_DIALOG_CLASS(klass)	  (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_RECENT_CHOOSER_DIALOG, GtkRecentChooserDialogClass))
+#define GTK_IS_RECENT_CHOOSER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_RECENT_CHOOSER_DIALOG))
+#define GTK_RECENT_CHOOSER_DIALOG_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_RECENT_CHOOSER_DIALOG, GtkRecentChooserDialogClass))
+
+typedef struct _GtkRecentChooserDialog        GtkRecentChooserDialog;
+typedef struct _GtkRecentChooserDialogClass   GtkRecentChooserDialogClass;
+
+typedef struct _GtkRecentChooserDialogPrivate GtkRecentChooserDialogPrivate;
+
+
+struct _GtkRecentChooserDialog
+{
+  /*< private >*/
+  GtkDialog parent_instance;
+  
+  GtkRecentChooserDialogPrivate *priv;
+};
+
+struct _GtkRecentChooserDialogClass
+{
+  GtkDialogClass parent_class;
+};
+
+
+GType      gtk_recent_chooser_dialog_get_type        (void) G_GNUC_CONST;
+
+GtkWidget *gtk_recent_chooser_dialog_new             (const gchar      *title,
+					              GtkWindow        *parent,
+					              const gchar      *first_button_text,
+					              ...) G_GNUC_NULL_TERMINATED;
+GtkWidget *gtk_recent_chooser_dialog_new_for_manager (const gchar      *title,
+						      GtkWindow        *parent,
+						      GtkRecentManager *manager,
+						      const gchar      *first_button_text,
+						      ...) G_GNUC_NULL_TERMINATED;
+
+G_END_DECLS
+
+#endif /* __GTK_RECENT_CHOOSER_DIALOG_H__ */
diff -Nuarp gtk+/gtk/gtkrecentchooser.h gtk+.recent/gtk/gtkrecentchooser.h
--- gtk+/gtk/gtkrecentchooser.h	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/gtk/gtkrecentchooser.h	2006-03-26 23:46:37.000000000 +0200
@@ -0,0 +1,186 @@
+/* GTK - The GIMP Toolkit
+ * gtkrecentchooser.h - Abstract interface for recent file selectors GUIs
+ *
+ * Copyright (C) 2006, Emmanuele Bassi
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_RECENT_CHOOSER_H__
+#define __GTK_RECENT_CHOOSER_H__
+
+#include <gtk/gtkwidget.h>
+
+#include "gtkrecentmanager.h"
+#include "gtkrecentfilter.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_RECENT_CHOOSER			(gtk_recent_chooser_get_type ())
+#define GTK_RECENT_CHOOSER(obj)			(G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_RECENT_CHOOSER, GtkRecentChooser))
+#define GTK_IS_RECENT_CHOOSER(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_RECENT_CHOOSER))
+#define GTK_RECENT_CHOOSER_GET_IFACE(inst)	(G_TYPE_INSTANCE_GET_INTERFACE ((inst), GTK_TYPE_RECENT_CHOOSER, GtkRecentChooserIface))
+
+/**
+ * GtkRecentSortType:
+ * @GTK_RECENT_SORT_NONE: Do not sort the returned list of recently used
+ *   resources.
+ * @GTK_RECENT_SORT_MRU: Sort the returned list with the most recently used
+ *   items first.
+ * @GTK_RECENT_SORT_LRU: Sort the returned list with the least recently used
+ *   items first.
+ * @GTK_RECENT_SORT_CUSTOM: Sort the returned list using a custom sorting
+ *   function passed using gtk_recent_manager_set_sort_func().
+ *
+ * Used to specify the sorting method to be applyed to the recently
+ * used resource list.
+ **/
+typedef enum
+{
+  GTK_RECENT_SORT_NONE = 0,
+  GTK_RECENT_SORT_MRU,
+  GTK_RECENT_SORT_LRU,
+  GTK_RECENT_SORT_CUSTOM
+} GtkRecentSortType;
+
+typedef gint (*GtkRecentSortFunc) (GtkRecentInfo *a,
+				   GtkRecentInfo *b,
+				   gpointer       user_data);
+
+
+typedef struct _GtkRecentChooser      GtkRecentChooser; /* dummy */
+typedef struct _GtkRecentChooserIface GtkRecentChooserIface;
+
+#define GTK_RECENT_CHOOSER_ERROR	(gtk_recent_chooser_error_quark ())
+
+typedef enum
+{
+  GTK_RECENT_CHOOSER_ERROR_NOT_FOUND,
+  GTK_RECENT_CHOOSER_ERROR_INVALID_URI
+} GtkRecentChooserError;
+
+GQuark  gtk_recent_chooser_error_quark (void);
+
+
+struct _GtkRecentChooserIface
+{
+  GTypeInterface base_iface;
+  
+  /*
+   * Methods
+   */
+  gboolean          (* set_current_uri)    (GtkRecentChooser  *chooser,
+  					    const gchar       *uri,
+  					    GError           **error);
+  gchar *           (* get_current_uri)    (GtkRecentChooser  *chooser);
+  gboolean          (* select_uri)         (GtkRecentChooser  *chooser,
+  					    const gchar       *uri,
+  					    GError           **error);
+  void              (* unselect_uri)       (GtkRecentChooser  *chooser,
+                                            const gchar       *uri);
+  void              (* select_all)         (GtkRecentChooser  *chooser);
+  void              (* unselect_all)       (GtkRecentChooser  *chooser);
+  GList *           (* get_items)          (GtkRecentChooser  *chooser);
+  GtkRecentManager *(* get_recent_manager) (GtkRecentChooser  *chooser);
+  void              (* add_filter)         (GtkRecentChooser  *chooser,
+  					    GtkRecentFilter   *filter);
+  void              (* remove_filter)      (GtkRecentChooser  *chooser,
+  					    GtkRecentFilter   *filter);
+  GSList *          (* list_filters)       (GtkRecentChooser  *chooser);
+  void              (* set_sort_func)      (GtkRecentChooser  *chooser,
+  					    GtkRecentSortFunc  sort_func,
+  					    gpointer           data,
+  					    GDestroyNotify     destroy);
+  
+  /*
+   * Signals
+   */
+  void		    (* item_activated)     (GtkRecentChooser  *chooser);
+  void		    (* selection_changed)  (GtkRecentChooser  *chooser);
+};
+
+GType   gtk_recent_chooser_get_type    (void) G_GNUC_CONST;
+
+/*
+ * Configuration
+ */
+void              gtk_recent_chooser_set_show_private    (GtkRecentChooser  *chooser,
+							  gboolean           show_private);
+gboolean          gtk_recent_chooser_get_show_private    (GtkRecentChooser  *chooser);
+void              gtk_recent_chooser_set_show_not_found  (GtkRecentChooser  *chooser,
+							  gboolean           show_not_found);
+gboolean          gtk_recent_chooser_get_show_not_found  (GtkRecentChooser  *chooser);
+void              gtk_recent_chooser_set_select_multiple (GtkRecentChooser  *chooser,
+							  gboolean           select_multiple);
+gboolean          gtk_recent_chooser_get_select_multiple (GtkRecentChooser  *chooser);
+void              gtk_recent_chooser_set_limit           (GtkRecentChooser  *chooser,
+							  gint               limit);
+gint              gtk_recent_chooser_get_limit           (GtkRecentChooser  *chooser);
+void              gtk_recent_chooser_set_local_only      (GtkRecentChooser  *chooser,
+							  gboolean           local_only);
+gboolean          gtk_recent_chooser_get_local_only      (GtkRecentChooser  *chooser);
+void              gtk_recent_chooser_set_show_tips       (GtkRecentChooser  *chooser,
+							  gboolean           show_tips);
+gboolean          gtk_recent_chooser_get_show_tips       (GtkRecentChooser  *chooser);
+void              gtk_recent_chooser_set_show_numbers    (GtkRecentChooser  *chooser,
+							  gboolean           show_numbers);
+gboolean          gtk_recent_chooser_get_show_numbers    (GtkRecentChooser  *chooser);
+void              gtk_recent_chooser_set_show_icons      (GtkRecentChooser  *chooser,
+							  gboolean           show_icons);
+gboolean          gtk_recent_chooser_get_show_icons      (GtkRecentChooser  *chooser);
+void              gtk_recent_chooser_set_sort_type       (GtkRecentChooser  *chooser,
+							  GtkRecentSortType  sort_type);
+GtkRecentSortType gtk_recent_chooser_get_sort_type       (GtkRecentChooser  *chooser);
+void              gtk_recent_chooser_set_sort_func       (GtkRecentChooser  *chooser,
+							  GtkRecentSortFunc  sort_func,
+							  gpointer           sort_data,
+							  GDestroyNotify     data_destroy);
+
+/*
+ * Items handling
+ */
+gboolean       gtk_recent_chooser_set_current_uri  (GtkRecentChooser  *chooser,
+						    const gchar       *uri,
+						    GError           **error);
+gchar *        gtk_recent_chooser_get_current_uri  (GtkRecentChooser  *chooser);
+GtkRecentInfo *gtk_recent_chooser_get_current_item (GtkRecentChooser  *chooser);
+gboolean       gtk_recent_chooser_select_uri       (GtkRecentChooser  *chooser,
+						    const gchar       *uri,
+						    GError           **error);
+void           gtk_recent_chooser_unselect_uri     (GtkRecentChooser  *chooser,
+					            const gchar       *uri);
+void           gtk_recent_chooser_select_all       (GtkRecentChooser  *chooser);
+void           gtk_recent_chooser_unselect_all     (GtkRecentChooser  *chooser);
+GList *        gtk_recent_chooser_get_items        (GtkRecentChooser  *chooser);
+gchar **       gtk_recent_chooser_get_uris         (GtkRecentChooser  *chooser,
+						    gsize             *length);
+
+/*
+ * Filters
+ */
+void 		 gtk_recent_chooser_add_filter    (GtkRecentChooser *chooser,
+			 			   GtkRecentFilter  *filter);
+void 		 gtk_recent_chooser_remove_filter (GtkRecentChooser *chooser,
+						   GtkRecentFilter  *filter);
+GSList * 	 gtk_recent_chooser_list_filters  (GtkRecentChooser *chooser);
+void 		 gtk_recent_chooser_set_filter    (GtkRecentChooser *chooser,
+						   GtkRecentFilter  *filter);
+GtkRecentFilter *gtk_recent_chooser_get_filter    (GtkRecentChooser *chooser);
+
+
+G_END_DECLS
+
+#endif /* __GTK_RECENT_CHOOSER_H__ */
diff -Nuarp gtk+/gtk/gtkrecentchoosermenu.c gtk+.recent/gtk/gtkrecentchoosermenu.c
--- gtk+/gtk/gtkrecentchoosermenu.c	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/gtk/gtkrecentchoosermenu.c	2006-03-26 23:46:37.000000000 +0200
@@ -0,0 +1,1236 @@
+/* GTK - The GIMP Toolkit
+ * gtkrecentchoosermenu.c - Recently used items menu widget
+ * Copyright (C) 2005, Emmanuele Bassi
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gdk/gdkscreen.h>
+
+#include "gtkstock.h"
+#include "gtkicontheme.h"
+#include "gtkiconfactory.h"
+#include "gtkintl.h"
+#include "gtksettings.h"
+#include "gtkmenushell.h"
+#include "gtkmenuitem.h"
+#include "gtkimagemenuitem.h"
+#include "gtkseparatormenuitem.h"
+#include "gtkmenu.h"
+#include "gtkimage.h"
+#include "gtkobject.h"
+#include "gtktooltips.h"
+#include "gtktypebuiltins.h"
+#include "gtkalias.h"
+
+#include "gtkrecentmanager.h"
+#include "gtkrecentfilter.h"
+#include "gtkrecentchooser.h"
+#include "gtkrecentchooserutils.h"
+#include "gtkrecentchooserprivate.h"
+#include "gtkrecentchoosermenu.h"
+
+struct _GtkRecentChooserMenuPrivate
+{
+  /* the recent manager object */
+  GtkRecentManager *manager;
+  
+  /* size of the icons of the menu items */  
+  gint icon_size;
+
+  /* RecentChooser properties */
+  gint limit;  
+  guint show_private : 1;
+  guint show_not_found : 1;
+  guint show_tips : 1;
+  guint show_icons : 1;
+  guint local_only : 1;
+  
+  guint show_numbers : 1;
+  
+  GtkRecentSortType sort_type;
+  GtkRecentSortFunc sort_func;
+  gpointer sort_data;
+  GDestroyNotify sort_data_destroy;
+  
+  GSList *filters;
+  GtkRecentFilter *current_filter;
+  
+  gulong manager_changed_id;
+
+  /* tooltips for our bookmark items*/
+  GtkTooltips *tooltips;
+};
+
+enum {
+  PROP_0,
+
+  PROP_SHOW_NUMBERS
+};
+
+#define FALLBACK_ICON_SIZE 	32
+#define FALLBACK_ITEM_LIMIT 	10
+
+#define GTK_RECENT_CHOOSER_MENU_GET_PRIVATE(obj)	(G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_RECENT_CHOOSER_MENU, GtkRecentChooserMenuPrivate))
+
+static void     gtk_recent_chooser_menu_finalize    (GObject                   *object);
+static GObject *gtk_recent_chooser_menu_constructor (GType                      type,
+						     guint                      n_construct_properties,
+						     GObjectConstructParam     *construct_params);
+
+static void gtk_recent_chooser_iface_init      (GtkRecentChooserIface     *iface);
+
+static void gtk_recent_chooser_menu_set_property (GObject      *object,
+						  guint         prop_id,
+						  const GValue *value,
+						  GParamSpec   *pspec);
+static void gtk_recent_chooser_menu_get_property (GObject      *object,
+						  guint         prop_id,
+						  GValue       *value,
+						  GParamSpec   *pspec);
+
+static gboolean          gtk_recent_chooser_menu_set_current_uri    (GtkRecentChooser  *chooser,
+							             const gchar       *uri,
+							             GError           **error);
+static gchar *           gtk_recent_chooser_menu_get_current_uri    (GtkRecentChooser  *chooser);
+static gboolean          gtk_recent_chooser_menu_select_uri         (GtkRecentChooser  *chooser,
+								     const gchar       *uri,
+								     GError           **error);
+static void              gtk_recent_chooser_menu_unselect_uri       (GtkRecentChooser  *chooser,
+								     const gchar       *uri);
+static void              gtk_recent_chooser_menu_select_all         (GtkRecentChooser  *chooser);
+static void              gtk_recent_chooser_menu_unselect_all       (GtkRecentChooser  *chooser);
+static GList *           gtk_recent_chooser_menu_get_items          (GtkRecentChooser  *chooser);
+static GtkRecentManager *gtk_recent_chooser_menu_get_recent_manager (GtkRecentChooser  *chooser);
+static void              gtk_recent_chooser_menu_set_sort_func      (GtkRecentChooser  *chooser,
+								     GtkRecentSortFunc  sort_func,
+								     gpointer           sort_data,
+								     GDestroyNotify     data_destroy);
+static void              gtk_recent_chooser_menu_add_filter         (GtkRecentChooser  *chooser,
+								     GtkRecentFilter   *filter);
+static void              gtk_recent_chooser_menu_remove_filter      (GtkRecentChooser  *chooser,
+								     GtkRecentFilter   *filter);
+static GSList *          gtk_recent_chooser_menu_list_filters       (GtkRecentChooser  *chooser);
+static void              gtk_recent_chooser_menu_set_current_filter (GtkRecentChooserMenu *menu,
+								     GtkRecentFilter      *filter);
+
+static void              gtk_recent_chooser_menu_map (GtkWidget *widget);
+static void              gtk_recent_chooser_menu_set_show_tips      (GtkRecentChooserMenu *menu,
+								     gboolean              show_tips);
+
+static void     set_recent_manager (GtkRecentChooserMenu *menu,
+				    GtkRecentManager     *manager);
+
+static void     chooser_set_sort_type (GtkRecentChooserMenu *menu,
+				       GtkRecentSortType     sort_type);
+
+static gint     get_icon_size_for_widget (GtkWidget *widget);
+
+static void     item_activate_cb   (GtkWidget        *widget,
+			            gpointer          user_data);
+static void     manager_changed_cb (GtkRecentManager *manager,
+				    gpointer          user_data);
+
+G_DEFINE_TYPE_WITH_CODE (GtkRecentChooserMenu,
+			 gtk_recent_chooser_menu,
+			 GTK_TYPE_MENU,
+			 G_IMPLEMENT_INTERFACE (GTK_TYPE_RECENT_CHOOSER,
+				 		gtk_recent_chooser_iface_init));
+
+
+static void
+gtk_recent_chooser_iface_init (GtkRecentChooserIface *iface)
+{
+  iface->set_current_uri = gtk_recent_chooser_menu_set_current_uri;
+  iface->get_current_uri = gtk_recent_chooser_menu_get_current_uri;
+  iface->select_uri = gtk_recent_chooser_menu_select_uri;
+  iface->unselect_uri = gtk_recent_chooser_menu_unselect_uri;
+  iface->select_all = gtk_recent_chooser_menu_select_all;
+  iface->unselect_all = gtk_recent_chooser_menu_unselect_all;
+  iface->get_items = gtk_recent_chooser_menu_get_items;
+  iface->get_recent_manager = gtk_recent_chooser_menu_get_recent_manager;
+  iface->set_sort_func = gtk_recent_chooser_menu_set_sort_func;
+  iface->add_filter = gtk_recent_chooser_menu_add_filter;
+  iface->remove_filter = gtk_recent_chooser_menu_remove_filter;
+  iface->list_filters = gtk_recent_chooser_menu_list_filters;
+}
+
+static void
+gtk_recent_chooser_menu_class_init (GtkRecentChooserMenuClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  
+  gobject_class->constructor = gtk_recent_chooser_menu_constructor;
+  gobject_class->finalize = gtk_recent_chooser_menu_finalize;
+  gobject_class->set_property = gtk_recent_chooser_menu_set_property;
+  gobject_class->get_property = gtk_recent_chooser_menu_get_property;
+
+  widget_class->map = gtk_recent_chooser_menu_map;
+  
+  _gtk_recent_chooser_install_properties (gobject_class);
+
+  g_object_class_install_property (gobject_class,
+		  		   PROP_SHOW_NUMBERS,
+				   g_param_spec_boolean ("show-numbers",
+							 P_("Show Numbers"),
+							 P_("Whether the items should be displayed with a number"),
+							 FALSE,
+							 G_PARAM_READWRITE));
+  
+  g_type_class_add_private (klass, sizeof (GtkRecentChooserMenuPrivate));
+}
+
+static void
+gtk_recent_chooser_menu_init (GtkRecentChooserMenu *menu)
+{
+  GtkRecentChooserMenuPrivate *priv;
+  
+  priv = GTK_RECENT_CHOOSER_MENU_GET_PRIVATE (menu);
+  
+  menu->priv = priv;
+  
+  priv->show_numbers = FALSE;
+  priv->show_tips = FALSE;
+  priv->show_not_found = FALSE;
+  priv->show_private = FALSE;
+  priv->local_only = TRUE;
+  
+  priv->limit = FALLBACK_ITEM_LIMIT;
+
+  priv->sort_type = GTK_RECENT_SORT_NONE;
+  
+  priv->icon_size = FALLBACK_ICON_SIZE;
+  
+  priv->current_filter = NULL;
+    
+  priv->tooltips = gtk_tooltips_new ();
+  g_object_ref_sink (priv->tooltips);
+}
+
+static void
+gtk_recent_chooser_menu_finalize (GObject *object)
+{
+  GtkRecentChooserMenu *menu = GTK_RECENT_CHOOSER_MENU (object);
+  GtkRecentChooserMenuPrivate *priv = menu->priv;
+  
+  g_signal_handler_disconnect (priv->manager, priv->manager_changed_id);
+  priv->manager_changed_id = 0;
+  g_object_unref (priv->manager);
+  
+  if (priv->sort_data_destroy)
+    {
+      priv->sort_data_destroy (priv->sort_data);
+      
+      priv->sort_data_destroy = NULL;
+      priv->sort_data = NULL;
+      priv->sort_func = NULL;
+    }
+  
+  if (priv->tooltips)
+    g_object_unref (priv->tooltips);
+  
+  if (priv->current_filter)
+    g_object_unref (priv->current_filter);
+  
+  G_OBJECT_CLASS (gtk_recent_chooser_menu_parent_class)->finalize;
+}
+
+static GObject *
+gtk_recent_chooser_menu_constructor (GType                  type,
+				     guint                  n_construct_properties,
+				     GObjectConstructParam *construct_params)
+{
+  GtkRecentChooserMenu *menu;
+  GObject *object;
+  
+  object = G_OBJECT_CLASS (gtk_recent_chooser_menu_parent_class)->constructor (type,
+		  							       n_construct_properties,
+									       construct_params);
+  menu = GTK_RECENT_CHOOSER_MENU (object);
+  
+  g_assert (menu->priv->manager);
+  
+  return object;
+}
+
+static void
+gtk_recent_chooser_menu_set_property (GObject      *object,
+				      guint         prop_id,
+				      const GValue *value,
+				      GParamSpec   *pspec)
+{
+  GtkRecentChooserMenu *menu = GTK_RECENT_CHOOSER_MENU (object);
+  
+  switch (prop_id)
+    {
+    case PROP_SHOW_NUMBERS:
+      menu->priv->show_numbers = g_value_get_boolean (value);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_RECENT_MANAGER:
+      set_recent_manager (menu, g_value_get_object (value));
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_PRIVATE:
+      menu->priv->show_private = g_value_get_boolean (value);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_NOT_FOUND:
+      menu->priv->show_not_found = g_value_get_boolean (value);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_TIPS:
+      gtk_recent_chooser_menu_set_show_tips (menu, g_value_get_boolean (value));
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_ICONS:
+      menu->priv->show_icons = g_value_get_boolean (value);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SELECT_MULTIPLE:
+      g_warning ("%s: RecentChoosers of type `%s' do not support "
+                 "selecting multiple items.",
+                 G_STRFUNC,
+                 G_OBJECT_TYPE_NAME (object));
+      break;
+    case GTK_RECENT_CHOOSER_PROP_LOCAL_ONLY:
+      menu->priv->local_only = g_value_get_boolean (value);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_LIMIT:
+      menu->priv->limit = g_value_get_int (value);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SORT_TYPE:
+      chooser_set_sort_type (menu, g_value_get_enum (value));
+      break;
+    case GTK_RECENT_CHOOSER_PROP_FILTER:
+      gtk_recent_chooser_menu_set_current_filter (menu, g_value_get_object (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_recent_chooser_menu_get_property (GObject    *object,
+				      guint       prop_id,
+				      GValue     *value,
+				      GParamSpec *pspec)
+{
+  GtkRecentChooserMenu *menu = GTK_RECENT_CHOOSER_MENU (object);
+  
+  switch (prop_id)
+    {
+    case PROP_SHOW_NUMBERS:
+      g_value_set_boolean (value, menu->priv->show_numbers);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_TIPS:
+      g_value_set_boolean (value, menu->priv->show_tips);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_LIMIT:
+      g_value_set_int (value, menu->priv->limit);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_LOCAL_ONLY:
+      g_value_set_boolean (value, menu->priv->local_only);
+    case GTK_RECENT_CHOOSER_PROP_SORT_TYPE:
+      g_value_set_enum (value, menu->priv->sort_type);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_PRIVATE:
+      g_value_set_boolean (value, menu->priv->show_private);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_NOT_FOUND:
+      g_value_set_boolean (value, menu->priv->show_not_found);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_ICONS:
+      g_value_set_boolean (value, menu->priv->show_icons);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SELECT_MULTIPLE:
+      g_warning ("%s: Recent Choosers of type `%s' do not support "
+                 "selecting multiple items.",
+                 G_STRFUNC,
+                 G_OBJECT_TYPE_NAME (object));
+      break;
+    case GTK_RECENT_CHOOSER_PROP_FILTER:
+      g_value_set_object (value, menu->priv->current_filter);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static gboolean
+gtk_recent_chooser_menu_set_current_uri (GtkRecentChooser  *chooser,
+					 const gchar       *uri,
+					 GError           **error)
+{
+  GtkRecentChooserMenu *menu = GTK_RECENT_CHOOSER_MENU (chooser);
+  GList *children, *l;
+  GtkWidget *menu_item = NULL;
+  gboolean found = FALSE;
+  
+  children = gtk_container_get_children (GTK_CONTAINER (menu));
+  for (l = children; l != NULL; l = l->next)
+    {
+      GtkRecentInfo *info;
+      
+      menu_item = GTK_WIDGET (l->data);
+      
+      info = g_object_get_data (G_OBJECT (menu_item), "gtk-recent-info");
+      if (!info)
+        continue;
+      
+      if (0 == strcmp (uri, gtk_recent_info_get_uri (info)))
+        found = TRUE;
+    }
+
+  g_list_free (children);
+  
+  if (!found)  
+    {
+      g_set_error (error, GTK_RECENT_CHOOSER_ERROR,
+      		   GTK_RECENT_CHOOSER_ERROR_NOT_FOUND,
+      		   _("No recently used resource found with URI `%s'"),
+      		   uri);
+      return FALSE;
+    }
+  else
+    {
+      gtk_menu_shell_activate_item (GTK_MENU_SHELL (menu), menu_item, TRUE);
+      
+      return TRUE;
+    }
+}
+
+static gchar *
+gtk_recent_chooser_menu_get_current_uri (GtkRecentChooser  *chooser)
+{
+  GtkRecentChooserMenu *menu = GTK_RECENT_CHOOSER_MENU (chooser);
+  GtkWidget *menu_item;
+  GtkRecentInfo *info;
+  
+  menu_item = gtk_menu_get_active (GTK_MENU (menu));
+  if (!menu_item)
+    return NULL;
+  
+  info = g_object_get_data (G_OBJECT (menu_item), "gtk-recent-info");
+  if (!info)
+    return NULL;
+  
+  return g_strdup (gtk_recent_info_get_uri (info));
+}
+
+static gboolean
+gtk_recent_chooser_menu_select_uri (GtkRecentChooser  *chooser,
+				    const gchar       *uri,
+				    GError           **error)
+{
+  GtkRecentChooserMenu *menu = GTK_RECENT_CHOOSER_MENU (chooser);
+  GList *children, *l;
+  GtkWidget *menu_item = NULL;
+  gboolean found = FALSE;
+  
+  children = gtk_container_get_children (GTK_CONTAINER (menu));
+  for (l = children; l != NULL; l = l->next)
+    {
+      GtkRecentInfo *info;
+      
+      menu_item = GTK_WIDGET (l->data);
+      
+      info = g_object_get_data (G_OBJECT (menu_item), "gtk-recent-info");
+      if (!info)
+        continue;
+      
+      if (0 == strcmp (uri, gtk_recent_info_get_uri (info)))
+        found = TRUE;
+    }
+
+  g_list_free (children);
+  
+  if (!found)  
+    {
+      g_set_error (error, GTK_RECENT_CHOOSER_ERROR,
+      		   GTK_RECENT_CHOOSER_ERROR_NOT_FOUND,
+      		   _("No recently used resource found with URI `%s'"),
+      		   uri);
+      return FALSE;
+    }
+  else
+    {
+      gtk_menu_shell_select_item (GTK_MENU_SHELL (menu), menu_item);
+
+      return TRUE;
+    }
+}
+
+static void
+gtk_recent_chooser_menu_unselect_uri (GtkRecentChooser *chooser,
+				       const gchar     *uri)
+{
+  GtkRecentChooserMenu *menu = GTK_RECENT_CHOOSER_MENU (chooser);
+  
+  gtk_menu_shell_deselect (GTK_MENU_SHELL (menu));
+}
+
+static void
+gtk_recent_chooser_menu_select_all (GtkRecentChooser *chooser)
+{
+  g_warning (_("This function is not implemented for "
+               "widgets of class '%s'"),
+             g_type_name (G_OBJECT_TYPE (chooser)));
+}
+
+static void
+gtk_recent_chooser_menu_unselect_all (GtkRecentChooser *chooser)
+{
+  g_warning (_("This function is not implemented for "
+               "widgets of class '%s'."),
+             g_type_name (G_OBJECT_TYPE (chooser)));
+}
+
+static void
+gtk_recent_chooser_menu_set_sort_func (GtkRecentChooser  *chooser,
+				       GtkRecentSortFunc  sort_func,
+				       gpointer           sort_data,
+				       GDestroyNotify     data_destroy)
+{
+  GtkRecentChooserMenu *menu = GTK_RECENT_CHOOSER_MENU (chooser);
+  GtkRecentChooserMenuPrivate *priv = menu->priv;
+  
+  if (priv->sort_data_destroy)
+    {
+      priv->sort_data_destroy (priv->sort_data);
+      
+      priv->sort_func = NULL;
+      priv->sort_data = NULL;
+      priv->sort_data_destroy = NULL;
+    }
+  
+  if (sort_func)
+    {
+      priv->sort_func = sort_func;
+      priv->sort_data = sort_data;
+      priv->sort_data_destroy = data_destroy;
+    }
+}
+
+static gint
+sort_recent_items_mru (GtkRecentInfo *a,
+		       GtkRecentInfo *b,
+		       gpointer       unused)
+{
+  g_assert (a != NULL && b != NULL);
+  
+  return (gtk_recent_info_get_modified (a) < gtk_recent_info_get_modified (b));
+}
+
+static gint
+sort_recent_items_lru (GtkRecentInfo *a,
+		       GtkRecentInfo *b,
+		       gpointer       unused)
+{
+  g_assert (a != NULL && b != NULL);
+  
+  return (gtk_recent_info_get_modified (a) > gtk_recent_info_get_modified (b));
+}
+
+/* our proxy sorting function */
+static gint
+sort_recent_items_proxy (gpointer *a,
+			 gpointer *b,
+			 gpointer  user_data)
+{
+  GtkRecentInfo *info_a = (GtkRecentInfo *) a;
+  GtkRecentInfo *info_b = (GtkRecentInfo *) b;
+  GtkRecentChooserMenu *menu = GTK_RECENT_CHOOSER_MENU (user_data);
+
+  if (menu->priv->sort_func)
+    return (* menu->priv->sort_func) (info_a,
+    				      info_b,
+    				      menu->priv->sort_data);
+  
+  /* fallback */
+  return 0;
+}
+
+static void
+chooser_set_sort_type (GtkRecentChooserMenu *menu,
+		       GtkRecentSortType     sort_type)
+{
+  if (menu->priv->sort_type == sort_type)
+    return;
+
+  menu->priv->sort_type = sort_type;
+}
+
+
+static GList *
+gtk_recent_chooser_menu_get_items (GtkRecentChooser *chooser)
+{
+  GtkRecentChooserMenu *menu = GTK_RECENT_CHOOSER_MENU (chooser);
+  GtkRecentChooserMenuPrivate *priv;
+  gint limit;
+  GtkRecentSortType sort_type;
+  GList *items;
+  GCompareDataFunc compare_func;
+  gint length;
+  
+  priv = menu->priv;
+  
+  if (!priv->manager)
+    return NULL;
+  
+  limit = gtk_recent_chooser_get_limit (chooser);
+  sort_type = gtk_recent_chooser_get_sort_type (chooser);
+
+  switch (sort_type)
+    {
+    case GTK_RECENT_SORT_NONE:
+      compare_func = NULL;
+      break;
+    case GTK_RECENT_SORT_MRU:
+      compare_func = (GCompareDataFunc) sort_recent_items_mru;
+      break;
+    case GTK_RECENT_SORT_LRU:
+      compare_func = (GCompareDataFunc) sort_recent_items_lru;
+      break;
+    case GTK_RECENT_SORT_CUSTOM:
+      compare_func = (GCompareDataFunc) sort_recent_items_proxy;
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+  
+  items = gtk_recent_manager_get_items (priv->manager);
+  if (!items)
+    return NULL;
+  
+  if (compare_func)  
+    items = g_list_sort_with_data (items, compare_func, menu);
+  
+  length = g_list_length (items);
+  if ((limit != -1) && (length > limit))
+    {
+      GList *clamp, *l;
+      
+      clamp = g_list_nth (items, limit - 1);
+
+      l = clamp->next;
+      clamp->next = NULL;      
+      
+      g_list_foreach (l, (GFunc) gtk_recent_info_unref, NULL);
+      g_list_free (l);
+    }
+  
+  return items;
+}
+
+static GtkRecentManager *
+gtk_recent_chooser_menu_get_recent_manager (GtkRecentChooser *chooser)
+{
+  GtkRecentChooserMenuPrivate *priv;
+ 
+  priv = GTK_RECENT_CHOOSER_MENU (chooser)->priv;
+  
+  return priv->manager;
+}
+
+static void
+gtk_recent_chooser_menu_add_filter (GtkRecentChooser *chooser,
+				    GtkRecentFilter  *filter)
+{
+  g_warning (_("This function is not implemented for "
+               "widgets of class '%s'"),
+             g_type_name (G_OBJECT_TYPE (chooser)));
+}
+
+static void
+gtk_recent_chooser_menu_remove_filter (GtkRecentChooser *chooser,
+				       GtkRecentFilter  *filter)
+{
+  g_warning (_("This function is not implemented for "
+               "widgets of class '%s'"),
+             g_type_name (G_OBJECT_TYPE (chooser)));
+}
+
+static GSList *
+gtk_recent_chooser_menu_list_filters (GtkRecentChooser  *chooser)
+{
+  g_warning (_("This function is not implemented for "
+               "widgets of class '%s'"),
+             g_type_name (G_OBJECT_TYPE (chooser)));
+
+  return NULL;
+}
+
+static void
+gtk_recent_chooser_menu_set_current_filter (GtkRecentChooserMenu *menu,
+					    GtkRecentFilter      *filter)
+{
+  GtkRecentChooserMenuPrivate *priv;
+
+  priv = menu->priv;
+  
+  if (priv->current_filter)
+    g_object_unref (G_OBJECT (priv->current_filter));
+  
+  priv->current_filter = filter;
+  g_object_ref_sink (priv->current_filter);
+  
+  g_object_notify (G_OBJECT (menu), "filter");
+}
+
+static gboolean
+get_is_recent_filtered (GtkRecentChooserMenu *menu,
+			GtkRecentInfo        *info)
+{
+  GtkRecentChooserMenuPrivate *priv;
+  GtkRecentFilter *current_filter;
+  GtkRecentFilterInfo filter_info;
+  GtkRecentFilterFlags needed;
+  gboolean retval;
+
+  g_assert (info != NULL);
+
+  priv = menu->priv;
+  
+  if (!priv->current_filter)
+    return FALSE;
+  
+  current_filter = priv->current_filter;
+  needed = gtk_recent_filter_get_needed (current_filter);
+  
+  filter_info.contains = GTK_RECENT_FILTER_URI | GTK_RECENT_FILTER_MIME_TYPE;
+  
+  filter_info.uri = gtk_recent_info_get_uri (info);
+  filter_info.mime_type = gtk_recent_info_get_mime_type (info);
+  
+  if (needed & GTK_RECENT_FILTER_DISPLAY_NAME)
+    {
+      filter_info.display_name = gtk_recent_info_get_display_name (info);
+      filter_info.contains |= GTK_RECENT_FILTER_DISPLAY_NAME;
+    }
+  else
+    filter_info.uri = NULL;
+  
+  if (needed & GTK_RECENT_FILTER_APPLICATION)
+    {
+      filter_info.applications = (const gchar **) gtk_recent_info_get_applications (info, NULL);
+      filter_info.contains |= GTK_RECENT_FILTER_APPLICATION;
+    }
+  else
+    filter_info.applications = NULL;
+
+  if (needed & GTK_RECENT_FILTER_GROUP)
+    {
+      filter_info.groups = (const gchar **) gtk_recent_info_get_groups (info, NULL);
+      filter_info.contains |= GTK_RECENT_FILTER_GROUP;
+    }
+  else
+    filter_info.groups = NULL;
+  
+  if (needed & GTK_RECENT_FILTER_AGE)
+    {
+      filter_info.age = gtk_recent_info_get_age (info);
+      filter_info.contains |= GTK_RECENT_FILTER_AGE;
+    }
+  else
+    filter_info.age = -1;
+  
+  retval = gtk_recent_filter_filter (current_filter, &filter_info);
+  
+  /* this we own */
+  if (filter_info.applications)
+    g_strfreev ((gchar **) filter_info.applications);
+  
+  return !retval;
+}
+
+/* taken from libeel/eel-strings.c */
+static gchar *
+escape_underscores (const gchar *string)
+{
+  gint underscores;
+  const gchar *p;
+  gchar *q;
+  gchar *escaped;
+
+  if (!string)
+    return NULL;
+	
+  underscores = 0;
+  for (p = string; *p != '\0'; p++)
+    underscores += (*p == '_');
+
+  if (underscores == 0)
+    return g_strdup (string);
+
+  escaped = g_new (char, strlen (string) + underscores + 1);
+  for (p = string, q = escaped; *p != '\0'; p++, q++)
+    {
+      /* Add an extra underscore. */
+      if (*p == '_')
+        *q++ = '_';
+      
+      *q = *p;
+    }
+  
+  *q = '\0';
+	
+  return escaped;
+}
+
+static void
+gtk_recent_chooser_menu_add_tip (GtkRecentChooserMenu *menu,
+				 GtkRecentInfo        *info,
+				 GtkWidget            *item)
+{
+  GtkRecentChooserMenuPrivate *priv;
+  gchar *path, *tip_text;
+
+  g_assert (info != NULL);
+  g_assert (item != NULL);
+
+  priv = menu->priv;
+  
+  if (!priv->tooltips)
+    return;
+  
+  path = gtk_recent_info_get_uri_display (info);
+  
+  tip_text = g_strdup_printf (_("Open '%s'"), path);
+ 
+  gtk_tooltips_set_tip (priv->tooltips,
+  			item,
+  			tip_text,
+  			NULL);
+
+  g_free (path);  
+  g_free (tip_text);
+}
+
+static GtkWidget *
+gtk_recent_chooser_menu_create_item (GtkRecentChooserMenu *menu,
+				     GtkRecentInfo        *info,
+				     gint                  count)
+{
+  GtkRecentChooserMenuPrivate *priv;
+  gchar *label;
+  GtkWidget *item, *image;
+  GdkPixbuf *icon;
+
+  g_assert (info != NULL);
+
+  priv = menu->priv;
+
+  if (priv->show_numbers)
+    {
+      gchar *name, *escaped;
+      
+      name = g_strdup (gtk_recent_info_get_display_name (info));
+      if (!name)
+        name = g_strdup (_("Unknown item"));
+      
+      escaped = escape_underscores (name);
+      
+      /* avoid clashing mnemonics */
+      if (count <= 10)
+        label = g_strdup_printf ("_%d. %s", count, escaped);
+      else
+        label = g_strdup_printf ("%d. %s", count, escaped);
+      
+      item = gtk_image_menu_item_new_with_mnemonic (label);
+      
+      g_free (escaped);
+      g_free (name);
+    }
+  else
+    {
+      label = g_strdup (gtk_recent_info_get_display_name (info));
+      item = gtk_image_menu_item_new_with_label (label);
+    }
+  
+  if (priv->show_icons)
+    {
+      icon = gtk_recent_info_get_icon (info, priv->icon_size);
+        
+      image = gtk_image_new_from_pixbuf (icon);
+      gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+    }
+  
+  if (!gtk_recent_info_exists (info))
+    {
+      gtk_widget_set_sensitive (item, FALSE);
+      
+      goto out;
+    }
+  
+  g_signal_connect (item, "activate",
+  		    G_CALLBACK (item_activate_cb),
+  		    menu);
+
+out:
+  g_free (label);
+
+  return item;
+}
+
+/* removes the items we own from the menu */
+static void
+gtk_recent_chooser_menu_dispose_items (GtkRecentChooserMenu *menu)
+{
+  GList *children, *l;
+ 
+  children = gtk_container_get_children (GTK_CONTAINER (menu));
+  for (l = children; l != NULL; l = l->next)
+    {
+      GtkWidget *menu_item = GTK_WIDGET (l->data);
+      gint mark = 0;
+      
+      /* check for our mark, in order to remove just the items we own */
+      mark = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu_item),
+                                                 "gtk-recent-menu-mark"));
+      if (mark == 1)
+        {
+          GtkRecentInfo *info;
+          
+          /* destroy the attached RecentInfo struct, if found */
+          info = g_object_get_data (G_OBJECT (menu_item), "gtk-recent-info");
+          if (info)
+            g_object_set_data_full (G_OBJECT (menu_item), "gtk-recent-info",
+            			    NULL, NULL);
+          
+          /* and finally remove the item from the menu */
+          gtk_container_remove (GTK_CONTAINER (menu), menu_item);
+        }
+    }
+
+  g_list_free (children);
+}
+
+/* GtkWidget::map method override
+ *
+ * We override this method in order to populate the menu with our
+ * menu items linked to the recently used resources.
+ */
+static void
+gtk_recent_chooser_menu_map (GtkWidget *widget)
+{
+  GtkRecentChooserMenu *menu = GTK_RECENT_CHOOSER_MENU (widget);
+  GtkRecentChooserMenuPrivate *priv = menu->priv;
+  GList *items, *l;
+  gint count;
+  gboolean has_items = FALSE;
+  
+  if (GTK_WIDGET_CLASS (gtk_recent_chooser_menu_parent_class)->map)
+    GTK_WIDGET_CLASS (gtk_recent_chooser_menu_parent_class)->map (widget);
+  
+  priv->icon_size = get_icon_size_for_widget (widget);
+  
+  /* dispose our menu items first */
+  gtk_recent_chooser_menu_dispose_items (menu);
+ 
+  items = gtk_recent_chooser_get_items (GTK_RECENT_CHOOSER (menu));
+  
+  count = g_list_length (items);
+  items = g_list_reverse (items);
+
+  for (l = items; l != NULL; l = l->next)
+    {
+      GtkRecentInfo *info = (GtkRecentInfo *) l->data;
+      GtkWidget *item;
+
+      g_assert (info != NULL);
+      
+      /* skip non-local items on request */
+      if (priv->local_only && !gtk_recent_info_is_local (info))
+        continue;
+      
+      /* skip private items on request */
+      if (!priv->show_private && gtk_recent_info_get_private_hint (info))
+        continue;
+      
+      /* skip non-existing items on request */
+      if (!priv->show_not_found && !gtk_recent_info_exists (info))
+        continue;
+
+      /* filter items based on the currently set filter object */
+      if (get_is_recent_filtered (menu, info))
+        continue;
+ 
+      item = gtk_recent_chooser_menu_create_item (menu, info, count);
+      if (!item)
+        continue;
+      
+      gtk_recent_chooser_menu_add_tip (menu, info, item);
+      
+      /* FIXME
+       *
+       * We should really place our items taking into account user
+       * defined menu items; this would also remove the need of
+       * reverting the scan order.
+       */
+      gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
+      gtk_widget_show (item);
+      
+      /* mark the menu item as one of our own */
+      g_object_set_data (G_OBJECT (item), "gtk-recent-menu-mark",
+      			 GINT_TO_POINTER (1));
+      
+      /* attach the RecentInfo object to the menu item, and own a reference
+       * to it, so that it will be destroyed with the menu item when it's
+       * not needed anymore.
+       */
+      g_object_set_data_full (G_OBJECT (item), "gtk-recent-info",
+      			      gtk_recent_info_ref (info),
+      			      (GDestroyNotify) gtk_recent_info_unref);
+      
+      /* we have at least one item */
+      if (!has_items)
+        has_items = TRUE;
+    }
+  
+  /* now, the RecentInfo objects are bound to the lifetime of the menu */
+  if (items)
+    {
+      g_list_foreach (items,
+  		      (GFunc) gtk_recent_info_unref,
+  		      NULL);
+      g_list_free (items);
+    }
+
+  /* no recently used resources were found, or they were filtered out, so
+   * we build an item stating that no recently used resources were found
+   * (as night follows the day...).
+   */
+  if (!has_items)
+    {
+      GtkWidget *item;
+      
+      item = gtk_menu_item_new_with_label ("No items found");
+      gtk_widget_set_sensitive (item, FALSE);
+      
+      /* we also mark this item, so that it gets removed when rebuilding
+       * the menu on the next map event
+       */
+      g_object_set_data (G_OBJECT (item), "gtk-recent-menu-mark",
+      			 GINT_TO_POINTER (1));
+      
+      gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
+      gtk_widget_show (item);
+    }
+}
+
+/* bounce activate signal from the recent menu item widget 
+ * to the recent menu widget
+ */
+static void
+item_activate_cb (GtkWidget *widget,
+		  gpointer   user_data)
+{
+  GtkRecentChooser *chooser = GTK_RECENT_CHOOSER (user_data);
+  
+  _gtk_recent_chooser_item_activated (chooser);
+}
+
+/* we force a redraw if the manager changes when we are showing */
+static void
+manager_changed_cb (GtkRecentManager *manager,
+		    gpointer          user_data)
+{
+  gtk_widget_queue_draw (GTK_WIDGET (user_data));
+}
+
+static void
+set_recent_manager (GtkRecentChooserMenu *menu,
+		    GtkRecentManager     *manager)
+{
+  if (menu->priv->manager)
+    g_signal_handler_disconnect (menu, menu->priv->manager_changed_id);
+  
+  menu->priv->manager = NULL;
+  
+  if (manager)
+    {
+      menu->priv->manager = manager;
+      
+      g_object_ref (menu->priv->manager);
+    }
+  else
+    {
+      GdkScreen *screen = gdk_screen_get_default ();
+      GtkRecentManager *default_manager = NULL;
+      
+      default_manager = g_object_get_data (G_OBJECT (screen), GTK_DEFAULT_RECENT_MANAGER);
+      if (default_manager)
+        menu->priv->manager = g_object_ref (default_manager);
+    }
+  
+  /* create a new recent manager object */
+  if (!menu->priv->manager)
+    {
+      GdkScreen *screen = gdk_screen_get_default ();
+      
+      menu->priv->manager = gtk_recent_manager_new ();
+      g_object_set_data_full (G_OBJECT (screen), GTK_DEFAULT_RECENT_MANAGER,
+		              menu->priv->manager,
+			      (GDestroyNotify) g_object_unref);
+    }
+  
+  if (menu->priv->manager)
+    menu->priv->manager_changed_id = g_signal_connect (menu->priv->manager, "changed",
+      						       G_CALLBACK (manager_changed_cb),
+      						       menu);
+}
+
+static gint
+get_icon_size_for_widget (GtkWidget *widget)
+{
+  GtkSettings *settings;
+  gint width, height;
+
+  if (gtk_widget_has_screen (widget))
+    settings = gtk_settings_get_for_screen (gtk_widget_get_screen (widget));
+  else
+    settings = gtk_settings_get_default ();
+
+  if (gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
+                                         &width, &height))
+    return MAX (width, height);
+
+  return FALLBACK_ICON_SIZE;
+}
+
+static void
+gtk_recent_chooser_menu_set_show_tips (GtkRecentChooserMenu *menu,
+				       gboolean              show_tips)
+{
+  if (menu->priv->show_tips == show_tips)
+    return;
+  
+  g_assert (menu->priv->tooltips != NULL);
+  
+  if (show_tips)
+    gtk_tooltips_enable (menu->priv->tooltips);
+  else
+    gtk_tooltips_disable (menu->priv->tooltips);
+  
+  menu->priv->show_tips = show_tips;
+}
+
+/*
+ * Public API
+ */
+
+/**
+ * gtk_recent_chooser_menu_new:
+ *
+ * Creates a new #GtkRecentChooserMenu widget.
+ *
+ * This kind of widget shows the list of recently used resources as
+ * a menu, each item as a menu item.  Each item inside the menu might
+ * have an icon, representing its MIME type, and a number, for mnemonic
+ * access.
+ *
+ * This widget implements the #GtkRecentChooser interface.
+ *
+ * This widget creates its own #GtkRecentManager object.  See the
+ * gtk_recent_chooser_menu_new_for_manager() function to know how to create
+ * a #GtkRecentChooserMenu widget bound to another #GtkRecentManager object.
+ *
+ * Return value: a new #GtkRecentChooserMenu
+ *
+ * Since: 2.10
+ */
+GtkWidget *
+gtk_recent_chooser_menu_new (void)
+{
+  return g_object_new (GTK_TYPE_RECENT_CHOOSER_MENU,
+  		       "recent-manager", NULL,
+  		       NULL);
+}
+
+/**
+ * gtk_recent_chooser_menu_new_for_manager:
+ * @manager: a #GtkRecentManager
+ *
+ * Creates a new #GtkRecentChooserMenu widget using @manager as the underlying
+ * recently used resources manager.
+ *
+ * This is useful if you have implemented your own recent manager, or if you
+ * have a customized instance of a #GtkRecentManager object (e.g. with your
+ * own sorting and/or filtering functions), or if you wish to share a common
+ * RecentManager object among multiple RecentChooser widgets.
+ *
+ * Return value: a new #GtkRecentChooserMenu, bound to @manager.
+ *
+ * Since: 2.10
+ */
+GtkWidget *
+gtk_recent_chooser_menu_new_for_manager (GtkRecentManager *manager)
+{
+  g_return_val_if_fail (GTK_IS_RECENT_MANAGER (manager), NULL);
+  
+  return g_object_new (GTK_TYPE_RECENT_CHOOSER_MENU,
+  		       "recent-manager", manager,
+  		       NULL);
+}
+
+/**
+ * gtk_recent_chooser_menu_get_show_numbers:
+ * @menu: a #GtkRecentChooserMenu
+ *
+ * Returns the value set by gtk_recent_chooser_menu_set_show_numbers().
+ * 
+ * Return value: %TRUE if numbers should be shown.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_recent_chooser_menu_get_show_numbers (GtkRecentChooserMenu *menu)
+{
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER_MENU (menu), FALSE);
+
+  return menu->priv->show_numbers;
+}
+
+/**
+ * gtk_recent_chooser_menu_set_show_numbers:
+ * @menu: a #GtkRecentChooserMenu
+ * @show_numbers: whether to show numbers
+ *
+ * Sets whether a number should be added to the items of @menu.  The
+ * numbers are shown to provide a unique character for a mnemonic to
+ * be used inside the menu item's label.  Only the first the items
+ * get a number to avoid clashes.
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_chooser_menu_set_show_numbers (GtkRecentChooserMenu *menu,
+					  gboolean              show_numbers)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER_MENU (menu));
+
+  if (menu->priv->show_numbers == show_numbers)
+    return;
+
+  menu->priv->show_numbers = show_numbers;
+  g_object_notify (G_OBJECT (menu), "show-numbers");
+}
+
+#define __GTK_RECENT_CHOOSER_MENU_C__
+#include "gtkaliasdef.c"
diff -Nuarp gtk+/gtk/gtkrecentchoosermenu.h gtk+.recent/gtk/gtkrecentchoosermenu.h
--- gtk+/gtk/gtkrecentchoosermenu.h	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/gtk/gtkrecentchoosermenu.h	2006-03-26 23:46:37.000000000 +0200
@@ -0,0 +1,70 @@
+/* GTK - The GIMP Toolkit
+ * gtkrecentchoosermenu.h - Recently used items menu widget
+ * Copyright (C) 2006, Emmanuele Bassi
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_RECENT_CHOOSER_MENU_H__
+#define __GTK_RECENT_CHOOSER_MENU_H__
+
+#include <gtk/gtkmenu.h>
+#include "gtkrecentchooser.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_RECENT_CHOOSER_MENU		(gtk_recent_chooser_menu_get_type ())
+#define GTK_RECENT_CHOOSER_MENU(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_RECENT_CHOOSER_MENU, GtkRecentChooserMenu))
+#define GTK_IS_RECENT_CHOOSER_MENU(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_RECENT_CHOOSER_MENU))
+#define GTK_RECENT_CHOOSER_MENU_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_RECENT_CHOOSER_MENU, GtkRecentChooserMenuClass))
+#define GTK_IS_RECENT_CHOOSER_MENU_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_RECENT_CHOOSER_MENU))
+#define GTK_RECENT_CHOOSER_MENU_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_RECENT_CHOOSER_MENU, GtkRecentChooserMenuClass))
+
+typedef struct _GtkRecentChooserMenu		GtkRecentChooserMenu;
+typedef struct _GtkRecentChooserMenuClass	GtkRecentChooserMenuClass;
+typedef struct _GtkRecentChooserMenuPrivate	GtkRecentChooserMenuPrivate;
+
+struct _GtkRecentChooserMenu
+{
+  /*< private >*/
+  GtkMenu parent_instance;
+
+  GtkRecentChooserMenuPrivate *priv;
+};
+
+struct _GtkRecentChooserMenuClass
+{
+  GtkMenuClass parent_class;
+  
+  /* padding for future expansion */
+  void (* gtk_recent1) (void);
+  void (* gtk_recent2) (void);
+  void (* gtk_recent3) (void);
+  void (* gtk_recent4) (void);
+};
+
+GType      gtk_recent_chooser_menu_get_type         (void) G_GNUC_CONST;
+
+GtkWidget *gtk_recent_chooser_menu_new              (void);
+GtkWidget *gtk_recent_chooser_menu_new_for_manager  (GtkRecentManager     *manager);
+
+gboolean   gtk_recent_chooser_menu_get_show_numbers (GtkRecentChooserMenu *menu);
+void       gtk_recent_chooser_menu_set_show_numbers (GtkRecentChooserMenu *menu,
+						     gboolean              show_numbers);
+
+G_END_DECLS
+
+#endif /* ! __GTK_RECENT_CHOOSER_MENU_H__ */
diff -Nuarp gtk+/gtk/gtkrecentchooserprivate.h gtk+.recent/gtk/gtkrecentchooserprivate.h
--- gtk+/gtk/gtkrecentchooserprivate.h	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/gtk/gtkrecentchooserprivate.h	2006-03-26 23:46:37.000000000 +0200
@@ -0,0 +1,42 @@
+/* gtkrecentprivatechooser.h - Interface definitions for recent selectors UI
+ *
+ * Copyright (C) 2006 Emmanuele Bassi
+ *
+ * All rights reserved
+ *
+ * This 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.
+ *
+ * This 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+ 
+#ifndef __GTK_RECENT_CHOOSER_PRIVATE_H__
+#define __GTK_RECENT_CHOOSER_PRIVATE_H__
+
+#include <glib-object.h>
+
+#include "gtkrecentmanager.h"
+#include "gtkrecentchooser.h"
+
+G_BEGIN_DECLS
+
+#define GTK_DEFAULT_RECENT_MANAGER 	"gtk-recent-manager-default"
+
+GtkRecentManager *_gtk_recent_chooser_get_recent_manager (GtkRecentChooser *chooser);
+
+void              _gtk_recent_chooser_item_activated     (GtkRecentChooser *chooser);
+void              _gtk_recent_chooser_selection_changed  (GtkRecentChooser *chooser);
+
+G_END_DECLS
+ 
+#endif /* ! __GTK_RECENT_CHOOSER_PRIVATE_H__ */
diff -Nuarp gtk+/gtk/gtkrecentchooserutils.c gtk+.recent/gtk/gtkrecentchooserutils.c
--- gtk+/gtk/gtkrecentchooserutils.c	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/gtk/gtkrecentchooserutils.c	2006-03-26 23:46:37.000000000 +0200
@@ -0,0 +1,298 @@
+/* gtkrecentchooserutils.h - Private utility functions for implementing a
+ *                           GtkRecentChooser interface
+ *
+ * Copyright (C) 2006 Emmanuele Bassi
+ *
+ * All rights reserved
+ *
+ * This 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.
+ *
+ * This 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Based on gtkfilechooserutils.c:
+ *	Copyright (C) 2003 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include "gtkrecentchooserutils.h"
+
+/* Methods */
+static void      delegate_set_sort_func              (GtkRecentChooser  *chooser,
+						      GtkRecentSortFunc  sort_func,
+						      gpointer           sort_data,
+						      GDestroyNotify     data_destroy);
+static void      delegate_add_filter                 (GtkRecentChooser  *chooser,
+						      GtkRecentFilter   *filter);
+static void      delegate_remove_filter              (GtkRecentChooser  *chooser,
+						      GtkRecentFilter   *filter);
+static GSList   *delegate_list_filters               (GtkRecentChooser  *chooser);
+static gboolean  delegate_select_uri                 (GtkRecentChooser  *chooser,
+						      const gchar       *uri,
+						      GError           **error);
+static void      delegate_unselect_uri               (GtkRecentChooser  *chooser,
+						      const gchar       *uri);
+static GList    *delegate_get_items                  (GtkRecentChooser  *chooser);
+static GtkRecentManager *delegate_get_recent_manager (GtkRecentChooser  *chooser);
+static void      delegate_select_all                 (GtkRecentChooser  *chooser);
+static void      delegate_unselect_all               (GtkRecentChooser  *chooser);
+static gboolean  delegate_set_current_uri            (GtkRecentChooser  *chooser,
+						      const gchar       *uri,
+						      GError           **error);
+static gchar *   delegate_get_current_uri            (GtkRecentChooser  *chooser);
+
+/* Signals */
+static void      delegate_notify            (GObject          *object,
+					     GParamSpec       *pspec,
+					     gpointer          user_data);
+static void      delegate_selection_changed (GtkRecentChooser *receiver,
+					     gpointer          user_data);
+static void      delegate_item_activated    (GtkRecentChooser *receiver,
+					     gpointer          user_data);
+
+/**
+ * _gtk_recent_chooser_install_properties:
+ * @klass: the class structure for a type deriving from #GObject
+ *
+ * Installs the necessary properties for a class implementing
+ * #GtkRecentChooser. A #GtkParamSpecOverride property is installed
+ * for each property, using the values from the #GtkRecentChooserProp
+ * enumeration. The caller must make sure itself that the enumeration
+ * values don't collide with some other property values they
+ * are using.
+ */
+void
+_gtk_recent_chooser_install_properties (GObjectClass *klass)
+{
+  g_object_class_override_property (klass,
+  				    GTK_RECENT_CHOOSER_PROP_RECENT_MANAGER,
+  				    "recent-manager");  				    
+  g_object_class_override_property (klass,
+  				    GTK_RECENT_CHOOSER_PROP_SHOW_PRIVATE,
+  				    "show-private");
+  g_object_class_override_property (klass,
+  				    GTK_RECENT_CHOOSER_PROP_SHOW_TIPS,
+  				    "show-tips");
+  g_object_class_override_property (klass,
+  				    GTK_RECENT_CHOOSER_PROP_SHOW_ICONS,
+  				    "show-icons");
+  g_object_class_override_property (klass,
+  				    GTK_RECENT_CHOOSER_PROP_SHOW_NOT_FOUND,
+  				    "show-not-found");
+  g_object_class_override_property (klass,
+  				    GTK_RECENT_CHOOSER_PROP_SELECT_MULTIPLE,
+  				    "select-multiple");
+  g_object_class_override_property (klass,
+  				    GTK_RECENT_CHOOSER_PROP_LIMIT,
+  				    "limit");
+  g_object_class_override_property (klass,
+		  		    GTK_RECENT_CHOOSER_PROP_LOCAL_ONLY,
+				    "local-only");
+  g_object_class_override_property (klass,
+		  		    GTK_RECENT_CHOOSER_PROP_SORT_TYPE,
+				    "sort-type");
+  g_object_class_override_property (klass,
+  				    GTK_RECENT_CHOOSER_PROP_FILTER,
+  				    "filter");
+}
+
+/**
+ * _gtk_recent_chooser_delegate_iface_init:
+ * @iface: a #GtkRecentChooserIface
+ *
+ * An interface-initialization function for use in cases where
+ * an object is simply delegating the methods, signals of
+ * the #GtkRecentChooser interface to another object.
+ * _gtk_recent_chooser_set_delegate() must be called on each
+ * instance of the object so that the delegate object can
+ * be found.
+ */
+void
+_gtk_recent_chooser_delegate_iface_init (GtkRecentChooserIface *iface)
+{
+  iface->set_current_uri = delegate_set_current_uri;
+  iface->get_current_uri = delegate_get_current_uri;
+  iface->select_uri = delegate_select_uri;
+  iface->unselect_uri = delegate_unselect_uri;
+  iface->select_all = delegate_select_all;
+  iface->unselect_all = delegate_unselect_all;
+  iface->get_items = delegate_get_items;
+  iface->get_recent_manager = delegate_get_recent_manager;
+  iface->set_sort_func = delegate_set_sort_func;
+  iface->add_filter = delegate_add_filter;
+  iface->remove_filter = delegate_remove_filter;
+  iface->list_filters = delegate_list_filters;
+}
+
+/**
+ * _gtk_recent_chooser_set_delegate:
+ * @receiver: a #GObject implementing #GtkRecentChooser
+ * @delegate: another #GObject implementing #GtkRecentChooser
+ *
+ * Establishes that calls on @receiver for #GtkRecentChooser
+ * methods should be delegated to @delegate, and that
+ * #GtkRecentChooser signals emitted on @delegate should be
+ * forwarded to @receiver. Must be used in conjunction with
+ * _gtk_recent_chooser_delegate_iface_init().
+ */
+void
+_gtk_recent_chooser_set_delegate (GtkRecentChooser *receiver,
+				  GtkRecentChooser *delegate)
+{
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (receiver));
+  g_return_if_fail (GTK_IS_RECENT_CHOOSER (delegate));
+  
+  g_object_set_data (G_OBJECT (receiver),
+  		    "gtk-recent-chooser-delegate", delegate);
+  
+  g_signal_connect (delegate, "notify",
+  		    G_CALLBACK (delegate_notify), receiver);
+  g_signal_connect (delegate, "selection-changed",
+  		    G_CALLBACK (delegate_selection_changed), receiver);
+  g_signal_connect (delegate, "item-activated",
+  		    G_CALLBACK (delegate_item_activated), receiver);
+}
+
+GQuark
+_gtk_recent_chooser_delegate_get_quark (void)
+{
+  static GQuark quark = 0;
+  
+  if (G_UNLIKELY (quark == 0))
+    quark = g_quark_from_static_string ("gtk-recent-chooser-delegate");
+  
+  return quark;
+}
+
+static GtkRecentChooser *
+get_delegate (GtkRecentChooser *receiver)
+{
+  return g_object_get_qdata (G_OBJECT (receiver),
+  			     GTK_RECENT_CHOOSER_DELEGATE_QUARK);
+}
+
+static void
+delegate_set_sort_func (GtkRecentChooser  *chooser,
+			GtkRecentSortFunc  sort_func,
+			gpointer           sort_data,
+			GDestroyNotify     data_destroy)
+{
+  gtk_recent_chooser_set_sort_func (get_delegate (chooser),
+		  		    sort_func,
+				    sort_data,
+				    data_destroy);
+}
+
+static void
+delegate_add_filter (GtkRecentChooser *chooser,
+		     GtkRecentFilter  *filter)
+{
+  gtk_recent_chooser_add_filter (get_delegate (chooser), filter);
+}
+
+static void
+delegate_remove_filter (GtkRecentChooser *chooser,
+			GtkRecentFilter  *filter)
+{
+  gtk_recent_chooser_remove_filter (get_delegate (chooser), filter);
+}
+
+static GSList *
+delegate_list_filters (GtkRecentChooser *chooser)
+{
+  return gtk_recent_chooser_list_filters (get_delegate (chooser));
+}
+
+static gboolean
+delegate_select_uri (GtkRecentChooser  *chooser,
+		     const gchar       *uri,
+		     GError           **error)
+{
+  return gtk_recent_chooser_select_uri (get_delegate (chooser), uri, error);
+}
+
+static void
+delegate_unselect_uri (GtkRecentChooser *chooser,
+		       const gchar      *uri)
+{
+  return gtk_recent_chooser_unselect_uri (get_delegate (chooser), uri);
+}
+
+static GList *
+delegate_get_items (GtkRecentChooser *chooser)
+{
+  return gtk_recent_chooser_get_items (get_delegate (chooser));
+}
+
+static GtkRecentManager *
+delegate_get_recent_manager (GtkRecentChooser *chooser)
+{
+  return _gtk_recent_chooser_get_recent_manager (get_delegate (chooser));
+}
+
+static void
+delegate_select_all (GtkRecentChooser *chooser)
+{
+  gtk_recent_chooser_select_all (get_delegate (chooser));
+}
+
+static void
+delegate_unselect_all (GtkRecentChooser *chooser)
+{
+  gtk_recent_chooser_unselect_all (get_delegate (chooser));
+}
+
+static gboolean
+delegate_set_current_uri (GtkRecentChooser  *chooser,
+			  const gchar       *uri,
+			  GError           **error)
+{
+  return gtk_recent_chooser_set_current_uri (get_delegate (chooser), uri, error);
+}
+
+static gchar *
+delegate_get_current_uri (GtkRecentChooser *chooser)
+{
+  return gtk_recent_chooser_get_current_uri (get_delegate (chooser));
+}
+
+static void
+delegate_notify (GObject    *object,
+		 GParamSpec *pspec,
+		 gpointer    user_data)
+{
+  gpointer iface;
+
+  iface = g_type_interface_peek (g_type_class_peek (G_OBJECT_TYPE (object)),
+				 gtk_recent_chooser_get_type ());
+  if (g_object_interface_find_property (iface, pspec->name))
+    g_object_notify (user_data, pspec->name);
+}
+
+static void
+delegate_selection_changed (GtkRecentChooser *receiver,
+			    gpointer          user_data)
+{
+  _gtk_recent_chooser_selection_changed (GTK_RECENT_CHOOSER (user_data));
+}
+
+static void
+delegate_item_activated (GtkRecentChooser *receiver,
+			 gpointer          user_data)
+{
+  _gtk_recent_chooser_item_activated (GTK_RECENT_CHOOSER (user_data));
+}
+
+#define __GTK_RECENT_CHOOSER_UTILS_H__
+#include "gtkaliasdef.c"
diff -Nuarp gtk+/gtk/gtkrecentchooserutils.h gtk+.recent/gtk/gtkrecentchooserutils.h
--- gtk+/gtk/gtkrecentchooserutils.h	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/gtk/gtkrecentchooserutils.h	2006-03-26 23:46:37.000000000 +0200
@@ -0,0 +1,63 @@
+/* gtkrecentchooserutils.h - Private utility functions for implementing a
+ *                           GtkRecentChooser interface
+ *
+ * Copyright (C) 2006 Emmanuele Bassi
+ *
+ * All rights reserved
+ *
+ * This 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.
+ *
+ * This 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Based on gtkfilechooserutils.h:
+ *	Copyright (C) 2003 Red Hat, Inc.
+ */
+ 
+#ifndef __GTK_RECENT_CHOOSER_UTILS_H__
+#define __GTK_RECENT_CHOOSER_UTILS_H__
+
+#include "gtkrecentchooserprivate.h"
+
+G_BEGIN_DECLS
+
+
+#define GTK_RECENT_CHOOSER_DELEGATE_QUARK	(_gtk_recent_chooser_delegate_get_quark ())
+
+typedef enum {
+  GTK_RECENT_CHOOSER_PROP_FIRST           = 0x3000,
+  GTK_RECENT_CHOOSER_PROP_RECENT_MANAGER,
+  GTK_RECENT_CHOOSER_PROP_SHOW_PRIVATE,
+  GTK_RECENT_CHOOSER_PROP_SHOW_NOT_FOUND,
+  GTK_RECENT_CHOOSER_PROP_SHOW_TIPS,
+  GTK_RECENT_CHOOSER_PROP_SHOW_ICONS,
+  GTK_RECENT_CHOOSER_PROP_SELECT_MULTIPLE,
+  GTK_RECENT_CHOOSER_PROP_LIMIT,
+  GTK_RECENT_CHOOSER_PROP_LOCAL_ONLY,
+  GTK_RECENT_CHOOSER_PROP_SORT_TYPE,
+  GTK_RECENT_CHOOSER_PROP_FILTER,
+  GTK_RECENT_CHOOSER_PROP_LAST
+} GtkRecentChooserProp;
+
+void   _gtk_recent_chooser_install_properties  (GObjectClass          *klass);
+
+void   _gtk_recent_chooser_delegate_iface_init (GtkRecentChooserIface *iface);
+void   _gtk_recent_chooser_set_delegate        (GtkRecentChooser      *receiver,
+						GtkRecentChooser      *delegate);
+
+GQuark _gtk_recent_chooser_delegate_get_quark  (void) G_GNUC_CONST;
+
+
+G_END_DECLS
+
+#endif /* __GTK_RECENT_CHOOSER_UTILS_H__ */
diff -Nuarp gtk+/gtk/gtkrecentchooserwidget.c gtk+.recent/gtk/gtkrecentchooserwidget.c
--- gtk+/gtk/gtkrecentchooserwidget.c	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/gtk/gtkrecentchooserwidget.c	2006-03-26 23:46:37.000000000 +0200
@@ -0,0 +1,201 @@
+/* GTK - The GIMP Toolkit
+ * gtkrecentchooserwidget.c: embeddable recently used resources chooser widget
+ * Copyright (C) 2006 Emmanuele Bassi
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include "gtkrecentchooserwidget.h"
+#include "gtkrecentchooserdefault.h"
+#include "gtkrecentchooserutils.h"
+#include "gtktypebuiltins.h"
+#include "gtkalias.h"
+
+struct _GtkRecentChooserWidgetPrivate
+{
+  GtkRecentManager *manager;
+  
+  GtkWidget *chooser;
+};
+
+#define GTK_RECENT_CHOOSER_WIDGET_GET_PRIVATE(obj)	(GTK_RECENT_CHOOSER_WIDGET (obj)->priv)
+
+static GObject *gtk_recent_chooser_widget_constructor  (GType                  type,
+						        guint                  n_params,
+						        GObjectConstructParam *params);
+static void     gtk_recent_chooser_widget_set_property (GObject               *object,
+						        guint                  prop_id,
+						        const GValue          *value,
+						        GParamSpec            *pspec);
+static void     gtk_recent_chooser_widget_get_property (GObject               *object,
+						        guint                  prop_id,
+						        GValue                *value,
+						        GParamSpec            *pspec);
+static void     gtk_recent_chooser_widget_finalize     (GObject               *object);
+
+
+G_DEFINE_TYPE_WITH_CODE (GtkRecentChooserWidget,
+		         gtk_recent_chooser_widget,
+			 GTK_TYPE_VBOX,
+			 G_IMPLEMENT_INTERFACE (GTK_TYPE_RECENT_CHOOSER,
+						_gtk_recent_chooser_delegate_iface_init));
+
+static void
+gtk_recent_chooser_widget_class_init (GtkRecentChooserWidgetClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->constructor = gtk_recent_chooser_widget_constructor;
+  gobject_class->set_property = gtk_recent_chooser_widget_set_property;
+  gobject_class->get_property = gtk_recent_chooser_widget_get_property;
+  gobject_class->finalize = gtk_recent_chooser_widget_finalize;
+
+  _gtk_recent_chooser_install_properties (gobject_class);
+
+  g_type_class_add_private (klass, sizeof (GtkRecentChooserWidgetPrivate));
+}
+
+
+static void
+gtk_recent_chooser_widget_init (GtkRecentChooserWidget *widget)
+{
+  widget->priv = G_TYPE_INSTANCE_GET_PRIVATE (widget, GTK_TYPE_RECENT_CHOOSER_WIDGET,
+					      GtkRecentChooserWidgetPrivate);
+}
+
+static GObject *
+gtk_recent_chooser_widget_constructor (GType                  type,
+				       guint                  n_params,
+				       GObjectConstructParam *params)
+{
+  GObject *object;
+  GtkRecentChooserWidgetPrivate *priv;
+
+  object = G_OBJECT_CLASS (gtk_recent_chooser_widget_parent_class)->constructor (type,
+										 n_params,
+										 params);
+
+  priv = GTK_RECENT_CHOOSER_WIDGET_GET_PRIVATE (object);
+  priv->chooser = _gtk_recent_chooser_default_new (priv->manager);
+  
+  
+  gtk_container_add (GTK_CONTAINER (object), priv->chooser);
+  gtk_widget_show (priv->chooser);
+  _gtk_recent_chooser_set_delegate (GTK_RECENT_CHOOSER (object),
+				    GTK_RECENT_CHOOSER (priv->chooser));
+
+  return object;
+}
+
+static void
+gtk_recent_chooser_widget_set_property (GObject      *object,
+				        guint         prop_id,
+				        const GValue *value,
+				        GParamSpec   *pspec)
+{
+  GtkRecentChooserWidgetPrivate *priv;
+
+  priv = GTK_RECENT_CHOOSER_WIDGET_GET_PRIVATE (object);
+  
+  switch (prop_id)
+    {
+    case GTK_RECENT_CHOOSER_PROP_RECENT_MANAGER:
+      if (priv->manager)
+        g_object_unref (priv->manager);
+      priv->manager = g_value_get_object (value);
+      if (priv->manager)
+        g_object_ref (priv->manager);
+      break;
+    default:
+      g_object_set_property (G_OBJECT (priv->chooser), pspec->name, value);
+      break;
+    }
+}
+
+static void
+gtk_recent_chooser_widget_get_property (GObject    *object,
+				        guint       prop_id,
+				        GValue     *value,
+				        GParamSpec *pspec)
+{
+  GtkRecentChooserWidgetPrivate *priv;
+
+  priv = GTK_RECENT_CHOOSER_WIDGET_GET_PRIVATE (object);
+
+  g_object_get_property (G_OBJECT (priv->chooser), pspec->name, value);
+}
+
+static void
+gtk_recent_chooser_widget_finalize (GObject *object)
+{
+  GtkRecentChooserWidgetPrivate *priv;
+  
+  priv = GTK_RECENT_CHOOSER_WIDGET_GET_PRIVATE (object);
+  
+  if (priv->manager)
+    g_object_unref (G_OBJECT (priv->manager));
+  
+  G_OBJECT_CLASS (gtk_recent_chooser_widget_parent_class)->finalize (object);
+}
+
+/*
+ * Public API
+ */
+
+/**
+ * gtk_recent_chooser_widget_new:
+ * 
+ * Creates a new #GtkRecentChooserWidget object.  This is an embeddable widget
+ * used to access the recently used resources list.
+ *
+ * Return value: a new #GtkRecentChooserWidget
+ *
+ * Since: 2.10
+ */
+GtkWidget *
+gtk_recent_chooser_widget_new (void)
+{
+  return g_object_new (GTK_TYPE_RECENT_CHOOSER_WIDGET, NULL);
+}
+
+/**
+ * gtk_recent_chooser_widget_new_for_manager:
+ * @manager: a #GtkRecentManager
+ *
+ * Creates a new #GtkRecentChooserWidget with a specified recent manager.
+ *
+ * This is useful if you have implemented your own recent manager, or if you
+ * have a customized instance of a #GtkRecentManager object (e.g. with your
+ * own sorting and/or filtering functions).
+ *
+ * Return value: a new #GtkRecentChooserWidget
+ *
+ * Since: 2.10
+ */
+GtkWidget *
+gtk_recent_chooser_widget_new_for_manager (GtkRecentManager *manager)
+{
+  g_return_val_if_fail (GTK_IS_RECENT_MANAGER (manager), NULL);
+  
+  return g_object_new (GTK_TYPE_RECENT_CHOOSER_WIDGET,
+  		       "recent-manager", manager,
+  		       NULL);
+}
+
+#define __GTK_RECENT_CHOOSER_WIDGET_C__
+#include "gtkaliasdef.c"
diff -Nuarp gtk+/gtk/gtkrecentchooserwidget.h gtk+.recent/gtk/gtkrecentchooserwidget.h
--- gtk+/gtk/gtkrecentchooserwidget.h	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/gtk/gtkrecentchooserwidget.h	2006-03-26 23:46:37.000000000 +0200
@@ -0,0 +1,60 @@
+/* GTK - The GIMP Toolkit
+ * gtkrecentchooserwidget.h: embeddable recently used resources chooser widget
+ * Copyright (C) 2006 Emmanuele Bassi
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_RECENT_CHOOSER_WIDGET_H__
+#define __GTK_RECENT_CHOOSER_WIDGET_H__
+
+#include "gtkrecentchooser.h"
+#include <gtk/gtkvbox.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_RECENT_CHOOSER_WIDGET		  (gtk_recent_chooser_widget_get_type ())
+#define GTK_RECENT_CHOOSER_WIDGET(obj)		  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_RECENT_CHOOSER_WIDGET, GtkRecentChooserWidget))
+#define GTK_IS_RECENT_CHOOSER_WIDGET(obj)	  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_RECENT_CHOOSER_WIDGET))
+#define GTK_RECENT_CHOOSER_WIDGET_CLASS(klass)	  (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_RECENT_CHOOSER_WIDGET, GtkRecentChooserWidgetClass))
+#define GTK_IS_RECENT_CHOOSER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_RECENT_CHOOSER_WIDGET))
+#define GTK_RECENT_CHOOSER_WIDGET_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_RECENT_CHOOSER_WIDGET, GtkRecentChooserWidgetClass))
+
+typedef struct _GtkRecentChooserWidget        GtkRecentChooserWidget;
+typedef struct _GtkRecentChooserWidgetClass   GtkRecentChooserWidgetClass;
+
+typedef struct _GtkRecentChooserWidgetPrivate GtkRecentChooserWidgetPrivate;
+
+struct _GtkRecentChooserWidget
+{
+  /*< private >*/
+  GtkVBox parent_instance;
+  
+  GtkRecentChooserWidgetPrivate *priv;
+};
+
+struct _GtkRecentChooserWidgetClass
+{
+  GtkVBoxClass parent_class;
+};
+
+GType      gtk_recent_chooser_widget_get_type        (void) G_GNUC_CONST;
+GtkWidget *gtk_recent_chooser_widget_new             (void);
+GtkWidget *gtk_recent_chooser_widget_new_for_manager (GtkRecentManager *manager);
+
+G_END_DECLS
+
+#endif /* __GTK_RECENT_CHOOSER_WIDGET_H__ */
diff -Nuarp gtk+/gtk/gtkrecentfilter.c gtk+.recent/gtk/gtkrecentfilter.c
--- gtk+/gtk/gtkrecentfilter.c	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/gtk/gtkrecentfilter.c	2006-03-26 23:46:37.000000000 +0200
@@ -0,0 +1,579 @@
+/* GTK - The GIMP Toolkit
+ * gtkrecentfilter.h - Filter object for recently used resources
+ * Copyright (C) 2006, Emmanuele Bassi
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include <string.h>
+
+#include "gtkrecentfilter.h"
+#include "gtkobject.h"
+#include "gtkintl.h"
+#include "gtkprivate.h"
+
+#include "gtkalias.h"
+
+#ifdef G_OS_UNIX
+#define XDG_PREFIX _gtk_xdg
+#include "xdgmime/xdgmime.h"
+#endif
+
+typedef struct _GtkRecentFilterClass GtkRecentFilterClass;
+typedef struct _FilterRule FilterRule;
+
+typedef enum {
+  FILTER_RULE_URI,
+  FILTER_RULE_DISPLAY_NAME,
+  FILTER_RULE_MIME_TYPE,
+  FILTER_RULE_PIXBUF_FORMATS,
+  FILTER_RULE_APPLICATION,
+  FILTER_RULE_AGE,
+  FILTER_RULE_GROUP,
+  FILTER_RULE_CUSTOM,
+} FilterRuleType;
+
+struct _GtkRecentFilter
+{
+  GtkObject parent_instance;
+  
+  gchar *name;
+  GSList *rules;
+  
+  GtkRecentFilterFlags needed;
+};
+
+struct _GtkRecentFilterClass
+{
+  GtkObjectClass parent_class;
+};
+
+struct _FilterRule
+{
+  FilterRuleType type;
+  GtkRecentFilterFlags needed;
+  
+  union {
+    gchar *uri;
+    gchar *pattern;
+    gchar *mime_type;
+    GSList *pixbuf_formats;
+    gchar *application;
+    gchar *group;
+    gint age;
+    struct {
+      GtkRecentFilterFunc func;
+      gpointer data;
+      GDestroyNotify data_destroy;
+    } custom;
+  } u;
+};
+
+G_DEFINE_TYPE (GtkRecentFilter, gtk_recent_filter, GTK_TYPE_OBJECT);
+
+
+static void
+filter_rule_free (FilterRule *rule)
+{
+  switch (rule->type)
+    {
+    case FILTER_RULE_MIME_TYPE:
+      g_free (rule->u.mime_type);
+      break;
+    case FILTER_RULE_URI:
+      g_free (rule->u.uri);
+      break;
+    case FILTER_RULE_DISPLAY_NAME:
+      g_free (rule->u.pattern);
+      break;
+    case FILTER_RULE_PIXBUF_FORMATS:
+      g_slist_free (rule->u.pixbuf_formats);
+      break;
+    case FILTER_RULE_AGE:
+      break;
+    case FILTER_RULE_APPLICATION:
+      g_free (rule->u.application);
+      break;
+    case FILTER_RULE_GROUP:
+      g_free (rule->u.group);
+      break;
+    case FILTER_RULE_CUSTOM:
+      if (rule->u.custom.data_destroy)
+        rule->u.custom.data_destroy (rule->u.custom.data);
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+  
+  g_free (rule);
+}
+
+static void
+gtk_recent_filter_finalize (GObject *object)
+{
+  GtkRecentFilter *filter = GTK_RECENT_FILTER (object);
+  
+  if (filter->name)
+    g_free (filter->name);
+  
+  if (filter->rules)
+    {
+      g_slist_foreach (filter->rules,
+      		       (GFunc) filter_rule_free,
+      		       NULL);
+      g_slist_free (filter->rules);
+    }
+  
+  G_OBJECT_CLASS (gtk_recent_filter_parent_class)->finalize (object);
+}
+
+static void
+gtk_recent_filter_class_init (GtkRecentFilterClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  
+  gobject_class->finalize = gtk_recent_filter_finalize;
+}
+
+static void
+gtk_recent_filter_init (GtkRecentFilter *filter)
+{
+
+}
+
+/*
+ * Public API
+ */
+ 
+/**
+ * gtk_recent_filter_new:
+ *
+ * Creates a new #GtkRecentFilter with no rules added to it.
+ * Such filter does not accept any recently used resources, so is not
+ * particularly useful until you add rules with
+ * gtk_recent_filter_add_pattern(), gtk_recent_filter_add_mime_type(),
+ * gtk_recent_filter_add_application(), gtk_recent_filter_add_age().
+ * To create a filter that accepts any recently used resource, use:
+ *
+ * <informalexample><programlisting>
+ * GtkRecentFilter *filter = gtk_recent_filter_new (<!-- -->);
+ * gtk_recent_filter_add_pattern (filter, "*");
+ * </programlisting></informalexample>
+ *
+ * Return value: a new #GtkRecentFilter
+ *
+ * Since: 2.10
+ */
+GtkRecentFilter *
+gtk_recent_filter_new (void)
+{
+  return g_object_new (GTK_TYPE_RECENT_FILTER, NULL);
+}
+
+/**
+ * gtk_recent_filter_set_name:
+ * @filter: a #GtkRecentFilter
+ * @name: then human readable name of @filter
+ *
+ * Sets the human-readable name of the filter; this is the string
+ * that will be displayed in the recently used resources selector
+ * user interface if there is a selectable list of filters.
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_filter_set_name (GtkRecentFilter *filter,
+			    const gchar     *name)
+{
+  g_return_if_fail (GTK_IS_RECENT_FILTER (filter));
+  
+  if (filter->name)
+    g_free (filter->name);
+  
+  if (name)
+    filter->name = g_strdup (name);
+}
+
+/**
+ * gtk_recent_filter_get_name:
+ * @filter: a #GtkRecentFilter
+ *
+ * Gets the human-readable name for the filter.
+ * See gtk_recent_filter_set_name().
+ *
+ * Return value: the name of the filter, or %NULL.  The returned string
+ *   is owned by the filter object and should not be freed.
+ *
+ * Since: 2.10
+ */
+G_CONST_RETURN gchar *
+gtk_recent_filter_get_name (GtkRecentFilter *filter)
+{
+  g_return_val_if_fail (GTK_IS_RECENT_FILTER (filter), NULL);
+  
+  return filter->name;
+}
+
+/**
+ * gtk_recent_filter_get_needed:
+ * @filter: a #GtkRecentFilter
+ *
+ * Gets the fields that need to be filled in for the structure
+ * passed to gtk_recent_filter_filter()
+ * 
+ * This function will not typically be used by applications; it
+ * is intended principally for use in the implementation of
+ * #GtkRecentChooser.
+ * 
+ * Return value: bitfield of flags indicating needed fields when
+ *   calling gtk_recent_filter_filter()
+ *
+ * Since: 2.10
+ */
+GtkRecentFilterFlags
+gtk_recent_filter_get_needed (GtkRecentFilter *filter)
+{
+  return filter->needed;
+}
+
+static void
+recent_filter_add_rule (GtkRecentFilter *filter,
+			FilterRule      *rule)
+{
+  filter->needed |= rule->needed;
+  filter->rules = g_slist_append (filter->rules, rule);
+}
+
+/**
+ * gtk_recent_filter_add_mime_type:
+ * @filter: a #GtkRecentFilter
+ * @mime_type: a MIME type
+ *
+ * Adds a rule that allows resources based on their registered MIME type.
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_filter_add_mime_type (GtkRecentFilter *filter,
+				 const gchar     *mime_type)
+{
+  FilterRule *rule;
+  
+  g_return_if_fail (GTK_IS_RECENT_FILTER (filter));
+  g_return_if_fail (mime_type != NULL);
+  
+  rule = g_new0 (FilterRule, 1);
+  rule->type = FILTER_RULE_MIME_TYPE;
+  rule->needed = GTK_RECENT_FILTER_MIME_TYPE;
+  rule->u.mime_type = g_strdup (mime_type);
+  
+  recent_filter_add_rule (filter, rule);
+}
+
+/**
+ * gtk_recent_filter_add_pattern:
+ * @filter: a #GtkRecentFilter
+ * @pattern: a file pattern
+ *
+ * Adds a rule that allows resources based on a pattern matching their
+ * display name.
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_filter_add_pattern (GtkRecentFilter *filter,
+			       const gchar     *pattern)
+{
+  FilterRule *rule;
+  
+  g_return_if_fail (GTK_IS_RECENT_FILTER (filter));
+  g_return_if_fail (pattern != NULL);
+  
+  rule = g_new0 (FilterRule, 1);
+  rule->type = FILTER_RULE_DISPLAY_NAME;
+  rule->needed = GTK_RECENT_FILTER_DISPLAY_NAME;
+  rule->u.pattern = g_strdup (pattern);
+  
+  recent_filter_add_rule (filter, rule);
+}
+
+/**
+ * gtk_recent_filter_add_pixbuf_formats:
+ * @filter: a #GtkRecentFilter
+ *
+ * Adds a rule allowing image files in the formats supported
+ * by GdkPixbuf.
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_filter_add_pixbuf_formats (GtkRecentFilter *filter)
+{
+  FilterRule *rule;
+
+  g_return_if_fail (GTK_IS_RECENT_FILTER (filter));
+
+  rule = g_new0 (FilterRule, 1);
+  rule->type = FILTER_RULE_PIXBUF_FORMATS;
+  rule->needed = GTK_RECENT_FILTER_MIME_TYPE;
+  rule->u.pixbuf_formats = gdk_pixbuf_get_formats ();
+  
+  recent_filter_add_rule (filter, rule);
+}
+
+/**
+ * gtk_recent_filter_add_application:
+ * @filter: a #GtkRecentFilter
+ * @application: an application name
+ *
+ * Adds a rule that allows resources based on the name of the application
+ * that has registered them.
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_filter_add_application (GtkRecentFilter *filter,
+				   const gchar     *application)
+{
+  FilterRule *rule;
+  
+  g_return_if_fail (GTK_IS_RECENT_FILTER (filter));
+  g_return_if_fail (application != NULL);
+  
+  rule = g_new0 (FilterRule, 1);
+  rule->type = FILTER_RULE_APPLICATION;
+  rule->needed = GTK_RECENT_FILTER_APPLICATION;
+  rule->u.application = g_strdup (application);
+  
+  recent_filter_add_rule (filter, rule);
+}
+
+/**
+ * gtk_recent_filter_add_group:
+ * @filter: a #GtkRecentFilter
+ * @group: a group name
+ *
+ * Adds a rule that allows resources based on the name of the group
+ * to which they belong
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_filter_add_group (GtkRecentFilter *filter,
+			     const gchar     *group)
+{
+  FilterRule *rule;
+  
+  g_return_if_fail (GTK_IS_RECENT_FILTER (filter));
+  g_return_if_fail (group != NULL);
+  
+  rule = g_new0 (FilterRule, 1);
+  rule->type = FILTER_RULE_GROUP;
+  rule->needed = GTK_RECENT_FILTER_GROUP;
+  rule->u.group = g_strdup (group);
+  
+  recent_filter_add_rule (filter, rule);
+}
+
+/**
+ * gtk_recent_filter_add_mime_type:
+ * @filter: a #GtkRecentFilter
+ * @days: number of days
+ *
+ * Adds a rule that allows resources based on their age - that is, the number
+ * of days elapsed since they were last modified.
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_filter_add_age (GtkRecentFilter *filter,
+			   gint             days)
+{
+  FilterRule *rule;
+  
+  g_return_if_fail (GTK_IS_RECENT_FILTER (filter));
+  
+  rule = g_new0 (FilterRule, 1);
+  rule->type = FILTER_RULE_AGE;
+  rule->needed = GTK_RECENT_FILTER_AGE;
+  rule->u.age = days;
+  
+  recent_filter_add_rule (filter, rule);
+}
+
+/**
+ * gtk_recent_filter_add_custom:
+ * @filter: a #GtkRecentFilter
+ * @needed: bitfield of flags indicating the information that the custom
+ *          filter function needs.
+ * @func: callback function; if the function returns %TRUE, then
+ *   the file will be displayed.
+ * @data: data to pass to @func
+ * @data_destroy: function to call to free @data when it is no longer needed.
+ * 
+ * Adds a rule to a filter that allows resources based on a custom callback
+ * function. The bitfield @needed which is passed in provides information
+ * about what sorts of information that the filter function needs;
+ * this allows GTK+ to avoid retrieving expensive information when
+ * it isn't needed by the filter.
+ * 
+ * Since: 2.10
+ **/
+void
+gtk_recent_filter_add_custom (GtkRecentFilter      *filter,
+			      GtkRecentFilterFlags  needed,
+			      GtkRecentFilterFunc   func,
+			      gpointer              data,
+			      GDestroyNotify        data_destroy)
+{
+  FilterRule *rule;
+  
+  g_return_if_fail (GTK_IS_RECENT_FILTER (filter));
+  g_return_if_fail (func != NULL);
+
+  rule = g_new0 (FilterRule, 1);
+  rule->type = FILTER_RULE_CUSTOM;
+  rule->needed = needed;
+  rule->u.custom.func = func;
+  rule->u.custom.data = data;
+  rule->u.custom.data_destroy = data_destroy;
+
+  recent_filter_add_rule (filter, rule);
+}
+
+
+/**
+ * gtk_recent_filter_filter:
+ * @filter: a #GtkRecentFilter
+ * @filter_info: a #GtkRecentFilterInfo structure containing information
+ *   about a recently used resource
+ *
+ * Tests whether a file should be displayed according to @filter.
+ * The #GtkRecentFilterInfo structure @filter_info should include
+ * the fields returned from gtk_recent_filter_get_needed().
+ *
+ * This function will not typically be used by applications; it
+ * is intended principally for use in the implementation of
+ * #GtkRecentChooser.
+ * 
+ * Return value: %TRUE if the file should be displayed
+ */
+gboolean
+gtk_recent_filter_filter (GtkRecentFilter           *filter,
+			  const GtkRecentFilterInfo *filter_info)
+{
+  GSList *l;
+  
+  g_return_val_if_fail (GTK_IS_RECENT_FILTER (filter), FALSE);
+  g_return_val_if_fail (filter_info != NULL, FALSE);
+  
+  for (l = filter->rules; l != NULL; l = l->next)
+    {
+      FilterRule *rule = (FilterRule *) l->data;
+
+      if ((filter_info->contains & rule->needed) != rule->needed)
+        continue;
+
+      switch (rule->type)
+        {
+        case FILTER_RULE_MIME_TYPE:
+          if ((filter_info->mime_type != NULL)
+#ifdef G_OS_UNIX
+              && (xdg_mime_mime_type_subclass (filter_info->mime_type, rule->u.mime_type)))
+#else
+	      && (strcmp (filter_info->mime_type, rule->u.mime_type) == 0))
+#endif
+            return TRUE;
+          break;
+        case FILTER_RULE_APPLICATION:
+          if (filter_info->applications)
+            {
+              gint i;
+              
+              for (i = 0; filter_info->applications[i] != NULL; i++)
+                {
+                  if (strcmp (filter_info->applications[i], rule->u.application) == 0)
+                    return TRUE;
+                }
+            }
+          break;
+	case FILTER_RULE_GROUP:
+	  if (filter_info->groups)
+            {
+	      gint i;
+
+	      for (i = 0; filter_info->groups[i] != NULL; i++)
+		{
+		  if (strcmp (filter_info->groups[i], rule->u.group) == 0)
+		    return TRUE;
+		}
+	    }
+	  break;
+	case FILTER_RULE_PIXBUF_FORMATS:
+	  {
+            GSList *list;
+	    if (!filter_info->mime_type)
+	      break;
+
+	    for (list = rule->u.pixbuf_formats; list; list = list->next)
+              {
+                gint i;
+		gchar **mime_types;
+
+		mime_types = gdk_pixbuf_format_get_mime_types (list->data);
+
+		for (i = 0; mime_types[i] != NULL; i++)
+                  {
+                    if (strcmp (mime_types[i], filter_info->mime_type) == 0)
+                      {
+			g_strfreev (mime_types);
+			return TRUE;
+		      }
+		  }
+
+		g_strfreev (mime_types);
+	      }
+	    break;
+	  }
+        case FILTER_RULE_URI:
+          if ((filter_info->uri != NULL) &&
+              _gtk_fnmatch (rule->u.uri, filter_info->uri, FALSE))
+            return TRUE;
+          break;
+        case FILTER_RULE_DISPLAY_NAME:
+          if ((filter_info->display_name != NULL) &&
+              _gtk_fnmatch (rule->u.pattern, filter_info->display_name, FALSE))
+            return TRUE;
+          break;
+        case FILTER_RULE_AGE:
+          if ((filter_info->age != -1) &&
+              (filter_info->age < rule->u.age))
+            return TRUE;
+          break;
+        case FILTER_RULE_CUSTOM:
+          if (rule->u.custom.func (filter_info, rule->u.custom.data))
+            return TRUE;
+          break;
+        }
+    }
+  
+  return FALSE;
+}
+
+#define __GTK_RECENT_FILTER_C__
+#include "gtkaliasdef.c"
diff -Nuarp gtk+/gtk/gtkrecentfilter.h gtk+.recent/gtk/gtkrecentfilter.h
--- gtk+/gtk/gtkrecentfilter.h	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/gtk/gtkrecentfilter.h	2006-03-26 23:46:37.000000000 +0200
@@ -0,0 +1,90 @@
+/* GTK - The GIMP Toolkit
+ * gtkrecentfilter.h - Filter object for recently used resources
+ * Copyright (C) 2006, Emmanuele Bassi
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_RECENT_FILTER_H__
+#define __GTK_RECENT_FILTER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_RECENT_FILTER		(gtk_recent_filter_get_type ())
+#define GTK_RECENT_FILTER(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_RECENT_FILTER, GtkRecentFilter))
+#define GTK_IS_RECENT_FILTER(obj)	(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_RECENT_FILTER))
+
+typedef struct _GtkRecentFilter		GtkRecentFilter;
+typedef struct _GtkRecentFilterInfo	GtkRecentFilterInfo;
+
+typedef enum {
+  GTK_RECENT_FILTER_URI          = 1 << 0,
+  GTK_RECENT_FILTER_DISPLAY_NAME = 1 << 1,
+  GTK_RECENT_FILTER_MIME_TYPE    = 1 << 2,
+  GTK_RECENT_FILTER_APPLICATION  = 1 << 3,
+  GTK_RECENT_FILTER_GROUP        = 1 << 4,
+  GTK_RECENT_FILTER_AGE          = 1 << 5
+} GtkRecentFilterFlags;
+
+typedef gboolean (*GtkRecentFilterFunc) (const GtkRecentFilterInfo *filter_info,
+					 gpointer                   user_data);
+
+struct _GtkRecentFilterInfo
+{
+  GtkRecentFilterFlags contains;
+
+  const gchar *uri;
+  const gchar *display_name;
+  const gchar *mime_type;
+  const gchar **applications;
+  const gchar **groups;
+  
+  gint age;
+};
+
+GType                 gtk_recent_filter_get_type (void) G_GNUC_CONST;
+
+GtkRecentFilter *     gtk_recent_filter_new      (void);
+void                  gtk_recent_filter_set_name (GtkRecentFilter *filter,
+						  const gchar     *name);
+G_CONST_RETURN gchar *gtk_recent_filter_get_name (GtkRecentFilter *filter);
+
+void gtk_recent_filter_add_mime_type      (GtkRecentFilter      *filter,
+					   const gchar          *mime_type);
+void gtk_recent_filter_add_pattern        (GtkRecentFilter      *filter,
+					   const gchar          *pattern);
+void gtk_recent_filter_add_pixbuf_formats (GtkRecentFilter      *filter);
+void gtk_recent_filter_add_application    (GtkRecentFilter      *filter,
+					   const gchar          *application);
+void gtk_recent_filter_add_group          (GtkRecentFilter      *filter,
+					   const gchar          *group);
+void gtk_recent_filter_add_age            (GtkRecentFilter      *filter,
+					   gint                  days);
+void gtk_recent_filter_add_custom         (GtkRecentFilter      *filter,
+					   GtkRecentFilterFlags  needed,
+					   GtkRecentFilterFunc   func,
+					   gpointer              data,
+					   GDestroyNotify        data_destroy);
+
+GtkRecentFilterFlags gtk_recent_filter_get_needed (GtkRecentFilter           *filter);
+gboolean             gtk_recent_filter_filter     (GtkRecentFilter           *filter,
+						   const GtkRecentFilterInfo *filter_info);
+
+G_END_DECLS
+
+#endif /* ! __GTK_RECENT_FILTER_H__ */
diff -Nuarp gtk+/gtk/gtkrecentmanager.c gtk+.recent/gtk/gtkrecentmanager.c
--- gtk+/gtk/gtkrecentmanager.c	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/gtk/gtkrecentmanager.c	2006-03-26 23:46:37.000000000 +0200
@@ -0,0 +1,2219 @@
+/* GTK - The GIMP Toolkit
+ * gtkrecentmanager.c: a manager for the recently used resources
+ *
+ * Copyright (C) 2006 Emmanuele Bassi
+ *
+ * This 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.
+ *
+ * This 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include "gtkrecentmanager.h"
+#include "gtkintl.h"
+#include "gtkstock.h"
+#include "gtkicontheme.h"
+#include "gtktypebuiltins.h"
+#include "gtkprivate.h"
+#include "gtkmarshalers.h"
+#include "gtkalias.h"
+
+#ifdef G_OS_UNIX
+#define XDG_PREFIX _gtk_xdg
+#include "xdgmime/xdgmime.h"
+#endif
+
+/* the file where we store the recently used items */
+#define GTK_RECENTLY_USED_FILE	".recently-used.xbel"
+
+/* a poll per second should be enough */
+#define POLL_DELTA	1000
+
+/* return all items by default */
+#define DEFAULT_LIMIT	-1
+
+/* keep in sync with xdgmime */
+#define GTK_RECENT_DEFAULT_MIME	"application/octet-stream"
+
+typedef struct
+{
+  gchar *name;
+  gchar *exec;
+  
+  guint count;
+  
+  time_t stamp;
+} RecentAppInfo;
+
+struct _GtkRecentInfo
+{
+  gchar *uri;
+  
+  gchar *display_name;
+  gchar *description;
+  
+  time_t added;
+  time_t modified;
+  time_t visited;
+  
+  gchar *mime_type;
+  
+  GSList *applications;
+  GHashTable *apps_lookup;
+  
+  GSList *groups;
+  
+  gboolean is_private;
+  
+  GdkPixbuf *icon;
+  
+  gint ref_count;
+};
+
+struct _GtkRecentManagerPrivate
+{
+  gchar *filename;
+
+  guint is_dirty : 1;
+  guint write_in_progress : 1;
+  guint read_in_progress : 1;
+  
+  gint limit;
+  gint size;
+  
+  GBookmarkFile *recent_items;
+  
+  time_t last_mtime;
+  guint poll_timeout;
+};
+
+enum
+{
+  PROP_0,
+  
+  PROP_LIMIT,
+  PROP_SIZE
+};
+
+static void           gtk_recent_manager_finalize     (GObject               *object);
+
+static void           gtk_recent_manager_set_property (GObject               *object,
+						       guint                  prop_id,
+						       const GValue          *value,
+						       GParamSpec            *pspec);
+static void           gtk_recent_manager_get_property (GObject               *object,
+						       guint                  prop_id,
+						       GValue                *value,
+						       GParamSpec            *pspec);
+static void           gtk_recent_manager_changed      (GtkRecentManager      *manager);
+
+static void           gtk_recent_manager_real_changed (GtkRecentManager      *manager);
+static gboolean       gtk_recent_manager_poll_timeout (gpointer               data);
+
+static void           build_recent_items_list         (GtkRecentManager      *manager);
+static void           purge_recent_items_list         (GtkRecentManager      *manager,
+						       GError               **error);
+
+static RecentAppInfo *recent_app_info_new             (const gchar           *app_name);
+static void           recent_app_info_free            (RecentAppInfo         *app_info);
+
+static GtkRecentInfo *gtk_recent_info_new             (const gchar           *uri);
+static void           gtk_recent_info_free            (GtkRecentInfo         *recent_info);
+
+static guint signal_changed = 0;
+
+G_DEFINE_TYPE (GtkRecentManager, gtk_recent_manager, G_TYPE_OBJECT);
+
+GQuark
+gtk_recent_manager_error_quark (void)
+{
+  static GQuark quark = 0;
+  if (quark == 0)
+    quark = g_quark_from_static_string ("gtk-recent-manager-error-quark");
+  return quark;
+}
+
+
+static void
+gtk_recent_manager_class_init (GtkRecentManagerClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  
+  gtk_recent_manager_parent_class = g_type_class_peek_parent (klass);
+  
+  gobject_class->set_property = gtk_recent_manager_set_property;
+  gobject_class->get_property = gtk_recent_manager_get_property;
+  gobject_class->finalize = gtk_recent_manager_finalize;
+  
+  /**
+   * GtkRecentManager:limit
+   *
+   * The maximum number of items to be returned by the
+   * gtk_recent_manager_get_items() function.
+   *
+   * Since: 2.10
+   */
+  g_object_class_install_property (gobject_class,
+  				   PROP_LIMIT,
+  				   g_param_spec_int ("limit",
+  				   		     P_("Limit"),
+  				   		     P_("The maximum number of items to be returned by gtk_recent_manager_get_items()"),
+  				   		     -1,
+  				   		     G_MAXINT,
+  				   		     DEFAULT_LIMIT,
+  				   		     G_PARAM_READWRITE));
+  /**
+   * GtkRecentManager:size
+   * 
+   * The size of the recently used resources list.
+   *
+   * Since: 2.10
+   */
+  g_object_class_install_property (gobject_class,
+		  		   PROP_SIZE,
+				   g_param_spec_int ("size",
+					   	     P_("Size"),
+						     P_("The size of the recently used resources list"),
+						     -1,
+						     G_MAXINT,
+						     0,
+						     G_PARAM_READABLE));
+  
+  /**
+   * GtkRecentManager::changed
+   * @recent_manager: the recent manager
+   *
+   * Emitted when the current recently used resources manager changes its
+   * contents.
+   *
+   * Since: 2.10
+   */
+  signal_changed =
+    g_signal_new (I_("changed"),
+		  G_TYPE_FROM_CLASS (klass),
+		  G_SIGNAL_RUN_FIRST,
+		  G_STRUCT_OFFSET (GtkRecentManagerClass, changed),
+		  NULL, NULL,
+		  g_cclosure_marshal_VOID__VOID,
+		  G_TYPE_NONE, 0);
+  
+  klass->changed = gtk_recent_manager_real_changed;
+  
+  g_type_class_add_private (klass, sizeof (GtkRecentManagerPrivate));
+}
+
+static void
+gtk_recent_manager_init (GtkRecentManager *manager)
+{
+  GtkRecentManagerPrivate *priv;
+  
+  priv = g_type_instance_get_private ((GTypeInstance *) manager,
+  				      GTK_TYPE_RECENT_MANAGER);
+  manager->priv = priv;
+  
+  /* where we store the recently used resources data */
+  priv->filename = g_build_filename (g_get_home_dir (),
+  				     GTK_RECENTLY_USED_FILE,
+  				     NULL);
+  
+  priv->limit = DEFAULT_LIMIT;
+  priv->size = 0;
+  
+  build_recent_items_list (manager);
+  
+  priv->poll_timeout = g_timeout_add (POLL_DELTA,
+  				      gtk_recent_manager_poll_timeout,
+  				      manager);
+  
+  priv->is_dirty = FALSE;
+  priv->write_in_progress = FALSE;
+  priv->read_in_progress = FALSE;
+}
+
+static void
+gtk_recent_manager_set_property (GObject               *object,
+				 guint                  prop_id,
+				 const GValue          *value,
+				 GParamSpec            *pspec)
+{
+  GtkRecentManager *recent_manager = GTK_RECENT_MANAGER (object);
+ 
+  switch (prop_id)
+    {
+    case PROP_LIMIT:
+      gtk_recent_manager_set_limit (recent_manager, g_value_get_int (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_recent_manager_get_property (GObject               *object,
+				 guint                  prop_id,
+				 GValue                *value,
+				 GParamSpec            *pspec)
+{
+  GtkRecentManager *recent_manager = GTK_RECENT_MANAGER (object);
+  
+  switch (prop_id)
+    {
+    case PROP_LIMIT:
+      g_value_set_int (value, recent_manager->priv->limit);
+      break;
+    case PROP_SIZE:
+      g_value_set_int (value, recent_manager->priv->size);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+} 
+
+static void
+gtk_recent_manager_finalize (GObject *object)
+{
+  GtkRecentManager *manager = GTK_RECENT_MANAGER (object);
+  GtkRecentManagerPrivate *priv = manager->priv;
+
+  /* remove the poll timeout */
+  if (priv->poll_timeout)
+    g_source_remove (priv->poll_timeout);
+  
+  if (priv->filename)
+    g_free (priv->filename);
+  
+  if (priv->recent_items)
+    g_bookmark_file_free (priv->recent_items);
+  
+  /* chain up parent's finalize method */  
+  G_OBJECT_CLASS (gtk_recent_manager_parent_class)->finalize (object);
+}
+
+static void
+gtk_recent_manager_real_changed (GtkRecentManager *manager)
+{
+  GtkRecentManagerPrivate *priv = manager->priv;
+
+  g_object_freeze_notify (G_OBJECT (manager));
+
+  if (priv->is_dirty)
+    {
+      GError *write_error;
+      struct stat stat_buf;
+      
+      /* we are marked as dirty, so we dump the content of our
+       * recently used items list
+       */
+      g_assert (priv->filename != NULL);
+
+      priv->write_in_progress = TRUE;
+
+      /* if no container object has been defined, we create a new
+       * empty container, and dump it
+       */
+      if (!priv->recent_items)
+        {
+          priv->recent_items = g_bookmark_file_new ();
+	  priv->size = 0;
+	}
+
+      write_error = NULL;
+      g_bookmark_file_to_file (priv->recent_items,
+		               priv->filename,
+			       &write_error);
+      if (write_error)
+        {
+          g_warning ("Attempting to store changes into `%s', "
+		     "but failed: %s",
+		     priv->filename,
+		     write_error->message);
+	  g_error_free (write_error);
+	}
+
+      /* we have sync'ed our list with the storage file, so we
+       * update the file mtime in order to skip the timed check
+       * and spare us from a re-read.
+       */
+      if (g_stat (priv->filename, &stat_buf) < 0)
+	{
+          g_warning ("Unable to stat() the recently used resources file "
+		     "at `%s': %s.",
+		     priv->filename,
+		     g_strerror (errno));
+
+	  priv->write_in_progress = FALSE;
+	  
+	  g_object_thaw_notify (G_OBJECT (manager));
+
+	  return;
+	}
+      
+      priv->last_mtime = stat_buf.st_mtime;
+      
+      /* mark us as clean */
+      priv->is_dirty = FALSE;
+    }
+  else
+    {
+      /* we are not marked as dirty, so we have been called
+       * because the recently used resources file has been
+       * changed (and not from us).
+       */
+      build_recent_items_list (manager);
+    }
+
+  g_object_thaw_notify (G_OBJECT (manager));
+}
+
+/* timed poll()-ing of the recently used resources file.
+ * an event-based system would be more efficient.
+ */
+static gboolean
+gtk_recent_manager_poll_timeout (gpointer data)
+{
+  GtkRecentManager *manager = GTK_RECENT_MANAGER (data);
+  GtkRecentManagerPrivate *priv = manager->priv;
+  struct stat stat_buf;
+  int stat_res;
+
+  /* wait for the next timeout if we have a read/write in progress */
+  if (priv->write_in_progress || priv->read_in_progress)
+    return TRUE;
+
+  stat_res = g_stat (priv->filename, &stat_buf);
+  if (stat_res < 0)
+    {
+      /* the file does not exist, yet, so we wait */
+      if (errno == ENOENT)
+        return TRUE;
+      
+      g_warning ("Unable to stat() the recently used resources file "
+		 "at `%s': %s.",
+		 priv->filename,
+		 g_strerror (errno));
+      
+      return TRUE;
+    }
+
+  /* the file didn't change from the last poll(), so we bail out */
+  if (stat_buf.st_mtime == priv->last_mtime)
+    return TRUE;
+
+  /* the file has been changed, hence we emit the "changed" signal */
+  gtk_recent_manager_changed (manager);
+
+  return TRUE;
+}
+
+/* reads the recently used resources file and builds the items list.
+ * we keep the items list inside the parser object, and build the
+ * RecentInfo object only on user's demand to avoid useless replication.
+ */
+static void
+build_recent_items_list (GtkRecentManager *manager)
+{
+  GtkRecentManagerPrivate *priv;
+  struct stat stat_buf;
+  int stat_res;
+  gboolean res;
+  GError *read_error;
+  gint size;
+
+  priv = manager->priv;
+  g_assert (priv->filename != NULL);
+  
+  if (!priv->recent_items)
+    {
+      priv->recent_items = g_bookmark_file_new ();
+      priv->size = 0;
+    }
+
+  stat_res = g_stat (priv->filename, &stat_buf);
+  if (stat_res < 0)
+    {
+      /* the file doesn't exists, so we bail out and wait for the first
+       * write operation
+       */
+
+      if (errno == ENOENT)
+        return;
+      else
+        {
+          g_warning ("Attempting to read the recently used resources file "
+                     "at `%s', but an error occurred: %s. Aborting.",
+                     priv->filename,
+                     g_strerror (errno));
+
+          return;
+        }
+    }
+
+  /* record the last mtime, for later use */
+  priv->last_mtime = stat_buf.st_mtime;
+  
+  priv->read_in_progress = TRUE;
+
+  /* the file exists, and it's valid (we hope); if not, destroy the container
+   * object and hope for a better result when the next "changed" signal is
+   * fired. */
+  read_error = NULL;
+  res = g_bookmark_file_load_from_file (priv->recent_items,
+		  			priv->filename,
+					&read_error);
+  if (read_error)
+    {
+      g_warning ("Attempting to read the recently used resources file "
+		 "at `%s', but the parser failed: %s.",
+		 priv->filename,
+		 read_error->message);
+
+      g_bookmark_file_free (priv->recent_items);
+      priv->recent_items = NULL;
+
+      g_error_free (read_error);
+    }
+
+  size = g_bookmark_file_get_size (priv->recent_items);
+  if (priv->size != size)
+    {
+      priv->size = size;
+      
+      g_object_notify (G_OBJECT (manager), "size");
+    }
+
+  priv->read_in_progress = FALSE;
+}
+
+
+/********************
+ * GtkRecentManager *
+ ********************/
+
+
+/**
+ * gtk_recent_manager_new:
+ * 
+ * Creates a new recent manager object.  Recent manager objects are used to
+ * handle the list of recently used resources.  A #GtkRecentManager object
+ * monitors the recently used resources list, and emits the "changed" signal
+ * each time something inside the list changes.
+ *
+ * #GtkRecentManager objects are expansive: be sure to create them only when
+ * needed.
+ *
+ * Return value: the newly created #GtkRecentManager object.
+ *
+ * Since: 2.10
+ */
+GtkRecentManager *
+gtk_recent_manager_new (void)
+{
+  return g_object_new (GTK_TYPE_RECENT_MANAGER, NULL);
+}
+
+/**
+ * gtk_recent_manager_set_limit:
+ * @recent_manager: a #GtkRecentManager
+ * @limit: the maximum number of items to return, or -1.
+ *
+ * Sets the maximum number of item that the gtk_recent_manager_get_items()
+ * function should return.  If @limit is set to -1, then return all the
+ * items.
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_manager_set_limit (GtkRecentManager *recent_manager,
+			      gint              limit)
+{
+  GtkRecentManagerPrivate *priv;
+  
+  g_return_if_fail (GTK_IS_RECENT_MANAGER (recent_manager));
+  
+  priv = recent_manager->priv;
+  priv->limit = limit;
+}
+
+/**
+ * gtk_recent_manager_get_limit:
+ * @recent_manager: a #GtkRecentManager
+ *
+ * Gets the maximum number of items that the gtk_recent_manager_get_items()
+ * function should return.
+ *
+ * Return value: the number of items to return, or -1 for every item.
+ *
+ * Since: 2.10
+ */
+gint
+gtk_recent_manager_get_limit (GtkRecentManager *recent_manager)
+{
+  GtkRecentManagerPrivate *priv;
+  
+  g_return_val_if_fail (GTK_IS_RECENT_MANAGER (recent_manager), DEFAULT_LIMIT);
+  
+  priv = recent_manager->priv;
+  return priv->limit;
+}
+
+/**
+ * gtk_recent_manager_add_item:
+ * @recent_manager: a #GtkRecentManager
+ * @uri: a valid URI
+ * @error: return location for a #GError, or %NULL
+ *
+ * Adds a new resource, pointed by @uri, into the recently used resources list.
+ *
+ * This function automatically retrieving some of the needed metadata and
+ * setting other metadata to common default values; it then feeds the data to
+ * gtk_recent_manager_add_full().
+ *
+ * See gtk_recent_manager_add_full() if you want to explicitely define the
+ * metadata for the resource pointed by @uri.
+ *
+ * Return value: %TRUE if the new item was successfully added to the
+ * recently used resources list, %FALSE otherwise.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_recent_manager_add_item (GtkRecentManager  *recent_manager,
+			     const gchar       *uri,
+			     GError           **error)
+{
+  GtkRecentData *recent_data;
+  GError *add_error;
+  gboolean retval;
+  
+  g_return_val_if_fail (GTK_IS_RECENT_MANAGER (recent_manager), FALSE);
+  g_return_val_if_fail (uri != NULL, FALSE);
+
+  recent_data = g_slice_new (GtkRecentData);
+  
+  recent_data->display_name = NULL;
+  recent_data->description = NULL;
+  
+#ifdef G_OS_UNIX
+  if (g_str_has_prefix (uri, "file://"))
+    {
+      gchar *filename;
+      const gchar *mime_type;
+      
+      filename = g_filename_from_uri (uri, NULL, NULL);
+      mime_type = xdg_mime_get_mime_type_for_file (filename, NULL);
+      if (!mime_type)
+        recent_data->mime_type = g_strdup (GTK_RECENT_DEFAULT_MIME);
+      else
+        recent_data->mime_type = g_strdup (mime_type);
+      
+      g_free (filename);
+    }
+  else
+#endif
+    recent_data->mime_type = g_strdup (GTK_RECENT_DEFAULT_MIME);
+  
+  recent_data->app_name = g_strdup (g_get_application_name ());
+  recent_data->app_exec = g_strjoin (" ", g_get_prgname (), "%u", NULL);
+  
+  recent_data->groups = NULL;
+  
+  recent_data->is_private = FALSE;
+  
+  add_error = NULL;
+  retval = gtk_recent_manager_add_full (recent_manager, uri, recent_data, &add_error);
+  
+  g_free (recent_data->mime_type);
+  g_free (recent_data->app_name);
+  g_free (recent_data->app_exec);
+
+  g_slice_free (GtkRecentData, recent_data);
+  
+  if (!retval)
+    {
+      g_propagate_error (error, add_error);
+      
+      return FALSE;
+    }
+  
+  return retval;
+}
+
+/**
+ * gtk_recent_manager_add_full:
+ * @recent_manager: a #GtkRecentManager
+ * @uri: a valid URI
+ * @recent_data: metadata of the resource
+ * @error: return location for a #GError, or %NULL
+ *
+ * Adds a new resource, pointed by @uri, into the recently used
+ * resources list, using the metadata specified inside the #GtkRecentData
+ * structure passed in @recent_data.
+ *
+ * The passed URI will be used to identify this resource inside the
+ * list.
+ *
+ * In order to register the new recently used resource, metadata about
+ * the resource must be passed as well as the URI; the metadata is
+ * stored in a #GtkRecentData structure, which must contain the MIME
+ * type of the resource pointed by the URI; the name of the application
+ * that is registering the item, and a command line to be used when
+ * launching the item.
+ *
+ * Optionally, a #GtkRecentData structure might contain a UTF-8 string
+ * to be used when viewing the item instead of the last component of the
+ * URI; a short description of the item; whether the item should be
+ * considered private - that is, should be displayed only by the
+ * applications that have registered it.
+ *
+ * Return value: %TRUE if the new item was successfully added to the
+ * recently used resources list, %FALSE otherwise.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_recent_manager_add_full (GtkRecentManager     *recent_manager,
+			     const gchar          *uri,
+			     const GtkRecentData  *data,
+			     GError              **error)
+{
+  GtkRecentManagerPrivate *priv;
+  
+  g_return_val_if_fail (GTK_IS_RECENT_MANAGER (recent_manager), FALSE);
+  g_return_val_if_fail (uri != NULL, FALSE);
+  g_return_val_if_fail (data != NULL, FALSE);
+
+  /* sanity checks */
+  if ((data->display_name) &&
+      (!g_utf8_validate (data->display_name, -1, NULL)))
+    {
+      g_set_error  (error, GTK_RECENT_MANAGER_ERROR,
+          	    GTK_RECENT_MANAGER_ERROR_INVALID_ENCODING,
+          	    _("The display name of the recently used resource "
+          	      "must be a valid UTF-8 encoded string."));
+      return FALSE;
+    }
+  
+  if ((data->description) &&
+      (!g_utf8_validate (data->description, -1, NULL)))
+    {
+      g_set_error (error, GTK_RECENT_MANAGER_ERROR,
+          	   GTK_RECENT_MANAGER_ERROR_INVALID_ENCODING,
+          	   _("The description of the recently used resource "
+          	     "must by a valid UTF-8 encoded string."));
+      return FALSE;
+    }
+
+ 
+  if (!data->mime_type)
+    {
+      g_set_error (error, GTK_RECENT_MANAGER_ERROR,
+                   GTK_RECENT_MANAGER_ERROR_INVALID_MIME,
+		   _("You must specify the MIME type of the "
+		     "resource pointed by `%s'"),
+		   uri);
+      return FALSE;
+    }
+  
+  if (!data->app_name)
+    {
+      g_set_error (error, GTK_RECENT_MANAGER_ERROR,
+      		   GTK_RECENT_MANAGER_ERROR_NOT_REGISTERED,
+      		   _("You must specify the name of the application "
+      		     "that is registering the recently used resource "
+      		     "pointed by `%s'"),
+      		   uri);
+      return FALSE;
+    }
+  
+  if (!data->app_exec)
+    {
+      g_set_error (error, GTK_RECENT_MANAGER_ERROR,
+                   GTK_RECENT_MANAGER_ERROR_BAD_EXEC_STRING,
+		   _("You must specify a command line to "
+		     "be used when launching the resource "
+		     "pointed by `%s'"),
+		   uri);
+      return FALSE;
+    }
+  
+  priv = recent_manager->priv;
+
+  if (!priv->recent_items)
+    {
+      priv->recent_items = g_bookmark_file_new ();
+      priv->size = 0;
+    }
+
+  if (data->display_name)  
+    g_bookmark_file_set_title (priv->recent_items, uri,
+    			       data->display_name);
+  
+  if (data->description)
+    g_bookmark_file_set_description (priv->recent_items, uri,
+    				     data->description);
+
+  g_bookmark_file_set_mime_type (priv->recent_items, uri,
+		  		 data->mime_type);
+  
+  if (data->groups && data->groups[0] != '\0')
+    {
+      gint j;
+      
+      for (j = 0; (data->groups)[j] != NULL; j++)
+        g_bookmark_file_add_group (priv->recent_items, uri, (data->groups)[j]);
+    }
+  
+  /* register the application; this will take care of updating the
+   * registration count and time in case the application has
+   * already registered the same document inside the list
+   */
+  g_bookmark_file_add_application (priv->recent_items, uri,
+		  		   data->app_name,
+				   data->app_exec);
+  
+  g_bookmark_file_set_is_private (priv->recent_items, uri,
+		  		  data->is_private);
+  
+  /* mark us as dirty, so that when emitting the "changed" signal we
+   * will dump our changes
+   */
+  priv->is_dirty = TRUE;
+  
+  gtk_recent_manager_changed (recent_manager);
+  
+  return TRUE;
+}
+
+/**
+ * gtk_recent_manager_remove_item:
+ * @recent_manager: a #GtkRecentManager
+ * @uri: the URI of the item you wish to remove
+ * @error: return location for a #GError, or %NULL
+ *
+ * Removes a resource pointed by @uri from the recently used resources
+ * list handled by a recent manager.
+ *
+ * Return value: %TRUE if the item pointed by @uri has been successfully
+ *   removed by the recently used resources list, and %FALSE otherwise.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_recent_manager_remove_item (GtkRecentManager  *recent_manager,
+				const gchar       *uri,
+				GError           **error)
+{
+  GtkRecentManagerPrivate *priv;
+  GError *remove_error = NULL;
+
+  g_return_val_if_fail (GTK_IS_RECENT_MANAGER (recent_manager), FALSE);
+  g_return_val_if_fail (uri != NULL, FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+  
+  priv = recent_manager->priv;
+  
+  if (!priv->recent_items)
+    {
+      priv->recent_items = g_bookmark_file_new ();
+      priv->size = 0;
+
+      g_set_error (error, GTK_RECENT_MANAGER_ERROR,
+		   GTK_RECENT_MANAGER_ERROR_NOT_FOUND,
+		   _("Unable to find an item with URI '%s'"),
+		   uri);
+
+      return FALSE;
+    }
+
+  g_bookmark_file_remove_item (priv->recent_items, uri, &remove_error);
+  if (remove_error)
+    {
+      g_propagate_error (error, remove_error);
+      
+      return FALSE;
+    }
+
+  priv->is_dirty = TRUE;
+
+  gtk_recent_manager_changed (recent_manager);
+  
+  return TRUE;
+}
+
+/**
+ * gtk_recent_manager_has_item:
+ * @recent_manager: a #GtkRecentManager
+ * @uri: a URI
+ *
+ * Checks whether there is a recently used resource registered
+ * with @uri inside the recent manager.
+ *
+ * Return value: %TRUE if the resource was found, %FALSE otherwise.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_recent_manager_has_item (GtkRecentManager *recent_manager,
+			     const gchar      *uri)
+{
+  GtkRecentManagerPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_RECENT_MANAGER (recent_manager), FALSE);
+  g_return_val_if_fail (uri != NULL, FALSE);
+
+  priv = recent_manager->priv;
+  g_return_val_if_fail (priv->recent_items != NULL, FALSE);
+
+  return g_bookmark_file_has_item (priv->recent_items, uri);
+}
+
+static gboolean
+build_recent_info (GBookmarkFile  *bookmarks,
+		   GtkRecentInfo  *info)
+{
+  gchar **apps, **groups;
+  gsize apps_len, groups_len, i;
+
+  g_assert (bookmarks != NULL);
+  g_assert (info != NULL);
+  
+  info->display_name = g_bookmark_file_get_title (bookmarks, info->uri, NULL);
+  info->description = g_bookmark_file_get_description (bookmarks, info->uri, NULL);
+  info->mime_type = g_bookmark_file_get_mime_type (bookmarks, info->uri, NULL);
+    
+  info->is_private = g_bookmark_file_get_is_private (bookmarks, info->uri, NULL);
+  
+  info->added = g_bookmark_file_get_added (bookmarks, info->uri, NULL);
+  info->modified = g_bookmark_file_get_modified (bookmarks, info->uri, NULL);
+  info->visited = g_bookmark_file_get_visited (bookmarks, info->uri, NULL);
+  
+  groups = g_bookmark_file_get_groups (bookmarks, info->uri, &groups_len, NULL);
+  for (i = 0; i < groups_len; i++)
+    {
+      gchar *group_name = g_strdup (groups[i]);
+      
+      info->groups = g_slist_append (info->groups, group_name);
+    }
+
+  g_strfreev (groups);
+  
+  apps = g_bookmark_file_get_applications (bookmarks, info->uri, &apps_len, NULL);
+  for (i = 0; i < apps_len; i++)
+    {
+      gchar *app_name, *app_exec;
+      guint count;
+      time_t stamp;
+      RecentAppInfo *app_info;
+      gboolean res;
+      
+      app_name = apps[i];
+      
+      res = g_bookmark_file_get_app_info (bookmarks, info->uri, app_name,
+      					  &app_exec,
+      					  &count,
+      					  &stamp,
+      					  NULL);
+      if (!res)
+        continue;
+      
+      app_info = recent_app_info_new (app_name);
+      app_info->exec = app_exec;
+      app_info->count = count;
+      app_info->stamp = stamp;
+      
+      info->applications = g_slist_append (info->applications,
+      					   app_info);
+      g_hash_table_replace (info->apps_lookup, app_info->name, app_info);
+    }
+  
+  g_strfreev (apps);
+  
+  return TRUE; 
+}
+
+/**
+ * gtk_recent_manager_lookup_item:
+ * @recent_manager: a #GtkRecentManager
+ * @uri: a URI
+ * @error: a return location for a #GError, or %NULL
+ *
+ * Searches for a URI inside the recently used resources list, and
+ * returns a structure containing informations about the resource
+ * like its MIME type, or its display name.
+ *
+ * Return value: a #GtkRecentInfo structure containing information
+ *   about the resource pointed by @uri, or %NULL if the URI was
+ *   not registered in the recently used resources list.  Free with
+ *   gtk_recent_info_unref().
+ **/
+GtkRecentInfo *
+gtk_recent_manager_lookup_item (GtkRecentManager  *recent_manager,
+				const gchar       *uri,
+				GError           **error)
+{
+  GtkRecentManagerPrivate *priv;
+  GtkRecentInfo *info = NULL;
+  gboolean res;
+  
+  g_return_val_if_fail (GTK_IS_RECENT_MANAGER (recent_manager), NULL);
+  g_return_val_if_fail (uri != NULL, NULL);
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+  
+  priv = recent_manager->priv;
+  if (!priv->recent_items)
+    {
+      priv->recent_items = g_bookmark_file_new ();
+      priv->size = 0;
+
+      g_set_error (error, GTK_RECENT_MANAGER_ERROR,
+		   GTK_RECENT_MANAGER_ERROR_NOT_FOUND,
+		   _("Unable to find an item with URI '%s'"),
+		   uri);
+
+      return NULL;
+    }
+  
+  if (!g_bookmark_file_has_item (priv->recent_items, uri))
+    {
+      g_set_error (error, GTK_RECENT_MANAGER_ERROR,
+      		   GTK_RECENT_MANAGER_ERROR_NOT_FOUND,
+      		   _("Unable to find an item with URI '%s'"),
+      		   uri);
+      return NULL;
+    }
+  
+  info = gtk_recent_info_new (uri);
+  g_return_val_if_fail (info != NULL, NULL);
+  
+  /* fill the RecentInfo structure with the data retrieved by our
+   * parser object from the storage file 
+   */
+  res = build_recent_info (priv->recent_items, info);
+  if (!res)
+    {
+      gtk_recent_info_free (info);
+      
+      return NULL;
+    }
+ 
+  return gtk_recent_info_ref (info);
+}
+
+/**
+ * gtk_recent_manager_move_item:
+ * @manager: a #GtkRecentManager
+ * @uri: the URI of a recently used resource
+ * @new_uri: the new URI of the recently used resource, or %NULL to
+ *    remove the item pointed by @uri in the list
+ * @error: a return location for a #GError, or %NULL
+ *
+ * Changes the location of a recently used resource from @uri to @new_uri.
+ * 
+ * Please note that this function will not affect the resource pointed
+ * by the URIs, but only the URI used in the recently used resources list.
+ *
+ * Return value: %TRUE on success.
+ *
+ * Since: 2.10
+ */ 
+gboolean
+gtk_recent_manager_move_item (GtkRecentManager  *recent_manager,
+			      const gchar       *uri,
+			      const gchar       *new_uri,
+			      GError           **error)
+{
+  GtkRecentManagerPrivate *priv;
+  GError *move_error;
+  gboolean res;
+  
+  g_return_val_if_fail (GTK_IS_RECENT_MANAGER (recent_manager), FALSE);
+  g_return_val_if_fail (uri != NULL, FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+  
+  priv = recent_manager->priv;
+
+  if (!g_bookmark_file_has_item (priv->recent_items, uri))
+    {
+      g_set_error (error, GTK_RECENT_MANAGER_ERROR,
+      		   GTK_RECENT_MANAGER_ERROR_NOT_FOUND,
+      		   _("Unable to find an item with URI '%s'"),
+      		   uri);
+      return FALSE;
+    }
+  
+  move_error = NULL;
+  res = g_bookmark_file_move_item (priv->recent_items,
+                                   uri, new_uri,
+                                   &move_error);
+  if (move_error)
+    {
+      g_propagate_error (error, move_error);
+      return FALSE;
+    }
+  
+  priv->is_dirty = TRUE;
+
+  gtk_recent_manager_changed (recent_manager);
+  
+  return TRUE;
+}
+
+/**
+ * gtk_recent_manager_get_items:
+ * @recent_manager: a #GtkRecentManager
+ *
+ * Gets the list of recently used resources.
+ *
+ * Return value: a list of newly allocated #GtkRecentInfo objects. Use
+ *   gtk_recent_info_unref() on each item inside the list, and then
+ *   free the list itself using g_list_free().
+ *
+ * Since: 2.10
+ */
+GList *
+gtk_recent_manager_get_items (GtkRecentManager *recent_manager)
+{
+  GtkRecentManagerPrivate *priv;
+  GList *retval = NULL;
+  gchar **uris;
+  gsize uris_len, i;
+  
+  g_return_val_if_fail (GTK_IS_RECENT_MANAGER (recent_manager), NULL);
+  
+  priv = recent_manager->priv;
+  if (!priv->recent_items)
+    return NULL;
+  
+  uris = g_bookmark_file_get_uris (priv->recent_items, &uris_len);
+  for (i = 0; i < uris_len; i++)
+    {
+      GtkRecentInfo *info;
+      gboolean res;
+      
+      info = gtk_recent_info_new (uris[i]);
+      res = build_recent_info (priv->recent_items, info);
+      if (!res)
+        {
+          g_warning ("Unable to create a RecentInfo object for "
+                     "item with URI `%s'",
+                     uris[i]);
+          gtk_recent_info_free (info);
+          continue;
+        }
+      
+      retval = g_list_prepend (retval, info);
+    }
+  
+  g_strfreev (uris);
+    
+  /* clamp the list, if a limit is present */
+  if ((priv->limit != -1) &&
+      (g_list_length (retval) > priv->limit))
+    {
+      GList *clamp, *l;
+      
+      clamp = g_list_nth (retval, priv->limit - 1);
+      
+      if (!clamp)
+        return retval;
+      
+      l = clamp->next;
+      clamp->next = NULL;
+      
+      g_list_foreach (l, (GFunc) gtk_recent_info_free, NULL);
+      g_list_free (l);
+    }
+  
+  return retval;
+}
+
+static void
+purge_recent_items_list (GtkRecentManager  *manager,
+			 GError           **error)
+{
+  GtkRecentManagerPrivate *priv = manager->priv;
+
+  if (!priv->recent_items)
+    return;
+  
+  g_bookmark_file_free (priv->recent_items);
+  priv->recent_items = NULL;
+      
+  priv->recent_items = g_bookmark_file_new ();
+  priv->size = 0;
+  priv->is_dirty = TRUE;
+      
+  /* emit the changed signal, to ensure that the purge is written */
+  gtk_recent_manager_changed (manager);
+}
+
+/**
+ * gtk_recent_manager_purge_items:
+ * @recent_manager: a #GtkRecentManager
+ * @error: a return location for a #GError, or %NULL
+ *
+ * Purges every item from the recently used resources list.
+ *
+ * Return value: the number of items that have been removed from the
+ *   recently used resources list.
+ *
+ * Since: 2.10
+ */
+gint
+gtk_recent_manager_purge_items (GtkRecentManager  *recent_manager,
+				GError           **error)
+{
+  GtkRecentManagerPrivate *priv;
+  gint count, purged;
+  
+  g_return_val_if_fail (GTK_IS_RECENT_MANAGER (recent_manager), -1);
+
+  priv = recent_manager->priv;
+  if (!priv->recent_items)
+    return 0;
+  
+  count = g_bookmark_file_get_size (priv->recent_items);
+  if (!count)
+    return 0;
+  
+  purge_recent_items_list (recent_manager, error);
+  
+  purged = count - g_bookmark_file_get_size (priv->recent_items);
+
+  return purged;
+}
+
+static void
+gtk_recent_manager_changed (GtkRecentManager *recent_manager)
+{
+  g_signal_emit (recent_manager, signal_changed, 0);
+}
+
+/*****************
+ * GtkRecentInfo *
+ *****************/
+ 
+GType
+gtk_recent_info_get_type (void)
+{
+  static GType info_type = 0;
+  
+  if (!info_type)
+    info_type = g_boxed_type_register_static ("GtkRecentInfo",
+    					      (GBoxedCopyFunc) gtk_recent_info_ref,
+    					      (GBoxedFreeFunc) gtk_recent_info_unref);
+  return info_type;
+}
+
+static GtkRecentInfo *
+gtk_recent_info_new (const gchar *uri)
+{
+  GtkRecentInfo *info;
+
+  g_assert (uri != NULL);
+
+  info = g_new0 (GtkRecentInfo, 1);
+  info->uri = g_strdup (uri);
+  
+  info->applications = NULL;
+  info->apps_lookup = g_hash_table_new (g_str_hash, g_str_equal);
+  
+  info->groups = NULL;
+  
+  info->ref_count = 1;
+
+  return info;
+}
+
+static void
+gtk_recent_info_free (GtkRecentInfo *recent_info)
+{
+  if (!recent_info)
+    return;
+
+  g_free (recent_info->uri);
+  g_free (recent_info->display_name);
+  g_free (recent_info->description);
+  g_free (recent_info->mime_type);
+  
+  if (recent_info->applications)
+    {
+      g_slist_foreach (recent_info->applications,
+      		       (GFunc) recent_app_info_free,
+      		       NULL);
+      g_slist_free (recent_info->applications);
+      
+      recent_info->applications = NULL;
+    }
+  
+  if (recent_info->apps_lookup)
+    g_hash_table_destroy (recent_info->apps_lookup);
+
+  if (recent_info->groups)
+    {
+      g_slist_foreach (recent_info->groups,
+		       (GFunc) g_free,
+		       NULL);
+      g_slist_free (recent_info->groups);
+
+      recent_info->groups = NULL;
+    }
+  
+  if (recent_info->icon)
+    g_object_unref (recent_info->icon);
+
+  g_free (recent_info);
+}
+
+/**
+ * gtk_recent_info_ref:
+ * @info: a #GtkRecentInfo
+ *
+ * Increases the reference count of @recent_info by one.
+ *
+ * Return value: the recent info object with its reference count increased
+ *   by one.
+ *
+ * Since: 2.10
+ */
+GtkRecentInfo *
+gtk_recent_info_ref (GtkRecentInfo *info)
+{
+  g_return_val_if_fail (info != NULL, NULL);
+  g_return_val_if_fail (info->ref_count > 0, NULL);
+  
+  info->ref_count += 1;
+    
+  return info;
+}
+
+/**
+ * gtk_recent_info_unref:
+ * @info: a #GtkRecentInfo
+ *
+ * Decreases the reference count of @info by one.  If the reference
+ * count reaches zero, @info is deallocated, and the memory freed.
+ *
+ * Since: 2.10
+ */
+void
+gtk_recent_info_unref (GtkRecentInfo *info)
+{
+  g_return_if_fail (info != NULL);
+  g_return_if_fail (info->ref_count > 0);
+
+  info->ref_count -= 1;
+  
+  if (info->ref_count == 0)
+    gtk_recent_info_free (info);
+}
+
+/**
+ * gtk_recent_info_get_uri:
+ * @info: a #GtkRecentInfo
+ *
+ * Gets the URI of the resource.
+ *
+ * Return value: the URI of the resource.  The returned string is
+ *   owned by the recent manager, and should not be freed.
+ *
+ * Since: 2.10
+ */
+G_CONST_RETURN gchar *
+gtk_recent_info_get_uri (GtkRecentInfo *info)
+{
+  g_return_val_if_fail (info != NULL, NULL);
+  
+  return info->uri;
+}
+
+/**
+ * gtk_recent_info_get_display_name:
+ * @info: a #GtkRecentInfo
+ *
+ * Gets the name of the resource.  If none has been defined, the basename
+ * of the resource is obtained.
+ *
+ * Return value: the display name of the resource.  The returned string
+ *   is owned by the recent manager, and should not be freed.
+ *
+ * Since: 2.10
+ */
+G_CONST_RETURN gchar *
+gtk_recent_info_get_display_name (GtkRecentInfo *info)
+{
+  g_return_val_if_fail (info != NULL, NULL);
+  
+  if (!info->display_name)
+    info->display_name = gtk_recent_info_get_short_name (info);
+  
+  return info->display_name;
+}
+
+/**
+ * gtk_recent_info_get_description:
+ * @info: a #GtkRecentInfo
+ *
+ * Gets the (short) description of the resource.
+ *
+ * Return value: the description of the resource.  The returned string
+ *   is owned by the recent manager, and should not be freed.
+ *
+ * Since: 2.10
+ **/
+G_CONST_RETURN gchar *
+gtk_recent_info_get_description (GtkRecentInfo *info)
+{
+  g_return_val_if_fail (info != NULL, NULL);
+  
+  return info->description;
+}
+
+/**
+ * gtk_recent_info_get_mime_type:
+ * @info: a #GtkRecentInfo
+ *
+ * Gets the MIME type of the resource.
+ *
+ * Return value: the MIME type of the resource.  The returned string
+ *   is owned by the recent manager, and should not be freed.
+ *
+ * Since: 2.10
+ */
+G_CONST_RETURN gchar *
+gtk_recent_info_get_mime_type (GtkRecentInfo *info)
+{
+  g_return_val_if_fail (info != NULL, NULL);
+  
+  if (!info->mime_type)
+    info->mime_type = g_strdup (GTK_RECENT_DEFAULT_MIME);
+  
+  return info->mime_type;
+}
+
+/**
+ * gtk_recent_info_get_added:
+ * @info: a #GtkRecentInfo
+ *
+ * Gets the timestamp (seconds from system's Epoch) when the resource
+ * was added to the recently used resources list.
+ *
+ * Return value: the number of seconds elapsed from system's Epoch when
+ *   the resource was added to the list, or -1 on failure.
+ *
+ * Since: 2.10
+ */
+time_t
+gtk_recent_info_get_added (GtkRecentInfo *info)
+{
+  g_return_val_if_fail (info != NULL, (time_t) -1);
+  
+  return info->added;
+}
+
+/**
+ * gtk_recent_info_get_modified:
+ * @info: a #GtkRecentInfo
+ *
+ * Gets the timestamp (seconds from system's Epoch) when the resource
+ * was last modified.
+ *
+ * Return value: the number of seconds elapsed from system's Epoch when
+ *   the resource was last modified, or -1 on failure.
+ *
+ * Since: 2.10
+ */
+time_t
+gtk_recent_info_get_modified (GtkRecentInfo *info)
+{
+  g_return_val_if_fail (info != NULL, (time_t) -1);
+  
+  return info->modified;
+}
+
+/**
+ * gtk_recent_info_get_visited:
+ * @info: a #GtkRecentInfo
+ *
+ * Gets the timestamp (seconds from system's Epoch) when the resource
+ * was last visited.
+ *
+ * Return value: the number of seconds elapsed from system's Epoch when
+ *   the resource was last visited, or -1 on failure.
+ *
+ * Since: 2.10
+ */
+time_t
+gtk_recent_info_get_visited (GtkRecentInfo *info)
+{
+  g_return_val_if_fail (info != NULL, (time_t) -1);
+  
+  return info->visited;
+}
+
+/**
+ * gtk_recent_info_get_private_hint:
+ * @info: a #GtkRecentInfo
+ *
+ * Gets the value of the "private" flag.  Resources in the recently used
+ * list that have this flag set to %TRUE should only be displayed by the
+ * applications that have registered them.
+ *
+ * Return value: %TRUE if the private flag was found, %FALSE otherwise.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_recent_info_get_private_hint (GtkRecentInfo *info)
+{
+  g_return_val_if_fail (info != NULL, FALSE);
+  
+  return info->is_private;
+}
+
+
+static RecentAppInfo *
+recent_app_info_new (const gchar *app_name)
+{
+  RecentAppInfo *app_info;
+
+  g_assert (app_name != NULL);
+  
+  app_info = g_new0 (RecentAppInfo, 1);
+  app_info->name = g_strdup (app_name);
+  app_info->exec = NULL;
+  app_info->count = 1;
+  app_info->stamp = time (NULL);
+  
+  return app_info;
+}
+
+static void
+recent_app_info_free (RecentAppInfo *app_info)
+{
+  if (!app_info)
+    return;
+  
+  if (app_info->name)
+    g_free (app_info->name);
+  
+  if (app_info->exec)
+    g_free (app_info->exec);
+  
+  g_free (app_info);
+}
+
+/**
+ * gtk_recent_info_get_application_info:
+ * @info: a #GtkRecentInfo
+ * @app_name: the name of the application that has registered this item
+ * @app_exec: return location for the string containing the command line
+ * @count: return location for the number of times this item was registered
+ * @time: return location for the timestamp this item was last registered
+ *    for this application
+ *
+ * Gets the data regarding the application that has registered the resource
+ * pointed by @info.
+ *
+ * If the command line contains any escape characters defined inside the
+ * storage specification, they will be expanded.
+ *
+ * Return value: %TRUE if an application with @app_name has registered this
+ *   resource inside the recently used list, or %FALSE otherwise.  You should
+ *   free the returned command line using g_free().
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_recent_info_get_application_info (GtkRecentInfo  *info,
+				      const gchar    *app_name,
+				      gchar         **app_exec,
+				      guint          *count,
+				      time_t         *time)
+{
+  RecentAppInfo *ai;
+  
+  g_return_val_if_fail (info != NULL, FALSE);
+  g_return_val_if_fail (app_name != NULL, FALSE);
+  
+  ai = (RecentAppInfo *) g_hash_table_lookup (info->apps_lookup,
+  					      app_name);
+  if (!ai)
+    {
+      g_warning ("No registered application with name '%s' "
+                 "for item with URI '%s' found",
+                 app_name,
+                 info->uri);
+      return FALSE;
+    }
+  
+  if (app_exec)
+    *app_exec = ai->exec;
+  
+  if (count)
+    *count = ai->count;
+  
+  if (time)
+    *time = ai->stamp;
+
+  return TRUE;
+}
+
+/**
+ * gtk_recent_info_get_applications:
+ * @info: a #GtkRecentInfo
+ * @length: return location for the length of the returned list, or %NULL
+ *
+ * Retrieves the list of applications that have registered this resource.
+ *
+ * Return value: a newly allocated %NULL-terminated array of strings.
+ *   Use g_strfreev() to free it.
+ *
+ * Since: 2.10
+ */ 			      
+gchar **
+gtk_recent_info_get_applications (GtkRecentInfo *info,
+				  gsize         *length)
+{
+  GSList *l;
+  gchar **retval;
+  gsize n_apps, i;
+  
+  g_return_val_if_fail (info != NULL, NULL);
+  
+  if (!info->applications)
+    {
+      if (length)
+        *length = 0;
+      
+      return NULL;    
+    }
+  
+  n_apps = g_slist_length (info->applications);
+  
+  retval = g_new0 (gchar *, n_apps + 1);
+  
+  for (l = info->applications, i = 0;
+       l != NULL;
+       l = l->next)
+    {
+      RecentAppInfo *ai = (RecentAppInfo *) l->data;
+      
+      g_assert (ai != NULL);
+      
+      retval[i++] = g_strdup (ai->name);
+    }
+  retval[i] = NULL;
+  
+  if (length)
+    *length = i;
+  
+  return retval;
+}
+
+/**
+ * gtk_recent_info_has_application:
+ * @info: a #GtkRecentInfo
+ * @app_name: a string containing an application name
+ *
+ * Checks whether an application registered this resource using @app_name.
+ *
+ * Return value: %TRUE if an application with name @app_name was found,
+ *   %FALSE otherwise.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_recent_info_has_application (GtkRecentInfo *info,
+				 const gchar   *app_name)
+{
+  g_return_val_if_fail (info != NULL, FALSE);
+  g_return_val_if_fail (app_name != NULL, FALSE);
+  
+  return (NULL != g_hash_table_lookup (info->apps_lookup, app_name));
+}
+
+/**
+ * gtk_recent_info_last_application:
+ * @info: a #GtkRecentInfo
+ *
+ * Gets the name of the last application that have registered the
+ * recently used resource represented by @info.
+ *
+ * Return value: an application name.  Use g_free() to free it.
+ *
+ * Since: 2.10
+ */
+gchar *
+gtk_recent_info_last_application (GtkRecentInfo  *info)
+{
+  GSList *l;
+  time_t last_stamp = (time_t) -1;
+  gchar *name = NULL;
+  
+  g_return_val_if_fail (info != NULL, NULL);
+  
+  for (l = info->applications; l != NULL; l = l->next)
+    {
+      RecentAppInfo *ai = (RecentAppInfo *) l->data;
+      
+      if (ai->stamp > last_stamp)
+        name = ai->name;
+    }
+  
+  return g_strdup (name);
+}
+
+typedef struct
+{
+  gint size;
+  GdkPixbuf *pixbuf;
+} IconCacheElement;
+
+static void
+icon_cache_element_free (IconCacheElement *element)
+{
+  if (element->pixbuf)
+    g_object_unref (element->pixbuf);
+  g_free (element);
+}
+
+static void
+icon_theme_changed (GtkIconTheme     *icon_theme)
+{
+  GHashTable *cache;
+
+  /* Difference from the initial creation is that we don't
+   * reconnect the signal
+   */
+  cache = g_hash_table_new_full (g_str_hash, g_str_equal,
+				 (GDestroyNotify)g_free,
+				 (GDestroyNotify)icon_cache_element_free);
+  g_object_set_data_full (G_OBJECT (icon_theme), "gtk-recent-icon-cache",
+			  cache, (GDestroyNotify)g_hash_table_destroy);
+}
+
+/* TODO: use the GtkFileChooser's icon cache instead of our own to reduce
+ * the memory footprint
+ */
+static GdkPixbuf *
+get_cached_icon (const gchar *name,
+		 gint         pixel_size)
+{
+  GtkIconTheme *icon_theme;
+  GHashTable *cache;
+  IconCacheElement *element;
+
+  icon_theme = gtk_icon_theme_get_default ();
+  cache = g_object_get_data (G_OBJECT (icon_theme), "gtk-recent-icon-cache");
+
+  if (!cache)
+    {
+      cache = g_hash_table_new_full (g_str_hash, g_str_equal,
+				     (GDestroyNotify)g_free,
+				     (GDestroyNotify)icon_cache_element_free);
+
+      g_object_set_data_full (G_OBJECT (icon_theme), "gtk-recent-icon-cache",
+			      cache, (GDestroyNotify)g_hash_table_destroy);
+      g_signal_connect (icon_theme, "changed",
+			G_CALLBACK (icon_theme_changed), NULL);
+    }
+
+  element = g_hash_table_lookup (cache, name);
+  if (!element)
+    {
+      element = g_new0 (IconCacheElement, 1);
+      g_hash_table_insert (cache, g_strdup (name), element);
+    }
+
+  if (element->size != pixel_size)
+    {
+      if (element->pixbuf)
+	g_object_unref (element->pixbuf);
+
+      element->size = pixel_size;
+      element->pixbuf = gtk_icon_theme_load_icon (icon_theme, name,
+						  pixel_size, 0, NULL);
+    }
+
+  return element->pixbuf ? g_object_ref (element->pixbuf) : NULL;
+}
+
+
+static GdkPixbuf *
+get_icon_for_mime_type (const char *mime_type,
+			gint        pixel_size)
+{
+  const char *separator;
+  GString *icon_name;
+  GdkPixbuf *pixbuf;
+
+  separator = strchr (mime_type, '/');
+  if (!separator)
+    return NULL; /* maybe we should return a GError with "invalid MIME-type" */
+
+  icon_name = g_string_new ("gnome-mime-");
+  g_string_append_len (icon_name, mime_type, separator - mime_type);
+  g_string_append_c (icon_name, '-');
+  g_string_append (icon_name, separator + 1);
+  pixbuf = get_cached_icon (icon_name->str, pixel_size);
+  g_string_free (icon_name, TRUE);
+  if (pixbuf)
+    return pixbuf;
+
+  icon_name = g_string_new ("gnome-mime-");
+  g_string_append_len (icon_name, mime_type, separator - mime_type);
+  pixbuf = get_cached_icon (icon_name->str, pixel_size);
+  g_string_free (icon_name, TRUE);
+
+  return pixbuf;
+}
+
+static GdkPixbuf *
+get_icon_fallback (const gchar *icon_name,
+		   gint         size)
+{
+  GtkIconTheme *icon_theme;
+  GdkPixbuf *retval;
+
+  icon_theme = gtk_icon_theme_get_default ();
+  
+  retval = gtk_icon_theme_load_icon (icon_theme, icon_name,
+  				     size,
+  				     GTK_ICON_LOOKUP_USE_BUILTIN,
+  				     NULL);
+  g_assert (retval != NULL);
+  
+  return retval; 
+}
+
+/**
+ * gtk_recent_info_get_icon:
+ * @info: a #GtkRecentInfo
+ * @size: the size of the icon in pixels
+ *
+ * Retrieves the icon of size @size associated to the resource MIME type.
+ *
+ * Return value: a #GdkPixbuf containing the icon, or %NULL.
+ *
+ * Since: 2.10
+ */
+GdkPixbuf *
+gtk_recent_info_get_icon (GtkRecentInfo *info,
+			  gint           size)
+{
+  GdkPixbuf *retval = NULL;
+  
+  g_return_val_if_fail (info != NULL, NULL);
+  
+  if (info->mime_type)
+    retval = get_icon_for_mime_type (info->mime_type, size);
+
+  /* this should never fail */  
+  if (!retval)
+    retval = get_icon_fallback (GTK_STOCK_FILE, size);
+  
+  return retval;
+}
+
+/**
+ * gtk_recent_info_is_local:
+ * @info: a #GtkRecentInfo
+ *
+ * Checks whether the resource is local or not by looking at the
+ * scheme of its URI.
+ *
+ * Return value: %TRUE if the resource is local.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_recent_info_is_local (GtkRecentInfo *info)
+{
+  g_return_val_if_fail (info != NULL, FALSE);
+  
+  return g_str_has_prefix (info->uri, "file://");
+}
+
+/**
+ * gtk_recent_info_exists:
+ * @info: a #GtkRecentInfo
+ *
+ * Checks whether the resource pointed by @info still exists.  At
+ * the moment this check is done only on resources pointing to local files.
+ *
+ * Return value: %TRUE if the resource exists
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_recent_info_exists (GtkRecentInfo *info)
+{
+  gchar *filename;
+  struct stat stat_buf;
+  gboolean retval = FALSE;
+  
+  g_return_val_if_fail (info != NULL, FALSE);
+  
+  /* we guarantee only local resources */
+  if (!gtk_recent_info_is_local (info))
+    return FALSE;
+  
+  filename = g_filename_from_uri (info->uri, NULL, NULL);
+  if (filename)
+    {
+      if (stat (filename, &stat_buf) == 0)
+        retval = TRUE;
+     
+      g_free (filename);
+    }
+  
+  return retval;
+}
+
+/**
+ * gtk_recent_info_match:
+ * @a: a #GtkRecentInfo
+ * @b: a #GtkRecentInfo
+ *
+ * Checks whether two #GtkRecentInfo structures point to the same
+ * resource.
+ *
+ * Return value: %TRUE if both #GtkRecentInfo structures point to se same
+ *   resource, %FALSE otherwise.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_recent_info_match (GtkRecentInfo *a,
+		       GtkRecentInfo *b)
+{
+  g_return_val_if_fail (a != NULL, FALSE);
+  g_return_val_if_fail (b != NULL, FALSE);
+  
+  return (0 == strcmp (a->uri, b->uri));
+}
+
+/* taken from gnome-vfs-uri.c */
+static const gchar *
+get_method_string (const gchar *substring, gchar **method_string)
+{
+  const gchar *p;
+  char *method;
+	
+  for (p = substring;
+       g_ascii_isalnum (*p) || *p == '+' || *p == '-' || *p == '.';
+       p++)
+    ;
+
+  if (*p == ':'
+#ifdef G_OS_WIN32
+                &&
+      !(p == substring + 1 && g_ascii_isalpha (*substring))
+#endif
+							   )
+    {
+      /* Found toplevel method specification.  */
+      method = g_strndup (substring, p - substring);
+      *method_string = g_ascii_strdown (method, -1);
+      g_free (method);
+      p++;
+    }
+  else
+    {
+      *method_string = g_strdup ("file");
+      p = substring;
+    }
+  
+  return p;
+}
+
+/* Stolen from gnome_vfs_make_valid_utf8() */
+static char *
+make_valid_utf8 (const char *name)
+{
+  GString *string;
+  const char *remainder, *invalid;
+  int remaining_bytes, valid_bytes;
+
+  string = NULL;
+  remainder = name;
+  remaining_bytes = name ? strlen (name) : 0;
+
+  while (remaining_bytes != 0)
+    {
+      if (g_utf8_validate (remainder, remaining_bytes, &invalid))
+        break;
+      
+      valid_bytes = invalid - remainder;
+      
+      if (string == NULL)
+        string = g_string_sized_new (remaining_bytes);
+      
+      g_string_append_len (string, remainder, valid_bytes);
+      g_string_append_c (string, '?');
+      
+      remaining_bytes -= valid_bytes + 1;
+      remainder = invalid + 1;
+    }
+  
+  if (string == NULL)
+    return g_strdup (name);
+
+  g_string_append (string, remainder);
+  g_assert (g_utf8_validate (string->str, -1, NULL));
+
+  return g_string_free (string, FALSE);
+}
+
+static gchar *
+get_uri_shortname_for_display (const gchar *uri)
+{
+  gchar *name = NULL;
+  gboolean validated = FALSE;
+
+  if (g_str_has_prefix (uri, "file://"))
+    {
+      gchar *local_file;
+      
+      local_file = g_filename_from_uri (uri, NULL, NULL);
+      
+      if (local_file != NULL)
+        {
+          name = g_filename_display_basename (local_file);
+          validated = TRUE;
+        }
+		
+      g_free (local_file);
+    } 
+  else
+    {
+      gchar *method;
+      gchar *local_file;
+      const gchar *rest;
+      
+      rest = get_method_string (uri, &method);
+      local_file = g_filename_display_basename (rest);
+      
+      name = g_strdup_printf ("%s: %s", method, local_file);
+      
+      g_free (local_file);
+      g_free (method);
+    }
+  
+  g_assert (name != NULL);
+  
+  if (!validated && !g_utf8_validate (name, -1, NULL))
+    {
+      gchar *utf8_name;
+      
+      utf8_name = make_valid_utf8 (name);
+      g_free (name);
+      
+      name = utf8_name;
+    }
+
+  return name;
+}
+
+/**
+ * gtk_recent_info_get_short_name:
+ * @info: an #GtkRecentInfo
+ *
+ * Computes a valid UTF-8 string that can be used as the name of the item in a
+ * menu or list.  For example, calling this function on an item that refers to
+ * "file:///foo/bar.txt" will yield "bar.txt".
+ *
+ * Return value: A newly-allocated string in UTF-8 encoding; free it with
+ *   g_free().
+ *
+ * Since: 2.10
+ */
+gchar *
+gtk_recent_info_get_short_name (GtkRecentInfo *info)
+{
+  gchar *short_name;
+
+  g_return_val_if_fail (info != NULL, NULL);
+
+  if (info->uri == NULL)
+    return NULL;
+
+  short_name = get_uri_shortname_for_display (info->uri);
+
+  return short_name;
+}
+
+/**
+ * gtk_recent_info_get_uri_display:
+ * @info: a #GtkRecentInfo
+ *
+ * Gets a displayable version of the resource's URI.
+ *
+ * Return value: a UTF-8 string containing the resource's URI or %NULL
+ *
+ * Since: 2.10
+ */
+gchar *
+gtk_recent_info_get_uri_display (GtkRecentInfo *info)
+{
+  gchar *filename, *filename_utf8;
+  
+  g_return_val_if_fail (info != NULL, NULL);
+  
+  filename = g_filename_from_uri (info->uri, NULL, NULL);
+  if (!filename)
+    return NULL;
+      
+  filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
+  g_free (filename);
+
+  return filename_utf8;
+}
+
+/**
+ * gtk_recent_info_get_age:
+ * @info: a #GtkRecentInfo
+ *
+ * Gets the number of days elapsed since the last update of the resource
+ * pointed by @info.
+ *
+ * Return value: a positive integer containing the number of days elapsed
+ *   since the time this resource was last modified.  On failure, -1 is
+ *   returned.
+ *
+ * Since: 2.10
+ */
+gint
+gtk_recent_info_get_age (GtkRecentInfo *info)
+{
+  time_t now, delta;
+  gint retval;
+
+  g_return_val_if_fail (info != NULL, -1);
+
+  now = time (NULL);
+  
+  delta = now - info->modified;
+  g_assert (delta >= 0);
+  
+  retval = (gint) (delta / (60 * 60 * 24));
+  
+  return retval;
+}
+
+/**
+ * gtk_recent_info_get_groups:
+ * @info: a #GtkRecentInfo
+ * @length: return location for the number of groups returned, or %NULL
+ *
+ * Returns all groups registered for the recently used item @info.  The
+ * array of returned group names will be %NULL terminated, so length might
+ * optionally be %NULL.
+ *
+ * Return value: a newly allocated %NULL terminated array of strings.  Use
+ *   g_strfreev() to free it.
+ *
+ * Since: 2.10
+ */
+gchar **
+gtk_recent_info_get_groups (GtkRecentInfo *info,
+			    gsize         *length)
+{
+  GSList *l;
+  gchar **retval;
+  gsize n_groups, i;
+  
+  g_return_val_if_fail (info != NULL, NULL);
+  
+  if (!info->groups)
+    {
+      if (length)
+        *length = 0;
+      
+      return NULL;
+    }
+  
+  n_groups = g_slist_length (info->groups);
+  
+  retval = g_new0 (gchar *, n_groups + 1);
+  
+  for (l = info->groups, i = 0;
+       l != NULL;
+       l = l->next)
+    {
+      gchar *group_name = (gchar *) l->data;
+      
+      g_assert (group_name != NULL);
+      
+      retval[i++] = g_strdup (group_name);
+    }
+  retval[i] = NULL;
+  
+  if (length)
+    *length = i;
+  
+  return retval;
+}
+
+/**
+ * gtk_recent_info_has_group:
+ * @info: a #GtkRecentInfo
+ * @group_name: name of a group
+ *
+ * Checks whether @group_name appears inside the groups registered for the
+ * recently used item @info.
+ *
+ * Return value: %TRUE if the group was found.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_recent_info_has_group (GtkRecentInfo *info,
+			   const gchar   *group_name)
+{
+  GSList *l;
+  
+  g_return_val_if_fail (info != NULL, FALSE);
+  g_return_val_if_fail (group_name != NULL, FALSE);
+
+  if (!info->groups)
+    return FALSE;
+
+  for (l = info->groups; l != NULL; l = l->next)
+    {
+      gchar *g = (gchar *) l->data;
+
+      if (strcmp (g, group_name) == 0)
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+#define __GTK_RECENT_MANAGER_C__
+#include "gtkaliasdef.c"
diff -Nuarp gtk+/gtk/gtkrecentmanager.h gtk+.recent/gtk/gtkrecentmanager.h
--- gtk+/gtk/gtkrecentmanager.h	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/gtk/gtkrecentmanager.h	2006-03-26 23:46:37.000000000 +0200
@@ -0,0 +1,207 @@
+/* GTK - The GIMP Toolkit
+ * gtkrecentmanager.h: a manager for the recently used resources
+ *
+ * Copyright (C) 2006 Emmanuele Bassi
+ *
+ * This 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.
+ *
+ * This 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ */
+
+#ifndef __GTK_RECENT_MANAGER_H__
+#define __GTK_RECENT_MANAGER_H__
+
+#include <glib-object.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <time.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_RECENT_INFO			(gtk_recent_info_get_type ())
+
+#define GTK_TYPE_RECENT_MANAGER			(gtk_recent_manager_get_type ())
+#define GTK_RECENT_MANAGER(obj)			(G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_RECENT_MANAGER, GtkRecentManager))
+#define GTK_IS_RECENT_MANAGER(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_RECENT_MANAGER))
+#define GTK_RECENT_MANAGER_CLASS(klass) 	(G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_RECENT_MANAGER, GtkRecentManagerClass))
+#define GTK_IS_RECENT_MANAGER_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_RECENT_MANAGER))
+#define GTK_RECENT_MANAGER_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_RECENT_MANAGER, GtkRecentManagerClass))
+
+typedef struct _GtkRecentInfo		GtkRecentInfo;
+typedef struct _GtkRecentData		GtkRecentData;
+typedef struct _GtkRecentManager	GtkRecentManager;
+typedef struct _GtkRecentManagerClass	GtkRecentManagerClass;
+typedef struct _GtkRecentManagerPrivate GtkRecentManagerPrivate;
+
+/**
+ * GtkRecentData:
+ *
+ * @display_name: a UTF-8 encoded string, containing the name of the recently
+ *   used resource to be displayed, or %NULL;
+ * @description: a UTF-8 encoded string, containing a short description of
+ *   the resource, or %NULL;
+ * @mime_type: the MIME type of the resource;
+ * @app_name: the name of the application that is registering this recently
+ *   used resource;
+ * @app_exec: command line used to launch this resource; may contain the
+ *   "%f" and "%u" escape characters which will be expanded to the resource
+ *   file path and URI respectively when the command line is retrieved;
+ * @groups: a vector of strings containing groups names;
+ * @is_private: whether this resource should be displayed only by the
+ *   applications that have registered it or not.
+ *
+ * Meta-data to be passed to gtk_recent_manager_add_full() when
+ * registering a recently used resource.
+ **/
+struct _GtkRecentData
+{
+  gchar *display_name;
+  gchar *description;
+  
+  gchar *mime_type;
+  
+  gchar *app_name;
+  gchar *app_exec;
+  
+  gchar **groups;
+  
+  gboolean is_private;
+};
+
+struct _GtkRecentManager
+{
+  /*< private >*/
+  GObject parent_instance;
+  
+  GtkRecentManagerPrivate *priv;
+};
+
+struct _GtkRecentManagerClass
+{
+  /*< private >*/
+  GObjectClass parent_class;
+  
+  void (*changed) (GtkRecentManager *manager);
+  
+  /* padding for future expansion */
+  void (*_gtk_recent1) (void);
+  void (*_gtk_recent2) (void);
+  void (*_gtk_recent3) (void);
+  void (*_gtk_recent4) (void);
+};
+
+/**
+ * GtkRecentManagerError:
+ * @GTK_RECENT_MANAGER_ERROR_NOT_FOUND: the URI specified does not exists in
+ *   the recently used resources list.
+ * @GTK_RECENT_MANAGER_ERROR_INVALID_URI: the URI specified is not valid.
+ * @GTK_RECENT_MANAGER_ERROR_INVALID_MIME: the MIME type specified is not
+ *   valid.
+ * @GTK_RECENT_MANAGER_ERROR_INVALID_ENCODING: the supplied string is not
+ *   UTF-8 encoded.
+ * @GTK_RECENT_MANAGER_ERROR_NOT_REGISTERED: no application has registered
+ *   the specified item.
+ * @GTK_RECENT_MANAGER_ERROR_READ: failure while reading the recently used
+ *   resources file.
+ * @GTK_RECENT_MANAGER_ERROR_WRITE: failure while writing the recently used
+ *   resources file.
+ * @GTK_RECENT_MANAGER_ERROR_UNKNOWN: unspecified error.
+ *
+ * Error codes for GtkRecentManager operations
+ **/
+typedef enum
+{
+  GTK_RECENT_MANAGER_ERROR_NOT_FOUND,
+  GTK_RECENT_MANAGER_ERROR_INVALID_URI,
+  GTK_RECENT_MANAGER_ERROR_INVALID_MIME,
+  GTK_RECENT_MANAGER_ERROR_INVALID_ENCODING,
+  GTK_RECENT_MANAGER_ERROR_NOT_REGISTERED,
+  GTK_RECENT_MANAGER_ERROR_BAD_EXEC_STRING,
+  GTK_RECENT_MANAGER_ERROR_READ,
+  GTK_RECENT_MANAGER_ERROR_WRITE,
+  GTK_RECENT_MANAGER_ERROR_UNKNOWN
+} GtkRecentManagerError;
+
+#define GTK_RECENT_MANAGER_ERROR	(gtk_recent_manager_error_quark ())
+GQuark 	gtk_recent_manager_error_quark (void);
+
+
+GType 		  gtk_recent_manager_get_type    (void) G_GNUC_CONST;
+
+GtkRecentManager *gtk_recent_manager_new         (void);
+gboolean          gtk_recent_manager_add_item    (GtkRecentManager     *manager,
+						  const gchar          *uri,
+						  GError              **error);
+gboolean          gtk_recent_manager_add_full    (GtkRecentManager     *manager,
+						  const gchar          *uri,
+						  const GtkRecentData  *recent_data,
+						  GError              **error);
+gboolean          gtk_recent_manager_remove_item (GtkRecentManager     *manager,
+						  const gchar          *uri,
+						  GError              **error);
+GtkRecentInfo *   gtk_recent_manager_lookup_item (GtkRecentManager     *manager,
+						  const gchar          *uri,
+						  GError              **error);
+gboolean          gtk_recent_manager_has_item    (GtkRecentManager     *manager,
+						  const gchar          *uri);
+gboolean          gtk_recent_manager_move_item   (GtkRecentManager     *manager,
+						  const gchar          *uri,
+						  const gchar          *new_uri,
+						  GError              **error);
+void              gtk_recent_manager_set_limit   (GtkRecentManager     *manager,
+						  gint                  limit);
+gint              gtk_recent_manager_get_limit   (GtkRecentManager     *manager);
+GList *           gtk_recent_manager_get_items   (GtkRecentManager     *manager);
+gint              gtk_recent_manager_purge_items (GtkRecentManager     *manager,
+						  GError              **error);
+
+
+GType	              gtk_recent_info_get_type             (void) G_GNUC_CONST;
+
+GtkRecentInfo *       gtk_recent_info_ref                  (GtkRecentInfo  *info);
+void                  gtk_recent_info_unref                (GtkRecentInfo  *info);
+
+G_CONST_RETURN gchar *gtk_recent_info_get_uri              (GtkRecentInfo  *info);
+G_CONST_RETURN gchar *gtk_recent_info_get_display_name     (GtkRecentInfo  *info);
+G_CONST_RETURN gchar *gtk_recent_info_get_description      (GtkRecentInfo  *info);
+G_CONST_RETURN gchar *gtk_recent_info_get_mime_type        (GtkRecentInfo  *info);
+time_t                gtk_recent_info_get_added            (GtkRecentInfo  *info);
+time_t                gtk_recent_info_get_modified         (GtkRecentInfo  *info);
+time_t                gtk_recent_info_get_visited          (GtkRecentInfo  *info);
+gboolean              gtk_recent_info_get_private_hint     (GtkRecentInfo  *info);
+gboolean              gtk_recent_info_get_application_info (GtkRecentInfo  *info,
+							    const gchar    *app_name,
+							    gchar         **app_exec,
+							    guint          *count,
+							    time_t         *time);
+gchar **              gtk_recent_info_get_applications     (GtkRecentInfo  *info,
+							    gsize          *length) G_GNUC_MALLOC;
+gchar *               gtk_recent_info_last_application     (GtkRecentInfo  *info) G_GNUC_MALLOC;
+gboolean              gtk_recent_info_has_application      (GtkRecentInfo  *info,
+							    const gchar    *app_name);
+gchar **              gtk_recent_info_get_groups           (GtkRecentInfo  *info,
+							    gsize          *length) G_GNUC_MALLOC;
+gboolean              gtk_recent_info_has_group            (GtkRecentInfo  *info,
+							    const gchar    *group_name);
+GdkPixbuf *           gtk_recent_info_get_icon             (GtkRecentInfo  *info,
+							    gint            size);
+gchar *               gtk_recent_info_get_short_name       (GtkRecentInfo  *info) G_GNUC_MALLOC;
+gchar *               gtk_recent_info_get_uri_display      (GtkRecentInfo  *info) G_GNUC_MALLOC;
+gint                  gtk_recent_info_get_age              (GtkRecentInfo  *info);
+gboolean              gtk_recent_info_is_local             (GtkRecentInfo  *info);
+gboolean              gtk_recent_info_exists               (GtkRecentInfo  *info);
+gboolean              gtk_recent_info_match                (GtkRecentInfo  *info_a,
+							    GtkRecentInfo  *info_b);
+
+G_END_DECLS
+
+#endif /* __GTK_RECENT_MANAGER_H__ */
diff -Nuarp gtk+/gtk/Makefile.am gtk+.recent/gtk/Makefile.am
--- gtk+/gtk/Makefile.am	2006-03-26 23:45:00.000000000 +0200
+++ gtk+.recent/gtk/Makefile.am	2006-03-26 23:45:28.000000000 +0200
@@ -227,6 +227,12 @@ gtk_public_h_sources =          \
 	gtkradiotoolbutton.h	\
 	gtkrange.h		\
 	gtkrc.h			\
+	gtkrecentchooser.h 	\
+	gtkrecentchooserdialog.h \
+	gtkrecentchoosermenu.h 	\
+	gtkrecentchooserwidget.h \
+	gtkrecentfilter.h 	\
+	gtkrecentmanager.h 	\
 	gtkruler.h		\
 	gtkscale.h		\
 	gtkscrollbar.h		\
@@ -309,6 +315,9 @@ gtk_private_h_sources =		\
 	gtkpathbar.h		\
 	gtkplugprivate.h	\
 	gtkrbtree.h		\
+	gtkrecentchooserdefault.h \
+	gtkrecentchooserprivate.h \
+	gtkrecentchooserutils.h \
 	gtksequence.h		\
 	gtksocketprivate.h	\
 	gtktextbtree.h		\
@@ -458,6 +467,14 @@ gtk_c_sources =                 \
 	gtkrange.c		\
 	gtkrbtree.c 		\
 	gtkrc.c			\
+	gtkrecentchooserdefault.c \
+	gtkrecentchooserdialog.c \
+	gtkrecentchoosermenu.c 	\
+	gtkrecentchooserwidget.c \
+	gtkrecentchooserutils.c \
+	gtkrecentchooser.c 	\
+	gtkrecentfilter.c 	\
+	gtkrecentmanager.c 	\
 	gtkruler.c		\
 	gtkscale.c		\
 	gtkscrollbar.c		\
diff -Nuarp gtk+/tests/Makefile.am gtk+.recent/tests/Makefile.am
--- gtk+/tests/Makefile.am	2006-03-26 23:45:10.000000000 +0200
+++ gtk+.recent/tests/Makefile.am	2006-03-26 23:45:28.000000000 +0200
@@ -53,6 +53,7 @@ noinst_PROGRAMS =			\
 	testmultiscreen			\
 	testnotebookdnd			\
 	testrgb				\
+	testrecentchooser 		\
 	testselection			\
 	$(testsocket_programs)		\
 	testspinbutton			\
@@ -103,6 +104,7 @@ testmenubars_DEPENDENCIES = $(TEST_DEPS)
 testmultidisplay_DEPENDENCIES = $(TEST_DEPS)
 testmultiscreen_DEPENDENCIES = $(TEST_DEPS)
 testnotebookdnd_DEPENDENCIES = $(TEST_DEPS)
+testrecentchooser_DEPENDENCIES = $(TEST_DEPS)
 testrgb_DEPENDENCIES = $(TEST_DEPS)
 testselection_DEPENDENCIES = $(TEST_DEPS)
 testsocket_DEPENDENCIES = $(DEPS)
@@ -148,6 +150,7 @@ testmenubars_LDADD = $(LDADDS)
 testmultidisplay_LDADD = $(LDADDS)
 testmultiscreen_LDADD = $(LDADDS)
 testnotebookdnd_LDADD = $(LDADDS)
+testrecentchooser_LDADD = $(LDADDS)
 testrgb_LDADD = $(LDADDS)
 testselection_LDADD = $(LDADDS)
 testsocket_LDADD = $(LDADDS)
@@ -236,6 +239,9 @@ testiconview_SOURCES = 		\
 	testiconview.c		\
 	prop-editor.c
 
+testrecentchooser_SOURCES = 	\
+	testrecentchooser.c
+
 EXTRA_DIST = 			\
 	prop-editor.h		\
 	testgtk.1 		\
diff -Nuarp gtk+/tests/testrecentchooser.c gtk+.recent/tests/testrecentchooser.c
--- gtk+/tests/testrecentchooser.c	1970-01-01 01:00:00.000000000 +0100
+++ gtk+.recent/tests/testrecentchooser.c	2006-03-26 23:46:48.000000000 +0200
@@ -0,0 +1,141 @@
+/* testrecentchooser.c
+ * Copyright (C) 2006  Emmanuele Bassi.
+ *
+ * This 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.
+ *
+ * This 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <time.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <gtk/gtk.h>
+
+#ifdef G_OS_WIN32
+# include <io.h>
+# define localtime_r(t,b) *(b) = localtime (t)
+# ifndef S_ISREG
+#  define S_ISREG(m) ((m) & _S_IFREG)
+# endif
+#endif
+
+static void
+print_current_item (GtkRecentChooser *chooser)
+{
+  gchar *uri;
+
+  uri = gtk_recent_chooser_get_current_uri (chooser);
+  g_print ("Current item changed :\n  %s\n", uri ? uri : "null");
+  g_free (uri);
+}
+
+static void
+print_selected (GtkRecentChooser *chooser)
+{
+  gsize uris_len, i;
+  gchar **uris = gtk_recent_chooser_get_uris (chooser, &uris_len);
+
+  g_print ("Selection changed :\n");
+  for (i = 0; i < uris_len; i++)
+    g_print ("  %s\n", uris[i]);
+  g_print ("\n");
+
+  g_strfreev (uris);
+}
+
+static void
+response_cb (GtkDialog *dialog,
+	     gint       response_id)
+{
+  if (response_id == GTK_RESPONSE_OK)
+    {
+    }
+  else
+    g_print ("Dialog was closed\n");
+
+  gtk_main_quit ();
+}
+
+static void
+filter_changed (GtkRecentChooserDialog *dialog,
+		gpointer                data)
+{
+  g_print ("recent filter changed\n");
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+  GtkWidget *dialog;
+  GtkRecentFilter *filter;
+  
+  gtk_init (&argc, &argv);
+
+  dialog = g_object_new (GTK_TYPE_RECENT_CHOOSER_DIALOG,
+		         "select-multiple", FALSE,
+			 NULL);
+  gtk_window_set_title (GTK_WINDOW (dialog), "Select a file");
+  gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+		  	  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+			  GTK_STOCK_OPEN, GTK_RESPONSE_OK,
+			  NULL);
+  
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+  g_signal_connect (dialog, "item-activated",
+		    G_CALLBACK (print_current_item), NULL);
+  g_signal_connect (dialog, "selection-changed",
+		    G_CALLBACK (print_selected), NULL);
+  g_signal_connect (dialog, "response",
+		    G_CALLBACK (response_cb), NULL);
+  
+  /* filters */
+  filter = gtk_recent_filter_new ();
+  gtk_recent_filter_set_name (filter, "All Files");
+  gtk_recent_filter_add_pattern (filter, "*");
+  gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (dialog), filter);
+
+  filter = gtk_recent_filter_new ();
+  gtk_recent_filter_set_name (filter, "Only PDF Files");
+  gtk_recent_filter_add_mime_type (filter, "application/pdf");
+  gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (dialog), filter);
+
+  g_signal_connect (dialog, "notify::filter",
+		    G_CALLBACK (filter_changed), NULL);
+
+  gtk_recent_chooser_set_filter (GTK_RECENT_CHOOSER (dialog), filter);
+
+  filter = gtk_recent_filter_new ();
+  gtk_recent_filter_set_name (filter, "PNG and JPEG");
+  gtk_recent_filter_add_mime_type (filter, "image/png");
+  gtk_recent_filter_add_mime_type (filter, "image/jpeg");
+  gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (dialog), filter);
+
+  gtk_widget_show_all (dialog);
+
+  g_object_ref (dialog);
+  gtk_main ();
+  gtk_widget_destroy (dialog);
+  g_object_unref (dialog);
+
+  return 0;
+}
