/*****************************************************************************
* 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>
*
* 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.
*****************************************************************************/
/*****************************************************************************
#include <vlc/intf.h>
#include <vlc/vout.h>
#include <vlc/aout.h>
+#include "charset.h"
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
"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 );
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;
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 );
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();
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;
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
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;
/* 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;
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 );
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;
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 )
{
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;
}
/* 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;
}
{
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;
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 );
}
}
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" );
{
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 )
{
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 )
{
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) ) ) )
{
}
#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;
}
/****************************************************************************
*
****************************************************************************/
-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;