]> git.sesse.net Git - vlc/blobdiff - modules/gui/ncurses.c
ncurses: remove "default: break;" from switches
[vlc] / modules / gui / ncurses.c
index 0760d81defc2c095238b0eb8de5cf57ea25f9ecb..176e320fe8fc5efe2a6d210db748c350e1be8819 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
-/*
- * Note that when we use wide characters (and link with libncursesw),
- * we assume that an UTF8 locale is used (or compatible, such as ASCII).
- * Other characters encodings are not supported.
- */
+/* UTF8 locale is required */
 
 /*****************************************************************************
  * Preamble
 #include <vlc_common.h>
 #include <vlc_plugin.h>
 
-#ifdef HAVE_NCURSESW
-#   define _XOPEN_SOURCE_EXTENDED 1
-#   include <wchar.h>
-#endif
+#define _XOPEN_SOURCE_EXTENDED 1
+#include <wchar.h>
 
 #include <ncurses.h>
 
@@ -64,9 +58,6 @@
 #   include <sys/stat.h>
 #endif
 
-#define SEARCH_CHAIN_SIZE 20
-#define OPEN_CHAIN_SIZE 50
-
 /*****************************************************************************
  * Local prototypes.
  *****************************************************************************/
@@ -101,7 +92,7 @@ enum
     BOX_NONE,
     BOX_HELP,
     BOX_INFO,
-    BOX_LOG,
+//  BOX_LOG,
     BOX_PLAYLIST,
     BOX_SEARCH,
     BOX_OPEN,
@@ -110,6 +101,7 @@ enum
     BOX_OBJECTS,
     BOX_STATS
 };
+
 enum
 {
     C_DEFAULT = 0,
@@ -119,38 +111,65 @@ enum
     C_PLAYLIST_3,
     C_BOX,
     C_STATUS,
+#if 0
     C_INFO,
     C_ERROR,
     C_WARNING,
     C_DEBUG,
+#endif
     C_CATEGORY,
-    C_FOLDER
+    C_FOLDER,
+    /* XXX: new elements here ! */
+
+    C_MAX
 };
-enum
+
+/* Available colors: BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE */
+static const struct { short f; short b; } color_pairs[] =
 {
-    VIEW_CATEGORY,
-    VIEW_ONELEVEL
+    /* element */       /* foreground*/ /* background*/
+    [C_TITLE]       = { COLOR_YELLOW,   COLOR_BLACK },
+
+    /* jamaican playlist, for rastafari sisters & brothers! */
+    [C_PLAYLIST_1]  = { COLOR_GREEN,    COLOR_BLACK },
+    [C_PLAYLIST_2]  = { COLOR_YELLOW,   COLOR_BLACK },
+    [C_PLAYLIST_3]  = { COLOR_RED,      COLOR_BLACK },
+
+    /* used in DrawBox() */
+    [C_BOX]         = { COLOR_CYAN,     COLOR_BLACK },
+    /* Source: State, Position, Volume, Chapters, etc...*/
+    [C_STATUS]      = { COLOR_BLUE,     COLOR_BLACK },
+
+#if 0
+    /* VLC messages, keep the order from highest priority to lowest */
+    [C_INFO]        = { COLOR_BLACK,    COLOR_WHITE },
+    [C_ERROR]       = { COLOR_RED,      COLOR_BLACK },
+    [C_WARNING]     = { COLOR_YELLOW,   COLOR_BLACK },
+    [C_DEBUG]       = { COLOR_WHITE,    COLOR_BLACK },
+#endif
+    /* Category title: help, info, metadata */
+    [C_CATEGORY]    = { COLOR_MAGENTA,  COLOR_BLACK },
+    /* Folder (BOX_BROWSE) */
+    [C_FOLDER]      = { COLOR_RED,      COLOR_BLACK },
 };
+
 struct dir_entry_t
 {
-    bool  b_file;
+    bool        b_file;
     char        *psz_path;
 };
+
 struct pl_item_t
 {
     playlist_item_t *p_item;
     char            *psz_display;
 };
+
 struct intf_sys_t
 {
     input_thread_t *p_input;
-    playlist_t     *p_playlist;
-
-    bool      b_color;
-    bool      b_color_started;
 
-    float           f_slider;
-    float           f_slider_old;
+    bool            b_color;
 
     WINDOW          *w;
 
@@ -166,28 +185,23 @@ struct intf_sys_t
 
     playlist_item_t *p_node;        /* current node */
 
-    int             b_box_cleared;
+//  msg_subscription_t* p_sub;                  /* message bank subscription */
 
-    msg_subscription_t* p_sub;                  /* message bank subscription */
-
-    char            *psz_search_chain;          /* for playlist searching    */
-    char            *psz_old_search;            /* for searching next        */
+    char            psz_search_chain[20];
+    char            *psz_old_search;
     int             i_before_search;
 
-    char            *psz_open_chain;
-#ifndef HAVE_NCURSESW
-    char             psz_partial_keys[7];
-#endif
+    char            psz_open_chain[50];
 
     char            *psz_current_dir;
     int             i_dir_entries;
     struct dir_entry_t  **pp_dir_entries;
-    bool      b_show_hidden_files;
+    bool            b_show_hidden_files;
 
-    int             i_current_view;             /* playlist view             */
+    bool            category_view;
     struct pl_item_t    **pp_plist;
     int             i_plist_entries;
-    bool      b_need_update;              /* for playlist view         */
+    bool            b_need_update;              /* for playlist view         */
 };
 
 /*****************************************************************************
@@ -218,6 +232,22 @@ static int comp_dir_entries(const void *pp_dir_entry1, const void *pp_dir_entry2
     return p_dir_entry1->b_file ? 1 : -1;
 }
 
+static bool IsFile(const char *current_dir, const char *entry)
+{
+    bool ret = true;
+#ifdef S_ISDIR
+    char *uri;
+    struct stat st;
+
+    if (asprintf(&uri, "%s/%s", current_dir, entry) != -1)
+    {
+        ret = vlc_stat(uri, &st) || !S_ISDIR(st.st_mode);
+        free(uri);
+    }
+#endif
+    return ret;
+}
+
 static void ReadDir(intf_thread_t *p_intf)
 {
     intf_sys_t *p_sys = p_intf->p_sys;
@@ -248,41 +278,21 @@ static void ReadDir(intf_thread_t *p_intf)
     /* while we still have entries in the directory */
     while ((psz_entry = vlc_readdir(p_current_dir)))
     {
-#if defined(S_ISDIR)
-        struct stat stat_data;
-#endif
         struct dir_entry_t *p_dir_entry;
-        char *psz_uri = NULL;
 
         if (!p_sys->b_show_hidden_files)
             if (*psz_entry == '.' && strcmp(psz_entry, ".."))
                 goto next;
 
-        if (asprintf(&psz_uri, "%s/%s", p_sys->psz_current_dir, psz_entry) == -1)
-        {
-            psz_uri = NULL;
-            goto next;
-        }
-
         if (!(p_dir_entry = malloc(sizeof *p_dir_entry)))
             goto next;
 
-        p_dir_entry->b_file =
-#if defined(S_ISDIR)
-            vlc_stat(psz_uri, &stat_data) || !S_ISDIR(stat_data.st_mode)
-/*#elif defined(DT_DIR)
-            !(p_dir_content->d_type & DT_DIR)*/
-#else
-            false
-#endif
-        ;
-
+        p_dir_entry->b_file = IsFile(p_sys->psz_current_dir, psz_entry);
         p_dir_entry->psz_path = strdup(psz_entry);
         INSERT_ELEM(p_sys->pp_dir_entries, p_sys->i_dir_entries,
              p_sys->i_dir_entries, p_dir_entry);
 
 next:
-        free(psz_uri);
         free(psz_entry);
     }
 
@@ -309,68 +319,75 @@ static void PlaylistDestroy(intf_sys_t *p_sys)
     p_sys->pp_plist = NULL;
 }
 
-static void PlaylistAddNode(intf_thread_t *p_intf, playlist_item_t *p_node,
-                             int i, const char *c)
+static inline playlist_item_t *PlaylistGetRoot(intf_thread_t *p_intf)
 {
-    intf_sys_t *p_sys = p_intf->p_sys;
-    playlist_item_t *p_child;
-    int k;
+    playlist_t *p_playlist = pl_Get(p_intf);
+    return p_intf->p_sys->category_view ?
+        p_playlist->p_root_category :
+        p_playlist->p_root_onelevel;
+}
 
-    for(k = 0; k < p_node->i_children; k++)
-    {
-        char *psz_display;
-        p_child = p_node->pp_children[k];
-        char *psz_name = input_item_GetTitleFbName(p_child->p_input);
+static bool PlaylistAddChild(intf_sys_t *p_sys, playlist_item_t *p_child,
+                             const char *c, const char d)
+{
+    int ret;
+    char *psz_name = input_item_GetTitleFbName(p_child->p_input);
+    struct pl_item_t *p_pl_item = malloc(sizeof *p_pl_item);
 
-        if (c && *c)
-        {
-            if (asprintf(&psz_display, "%s%c-%s", c,
-                    k == p_node->i_children - 1 ?  '`' : '|', psz_name) == -1)
-                return;
-        }
-        else if (asprintf(&psz_display, " %s", psz_name) == -1)
-                return;
+    if (!psz_name || !p_pl_item)
+        goto error;
 
-        free(psz_name);
-        struct pl_item_t *p_pl_item = malloc(sizeof(struct pl_item_t));
-        if (!p_pl_item)
+    p_pl_item->p_item = p_child;
+
+    if (c && *c)
+        ret = asprintf(&p_pl_item->psz_display, "%s%c-%s", c, d, psz_name);
+    else
+        ret = asprintf(&p_pl_item->psz_display, " %s", psz_name);
+
+    free(psz_name);
+    psz_name = NULL;
+
+    if (ret == -1)
+        goto error;
+
+    INSERT_ELEM(p_sys->pp_plist, p_sys->i_plist_entries,
+                 p_sys->i_plist_entries, p_pl_item);
+
+    return true;
+
+error:
+    free(psz_name);
+    free(p_pl_item);
+    return false;
+}
+
+static void PlaylistAddNode(intf_sys_t *p_sys, playlist_item_t *p_node,
+                            const char *c)
+{
+    for(int k = 0; k < p_node->i_children; k++)
+    {
+        playlist_item_t *p_child = p_node->pp_children[k];
+        char d = k == p_node->i_children - 1 ? '`' : '|';
+        if(!PlaylistAddChild(p_sys, p_child, c, d))
             return;
-        p_pl_item->psz_display = psz_display;
-        p_pl_item->p_item = p_child;
-        INSERT_ELEM(p_sys->pp_plist, p_sys->i_plist_entries,
-                     p_sys->i_plist_entries, p_pl_item);
-        i++;
 
-        if (p_child->i_children > 0)
+        if (p_child->i_children <= 0)
+            continue;
+
+        if (*c)
         {
             char *psz_tmp;
             if (asprintf(&psz_tmp, "%s%c ", c,
                      k == p_node->i_children - 1 ? ' ' : '|') == -1)
                 return;
-            PlaylistAddNode(p_intf, p_child, i,
-                             strlen(c) ? psz_tmp : " ");
+            PlaylistAddNode(p_sys, p_child, psz_tmp);
             free(psz_tmp);
         }
+        else
+            PlaylistAddNode(p_sys, p_child, " ");
     }
 }
 
-static playlist_item_t *PlaylistGetRoot(intf_thread_t *p_intf)
-{
-    intf_sys_t *p_sys = p_intf->p_sys;
-    playlist_t *p_playlist = pl_Get(p_intf);
-    playlist_item_t *p_item;
-
-    switch(p_sys->i_current_view)
-    {
-        case VIEW_CATEGORY:
-            p_item = p_playlist->p_root_category;
-            break;
-        default:
-            p_item = p_playlist->p_root_onelevel;
-    }
-    return p_item;
-}
-
 static void PlaylistRebuild(intf_thread_t *p_intf)
 {
     intf_sys_t *p_sys = p_intf->p_sys;
@@ -378,12 +395,8 @@ static void PlaylistRebuild(intf_thread_t *p_intf)
 
     PL_LOCK;
 
-    /* First clear the old one */
     PlaylistDestroy(p_sys);
-
-    /* Build the new one */
-    PlaylistAddNode(p_intf, PlaylistGetRoot(p_intf), 0, "");
-
+    PlaylistAddNode(p_sys, PlaylistGetRoot(p_intf), "");
     p_sys->b_need_update = false;
 
     PL_UNLOCK;
@@ -394,100 +407,94 @@ static int PlaylistChanged(vlc_object_t *p_this, const char *psz_variable,
 {
     VLC_UNUSED(p_this); VLC_UNUSED(psz_variable);
     VLC_UNUSED(oval); VLC_UNUSED(nval);
-    intf_thread_t *p_intf = (intf_thread_t *)param;
-    playlist_t *p_playlist = pl_Get(p_intf);
-    p_intf->p_sys->b_need_update = true;
-    p_intf->p_sys->p_node = playlist_CurrentPlayingItem(p_playlist) ? playlist_CurrentPlayingItem(p_playlist)->p_parent : NULL;
+
+    intf_thread_t *p_intf   = (intf_thread_t *)param;
+    intf_sys_t *p_sys       = p_intf->p_sys;
+    playlist_item_t *p_node = playlist_CurrentPlayingItem(pl_Get(p_intf));
+
+    p_sys->b_need_update = true;
+    p_sys->p_node = p_node ? p_node->p_parent : NULL;
+
     return VLC_SUCCESS;
 }
 
 /* Playlist suxx */
 /* This function have to be called with the playlist locked */
 static inline bool PlaylistIsPlaying(playlist_t *p_playlist,
-                                      playlist_item_t *p_item)
+                                     playlist_item_t *p_item)
 {
     playlist_item_t *p_played_item = playlist_CurrentPlayingItem(p_playlist);
-    return(p_item && p_played_item && p_item->p_input && p_played_item->p_input
-        && p_item->p_input->i_id == p_played_item->p_input->i_id);
+    return p_item                && p_played_item
+        && p_item->p_input       && p_played_item->p_input
+        && p_item->p_input->i_id == p_played_item->p_input->i_id;
 }
 
-static int SubSearchPlaylist(intf_thread_t *p_intf, char *psz_searchstring,
+static int SubSearchPlaylist(intf_sys_t *p_sys, char *psz_searchstring,
                               int i_start, int i_stop)
 {
-    intf_sys_t *p_sys = p_intf->p_sys;
-    int i, i_item = -1;
-
-    for(i = i_start + 1; i < i_stop; i++)
+    for(int i = i_start + 1; i < i_stop; i++)
         if (strcasestr(p_sys->pp_plist[i]->psz_display, psz_searchstring))
-        {
-            i_item = i;
-            break;
-        }
+            return i;
 
-    return i_item;
+    return -1;
 }
 
-static void SearchPlaylist(intf_thread_t *p_intf, char *psz_searchstring)
+static void SearchPlaylist(intf_sys_t *p_sys, char *psz_searchstring)
 {
-    int i_max;
-    int i_first = 0 ;
-    int i_item = -1;
-    intf_sys_t *p_sys = p_intf->p_sys;
+    int i_item, i_first = p_sys->i_before_search;
 
-    if (p_sys->i_before_search >= 0)
-        i_first = p_sys->i_before_search;
+    if (i_first < 0)
+        i_first = 0;
 
-    if ((! psz_searchstring) ||  strlen(psz_searchstring) <= 0)
+    if (!psz_searchstring || !*psz_searchstring)
     {
         p_sys->i_box_plidx = p_sys->i_before_search;
         return;
     }
 
-    i_max = p_sys->i_plist_entries;
-
-    i_item = SubSearchPlaylist(p_intf, psz_searchstring, i_first + 1, i_max);
+    i_item = SubSearchPlaylist(p_sys, psz_searchstring, i_first + 1,
+                               p_sys->i_plist_entries);
     if (i_item < 0)
-        i_item = SubSearchPlaylist(p_intf, psz_searchstring, 0, i_first);
-
-    if (i_item < 0 || i_item >= i_max) return;
+        i_item = SubSearchPlaylist(p_sys, psz_searchstring, 0, i_first);
 
-    p_sys->i_box_plidx = i_item;
+    if (i_item > 0)
+        p_sys->i_box_plidx = i_item;
 }
 
-static void FindIndex(intf_thread_t *p_intf, playlist_t *p_playlist)
+static inline bool IsIndex(intf_sys_t *p_sys, playlist_t *p_playlist, int i)
 {
-    intf_sys_t *p_sys = p_intf->p_sys;
-    int i;
+    playlist_item_t *p_item = p_sys->pp_plist[i]->p_item;
+    return (p_item->i_children == 0 && p_item == p_sys->p_node) ||
+            PlaylistIsPlaying(p_playlist, p_item);
+}
 
-    if (p_sys->i_box_plidx < p_sys->i_plist_entries && p_sys->i_box_plidx >= 0)
-    {
-        playlist_item_t *p_item = p_sys->pp_plist[p_sys->i_box_plidx]->p_item;
+static void FindIndex(intf_sys_t *p_sys, playlist_t *p_playlist, bool locked)
+{
+    int plidx = p_sys->i_box_plidx;
+    if (!locked)
         PL_LOCK;
-        if ((p_item->i_children == 0 && p_item == p_sys->p_node) ||
-                PlaylistIsPlaying(p_playlist, p_item))
-        {
-            PL_UNLOCK;
-            return;
-        }
-    }
 
-    for(i = 0; i < p_sys->i_plist_entries; i++)
+    if (plidx < 0 || plidx >= p_sys->i_plist_entries ||
+        !IsIndex(p_sys, p_playlist, plidx))
     {
-        playlist_item_t *p_item = p_sys->pp_plist[i]->p_item;
-        if ((p_item->i_children == 0 && p_item == p_sys->p_node) ||
-                PlaylistIsPlaying(p_playlist, p_item))
-        {
-            p_sys->i_box_plidx = i;
-            break;
-        }
+        for(int i = 0; i < p_sys->i_plist_entries; i++)
+            if (IsIndex(p_sys, p_playlist, i))
+            {
+                p_sys->i_box_plidx = i;
+                break;
+            }
     }
-    PL_UNLOCK;
+
+    if (!locked)
+        PL_UNLOCK;
 }
 
+/****************************************************************************
+ * Drawing
+ ****************************************************************************/
+
 static void start_color_and_pairs(intf_thread_t *p_intf)
 {
-    assert(p_intf->p_sys->b_color && !p_intf->p_sys->b_color_started);
-
     if (!has_colors())
     {
         p_intf->p_sys->b_color = false;
@@ -496,82 +503,46 @@ static void start_color_and_pairs(intf_thread_t *p_intf)
     }
 
     start_color();
-
-    /* Available colors: BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE */
+    for(int i = C_DEFAULT + 1; i < C_MAX; i++)
+        init_pair(i, color_pairs[i].f, color_pairs[i].b);
 
     /* untested, in all my terminals, !can_change_color() --funman */
     if (can_change_color())
         init_color(COLOR_YELLOW, 960, 500, 0); /* YELLOW -> ORANGE */
-
-    /* title */
-    init_pair(C_TITLE, COLOR_YELLOW, COLOR_BLACK);
-
-    /* jamaican playlist */
-    init_pair(C_PLAYLIST_1, COLOR_GREEN, COLOR_BLACK);
-    init_pair(C_PLAYLIST_2, COLOR_YELLOW, COLOR_BLACK);
-    init_pair(C_PLAYLIST_3, COLOR_RED, COLOR_BLACK);
-
-    /* used in DrawBox() */
-    init_pair(C_BOX, COLOR_CYAN, COLOR_BLACK);
-    /* Source, State, Position, Volume, Chapters, etc...*/
-    init_pair(C_STATUS, COLOR_BLUE, COLOR_BLACK);
-
-    /* VLC messages, keep the order from highest priority to lowest */
-
-    /* infos */
-    init_pair(C_INFO, COLOR_BLACK, COLOR_WHITE);
-    /* errors */
-    init_pair(C_ERROR, COLOR_RED, COLOR_BLACK);
-    /* warnings */
-    init_pair(C_WARNING, COLOR_YELLOW, COLOR_BLACK);
-/* debug */
-    init_pair(C_DEBUG, COLOR_WHITE, COLOR_BLACK);
-
-    /* Category title (help, info, metadata) */
-    init_pair(C_CATEGORY, COLOR_MAGENTA, COLOR_BLACK);
-
-    /* Folder (BOX_BROWSE) */
-    init_pair(C_FOLDER, COLOR_RED, COLOR_BLACK);
-
-    p_intf->p_sys->b_color_started = true;
 }
 
-/****************************************************************************
- * Drawing
- ****************************************************************************/
-
 static void DrawBox(WINDOW *win, int y, int x, int h, int w, const char *title, bool b_color)
 {
-    int i;
     int i_len;
 
-    if (w > 3 && h > 2)
-    {
-        if (b_color)
-            wcolor_set(win, C_BOX, NULL);
-        if (!title) title = "";
-        i_len = strlen(title);
+    if (w <= 3 || h <= 2)
+        return;
 
-        if (i_len > w - 2) i_len = w - 2;
+    if (b_color)
+        wcolor_set(win, C_BOX, NULL);
+    if (!title) title = "";
+    i_len = strlen(title);
 
-        mvwaddch(win, y, x,    ACS_ULCORNER);
-        mvwhline(win, y, x+1,  ACS_HLINE, (w-i_len-2)/2);
-        mvwprintw(win,y, x+1+(w-i_len-2)/2, "%s", title);
-        mvwhline(win, y, x+(w-i_len)/2+i_len,  ACS_HLINE, w - 1 - ((w-i_len)/2+i_len));
-        mvwaddch(win, y, x+w-1,ACS_URCORNER);
+    if (i_len > w - 2)
+        i_len = w - 2;
 
-        for(i = 0; i < h-2; i++)
-        {
-            mvwaddch(win, y+i+1, x,     ACS_VLINE);
-            mvwaddch(win, y+i+1, x+w-1, ACS_VLINE);
-        }
+    mvwaddch(win, y, x,    ACS_ULCORNER);
+    mvwhline(win, y, x+1,  ACS_HLINE, (w-i_len-2)/2);
+    mvwprintw(win,y, x+1+(w-i_len-2)/2, "%s", title);
+    mvwhline(win, y, x+(w-i_len)/2+i_len,  ACS_HLINE, w - 1 - ((w-i_len)/2+i_len));
+    mvwaddch(win, y, x+w-1,ACS_URCORNER);
 
-        mvwaddch(win, y+h-1, x,     ACS_LLCORNER);
-        mvwhline(win, y+h-1, x+1,   ACS_HLINE, w - 2);
-        mvwaddch(win, y+h-1, x+w-1, ACS_LRCORNER);
-        if (b_color)
-            wcolor_set(win, C_DEFAULT, NULL);
+    for(int i = 0; i < h-2; i++)
+    {
+        mvwaddch(win, y+i+1, x,     ACS_VLINE);
+        mvwaddch(win, y+i+1, x+w-1, ACS_VLINE);
     }
+
+    mvwaddch(win, y+h-1, x,     ACS_LLCORNER);
+    mvwhline(win, y+h-1, x+1,   ACS_HLINE, w - 2);
+    mvwaddch(win, y+h-1, x+w-1, ACS_LRCORNER);
+    if (b_color)
+        wcolor_set(win, C_DEFAULT, NULL);
 }
 
 static void DrawEmptyLine(WINDOW *win, int y, int x, int w)
@@ -593,7 +564,7 @@ static void DrawLine(WINDOW *win, int y, int x, int w)
 static void mvnprintw(int y, int x, int w, const char *p_fmt, ...)
 {
     va_list  vl_args;
-    char    *p_buf = NULL;
+    char    *p_buf;
     int      i_len;
 
     if (w <= 0)
@@ -606,7 +577,6 @@ static void mvnprintw(int y, int x, int w, const char *p_fmt, ...)
 
     i_len = strlen(p_buf);
 
-#ifdef HAVE_NCURSESW
     wchar_t psz_wide[i_len + 1];
 
     EnsureUTF8(p_buf);
@@ -614,117 +584,83 @@ static void mvnprintw(int y, int x, int w, const char *p_fmt, ...)
 
     size_t i_width; /* number of columns */
 
-    if (i_char_len == (size_t)-1)
-    /* an invalid character was encountered */
+    if (i_char_len == (size_t)-1) /* an invalid character was encountered */
     {
         free(p_buf);
         return;
     }
-    else
+
+    i_width = wcswidth(psz_wide, i_char_len);
+    if (i_width == (size_t)-1)
     {
-        i_width = wcswidth(psz_wide, i_char_len);
-        if (i_width == (size_t)-1)
+        /* a non printable character was encountered */
+        i_width = 0;
+        for(unsigned i = 0 ; i < i_char_len ; i++)
         {
-            /* a non printable character was encountered */
-            unsigned int i;
-            int i_cwidth;
-            i_width = 0;
-            for(i = 0 ; i < i_char_len ; i++)
-            {
-                i_cwidth = wcwidth(psz_wide[i]);
-                if (i_cwidth != -1)
-                    i_width += i_cwidth;
-            }
+            int i_cwidth = wcwidth(psz_wide[i]);
+            if (i_cwidth != -1)
+                i_width += i_cwidth;
         }
     }
-    if (i_width > (size_t)w)
-    {
-        int i_total_width = 0;
-        int i = 0;
-        while (i_total_width < w)
-        {
-            i_total_width += wcwidth(psz_wide[i]);
-            if (w > 7 && i_total_width >= w/2)
-            {
-                psz_wide[i  ] = '.';
-                psz_wide[i+1] = '.';
-                i_total_width -= wcwidth(psz_wide[i]) - 2;
-                if (i > 0)
-                {
-                    /* we require this check only if at least one character
-                     * 4 or more columns wide exists (which i doubt) */
-                    psz_wide[i-1] = '.';
-                    i_total_width -= wcwidth(psz_wide[i-1]) - 1;
-                }
-
-                /* find the widest string */
-                int j, i_2nd_width = 0;
-                for(j = i_char_len - 1; i_2nd_width < w - i_total_width; j--)
-                    i_2nd_width += wcwidth(psz_wide[j]);
-
-                /* we already have i_total_width columns filled, and we can't
-                 * have more than w columns */
-                if (i_2nd_width > w - i_total_width)
-                    j++;
-
-                wmemmove(&psz_wide[i+2], &psz_wide[j+1], i_char_len - j - 1);
-                psz_wide[i + 2 + i_char_len - j - 1] = '\0';
-                break;
-            }
-            i++;
-        }
-        if (w <= 7) /* we don't add the '...' else we lose too much chars */
-            psz_wide[i] = '\0';
 
-        size_t i_wlen = wcslen(psz_wide) * 6 + 1; /* worst case */
-        char psz_ellipsized[i_wlen];
-        wcstombs(psz_ellipsized, psz_wide, i_wlen);
-        mvprintw(y, x, "%s", psz_ellipsized);
-    }
-    else
+    if (i_width <= (size_t)w)
     {
         mvprintw(y, x, "%s", p_buf);
         mvhline(y, x + i_width, ' ', w - i_width);
+        free(p_buf);
+        return;
     }
 
-#else
-    if (i_len > w)
+    int i_total_width = 0;
+    int i = 0;
+    while (i_total_width < w)
     {
-        int i_cut = i_len - w;
-        int x1 = i_len/2 - i_cut/2;
-        int x2 = x1 + i_cut;
+        i_total_width += wcwidth(psz_wide[i]);
+        if (w > 7 && i_total_width >= w/2)
+        {
+            psz_wide[i  ] = '.';
+            psz_wide[i+1] = '.';
+            i_total_width -= wcwidth(psz_wide[i]) - 2;
+            if (i > 0)
+            {
+                /* we require this check only if at least one character
+                 * 4 or more columns wide exists (which i doubt) */
+                psz_wide[i-1] = '.';
+                i_total_width -= wcwidth(psz_wide[i-1]) - 1;
+            }
 
-        if (i_len > x2)
-            memmove(&p_buf[x1], &p_buf[x2], i_len - x2);
+            /* find the widest string */
+            int j, i_2nd_width = 0;
+            for(j = i_char_len - 1; i_2nd_width < w - i_total_width; j--)
+                i_2nd_width += wcwidth(psz_wide[j]);
 
-        p_buf[w] = '\0';
-        if (w > 7)
-        {
-            p_buf[w/2-1] = '.';
-            p_buf[w/2  ] = '.';
-            p_buf[w/2+1] = '.';
+            /* we already have i_total_width columns filled, and we can't
+             * have more than w columns */
+            if (i_2nd_width > w - i_total_width)
+                j++;
+
+            wmemmove(&psz_wide[i+2], &psz_wide[j+1], i_char_len - j - 1);
+            psz_wide[i + 2 + i_char_len - j - 1] = '\0';
+            break;
         }
-        char *psz_local = ToLocale(p_buf);
-        mvprintw(y, x, "%s", psz_local);
-        LocaleFree(p_buf);
-    }
-    else
-    {
-        char *psz_local = ToLocale(p_buf);
-        mvprintw(y, x, "%s", psz_local);
-        LocaleFree(p_buf);
-        mvhline(y, x + i_len, ' ', w - i_len);
+        i++;
     }
-#endif
+    if (w <= 7) /* we don't add the '...' else we lose too much chars */
+        psz_wide[i] = '\0';
+
+    size_t i_wlen = wcslen(psz_wide) * 6 + 1; /* worst case */
+    char psz_ellipsized[i_wlen];
+    wcstombs(psz_ellipsized, psz_wide, i_wlen);
+    mvprintw(y, x, "%s", psz_ellipsized);
+
     free(p_buf);
 }
 
 static void MainBoxWrite(intf_thread_t *p_intf, int l, int x, const char *p_fmt, ...)
 {
-    intf_sys_t     *p_sys = p_intf->p_sys;
-
-    va_list  vl_args;
-    char    *p_buf = NULL;
+    intf_sys_t  *p_sys = p_intf->p_sys;
+    va_list      vl_args;
+    char        *p_buf;
 
     if (l < p_sys->i_box_start || l - p_sys->i_box_start >= p_sys->i_box_lines)
         return;
@@ -772,7 +708,7 @@ static void Redraw(intf_thread_t *p_intf, time_t *t_last_refresh)
 
     /* Title */
     attrset(A_REVERSE);
-    int i_len = strlen("VLC media player "PACKAGE_VERSION);
+    int i_len = sizeof "VLC media player "PACKAGE_VERSION - 1;
     int mid = (COLS - i_len) / 2;
     if (mid < 0)
         mid = 0;
@@ -817,7 +753,9 @@ static void Redraw(intf_thread_t *p_intf, time_t *t_last_refresh)
         else if (val.i_int == PAUSE_S)
             mvnprintw(y++, 0, COLS, _(" State    : Paused %s"), psz_state);
 
-        if (val.i_int != INIT_S && val.i_int != END_S)
+        if (val.i_int == INIT_S || val.i_int == END_S)
+            y += 2;
+        else
         {
             audio_volume_t i_volume;
 
@@ -828,7 +766,7 @@ static void Redraw(intf_thread_t *p_intf, time_t *t_last_refresh)
             var_Get(p_input, "length", &val);
             secstotimestr(buf2, val.i_time / CLOCK_FREQ);
 
-            mvnprintw(y++, 0, COLS, _(" Position : %s/%s (%.2f%%)"), buf1, buf2, p_sys->f_slider);
+            mvnprintw(y++, 0, COLS, _(" Position : %s/%s"), buf1, buf2);
 
             /* Volume */
             aout_VolumeGet(p_playlist, &i_volume);
@@ -852,10 +790,6 @@ static void Redraw(intf_thread_t *p_intf, time_t *t_last_refresh)
                                val.i_int, i_chapter_count);
             }
         }
-        else
-        {
-            y += 2;
-        }
     }
     else
     {
@@ -870,7 +804,13 @@ static void Redraw(intf_thread_t *p_intf, time_t *t_last_refresh)
 
     DrawBox(p_sys->w, y, 0, 3, COLS, "", p_sys->b_color);
     DrawEmptyLine(p_sys->w, y+1, 1, COLS-2);
-    DrawLine(p_sys->w, y+1, 1, (int)(p_intf->p_sys->f_slider/100.0 * (COLS -2)));
+
+    if (p_input && var_GetInteger(p_input, "state") == PLAYING_S)
+    {
+        float pos = var_GetFloat(p_input, "position");
+        DrawLine(p_sys->w, y+1, 1, (int)(pos * (COLS-2)));
+    }
+
     y += 3;
 
     p_sys->i_box_y = y + 1;
@@ -893,12 +833,11 @@ static void Redraw(intf_thread_t *p_intf, time_t *t_last_refresh)
         MainBoxWrite(p_intf, l++, 1, _("     h,H         Show/Hide help box"));
         MainBoxWrite(p_intf, l++, 1, _("     i           Show/Hide info box"));
         MainBoxWrite(p_intf, l++, 1, _("     m           Show/Hide metadata box"));
-        MainBoxWrite(p_intf, l++, 1, _("     L           Show/Hide messages box"));
+//      MainBoxWrite(p_intf, l++, 1, _("     L           Show/Hide messages box"));
         MainBoxWrite(p_intf, l++, 1, _("     P           Show/Hide playlist box"));
         MainBoxWrite(p_intf, l++, 1, _("     B           Show/Hide filebrowser"));
         MainBoxWrite(p_intf, l++, 1, _("     x           Show/Hide objects box"));
         MainBoxWrite(p_intf, l++, 1, _("     S           Show/Hide statistics box"));
-        MainBoxWrite(p_intf, l++, 1, _("     c           Switch color on/off"));
         MainBoxWrite(p_intf, l++, 1, _("     Esc         Close Add/Search entry"));
         MainBoxWrite(p_intf, l++, 1, "");
 
@@ -1031,62 +970,19 @@ static void Redraw(intf_thread_t *p_intf, time_t *t_last_refresh)
 
         if (p_input)
         {
-            int i;
             input_item_t *p_item = input_GetItem(p_input);
             vlc_mutex_lock(&p_item->lock);
-            for(i=0; i<VLC_META_TYPE_COUNT; i++)
+            for(int i=0; i<VLC_META_TYPE_COUNT; i++)
             {
-                if (y >= y_end) break;
                 const char *psz_meta = vlc_meta_Get(p_item->p_meta, i);
-                if (psz_meta && *psz_meta)
-                {
-                    const char *psz_meta_title;
-                    switch(i)
-                    {
-                        case 0:
-                            psz_meta_title = VLC_META_TITLE; break;
-                        case 1:
-                            psz_meta_title = VLC_META_ARTIST; break;
-                        case 2:
-                            psz_meta_title = VLC_META_GENRE ; break;
-                        case 3:
-                            psz_meta_title = VLC_META_COPYRIGHT; break;
-                        case 4:
-                            psz_meta_title = VLC_META_ALBUM; break;
-                        case 5:
-                            psz_meta_title = VLC_META_TRACK_NUMBER; break;
-                        case 6:
-                            psz_meta_title = VLC_META_DESCRIPTION; break;
-                        case 7:
-                            psz_meta_title = VLC_META_RATING; break;
-                        case 8:
-                            psz_meta_title = VLC_META_DATE; break;
-                        case 9:
-                            psz_meta_title = VLC_META_SETTING; break;
-                        case 10:
-                            psz_meta_title = VLC_META_URL; break;
-                        case 11:
-                            psz_meta_title = VLC_META_LANGUAGE; break;
-                        case 12:
-                            psz_meta_title = VLC_META_NOW_PLAYING; break;
-                        case 13:
-                            psz_meta_title = VLC_META_PUBLISHER; break;
-                        case 14:
-                            psz_meta_title = VLC_META_ENCODED_BY; break;
-                        case 15:
-                            psz_meta_title = VLC_META_ART_URL; break;
-                        case 16:
-                            psz_meta_title = VLC_META_TRACKID; break;
-                        default:
-                            psz_meta_title = ""; break;
-                    }
-                    if (p_sys->b_color)
-                        wcolor_set(p_sys->w, C_CATEGORY, NULL);
-                    MainBoxWrite(p_intf, l++, 1, "  [%s]", psz_meta_title);
-                    if (p_sys->b_color)
-                        wcolor_set(p_sys->w, C_DEFAULT, NULL);
-                    MainBoxWrite(p_intf, l++, 1, "      %s", psz_meta);
-                }
+                if (!psz_meta || !*psz_meta)
+                    continue;
+
+                if (p_sys->b_color) wcolor_set(p_sys->w, C_CATEGORY, NULL);
+                MainBoxWrite(p_intf, l++, 1, "  [%s]",
+                             vlc_meta_TypeToLocalizedString(i));
+                if (p_sys->b_color) wcolor_set(p_sys->w, C_DEFAULT, NULL);
+                MainBoxWrite(p_intf, l++, 1, "      %s", psz_meta);
             }
             vlc_mutex_unlock(&p_item->lock);
         }
@@ -1097,15 +993,11 @@ static void Redraw(intf_thread_t *p_intf, time_t *t_last_refresh)
         if (p_sys->i_box_start >= p_sys->i_box_lines_total)
             p_sys->i_box_start = p_sys->i_box_lines_total - 1;
 
-        if (l - p_sys->i_box_start < p_sys->i_box_lines)
-            y += l - p_sys->i_box_start;
-        else
-            y += p_sys->i_box_lines;
+        y += __MIN(l - p_sys->i_box_start, p_sys->i_box_lines);
     }
+#if 0 /* Deprecated API */
     else if (p_sys->i_box_type == BOX_LOG)
     {
-#warning Deprecated API
-#if 0
         int i_line = 0;
         int i_stop;
         int i_start;
@@ -1148,8 +1040,8 @@ static void Redraw(intf_thread_t *p_intf, time_t *t_last_refresh)
         p_intf->p_sys->p_sub->i_start = i_stop;
         vlc_mutex_unlock(p_intf->p_sys->p_sub->p_lock);
         y = y_end;
-#endif
     }
+#endif
     else if (p_sys->i_box_type == BOX_BROWSE)
     {
         /* Filebrowser box */
@@ -1341,17 +1233,10 @@ static void Redraw(intf_thread_t *p_intf, time_t *t_last_refresh)
         int        i_item;
         char       *psz_title;
 
-        switch(p_sys->i_current_view)
-        {
-            case VIEW_ONELEVEL:
-                psz_title = strdup(_(" Playlist (All, one level) "));
-                break;
-            case VIEW_CATEGORY:
-                psz_title = strdup(_(" Playlist (By category) "));
-                break;
-            default:
-                psz_title = strdup(_(" Playlist (Manually added) "));
-        }
+        if (p_sys->category_view)
+            psz_title = strdup(_(" Playlist (By category) "));
+        else
+            psz_title = strdup(_(" Playlist (All, one level) "));
 
         DrawBox(p_sys->w, y++, 0, h, COLS, psz_title, p_sys->b_color);
         free(psz_title);
@@ -1359,9 +1244,8 @@ static void Redraw(intf_thread_t *p_intf, time_t *t_last_refresh)
         if (p_sys->b_need_update || !p_sys->pp_plist)
             PlaylistRebuild(p_intf);
         if (p_sys->b_box_plidx_follow)
-            FindIndex(p_intf, p_playlist);
+            FindIndex(p_sys, p_playlist, false);
 
-        if (p_sys->i_box_plidx < 0) p_sys->i_box_plidx = 0;
         if (p_sys->i_box_plidx < 0) p_sys->i_box_plidx = 0;
         if (p_sys->i_box_plidx >= i_max) p_sys->i_box_plidx = i_max - 1;
 
@@ -1428,16 +1312,10 @@ static void Redraw(intf_thread_t *p_intf, time_t *t_last_refresh)
     if (p_sys->i_box_type == BOX_SEARCH)
     {
         DrawEmptyLine(p_sys->w, 7, 1, COLS-2);
-        if (p_sys->psz_search_chain)
-        {
-            if (*p_sys->psz_search_chain == '\0' && p_sys->psz_old_search)
-                /* Searching next entry */
-                mvnprintw(7, 1, COLS-2, _("Find: %s"), p_sys->psz_old_search);
-            else
-                mvnprintw(7, 1, COLS-2, _("Find: %s"), p_sys->psz_search_chain);
-        }
+        mvnprintw(7, 1, COLS-2, _("Find: %s"), p_sys->psz_old_search ?
+                  p_sys->psz_old_search : p_sys->psz_search_chain);
     }
-    if (p_sys->i_box_type == BOX_OPEN && p_sys->psz_open_chain)
+    if (p_sys->i_box_type == BOX_OPEN)
     {
         DrawEmptyLine(p_sys->w, 7, 1, COLS-2);
         mvnprintw(7, 1, COLS-2, _("Open: %s"), p_sys->psz_open_chain);
@@ -1451,92 +1329,74 @@ static void Redraw(intf_thread_t *p_intf, time_t *t_last_refresh)
     *t_last_refresh = time(0);
 }
 
-static void ManageSlider(intf_thread_t *p_intf)
+static void ChangePosition(intf_thread_t *p_intf, float increment)
 {
     intf_sys_t     *p_sys = p_intf->p_sys;
     input_thread_t *p_input = p_sys->p_input;
-    vlc_value_t     val;
+    float pos;
 
-    if (!p_input)
-        return;
-    var_Get(p_input, "state", &val);
-    if (val.i_int != PLAYING_S)
+    if (!p_input || var_GetInteger(p_input, "state") != PLAYING_S)
         return;
 
-    var_Get(p_input, "position", &val);
-    if (p_sys->f_slider == p_sys->f_slider_old)
-        p_sys->f_slider = p_sys->f_slider_old = 100 * val.f_float;
-    else
-    {
-        p_sys->f_slider_old = p_sys->f_slider;
+    pos = var_GetFloat(p_input, "position") + increment;
 
-        val.f_float = p_sys->f_slider / 100.0;
-        var_Set(p_input, "position", val);
-    }
-}
+    if (pos > 0.99) pos = 0.99;
+    if (pos < 0.0)  pos = 0.0;
 
+    var_SetFloat(p_input, "position", pos);
+}
 
-/* following functions are local */
-#ifndef HAVE_NCURSESW
-static char *KeyToUTF8(int i_key, char *psz_part)
+static inline int RemoveLastUTF8Entity(char *psz, int len)
 {
-    char *psz_utf8;
-    int len = strlen(psz_part);
-    if (len == 6)
-    {
-        /* overflow error - should not happen */
-        memset(psz_part, 0, 6);
-        return NULL;
-    }
-
-    psz_part[len] = (char)i_key;
+    while (len && ((psz[--len] & 0xc0) == 0x80));
+                       /* UTF8 continuation byte */
 
-    psz_utf8 = FromLocaleDup(psz_part);
+    psz[len] = '\0';
+    return len;
+}
 
-    /* Ugly check for incomplete bytes sequences
-     * (in case of non-UTF8 multibyte local encoding) */
-    char *psz;
-    for(psz = psz_utf8; *psz; psz++)
-        if ((*psz == '?') && (*psz_utf8 != '?'))
-        {
-            /* incomplete bytes sequence detected
-             * (VLC core inserted dummy question marks) */
-            free(psz_utf8);
-            return NULL;
-        }
+static char *GetDiscDevice(intf_thread_t *p_intf, const char *name)
+{
+    static const struct { const char *s; size_t n; const char *v; } devs[] =
+    {
+        { "cdda://", 7, "cd-audio", },
+        { "dvd://",  6, "dvd",      },
+        { "vcd://",  6, "vcd",      },
+    };
+    char *device;
 
-    /* Check for incomplete UTF8 bytes sequence */
-    if (!EnsureUTF8(psz_utf8))
+    for (unsigned i = 0; i < sizeof devs / sizeof *devs; i++)
     {
-        free(psz_utf8);
-        return NULL;
+        size_t n = devs[i].n;
+        if (!strncmp(name, devs[i].s, n))
+            switch(name[n])
+            {
+            case '\0':
+            case '@':
+                return config_GetPsz(p_intf, devs[i].v);
+            default:
+                /* Omit the beginning MRL-selector characters */
+                return strdup(name + n);
+            }
     }
 
-    memset(psz_part, 0, 6);
-    return psz_utf8;
-}
-#endif
+    device = strdup(name);
 
-static inline int RemoveLastUTF8Entity(char *psz, int len)
-{
-    while (len && ((psz[--len] & 0xc0) == 0x80));
-                       /* UTF8 continuation byte */
+    if (device) /* Remove what we have after @ */
+        device[strcspn(device, "@")] = '\0';
 
-    psz[len] = '\0';
-    return len;
+    return device;
 }
 
 static void Eject(intf_thread_t *p_intf)
 {
-    char *psz_device = NULL, *psz_parser, *psz_name;
+    char *psz_device, *psz_name;
+    playlist_t * p_playlist = pl_Get(p_intf);
 
-    /*
-     * Get the active input
-     * Determine whether we can eject a media, ie it's a DVD, VCD or CD-DA
-     * If it's neither of these, then return
-     */
+    /* If there's a stream playing, we aren't allowed to eject ! */
+    if (p_intf->p_sys->p_input)
+        return;
 
-    playlist_t * p_playlist = pl_Get(p_intf);
     PL_LOCK;
 
     if (!playlist_CurrentPlayingItem(p_playlist))
@@ -1546,341 +1406,256 @@ static void Eject(intf_thread_t *p_intf)
     }
 
     psz_name = playlist_CurrentPlayingItem(p_playlist)->p_input->psz_name;
+    psz_device = psz_name ? GetDiscDevice(p_intf, psz_name) : NULL;
 
-    if (psz_name)
+    PL_UNLOCK;
+
+    if (psz_device)
     {
-        if (!strncmp(psz_name, "dvd://", 6))
-        {
-            switch(psz_name[6])
-            {
-            case '\0':
-            case '@':
-                psz_device = config_GetPsz(p_intf, "dvd");
-                break;
-            default:
-                /* Omit the first MRL-selector characters */
-                psz_device = strdup(psz_name + strlen("dvd://"));
-                break;
-            }
-        }
-        else if (!strncmp(psz_name, "vcd://", 6))
-        {
-            switch(psz_name[6])
-            {
-            case '\0':
-            case '@':
-                psz_device = config_GetPsz(p_intf, "vcd");
-                break;
-            default:
-                /* Omit the beginning MRL-selector characters */
-                psz_device = strdup(psz_name + 6);
-                break;
-            }
-        }
-        else if (!strncmp(psz_name, "cdda://", 7))
-        {
-            switch(psz_name[7])
-            {
-            case '\0':
-            case '@':
-                psz_device = config_GetPsz(p_intf, "cd-audio");
-                break;
-            default:
-                /* Omit the beginning MRL-selector characters */
-                psz_device = strdup(psz_name + 7);
-                break;
-            }
-        }
-        else
-            psz_device = strdup(psz_name);
-    }
-
-    PL_UNLOCK;
-
-    if (!psz_device)
-        return;
-
-    /* Remove what we have after @ */
-    for(psz_parser = psz_device ; *psz_parser ; psz_parser++)
-        if (*psz_parser == '@')
-        {
-            *psz_parser = '\0';
-            break;
-        }
-
-    /* If there's a stream playing, we aren't allowed to eject ! */
-    if (!p_intf->p_sys->p_input)
-    {
-        msg_Dbg(p_intf, "ejecting %s", psz_device);
-
         intf_Eject(p_intf, psz_device);
+        free(psz_device);
     }
-
-    free(psz_device);
 }
 
 static void PlayPause(intf_thread_t *p_intf)
 {
     input_thread_t *p_input = p_intf->p_sys->p_input;
-    playlist_t *p_playlist = pl_Get(p_intf);
-    vlc_value_t val;
 
     if (p_input)
     {
-        var_Get(p_input, "state", &val);
-        if (val.i_int != PAUSE_S)
-            val.i_int = PAUSE_S;
-        else
-            val.i_int = PLAYING_S;
-        var_Set(p_input, "state", val);
+        int64_t state = var_GetInteger( p_input, "state" );
+        state = (state != PLAYING_S) ? PLAYING_S : PAUSE_S;
+        var_SetInteger( p_input, "state", state );
     }
     else
-        playlist_Play(p_playlist);
+        playlist_Play(pl_Get(p_intf));
 }
 
-static int HandleKey(intf_thread_t *p_intf, int i_key)
+static inline void BoxSwitch(intf_sys_t *p_sys, int box)
 {
-    intf_sys_t *p_sys = p_intf->p_sys;
-    int i_ret = 1;
+    p_sys->i_box_type = (p_sys->i_box_type == box) ? BOX_NONE : box;
+}
 
+static bool HandlePlaylistKey(intf_thread_t *p_intf, int key)
+{
+    bool b_box_plidx_follow = false;
+    intf_sys_t *p_sys = p_intf->p_sys;
     playlist_t *p_playlist = pl_Get(p_intf);
+    struct pl_item_t *p_pl_item;
 
-    if (p_sys->i_box_type == BOX_PLAYLIST)
+    switch(key)
     {
-        int b_ret = true;
-        bool b_box_plidx_follow = false;
-
-        switch(i_key)
-        {
-            /* Playlist Settings */
-            case 'r':
-                var_ToggleBool(p_playlist, "random");
-                goto end;
-            case 'l':
-                var_ToggleBool(p_playlist, "loop");
-                goto end;
-            case 'R':
-                var_ToggleBool(p_playlist, "repeat");
-                goto end;
-
-            /* Playlist sort */
-            case 'o':
-                playlist_RecursiveNodeSort(p_playlist,
-                                            PlaylistGetRoot(p_intf),
-                                            SORT_TITLE_NODES_FIRST, ORDER_NORMAL);
-                p_sys->b_need_update = true;
-                goto end;
-            case 'O':
-                playlist_RecursiveNodeSort(p_playlist,
-                                            PlaylistGetRoot(p_intf),
-                                            SORT_TITLE_NODES_FIRST, ORDER_REVERSE);
-                p_sys->b_need_update = true;
-                goto end;
-
-            /* Playlist view */
-            case 'v':
-                switch(p_sys->i_current_view)
-                {
-                    case VIEW_CATEGORY:
-                        p_sys->i_current_view = VIEW_ONELEVEL;
-                        break;
-                    default:
-                        p_sys->i_current_view = VIEW_CATEGORY;
-                }
-                PlaylistRebuild(p_intf);
-                goto end;
-
-            /* Playlist navigation */
-            case 'g':
-                FindIndex(p_intf, p_playlist);
-                break;
-            case KEY_HOME:
-                p_sys->i_box_plidx = 0;
-                break;
+    /* Playlist Settings */
+    case 'r': var_ToggleBool(p_playlist, "random"); return true;
+    case 'l': var_ToggleBool(p_playlist, "loop");   return true;
+    case 'R': var_ToggleBool(p_playlist, "repeat"); return true;
+
+    /* Playlist sort */
+    case 'o':
+    case 'O':
+        playlist_RecursiveNodeSort(p_playlist, PlaylistGetRoot(p_intf),
+                                    SORT_TITLE_NODES_FIRST,
+                                    (key == 'o')? ORDER_NORMAL : ORDER_REVERSE);
+        p_sys->b_need_update = true;
+        return true;
+
+    /* Playlist view */
+    case 'v':
+        p_sys->category_view = !p_sys->category_view;
+        p_sys->b_need_update = true;
+        return true;
+
+    /* Playlist navigation */
 #ifdef __FreeBSD__
 /* workaround for FreeBSD + xterm:
- * see http://www.nabble.com/curses-vs.-xterm-key-mismatch-t3574377.html */
-            case KEY_SELECT:
+* see http://www.nabble.com/curses-vs.-xterm-key-mismatch-t3574377.html */
+    case KEY_SELECT:
 #endif
-            case KEY_END:
-                p_sys->i_box_plidx = p_playlist->items.i_size - 1;
-                break;
-            case KEY_UP:
-                p_sys->i_box_plidx--;
-                break;
-            case KEY_DOWN:
-                p_sys->i_box_plidx++;
-                break;
-            case KEY_PPAGE:
-                p_sys->i_box_plidx -= p_sys->i_box_lines;
-                break;
-            case KEY_NPAGE:
-                p_sys->i_box_plidx += p_sys->i_box_lines;
-                break;
-            case 'D':
-            case KEY_BACKSPACE:
-            case 0x7f:
-            case KEY_DC:
+    case KEY_END:   p_sys->i_box_plidx = p_playlist->items.i_size - 1;  break;
+    case KEY_HOME:  p_sys->i_box_plidx = 0;                             break;
+    case KEY_UP:    p_sys->i_box_plidx--;                               break;
+    case KEY_DOWN:  p_sys->i_box_plidx++;                               break;
+    case KEY_PPAGE: p_sys->i_box_plidx -= p_sys->i_box_lines;           break;
+    case KEY_NPAGE: p_sys->i_box_plidx += p_sys->i_box_lines;           break;
+    case 'g':       FindIndex(p_sys, p_playlist, false);                break;
+
+    /* Deletion */
+    case 'D':
+    case KEY_BACKSPACE:
+    case 0x7f:
+    case KEY_DC:
+    {
+        playlist_item_t *p_item;
+
+        PL_LOCK;
+        p_item = p_sys->pp_plist[p_sys->i_box_plidx]->p_item;
+        if (p_item->i_children == -1)
+            playlist_DeleteFromInput(p_playlist, p_item->p_input, pl_Locked);
+        else
+            playlist_NodeDelete(p_playlist, p_item, true , false);
+        PL_UNLOCK;
+        p_sys->b_need_update = true;
+        break;
+    }
+
+    case KEY_ENTER:
+    case '\r':
+    case '\n':
+        if (!(p_pl_item = p_sys->pp_plist[p_sys->i_box_plidx]))
+            return false;
+
+        if (p_pl_item->p_item->i_children)
+        {
+            playlist_item_t *p_item, *p_parent = p_pl_item->p_item;
+            if (p_parent->i_children == -1)
             {
-                playlist_item_t *p_item;
+                p_item = p_parent;
 
-                PL_LOCK;
-                p_item = p_sys->pp_plist[p_sys->i_box_plidx]->p_item;
-                if (p_item->i_children == -1)
-                    playlist_DeleteFromInput(p_playlist,
-                                              p_item->p_input, pl_Locked);
-                else
-                    playlist_NodeDelete(p_playlist, p_item, true , false);
-                PL_UNLOCK;
-                PlaylistRebuild(p_intf);
-                break;
+                while (p_parent->p_parent)
+                    p_parent = p_parent->p_parent;
+            }
+            else
+            {
+                p_sys->p_node = p_parent;
+                p_item = NULL;
             }
 
-            case KEY_ENTER:
-            case '\r':
-            case '\n':
-                if (!p_sys->pp_plist[p_sys->i_box_plidx])
-                {
-                    b_ret = false;
-                    break;
-                }
-                if (p_sys->pp_plist[p_sys->i_box_plidx]->p_item->i_children
-                        == -1)
-                {
-                    playlist_item_t *p_item, *p_parent;
-                    p_item = p_parent =
-                            p_sys->pp_plist[p_sys->i_box_plidx]->p_item;
-
-                    if (!p_parent)
-                        p_parent = p_playlist->p_root_onelevel;
-                    while (p_parent->p_parent)
-                        p_parent = p_parent->p_parent;
-                    playlist_Control(p_playlist, PLAYLIST_VIEWPLAY,
-                                      pl_Unlocked, p_parent, p_item);
-                }
-                else if (p_sys->pp_plist[p_sys->i_box_plidx]->p_item->i_children
-                        == 0)
-                {   /* We only want to set the current node */
-                    playlist_Stop(p_playlist);
-                    p_sys->p_node = p_sys->pp_plist[p_sys->i_box_plidx]->p_item;
-                }
-                else
-                {
-                    p_sys->p_node = p_sys->pp_plist[p_sys->i_box_plidx]->p_item;
-                    playlist_Control(p_playlist, PLAYLIST_VIEWPLAY, pl_Unlocked,
-                        p_sys->pp_plist[p_sys->i_box_plidx]->p_item, NULL);
-                }
-                b_box_plidx_follow = true;
-                break;
-            default:
-                b_ret = false;
-                break;
+            playlist_Control(p_playlist, PLAYLIST_VIEWPLAY, pl_Unlocked,
+                              p_parent, p_item);
+        }
+        else
+        {   /* We only want to set the current node */
+            playlist_Stop(p_playlist);
+            p_sys->p_node = p_pl_item->p_item;
         }
 
-        if (b_ret)
-        {
-            int i_max = p_sys->i_plist_entries;
-            if (p_sys->i_box_plidx >= i_max) p_sys->i_box_plidx = i_max - 1;
-            if (p_sys->i_box_plidx < 0) p_sys->i_box_plidx = 0;
+        b_box_plidx_follow = true;
+        break;
 
-            PL_LOCK;
-            if (PlaylistIsPlaying(p_playlist,
-                                   p_sys->pp_plist[p_sys->i_box_plidx]->p_item))
-                b_box_plidx_follow = true;
-            PL_UNLOCK;
-            p_sys->b_box_plidx_follow = b_box_plidx_follow;
-            goto end;
-        }
+    default:
+        return false;
     }
-    if (p_sys->i_box_type == BOX_BROWSE)
+
+    if (p_sys->i_box_plidx > p_sys->i_plist_entries - 1)
+        p_sys->i_box_plidx = p_sys->i_plist_entries - 1;
+    if (p_sys->i_box_plidx < 0)
+        p_sys->i_box_plidx = 0;
+
+    p_pl_item = p_sys->pp_plist[p_sys->i_box_plidx];
+
+    PL_LOCK;
+    if (PlaylistIsPlaying(p_playlist, p_pl_item->p_item))
+        b_box_plidx_follow = true;
+    PL_UNLOCK;
+    p_sys->b_box_plidx_follow = b_box_plidx_follow;
+    return true;
+}
+
+static bool HandleBrowseKey(intf_thread_t *p_intf, int key)
+{
+    struct dir_entry_t *dir_entry;
+    intf_sys_t *p_sys = p_intf->p_sys;
+
+    switch(key)
     {
-        bool b_ret = true;
-        /* Browser navigation */
-        switch(i_key)
+    case '.':
+        p_sys->b_show_hidden_files = !p_sys->b_show_hidden_files;
+        ReadDir(p_intf);
+        return true;
+
+    case KEY_ENTER:
+    case '\r':
+    case '\n':
+    case ' ':
+        dir_entry = p_sys->pp_dir_entries[p_sys->i_box_bidx];
+
+        if (!dir_entry->b_file && key != ' ')
         {
-            case KEY_HOME:
-                p_sys->i_box_bidx = 0;
-                break;
-#ifdef __FreeBSD__
-            case KEY_SELECT:
-#endif
-            case KEY_END:
-                p_sys->i_box_bidx = p_sys->i_dir_entries - 1;
-                break;
-            case KEY_UP:
-                p_sys->i_box_bidx--;
-                break;
-            case KEY_DOWN:
-                p_sys->i_box_bidx++;
-                break;
-            case KEY_PPAGE:
-                p_sys->i_box_bidx -= p_sys->i_box_lines;
-                break;
-            case KEY_NPAGE:
-                p_sys->i_box_bidx += p_sys->i_box_lines;
-                break;
-            case '.': /* Toggle show hidden files */
-                p_sys->b_show_hidden_files = (p_sys->b_show_hidden_files ==
-                    true ? false : true);
+            char *current_dir = p_sys->psz_current_dir;
+            if (asprintf(&p_sys->psz_current_dir, "%s/%s",
+                          p_sys->psz_current_dir, dir_entry->psz_path) != -1)
+            {
                 ReadDir(p_intf);
-                break;
+                free(current_dir);
+            }
+            else
+                p_sys->psz_current_dir = current_dir;
 
-            case KEY_ENTER:
-            case '\r':
-            case '\n':
-            case ' ':
-                if (p_sys->pp_dir_entries[p_sys->i_box_bidx]->b_file || i_key == ' ')
-                {
-                    char* psz_uri;
-                    if (asprintf(&psz_uri, "%s://%s/%s",
-                        p_sys->pp_dir_entries[p_sys->i_box_bidx]->b_file ?
-                            "file" : "directory",
-                        p_sys->psz_current_dir,
-                        p_sys->pp_dir_entries[p_sys->i_box_bidx]->psz_path
-                       ) == -1)
-                    {
-                        psz_uri = NULL;
-                    }
-
-                    playlist_item_t *p_parent = p_sys->p_node;
-                    if (!p_parent)
-                    {
-                        PL_LOCK;
-                        p_parent = playlist_CurrentPlayingItem(p_playlist) ? playlist_CurrentPlayingItem(p_playlist)->p_parent : NULL;
-                        PL_UNLOCK;
-                        if (!p_parent)
-                            p_parent = p_playlist->p_local_onelevel;
-                    }
-
-                    while (p_parent->p_parent && p_parent->p_parent->p_parent)
-                        p_parent = p_parent->p_parent;
-
-                    playlist_Add(p_playlist, psz_uri, NULL, PLAYLIST_APPEND,
-                                  PLAYLIST_END,
-                                  p_parent->p_input ==
-                                    p_playlist->p_local_onelevel->p_input
-                                  , false);
-
-                    p_sys->i_box_type = BOX_PLAYLIST;
-                    free(psz_uri);
-                }
-                else
-                {
-                    if (asprintf(&(p_sys->psz_current_dir), "%s/%s", p_sys->psz_current_dir,
-                                  p_sys->pp_dir_entries[p_sys->i_box_bidx]->psz_path) != -1)
-                        ReadDir(p_intf);
-                }
-                break;
-            default:
-                b_ret = false;
-                break;
+            return true;
+        }
+
+        char* psz_uri;
+        if (asprintf(&psz_uri, "%s://%s/%s",
+                    dir_entry->b_file ? "file" : "directory",
+                    p_sys->psz_current_dir, dir_entry->psz_path) == -1)
+        {
+            return false;
         }
-        if (b_ret)
+
+        playlist_t *p_playlist = pl_Get(p_intf);
+        playlist_item_t *p_parent = p_sys->p_node;
+        if (!p_parent)
         {
-            if (p_sys->i_box_bidx >= p_sys->i_dir_entries) p_sys->i_box_bidx = p_sys->i_dir_entries - 1;
-            if (p_sys->i_box_bidx < 0) p_sys->i_box_bidx = 0;
-            goto end;
+            playlist_item_t *p_item;
+            PL_LOCK;
+            p_item = playlist_CurrentPlayingItem(p_playlist);
+            p_parent = p_item ? p_item->p_parent : NULL;
+            PL_UNLOCK;
+            if (!p_parent)
+                p_parent = p_playlist->p_local_onelevel;
         }
+
+        while (p_parent->p_parent && p_parent->p_parent->p_parent)
+            p_parent = p_parent->p_parent;
+
+        input_item_t *p_input = p_playlist->p_local_onelevel->p_input;
+        playlist_Add(p_playlist, psz_uri, NULL, PLAYLIST_APPEND,
+                      PLAYLIST_END, p_parent->p_input == p_input, false);
+
+        p_sys->i_box_type = BOX_PLAYLIST;
+        free(psz_uri);
+        return true;
+
+#ifdef __FreeBSD__
+    case KEY_SELECT:
+#endif
+    case KEY_END:   p_sys->i_box_bidx = p_sys->i_dir_entries - 1;   break;
+    case KEY_HOME:  p_sys->i_box_bidx = 0;                          break;
+    case KEY_UP:    p_sys->i_box_bidx--;                            break;
+    case KEY_DOWN:  p_sys->i_box_bidx++;                            break;
+    case KEY_PPAGE: p_sys->i_box_bidx -= p_sys->i_box_lines;        break;
+    case KEY_NPAGE: p_sys->i_box_bidx += p_sys->i_box_lines;        break;
+
+    default:
+        return false;
+    }
+
+    if (p_sys->i_box_bidx >= p_sys->i_dir_entries)
+        p_sys->i_box_bidx = p_sys->i_dir_entries - 1;
+    if (p_sys->i_box_bidx < 0)
+        p_sys->i_box_bidx = 0;
+
+    return true;
+}
+
+static int HandleKey(intf_thread_t *p_intf)
+{
+    intf_sys_t *p_sys = p_intf->p_sys;
+    playlist_t *p_playlist = pl_Get(p_intf);
+    int i_key = wgetch(p_sys->w);
+
+    if (i_key == -1)
+        return 0;
+
+    if (p_sys->i_box_type == BOX_PLAYLIST)
+    {
+        if (HandlePlaylistKey(p_intf, i_key))
+            return 1;
+    }
+    else if (p_sys->i_box_type == BOX_BROWSE)
+    {
+        if (HandleBrowseKey(p_intf, i_key))
+            return 1;
     }
     else if (p_sys->i_box_type == BOX_HELP || p_sys->i_box_type == BOX_INFO ||
              p_sys->i_box_type == BOX_META || p_sys->i_box_type == BOX_STATS ||
@@ -1888,396 +1663,314 @@ static int HandleKey(intf_thread_t *p_intf, int i_key)
     {
         switch(i_key)
         {
-            case KEY_HOME:
-                p_sys->i_box_start = 0;
-                goto end;
+        case KEY_HOME:
+            p_sys->i_box_start = 0;
+            return 1;
 #ifdef __FreeBSD__
-            case KEY_SELECT:
+        case KEY_SELECT:
 #endif
-            case KEY_END:
+        case KEY_END:
+            p_sys->i_box_start = p_sys->i_box_lines_total - 1;
+            return 1;
+        case KEY_UP:
+            if (p_sys->i_box_start > 0) p_sys->i_box_start--;
+            return 1;
+        case KEY_DOWN:
+            if (p_sys->i_box_start < p_sys->i_box_lines_total - 1)
+                p_sys->i_box_start++;
+            return 1;
+        case KEY_PPAGE:
+            p_sys->i_box_start -= p_sys->i_box_lines;
+            if (p_sys->i_box_start < 0) p_sys->i_box_start = 0;
+            return 1;
+        case KEY_NPAGE:
+            p_sys->i_box_start += p_sys->i_box_lines;
+            if (p_sys->i_box_start >= p_sys->i_box_lines_total)
                 p_sys->i_box_start = p_sys->i_box_lines_total - 1;
-                goto end;
-            case KEY_UP:
-                if (p_sys->i_box_start > 0) p_sys->i_box_start--;
-                goto end;
-            case KEY_DOWN:
-                if (p_sys->i_box_start < p_sys->i_box_lines_total - 1)
-                    p_sys->i_box_start++;
-                goto end;
-            case KEY_PPAGE:
-                p_sys->i_box_start -= p_sys->i_box_lines;
-                if (p_sys->i_box_start < 0) p_sys->i_box_start = 0;
-                goto end;
-            case KEY_NPAGE:
-                p_sys->i_box_start += p_sys->i_box_lines;
-                if (p_sys->i_box_start >= p_sys->i_box_lines_total)
-                    p_sys->i_box_start = p_sys->i_box_lines_total - 1;
-                goto end;
-            default:
-                break;
+            return 1;
         }
     }
     else if (p_sys->i_box_type == BOX_NONE)
     {
         switch(i_key)
         {
-            case KEY_HOME:
-                p_sys->f_slider = 0;
-                ManageSlider(p_intf);
-                goto end;
+        case KEY_HOME:
+            ChangePosition(p_intf, -1.0);
+            return 1;
 #ifdef __FreeBSD__
-            case KEY_SELECT:
+        case KEY_SELECT:
 #endif
-            case KEY_END:
-                p_sys->f_slider = 99.9;
-                ManageSlider(p_intf);
-                goto end;
-            case KEY_UP:
-                p_sys->f_slider += 5.0;
-                if (p_sys->f_slider >= 99.0) p_sys->f_slider = 99.0;
-                ManageSlider(p_intf);
-                goto end;
-            case KEY_DOWN:
-                p_sys->f_slider -= 5.0;
-                if (p_sys->f_slider < 0.0) p_sys->f_slider = 0.0;
-                ManageSlider(p_intf);
-                goto end;
-
-            default:
-                break;
+        case KEY_END:
+            ChangePosition(p_intf, .99);
+            return 1;
+        case KEY_UP:
+            ChangePosition(p_intf, 0.05);
+            return 1;
+        case KEY_DOWN:
+            ChangePosition(p_intf, -0.05);
+            return 1;
         }
     }
-    else if (p_sys->i_box_type == BOX_SEARCH && p_sys->psz_search_chain)
+    else if (p_sys->i_box_type == BOX_SEARCH)
     {
-        int i_chain_len = strlen(p_sys->psz_search_chain);
+        size_t i_chain_len = strlen(p_sys->psz_search_chain);
         switch(i_key)
         {
-            case KEY_CLEAR:
-            case 0x0c:      /* ^l */
-                clear();
-                goto end;
-            case KEY_ENTER:
-            case '\r':
-            case '\n':
-                if (i_chain_len > 0)
-                    p_sys->psz_old_search = strdup(p_sys->psz_search_chain);
-                else if (p_sys->psz_old_search)
-                    SearchPlaylist(p_intf, p_sys->psz_old_search);
-                p_sys->i_box_type = BOX_PLAYLIST;
-                goto end;
-            case 0x1b: /* ESC */
-                /* Alt+key combinations return 2 keys in the terminal keyboard:
-                 * ESC, and the 2nd key.
-                 * If some other key is available immediately (where immediately
-                 * means after wgetch() 1 second delay), that means that the
-                 * ESC key was not pressed.
-                 *
-                 * man 3X curs_getch says:
-                 *
-                 * Use of the escape key by a programmer for a single
-                 * character function is discouraged, as it will cause a delay
-                 * of up to one second while the keypad code looks for a
-                 * following function-key sequence.
-                 *
-                 */
-                if (wgetch(p_sys->w) != ERR)
-                {
-                    i_ret = 0;
-                    goto end;
-                }
-                p_sys->i_box_plidx = p_sys->i_before_search;
-                p_sys->i_box_type = BOX_PLAYLIST;
-                goto end;
-            case KEY_BACKSPACE:
-            case 0x7f:
-                RemoveLastUTF8Entity(p_sys->psz_search_chain, i_chain_len);
-                break;
-            default:
+        case KEY_CLEAR:
+        case 0x0c:      /* ^l */
+            clear();
+            return 1;
+        case KEY_ENTER:
+        case '\r':
+        case '\n':
+            if (i_chain_len)
+                p_sys->psz_old_search = strdup(p_sys->psz_search_chain);
+            else if (p_sys->psz_old_search)
+                SearchPlaylist(p_sys, p_sys->psz_old_search);
+            p_sys->i_box_type = BOX_PLAYLIST;
+            return 1;
+        case 0x1b: /* ESC */
+            /* Alt+key combinations return 2 keys in the terminal keyboard:
+             * ESC, and the 2nd key.
+             * If some other key is available immediately (where immediately
+             * means after wgetch() 1 second delay), that means that the
+             * ESC key was not pressed.
+             *
+             * man 3X curs_getch says:
+             *
+             * Use of the escape key by a programmer for a single
+             * character function is discouraged, as it will cause a delay
+             * of up to one second while the keypad code looks for a
+             * following function-key sequence.
+             *
+             */
+            if (wgetch(p_sys->w) != ERR)
+                return 0;
+            p_sys->i_box_plidx = p_sys->i_before_search;
+            p_sys->i_box_type = BOX_PLAYLIST;
+            return 1;
+        case KEY_BACKSPACE:
+        case 0x7f:
+            RemoveLastUTF8Entity(p_sys->psz_search_chain, i_chain_len);
+            break;
+        default:
+            if (i_chain_len + 1 < sizeof p_sys->psz_search_chain)
             {
-#ifdef HAVE_NCURSESW
-                if (i_chain_len + 1 < SEARCH_CHAIN_SIZE)
-                {
-                    p_sys->psz_search_chain[i_chain_len] = (char) i_key;
-                    p_sys->psz_search_chain[i_chain_len + 1] = '\0';
-                }
-#else
-                char *psz_utf8 = KeyToUTF8(i_key, p_sys->psz_partial_keys);
-
-                if (psz_utf8)
-                {
-                    if (i_chain_len + strlen(psz_utf8) < SEARCH_CHAIN_SIZE)
-                        strcpy(p_sys->psz_search_chain + i_chain_len, psz_utf8);
-                    free(psz_utf8);
-                }
-#endif
-                break;
+                p_sys->psz_search_chain[i_chain_len] = (char) i_key;
+                p_sys->psz_search_chain[i_chain_len + 1] = '\0';
             }
         }
         free(p_sys->psz_old_search);
         p_sys->psz_old_search = NULL;
-        SearchPlaylist(p_intf, p_sys->psz_search_chain);
-        goto end;
+        SearchPlaylist(p_sys, p_sys->psz_search_chain);
+        return 1;
     }
-    else if (p_sys->i_box_type == BOX_OPEN && p_sys->psz_open_chain)
+    else if (p_sys->i_box_type == BOX_OPEN)
     {
-        int i_chain_len = strlen(p_sys->psz_open_chain);
+        size_t i_chain_len = strlen(p_sys->psz_open_chain);
 
         switch(i_key)
         {
-            case KEY_CLEAR:
-            case 0x0c:          /* ^l */
-                clear();
-                break;
-            case KEY_ENTER:
-            case '\r':
-            case '\n':
-                if (i_chain_len > 0)
-                {
-                    playlist_item_t *p_parent = p_sys->p_node;
+        case KEY_CLEAR:
+        case 0x0c:          /* ^l */
+            clear();
+            return 1;
+        case KEY_ENTER:
+        case '\r':
+        case '\n':
+            if (i_chain_len)
+            {
+                playlist_item_t *p_parent = p_sys->p_node;
 
-                    PL_LOCK;
-                    if (!p_parent)
-                    p_parent = playlist_CurrentPlayingItem(p_playlist) ? playlist_CurrentPlayingItem(p_playlist)->p_parent : NULL;
-                    if (!p_parent)
-                        p_parent = p_playlist->p_local_onelevel;
+                PL_LOCK;
+                if (!p_parent)
+                p_parent = playlist_CurrentPlayingItem(p_playlist) ? playlist_CurrentPlayingItem(p_playlist)->p_parent : NULL;
+                if (!p_parent)
+                    p_parent = p_playlist->p_local_onelevel;
 
-                    while (p_parent->p_parent && p_parent->p_parent->p_parent)
-                        p_parent = p_parent->p_parent;
-                    PL_UNLOCK;
+                while (p_parent->p_parent && p_parent->p_parent->p_parent)
+                    p_parent = p_parent->p_parent;
+                PL_UNLOCK;
 
-                    playlist_Add(p_playlist, p_sys->psz_open_chain, NULL,
-                                  PLAYLIST_APPEND|PLAYLIST_GO, PLAYLIST_END,
-                                  p_parent->p_input ==
-                                    p_playlist->p_local_onelevel->p_input
-                                  , false);
+                playlist_Add(p_playlist, p_sys->psz_open_chain, NULL,
+                              PLAYLIST_APPEND|PLAYLIST_GO, PLAYLIST_END,
+                              p_parent->p_input ==
+                                p_playlist->p_local_onelevel->p_input
+                              , false);
 
-                    p_sys->b_box_plidx_follow = true;
-                }
-                p_sys->i_box_type = BOX_PLAYLIST;
-                break;
-            case 0x1b:  /* ESC */
-                if (wgetch(p_sys->w) != ERR)
-                {
-                    i_ret = 0;
-                    break;
-                }
-                p_sys->i_box_type = BOX_PLAYLIST;
-                break;
-            case KEY_BACKSPACE:
-            case 0x7f:
-                RemoveLastUTF8Entity(p_sys->psz_open_chain, i_chain_len);
-                break;
-            default:
+                p_sys->b_box_plidx_follow = true;
+            }
+            p_sys->i_box_type = BOX_PLAYLIST;
+            return 1;
+        case 0x1b:  /* ESC */
+            if (wgetch(p_sys->w) != ERR)
+                return 0;
+            p_sys->i_box_type = BOX_PLAYLIST;
+            return 1;
+        case KEY_BACKSPACE:
+        case 0x7f:
+            RemoveLastUTF8Entity(p_sys->psz_open_chain, i_chain_len);
+            return 1;
+        default:
+            if (i_chain_len + 1 < sizeof p_sys->psz_open_chain)
             {
-#ifdef HAVE_NCURSESW
-                if (i_chain_len + 1 < OPEN_CHAIN_SIZE)
-                {
-                    p_sys->psz_open_chain[i_chain_len] = (char) i_key;
-                    p_sys->psz_open_chain[i_chain_len + 1] = '\0';
-                }
-#else
-                char *psz_utf8 = KeyToUTF8(i_key, p_sys->psz_partial_keys);
-
-                if (psz_utf8)
-                {
-                    if (i_chain_len + strlen(psz_utf8) < OPEN_CHAIN_SIZE)
-                        strcpy(p_sys->psz_open_chain + i_chain_len, psz_utf8);
-                    free(psz_utf8);
-                }
-#endif
+                p_sys->psz_open_chain[i_chain_len] = (char) i_key;
+                p_sys->psz_open_chain[i_chain_len + 1] = '\0';
             }
         }
-        goto end;
+        return 1;
     }
 
 
     /* Common keys */
     switch(i_key)
     {
-        case 0x1b:  /* ESC */
-            if (wgetch(p_sys->w) != ERR)
-            {
-                i_ret = 0;
-                break;
-            }
-        case 'q':
-        case 'Q':
-        case KEY_EXIT:
-            libvlc_Quit(p_intf->p_libvlc);
-            i_ret = 0;
-            break;
-
-        /* Box switching */
-        case 'i':
-            if (p_sys->i_box_type == BOX_INFO)
-                p_sys->i_box_type = BOX_NONE;
-            else
-                p_sys->i_box_type = BOX_INFO;
-            p_sys->i_box_lines_total = 0;
-            break;
-        case 'm':
-            if (p_sys->i_box_type == BOX_META)
-                p_sys->i_box_type = BOX_NONE;
-            else
-                p_sys->i_box_type = BOX_META;
-            p_sys->i_box_lines_total = 0;
-            break;
-        case 'L':
-            if (p_sys->i_box_type == BOX_LOG)
-                p_sys->i_box_type = BOX_NONE;
-            else
-                p_sys->i_box_type = BOX_LOG;
-            break;
-        case 'P':
-            if (p_sys->i_box_type == BOX_PLAYLIST)
-                p_sys->i_box_type = BOX_NONE;
-            else
-                p_sys->i_box_type = BOX_PLAYLIST;
-            break;
-        case 'B':
-            if (p_sys->i_box_type == BOX_BROWSE)
-                p_sys->i_box_type = BOX_NONE;
-            else
-                p_sys->i_box_type = BOX_BROWSE;
-            break;
-        case 'x':
-            if (p_sys->i_box_type == BOX_OBJECTS)
-                p_sys->i_box_type = BOX_NONE;
-            else
-                p_sys->i_box_type = BOX_OBJECTS;
-            break;
-        case 'S':
-            if (p_sys->i_box_type == BOX_STATS)
-                p_sys->i_box_type = BOX_NONE;
-            else
-                p_sys->i_box_type = BOX_STATS;
-            break;
-        case 'c':
-            p_sys->b_color = !p_sys->b_color;
-            if (p_sys->b_color && !p_sys->b_color_started)
-                start_color_and_pairs(p_intf);
-            break;
-        case 'h':
-        case 'H':
-            if (p_sys->i_box_type == BOX_HELP)
-                p_sys->i_box_type = BOX_NONE;
-            else
-                p_sys->i_box_type = BOX_HELP;
-            p_sys->i_box_lines_total = 0;
-            break;
-        case '/':
-            if (p_sys->i_box_type != BOX_SEARCH && p_sys->psz_search_chain)
-            {
-                p_sys->psz_search_chain[0] = '\0';
-                p_sys->b_box_plidx_follow = false;
-                p_sys->i_before_search = p_sys->i_box_plidx;
-                p_sys->i_box_type = BOX_SEARCH;
-            }
-            break;
-        case 'A': /* Open */
-            if (p_sys->i_box_type != BOX_OPEN && p_sys->psz_open_chain)
-            {
-                p_sys->psz_open_chain[0] = '\0';
-                p_sys->i_box_type = BOX_OPEN;
-            }
-            break;
+    case 0x1b:  /* ESC */
+        if (wgetch(p_sys->w) != ERR)
+            return 0;
+
+    case 'q':
+    case 'Q':
+    case KEY_EXIT:
+        libvlc_Quit(p_intf->p_libvlc);
+        return 0;
+
+    /* Box switching */
+    case 'i':
+        BoxSwitch(p_sys, BOX_INFO);
+        p_sys->i_box_lines_total = 0;
+        break;
+    case 'm':
+        BoxSwitch(p_sys, BOX_META);
+        p_sys->i_box_lines_total = 0;
+        break;
+#if 0
+    case 'L':
+        BoxSwitch(p_sys, BOX_LOG)
+        break;
+#endif
+    case 'P':
+        BoxSwitch(p_sys, BOX_PLAYLIST);
+        break;
+    case 'B':
+        BoxSwitch(p_sys, BOX_BROWSE);
+        break;
+    case 'x':
+        BoxSwitch(p_sys, BOX_OBJECTS);
+        break;
+    case 'S':
+        BoxSwitch(p_sys, BOX_STATS);
+        break;
+    case 'h':
+    case 'H':
+        BoxSwitch(p_sys, BOX_HELP);
+        p_sys->i_box_lines_total = 0;
+        break;
+    case '/':
+        if (p_sys->i_box_type != BOX_SEARCH && p_sys->psz_search_chain)
+        {
+            p_sys->psz_search_chain[0] = '\0';
+            p_sys->b_box_plidx_follow = false;
+            p_sys->i_before_search = p_sys->i_box_plidx;
+            p_sys->i_box_type = BOX_SEARCH;
+        }
+        break;
+    case 'A': /* Open */
+        if (p_sys->i_box_type != BOX_OPEN)
+        {
+            p_sys->psz_open_chain[0] = '\0';
+            p_sys->i_box_type = BOX_OPEN;
+        }
+        break;
 
-        /* Navigation */
-        case KEY_RIGHT:
-            p_sys->f_slider += 1.0;
-            if (p_sys->f_slider > 99.9) p_sys->f_slider = 99.9;
-            ManageSlider(p_intf);
-            break;
+    /* Navigation */
+    case KEY_RIGHT:
+        ChangePosition(p_intf, 0.01);
+        break;
 
-        case KEY_LEFT:
-            p_sys->f_slider -= 1.0;
-            if (p_sys->f_slider < 0.0) p_sys->f_slider = 0.0;
-            ManageSlider(p_intf);
-            break;
+    case KEY_LEFT:
+        ChangePosition(p_intf, -0.01);
+        break;
 
-        /* Common control */
-        case 'f':
+    /* Common control */
+    case 'f':
+        if (p_intf->p_sys->p_input)
         {
-            bool fs = var_ToggleBool(p_playlist, "fullscreen");
-            if (p_intf->p_sys->p_input)
+            vout_thread_t *p_vout = input_GetVout(p_intf->p_sys->p_input);
+            if (p_vout)
             {
-                vout_thread_t *p_vout = input_GetVout(p_intf->p_sys->p_input);
-                if (p_vout)
-                {
-                    var_SetBool(p_vout, "fullscreen", fs);
-                    vlc_object_release(p_vout);
-                }
+                bool fs = var_ToggleBool(p_playlist, "fullscreen");
+                var_SetBool(p_vout, "fullscreen", fs);
+                vlc_object_release(p_vout);
             }
-            i_ret = 0;
-            break;
         }
+        return 0;
+
+    case ' ':
+        PlayPause(p_intf);
+        break;
+
+    case 's':
+        playlist_Stop(p_playlist);
+        break;
+
+    case 'e':
+        Eject(p_intf);
+        break;
+
+    case '[':
+        if (p_sys->p_input)
+            var_TriggerCallback(p_sys->p_input, "prev-title");
+        break;
+
+    case ']':
+        if (p_sys->p_input)
+            var_TriggerCallback(p_sys->p_input, "next-title");
+        break;
+
+    case '<':
+        if (p_sys->p_input)
+            var_TriggerCallback(p_sys->p_input, "prev-chapter");
+        break;
+
+    case '>':
+        if (p_sys->p_input)
+            var_TriggerCallback(p_sys->p_input, "next-chapter");
+        break;
+
+    case 'p':
+        playlist_Prev(p_playlist);
+        clear();
+        break;
+
+    case 'n':
+        playlist_Next(p_playlist);
+        clear();
+        break;
+
+    case 'a':
+        aout_VolumeUp(p_playlist, 1, NULL);
+        clear();
+        break;
+
+    case 'z':
+        aout_VolumeDown(p_playlist, 1, NULL);
+        clear();
+        break;
 
-        case ' ':
-            PlayPause(p_intf);
-            break;
-
-        case 's':
-            playlist_Stop(p_playlist);
-            break;
-
-        case 'e':
-            Eject(p_intf);
-            break;
-
-        case '[':
-            if (p_sys->p_input)
-                var_TriggerCallback(p_sys->p_input, "prev-title");
-            break;
-
-        case ']':
-            if (p_sys->p_input)
-                var_TriggerCallback(p_sys->p_input, "next-title");
-            break;
-
-        case '<':
-            if (p_sys->p_input)
-                var_TriggerCallback(p_sys->p_input, "prev-chapter");
-            break;
-
-        case '>':
-            if (p_sys->p_input)
-                var_TriggerCallback(p_sys->p_input, "next-chapter");
-            break;
-
-        case 'p':
-            playlist_Prev(p_playlist);
-            clear();
-            break;
-
-        case 'n':
-            playlist_Next(p_playlist);
-            clear();
-            break;
-
-        case 'a':
-            aout_VolumeUp(p_playlist, 1, NULL);
-            clear();
-            break;
-
-        case 'z':
-            aout_VolumeDown(p_playlist, 1, NULL);
-            clear();
-            break;
-
-        /*
-         * ^l should clear and redraw the screen
-         */
-        case KEY_CLEAR:
-        case 0x0c:          /* ^l */
-            clear();
-            break;
+    /*
+     * ^l should clear and redraw the screen
+     */
+    case KEY_CLEAR:
+    case 0x0c:          /* ^l */
+        clear();
+        break;
 
-        default:
-            i_ret = 0;
+    default:
+        return 0;
     }
 
-end:
-    return i_ret;
+    return 1;
 }
 
 /*****************************************************************************
@@ -2287,20 +1980,14 @@ static void Run(intf_thread_t *p_intf)
 {
     intf_sys_t    *p_sys = p_intf->p_sys;
     playlist_t    *p_playlist = pl_Get(p_intf);
-    p_sys->p_playlist = p_playlist;
+    bool           force_redraw = false;
 
-    int i_key;
     time_t t_last_refresh;
     int canc = vlc_savecancel();
 
-    /*
-     * force drawing the interface for the first time
-     */
-    t_last_refresh = (time(0) - 1);
-    /*
-     * force building of the playlist array
-     */
     PlaylistRebuild(p_intf);
+    Redraw(p_intf, &t_last_refresh);
+
     var_AddCallback(p_playlist, "intf-change", PlaylistChanged, p_intf);
     var_AddCallback(p_playlist, "playlist-item-append", PlaylistChanged, p_intf);
 
@@ -2310,44 +1997,34 @@ static void Run(intf_thread_t *p_intf)
 
         /* Update the input */
         if (!p_sys->p_input)
+        {
             p_sys->p_input = playlist_CurrentInput(p_playlist);
+            force_redraw = true;
+        }
         else if (p_sys->p_input->b_dead)
         {
             vlc_object_release(p_sys->p_input);
             p_sys->p_input = NULL;
-            p_sys->f_slider = p_sys->f_slider_old = 0.0;
-            p_sys->b_box_cleared = false;
         }
 
         PL_LOCK;
         if (p_sys->b_box_plidx_follow && playlist_CurrentPlayingItem(p_playlist))
-        {
-            PL_UNLOCK;
-            FindIndex(p_intf, p_playlist);
-        }
-        else
-            PL_UNLOCK;
+            FindIndex(p_sys, p_playlist, true);
 
-        while ((i_key = wgetch(p_sys->w)) != -1)
-            if (HandleKey(p_intf, i_key))
-                Redraw(p_intf, &t_last_refresh);
+        PL_UNLOCK;
 
-        /* Hack */
-        if (p_sys->f_slider > 0.0001 && !p_sys->b_box_cleared)
+        while (HandleKey(p_intf))
+            Redraw(p_intf, &t_last_refresh);
+
+        if (force_redraw)
         {
             clear();
             Redraw(p_intf, &t_last_refresh);
-            p_sys->b_box_cleared = true;
+            force_redraw = false;
         }
 
-        /*
-         * redraw the screen every second
-         */
         if ((time(0) - t_last_refresh) >= 1)
-        {
-            ManageSlider(p_intf);
             Redraw(p_intf, &t_last_refresh);
-        }
     }
     var_DelCallback(p_playlist, "intf-change", PlaylistChanged, p_intf);
     var_DelCallback(p_playlist, "playlist-item-append", PlaylistChanged, p_intf);
@@ -2360,87 +2037,43 @@ static void Run(intf_thread_t *p_intf)
 static int Open(vlc_object_t *p_this)
 {
     intf_thread_t *p_intf = (intf_thread_t *)p_this;
-    intf_sys_t    *p_sys;
-
-    /* Allocate instance and initialize some members */
-    p_sys = p_intf->p_sys = malloc(sizeof(intf_sys_t));
+    intf_sys_t    *p_sys  = p_intf->p_sys = calloc(1, sizeof(intf_sys_t));
     if (!p_sys)
         return VLC_ENOMEM;
-    p_sys->p_node = NULL;
-    p_sys->p_input = NULL;
-    p_sys->f_slider = 0.0;
-    p_sys->f_slider_old = 0.0;
+
     p_sys->i_box_type = BOX_PLAYLIST;
-    p_sys->i_box_lines = 0;
-    p_sys->i_box_start= 0;
-    p_sys->i_box_lines_total = 0;
     p_sys->b_box_plidx_follow = true;
-    p_sys->b_box_cleared = false;
-    p_sys->i_box_plidx = 0;
-    p_sys->i_box_bidx = 0;
-// FIXME    p_sys->p_sub = msg_Subscribe(p_intf);
+//  p_sys->p_sub = msg_Subscribe(p_intf);
     p_sys->b_color = var_CreateGetBool(p_intf, "color");
-    p_sys->b_color_started = false;
 
-#ifndef HAVE_NCURSESW
-    memset(p_sys->psz_partial_keys, 0, sizeof(p_sys->psz_partial_keys));
-#endif
+    p_sys->category_view = true; //FIXME: switching back & forth is broken
+
+    p_sys->psz_current_dir = var_CreateGetString(p_intf, "browse-dir");
+    if (!p_sys->psz_current_dir || !*p_sys->psz_current_dir)
+    {
+        free(p_sys->psz_current_dir);
+        p_sys->psz_current_dir = config_GetUserDir(VLC_HOME_DIR);
+    }
 
-    /* Initialize the curses library */
-    p_sys->w = initscr();
+    p_sys->w = initscr();   /* Initialize the curses library */
 
     if (p_sys->b_color)
         start_color_and_pairs(p_intf);
 
-    keypad(p_sys->w, TRUE);
-    /* Don't do NL -> CR/NL */
-    nonl();
-    /* Take input chars one at a time */
-    cbreak();
-    /* Don't echo */
-    noecho();
-    /* Invisible cursor */
-    curs_set(0);
-    /* Non blocking wgetch() */
+    keypad(p_sys->w, TRUE); /* Don't do NL -> CR/NL */
+    nonl();                 /* Take input chars one at a time */
+    cbreak();               /* Don't echo */
+    noecho();               /* Invisible cursor */
+    curs_set(0);            /* Non blocking wgetch() */
     wtimeout(p_sys->w, 0);
-
     clear();
 
-    /* exported function */
-    p_intf->pf_run = Run;
-
     /* Stop printing errors to the console */
     freopen("/dev/null", "wb", stderr);
 
-    /* Set defaul playlist view */
-    p_sys->i_current_view = VIEW_CATEGORY;
-    p_sys->pp_plist = NULL;
-    p_sys->i_plist_entries = 0;
-    p_sys->b_need_update = false;
-
-    /* Initialize search chain */
-    p_sys->psz_search_chain = malloc(SEARCH_CHAIN_SIZE + 1);
-    p_sys->psz_old_search = NULL;
-    p_sys->i_before_search = 0;
-
-    /* Initialize open chain */
-    p_sys->psz_open_chain = malloc(OPEN_CHAIN_SIZE + 1);
-
-    /* Initialize browser options */
-    char* psz_tmp = var_CreateGetString(p_intf, "browse-dir");
-    if (psz_tmp && *psz_tmp)
-        p_sys->psz_current_dir = psz_tmp;
-    else
-    {
-        p_sys->psz_current_dir = config_GetUserDir(VLC_HOME_DIR);
-        free(psz_tmp);
-    }
-
-    p_sys->i_dir_entries = 0;
-    p_sys->pp_dir_entries = NULL;
-    p_sys->b_show_hidden_files = false;
     ReadDir(p_intf);
 
+    p_intf->pf_run = Run;
     return VLC_SUCCESS;
 }
 
@@ -2449,16 +2082,13 @@ static int Open(vlc_object_t *p_this)
  *****************************************************************************/
 static void Close(vlc_object_t *p_this)
 {
-    intf_thread_t *p_intf = (intf_thread_t *)p_this;
-    intf_sys_t    *p_sys = p_intf->p_sys;
+    intf_sys_t *p_sys = ((intf_thread_t*)p_this)->p_sys;
 
     PlaylistDestroy(p_sys);
     DirsDestroy(p_sys);
 
     free(p_sys->psz_current_dir);
-    free(p_sys->psz_search_chain);
     free(p_sys->psz_old_search);
-    free(p_sys->psz_open_chain);
 
     if (p_sys->p_input)
         vlc_object_release(p_sys->p_input);
@@ -2466,8 +2096,7 @@ static void Close(vlc_object_t *p_this)
     /* Close the ncurses interface */
     endwin();
 
-// FIXME    msg_Unsubscribe(p_intf, p_sys->p_sub);
+//  msg_Unsubscribe(p_intf, p_sys->p_sub);
 
-    /* Destroy structure */
     free(p_sys);
 }