From bc9ee06dac31c1a6e214e325f1234d3d9802bf3c Mon Sep 17 00:00:00 2001
From: Sergios - Anestis Kefalidis <sergioskefalidis@gmail.com>
Date: Wed, 30 Jun 2021 22:54:32 +0300
Subject: [PATCH] Add support for the `recent:///` location in Thunar.

Fixes duplicated files in `recent:///`
Support sorting by `Recency`
Add the recent location to the sidepane and go menu
Automatically add opened files to `recent:///`
Add a `Remove from recent` option for files in `recent:///`

Issue #257
MR !115
---
 thunar/thunar-chooser-dialog.c    | 11 ++++-
 thunar/thunar-details-view.c      | 10 ++++
 thunar/thunar-details-view.h      |  1 +
 thunar/thunar-enum-types.c        |  1 +
 thunar/thunar-enum-types.h        |  1 +
 thunar/thunar-file.c              | 79 ++++++++++++++++++++++++++++--
 thunar/thunar-file.h              |  7 +++
 thunar/thunar-gio-extensions.c    | 34 +++++++++++++
 thunar/thunar-gio-extensions.h    |  3 ++
 thunar/thunar-io-scan-directory.c | 12 +++--
 thunar/thunar-launcher.c          | 78 ++++++++++++++++++++++-------
 thunar/thunar-launcher.h          |  1 +
 thunar/thunar-list-model.c        | 81 +++++++++++++++++--------------
 thunar/thunar-menu.c              |  5 ++
 thunar/thunar-menu.h              | 31 ++++++------
 thunar/thunar-shortcuts-model.c   | 13 +++++
 thunar/thunar-shortcuts-model.h   | 22 +++++----
 thunar/thunar-standard-view.c     |  1 +
 thunar/thunar-tree-model.c        |  3 ++
 thunar/thunar-window.c            | 55 +++++++++++++++++++++
 thunar/thunar-window.h            |  1 +
 thunarx/thunarx-file-info.h       |  1 +
 22 files changed, 362 insertions(+), 89 deletions(-)

diff --git a/thunar/thunar-chooser-dialog.c b/thunar/thunar-chooser-dialog.c
index f57518785..e8bda691b 100644
--- a/thunar/thunar-chooser-dialog.c
+++ b/thunar/thunar-chooser-dialog.c
@@ -505,6 +505,12 @@ thunar_chooser_dialog_response (GtkDialog *widget,
   /* check if we should also execute the application */
   if (G_LIKELY (succeed && dialog->open))
     {
+      GFile *gfile;
+      gchar *uri;
+
+      gfile = thunar_file_get_file (dialog->file); list.next = list.prev = NULL;
+      uri = g_file_get_uri (gfile);
+
       /* create launch context */
       screen = gtk_widget_get_screen (GTK_WIDGET (dialog));
       context = gdk_display_get_app_launch_context (gdk_screen_get_display (screen));
@@ -512,7 +518,10 @@ thunar_chooser_dialog_response (GtkDialog *widget,
       gdk_app_launch_context_set_timestamp (context, gtk_get_current_event_time ());
 
       /* create fake file list */
-      list.data = thunar_file_get_file (dialog->file); list.next = list.prev = NULL;
+      list.data = gfile;
+
+      gtk_recent_manager_add_item (gtk_recent_manager_get_default(), uri);
+      g_free (uri);
 
       if (!g_app_info_launch (app_info, &list, G_APP_LAUNCH_CONTEXT (context), &error))
         {
diff --git a/thunar/thunar-details-view.c b/thunar/thunar-details-view.c
index ff6e0c28a..c42a6cf52 100644
--- a/thunar/thunar-details-view.c
+++ b/thunar/thunar-details-view.c
@@ -1077,3 +1077,13 @@ thunar_details_view_set_date_deleted_column_visible (ThunarDetailsView *details_
 {
   thunar_column_model_set_column_visible (details_view->column_model, THUNAR_COLUMN_DATE_DELETED, visible);
 }
+
+
+
+void
+thunar_details_view_set_recency_column_visible      (ThunarDetailsView *details_view,
+                                                     gboolean           visible)
+{
+  thunar_column_model_set_column_visible (details_view->column_model, THUNAR_COLUMN_RECENCY, visible);
+}
+
diff --git a/thunar/thunar-details-view.h b/thunar/thunar-details-view.h
index f7f45597f..835541c86 100644
--- a/thunar/thunar-details-view.h
+++ b/thunar/thunar-details-view.h
@@ -42,6 +42,7 @@ typedef enum
 
 GType      thunar_details_view_get_type                         (void) G_GNUC_CONST;
 void       thunar_details_view_set_date_deleted_column_visible  (ThunarDetailsView*, gboolean);
+void       thunar_details_view_set_recency_column_visible       (ThunarDetailsView*, gboolean);
 
 G_END_DECLS;
 
diff --git a/thunar/thunar-enum-types.c b/thunar/thunar-enum-types.c
index 0db00b441..f79f19377 100644
--- a/thunar/thunar-enum-types.c
+++ b/thunar/thunar-enum-types.c
@@ -103,6 +103,7 @@ thunar_column_get_type (void)
         { THUNAR_COLUMN_DATE_ACCESSED, "THUNAR_COLUMN_DATE_ACCESSED", N_ ("Date Accessed"), },
         { THUNAR_COLUMN_DATE_MODIFIED, "THUNAR_COLUMN_DATE_MODIFIED", N_ ("Date Modified"), },
         { THUNAR_COLUMN_DATE_DELETED,  "THUNAR_COLUMN_DATE_DELETED",  N_ ("Date Deleted"),  },
+        { THUNAR_COLUMN_RECENCY,       "THUNAR_COLUMN_RECENCY",       N_ ("Recency"),       },
         { THUNAR_COLUMN_GROUP,         "THUNAR_COLUMN_GROUP",         N_ ("Group"),         },
         { THUNAR_COLUMN_MIME_TYPE,     "THUNAR_COLUMN_MIME_TYPE",     N_ ("MIME Type"),     },
         { THUNAR_COLUMN_NAME,          "THUNAR_COLUMN_NAME",          N_ ("Name"),          },
diff --git a/thunar/thunar-enum-types.h b/thunar/thunar-enum-types.h
index e6dacc88b..5fe3960bb 100644
--- a/thunar/thunar-enum-types.h
+++ b/thunar/thunar-enum-types.h
@@ -101,6 +101,7 @@ typedef enum
   THUNAR_COLUMN_DATE_ACCESSED,
   THUNAR_COLUMN_DATE_MODIFIED,
   THUNAR_COLUMN_DATE_DELETED,
+  THUNAR_COLUMN_RECENCY,
   THUNAR_COLUMN_GROUP,
   THUNAR_COLUMN_MIME_TYPE,
   THUNAR_COLUMN_NAME,
diff --git a/thunar/thunar-file.c b/thunar/thunar-file.c
index 25662ea95..7f55d7d56 100644
--- a/thunar/thunar-file.c
+++ b/thunar/thunar-file.c
@@ -164,6 +164,7 @@ struct _ThunarFile
 
   /* storage for the file information */
   GFileInfo            *info;
+  GFileInfo            *recent_info;
   GFileType             kind;
   GFile                *gfile;
   gchar                *content_type;
@@ -445,6 +446,10 @@ thunar_file_finalize (GObject *object)
   if (file->info != NULL)
     g_object_unref (file->info);
 
+  /* release file info */
+  if (file->recent_info != NULL)
+    g_object_unref (file->recent_info);
+
   /* free the custom icon name */
   g_free (file->custom_icon_name);
 
@@ -1299,6 +1304,7 @@ thunar_file_get (GFile   *gfile,
  * thunar_file_get_with_info:
  * @uri         : an URI or an absolute filename.
  * @info        : #GFileInfo to use when loading the info.
+ * @recent_info : additional #GFileInfo to use when loading the info, only for files in `recent:///`.
  * @not_mounted : if the file is mounted.
  *
  * Looks up the #ThunarFile referred to by @file. This function may return a
@@ -1316,6 +1322,7 @@ thunar_file_get (GFile   *gfile,
 ThunarFile *
 thunar_file_get_with_info (GFile     *gfile,
                            GFileInfo *info,
+                           GFileInfo *recent_info,
                            gboolean   not_mounted)
 {
   ThunarFile *file;
@@ -1360,14 +1367,15 @@ thunar_file_get_with_info (GFile     *gfile,
       /* done inserting in the cache */
       G_UNLOCK (file_cache_mutex);
     }
+    
+  if (recent_info != NULL)
+    file->recent_info = g_object_ref (recent_info);
 
   return file;
 }
 
 
 
-
-
 /**
  * thunar_file_get_for_uri:
  * @uri   : an URI or an absolute filename.
@@ -2127,6 +2135,8 @@ thunar_file_get_date (const ThunarFile  *file,
       date = g_date_time_to_unix (datetime);
       g_date_time_unref (datetime);
       return date;
+    case THUNAR_FILE_RECENCY:
+      return g_file_info_get_attribute_int64 (file->recent_info ? file->recent_info : file->info, G_FILE_ATTRIBUTE_RECENT_MODIFIED);
 
     default:
       _thunar_assert_not_reached ();
@@ -3066,6 +3076,32 @@ thunar_file_is_trashed (const ThunarFile *file)
 
 
 
+/**
+ * thunar_file_is_recent:
+ * @file : a #ThunarFile instance.
+ *
+ * Returns %TRUE if @file is the recent folder.
+ *
+ * Return value: %TRUE if @file is the recent folder bin
+ **/
+gboolean
+thunar_file_is_recent (const ThunarFile *file)
+{
+  _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
+  return thunar_g_file_is_recent (file->gfile);
+}
+
+
+
+gboolean
+thunar_file_is_in_recent (const ThunarFile *file)
+{
+  _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
+  return thunar_g_file_is_in_recent (file->gfile);
+}
+
+
+
 /**
  * thunar_file_is_desktop_file:
  * @file      : a #ThunarFile.
@@ -3195,6 +3231,43 @@ thunar_file_get_deletion_date (const ThunarFile *file,
 
 
 
+/**
+ * thunar_file_get_recency:
+ * @file       : a #ThunarFile instance.
+ * @date_style : the style used to format the date.
+ * @date_custom_style : custom style to apply, if @date_style is set to custom
+ *
+ * Returns the recency date of the @file if the @file
+ * is in the `recent:///` location. Recency differs from date accessed and date
+ * modified. It refers to the time of the last metadata change of a file in `recent:///`.
+ *
+ * Return value: the recency date of @file if @file is
+ *               in `recent:///`, %NULL otherwise.
+ **/
+gchar*
+thunar_file_get_recency       (const ThunarFile *file,
+                               ThunarDateStyle   date_style,
+                               const gchar      *date_custom_style)
+{
+  const gchar *date;
+  time_t       recency_time;
+
+  _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL);
+  _thunar_return_val_if_fail (G_IS_FILE_INFO (file->recent_info), NULL);
+
+  date = g_file_info_get_attribute_string (file->recent_info, G_FILE_ATTRIBUTE_RECENT_MODIFIED);
+  if (G_UNLIKELY (date == NULL))
+    return NULL;
+
+  /* try to parse the DeletionDate (RFC 3339 string) */
+  recency_time = thunar_util_time_from_rfc3339 (date);
+
+  /* humanize the time value */
+  return thunar_util_humanize_file_time (recency_time, date_style, date_custom_style);
+}
+
+
+
 /**
  * thunar_file_get_original_path:
  * @file : a #ThunarFile instance.
@@ -3374,7 +3447,7 @@ thunar_file_get_emblem_names (ThunarFile *file)
     {
       emblems = g_list_prepend (emblems, THUNAR_FILE_EMBLEM_NAME_CANT_READ);
     }
-  else if (G_UNLIKELY (uid == effective_user_id && !thunar_file_is_writable (file) && !thunar_file_is_trashed (file)))
+  else if (G_UNLIKELY (uid == effective_user_id && !thunar_file_is_writable (file) && !thunar_file_is_trashed (file) && !thunar_file_is_in_recent (file)))
     {
       /* we own the file, but we cannot write to it, that's why we mark it as "cant-write", so
        * users won't be surprised when opening the file in a text editor, but are unable to save.
diff --git a/thunar/thunar-file.h b/thunar/thunar-file.h
index 74bf13e4e..6fb43cbb8 100644
--- a/thunar/thunar-file.h
+++ b/thunar/thunar-file.h
@@ -60,6 +60,7 @@ typedef enum
   THUNAR_FILE_DATE_CREATED,
   THUNAR_FILE_DATE_MODIFIED,
   THUNAR_FILE_DATE_DELETED,
+  THUNAR_FILE_RECENCY,
 } ThunarFileDateType;
 
 /**
@@ -124,6 +125,7 @@ ThunarFile       *thunar_file_get                        (GFile
                                                           GError                **error);
 ThunarFile       *thunar_file_get_with_info              (GFile                  *file,
                                                           GFileInfo              *info,
+                                                          GFileInfo              *recent_info,
                                                           gboolean                not_mounted);
 ThunarFile       *thunar_file_get_for_uri                (const gchar            *uri,
                                                           GError                **error);
@@ -213,6 +215,8 @@ gboolean          thunar_file_is_home                    (const ThunarFile
 gboolean          thunar_file_is_regular                 (const ThunarFile       *file) G_GNUC_PURE;
 gboolean          thunar_file_is_trash                   (const ThunarFile       *file);
 gboolean          thunar_file_is_trashed                 (const ThunarFile       *file);
+gboolean          thunar_file_is_recent                  (const ThunarFile       *file);
+gboolean          thunar_file_is_in_recent               (const ThunarFile       *file);
 gboolean          thunar_file_is_desktop_file            (const ThunarFile       *file,
                                                           gboolean               *is_secure);
 const gchar      *thunar_file_get_display_name           (const ThunarFile       *file) G_GNUC_CONST;
@@ -220,6 +224,9 @@ const gchar      *thunar_file_get_display_name           (const ThunarFile
 gchar            *thunar_file_get_deletion_date          (const ThunarFile       *file,
                                                           ThunarDateStyle         date_style,
                                                           const gchar            *date_custom_style) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+gchar            *thunar_file_get_recency                (const ThunarFile       *file,
+                                                          ThunarDateStyle         date_style,
+                                                          const gchar            *date_custom_style) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
 const gchar      *thunar_file_get_original_path          (const ThunarFile       *file);
 guint32           thunar_file_get_item_count             (const ThunarFile       *file);
 
diff --git a/thunar/thunar-gio-extensions.c b/thunar/thunar-gio-extensions.c
index 394a1032e..a6f5e595b 100644
--- a/thunar/thunar-gio-extensions.c
+++ b/thunar/thunar-gio-extensions.c
@@ -94,6 +94,14 @@ thunar_g_file_new_for_root (void)
 
 
 
+GFile *
+thunar_g_file_new_for_recent (void)
+{
+  return g_file_new_for_uri ("recent:///");
+}
+
+
+
 GFile *
 thunar_g_file_new_for_trash (void)
 {
@@ -152,6 +160,15 @@ thunar_g_file_is_trashed (GFile *file)
 
 
 
+gboolean
+thunar_g_file_is_in_recent (GFile *file)
+{
+  _thunar_return_val_if_fail (G_IS_FILE (file), FALSE);
+  return g_file_has_uri_scheme (file, "recent");
+}
+
+
+
 gboolean
 thunar_g_file_is_home (GFile *file)
 {
@@ -186,6 +203,23 @@ thunar_g_file_is_trash (GFile *file)
 
 
 
+gboolean
+thunar_g_file_is_recent (GFile *file)
+{
+  char *uri;
+  gboolean is_recent = FALSE;
+
+  _thunar_return_val_if_fail (G_IS_FILE (file), FALSE);
+
+  uri = g_file_get_uri (file);
+  is_recent = g_strcmp0 (uri, "recent:///") == 0;
+  g_free (uri);
+
+  return is_recent;
+}
+
+
+
 gboolean
 thunar_g_file_is_computer (GFile *file)
 {
diff --git a/thunar/thunar-gio-extensions.h b/thunar/thunar-gio-extensions.h
index 5b183971d..226022c59 100644
--- a/thunar/thunar-gio-extensions.h
+++ b/thunar/thunar-gio-extensions.h
@@ -27,6 +27,7 @@ G_BEGIN_DECLS
 
 GFile       *thunar_g_file_new_for_home             (void);
 GFile       *thunar_g_file_new_for_root             (void);
+GFile       *thunar_g_file_new_for_recent           (void);
 GFile       *thunar_g_file_new_for_trash            (void);
 GFile       *thunar_g_file_new_for_desktop          (void);
 GFile       *thunar_g_file_new_for_computer         (void);
@@ -34,8 +35,10 @@ GFile       *thunar_g_file_new_for_bookmarks        (void);
 
 gboolean     thunar_g_file_is_root                  (GFile                *file);
 gboolean     thunar_g_file_is_trashed               (GFile                *file);
+gboolean     thunar_g_file_is_in_recent             (GFile                *file);
 gboolean     thunar_g_file_is_home                  (GFile                *file);
 gboolean     thunar_g_file_is_trash                 (GFile                *file);
+gboolean     thunar_g_file_is_recent                (GFile                *file);
 gboolean     thunar_g_file_is_computer              (GFile                *file);
 gboolean     thunar_g_file_is_network               (GFile                *file);
 
diff --git a/thunar/thunar-io-scan-directory.c b/thunar/thunar-io-scan-directory.c
index 9be7cbb81..bc14628b2 100644
--- a/thunar/thunar-io-scan-directory.c
+++ b/thunar/thunar-io-scan-directory.c
@@ -44,6 +44,7 @@ thunar_io_scan_directory (ThunarJob          *job,
 {
   GFileEnumerator *enumerator;
   GFileInfo       *info;
+  GFileInfo       *recent_info;
   GFileType        type;
   GError          *err = NULL;
   GFile           *child_file;
@@ -92,7 +93,7 @@ thunar_io_scan_directory (ThunarJob          *job,
     namespace = THUNARX_FILE_INFO_NAMESPACE;
   else
     namespace = G_FILE_ATTRIBUTE_STANDARD_TYPE ","
-                G_FILE_ATTRIBUTE_STANDARD_NAME;
+                G_FILE_ATTRIBUTE_STANDARD_NAME ", recent::*";
 
   /* try to read from the direectory */
   enumerator = g_file_enumerate_children (file, namespace,
@@ -129,26 +130,27 @@ thunar_io_scan_directory (ThunarJob          *job,
             }
         }
 
-      /* check if file has 'recent' URI scheme */
+      /* check if we are scanning `recent:///` */
       if (g_file_has_uri_scheme (file, "recent"))
         {
           /* create Gfile using the target URI */
-          child_file = g_file_new_for_uri(g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI));
+          child_file = g_file_new_for_uri (g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI));
 
           /* create new file info using Gfile*/
-          g_object_unref(info);
+          recent_info = info;
           info = g_file_query_info (child_file, namespace, flags, cancellable, &err);
         }
       else
         {
           /* create GFile for the child */
           child_file = g_file_get_child (file, g_file_info_get_name (info));
+          recent_info = NULL;
         }
 
       if (return_thunar_files)
         {
           /* Prepend the ThunarFile */
-          thunar_file = thunar_file_get_with_info (child_file, info, !is_mounted);
+          thunar_file = thunar_file_get_with_info (child_file, info, recent_info, !is_mounted);
           files = thunar_g_list_prepend_deep (files, thunar_file);
           g_object_unref (G_OBJECT (thunar_file));
         }
diff --git a/thunar/thunar-launcher.c b/thunar/thunar-launcher.c
index d04b26117..26a4d37a1 100644
--- a/thunar/thunar-launcher.c
+++ b/thunar/thunar-launcher.c
@@ -185,6 +185,7 @@ static void                    thunar_launcher_action_rename              (Thuna
 static void                    thunar_launcher_action_move_to_trash       (ThunarLauncher                 *launcher);
 static void                    thunar_launcher_action_delete              (ThunarLauncher                 *launcher);
 static void                    thunar_launcher_action_trash_delete        (ThunarLauncher                 *launcher);
+static void                    thunar_launcher_action_remove_from_recent  (ThunarLauncher                 *launcher);
 static void                    thunar_launcher_action_cut                 (ThunarLauncher                 *launcher);
 static void                    thunar_launcher_action_copy                (ThunarLauncher                 *launcher);
 static void                    thunar_launcher_action_paste               (ThunarLauncher                 *launcher);
@@ -270,24 +271,25 @@ static XfceGtkActionEntry thunar_launcher_action_entries[] =
 
     /* For backward compatibility the old accel paths are re-used. Currently not possible to automatically migrate to new accel paths. */
     /* Waiting for https://gitlab.gnome.org/GNOME/gtk/issues/2375 to be able to fix that */
-    { THUNAR_LAUNCHER_ACTION_SENDTO_MENU,      "<Actions>/ThunarWindow/sendto-menu",               "",                  XFCE_GTK_MENU_ITEM,       N_ ("_Send To"),                        NULL,                                                                                            NULL,                   NULL,                                                    },
-    { THUNAR_LAUNCHER_ACTION_SENDTO_SHORTCUTS, "<Actions>/ThunarShortcutsPane/sendto-shortcuts",   "<Primary>D",        XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Add Bookmark"),                   N_ ("Create bookmarks for all selected folders in the sidepane. If nothing is selected, the current directory is bookmarked."), "bookmark-new", G_CALLBACK (thunar_launcher_action_add_shortcuts), },
-    { THUNAR_LAUNCHER_ACTION_SENDTO_DESKTOP,   "<Actions>/ThunarLauncher/sendto-desktop",          "",                  XFCE_GTK_MENU_ITEM,       NULL,                                   NULL,                                                                                            "user-desktop",         G_CALLBACK (thunar_launcher_action_sendto_desktop),      },
-    { THUNAR_LAUNCHER_ACTION_PROPERTIES,       "<Actions>/ThunarStandardView/properties",          "<Alt>Return",       XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Properties..."),                  N_ ("View the properties of the selected file"),                                                 "document-properties",  G_CALLBACK (thunar_launcher_action_properties),          },
-    { THUNAR_LAUNCHER_ACTION_MAKE_LINK,        "<Actions>/ThunarStandardView/make-link",           "",                  XFCE_GTK_MENU_ITEM,       N_ ("Ma_ke Link"),                      NULL,                                                                                            NULL,                   G_CALLBACK (thunar_launcher_action_make_link),           },
-    { THUNAR_LAUNCHER_ACTION_DUPLICATE,        "<Actions>/ThunarStandardView/duplicate",           "",                  XFCE_GTK_MENU_ITEM,       N_ ("Du_plicate"),                      NULL,                                                                                            NULL,                   G_CALLBACK (thunar_launcher_action_duplicate),           },
-    { THUNAR_LAUNCHER_ACTION_RENAME,           "<Actions>/ThunarStandardView/rename",              "F2",                XFCE_GTK_MENU_ITEM,       N_ ("_Rename..."),                      NULL,                                                                                            NULL,                   G_CALLBACK (thunar_launcher_action_rename),              },
-    { THUNAR_LAUNCHER_ACTION_EMPTY_TRASH,      "<Actions>/ThunarWindow/empty-trash",               "",                  XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Empty Trash"),                    N_ ("Delete all files and folders in the Trash"),                                                NULL,                   G_CALLBACK (thunar_launcher_action_empty_trash),         },
-    { THUNAR_LAUNCHER_ACTION_CREATE_FOLDER,    "<Actions>/ThunarStandardView/create-folder",       "<Primary><shift>N", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Create _Folder..."),               N_ ("Create an empty folder within the current folder"),                                         "folder-new",           G_CALLBACK (thunar_launcher_action_create_folder),       },
-    { THUNAR_LAUNCHER_ACTION_CREATE_DOCUMENT,  "<Actions>/ThunarStandardView/create-document",     "",                  XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Create _Document"),                N_ ("Create a new document from a template"),                                                    "document-new",         G_CALLBACK (NULL),                                       },
-
-    { THUNAR_LAUNCHER_ACTION_RESTORE,          "<Actions>/ThunarLauncher/restore",                 "",                  XFCE_GTK_MENU_ITEM,       N_ ("_Restore"),                        NULL,                                                                                            NULL,                   G_CALLBACK (thunar_launcher_action_restore),             },
-    { THUNAR_LAUNCHER_ACTION_MOVE_TO_TRASH,    "<Actions>/ThunarLauncher/move-to-trash",           "",                  XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Mo_ve to Trash"),                  NULL,                                                                                            "user-trash",           G_CALLBACK (thunar_launcher_action_trash_delete),       },
-    { THUNAR_LAUNCHER_ACTION_DELETE,           "<Actions>/ThunarLauncher/delete",                  "",                  XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Delete"),                         NULL,                                                                                            "edit-delete",          G_CALLBACK (thunar_launcher_action_delete),              },
-    { THUNAR_LAUNCHER_ACTION_DELETE,           "<Actions>/ThunarLauncher/delete-2",                "<Shift>Delete",     XFCE_GTK_IMAGE_MENU_ITEM, NULL,                                   NULL,                                                                                            NULL,                   G_CALLBACK (thunar_launcher_action_delete),              },
-    { THUNAR_LAUNCHER_ACTION_DELETE,           "<Actions>/ThunarLauncher/delete-3",                "<Shift>KP_Delete",  XFCE_GTK_IMAGE_MENU_ITEM, NULL,                                   NULL,                                                                                            NULL,                   G_CALLBACK (thunar_launcher_action_delete),              },
-    { THUNAR_LAUNCHER_ACTION_TRASH_DELETE,     "<Actions>/ThunarLauncher/trash-delete",            "Delete",            XFCE_GTK_IMAGE_MENU_ITEM, NULL,                                   NULL,                                                                                            NULL,                   G_CALLBACK (thunar_launcher_action_trash_delete),        },
-    { THUNAR_LAUNCHER_ACTION_TRASH_DELETE,     "<Actions>/ThunarLauncher/trash-delete-2",          "KP_Delete",         XFCE_GTK_IMAGE_MENU_ITEM, NULL,                                   NULL,                                                                                            NULL,                   G_CALLBACK (thunar_launcher_action_trash_delete),        },
+    {THUNAR_LAUNCHER_ACTION_SENDTO_MENU,        "<Actions>/ThunarWindow/sendto-menu",             "",                  XFCE_GTK_MENU_ITEM,       N_ ("_Send To"),            NULL,                                             NULL,                                                                                         NULL,                                                    },
+    {THUNAR_LAUNCHER_ACTION_SENDTO_SHORTCUTS,   "<Actions>/ThunarShortcutsPane/sendto-shortcuts", "<Primary>D",        XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Add Bookmark"),       N_ ("Create bookmarks for all selected folders in the sidepane. If nothing is selected, the current directory is bookmarked."), "bookmark-new", G_CALLBACK (thunar_launcher_action_add_shortcuts), },
+    {THUNAR_LAUNCHER_ACTION_SENDTO_DESKTOP,     "<Actions>/ThunarLauncher/sendto-desktop",        "",                  XFCE_GTK_MENU_ITEM,       NULL,                       NULL,                                                                                            "user-desktop",                                G_CALLBACK (thunar_launcher_action_sendto_desktop),      },
+    {THUNAR_LAUNCHER_ACTION_PROPERTIES,         "<Actions>/ThunarStandardView/properties",        "<Alt>Return",       XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Properties..."),      N_ ("View the properties of the selected file"),                                                 "document-properties",                         G_CALLBACK (thunar_launcher_action_properties),          },
+    {THUNAR_LAUNCHER_ACTION_MAKE_LINK,          "<Actions>/ThunarStandardView/make-link",         "",                  XFCE_GTK_MENU_ITEM,       N_ ("Ma_ke Link"),          NULL,                                             NULL,                                                                                         G_CALLBACK (thunar_launcher_action_make_link),           },
+    {THUNAR_LAUNCHER_ACTION_DUPLICATE,          "<Actions>/ThunarStandardView/duplicate",         "",                  XFCE_GTK_MENU_ITEM,       N_ ("Du_plicate"),          NULL,                                             NULL,                                                                                         G_CALLBACK (thunar_launcher_action_duplicate),           },
+    {THUNAR_LAUNCHER_ACTION_RENAME,             "<Actions>/ThunarStandardView/rename",            "F2",                XFCE_GTK_MENU_ITEM,       N_ ("_Rename..."),          NULL,                                             NULL,                                                                                         G_CALLBACK (thunar_launcher_action_rename),              },
+    {THUNAR_LAUNCHER_ACTION_EMPTY_TRASH,        "<Actions>/ThunarWindow/empty-trash",             "",                  XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Empty Trash"),        N_ ("Delete all files and folders in the Trash"), NULL,                                                                                         G_CALLBACK (thunar_launcher_action_empty_trash),         },
+    {THUNAR_LAUNCHER_ACTION_REMOVE_FROM_RECENT, "<Actions>/ThunarWindow/remove-from-recent",      "",                  XFCE_GTK_MENU_ITEM,       N_ ("_Remove from recent"), N_ ("Remove the selected files from Recent"),     NULL,                                                                                         G_CALLBACK (thunar_launcher_action_remove_from_recent),       },
+    {THUNAR_LAUNCHER_ACTION_CREATE_FOLDER,      "<Actions>/ThunarStandardView/create-folder",     "<Primary><shift>N", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Create _Folder..."),   N_ ("Create an empty folder within the current folder"),                                         "folder-new",                                  G_CALLBACK (thunar_launcher_action_create_folder),       },
+    {THUNAR_LAUNCHER_ACTION_CREATE_DOCUMENT,    "<Actions>/ThunarStandardView/create-document",   "",                  XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Create _Document"),    N_ ("Create a new document from a template"),                                                    "document-new",                                G_CALLBACK (NULL),                                       },
+
+    {THUNAR_LAUNCHER_ACTION_RESTORE,            "<Actions>/ThunarLauncher/restore",               "",                  XFCE_GTK_MENU_ITEM,       N_ ("_Restore"),            NULL,                                             NULL,                                                                                         G_CALLBACK (thunar_launcher_action_restore),             },
+    {THUNAR_LAUNCHER_ACTION_MOVE_TO_TRASH,      "<Actions>/ThunarLauncher/move-to-trash",         "",                  XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Mo_ve to Trash"),      NULL,                                                                                            "user-trash",                                  G_CALLBACK (thunar_launcher_action_trash_delete),        },
+    {THUNAR_LAUNCHER_ACTION_DELETE,             "<Actions>/ThunarLauncher/delete",                "",                  XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Delete"),             NULL,                                                                                            "edit-delete",                                 G_CALLBACK (thunar_launcher_action_delete),              },
+    {THUNAR_LAUNCHER_ACTION_DELETE,             "<Actions>/ThunarLauncher/delete-2",              "<Shift>Delete",     XFCE_GTK_IMAGE_MENU_ITEM, NULL,                       NULL,                                             NULL,                                                                                         G_CALLBACK (thunar_launcher_action_delete),              },
+    {THUNAR_LAUNCHER_ACTION_DELETE,             "<Actions>/ThunarLauncher/delete-3",              "<Shift>KP_Delete",  XFCE_GTK_IMAGE_MENU_ITEM, NULL,                       NULL,                                             NULL,                                                                                         G_CALLBACK (thunar_launcher_action_delete),              },
+    {THUNAR_LAUNCHER_ACTION_TRASH_DELETE,       "<Actions>/ThunarLauncher/trash-delete",          "Delete",            XFCE_GTK_IMAGE_MENU_ITEM, NULL,                       NULL,                                             NULL,                                                                                         G_CALLBACK (thunar_launcher_action_trash_delete),        },
+    {THUNAR_LAUNCHER_ACTION_TRASH_DELETE,       "<Actions>/ThunarLauncher/trash-delete-2",        "KP_Delete",         XFCE_GTK_IMAGE_MENU_ITEM, NULL,                       NULL,                                             NULL,                                                                                         G_CALLBACK (thunar_launcher_action_trash_delete),        },
     { THUNAR_LAUNCHER_ACTION_PASTE,            "<Actions>/ThunarLauncher/paste",                   "<Primary>V",        XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Paste"),                          N_ ("Move or copy files previously selected by a Cut or Copy command"),                          "edit-paste",           G_CALLBACK (thunar_launcher_action_paste),               },
     { THUNAR_LAUNCHER_ACTION_PASTE_INTO_FOLDER,NULL,                                               "",                  XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Paste Into Folder"),              N_ ("Move or copy files previously selected by a Cut or Copy command into the selected folder"), "edit-paste",           G_CALLBACK (thunar_launcher_action_paste_into_folder),   },
     { THUNAR_LAUNCHER_ACTION_COPY,             "<Actions>/ThunarLauncher/copy",                    "<Primary>C",        XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Copy"),                           N_ ("Prepare the selected files to be copied with a Paste command"),                             "edit-copy",            G_CALLBACK (thunar_launcher_action_copy),                },
@@ -771,7 +773,11 @@ thunar_launcher_execute_files (ThunarLauncher *launcher,
   /* execute all selected files */
   for (lp = files; lp != NULL; lp = lp->next)
     {
+      ThunarFile  *file   = lp->data;
+      GFile       *gfile  = thunar_file_get_file (file);
+
       working_directory = thunar_file_get_file (launcher->current_directory);
+      gtk_recent_manager_add_item (gtk_recent_manager_get_default(), g_file_get_uri (gfile));
 
       if (!thunar_file_execute (lp->data, working_directory, launcher->widget, NULL, NULL, &error))
         {
@@ -1132,6 +1138,10 @@ thunar_launcher_poke_files_finish (ThunarBrowser *browser,
   /* check if poking succeeded */
   if (error == NULL)
     {
+      /* add opened file to `recent:///` */
+      GFile *gfile = thunar_file_get_file (target_file);
+      gtk_recent_manager_add_item (gtk_recent_manager_get_default(), g_file_get_uri (gfile));
+
       /* add the resolved file to the list of file to be opened/executed later */
       poke_data->files_poked = g_list_prepend (poke_data->files_poked,g_object_ref (target_file));
     }
@@ -1622,6 +1632,15 @@ thunar_launcher_append_menu_item (ThunarLauncher       *launcher,
           }
         return NULL;
 
+      case THUNAR_LAUNCHER_ACTION_REMOVE_FROM_RECENT:
+        if (launcher->files_are_selected && thunar_file_is_recent (launcher->current_directory))
+          {
+            item = xfce_gtk_image_menu_item_new_from_icon_name (action_entry->menu_item_label_text, action_entry->menu_item_tooltip_text, action_entry->accel_path,
+                                                                action_entry->callback, G_OBJECT (launcher), action_entry->menu_item_icon_name, menu);
+            return item;
+          }
+        return NULL;
+
       case THUNAR_LAUNCHER_ACTION_CREATE_FOLDER:
         if (THUNAR_IS_TREE_VIEW (launcher->widget) && launcher->files_are_selected && launcher->single_directory_to_process)
           parent = launcher->single_folder;
@@ -2403,6 +2422,29 @@ thunar_launcher_action_trash_delete (ThunarLauncher *launcher)
 
 
 
+static void
+thunar_launcher_action_remove_from_recent (ThunarLauncher *launcher)
+{
+  GtkRecentManager  *recent_manager = gtk_recent_manager_get_default();
+  GList             *lp;
+
+  _thunar_return_if_fail (THUNAR_IS_LAUNCHER (launcher));
+
+  if (launcher->parent_folder == NULL || launcher->files_are_selected == FALSE)
+    return;
+
+  for (lp = launcher->files_to_process; lp != NULL; lp = lp->next)
+    {
+      ThunarFile  *file  = lp->data;
+      GFile       *gfile = thunar_file_get_file (file);
+      gchar       *uri   = g_file_get_uri (gfile);
+      gtk_recent_manager_remove_item (recent_manager, uri, NULL);
+      g_free(uri);
+    }
+}
+
+
+
 void
 thunar_launcher_action_empty_trash (ThunarLauncher *launcher)
 {
diff --git a/thunar/thunar-launcher.h b/thunar/thunar-launcher.h
index e5dc2c501..9b88e9079 100644
--- a/thunar/thunar-launcher.h
+++ b/thunar/thunar-launcher.h
@@ -53,6 +53,7 @@ typedef enum
   THUNAR_LAUNCHER_ACTION_DUPLICATE,
   THUNAR_LAUNCHER_ACTION_RENAME,
   THUNAR_LAUNCHER_ACTION_EMPTY_TRASH,
+  THUNAR_LAUNCHER_ACTION_REMOVE_FROM_RECENT,
   THUNAR_LAUNCHER_ACTION_CREATE_FOLDER,
   THUNAR_LAUNCHER_ACTION_CREATE_DOCUMENT,
   THUNAR_LAUNCHER_ACTION_RESTORE,
diff --git a/thunar/thunar-list-model.c b/thunar/thunar-list-model.c
index 75d66b2d5..a20eaa179 100644
--- a/thunar/thunar-list-model.c
+++ b/thunar/thunar-list-model.c
@@ -152,6 +152,10 @@ static void               thunar_list_model_files_added           (ThunarFolder
 static void               thunar_list_model_files_removed         (ThunarFolder           *folder,
                                                                    GList                  *files,
                                                                    ThunarListModel        *store);
+static gint               sort_by_date                            (const ThunarFile       *a,
+                                                                   const ThunarFile       *b,
+                                                                   gboolean                case_sensitive,
+                                                                   gint                    type);
 static gint               sort_by_date_created                    (const ThunarFile       *a,
                                                                    const ThunarFile       *b,
                                                                    gboolean                case_sensitive);
@@ -164,6 +168,9 @@ static gint               sort_by_date_modified                   (const ThunarF
 static gint               sort_by_date_deleted                    (const ThunarFile       *a,
                                                                    const ThunarFile       *b,
                                                                    gboolean                case_sensitive);
+static gint               sort_by_recency                         (const ThunarFile       *a,
+                                                                   const ThunarFile       *b,
+                                                                   gboolean                case_sensitive);
 static gint               sort_by_group                           (const ThunarFile       *a,
                                                                    const ThunarFile       *b,
                                                                    gboolean                case_sensitive);
@@ -746,6 +753,12 @@ thunar_list_model_get_value (GtkTreeModel *model,
       g_value_take_string (value, str);
       break;
 
+    case THUNAR_COLUMN_RECENCY:
+      g_value_init (value, G_TYPE_STRING);
+      str = thunar_file_get_date_string (file, THUNAR_FILE_RECENCY, THUNAR_LIST_MODEL (model)->date_style, THUNAR_LIST_MODEL (model)->date_custom_style);
+      g_value_take_string (value, str);
+      break;
+
     case THUNAR_COLUMN_GROUP:
       g_value_init (value, G_TYPE_STRING);
       group = thunar_file_get_group (file);
@@ -999,6 +1012,8 @@ thunar_list_model_get_sort_column_id (GtkTreeSortable *sortable,
     *sort_column_id = THUNAR_COLUMN_DATE_MODIFIED;
   else if (store->sort_func == sort_by_date_deleted)
     *sort_column_id = THUNAR_COLUMN_DATE_DELETED;
+  else if (store->sort_func == sort_by_recency)
+    *sort_column_id = THUNAR_COLUMN_RECENCY;
   else if (store->sort_func == sort_by_type)
     *sort_column_id = THUNAR_COLUMN_TYPE;
   else if (store->sort_func == sort_by_owner)
@@ -1048,6 +1063,10 @@ thunar_list_model_set_sort_column_id (GtkTreeSortable *sortable,
       store->sort_func = sort_by_date_deleted;
       break;
 
+    case THUNAR_COLUMN_RECENCY:
+      store->sort_func = sort_by_recency;
+      break;
+
     case THUNAR_COLUMN_GROUP:
       store->sort_func = sort_by_group;
       break;
@@ -1449,15 +1468,16 @@ thunar_list_model_files_removed (ThunarFolder    *folder,
 
 
 static gint
-sort_by_date_created (const ThunarFile *a,
+sort_by_date         (const ThunarFile *a,
                       const ThunarFile *b,
-                      gboolean          case_sensitive)
+                      gboolean          case_sensitive,
+                      gint              type)
 {
   guint64 date_a;
   guint64 date_b;
 
-  date_a = thunar_file_get_date (a, THUNAR_FILE_DATE_CREATED);
-  date_b = thunar_file_get_date (b, THUNAR_FILE_DATE_CREATED);
+  date_a = thunar_file_get_date (a, type);
+  date_b = thunar_file_get_date (b, type);
 
   if (date_a < date_b)
     return -1;
@@ -1470,22 +1490,21 @@ sort_by_date_created (const ThunarFile *a,
 
 
 static gint
-sort_by_date_accessed (const ThunarFile *a,
-                       const ThunarFile *b,
-                       gboolean          case_sensitive)
+sort_by_date_created (const ThunarFile *a,
+                      const ThunarFile *b,
+                      gboolean          case_sensitive)
 {
-  guint64 date_a;
-  guint64 date_b;
+  return sort_by_date (a, b, case_sensitive, THUNAR_FILE_DATE_CREATED);
+}
 
-  date_a = thunar_file_get_date (a, THUNAR_FILE_DATE_ACCESSED);
-  date_b = thunar_file_get_date (b, THUNAR_FILE_DATE_ACCESSED);
 
-  if (date_a < date_b)
-    return -1;
-  else if (date_a > date_b)
-    return 1;
 
-  return thunar_file_compare_by_name (a, b, case_sensitive);
+static gint
+sort_by_date_accessed (const ThunarFile *a,
+                       const ThunarFile *b,
+                       gboolean          case_sensitive)
+{
+  return sort_by_date (a, b, case_sensitive, THUNAR_FILE_DATE_ACCESSED);
 }
 
 
@@ -1495,18 +1514,7 @@ sort_by_date_modified (const ThunarFile *a,
                        const ThunarFile *b,
                        gboolean          case_sensitive)
 {
-  guint64 date_a;
-  guint64 date_b;
-
-  date_a = thunar_file_get_date (a, THUNAR_FILE_DATE_MODIFIED);
-  date_b = thunar_file_get_date (b, THUNAR_FILE_DATE_MODIFIED);
-
-  if (date_a < date_b)
-    return -1;
-  else if (date_a > date_b)
-    return 1;
-
-  return thunar_file_compare_by_name (a, b, case_sensitive);
+  return sort_by_date (a, b, case_sensitive, THUNAR_FILE_DATE_MODIFIED);
 }
 
 
@@ -1516,18 +1524,17 @@ sort_by_date_deleted (const ThunarFile *a,
                       const ThunarFile *b,
                       gboolean          case_sensitive)
 {
-  guint64 date_a;
-  guint64 date_b;
+  return sort_by_date (a, b, case_sensitive, THUNAR_FILE_DATE_DELETED);
+}
 
-  date_a = thunar_file_get_date (a, THUNAR_FILE_DATE_DELETED);
-  date_b = thunar_file_get_date (b, THUNAR_FILE_DATE_DELETED);
 
-  if (date_a < date_b)
-    return -1;
-  else if (date_a > date_b)
-    return 1;
 
-  return thunar_file_compare_by_name (a, b, case_sensitive);
+static gint
+sort_by_recency      (const ThunarFile *a,
+                      const ThunarFile *b,
+                      gboolean          case_sensitive)
+{
+  return sort_by_date (a, b, case_sensitive, THUNAR_FILE_RECENCY);
 }
 
 
diff --git a/thunar/thunar-menu.c b/thunar/thunar-menu.c
index 29394bc9c..4d3a11652 100644
--- a/thunar/thunar-menu.c
+++ b/thunar/thunar-menu.c
@@ -308,6 +308,11 @@ thunar_menu_add_sections (ThunarMenu         *menu,
       if (thunar_launcher_append_menu_item (menu->launcher, GTK_MENU_SHELL (menu), THUNAR_LAUNCHER_ACTION_RESTORE, FALSE) != NULL)
          xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
     }
+  if (menu_sections & THUNAR_MENU_SECTION_REMOVE_FROM_RECENT)
+    {
+      if (thunar_launcher_append_menu_item (menu->launcher, GTK_MENU_SHELL (menu), THUNAR_LAUNCHER_ACTION_REMOVE_FROM_RECENT, FALSE) != NULL)
+        xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
+    }
 
   item_added = FALSE;
   if (menu_sections & THUNAR_MENU_SECTION_DUPLICATE)
diff --git a/thunar/thunar-menu.h b/thunar/thunar-menu.h
index 3fd5abad8..d31ee4fd0 100644
--- a/thunar/thunar-menu.h
+++ b/thunar/thunar-menu.h
@@ -49,21 +49,22 @@ typedef enum
 /* Bundles of #GtkMenuItems, which can be created by this widget */
 typedef enum
 {
-  THUNAR_MENU_SECTION_OPEN             = 1 << 0,
-  THUNAR_MENU_SECTION_SENDTO           = 1 << 1,
-  THUNAR_MENU_SECTION_CREATE_NEW_FILES = 1 << 2,
-  THUNAR_MENU_SECTION_CUT              = 1 << 3,
-  THUNAR_MENU_SECTION_COPY_PASTE       = 1 << 4,
-  THUNAR_MENU_SECTION_TRASH_DELETE     = 1 << 5,
-  THUNAR_MENU_SECTION_EMPTY_TRASH      = 1 << 6,
-  THUNAR_MENU_SECTION_RESTORE          = 1 << 7,
-  THUNAR_MENU_SECTION_DUPLICATE        = 1 << 8,
-  THUNAR_MENU_SECTION_MAKELINK         = 1 << 9,
-  THUNAR_MENU_SECTION_RENAME           = 1 << 10,
-  THUNAR_MENU_SECTION_CUSTOM_ACTIONS   = 1 << 11,
-  THUNAR_MENU_SECTION_ZOOM             = 1 << 12,
-  THUNAR_MENU_SECTION_PROPERTIES       = 1 << 13,
-  THUNAR_MENU_SECTION_MOUNTABLE        = 1 << 14,
+  THUNAR_MENU_SECTION_OPEN                = 1 << 0,
+  THUNAR_MENU_SECTION_SENDTO              = 1 << 1,
+  THUNAR_MENU_SECTION_CREATE_NEW_FILES    = 1 << 2,
+  THUNAR_MENU_SECTION_CUT                 = 1 << 3,
+  THUNAR_MENU_SECTION_COPY_PASTE          = 1 << 4,
+  THUNAR_MENU_SECTION_TRASH_DELETE        = 1 << 5,
+  THUNAR_MENU_SECTION_EMPTY_TRASH         = 1 << 6,
+  THUNAR_MENU_SECTION_RESTORE             = 1 << 7,
+  THUNAR_MENU_SECTION_DUPLICATE           = 1 << 8,
+  THUNAR_MENU_SECTION_MAKELINK            = 1 << 9,
+  THUNAR_MENU_SECTION_RENAME              = 1 << 10,
+  THUNAR_MENU_SECTION_CUSTOM_ACTIONS      = 1 << 11,
+  THUNAR_MENU_SECTION_ZOOM                = 1 << 12,
+  THUNAR_MENU_SECTION_PROPERTIES          = 1 << 13,
+  THUNAR_MENU_SECTION_MOUNTABLE           = 1 << 14,
+  THUNAR_MENU_SECTION_REMOVE_FROM_RECENT  = 1 << 15,
 
 } ThunarMenuSections;
 
diff --git a/thunar/thunar-shortcuts-model.c b/thunar/thunar-shortcuts-model.c
index ba877f6e0..2db1a5280 100644
--- a/thunar/thunar-shortcuts-model.c
+++ b/thunar/thunar-shortcuts-model.c
@@ -1140,6 +1140,19 @@ thunar_shortcuts_model_shortcut_places (ThunarShortcutsModel *model)
       shortcut->hidden = thunar_shortcuts_model_get_hidden (model, shortcut);
       thunar_shortcuts_model_add_shortcut (model, shortcut);
     }
+
+  /* append the recent icon if browsing recent is supported */
+  if (thunar_g_vfs_is_uri_scheme_supported ("recent"))
+    {
+      shortcut = g_slice_new0 (ThunarShortcut);
+      shortcut->group = THUNAR_SHORTCUT_GROUP_PLACES_RECENT;
+      shortcut->name = g_strdup (_("Recent"));
+      shortcut->tooltip = g_strdup (_("Browse recently used files"));
+      shortcut->location = thunar_g_file_new_for_recent();
+      shortcut->gicon = g_themed_icon_new ("document-open-recent");
+      shortcut->hidden = thunar_shortcuts_model_get_hidden (model, shortcut);
+      thunar_shortcuts_model_add_shortcut (model, shortcut);
+    }
 }
 
 
diff --git a/thunar/thunar-shortcuts-model.h b/thunar/thunar-shortcuts-model.h
index 71363a708..179d346ad 100644
--- a/thunar/thunar-shortcuts-model.h
+++ b/thunar/thunar-shortcuts-model.h
@@ -64,7 +64,8 @@ typedef enum
                                        | THUNAR_SHORTCUT_GROUP_PLACES_DEFAULT \
                                        | THUNAR_SHORTCUT_GROUP_PLACES_TRASH \
                                        | THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS \
-                                       | THUNAR_SHORTCUT_GROUP_PLACES_COMPUTER )
+                                       | THUNAR_SHORTCUT_GROUP_PLACES_COMPUTER \
+                                       | THUNAR_SHORTCUT_GROUP_PLACES_RECENT)
 #define THUNAR_SHORTCUT_GROUP_NETWORK (THUNAR_SHORTCUT_GROUP_NETWORK_HEADER \
                                        | THUNAR_SHORTCUT_GROUP_NETWORK_DEFAULT \
                                        | THUNAR_SHORTCUT_GROUP_NETWORK_MOUNTS)
@@ -78,19 +79,20 @@ enum _ThunarShortcutGroup
   THUNAR_SHORTCUT_GROUP_PLACES_HEADER      = (1 << 0),  /* places header */
   THUNAR_SHORTCUT_GROUP_PLACES_COMPUTER    = (1 << 1),  /* computer */
   THUNAR_SHORTCUT_GROUP_PLACES_DEFAULT     = (1 << 2),  /* home and desktop */
-  THUNAR_SHORTCUT_GROUP_PLACES_TRASH       = (1 << 3),  /* trash */
-  THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS   = (1 << 4),  /* gtk-bookmarks */
+  THUNAR_SHORTCUT_GROUP_PLACES_RECENT      = (1 << 3),  /* recent */
+  THUNAR_SHORTCUT_GROUP_PLACES_TRASH       = (1 << 4),  /* trash */
+  THUNAR_SHORTCUT_GROUP_PLACES_BOOKMARKS   = (1 << 5),  /* gtk-bookmarks */
 
   /* THUNAR_SHORTCUT_GROUP_DEVICES */
-  THUNAR_SHORTCUT_GROUP_DEVICES_HEADER     = (1 << 5),  /* devices header */
-  THUNAR_SHORTCUT_GROUP_DEVICES_FILESYSTEM = (1 << 6),  /* local filesystem */
-  THUNAR_SHORTCUT_GROUP_DEVICES_VOLUMES    = (1 << 7),  /* local ThunarDevices */
-  THUNAR_SHORTCUT_GROUP_DEVICES_MOUNTS     = (1 << 8),  /* local mounts, like cameras and archives */
+  THUNAR_SHORTCUT_GROUP_DEVICES_HEADER     = (1 << 6),  /* devices header */
+  THUNAR_SHORTCUT_GROUP_DEVICES_FILESYSTEM = (1 << 7),  /* local filesystem */
+  THUNAR_SHORTCUT_GROUP_DEVICES_VOLUMES    = (1 << 8),  /* local ThunarDevices */
+  THUNAR_SHORTCUT_GROUP_DEVICES_MOUNTS     = (1 << 9),  /* local mounts, like cameras and archives */
 
   /* THUNAR_SHORTCUT_GROUP_NETWORK */
-  THUNAR_SHORTCUT_GROUP_NETWORK_HEADER     = (1 << 9),  /* network header */
-  THUNAR_SHORTCUT_GROUP_NETWORK_DEFAULT    = (1 << 10), /* browse network */
-  THUNAR_SHORTCUT_GROUP_NETWORK_MOUNTS     = (1 << 11), /* remote ThunarDevices */
+  THUNAR_SHORTCUT_GROUP_NETWORK_HEADER     = (1 << 10),  /* network header */
+  THUNAR_SHORTCUT_GROUP_NETWORK_DEFAULT    = (1 << 11), /* browse network */
+  THUNAR_SHORTCUT_GROUP_NETWORK_MOUNTS     = (1 << 12), /* remote ThunarDevices */
 };
 
 
diff --git a/thunar/thunar-standard-view.c b/thunar/thunar-standard-view.c
index ab5ab33e9..36ecfbbc1 100644
--- a/thunar/thunar-standard-view.c
+++ b/thunar/thunar-standard-view.c
@@ -3657,6 +3657,7 @@ thunar_standard_view_context_menu (ThunarStandardView *standard_view)
                                             | THUNAR_MENU_SECTION_COPY_PASTE
                                             | THUNAR_MENU_SECTION_TRASH_DELETE
                                             | THUNAR_MENU_SECTION_EMPTY_TRASH
+                                            | THUNAR_MENU_SECTION_REMOVE_FROM_RECENT
                                             | THUNAR_MENU_SECTION_RESTORE
                                             | THUNAR_MENU_SECTION_RENAME
                                             | THUNAR_MENU_SECTION_CUSTOM_ACTIONS
diff --git a/thunar/thunar-tree-model.c b/thunar/thunar-tree-model.c
index 98bf136b5..9ecd5a6ba 100644
--- a/thunar/thunar-tree-model.c
+++ b/thunar/thunar-tree-model.c
@@ -326,6 +326,9 @@ thunar_tree_model_init (ThunarTreeModel *model)
   home = thunar_g_file_new_for_home ();
   system_paths = g_list_append (system_paths, g_object_ref (home));
 
+  if (thunar_g_vfs_is_uri_scheme_supported ("recent"))
+    system_paths = g_list_append (system_paths, thunar_g_file_new_for_recent());
+
   /* append the trash icon if the trash is supported */
   if (thunar_g_vfs_is_uri_scheme_supported ("trash"))
     system_paths = g_list_append (system_paths, thunar_g_file_new_for_trash ());
diff --git a/thunar/thunar-window.c b/thunar/thunar-window.c
index 06e4f10a8..c4cd243fa 100644
--- a/thunar/thunar-window.c
+++ b/thunar/thunar-window.c
@@ -215,6 +215,7 @@ static void      thunar_window_action_open_desktop        (ThunarWindow
 static void      thunar_window_action_open_computer       (ThunarWindow           *window);
 static void      thunar_window_action_open_templates      (ThunarWindow           *window);
 static void      thunar_window_action_open_file_system    (ThunarWindow           *window);
+static void      thunar_window_action_open_recent         (ThunarWindow           *window);
 static void      thunar_window_action_open_trash          (ThunarWindow           *window);
 static void      thunar_window_action_open_network        (ThunarWindow           *window);
 static void      thunar_window_action_open_bookmark       (GFile                  *g_file);
@@ -298,6 +299,8 @@ static void      thunar_window_trash_infobar_clicked           (GtkInfoBar
                                                                 gint                    response_id,
                                                                 ThunarWindow           *window);
 static void      thunar_window_trash_selection_updated         (ThunarWindow           *window);
+static void      thunar_window_recent_reload                   (GtkRecentManager       *recent_manager,
+                                                                ThunarWindow           *window);
 
 
 
@@ -438,6 +441,7 @@ static XfceGtkActionEntry thunar_window_action_entries[] =
     { THUNAR_WINDOW_ACTION_OPEN_HOME,                      "<Actions>/ThunarWindow/open-home",                       "<Alt>Home",            XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Home"),                  N_ ("Go to the home folder"),                                                        "go-home-symbolic",        G_CALLBACK (thunar_window_action_open_home),          },
     { THUNAR_WINDOW_ACTION_OPEN_DESKTOP,                   "<Actions>/ThunarWindow/open-desktop",                    "",                     XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Desktop"),                N_ ("Go to the desktop folder"),                                                     "user-desktop",            G_CALLBACK (thunar_window_action_open_desktop),       },
     { THUNAR_WINDOW_ACTION_OPEN_COMPUTER,                  "<Actions>/ThunarWindow/open-computer",                   "",                     XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Computer"),               N_ ("Browse all local and remote disks and folders accessible from this computer"),  "computer",                G_CALLBACK (thunar_window_action_open_computer),      },
+    { THUNAR_WINDOW_ACTION_OPEN_RECENT,                    "<Actions>/ThunarWindow/open-recent",                     "",                     XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Recent"),                 N_ ("Display recently used files"),                                                  "document-open-recent",    G_CALLBACK (thunar_window_action_open_recent),        },
     { THUNAR_WINDOW_ACTION_OPEN_TRASH,                     "<Actions>/ThunarWindow/open-trash",                      "",                     XFCE_GTK_IMAGE_MENU_ITEM, N_ ("T_rash"),                 N_ ("Display the contents of the trash can"),                                        NULL,                      G_CALLBACK (thunar_window_action_open_trash),         },
     { THUNAR_WINDOW_ACTION_OPEN_PARENT,                    "<Actions>/ThunarWindow/open-parent",                     "<Alt>Up",              XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Open _Parent"),           N_ ("Open the parent folder"),                                                       "go-up-symbolic",          G_CALLBACK (thunar_window_action_go_up),              },
     { THUNAR_WINDOW_ACTION_OPEN_LOCATION,                  "<Actions>/ThunarWindow/open-location",                   "<Primary>l",           XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Open Location..."),      N_ ("Specify a location to open"),                                                   NULL,                      G_CALLBACK (thunar_window_action_open_location),      },
@@ -931,6 +935,9 @@ thunar_window_init (ThunarWindow *window)
 
   /* initial load of the bookmarks */
   thunar_window_update_bookmarks (window);
+
+  /* update recent */
+  g_signal_connect (G_OBJECT (gtk_recent_manager_get_default()), "changed", G_CALLBACK (thunar_window_recent_reload), window);
 }
 
 
@@ -1192,6 +1199,8 @@ thunar_window_update_go_menu (ThunarWindow *window,
   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_COMPUTER), G_OBJECT (window), GTK_MENU_SHELL (menu));
   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_HOME), G_OBJECT (window), GTK_MENU_SHELL (menu));
   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_DESKTOP), G_OBJECT (window), GTK_MENU_SHELL (menu));
+  if (thunar_g_vfs_is_uri_scheme_supported ("recent"))
+    xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_MENU_SECTION_REMOVE_FROM_RECENT), G_OBJECT (window), GTK_MENU_SHELL (menu));
   if (thunar_g_vfs_is_uri_scheme_supported ("trash"))
     {
       GFile      *gfile;
@@ -3533,6 +3542,39 @@ thunar_window_action_open_file_system (ThunarWindow *window)
 
 
 
+static void
+thunar_window_action_open_recent (ThunarWindow *window)
+{
+  GFile      *recent;
+  ThunarFile *recent_file;
+  GError     *error = NULL;
+
+  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
+
+  /* determine the path to `Recent` */
+  recent = thunar_g_file_new_for_recent ();
+
+  /* determine the file for `Recent` */
+  recent_file = thunar_file_get (recent, &error);
+  if (G_UNLIKELY (recent_file == NULL))
+    {
+      /* display an error to the user */
+      thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to display `Recent`"));
+      g_error_free (error);
+    }
+  else
+    {
+      /* open the `Recent` folder */
+      thunar_window_set_current_directory (window, recent_file);
+      g_object_unref (G_OBJECT (recent_file));
+    }
+
+  /* release our reference on the `Recent` path */
+  g_object_unref (recent);
+}
+
+
+
 static void
 thunar_window_action_open_trash (ThunarWindow *window)
 {
@@ -4057,6 +4099,7 @@ thunar_window_set_current_directory (ThunarWindow *window,
                                      ThunarFile   *current_directory)
 {
   gboolean is_trash;
+  gboolean is_recent;
 
   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
   _thunar_return_if_fail (current_directory == NULL || THUNAR_IS_FILE (current_directory));
@@ -4141,6 +4184,7 @@ thunar_window_set_current_directory (ThunarWindow *window,
     return;
 
   is_trash = thunar_file_is_trash (current_directory);
+  is_recent = thunar_file_is_recent (current_directory);
   if (is_trash)
     gtk_widget_show (window->trash_infobar);
   else
@@ -4149,6 +4193,7 @@ thunar_window_set_current_directory (ThunarWindow *window,
   if (THUNAR_IS_DETAILS_VIEW (window->view) == FALSE)
     return;
   thunar_details_view_set_date_deleted_column_visible (THUNAR_DETAILS_VIEW (window->view), is_trash);
+  thunar_details_view_set_recency_column_visible (THUNAR_DETAILS_VIEW (window->view), is_recent);
 }
 
 
@@ -4610,3 +4655,13 @@ thunar_window_trash_selection_updated (ThunarWindow *window)
   else
     gtk_widget_set_sensitive (window->trash_infobar_restore_button, FALSE);
 }
+
+
+
+static void
+thunar_window_recent_reload (GtkRecentManager *recent_manager,
+                             ThunarWindow     *window)
+{
+  if (thunar_file_is_in_recent (window->current_directory))
+    thunar_window_action_reload (window, NULL);
+}
diff --git a/thunar/thunar-window.h b/thunar/thunar-window.h
index 66cde9322..027a967bd 100644
--- a/thunar/thunar-window.h
+++ b/thunar/thunar-window.h
@@ -85,6 +85,7 @@ typedef enum
   THUNAR_WINDOW_ACTION_OPEN_HOME,
   THUNAR_WINDOW_ACTION_OPEN_DESKTOP,
   THUNAR_WINDOW_ACTION_OPEN_COMPUTER,
+  THUNAR_WINDOW_ACTION_OPEN_RECENT,
   THUNAR_WINDOW_ACTION_OPEN_TRASH,
   THUNAR_WINDOW_ACTION_OPEN_LOCATION,
   THUNAR_WINDOW_ACTION_OPEN_LOCATION_ALT,
diff --git a/thunarx/thunarx-file-info.h b/thunarx/thunarx-file-info.h
index 57de0ff53..9668afcde 100644
--- a/thunarx/thunarx-file-info.h
+++ b/thunarx/thunarx-file-info.h
@@ -46,6 +46,7 @@ G_BEGIN_DECLS
   "standard::size,standard::symlink-target," \
   "time::*," \
   "trash::*," \
+  "recent::*," \
   "unix::gid,unix::uid,unix::mode," \
   "metadata::emblems," \
   "metadata::thunar-view-type," \
-- 
GitLab