]> git.sesse.net Git - vlc/blobdiff - modules/gui/ncurses.c
interactions.*: button order (fix #470)
[vlc] / modules / gui / ncurses.c
index bdc5d3439f263d14909ffc11507416839cbb53e5..e02831573d297c4f49158ce09e628b4a75cf9f25 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * ncurses.c : NCurses plugin for vlc
  *****************************************************************************
- * Copyright (C) 2001-2004 VideoLAN
+ * Copyright (C) 2001-2006 the VideoLAN team
  * $Id$
  *
  * Authors: Sam Hocevar <sam@zoy.org>
@@ -21,7 +21,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 /*****************************************************************************
@@ -39,6 +39,7 @@
 #include <vlc/intf.h>
 #include <vlc/vout.h>
 #include <vlc/aout.h>
+#include "charset.h"
 
 #ifdef HAVE_SYS_STAT_H
 #   include <sys/stat.h>
@@ -96,11 +97,11 @@ static void ReadDir        ( intf_thread_t * );
     "will show you initially.")
 
 vlc_module_begin();
-    set_shortname( _("Ncurses"));
+    set_shortname( "Ncurses" );
     set_description( _("Ncurses interface") );
     set_capability( "interface", 10 );
     set_category( CAT_INTERFACE );
-    set_subcategory( SUBCAT_INTERFACE_GENERAL );
+    set_subcategory( SUBCAT_INTERFACE_MAIN );
     set_callbacks( Open, Close );
     add_shortcut( "curses" );
     add_directory( "browse-dir", NULL, NULL, BROWSE_TEXT, BROWSE_LONGTEXT, VLC_FALSE );
@@ -160,10 +161,12 @@ struct intf_sys_t
     int             i_before_search;
 
     char            *psz_open_chain;
+    char             psz_partial_keys[7];
 
     char            *psz_current_dir;
     int             i_dir_entries;
     struct dir_entry_t  **pp_dir_entries;
+    vlc_bool_t      b_show_hidden_files;
 
     int             i_current_view;             /* playlist view             */
     struct pl_item_t    **pp_plist;
@@ -171,7 +174,7 @@ struct intf_sys_t
     vlc_bool_t      b_need_update;              /* for playlist view */
 };
 
-static void DrawBox( WINDOW *win, int y, int x, int h, int w, char *title );
+static void DrawBox( WINDOW *win, int y, int x, int h, int w, const char *title );
 static void DrawLine( WINDOW *win, int y, int x, int w );
 static void DrawEmptyLine( WINDOW *win, int y, int x, int w );
 
@@ -199,7 +202,8 @@ static int Open( vlc_object_t *p_this )
     p_sys->i_box_plidx = 0;
     p_sys->p_plnode = NULL;
     p_sys->i_box_bidx = 0;
-    p_sys->p_sub = msg_Subscribe( p_intf );
+    p_sys->p_sub = msg_Subscribe( p_intf, MSG_QUEUE_NORMAL );
+    memset( p_sys->psz_partial_keys, 0, sizeof( p_sys->psz_partial_keys ) );
 
     /* Initialize the curses library */
     p_sys->w = initscr();
@@ -224,7 +228,7 @@ static int Open( vlc_object_t *p_this )
     var_Set( p_intf->p_vlc, "verbose", val );
 
     /* Set defaul playlist view */
-    p_sys->i_current_view = VIEW_SIMPLE;
+    p_sys->i_current_view = VIEW_CATEGORY;
     p_sys->pp_plist = NULL;
     p_sys->i_plist_entries = 0;
     p_sys->b_need_update = VLC_FALSE;
@@ -243,7 +247,7 @@ static int Open( vlc_object_t *p_this )
 
     if( val.psz_string && *val.psz_string )
     {
-        p_sys->psz_current_dir = strdup( val.psz_string);
+        p_sys->psz_current_dir = strdup( val.psz_string );
         free( val.psz_string );
     }
     else
@@ -253,6 +257,7 @@ static int Open( vlc_object_t *p_this )
 
     p_sys->i_dir_entries = 0;
     p_sys->pp_dir_entries = NULL;
+    p_sys->b_show_hidden_files = VLC_FALSE;
     ReadDir( p_intf );
 
     return VLC_SUCCESS;
@@ -398,6 +403,52 @@ static void Run( intf_thread_t *p_intf )
 
 /* following functions are local */
 
+static char *KeyToUTF8( int i_key, char *psz_part )
+{
+    char *psz_utf8, *psz;
+    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;
+
+    psz_utf8 = FromLocaleDup( psz_part );
+
+    /* Ugly check for incomplete bytes sequences
+     * (in case of non-UTF8 multibyte local encoding) */
+    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;
+        }
+
+    /* Check for incomplete UTF8 bytes sequence */
+    if( EnsureUTF8( psz_utf8 ) == NULL )
+    {
+        free( psz_utf8 );
+        return NULL;
+    }
+
+    memset( psz_part, 0, 6 );
+    return psz_utf8;
+}
+
+static inline int RemoveLastUTF8Entity( char *psz, int len )
+{
+    while( len && ( (psz[--len] & 0xc0) == 0x80 ) );
+                       /* UTF8 continuation byte */
+
+    psz[len] = '\0';
+    return len;
+}
+
 static int HandleKey( intf_thread_t *p_intf, int i_key )
 {
     intf_sys_t *p_sys = p_intf->p_sys;
@@ -439,14 +490,11 @@ static int HandleKey( intf_thread_t *p_intf, int i_key )
             case 'v':
                 switch( p_sys->i_current_view )
                 {
-                    case VIEW_SIMPLE:
-                        p_sys->i_current_view = VIEW_CATEGORY;
-                        break;
                     case VIEW_CATEGORY:
                         p_sys->i_current_view = VIEW_ALL;
                         break;
                     default:
-                        p_sys->i_current_view = VIEW_SIMPLE;
+                        p_sys->i_current_view = VIEW_CATEGORY;
                 }
                 PlaylistRebuild( p_intf );
                 FindIndex( p_intf );
@@ -564,10 +612,16 @@ static int HandleKey( intf_thread_t *p_intf, int i_key )
             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 ==
+                    VLC_TRUE ? VLC_FALSE : VLC_TRUE );
+                ReadDir( p_intf );
+                break;
 
             case KEY_ENTER:
             case 0x0d:
-                if( p_sys->pp_dir_entries[p_sys->i_box_bidx]->b_file )
+            case ' ':
+                if( p_sys->pp_dir_entries[p_sys->i_box_bidx]->b_file || i_key == ' ' )
                 {
                     int i_size_entry = strlen( p_sys->psz_current_dir ) +
                                        strlen( p_sys->pp_dir_entries[p_sys->i_box_bidx]->psz_path ) + 2;
@@ -691,18 +745,23 @@ static int HandleKey( intf_thread_t *p_intf, int i_key )
                 p_sys->i_box_type = BOX_PLAYLIST;
                 return 1;
             case KEY_BACKSPACE:
-                if( i_chain_len > 0 )
-                {
-                    p_sys->psz_search_chain[ i_chain_len - 1 ] = '\0';
-                }
+                RemoveLastUTF8Entity( p_sys->psz_search_chain, i_chain_len );
                 break;
             default:
-                if( i_chain_len < SEARCH_CHAIN_SIZE )
+            {
+                char *psz_utf8 = KeyToUTF8( i_key, p_sys->psz_partial_keys );
+
+                if( psz_utf8 != NULL )
                 {
-                    p_sys->psz_search_chain[ i_chain_len++ ] = i_key;
-                    p_sys->psz_search_chain[ i_chain_len ] = 0;
+                    if( i_chain_len + strlen( psz_utf8 ) < SEARCH_CHAIN_SIZE )
+                    {
+                        strcpy( p_sys->psz_search_chain + i_chain_len,
+                                psz_utf8 );
+                    }
+                    free( psz_utf8 );
                 }
                 break;
+            }
         }
         if( p_sys->psz_old_search )
         {
@@ -737,18 +796,23 @@ static int HandleKey( intf_thread_t *p_intf, int i_key )
                 p_sys->i_box_type = BOX_PLAYLIST;
                 return 1;
             case KEY_BACKSPACE:
-                if( i_chain_len > 0 )
-                {
-                    p_sys->psz_open_chain[ i_chain_len - 1 ] = '\0';
-                }
+                RemoveLastUTF8Entity( p_sys->psz_open_chain, i_chain_len );
                 break;
             default:
-                if( i_chain_len < OPEN_CHAIN_SIZE )
+            {
+                char *psz_utf8 = KeyToUTF8( i_key, p_sys->psz_partial_keys );
+
+                if( psz_utf8 != NULL )
                 {
-                    p_sys->psz_open_chain[ i_chain_len++ ] = i_key;
-                    p_sys->psz_open_chain[ i_chain_len ] = 0;
+                    if( i_chain_len + strlen( psz_utf8 ) < OPEN_CHAIN_SIZE )
+                    {
+                        strcpy( p_sys->psz_open_chain + i_chain_len,
+                                psz_utf8 );
+                    }
+                    free( psz_utf8 );
                 }
                 break;
+            }
         }
         return 1;
     }
@@ -838,16 +902,31 @@ static int HandleKey( intf_thread_t *p_intf, int i_key )
         /* Common control */
         case 'f':
         {
-            vout_thread_t *p_vout;
             if( p_intf->p_sys->p_input )
             {
+                vout_thread_t *p_vout;
                 p_vout = vlc_object_find( p_intf->p_sys->p_input,
                                           VLC_OBJECT_VOUT, FIND_CHILD );
                 if( p_vout )
                 {
-                    p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
+                    var_Get( p_vout, "fullscreen", &val );
+                    val.b_bool = !val.b_bool;
+                    var_Set( p_vout, "fullscreen", val );
                     vlc_object_release( p_vout );
                 }
+                else
+                {
+                    playlist_t *p_playlist;
+                    p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
+                                                  FIND_ANYWHERE );
+                    if( p_playlist )
+                    {
+                        var_Get( p_playlist, "fullscreen", &val );
+                        val.b_bool = !val.b_bool;
+                        var_Set( p_playlist, "fullscreen", val );
+                        vlc_object_release( p_playlist );
+                    }
+                }
             }
             return 0;
         }
@@ -1057,6 +1136,7 @@ static void mvnprintw( int y, int x, int w, const char *p_fmt, ... )
     {
         if( ( i_len = strlen( p_buf ) ) > w )
         {
+            char *psz_local;
             int i_cut = i_len - w;
             int x1 = i_len/2 - i_cut/2;
             int x2 = x1 + i_cut;
@@ -1072,11 +1152,15 @@ static void mvnprintw( int y, int x, int w, const char *p_fmt, ... )
                 p_buf[w/2  ] = '.';
                 p_buf[w/2+1] = '.';
             }
-            mvprintw( y, x, "%s", p_buf );
+            psz_local = ToLocale( p_buf );
+            mvprintw( y, x, "%s", psz_local );
+            LocaleFree( p_buf );
         }
         else
         {
-            mvprintw( y, x, "%s", p_buf );
+            char *psz_local = ToLocale( p_buf );
+            mvprintw( y, x, "%s", psz_local );
+            LocaleFree( p_buf );
             mvhline( y, x + i_len, ' ', w - i_len );
         }
     }
@@ -1250,6 +1334,12 @@ static void Redraw( intf_thread_t *p_intf, time_t *t_last_refresh )
         MainBoxWrite( p_intf, l++, 1, "     <backspace> Delete an entry" );
         MainBoxWrite( p_intf, l++, 1, "" );
 
+        MainBoxWrite( p_intf, l++, 1, "[Filebrowser]" );
+        MainBoxWrite( p_intf, l++, 1, "     <enter>     Add the selected file to the playlist" );
+        MainBoxWrite( p_intf, l++, 1, "     <space>     Add the selected directory to the playlist" );
+        MainBoxWrite( p_intf, l++, 1, "     .           Show/Hide hidden files" );
+        MainBoxWrite( p_intf, l++, 1, "" );
+
         MainBoxWrite( p_intf, l++, 1, "[Boxes]" );
         MainBoxWrite( p_intf, l++, 1, "     <up>,<down>     Navigate through the box line by line" );
         MainBoxWrite( p_intf, l++, 1, "     <pgup>,<pgdown> Navigate through the box page by page" );
@@ -1401,7 +1491,7 @@ static void Redraw( intf_thread_t *p_intf, time_t *t_last_refresh )
             {
                 attrset( A_REVERSE );
             }
-            mvnprintw( y++, 1, COLS - 2, "%c %s", p_sys->pp_dir_entries[i_item]->b_file == VLC_TRUE ? '-' : '+',
+            mvnprintw( y++, 1, COLS - 2, " %c %s", p_sys->pp_dir_entries[i_item]->b_file == VLC_TRUE ? ' ' : '+',
                             p_sys->pp_dir_entries[i_item]->psz_path );
             if( b_selected )
             {
@@ -1805,17 +1895,32 @@ static void Eject( intf_thread_t *p_intf )
     return;
 }
 
+static int comp_dir_entries( const void *pp_dir_entry1,
+                             const void *pp_dir_entry2 )
+{
+    struct dir_entry_t *p_dir_entry1 = *(struct dir_entry_t**)pp_dir_entry1;
+    struct dir_entry_t *p_dir_entry2 = *(struct dir_entry_t**)pp_dir_entry2;
+    if ( p_dir_entry1->b_file == p_dir_entry2->b_file ) {
+        return strcasecmp( p_dir_entry1->psz_path, p_dir_entry2->psz_path );
+    }
+    else 
+    {
+        return ( p_dir_entry1->b_file ? 1 : -1 );
+    }
+}
+
 static void ReadDir( intf_thread_t *p_intf )
 {
     intf_sys_t     *p_sys = p_intf->p_sys;
     DIR *                       p_current_dir;
-    struct dirent *             p_dir_content;
     int i;
 
     if( p_sys->psz_current_dir && *p_sys->psz_current_dir )
     {
+        const char *psz_entry;
+
         /* Open the dir */
-        p_current_dir = opendir( p_sys->psz_current_dir );
+        p_current_dir = utf8_opendir( p_sys->psz_current_dir );
 
         if( p_current_dir == NULL )
         {
@@ -1841,21 +1946,30 @@ static void ReadDir( intf_thread_t *p_intf )
         p_sys->i_dir_entries = 0;
 
         /* get the first directory entry */
-        p_dir_content = readdir( p_current_dir );
+        psz_entry = utf8_readdir( p_current_dir );
 
         /* while we still have entries in the directory */
-        while( p_dir_content != NULL )
+        while( psz_entry != NULL )
         {
 #if defined( S_ISDIR )
             struct stat stat_data;
 #endif
             struct dir_entry_t *p_dir_entry;
             int i_size_entry = strlen( p_sys->psz_current_dir ) +
-                               strlen( p_dir_content->d_name ) + 2;
-            char *psz_uri = (char *)malloc( sizeof(char)*i_size_entry);
+                               strlen( psz_entry ) + 2;
+            char *psz_uri;
 
-            sprintf( psz_uri, "%s/%s", p_sys->psz_current_dir,
-                     p_dir_content->d_name );
+            if( p_sys->b_show_hidden_files == VLC_FALSE && 
+                ( strlen( psz_entry ) && psz_entry[0] == '.' ) &&
+                strcmp( psz_entry, ".." ) )
+            {
+                LocaleFree( psz_entry );
+                psz_entry = utf8_readdir( p_current_dir );
+                continue;
+            }
+
+            psz_uri = (char *)malloc( sizeof(char)*i_size_entry);
+            sprintf( psz_uri, "%s/%s", p_sys->psz_current_dir, psz_entry );
 
             if( !( p_dir_entry = malloc( sizeof( struct dir_entry_t) ) ) )
             {
@@ -1864,31 +1978,37 @@ static void ReadDir( intf_thread_t *p_intf )
             }
 
 #if defined( S_ISDIR )
-            stat( psz_uri, &stat_data );
+            utf8_stat( psz_uri, &stat_data );
             if( S_ISDIR(stat_data.st_mode) )
-#elif defined( DT_DIR )
-            if( p_dir_content->d_type & DT_DIR )
+/*#elif defined( DT_DIR )
+            if( p_dir_content->d_type & DT_DIR )*/
 #else
             if( 0 )
 #endif
             {
-                p_dir_entry->psz_path = strdup( p_dir_content->d_name );
+                p_dir_entry->psz_path = strdup( psz_entry );
                 p_dir_entry->b_file = VLC_FALSE;
                 INSERT_ELEM( p_sys->pp_dir_entries, p_sys->i_dir_entries,
                      p_sys->i_dir_entries, p_dir_entry );
             }
             else
             {
-                p_dir_entry->psz_path = strdup( p_dir_content->d_name );
+                p_dir_entry->psz_path = strdup( psz_entry );
                 p_dir_entry->b_file = VLC_TRUE;
                 INSERT_ELEM( p_sys->pp_dir_entries, p_sys->i_dir_entries,
                      p_sys->i_dir_entries, p_dir_entry );
             }
 
             free( psz_uri );
+            LocaleFree( psz_entry );
             /* Read next entry */
-            p_dir_content = readdir( p_current_dir );
+            psz_entry = utf8_readdir( p_current_dir );
         }
+
+        /* Sort */
+        qsort( p_sys->pp_dir_entries, p_sys->i_dir_entries,
+               sizeof(struct dir_entry_t*), &comp_dir_entries );
+
         closedir( p_current_dir );
         return;
     }
@@ -1926,7 +2046,7 @@ static void PlayPause( intf_thread_t *p_intf )
 /****************************************************************************
  *
  ****************************************************************************/
-static void DrawBox( WINDOW *win, int y, int x, int h, int w, char *title )
+static void DrawBox( WINDOW *win, int y, int x, int h, int w, const char *title )
 {
     int i;
     int i_len;