Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/libgnomeui/ChangeLog,v
retrieving revision 1.492.2.5
diff -u -r1.492.2.5 ChangeLog
--- ChangeLog	22 Jun 2005 15:46:39 -0000	1.492.2.5
+++ ChangeLog	23 Jun 2005 00:26:49 -0000
@@ -1,3 +1,32 @@
+2005-06-22  Federico Mena Quintero  <federico@ximian.com>
+
+	Add support for .desktop file links; fixes #136271:
+
+	* file-chooser/gtkfilesystemgnomevfs.c
+	(gtk_file_system_gnome_vfs_get_folder): If the URI refers to a
+	.desktop link, read it, and try to get the destination URI
+	instead.  Also, clean up a bit by using helper functions.
+	(info_from_vfs_info): Take an error argument; we'll fill it in if
+	there is an error while reading a .desktop file.
+	(gtk_file_folder_gnome_vfs_get_info): Pass an error argument to
+	info_from_vfs_info().
+	(is_vfs_info_an_afs_folder): New helper function.
+	(get_desktop_link_uri): New helper function.
+
+	* configure.in: Add libgnome to the modules needed by the
+	file-chooser directory.
+	Add a --with-kde-datadir option for KDE_ICONDIR.
+
+	* file-chooser/sucky-desktop-item.[ch]: Sigh.  We need
+	GnomeDesktopItem for GtkFileSystemGnomeVFS, but that sucker lives
+	in the gnome-desktop module, which has libgnomeui as a dependency.
+	So I just copied the relevant files and replaced "gnome" with
+	"sucky".  To keep an optimistic outlook on life, those strings are
+	of equal length, so indentation is preserved.
+
+	* file-chooser/Makefile.am (libgnome_vfs_la_SOURCES): Added the
+	sucky files.
+
 2005-06-22  Matthias Clasen <mclasen@redhat.com>
 
 	* file-chooser/gtkfilesystemgnomevfs.c: Ignore
Index: configure.in
===================================================================
RCS file: /cvs/gnome/libgnomeui/configure.in,v
retrieving revision 1.203.2.1
diff -u -r1.203.2.1 configure.in
--- configure.in	11 May 2005 11:46:20 -0000	1.203.2.1
+++ configure.in	23 Jun 2005 00:26:49 -0000
@@ -169,6 +169,7 @@
 dnl File Chooser stuff
 PKG_CHECK_MODULES(FILE_SYSTEM,
  [gtk+-2.0 >= gtk_required_version dnl
+  libgnome-2.0 >= libgnome_required_version dnl
   gnome-vfs-2.0 >= gnomevfs_required_version])
 
 GTK_BINARY_VERSION=`$PKG_CONFIG --variable=gtk_binary_version gtk+-2.0`
@@ -208,6 +209,16 @@
 if test x$have_crt_externs = xyes; then
   AC_DEFINE(HAVE_CRT_EXTERNS_H, 1, [whether we have crt_externs.h])
 fi
+
+dnl For file-chooser/sucky-desktop-item.c.
+AC_ARG_WITH(kde-datadir, [  --with-kde-datadir=DIR  Location of KDE data])
+if test "x$with_kde_datadir" = x ; then
+  kde_datadir=/usr/share
+else
+  kde_datadir=$with_kde_datadir
+fi
+AC_DEFINE_UNQUOTED(KDE_ICONDIR, "$kde_datadir/icons",
+                   [The KDE icon directory])
 
 dnl This is installed from GTK+ 2.0's gdk-pixbuf
 AC_PATH_PROG(GDK_PIXBUF_CSOURCE, gdk-pixbuf-csource)
Index: file-chooser/Makefile.am
===================================================================
RCS file: /cvs/gnome/libgnomeui/file-chooser/Makefile.am,v
retrieving revision 1.4
diff -u -r1.4 Makefile.am
--- file-chooser/Makefile.am	12 Mar 2004 03:57:10 -0000	1.4
+++ file-chooser/Makefile.am	23 Jun 2005 00:26:49 -0000
@@ -24,7 +24,7 @@
 	libgnome-vfs.la			\
 	$(NULL)
 
-libgnome_vfs_la_SOURCES = gtkfilesystemgnomevfs.c gtkfilesystemgnomevfs.h
+libgnome_vfs_la_SOURCES = gtkfilesystemgnomevfs.c gtkfilesystemgnomevfs.h sucky-desktop-item.c sucky-desktop-item.h
 libgnome_vfs_la_LDFLAGS = $(module_flags)
 libgnome_vfs_la_LIBADD = $(FILE_SYSTEM_LIBS)	\
 	$(top_builddir)/libgnomeui/libgnomeui-2.la
Index: file-chooser/gtkfilesystemgnomevfs.c
===================================================================
RCS file: /cvs/gnome/libgnomeui/file-chooser/gtkfilesystemgnomevfs.c,v
retrieving revision 1.59.2.3
diff -u -r1.59.2.3 gtkfilesystemgnomevfs.c
--- file-chooser/gtkfilesystemgnomevfs.c	22 Jun 2005 15:46:39 -0000	1.59.2.3
+++ file-chooser/gtkfilesystemgnomevfs.c	23 Jun 2005 00:26:49 -0000
@@ -57,6 +57,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include "sucky-desktop-item.h"
 
 #define BOOKMARKS_FILENAME ".gtk-bookmarks"
 #define BOOKMARKS_TMP_FILENAME ".gtk-bookmarks-XXXXXX"
@@ -256,7 +257,8 @@
 
 static GtkFileInfo *           info_from_vfs_info (const gchar      *uri,
 						   GnomeVFSFileInfo *vfs_info,
-						   GtkFileInfoType   types);
+						   GtkFileInfoType   types,
+						   GError          **error);
 static GnomeVFSFileInfoOptions get_options        (GtkFileInfoType   types);
 
 static void volume_mount_unmount_cb (GnomeVFSVolumeMonitor *monitor,
@@ -727,6 +729,93 @@
   return canonical;
 }
 
+/* Returns whether the MIME type of a vfs_info is "application/x-desktop" */
+static gboolean
+is_desktop_file (GnomeVFSFileInfo *vfs_info)
+{
+  return ((vfs_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE) != 0
+	  && strcmp (gnome_vfs_file_info_get_mime_type (vfs_info), "application/x-desktop") == 0);
+}
+
+/* Returns whether a .desktop file indicates a link to a folder */
+static gboolean
+is_desktop_file_a_folder (SuckyDesktopItem *ditem)
+{
+  SuckyDesktopItemType ditem_type;
+
+  ditem_type = sucky_desktop_item_get_entry_type (ditem);
+
+  if (ditem_type != SUCKY_DESKTOP_ITEM_TYPE_LINK)
+    return FALSE;
+
+  /* FIXME: do we have to get the link URI and figure out its type?  For now,
+   * we'll just assume that it does link to a folder...
+   */
+
+  return TRUE;
+}
+
+/* Checks whether a vfs_info matches what we know about the AFS directories on
+ * the system.
+ */
+static gboolean
+is_vfs_info_an_afs_folder (GtkFileSystemGnomeVFS *system_vfs,
+			   GnomeVFSFileInfo      *vfs_info)
+{
+  return (GNOME_VFS_FILE_INFO_LOCAL (vfs_info)
+	  && (vfs_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_DEVICE) != 0
+	  && (vfs_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_INODE) != 0
+	  && ((system_vfs->have_afs
+	       && system_vfs->afs_statbuf.st_dev == vfs_info->device
+	       && system_vfs->afs_statbuf.st_ino == vfs_info->inode)
+	      || (system_vfs->have_net
+		  && system_vfs->net_statbuf.st_dev == vfs_info->device
+		  && system_vfs->net_statbuf.st_ino == vfs_info->inode)));
+}
+
+/* Returns the URL attribute for a .desktop file of type Link */
+static char *
+get_desktop_link_uri (const char *desktop_uri,
+		      GError    **error)
+{
+  SuckyDesktopItem *ditem;
+  const char *ditem_url;
+  char *ret_uri;
+
+  ditem = sucky_desktop_item_new_from_uri (desktop_uri, 0, error);
+  if (ditem == NULL)
+    return NULL;
+
+  ret_uri = NULL;
+
+  if (!is_desktop_file_a_folder (ditem))
+    {
+      g_set_error (error,
+		   GTK_FILE_SYSTEM_ERROR,
+		   GTK_FILE_SYSTEM_ERROR_NOT_FOLDER,
+		   _("%s is a link to something that is not a folder"),
+		   desktop_uri);
+      goto out;
+    }
+
+  ditem_url = sucky_desktop_item_get_string (ditem, SUCKY_DESKTOP_ITEM_URL);
+  if (ditem_url == NULL || strlen (ditem_url) == 0)
+    {
+      g_set_error (error,
+		   GTK_FILE_SYSTEM_ERROR,
+		   GTK_FILE_SYSTEM_ERROR_INVALID_URI,
+		   _("%s is a link without a destination location"),
+		   desktop_uri);
+      goto out;
+    }
+
+  ret_uri = g_strdup (ditem_url);
+
+ out:
+
+  sucky_desktop_item_unref (ditem);
+  return ret_uri;
+}
 
 static GtkFileFolder *
 gtk_file_system_gnome_vfs_get_folder (GtkFileSystem     *file_system,
@@ -741,7 +830,6 @@
   GnomeVFSMonitorHandle *monitor;
   GnomeVFSResult result;
   GnomeVFSFileInfo *vfs_info;
-  GnomeVFSFileType vfs_info_type;
 
   uri = make_uri_canonical (gtk_file_path_get_string (path));
   folder_vfs = g_hash_table_lookup (system_vfs->folders, uri);
@@ -804,9 +892,22 @@
 	}
     }
 
-  vfs_info_type = vfs_info->type;
+  if (is_desktop_file (vfs_info))
+    {
+      char *ditem_uri;
 
-  if (vfs_info_type != GNOME_VFS_FILE_TYPE_DIRECTORY)
+      ditem_uri = get_desktop_link_uri (uri, error);
+      if (ditem_uri == NULL)
+	{
+	  g_free (uri);
+	  gnome_vfs_file_info_unref (vfs_info);
+	  return NULL;
+	}
+
+      g_free (uri);
+      uri = ditem_uri;
+    }
+  else if (vfs_info->type != GNOME_VFS_FILE_TYPE_DIRECTORY)
     {
       g_set_error (error,
 		   GTK_FILE_SYSTEM_ERROR,
@@ -820,21 +921,10 @@
 
   folder_vfs = g_object_new (GTK_TYPE_FILE_FOLDER_GNOME_VFS, NULL);
 
-  /* Check for AFS */
-  if (GNOME_VFS_FILE_INFO_LOCAL (vfs_info)
-      && (vfs_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_DEVICE) != 0
-      && (vfs_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_INODE) != 0
-      && ((system_vfs->have_afs
-	   && system_vfs->afs_statbuf.st_dev == vfs_info->device
-	   && system_vfs->afs_statbuf.st_ino == vfs_info->inode)
-	  || (system_vfs->have_net
-	      && system_vfs->net_statbuf.st_dev == vfs_info->device
-	      && system_vfs->net_statbuf.st_ino == vfs_info->inode)))
-    folder_vfs->is_afs_or_net = TRUE;
-  else
-    folder_vfs->is_afs_or_net = FALSE;
+  folder_vfs->is_afs_or_net = is_vfs_info_an_afs_folder (system_vfs, vfs_info);
 
   gnome_vfs_file_info_unref (vfs_info);
+  vfs_info = NULL;
 
   monitor = NULL;
 
@@ -2185,7 +2275,7 @@
 	  set_vfs_error (result, folder_vfs->uri, error);
 	}
       else
-	file_info = info_from_vfs_info (folder_vfs->uri, info, GTK_FILE_INFO_ALL);
+	file_info = info_from_vfs_info (folder_vfs->uri, info, GTK_FILE_INFO_ALL, error);
 
       gnome_vfs_file_info_unref (info);
       return file_info;
@@ -2194,7 +2284,7 @@
   child = lookup_folder_child (folder, path, error);
 
   if (child)
-    return info_from_vfs_info (uri, child->info, folder_vfs->types);
+    return info_from_vfs_info (uri, child->info, folder_vfs->types, error);
   else
     return NULL;
 }
@@ -2257,15 +2347,41 @@
 static GtkFileInfo *
 info_from_vfs_info (const gchar      *uri,
 		    GnomeVFSFileInfo *vfs_info,
-		    GtkFileInfoType   types)
+		    GtkFileInfoType   types,
+		    GError          **error)
 {
   GtkFileInfo *info = gtk_file_info_new ();
-  char *local_file;
-  char *display_name;
+  gboolean is_desktop;
+  SuckyDesktopItem *ditem;
+
+  /* Desktop files are special.  They can override the name, type, icon, etc. */
+
+  is_desktop = is_desktop_file (vfs_info);
+
+  ditem = NULL; /* shut up GCC */
+
+  if (is_desktop)
+    {
+      ditem = sucky_desktop_item_new_from_uri (uri, 0, error);
+      if (ditem == NULL)
+	return NULL;
+    }
+
+  /* Display name */
 
   if (types & GTK_FILE_INFO_DISPLAY_NAME)
     {
-      if (!vfs_info->name || strcmp (vfs_info->name, "/") == 0)
+      if (is_desktop)
+	{
+	  const char *name;
+
+	  name = sucky_desktop_item_get_localestring (ditem, SUCKY_DESKTOP_ITEM_NAME);
+	  if (name != NULL)
+	    gtk_file_info_set_display_name (info, name);
+	  else
+	    goto fetch_name_from_uri;
+	}
+      else if (!vfs_info->name || strcmp (vfs_info->name, "/") == 0)
 	{
 	  if (strcmp (uri, "file:///") == 0)
 	    gtk_file_info_set_display_name (info, "/");
@@ -2274,6 +2390,11 @@
 	}
       else
 	{
+	  char *local_file;
+	  char *display_name;
+
+	fetch_name_from_uri:
+
 	  local_file = gnome_vfs_get_local_path_from_uri (uri);
 	  if (local_file != NULL)
 	    {
@@ -2291,20 +2412,51 @@
 	}
     }
 
-  gtk_file_info_set_is_hidden (info, vfs_info->name && vfs_info->name[0] == '.');
-  gtk_file_info_set_is_folder (info, vfs_info->type == GNOME_VFS_FILE_TYPE_DIRECTORY);
+  /* Hidden */
+
+  if (types & GTK_FILE_INFO_IS_HIDDEN)
+    {
+      gboolean is_hidden;
+
+      if (is_desktop)
+	is_hidden = sucky_desktop_item_get_boolean (ditem, SUCKY_DESKTOP_ITEM_HIDDEN);
+      else
+	is_hidden = (vfs_info->name && vfs_info->name[0] == '.');
+
+      gtk_file_info_set_is_hidden (info, is_hidden);
+    }
+
+  /* Folder */
+
+  if (types & GTK_FILE_INFO_IS_FOLDER)
+    {
+      gboolean is_folder;
+
+      if (is_desktop)
+	is_folder = is_desktop_file_a_folder (ditem);
+      else
+	is_folder = (vfs_info->type == GNOME_VFS_FILE_TYPE_DIRECTORY);
+
+      gtk_file_info_set_is_folder (info, is_folder);
+    }
 
-#if 0
-  if ((types & GTK_FILE_INFO_MIME_TYPE) || (types & GTK_FILE_INFO_ICON))
-#else
   if (types & GTK_FILE_INFO_MIME_TYPE)
-#endif
     {
-      gtk_file_info_set_mime_type (info, vfs_info->mime_type);
+      const char *mime_type;
+
+      if (is_desktop)
+	mime_type = "application/x-desktop"; /* FIXME: do we have to get the link URI and figure out its type? */
+      else
+	mime_type = vfs_info->mime_type;
+
+      gtk_file_info_set_mime_type (info, mime_type);
     }
 
   gtk_file_info_set_modification_time (info, vfs_info->mtime);
   gtk_file_info_set_size (info, vfs_info->size);
+
+  if (is_desktop)
+    sucky_desktop_item_unref (ditem);
 
   return info;
 }
