Git Repositories

2005-08-28 Benedikt Meurer <benny@xfce.org>
authorBenedikt Meurer <benny@xfce.org>
Sun, 28 Aug 2005 15:48:04 +0000 (15:48 +0000)
committerBenedikt Meurer <benny@xfce.org>
Sun, 28 Aug 2005 15:48:04 +0000 (15:48 +0000)
* thunar/thunar-file.{c,h}, thunar/thunar-local-file.c,
  thunar/thunar-standard-view.c: Rename can_execute(), can_read() and
  can_write() to is_executable(), is_readable() and is_writable() to
  get consistent naming.
* thunar-vfs/thunar-vfs-info.{c,h}: Add THUNAR_VFS_FILE_FLAGS_EXECUTABLE
  to the ThunarVfsFileFlags, which will be set if a ThunarVfsInfo
  can be executed, either as regular binary or as .desktop file.
* thunar-vfs/thunar-vfs-mime-application.c,
  thunar-vfs/thunar-vfs-sysdep.{c,h}: Move the Exec parsing code from
  ThunarVfsMimeApplication to thunar-vfs-sysdep, so it can be used by
  other modules as well.
* thunar-vfs/thunar-vfs-info.{c,h}, thunar-vfs/thunar-vfs.symbols: Add
  new method thunar_vfs_info_execute(), which is used to execute
  files with a list of URIs. These method can handle both regular
  executable files as well as .desktop files.
* thunar/thunar-file.{c,h}, thunar/thunar-launcher.c,
  thunar/thunar-local-file.c: Add support to execute files that are
  marked as executable by the ThunarVfsInfo module.
* thunar-vfs/thunar-vfs-mime-database.c
  (thunar_vfs_mime_database_get_info_locked),
  (thunar_vfs_mime_database_get_infos_for_info_locked): Be sure to
  always unalias MIME-types prior to returning them from the mime
  database instance. This way we don't need to care for unaliasing
  when determining the MIME-type comment or MIME-type icon.
* thunar-vfs/thunar-vfs-mime-database.{c,h},
  thunar-vfs/thunar-vfs.symbols: Add new method
  thunar_vfs_mime_database_get_infos_for_info() to the public API, to
  allow other components to access the subclassing information.
* FAQ, Makefile.am: Add initial items for the list of frequently asked
  questions.
* TODO: Remove obsolete items.

(Old svn revision: 17147)

17 files changed:
ChangeLog
FAQ [new file with mode: 0644]
Makefile.am
TODO
thunar-vfs/thunar-vfs-info.c
thunar-vfs/thunar-vfs-info.h
thunar-vfs/thunar-vfs-mime-application.c
thunar-vfs/thunar-vfs-mime-database.c
thunar-vfs/thunar-vfs-mime-database.h
thunar-vfs/thunar-vfs-sysdep.c
thunar-vfs/thunar-vfs-sysdep.h
thunar-vfs/thunar-vfs.symbols
thunar/thunar-file.c
thunar/thunar-file.h
thunar/thunar-launcher.c
thunar/thunar-local-file.c
thunar/thunar-standard-view.c

index a5f2c6c..18c19e4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,37 @@
+2005-08-28     Benedikt Meurer <benny@xfce.org>
+
+       * thunar/thunar-file.{c,h}, thunar/thunar-local-file.c,
+         thunar/thunar-standard-view.c: Rename can_execute(), can_read() and
+         can_write() to is_executable(), is_readable() and is_writable() to
+         get consistent naming.
+       * thunar-vfs/thunar-vfs-info.{c,h}: Add THUNAR_VFS_FILE_FLAGS_EXECUTABLE
+         to the ThunarVfsFileFlags, which will be set if a ThunarVfsInfo
+         can be executed, either as regular binary or as .desktop file.
+       * thunar-vfs/thunar-vfs-mime-application.c,
+         thunar-vfs/thunar-vfs-sysdep.{c,h}: Move the Exec parsing code from
+         ThunarVfsMimeApplication to thunar-vfs-sysdep, so it can be used by
+         other modules as well.
+       * thunar-vfs/thunar-vfs-info.{c,h}, thunar-vfs/thunar-vfs.symbols: Add
+         new method thunar_vfs_info_execute(), which is used to execute
+         files with a list of URIs. These method can handle both regular
+         executable files as well as .desktop files.
+       * thunar/thunar-file.{c,h}, thunar/thunar-launcher.c,
+         thunar/thunar-local-file.c: Add support to execute files that are
+         marked as executable by the ThunarVfsInfo module.
+       * thunar-vfs/thunar-vfs-mime-database.c
+         (thunar_vfs_mime_database_get_info_locked),
+         (thunar_vfs_mime_database_get_infos_for_info_locked): Be sure to
+         always unalias MIME-types prior to returning them from the mime
+         database instance. This way we don't need to care for unaliasing
+         when determining the MIME-type comment or MIME-type icon.
+       * thunar-vfs/thunar-vfs-mime-database.{c,h},
+         thunar-vfs/thunar-vfs.symbols: Add new method
+         thunar_vfs_mime_database_get_infos_for_info() to the public API, to
+         allow other components to access the subclassing information.
+       * FAQ, Makefile.am: Add initial items for the list of frequently asked
+         questions.
+       * TODO: Remove obsolete items.
+
 2005-08-27     Benedikt Meurer <benny@xfce.org>
 
        * thunar-vfs/thunar-vfs-info.{c,h}: Add support to pass hints from the
diff --git a/FAQ b/FAQ
new file mode 100644 (file)
index 0000000..c4faefe
--- /dev/null
+++ b/FAQ
@@ -0,0 +1,24 @@
+This file contains a list of frequently asked questions about Thunar and the
+appropriate answers to these questions.
+
+
+1. What is Thunar?
+==================
+
+  Thunar is a fast and easy-to-use file manager for the X Window System, with a
+  special focus on the Xfce Desktop Environment.
+
+
+2. Why doesn't Thunar execute files marked as executable?
+=========================================================
+
+  For security reasons Thunar only executes files of type application/x-desktop,
+  application/x-executable and application/x-shellscript. For desktop files
+  the execution feature will only be enabled if the desktop file is of type
+  Application and a valid Exec line is given. For the other types the feature
+  is available if the file is marked executable for the current user.
+
+  Also note that for application/x-executable and application/x-shellscript, the
+  types of the file don't really need to match these types exactly, but it is
+  suffice if the detected type has a parent that matches one of the two types
+  listed above, or if the MIME-type is an alias for one of the above.
index 5cbdcd8..df74194 100644 (file)
@@ -25,6 +25,7 @@ desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
 @INTLTOOL_DESKTOP_RULE@
 
 EXTRA_DIST =                                                           \
+       FAQ                                                             \
        HACKING                                                         \
        intltool-extract.in                                             \
        intltool-merge.in                                               \
diff --git a/TODO b/TODO
index 683176e..ae17009 100644 (file)
--- a/TODO
+++ b/TODO
@@ -8,9 +8,6 @@ Important for Thunar 1.0
  - We need a way to "refresh" folders after a "Cut"-operation with Nautilus.
    With local folders - with not many files inside - the move is too fast!
 
- - ThunarVfsURI should have it's own parameter specification, that
-   can be used for GValue handling.
-
  - The ThunarTrashFile constructor needs some rework, as it's currently
    mostly brain-dead. Should probably be splitted into several functions.
    In addition the ThunarTrashFile should enable the monitoring on the
@@ -70,8 +67,3 @@ Important for Thunar 1.0
    development of Thunar core modules is to be done, and what
    material each developer in addition to the source code.
 
- - The ThunarVfsMonitor framework must be designed and implemented.
-   The list of supported backends for 1.0 is kqueue, fam and
-   the stat-thread. Backend technologies must be thread-safe. If
-   there's a lot of time or manpower in the end, additional
-   backends can be added, as long as they fit into the framework.
index ecd3c25..5f6efe0 100644 (file)
 #ifdef HAVE_STRING_H
 #include <string.h>
 #endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 
 #include <thunar-vfs/thunar-vfs-info.h>
 #include <thunar-vfs/thunar-vfs-mime-database.h>
+#include <thunar-vfs/thunar-vfs-sysdep.h>
 #include <thunar-vfs/thunar-vfs-alias.h>
 
+/* Use g_access() if possible */
+#if GLIB_CHECK_VERSION(2,8,0)
+#include <glib/gstdio.h>
+#else
+#define g_access(path, mode) (access ((path), (mode)))
+#endif
+
 
 
 /**
@@ -59,12 +70,15 @@ thunar_vfs_info_new_for_uri (ThunarVfsURI *uri,
                              GError      **error)
 {
   ThunarVfsMimeDatabase *database;
+  ThunarVfsMimeInfo     *mime_info;
   ThunarVfsInfo         *info;
   const gchar           *path;
   const gchar           *str;
   struct stat            lsb;
   struct stat            sb;
   XfceRc                *rc;
+  GList                 *mime_infos;
+  GList                 *lp;
 
   g_return_val_if_fail (THUNAR_VFS_IS_URI (uri), NULL);
   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
@@ -84,6 +98,7 @@ thunar_vfs_info_new_for_uri (ThunarVfsURI *uri,
   info->display_name = thunar_vfs_uri_get_display_name (uri);
   info->hints = NULL;
 
+  /* determine the POSIX file attributes */
   if (G_LIKELY (!S_ISLNK (lsb.st_mode)))
     {
       info->type = (lsb.st_mode & S_IFMT) >> 12;
@@ -130,6 +145,7 @@ thunar_vfs_info_new_for_uri (ThunarVfsURI *uri,
         }
     }
 
+  /* determine the file's mime type */
   database = thunar_vfs_mime_database_get_default ();
   switch (info->type)
     {
@@ -158,7 +174,28 @@ thunar_vfs_info_new_for_uri (ThunarVfsURI *uri,
       break;
 
     case THUNAR_VFS_FILE_TYPE_REGULAR:
+      /* determine the MIME-type for the regular file */
       info->mime_info = thunar_vfs_mime_database_get_info_for_file (database, path, info->display_name);
+
+      /* check if the file is executable (for security reasons
+       * we only allow execution of well known file types).
+       */
+      if (G_LIKELY (info->type == THUNAR_VFS_FILE_TYPE_REGULAR)
+          && (info->mode & 0444) != 0 && g_access (path, X_OK) == 0)
+        {
+          mime_infos = thunar_vfs_mime_database_get_infos_for_info (database, info->mime_info);
+          for (lp = mime_infos; lp != NULL; lp = lp->next)
+            {
+              mime_info = THUNAR_VFS_MIME_INFO (lp->data);
+              if (strcmp (mime_info->name, "application/x-executable") == 0
+                  || strcmp (mime_info->name, "application/x-shellscript") == 0)
+                {
+                  info->flags |= THUNAR_VFS_FILE_FLAGS_EXECUTABLE;
+                  break;
+                }
+            }
+          thunar_vfs_mime_info_list_free (mime_infos);
+        }
       break;
 
     default:
@@ -190,6 +227,16 @@ thunar_vfs_info_new_for_uri (ThunarVfsURI *uri,
           if (G_LIKELY (str != NULL))
             info->hints[THUNAR_VFS_FILE_HINT_NAME] = g_strdup (str);
 
+          /* check if the desktop file refers to an application
+           * and has a non-NULL Exec field set.
+           */
+          str = xfce_rc_read_entry (rc, "Type", "Application");
+          if (G_LIKELY (exo_str_is_equal (str, "Application"))
+              && xfce_rc_read_entry (rc, "Exec", NULL) != NULL)
+            {
+              info->flags |= THUNAR_VFS_FILE_FLAGS_EXECUTABLE;
+            }
+
           /* close the file */
           xfce_rc_close (rc);
         }
@@ -269,6 +316,112 @@ thunar_vfs_info_unref (ThunarVfsInfo *info)
 
 
 /**
+ * thunar_vfs_info_execute:
+ * @info   : a #ThunarVfsInfo.
+ * @screen : a #GdkScreen or %NULL to use the default #GdkScreen.
+ * @uris   : the list of #ThunarVfsURI<!---->s to give as parameters
+ *           to the file referred to by @info on execution.
+ * @error  : return location for errors or %NULL.
+ *
+ * Executes the file referred to by @info, given @uris as parameters,
+ * on the specified @screen. @info may refer to either a regular,
+ * executable file, or a <filename>.desktop</filename> file, whose
+ * type is <literal>Application</literal>.
+ *
+ * Return value: %TRUE on success, else %FALSE.
+ **/
+gboolean
+thunar_vfs_info_execute (const ThunarVfsInfo *info,
+                         GdkScreen           *screen,
+                         GList               *uris,
+                         GError             **error)
+{
+  const gchar *icon;
+  const gchar *name;
+  const gchar *path;
+  gboolean     terminal;
+  gboolean     result = FALSE;
+  XfceRc      *rc;
+  gchar       *working_directory;
+  gchar       *path_escaped;
+  gchar      **argv = NULL;
+  gchar       *exec;
+
+  g_return_val_if_fail (info != NULL, FALSE);
+  g_return_val_if_fail (info->ref_count > 0, FALSE);
+  g_return_val_if_fail (screen == NULL || GDK_IS_SCREEN (screen), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  /* fallback to the default screen if none given */
+  if (G_UNLIKELY (screen == NULL))
+    screen = gdk_screen_get_default ();
+
+  /* determine the path */
+  path = thunar_vfs_uri_get_path (info->uri);
+
+  /* check if we have a .desktop file here */
+  if (G_UNLIKELY (strcmp (info->mime_info->name, "application/x-desktop") == 0))
+    {
+      rc = xfce_rc_simple_open (path, TRUE);
+      if (G_LIKELY (rc != NULL))
+        {
+          /* check if we have a valid Exec field */
+          exec = (gchar *) xfce_rc_read_entry_untranslated (rc, "Exec", NULL);
+          if (G_LIKELY (exec != NULL))
+            {
+              /* parse the Exec field */
+              name = xfce_rc_read_entry (rc, "Name", NULL);
+              icon = xfce_rc_read_entry_untranslated (rc, "Icon", NULL);
+              terminal = xfce_rc_read_bool_entry (rc, "Terminal", FALSE);
+              result = _thunar_vfs_sysdep_parse_exec (exec, uris, icon, name, path,
+                                                      terminal, NULL, &argv, error);
+            }
+          else
+            {
+              g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, _("No Exec field specified"));
+            }
+
+          /* close the rc file */
+          xfce_rc_close (rc);
+        }
+      else
+        {
+          g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, _("Unable to parse file"));
+        }
+    }
+  else
+    {
+      /* fake the Exec line */
+      path_escaped = g_shell_quote (path);
+      exec = g_strconcat (path_escaped, " %F", NULL);
+      result = _thunar_vfs_sysdep_parse_exec (exec, uris, NULL, NULL, NULL, FALSE, NULL, &argv, error);
+      g_free (path_escaped);
+      g_free (exec);
+    }
+
+  if (G_LIKELY (result))
+    {
+      /* determine the working directory */
+      working_directory = g_path_get_dirname ((uris != NULL) ?  thunar_vfs_uri_get_path (uris->data) : path);
+
+      /* execute the command */
+      result = gdk_spawn_on_screen (screen, working_directory, argv,
+                                    NULL, G_SPAWN_SEARCH_PATH, NULL,
+                                    NULL, NULL, error);
+
+      /* release the working directory */
+      g_free (working_directory);
+    }
+
+  /* clean up */
+  g_strfreev (argv);
+
+  return result;
+}
+
+
+
+/**
  * thunar_vfs_info_get_hint:
  * @info : a #ThunarVfsInfo.
  * @hint : a #ThunarVfsFileHint.
index 1ae3f75..eaa374b 100644 (file)
@@ -97,18 +97,21 @@ typedef enum { /*< flags >*/
 
 /**
  * ThunarVfsFileFlags:
- * @THUNAR_VFS_FILE_FLAGS_NONE    : No additional information available.
- * @THUNAR_VFS_FILE_FLAGS_SYMLINK : The file is a symlink. Whether or not
- *                                  the info fields refer to the symlink
- *                                  itself or the linked file, depends on 
- *                                  whether the symlink is broken or not.
+ * @THUNAR_VFS_FILE_FLAGS_NONE       : No additional information available.
+ * @THUNAR_VFS_FILE_FLAGS_SYMLINK    : The file is a symlink. Whether or not
+ *                                     the info fields refer to the symlink
+ *                                     itself or the linked file, depends on 
+ *                                     whether the symlink is broken or not.
+ * @THUNAR_VFS_FILE_FLAGS_EXECUTABLE : The file can most probably be executed
+ *                                     by #thunar_vfs_info_execute().
  *
  * Flags providing additional information about the
  * file system entity.
  **/
 typedef enum { /*< flags >*/
-  THUNAR_VFS_FILE_FLAGS_NONE    = 0,
-  THUNAR_VFS_FILE_FLAGS_SYMLINK = 1 << 0,
+  THUNAR_VFS_FILE_FLAGS_NONE       = 0,
+  THUNAR_VFS_FILE_FLAGS_SYMLINK    = 1L << 0,
+  THUNAR_VFS_FILE_FLAGS_EXECUTABLE = 1L << 1,
 } ThunarVfsFileFlags;
 
 /**
@@ -231,6 +234,11 @@ ThunarVfsInfo *thunar_vfs_info_new_for_uri (ThunarVfsURI        *uri,
 ThunarVfsInfo *thunar_vfs_info_ref         (ThunarVfsInfo       *info);
 void           thunar_vfs_info_unref       (ThunarVfsInfo       *info);
 
+gboolean       thunar_vfs_info_execute     (const ThunarVfsInfo *info,
+                                            GdkScreen           *screen,
+                                            GList               *uris,
+                                            GError             **error);
+
 const gchar   *thunar_vfs_info_get_hint    (const ThunarVfsInfo *info,
                                             ThunarVfsFileHint    hint);
 
index eae6fd5..96f7ef3 100644 (file)
@@ -30,6 +30,8 @@
 #endif
 
 #include <thunar-vfs/thunar-vfs-mime-application.h>
+#include <thunar-vfs/thunar-vfs-sysdep.h>
+#include <thunar-vfs/thunar-vfs-util.h>
 #include <thunar-vfs/thunar-vfs-alias.h>
 
 
@@ -157,141 +159,7 @@ thunar_vfs_mime_application_get_argv (const ThunarVfsMimeApplication *applicatio
                                       gchar                        ***argv,
                                       GError                        **error)
 {
-  const gchar *p;
-  gboolean     result;
-  GString     *command_line = g_string_new (NULL);
-  GList       *lp;
-  gchar       *uri_string;
-  gchar       *quoted;
-
-  /* prepend terminal command if required */
-  if (G_UNLIKELY (application->requires_terminal))
-    {
-      quoted = g_shell_quote (application->name);
-      g_string_append (command_line, "Terminal -T ");
-      g_string_append (command_line, quoted);
-      g_string_append (command_line, " -x ");
-      g_free (quoted);
-    }
-
-  for (p = application->exec; *p != '\0'; ++p)
-    {
-      if (p[0] == '%' && p[1] != '\0')
-        {
-          switch (*++p)
-            {
-            case 'f':
-              quoted = g_shell_quote (thunar_vfs_uri_get_path (uris->data));
-              g_string_append (command_line, quoted);
-              g_free (quoted);
-              break;
-
-            case 'F':
-              for (lp = uris; lp != NULL; lp = lp->next)
-                {
-                  if (G_LIKELY (lp != uris))
-                    g_string_append_c (command_line, ' ');
-                  quoted = g_shell_quote (thunar_vfs_uri_get_path (lp->data));
-                  g_string_append (command_line, quoted);
-                  g_free (quoted);
-                }
-              break;
-
-            case 'u':
-              /* we need to hide the host parameter here, because there are quite a few
-               * applications out there (namely GNOME applications), which cannot handle
-               * 'file:'-URIs with host names.
-               */
-              uri_string = thunar_vfs_uri_to_string (uris->data, THUNAR_VFS_URI_HIDE_HOST);
-              quoted = g_shell_quote (uri_string);
-              g_string_append (command_line, quoted);
-              g_free (uri_string);
-              g_free (quoted);
-              break;
-
-            case 'U':
-              for (lp = uris; lp != NULL; lp = lp->next)
-                {
-                  if (G_LIKELY (lp != uris))
-                    g_string_append_c (command_line, ' ');
-                  uri_string = thunar_vfs_uri_to_string (lp->data, THUNAR_VFS_URI_HIDE_HOST);
-                  quoted = g_shell_quote (uri_string);
-                  g_string_append (command_line, quoted);
-                  g_free (uri_string);
-                  g_free (quoted);
-                }
-              break;
-
-            case 'd':
-              uri_string = g_path_get_dirname (thunar_vfs_uri_get_path (uris->data));
-              quoted = g_shell_quote (uri_string);
-              g_string_append (command_line, quoted);
-              g_free (uri_string);
-              g_free (quoted);
-              break;
-
-            case 'D':
-              for (lp = uris; lp != NULL; lp = lp->next)
-                {
-                  if (G_LIKELY (lp != uris))
-                    g_string_append_c (command_line, ' ');
-                  uri_string = g_path_get_dirname (thunar_vfs_uri_get_path (lp->data));
-                  quoted = g_shell_quote (uri_string);
-                  g_string_append (command_line, quoted);
-                  g_free (uri_string);
-                  g_free (quoted);
-                }
-              break;
-
-            case 'n':
-              quoted = g_shell_quote (thunar_vfs_uri_get_name (uris->data));
-              g_string_append (command_line, quoted);
-              g_free (quoted);
-              break;
-
-            case 'N':
-              for (lp = uris; lp != NULL; lp = lp->next)
-                {
-                  if (G_LIKELY (lp != uris))
-                    g_string_append_c (command_line, ' ');
-                  quoted = g_shell_quote (thunar_vfs_uri_get_name (lp->data));
-                  g_string_append (command_line, quoted);
-                  g_free (quoted);
-                }
-              break;
-
-            case 'i':
-              if (G_LIKELY (application->icon != NULL))
-                {
-                  quoted = g_shell_quote (application->icon);
-                  g_string_append (command_line, "--icon ");
-                  g_string_append (command_line, quoted);
-                  g_free (quoted);
-                }
-              break;
-
-            case 'c':
-              quoted = g_shell_quote (application->name);
-              g_string_append (command_line, quoted);
-              g_free (quoted);
-              break;
-
-            case '%':
-              g_string_append_c (command_line, '%');
-              break;
-            }
-        }
-      else
-        {
-          g_string_append_c (command_line, *p);
-        }
-    }
-
-  result = g_shell_parse_argv (command_line->str, argc, argv, NULL);
-
-  g_string_free (command_line, TRUE);
-
-  return result;
+  return _thunar_vfs_sysdep_parse_exec (application->exec, uris, application->icon, application->name, NULL, application->requires_terminal, argc, argv, error);
 }
 
 
index 805719b..7651a48 100644 (file)
@@ -270,12 +270,29 @@ static ThunarVfsMimeInfo*
 thunar_vfs_mime_database_get_info_locked (ThunarVfsMimeDatabase *database,
                                           const gchar           *mime_type)
 {
-  ThunarVfsMimeInfo *info;
-  const gchar       *s;
-  const gchar       *t;
-  const gchar       *u;
-  gchar             *v;
-  guint              n;
+  ThunarVfsMimeProvider *provider;
+  ThunarVfsMimeInfo     *info;
+  const gchar           *s;
+  const gchar           *t;
+  const gchar           *u;
+  GList                 *lp;
+  gchar                 *v;
+  guint                  n;
+
+  /* unalias the mime type */
+  for (lp = database->providers; lp != NULL; lp = lp->next)
+    {
+      provider = THUNAR_VFS_MIME_PROVIDER_DATA (lp->data)->provider;
+      if (G_LIKELY (provider != NULL))
+        {
+          t = thunar_vfs_mime_provider_lookup_alias (provider, mime_type);
+          if (G_UNLIKELY (t != NULL && strcmp (mime_type, t) != 0))
+            {
+              mime_type = t;
+              break;
+            }
+        }
+    }
 
   /* check if we have a cached version of the mime type */
   info = g_hash_table_lookup (database->infos, mime_type);
@@ -446,7 +463,6 @@ thunar_vfs_mime_database_get_infos_for_info_locked (ThunarVfsMimeDatabase *datab
   ThunarVfsMimeProvider *provider;
   ThunarVfsMimeInfo     *parent_info;
   const gchar           *name = thunar_vfs_mime_info_get_name (info);
-  const gchar           *type;
   gchar                 *parents[128];
   GList                 *infos;
   GList                 *lp;
@@ -455,23 +471,6 @@ thunar_vfs_mime_database_get_infos_for_info_locked (ThunarVfsMimeDatabase *datab
   /* the info itself is of course on the list */
   infos = g_list_prepend (NULL, thunar_vfs_mime_info_ref (info));
 
-  /* check if the info is an alias */
-  for (lp = database->providers; lp != NULL; lp = lp->next)
-    {
-      provider = THUNAR_VFS_MIME_PROVIDER_DATA (lp->data)->provider;
-      if (G_LIKELY (provider != NULL))
-        {
-          type = thunar_vfs_mime_provider_lookup_alias (provider, name);
-          if (G_UNLIKELY (type != NULL && strcmp (name, type) != 0))
-            {
-              /* it is indeed an alias, so we use the unaliased type instead */
-              info = thunar_vfs_mime_database_get_info_locked (database, type);
-              name = thunar_vfs_mime_info_get_name (info);
-              infos = g_list_append (infos, info);
-            }
-        }
-    }
-
   /* lookup all parents on every provider */
   for (lp = database->providers; lp != NULL; lp = lp->next)
     {
@@ -1114,6 +1113,49 @@ thunar_vfs_mime_database_get_info_for_file (ThunarVfsMimeDatabase *database,
 
 
 /**
+ * thunar_vfs_mime_database_get_infos_for_info:
+ * @database : a #ThunarVfsMimeDatabase.
+ * @info     : a #ThunarVfsMimeInfo.
+ *
+ * Returns a list of all #ThunarVfsMimeInfo<!---->s,
+ * that are related to @info in @database. Currently
+ * this is the list of parent MIME-types for @info,
+ * as defined in the Shared Mime Database.
+ *
+ * Note that the returned list will also include
+ * a reference @info itself. In addition, this
+ * method also handles details specified by the
+ * Shared Mime Database Specification like the
+ * fact that every "text/xxxx" MIME-type is a
+ * subclass of "text/plain" and every MIME-type
+ * is a subclass of "application/octet-stream".
+ *
+ * The caller is responsible to free the returned
+ * list using #thunar_vfs_mime_info_list_free()
+ * when done with it.
+ *
+ * Return value: the list of #ThunarVfsMimeInfo<!---->s
+ *               related to @info.
+ **/
+GList*
+thunar_vfs_mime_database_get_infos_for_info (ThunarVfsMimeDatabase *database,
+                                             ThunarVfsMimeInfo     *info)
+{
+  GList *infos;
+
+  g_return_val_if_fail (THUNAR_VFS_IS_MIME_DATABASE (database), NULL);
+  g_return_val_if_fail (THUNAR_VFS_IS_MIME_INFO (info), NULL);
+
+  g_mutex_lock (database->lock);
+  infos = thunar_vfs_mime_database_get_infos_for_info_locked (database, info);
+  g_mutex_unlock (database->lock);
+
+  return infos;
+}
+
+
+
+/**
  * thunar_vfs_mime_database_get_applications:
  * @database : a #ThunarVfsMimeDatabase.
  * @info     : a #ThunarVfsMimeInfo.
index ec4d0aa..6d40121 100644 (file)
@@ -51,6 +51,9 @@ ThunarVfsMimeInfo        *thunar_vfs_mime_database_get_info_for_file        (Thu
                                                                              const gchar           *path,
                                                                              const gchar           *name);
 
+GList                    *thunar_vfs_mime_database_get_infos_for_info       (ThunarVfsMimeDatabase *database,
+                                                                             ThunarVfsMimeInfo     *info);
+
 GList                    *thunar_vfs_mime_database_get_applications         (ThunarVfsMimeDatabase *database,
                                                                              ThunarVfsMimeInfo     *info);
 ThunarVfsMimeApplication *thunar_vfs_mime_database_get_default_application  (ThunarVfsMimeDatabase *database,
index 46e8916..691b41a 100644 (file)
@@ -40,6 +40,8 @@
 #endif
 
 #include <thunar-vfs/thunar-vfs-sysdep.h>
+#include <thunar-vfs/thunar-vfs-uri.h>
+#include <thunar-vfs/thunar-vfs-alias.h>
 
 
 
@@ -113,3 +115,210 @@ _thunar_vfs_sysdep_readdir (gpointer        dirp,
 
 
 
+/**
+ * _thunar_vfs_sysdep_parse_exec:
+ * @exec     : the value of the <literal>Exec</literal> field.
+ * @uris     : the list of #ThunarVfsURI<!---->s.
+ * @icon     : value of the <literal>Icon</literal> field or %NULL.
+ * @name     : translated value for the <literal>Name</literal> field or %NULL.
+ * @path     : full path to the desktop file or %NULL.
+ * @terminal : whether to execute the command in a terminal.
+ * @argc     : return location for the number of items placed into @argv.
+ * @argv     : return location for the argument vector.
+ * @error    : return location for errors or %NULL.
+ *
+ * Substitutes <literal>Exec</literal> parameter variables according
+ * to the <ulink href="http://freedesktop.org/wiki/Standards_2fdesktop_2dentry_2dspec"
+ * type="http">Desktop Entry Specification</ulink> and returns the
+ * parsed argument vector (in @argv) and the number of items placed
+ * into @argv (in @argc).
+ *
+ * The @icon, @name and @path fields are optional and may be %NULL
+ * if you don't know their values. The @icon parameter should be
+ * the value of the <literal>Icon</literal> field from the desktop
+ * file, the @name parameter should be the translated <literal>Name</literal>
+ * value, while the @path parameter should refer to the full path
+ * to the desktop file, whose <literal>Exec</literal> field is
+ * being parsed here.
+ *
+ * Return value: %TRUE on success, else %FALSE.
+ **/
+gboolean
+_thunar_vfs_sysdep_parse_exec (const gchar *exec,
+                               GList       *uris,
+                               const gchar *icon,
+                               const gchar *name,
+                               const gchar *path,
+                               gboolean     terminal,
+                               gint        *argc,
+                               gchar     ***argv,
+                               GError     **error)
+{
+  const gchar *p;
+  gboolean     result;
+  GString     *command_line = g_string_new (NULL);
+  GList       *lp;
+  gchar       *uri_string;
+  gchar       *quoted;
+
+  /* prepend terminal command if required */
+  if (G_UNLIKELY (terminal))
+    {
+      g_string_append (command_line, "Terminal ");
+      if (G_LIKELY (name != NULL))
+        {
+          quoted = g_shell_quote (name);
+          g_string_append (command_line, "-T ");
+          g_string_append (command_line, quoted);
+          g_free (quoted);
+        }
+      g_string_append (command_line, "-x ");
+    }
+
+  for (p = exec; *p != '\0'; ++p)
+    {
+      if (p[0] == '%' && p[1] != '\0')
+        {
+          switch (*++p)
+            {
+            case 'f':
+              if (G_LIKELY (uris != NULL))
+                {
+                  quoted = g_shell_quote (thunar_vfs_uri_get_path (uris->data));
+                  g_string_append (command_line, quoted);
+                  g_free (quoted);
+                }
+              break;
+
+            case 'F':
+              for (lp = uris; lp != NULL; lp = lp->next)
+                {
+                  if (G_LIKELY (lp != uris))
+                    g_string_append_c (command_line, ' ');
+                  quoted = g_shell_quote (thunar_vfs_uri_get_path (lp->data));
+                  g_string_append (command_line, quoted);
+                  g_free (quoted);
+                }
+              break;
+
+            case 'u':
+              /* we need to hide the host parameter here, because there are quite a few
+               * applications out there (namely GNOME applications), which cannot handle
+               * 'file:'-URIs with host names.
+               */
+              if (G_LIKELY (uris != NULL))
+                {
+                  uri_string = thunar_vfs_uri_to_string (uris->data, THUNAR_VFS_URI_HIDE_HOST);
+                  quoted = g_shell_quote (uri_string);
+                  g_string_append (command_line, quoted);
+                  g_free (uri_string);
+                  g_free (quoted);
+                }
+              break;
+
+            case 'U':
+              for (lp = uris; lp != NULL; lp = lp->next)
+                {
+                  if (G_LIKELY (lp != uris))
+                    g_string_append_c (command_line, ' ');
+                  uri_string = thunar_vfs_uri_to_string (lp->data, THUNAR_VFS_URI_HIDE_HOST);
+                  quoted = g_shell_quote (uri_string);
+                  g_string_append (command_line, quoted);
+                  g_free (uri_string);
+                  g_free (quoted);
+                }
+              break;
+
+            case 'd':
+              if (G_LIKELY (uris != NULL))
+                {
+                  uri_string = g_path_get_dirname (thunar_vfs_uri_get_path (uris->data));
+                  quoted = g_shell_quote (uri_string);
+                  g_string_append (command_line, quoted);
+                  g_free (uri_string);
+                  g_free (quoted);
+                }
+              break;
+
+            case 'D':
+              for (lp = uris; lp != NULL; lp = lp->next)
+                {
+                  if (G_LIKELY (lp != uris))
+                    g_string_append_c (command_line, ' ');
+                  uri_string = g_path_get_dirname (thunar_vfs_uri_get_path (lp->data));
+                  quoted = g_shell_quote (uri_string);
+                  g_string_append (command_line, quoted);
+                  g_free (uri_string);
+                  g_free (quoted);
+                }
+              break;
+
+            case 'n':
+              if (G_LIKELY (uris != NULL))
+                {
+                  quoted = g_shell_quote (thunar_vfs_uri_get_name (uris->data));
+                  g_string_append (command_line, quoted);
+                  g_free (quoted);
+                }
+              break;
+
+            case 'N':
+              for (lp = uris; lp != NULL; lp = lp->next)
+                {
+                  if (G_LIKELY (lp != uris))
+                    g_string_append_c (command_line, ' ');
+                  quoted = g_shell_quote (thunar_vfs_uri_get_name (lp->data));
+                  g_string_append (command_line, quoted);
+                  g_free (quoted);
+                }
+              break;
+
+            case 'i':
+              if (G_LIKELY (icon != NULL))
+                {
+                  quoted = g_shell_quote (icon);
+                  g_string_append (command_line, "--icon ");
+                  g_string_append (command_line, quoted);
+                  g_free (quoted);
+                }
+              break;
+
+            case 'c':
+              if (G_LIKELY (name != NULL))
+                {
+                  quoted = g_shell_quote (name);
+                  g_string_append (command_line, quoted);
+                  g_free (quoted);
+                }
+              break;
+
+            case 'k':
+              if (G_LIKELY (path != NULL))
+                {
+                  quoted = g_shell_quote (path);
+                  g_string_append (command_line, path);
+                  g_free (quoted);
+                }
+              break;
+
+            case '%':
+              g_string_append_c (command_line, '%');
+              break;
+            }
+        }
+      else
+        {
+          g_string_append_c (command_line, *p);
+        }
+    }
+
+  result = g_shell_parse_argv (command_line->str, argc, argv, error);
+
+  g_string_free (command_line, TRUE);
+
+  return result;
+}
+
+
+
+
index 68534ce..64b6441 100644 (file)
 
 G_BEGIN_DECLS;
 
-gboolean _thunar_vfs_sysdep_readdir (gpointer        dirp,
-                                     struct dirent  *entry,
-                                     struct dirent **result,
-                                     GError        **error);
+/* forward declarations */
+struct dirent;
+
+gboolean _thunar_vfs_sysdep_readdir    (gpointer        dirp,
+                                        struct dirent  *entry,
+                                        struct dirent **result,
+                                        GError        **error);
+
+gboolean _thunar_vfs_sysdep_parse_exec (const gchar    *exec,
+                                        GList          *uris,
+                                        const gchar    *icon,
+                                        const gchar    *name,
+                                        const gchar    *path,
+                                        gboolean        terminal,
+                                        gint           *argc,
+                                        gchar        ***argv,
+                                        GError        **error)
 
 G_END_DECLS;
 
index c992999..7d54dd8 100644 (file)
@@ -52,6 +52,7 @@ thunar_vfs_unlink
 thunar_vfs_info_new_for_uri
 thunar_vfs_info_ref
 thunar_vfs_info_unref
+thunar_vfs_info_execute
 thunar_vfs_info_get_hint
 thunar_vfs_info_matches
 thunar_vfs_info_list_free
@@ -116,6 +117,7 @@ thunar_vfs_mime_database_get_info
 thunar_vfs_mime_database_get_info_for_data
 thunar_vfs_mime_database_get_info_for_name
 thunar_vfs_mime_database_get_info_for_file
+thunar_vfs_mime_database_get_infos_for_info
 thunar_vfs_mime_database_get_applications
 thunar_vfs_mime_database_get_default_application
 #endif
index a3c8316..c196b43 100644 (file)
@@ -47,12 +47,15 @@ static void               thunar_file_class_init               (ThunarFileClass
 static void               thunar_file_finalize                 (GObject                *object);
 static ThunarFile        *thunar_file_real_get_parent          (ThunarFile             *file,
                                                                 GError                **error);
+static gboolean           thunar_file_real_execute             (ThunarFile             *file,
+                                                                GdkScreen              *screen,
+                                                                GList                  *uris,
+                                                                GError                **error);
 static ThunarFolder      *thunar_file_real_open_as_folder      (ThunarFile             *file,
                                                                 GError                **error);
 static const gchar       *thunar_file_real_get_special_name    (ThunarFile             *file);
-static gboolean           thunar_file_real_can_execute         (ThunarFile             *file);
-static gboolean           thunar_file_real_can_read            (ThunarFile             *file);
-static gboolean           thunar_file_real_can_write           (ThunarFile             *file);
+static gboolean           thunar_file_real_is_readable         (ThunarFile             *file);
+static gboolean           thunar_file_real_is_writable         (ThunarFile             *file);
 static void               thunar_file_real_changed             (ThunarFile             *file);
 static ThunarFile        *thunar_file_new_internal             (ThunarVfsURI           *uri,
                                                                 GError                **error);
@@ -154,6 +157,7 @@ thunar_file_class_init (ThunarFileClass *klass)
 
   klass->has_parent = (gpointer) exo_noop_true;
   klass->get_parent = thunar_file_real_get_parent;
+  klass->execute = thunar_file_real_execute;
   klass->open_as_folder = thunar_file_real_open_as_folder;
   klass->get_mime_info = (gpointer) exo_noop_null;
   klass->get_special_name = thunar_file_real_get_special_name;
@@ -162,9 +166,9 @@ thunar_file_class_init (ThunarFileClass *klass)
   klass->get_volume = (gpointer) exo_noop_null;
   klass->get_group = (gpointer) exo_noop_null;
   klass->get_user = (gpointer) exo_noop_null;
-  klass->can_execute = thunar_file_real_can_execute;
-  klass->can_read = thunar_file_real_can_read;
-  klass->can_write = thunar_file_real_can_write;
+  klass->is_executable = (gpointer) exo_noop_false;
+  klass->is_readable = thunar_file_real_is_readable;
+  klass->is_writable = thunar_file_real_is_writable;
   klass->get_emblem_names = (gpointer) exo_noop_null;
   klass->reload = (gpointer) exo_noop;
   klass->changed = thunar_file_real_changed;
@@ -239,6 +243,18 @@ thunar_file_real_get_parent (ThunarFile *file,
 
 
 
+static gboolean
+thunar_file_real_execute (ThunarFile *file,
+                          GdkScreen  *screen,
+                          GList      *uris,
+                          GError    **error)
+{
+  g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (ENOEXEC), g_strerror (ENOEXEC));
+  return FALSE;
+}
+
+
+
 static ThunarFolder*
 thunar_file_real_open_as_folder (ThunarFile *file,
                                  GError    **error)
@@ -258,18 +274,7 @@ thunar_file_real_get_special_name (ThunarFile *file)
 
 
 static gboolean
-thunar_file_real_can_execute (ThunarFile *file)
-{
-  return !thunar_file_denies_access_permission (file,
-                                                THUNAR_VFS_FILE_MODE_USR_EXEC,
-                                                THUNAR_VFS_FILE_MODE_GRP_EXEC,
-                                                THUNAR_VFS_FILE_MODE_OTH_EXEC);
-}
-
-
-
-static gboolean
-thunar_file_real_can_read (ThunarFile *file)
+thunar_file_real_is_readable (ThunarFile *file)
 {
   return !thunar_file_denies_access_permission (file,
                                                 THUNAR_VFS_FILE_MODE_USR_READ,
@@ -280,7 +285,7 @@ thunar_file_real_can_read (ThunarFile *file)
 
 
 static gboolean
-thunar_file_real_can_write (ThunarFile *file)
+thunar_file_real_is_writable (ThunarFile *file)
 {
   return !thunar_file_denies_access_permission (file,
                                                 THUNAR_VFS_FILE_MODE_USR_WRITE,
@@ -552,6 +557,34 @@ thunar_file_get_parent (ThunarFile *file,
 
 
 /**
+ * thunar_file_execute:
+ * @file   : a #ThunarFile instance.
+ * @screen : a #GdkScreen.
+ * @uris   : the list of #ThunarVfsURI<!---->s to supply to @file on
+ *           execution.
+ * @error  : return location for errors or %NULL.
+ *
+ * Tries to execute @file on the specified @screen. If @file is executable
+ * and could have been spawned successfully, %TRUE is returned, else %FALSE
+ * will be returned and @error will be set to point to the error location.
+ *
+ * Return value: %TRUE on success, else %FALSE.
+ **/
+gboolean
+thunar_file_execute (ThunarFile *file,
+                     GdkScreen  *screen,
+                     GList      *uris,
+                     GError    **error)
+{
+  g_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+  return (*THUNAR_FILE_GET_CLASS (file)->execute) (file, screen, uris, error);
+}
+
+
+
+/**
  * thunar_file_open_as_folder:
  * @file  : a #ThunarFile instance.
  * @error : return location for errors or %NULL.
@@ -968,7 +1001,7 @@ thunar_file_get_user (ThunarFile *file)
 
 
 /**
- * thunar_file_can_execute:
+ * thunar_file_is_executable:
  * @file : a #ThunarFile instance.
  *
  * Determines whether the owner of the current process is allowed
@@ -976,7 +1009,7 @@ thunar_file_get_user (ThunarFile *file)
  * @file).
  *
  * If the specific #ThunarFile implementation does not provide
- * a custom #thunar_file_can_execute() method, the fallback
+ * a custom #thunar_file_is_executable() method, the fallback
  * method provided by #ThunarFile is used, which determines
  * whether the @file can be executed based on the data provided
  * by #thunar_file_get_mode(), #thunar_file_get_user() and
@@ -985,23 +1018,23 @@ thunar_file_get_user (ThunarFile *file)
  * Return value: %TRUE if @file can be executed.
  **/
 gboolean
-thunar_file_can_execute (ThunarFile *file)
+thunar_file_is_executable (ThunarFile *file)
 {
   g_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
-  return THUNAR_FILE_GET_CLASS (file)->can_execute (file);
+  return THUNAR_FILE_GET_CLASS (file)->is_executable (file);
 }
 
 
 
 /**
- * thunar_file_can_read:
+ * thunar_file_is_readable:
  * @file : a #ThunarFile instance.
  *
  * Determines whether the owner of the current process is allowed
  * to read the @file.
  *
  * If the specific #ThunarFile implementation does not provide
- * a custom #thunar_file_can_read() method, the fallback
+ * a custom #thunar_file_is_readable() method, the fallback
  * method provided by #ThunarFile is used, which determines
  * whether the @file can be read based on the data provided
  * by #thunar_file_get_mode(), #thunar_file_get_user() and
@@ -1010,23 +1043,23 @@ thunar_file_can_execute (ThunarFile *file)
  * Return value: %TRUE if @file can be read.
  **/
 gboolean
-thunar_file_can_read (ThunarFile *file)
+thunar_file_is_readable (ThunarFile *file)
 {
   g_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
-  return THUNAR_FILE_GET_CLASS (file)->can_read (file);
+  return THUNAR_FILE_GET_CLASS (file)->is_readable (file);
 }
 
 
 
 /**
- * thunar_file_can_write:
+ * thunar_file_is_writable:
  * @file : a #ThunarFile instance.
  *
  * Determines whether the owner of the current process is allowed
  * to write the @file.
  *
  * If the specific #ThunarFile implementation does not provide
- * a custom #thunar_file_can_write() method, the fallback
+ * a custom #thunar_file_is_writable() method, the fallback
  * method provided by #ThunarFile is used, which determines
  * whether the @file can be written based on the data provided
  * by #thunar_file_get_mode(), #thunar_file_get_user() and
@@ -1035,10 +1068,10 @@ thunar_file_can_read (ThunarFile *file)
  * Return value: %TRUE if @file can be read.
  **/
 gboolean
-thunar_file_can_write (ThunarFile *file)
+thunar_file_is_writable (ThunarFile *file)
 {
   g_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
-  return THUNAR_FILE_GET_CLASS (file)->can_write (file);
+  return THUNAR_FILE_GET_CLASS (file)->is_writable (file);
 }
 
 
index b23adfe..bf2d098 100644 (file)
@@ -71,6 +71,11 @@ struct _ThunarFileClass
   ThunarFile          *(*get_parent)          (ThunarFile             *file,
                                                GError                **error);
 
+  gboolean             (*execute)             (ThunarFile             *file,
+                                               GdkScreen              *screen,
+                                               GList                  *uris,
+                                               GError                **error);
+
   ThunarFolder        *(*open_as_folder)      (ThunarFile             *file,
                                                GError                **error);
 
@@ -95,9 +100,9 @@ struct _ThunarFileClass
   ThunarVfsGroup      *(*get_group)           (ThunarFile             *file);
   ThunarVfsUser       *(*get_user)            (ThunarFile             *file);
 
-  gboolean             (*can_execute)         (ThunarFile             *file);
-  gboolean             (*can_read)            (ThunarFile             *file);
-  gboolean             (*can_write)           (ThunarFile             *file);
+  gboolean             (*is_executable)       (ThunarFile             *file);
+  gboolean             (*is_readable)         (ThunarFile             *file);
+  gboolean             (*is_writable)         (ThunarFile             *file);
 
   GList               *(*get_emblem_names)    (ThunarFile             *file);
   const gchar         *(*get_icon_name)       (ThunarFile             *file,
@@ -135,6 +140,11 @@ gboolean           thunar_file_has_parent       (ThunarFile             *file);
 ThunarFile        *thunar_file_get_parent       (ThunarFile             *file,
                                                  GError                **error);
 
+gboolean           thunar_file_execute          (ThunarFile             *file,
+                                                 GdkScreen              *screen,
+                                                 GList                  *uris,
+                                                 GError                **error);
+
 ThunarFolder      *thunar_file_open_as_folder   (ThunarFile             *file,
                                                  GError                **error);
 
@@ -164,9 +174,9 @@ ThunarVfsVolume   *thunar_file_get_volume       (ThunarFile             *file,
 ThunarVfsGroup    *thunar_file_get_group        (ThunarFile             *file);
 ThunarVfsUser     *thunar_file_get_user         (ThunarFile             *file);
 
-gboolean          thunar_file_can_execute       (ThunarFile             *file);
-gboolean          thunar_file_can_read          (ThunarFile             *file);
-gboolean          thunar_file_can_write         (ThunarFile             *file);
+gboolean          thunar_file_is_executable     (ThunarFile             *file);
+gboolean          thunar_file_is_readable       (ThunarFile             *file);
+gboolean          thunar_file_is_writable       (ThunarFile             *file);
 
 GList             *thunar_file_get_emblem_names (ThunarFile             *file);
 GdkPixbuf         *thunar_file_load_icon        (ThunarFile             *file,
index a49f93e..852bf8f 100644 (file)
@@ -55,6 +55,8 @@ static void thunar_launcher_set_property              (GObject
                                                        guint                     prop_id,
                                                        const GValue             *value,
                                                        GParamSpec               *pspec);
+static void thunar_launcher_execute_files             (ThunarLauncher           *launcher,
+                                                       GList                    *files);
 static void thunar_launcher_open_uris                 (ThunarVfsMimeApplication *application,
                                                        GList                    *uri_list,
                                                        ThunarLauncher           *launcher);
@@ -284,6 +286,47 @@ thunar_launcher_set_property (GObject      *object,
 
 
 static void
+thunar_launcher_execute_files (ThunarLauncher *launcher,
+                               GList          *files)
+{
+  ThunarFile *file;
+  GtkWidget  *message;
+  GtkWidget  *window;
+  GdkScreen  *screen;
+  GError     *error = NULL;
+  GList      *lp;
+
+  /* determine the screen on which to run the file(s) */
+  screen = (launcher->widget != NULL)
+         ? gtk_widget_get_screen (launcher->widget)
+         : gdk_screen_get_default ();
+
+  /* execute all selected files */
+  for (lp = files; lp != NULL; lp = lp->next)
+    {
+      file = THUNAR_FILE (lp->data);
+      if (!thunar_file_execute (file, screen, NULL, &error))
+        {
+          window = (launcher->widget != NULL) ? gtk_widget_get_toplevel (launcher->widget) : NULL;
+          message = gtk_message_dialog_new ((GtkWindow *) window,
+                                            GTK_DIALOG_MODAL
+                                            | GTK_DIALOG_DESTROY_WITH_PARENT,
+                                            GTK_MESSAGE_ERROR,
+                                            GTK_BUTTONS_OK,
+                                            _("Unable to execute file \"%s\"."),
+                                            thunar_file_get_display_name (file));
+          gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (message), "%s.", error->message);
+          gtk_dialog_run (GTK_DIALOG (message));
+          gtk_widget_destroy (message);
+          g_error_free (error);
+          break;
+        }
+    }
+}
+
+
+
+static void
 thunar_launcher_open_uris (ThunarVfsMimeApplication *application,
                            GList                    *uri_list,
                            ThunarLauncher           *launcher)
@@ -460,6 +503,7 @@ thunar_launcher_update (ThunarLauncher *launcher)
   GList *lp;
   gchar  text[256];
   gint   n_directories = 0;
+  gint   n_executables = 0;
   gint   n_files = 0;
   gint   n_items;
 
@@ -471,9 +515,15 @@ thunar_launcher_update (ThunarLauncher *launcher)
   for (lp = items; lp != NULL; lp = lp->next)
     {
       if (thunar_file_is_directory (lp->data))
-        ++n_directories;
+        {
+          ++n_directories;
+        }
       else
-        ++n_files;
+        {
+          if (thunar_file_is_executable (lp->data))
+            ++n_executables;
+          ++n_files;
+        }
     }
 
   if (G_UNLIKELY (n_directories == n_items))
@@ -496,6 +546,12 @@ thunar_launcher_update (ThunarLauncher *launcher)
     }
   else
     {
+      /* we turn the "Open" label into "Execute" if we have only one executable file */
+      if (G_UNLIKELY (n_executables == 1 && n_items == 1))
+        g_object_set (G_OBJECT (launcher->action_open), "label", _("Execute"), NULL);
+      else
+        g_object_set (G_OBJECT (launcher->action_open), "label", _("Open"), NULL);
+
 #if GTK_CHECK_VERSION(2,6,0)
       gtk_action_set_sensitive (launcher->action_open, (n_items > 0));
       gtk_action_set_visible (launcher->action_open_in_new_window, FALSE);
@@ -548,7 +604,10 @@ thunar_launcher_action_open (GtkAction      *action,
   /* open the files */
   if (files != NULL)
     {
-      thunar_launcher_open_files (launcher, files);
+      if (g_list_length (files) == 1 && thunar_file_is_executable (files->data))
+        thunar_launcher_execute_files (launcher, files);
+      else
+        thunar_launcher_open_files (launcher, files);
       thunar_file_list_free (files);
     }
 }
index 1745872..b0f2bdb 100644 (file)
@@ -30,6 +30,10 @@ static void               thunar_local_file_class_init        (ThunarLocalFileCl
 static void               thunar_local_file_finalize          (GObject                *object);
 static ThunarFile        *thunar_local_file_get_parent        (ThunarFile             *file,
                                                                GError                **error);
+static gboolean           thunar_local_file_execute           (ThunarFile             *file,
+                                                               GdkScreen              *screen,
+                                                               GList                  *uris,
+                                                               GError                **error);
 static ThunarFolder      *thunar_local_file_open_as_folder    (ThunarFile             *file,
                                                                GError                **error);
 static ThunarVfsURI      *thunar_local_file_get_uri           (ThunarFile             *file);
@@ -47,6 +51,7 @@ static ThunarVfsVolume   *thunar_local_file_get_volume        (ThunarFile
                                                                ThunarVfsVolumeManager *volume_manager);
 static ThunarVfsGroup    *thunar_local_file_get_group         (ThunarFile             *file);
 static ThunarVfsUser     *thunar_local_file_get_user          (ThunarFile             *file);
+static gboolean           thunar_local_file_is_executable     (ThunarFile             *file);
 static GList             *thunar_local_file_get_emblem_names  (ThunarFile             *file);
 static const gchar       *thunar_local_file_get_icon_name     (ThunarFile             *file,
                                                                GtkIconTheme           *icon_theme);
@@ -133,6 +138,7 @@ thunar_local_file_class_init (ThunarLocalFileClass *klass)
 
   thunarfile_class = THUNAR_FILE_CLASS (klass);
   thunarfile_class->get_parent = thunar_local_file_get_parent;
+  thunarfile_class->execute = thunar_local_file_execute;
   thunarfile_class->open_as_folder = thunar_local_file_open_as_folder;
   thunarfile_class->get_uri = thunar_local_file_get_uri;
   thunarfile_class->get_mime_info = thunar_local_file_get_mime_info;
@@ -145,6 +151,7 @@ thunar_local_file_class_init (ThunarLocalFileClass *klass)
   thunarfile_class->get_volume = thunar_local_file_get_volume;
   thunarfile_class->get_group = thunar_local_file_get_group;
   thunarfile_class->get_user = thunar_local_file_get_user;
+  thunarfile_class->is_executable = thunar_local_file_is_executable;
   thunarfile_class->get_emblem_names = thunar_local_file_get_emblem_names;
   thunarfile_class->get_icon_name = thunar_local_file_get_icon_name;
   thunarfile_class->watch = thunar_local_file_watch;
@@ -206,6 +213,18 @@ thunar_local_file_get_parent (ThunarFile *file,
 
 
 
+static gboolean
+thunar_local_file_execute (ThunarFile *file,
+                           GdkScreen  *screen,
+                           GList      *uris,
+                           GError    **error)
+{
+  ThunarLocalFile *local_file = THUNAR_LOCAL_FILE (file);
+  return thunar_vfs_info_execute (local_file->info, screen, uris, error);
+}
+
+
+
 static ThunarFolder*
 thunar_local_file_open_as_folder (ThunarFile *file,
                                   GError    **error)
@@ -352,6 +371,15 @@ thunar_local_file_get_user (ThunarFile *file)
 
 
 
+static gboolean
+thunar_local_file_is_executable (ThunarFile *file)
+{
+  ThunarLocalFile *local_file = THUNAR_LOCAL_FILE (file);
+  return ((local_file->info->flags & THUNAR_VFS_FILE_FLAGS_EXECUTABLE) != 0);
+}
+
+
+
 static GList*
 thunar_local_file_get_emblem_names (ThunarFile *file)
 {
@@ -371,7 +399,7 @@ thunar_local_file_get_emblem_names (ThunarFile *file)
   if ((info->flags & THUNAR_VFS_FILE_FLAGS_SYMLINK) != 0)
     emblems = g_list_prepend (emblems, THUNAR_FILE_EMBLEM_NAME_SYMBOLIC_LINK);
 
-  if (!thunar_file_can_read (file))
+  if (!thunar_file_is_readable (file))
     emblems = g_list_prepend (emblems, THUNAR_FILE_EMBLEM_NAME_CANT_READ);
 
   return emblems;
index 5b5d97a..9d18a97 100644 (file)
@@ -1172,7 +1172,7 @@ thunar_standard_view_selection_changed (ThunarStandardView *standard_view)
 
   /* check whether the folder displayed by the view is writable */
   current_directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (standard_view));
-  writable = (current_directory != NULL && thunar_file_can_write (current_directory));
+  writable = (current_directory != NULL && thunar_file_is_writable (current_directory));
 
   /* check whether the clipboard contains data that can be pasted here */
   pastable = (standard_view->clipboard != NULL && thunar_clipboard_manager_get_can_paste (standard_view->clipboard));
@@ -1185,7 +1185,7 @@ thunar_standard_view_selection_changed (ThunarStandardView *standard_view)
    * folder to which we can paste to */
   can_paste_into_folder = (n_selected_files == 1)
                        && thunar_file_is_directory (selected_files->data)
-                       && thunar_file_can_write (selected_files->data);
+                       && thunar_file_is_writable (selected_files->data);
 
   /* update the "Properties" action */
   gtk_action_set_sensitive (standard_view->priv->action_properties, (n_selected_files == 1));