diff --git a/apps/SOURCES b/apps/SOURCES
index 26e53d1..51a94b3 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -52,6 +52,7 @@ root_menu.c
 screens.c
 settings.c
 settings_list.c
+shortcuts.c
 status.c
 cuesheet.c
 talk.c
diff --git a/apps/main.c b/apps/main.c
index 07a8bba..f860903 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -384,6 +384,7 @@ static void init(void)
     filetype_init();
     playlist_init();
     theme_init_buffer();
+    shortcuts_init(); /* must be after filetype_init() */
 
 #if CONFIG_CODEC != SWCODEC
     mp3_init( global_settings.volume,
@@ -657,6 +658,7 @@ static void init(void)
     filetype_init();
     scrobbler_init();
     theme_init_buffer();
+    shortcuts_init(); /* must be after filetype_init() */
 
 #if CONFIG_CODEC != SWCODEC
     /* No buffer allocation (see buffer.c) may take place after the call to
diff --git a/apps/menu.c b/apps/menu.c
index 6a28b1d..34a9d5a 100644
--- a/apps/menu.c
+++ b/apps/menu.c
@@ -52,6 +52,7 @@
 #include "audio.h"
 #include "viewport.h"
 #include "quickscreen.h"
+#include "shortcuts.h"
 
 #ifdef HAVE_LCD_BITMAP
 #include "icons.h"
@@ -280,19 +281,10 @@ static int talk_menu_item(int selected_item, void *data)
         return 0;
 }
 
-void do_setting_from_menu(const struct menu_item_ex *temp,
-                          struct viewport parent[NB_SCREENS])
+void do_setting_screen(const struct settings_list *setting, const char * title,
+                        struct viewport parent[NB_SCREENS])
 {
-    int setting_id;
-    const struct settings_list *setting =
-            find_setting(temp->variable, &setting_id);
-    char *title;
     char padded_title[MAX_PATH];
-    if ((temp->flags&MENU_TYPE_MASK) == MT_SETTING_W_TEXT)
-        title = temp->callback_and_desc->desc;
-    else
-        title = ID2P(setting->lang_id);
-
     /* Pad the title string by repeating it. This is needed
        so the scroll settings title can actually be used to
        test the setting */
@@ -317,7 +309,22 @@ void do_setting_from_menu(const struct menu_item_ex *temp,
     }
 
     option_screen((struct settings_list *)setting, parent,
-                  setting->flags&F_TEMPVAR, title);
+                  setting->flags&F_TEMPVAR, (char*)title);
+}
+    
+
+void do_setting_from_menu(const struct menu_item_ex *temp,
+                          struct viewport parent[NB_SCREENS])
+{
+    char *title;
+    int setting_id;
+    const struct settings_list *setting =
+        find_setting(temp->variable, &setting_id);
+    if (temp && ((temp->flags&MENU_TYPE_MASK) == MT_SETTING_W_TEXT))
+        title = temp->callback_and_desc->desc;
+    else
+        title = ID2P(setting->lang_id);
+    do_setting_screen(setting, title, parent);
 }
 
 /* display a menu */
@@ -451,7 +458,8 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
                                         ID2P(LANG_TOP_QS_ITEM),
                                         ID2P(LANG_LEFT_QS_ITEM),
                                         ID2P(LANG_BOTTOM_QS_ITEM),
-                                        ID2P(LANG_RIGHT_QS_ITEM));
+                                        ID2P(LANG_RIGHT_QS_ITEM),
+                                        ID2P(LANG_ADD_TO_FAVES));
 #endif
                     MENUITEM_STRINGLIST(notquickscreen_able_option, 
                                         ID2P(LANG_ONPLAY_MENU_TITLE), NULL,
@@ -486,6 +494,10 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
                         case 4: /* set as right QS item */
                             set_as_qs_item(setting, QUICKSCREEN_RIGHT);
                             break;
+                        case 5: /* Add to faves. Same limitation on which can be
+                                  added to the shortcuts menu as the quickscreen */
+                            shortcuts_add(SHORTCUT_SETTING, (void*)setting);
+                            break;
 #endif
                     } /* swicth(do_menu()) */
                     redraw_lists = true;
diff --git a/apps/menu.h b/apps/menu.h
index b5bab90..a29b461 100644
--- a/apps/menu.h
+++ b/apps/menu.h
@@ -26,6 +26,7 @@
 #include "icon.h"
 #include "icons.h"
 #include "root_menu.h" /* needed for MENU_* return codes */
+#include "settings_list.h"
 
 
 enum menu_item_type {
@@ -103,6 +104,8 @@ typedef int (*menu_callback_type)(int action,
                                   const struct menu_item_ex *this_item);
 void do_setting_from_menu(const struct menu_item_ex *temp,
                           struct viewport parent[NB_SCREENS]);
+void do_setting_screen(const struct settings_list *setting, const char * title,
+                        struct viewport parent[NB_SCREENS]);
 
 /* 
    int do_menu(const struct menu_item_ex *menu, int *start_selected)
diff --git a/apps/onplay.c b/apps/onplay.c
index 03981c6..a51c371 100644
--- a/apps/onplay.c
+++ b/apps/onplay.c
@@ -63,6 +63,7 @@
 #include "pitchscreen.h"
 #include "viewport.h"
 #include "filefuncs.h"
+#include "shortcuts.h"
 
 static int context;
 static char* selected_file = NULL;
@@ -1025,8 +1026,13 @@ MENUITEM_FUNCTION(list_viewers_item, 0, ID2P(LANG_ONPLAY_OPEN_WITH),
 MENUITEM_FUNCTION(properties_item, MENU_FUNC_USEPARAM, ID2P(LANG_PROPERTIES),
                   onplay_load_plugin, (void *)"properties",
                   clipboard_callback, Icon_NOICON);
-MENUITEM_FUNCTION(add_to_faves_item, MENU_FUNC_USEPARAM, ID2P(LANG_ADD_TO_FAVES),
-                  onplay_load_plugin, (void *)"shortcuts_append",
+static bool onplay_add_to_shortcuts(void)
+{
+    shortcuts_add(SHORTCUT_BROWSER, selected_file);
+    return false;
+}
+MENUITEM_FUNCTION(add_to_faves_item, 0, ID2P(LANG_ADD_TO_FAVES),
+                  onplay_add_to_shortcuts, NULL,
                   clipboard_callback, Icon_NOICON);
 
 #if LCD_DEPTH > 1
diff --git a/apps/root_menu.c b/apps/root_menu.c
index 472c1db..d776716 100644
--- a/apps/root_menu.c
+++ b/apps/root_menu.c
@@ -37,6 +37,7 @@
 #include "power.h"
 #include "talk.h"
 #include "audio.h"
+#include "shortcuts.h"
 
 #ifdef HAVE_HOTSWAP
 #include "storage.h"
@@ -378,7 +379,7 @@ static int load_bmarks(void* param)
     return GO_TO_PREVIOUS;
 }
 
-int time_screen(void* ignored);     
+int time_screen(void* ignored);
 
 /* These are all static const'd from apps/menus/ *.c
    so little hack so we can use them */
@@ -416,12 +417,16 @@ static const struct root_items items[] = {
                                                         &playlist_options },
     [GO_TO_PLAYLIST_VIEWER] = { playlist_view, NULL, &playlist_options },
     [GO_TO_SYSTEM_SCREEN] = { miscscrn, &info_menu, &system_menu },
+    [GO_TO_SHORTCUTMENU] = { do_shortcut_menu, NULL, NULL },
     
 };
 static const int nb_items = sizeof(items)/sizeof(*items);
 
 static int item_callback(int action, const struct menu_item_ex *this_item) ;
 
+MENUITEM_RETURNVALUE(shortcut_menu, "shortcuts", GO_TO_SHORTCUTMENU,
+                        NULL, Icon_file_view_menu);
+
 MENUITEM_RETURNVALUE(file_browser, ID2P(LANG_DIR_BROWSER), GO_TO_FILEBROWSER,
                         NULL, Icon_file_view_menu);
 #ifdef HAVE_TAGCACHE
@@ -493,6 +498,7 @@ MAKE_MENU(root_menu_, ID2P(LANG_ROCKBOX_TITLE),
 #if CONFIG_KEYPAD == PLAYER_PAD
             ,&do_shutdown_item
 #endif
+            ,&shortcut_menu
         );
 
 static int item_callback(int action, const struct menu_item_ex *this_item) 
diff --git a/apps/root_menu.h b/apps/root_menu.h
index 2ffdced..8d11d9b 100644
--- a/apps/root_menu.h
+++ b/apps/root_menu.h
@@ -58,6 +58,7 @@ enum {
     GO_TO_PLAYLISTS_SCREEN,
     GO_TO_PLAYLIST_VIEWER,
     GO_TO_SYSTEM_SCREEN,
+    GO_TO_SHORTCUTMENU
 };
 
 extern const struct menu_item_ex root_menu_;
diff --git a/apps/shortcuts.c b/apps/shortcuts.c
new file mode 100644
index 0000000..96311eb
--- /dev/null
+++ b/apps/shortcuts.c
@@ -0,0 +1,351 @@
+/***************************************************************************
+ *
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2011 Jonathan Gordon
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include "config.h"
+#include "system.h"
+#include "action.h"
+#include "ata_idle_notify.h"
+#include "core_alloc.h"
+#include "list.h"
+#include "settings.h"
+#include "settings_list.h"
+#include "lang.h"
+#include "menu.h"
+#include "misc.h"
+#include "tree.h"
+#include "splash.h"
+#include "filefuncs.h"
+#include "filetypes.h"
+#include "shortcuts.h"
+
+
+
+#define MAX_SHORTCUT_NAME 32
+#define SHORTCUTS_FILENAME ROCKBOX_DIR "/shortcuts.txt"
+struct shortcut {
+    enum shortcut_type type;
+    char name[MAX_SHORTCUT_NAME];
+    int icon;
+    union {
+        char path[MAX_PATH];
+        const struct settings_list *setting;
+    } u;
+};
+#define SHORTCUTS_PER_HANDLE 32
+struct shortcut_handle {
+    struct shortcut shortcuts[SHORTCUTS_PER_HANDLE];
+    int next_handle;
+};
+static int first_handle = 0;
+static int shortcut_count = 0;
+
+static struct shortcut* get_shortcut(int index)
+{
+    int handle_count, handle_index;
+    int current_handle = first_handle;
+    struct shortcut_handle *h = NULL;
+    handle_count = index/SHORTCUTS_PER_HANDLE + 1;
+    handle_index = index%SHORTCUTS_PER_HANDLE;
+    do {
+        h = core_get_data(current_handle);
+        current_handle = h->next_handle;
+        handle_count--;
+    } while (handle_count > 0 && current_handle > 0);
+    if (handle_count > 0 && handle_index == 0)
+    {
+        char buf[32];
+        snprintf(buf, sizeof buf, "shortcuts_%d", index/SHORTCUTS_PER_HANDLE);
+        h->next_handle = core_alloc(buf, sizeof(struct shortcut_handle));
+        if (h->next_handle == 0)
+            return NULL;
+        h = core_get_data(h->next_handle);
+        h->next_handle = 0;
+    }
+    return &h->shortcuts[handle_index];
+}
+
+bool verify_shortcut(struct shortcut* sc)
+{
+    switch (sc->type)
+    {
+        case SHORTCUT_UNDEFINED:
+            return false;
+        case SHORTCUT_BROWSER:
+        case SHORTCUT_FILE:
+            if (sc->u.path[0] == '\0')
+                return false;
+            if (sc->name[0] == '\0')
+                strlcpy(sc->name, sc->u.path, MAX_SHORTCUT_NAME);
+            break;
+        case SHORTCUT_SETTING:
+            break;
+    }
+    return true;
+}
+
+static void init_shortcut(struct shortcut* sc)
+{
+    sc->type = SHORTCUT_UNDEFINED;
+    sc->name[0] = '\0';
+    sc->u.path[0] = '\0';
+    sc->icon = Icon_NOICON;
+}    
+static int first_idx_to_writeback = -1;
+void shortcuts_ata_idle_callback(void* data)
+{
+    (void)data;
+    int fd;
+    char buf[MAX_PATH];
+    if (first_idx_to_writeback < 0)
+        return;
+    fd = open(SHORTCUTS_FILENAME, O_APPEND|O_RDWR);
+    if (fd < 0)
+        return;
+    while (first_idx_to_writeback < shortcut_count)
+    {
+        struct shortcut* sc = get_shortcut(first_idx_to_writeback++);
+        char *type;
+        int len;
+        if (!sc)
+            break;
+        switch (sc->type)
+        {
+            case SHORTCUT_SETTING:
+                type = "setting";
+                break;
+            case SHORTCUT_BROWSER:
+                type = "browse";
+                break;
+            case SHORTCUT_FILE:
+                type = "file";
+                break;
+            case SHORTCUT_UNDEFINED:
+                type = "";
+                break;
+        }
+        len = snprintf(buf, MAX_PATH, "[shortcut]\ntype: %s\ndata: ", type);
+        write(fd, buf, len);
+        if (sc->type == SHORTCUT_SETTING)
+            write(fd, sc->u.setting->cfg_name, strlen(sc->u.setting->cfg_name));
+        else
+            write(fd, sc->u.path, strlen(sc->u.path));
+        write(fd, "\n\n", 2);
+    }
+    close(fd);
+    first_idx_to_writeback = -1;
+}
+void shortcuts_add(enum shortcut_type type, char* value)
+{
+    struct shortcut* sc = get_shortcut(shortcut_count++);
+    if (!sc)
+        return;
+    init_shortcut(sc);
+    sc->type = type;
+    if (type == SHORTCUT_SETTING)
+        sc->u.setting = (void*)value;
+    else
+        strlcpy(sc->u.path, value, MAX_PATH);
+    first_idx_to_writeback = shortcut_count - 1;
+    register_storage_idle_func(shortcuts_ata_idle_callback);
+}
+        
+
+int readline_cb(int n, char *buf, void *parameters)
+{
+    (void)n;
+    (void)parameters;
+    struct shortcut **param = (struct shortcut**)parameters;
+    struct shortcut* sc = *param;
+    char *name, *value;
+
+    if (!strcasecmp(skip_whitespace(buf), "[shortcut]"))
+    {
+        if (sc && verify_shortcut(sc))
+            shortcut_count++;
+        sc = get_shortcut(shortcut_count);
+        if (!sc)
+            return 1;
+        init_shortcut(sc);
+        *param = sc;
+    }
+    else if (sc && settings_parseline(buf, &name, &value))
+    {
+        if (!strcmp(name, "type"))
+        {
+            if (!strcmp(value, "browse"))
+                sc->type = SHORTCUT_BROWSER;
+            else if (!strcmp(value, "file"))
+                sc->type = SHORTCUT_FILE;
+            else if (!strcmp(value, "setting"))
+                sc->type = SHORTCUT_SETTING;
+        }
+        else if (!strcmp(name, "name"))
+        {
+            strlcpy(sc->name, value, MAX_SHORTCUT_NAME);
+        }
+        else if (!strcmp(name, "data"))
+        {
+            switch (sc->type)
+            {
+                case SHORTCUT_UNDEFINED:
+                    *param = NULL;
+                    break;
+                case SHORTCUT_BROWSER:
+                case SHORTCUT_FILE:
+                    strlcpy(sc->u.path, value, MAX_PATH);
+                    break;
+                case SHORTCUT_SETTING:
+                {
+                    int i;
+                    /* Find the setting */
+                    for (i=0; i<nb_settings; i++)
+                        if (settings[i].cfg_name &&
+                            !strcmp(settings[i].cfg_name, value))
+                            break;
+                    if (i < nb_settings)
+                        sc->u.setting = &settings[i];
+                    else
+                        *param = NULL;
+                }
+                break;
+            }
+        }
+        else if (!strcmp(name, "icon"))
+        {
+            if (!strcmp(value, "filetype") && sc->type != SHORTCUT_SETTING && sc->u.path[0])
+            {
+                sc->icon = filetype_get_icon(filetype_get_attr(sc->u.path));
+            }
+            else
+            {
+                sc->icon = atoi(value);
+            }
+        }
+    }
+    return 0;
+}
+void shortcuts_init(void)
+{
+    int fd;
+    char buf[512];
+    struct shortcut *param = NULL;
+    struct shortcut_handle *h;
+    shortcut_count = 0;
+    fd = open_utf8(SHORTCUTS_FILENAME, O_RDONLY);
+    if (fd < 0)
+        return;
+    first_handle = core_alloc("shortcuts_head", sizeof(struct shortcut_handle));
+    if (first_handle == 0)
+        return;
+    h = core_get_data(first_handle);
+    h->next_handle = 0;
+    fast_readline(fd, buf, sizeof buf, &param, readline_cb);
+    close(fd);
+    if (param && verify_shortcut(param))
+        shortcut_count++;
+}
+
+const char * shortcut_menu_get_name(int selected_item, void * data,
+                                   char * buffer, size_t buffer_len)
+{
+    (void)data;
+    (void)buffer;
+    (void)buffer_len;
+    struct shortcut *sc = get_shortcut(selected_item);
+    if (!sc)
+        return "";
+    if (sc->type == SHORTCUT_SETTING)
+        return sc->name[0] ? sc->name : P2STR(ID2P(sc->u.setting->lang_id));
+    return sc->name[0] ? sc->name : sc->u.path;
+}
+
+int shortcut_menu_get_action(int action, struct gui_synclist *lists)
+{
+    (void)lists;
+    if (action == ACTION_STD_OK)
+        return ACTION_STD_CANCEL;
+    return action;
+}
+int shortcut_menu_get_icon(int selected_item, void * data)
+{
+    (void)data;
+    struct shortcut *sc = get_shortcut(selected_item);
+    if (!sc)
+        return Icon_NOICON;
+    return sc->icon;
+}
+
+int do_shortcut_menu(void *ignored)
+{
+    (void)ignored;
+    struct simplelist_info list;
+    struct shortcut *sc;
+    int done = GO_TO_PREVIOUS;
+    simplelist_info_init(&list, "shortcuts", shortcut_count, NULL);
+    list.get_name = shortcut_menu_get_name;
+    list.action_callback = shortcut_menu_get_action;
+    list.get_icon = shortcut_menu_get_icon;
+    list.title_icon = Icon_Rockbox;
+    
+    while (done == GO_TO_PREVIOUS)
+    {
+        if (simplelist_show_list(&list))
+            return GO_TO_PREVIOUS; /* some error happened?! */
+        if (list.selection == -1)
+            return GO_TO_PREVIOUS;
+        else
+        {
+            sc = get_shortcut(list.selection);
+            if (!sc)
+                continue;
+            switch (sc->type)
+            {
+                case SHORTCUT_UNDEFINED:
+                    break;
+                case SHORTCUT_FILE:
+                    if (!file_exists(sc->u.path))
+                    {
+                        splash(HZ, ID2P(LANG_NO_FILES));
+                        break;
+                    }
+                    /* else fall through */
+                case SHORTCUT_BROWSER:
+                {
+                    struct browse_context browse;
+                    browse_context_init(&browse, global_settings.dirfilter, 0,
+                            NULL, NOICON, sc->u.path, NULL);
+                    if (sc->type == SHORTCUT_FILE)
+                        browse.flags |= BROWSE_RUNFILE;
+                    done = rockbox_browse(&browse);
+                }
+                break;
+                case SHORTCUT_SETTING:
+                    do_setting_screen(sc->u.setting,
+                            sc->name[0] ? sc->name : P2STR(ID2P(sc->u.setting->lang_id)),NULL);
+                    break;
+            }
+        }
+    }
+    return done;
+}
diff --git a/apps/shortcuts.h b/apps/shortcuts.h
new file mode 100644
index 0000000..74ff446
--- /dev/null
+++ b/apps/shortcuts.h
@@ -0,0 +1,38 @@
+/***************************************************************************
+ *
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2011 Jonathan Gordon
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __SHORTCUTS_H__
+#define __SHORTCUTS_H__
+#include <stdbool.h>
+#include <stdlib.h>
+ 
+enum shortcut_type {
+    SHORTCUT_UNDEFINED = -1,
+    SHORTCUT_SETTING,
+    SHORTCUT_FILE,
+    SHORTCUT_BROWSER
+};
+
+void shortcuts_add(enum shortcut_type type, char* value);
+void shortcuts_init(void);
+int do_shortcut_menu(void*ignored);
+
+#endif
diff --git a/apps/tree.c b/apps/tree.c
index 24acd5a..7aed09a 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -997,7 +997,10 @@ int rockbox_browse(struct browse_context *browse)
         tc.browse = browse;
         strcpy(current, browse->root);
         set_current_file(current);
-        ret_val = dirbrowse();
+        if (browse->flags&BROWSE_RUNFILE)
+            ret_val = ft_enter(&tc);
+        else
+            ret_val = dirbrowse();
     }
     backup_count--;
     if (backup_count >= 0)
diff --git a/apps/tree.h b/apps/tree.h
index 2b29605..a12045c 100644
--- a/apps/tree.h
+++ b/apps/tree.h
@@ -36,8 +36,10 @@ struct entry {
 
 #define BROWSE_SELECTONLY       0x0001  /* exit on selecting a file */
 #define BROWSE_NO_CONTEXT_MENU  0x0002  /* disable context menu */
+#define BROWSE_RUNFILE          0x0004  /* do ft_open() on the file instead of browsing */
 #define BROWSE_SELECTED         0x0100  /* this bit is set if user selected item */
 
+
 struct tree_context;
 
 struct tree_cache {
