]> git.sesse.net Git - vlc/blob - modules/gui/ncurses.c
Don't mix 2 implementation approaches
[vlc] / modules / gui / ncurses.c
1 /*****************************************************************************
2  * ncurses.c : NCurses interface for vlc
3  *****************************************************************************
4  * Copyright © 2001-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Sam Hocevar <sam@zoy.org>
8  *          Laurent Aimar <fenrir@via.ecp.fr>
9  *          Yoann Peronneau <yoann@videolan.org>
10  *          Derk-Jan Hartman <hartman at videolan dot org>
11  *          Rafaël Carré <funman@videolanorg>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 /*
29  * Note that when we use wide characters (and link with libncursesw),
30  * we assume that an UTF8 locale is used (or compatible, such as ASCII).
31  * Other characters encodings are not supported.
32  */
33
34 /*****************************************************************************
35  * Preamble
36  *****************************************************************************/
37 #ifdef HAVE_CONFIG_H
38 # include "config.h"
39 #endif
40
41 #include <vlc/vlc.h>
42
43 #ifdef HAVE_NCURSESW
44 #   define _XOPEN_SOURCE_EXTENDED 1
45 #   include <wchar.h>
46 #endif
47
48 #include <ncurses.h>
49
50 #include <vlc_interface.h>
51 #include <vlc_vout.h>
52 #include <vlc_aout.h>
53 #include <vlc_charset.h>
54 #include <vlc_input.h>
55 #include <vlc_es.h>
56 #include <vlc_playlist.h>
57 #include <vlc_meta.h>
58
59 #ifdef HAVE_SYS_STAT_H
60 #   include <sys/stat.h>
61 #endif
62 #if (!defined( WIN32 ) || defined(__MINGW32__))
63 /* Mingw has its own version of dirent */
64 #   include <dirent.h>
65 #endif
66
67 #ifdef HAVE_CDDAX
68 #define CDDA_MRL "cddax://"
69 #else
70 #define CDDA_MRL "cdda://"
71 #endif
72
73 #ifdef HAVE_VCDX
74 #define VCD_MRL "vcdx://"
75 #else
76 #define VCD_MRL "vcd://"
77 #endif
78
79 #define SEARCH_CHAIN_SIZE 20
80 #define OPEN_CHAIN_SIZE 50
81
82 /*****************************************************************************
83  * Local prototypes.
84  *****************************************************************************/
85 static int  Open           ( vlc_object_t * );
86 static void Close          ( vlc_object_t * );
87
88 static void Run            ( intf_thread_t * );
89 static void PlayPause      ( intf_thread_t * );
90 static void Eject          ( intf_thread_t * );
91
92 static int  HandleKey      ( intf_thread_t *, int );
93 static void Redraw         ( intf_thread_t *, time_t * );
94
95 static playlist_item_t *PlaylistGetRoot( intf_thread_t * );
96 static void PlaylistRebuild( intf_thread_t * );
97 static void PlaylistAddNode( intf_thread_t *, playlist_item_t *, int, const char *);
98 static void PlaylistDestroy( intf_thread_t * );
99 static int  PlaylistChanged( vlc_object_t *, const char *, vlc_value_t,
100                              vlc_value_t, void * );
101 static inline bool PlaylistIsPlaying( intf_thread_t *,
102                                             playlist_item_t * );
103 static void FindIndex      ( intf_thread_t * );
104 static void SearchPlaylist ( intf_thread_t *, char * );
105 static int  SubSearchPlaylist( intf_thread_t *, char *, int, int );
106
107 static void ManageSlider   ( intf_thread_t * );
108 static void ReadDir        ( intf_thread_t * );
109
110 static void start_color_and_pairs ( intf_thread_t * );
111
112 /*****************************************************************************
113  * Module descriptor
114  *****************************************************************************/
115
116 #define BROWSE_TEXT N_("Filebrowser starting point")
117 #define BROWSE_LONGTEXT N_( \
118     "This option allows you to specify the directory the ncurses filebrowser " \
119     "will show you initially.")
120
121 vlc_module_begin();
122     set_shortname( "Ncurses" );
123     set_description( _("Ncurses interface") );
124     set_capability( "interface", 10 );
125     set_category( CAT_INTERFACE );
126     set_subcategory( SUBCAT_INTERFACE_MAIN );
127     set_callbacks( Open, Close );
128     add_shortcut( "curses" );
129     add_directory( "browse-dir", NULL, NULL, BROWSE_TEXT, BROWSE_LONGTEXT, false );
130 vlc_module_end();
131
132 /*****************************************************************************
133  * intf_sys_t: description and status of ncurses interface
134  *****************************************************************************/
135 enum
136 {
137     BOX_NONE,
138     BOX_HELP,
139     BOX_INFO,
140     BOX_LOG,
141     BOX_PLAYLIST,
142     BOX_SEARCH,
143     BOX_OPEN,
144     BOX_BROWSE,
145     BOX_META,
146     BOX_OBJECTS,
147     BOX_STATS
148 };
149 enum
150 {
151     C_DEFAULT = 0,
152     C_TITLE,
153     C_PLAYLIST_1,
154     C_PLAYLIST_2,
155     C_PLAYLIST_3,
156     C_BOX,
157     C_STATUS,
158     C_INFO,
159     C_ERROR,
160     C_WARNING,
161     C_DEBUG,
162     C_CATEGORY,
163     C_FOLDER
164 };
165 enum
166 {
167     VIEW_CATEGORY,
168     VIEW_ONELEVEL
169 };
170 struct dir_entry_t
171 {
172     bool  b_file;
173     char        *psz_path;
174 };
175 struct pl_item_t
176 {
177     playlist_item_t *p_item;
178     char            *psz_display;
179 };
180 struct intf_sys_t
181 {
182     input_thread_t *p_input;
183     playlist_t     *p_playlist;
184
185     bool      b_color;
186     bool      b_color_started;
187
188     float           f_slider;
189     float           f_slider_old;
190
191     WINDOW          *w;
192
193     int             i_box_type;
194     int             i_box_y;
195     int             i_box_lines;
196     int             i_box_lines_total;
197     int             i_box_start;
198
199     int             i_box_plidx;    /* Playlist index */
200     int             b_box_plidx_follow;
201     int             i_box_bidx;     /* browser index */
202
203     playlist_item_t *p_node;        /* current node */
204
205     int             b_box_cleared;
206
207     msg_subscription_t* p_sub;                  /* message bank subscription */
208
209     char            *psz_search_chain;          /* for playlist searching    */
210     char            *psz_old_search;            /* for searching next        */
211     int             i_before_search;
212
213     char            *psz_open_chain;
214 #ifndef HAVE_NCURSESW
215     char             psz_partial_keys[7];
216 #endif
217
218     char            *psz_current_dir;
219     int             i_dir_entries;
220     struct dir_entry_t  **pp_dir_entries;
221     bool      b_show_hidden_files;
222
223     int             i_current_view;             /* playlist view             */
224     struct pl_item_t    **pp_plist;
225     int             i_plist_entries;
226     bool      b_need_update;              /* for playlist view         */
227
228     int             i_verbose;                  /* stores verbosity level    */
229 };
230
231 static void DrawBox( WINDOW *win, int y, int x, int h, int w, const char *title, bool b_color );
232 static void DrawLine( WINDOW *win, int y, int x, int w );
233 static void DrawEmptyLine( WINDOW *win, int y, int x, int w );
234
235 /*****************************************************************************
236  * Open: initialize and create window
237  *****************************************************************************/
238 static int Open( vlc_object_t *p_this )
239 {
240     intf_thread_t *p_intf = (intf_thread_t *)p_this;
241     intf_sys_t    *p_sys;
242     vlc_value_t    val;
243
244     /* Allocate instance and initialize some members */
245     p_sys = p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
246     p_sys->p_node = NULL;
247     p_sys->p_input = NULL;
248     p_sys->f_slider = 0.0;
249     p_sys->f_slider_old = 0.0;
250     p_sys->i_box_type = BOX_PLAYLIST;
251     p_sys->i_box_lines = 0;
252     p_sys->i_box_start= 0;
253     p_sys->i_box_lines_total = 0;
254     p_sys->b_box_plidx_follow = true;
255     p_sys->b_box_cleared = false;
256     p_sys->i_box_plidx = 0;
257     p_sys->i_box_bidx = 0;
258     p_sys->p_sub = msg_Subscribe( p_intf, MSG_QUEUE_NORMAL );
259     p_sys->b_color = var_CreateGetBool( p_intf, "color" );
260     p_sys->b_color_started = false;
261
262 #ifndef HAVE_NCURSESW
263     memset( p_sys->psz_partial_keys, 0, sizeof( p_sys->psz_partial_keys ) );
264 #endif
265
266     /* Initialize the curses library */
267     p_sys->w = initscr();
268
269     if( p_sys->b_color )
270         start_color_and_pairs( p_intf );
271
272     keypad( p_sys->w, TRUE );
273     /* Don't do NL -> CR/NL */
274     nonl();
275     /* Take input chars one at a time */
276     cbreak();
277     /* Don't echo */
278     noecho();
279     /* Invisible cursor */
280     curs_set( 0 );
281     /* Non blocking wgetch() */
282     wtimeout( p_sys->w, 0 );
283
284     clear();
285
286     /* exported function */
287     p_intf->pf_run = Run;
288
289     /* Remember verbosity level */
290     var_Get( p_intf->p_libvlc, "verbose", &val );
291     p_sys->i_verbose = val.i_int;
292     /* Set quiet mode */
293     val.i_int = -1;
294     var_Set( p_intf->p_libvlc, "verbose", val );
295
296     /* Set defaul playlist view */
297     p_sys->i_current_view = VIEW_CATEGORY;
298     p_sys->pp_plist = NULL;
299     p_sys->i_plist_entries = 0;
300     p_sys->b_need_update = false;
301
302     /* Initialize search chain */
303     p_sys->psz_search_chain = (char *)malloc( SEARCH_CHAIN_SIZE + 1 );
304     p_sys->psz_old_search = NULL;
305     p_sys->i_before_search = 0;
306
307     /* Initialize open chain */
308     p_sys->psz_open_chain = (char *)malloc( OPEN_CHAIN_SIZE + 1 );
309
310     /* Initialize browser options */
311     var_Create( p_intf, "browse-dir", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
312     var_Get( p_intf, "browse-dir", &val);
313
314     if( val.psz_string && *val.psz_string )
315     {
316         p_sys->psz_current_dir = strdup( val.psz_string );
317         free( val.psz_string );
318     }
319     else
320     {
321         p_sys->psz_current_dir = strdup( p_intf->p_libvlc->psz_homedir );
322     }
323
324     p_sys->i_dir_entries = 0;
325     p_sys->pp_dir_entries = NULL;
326     p_sys->b_show_hidden_files = false;
327     ReadDir( p_intf );
328
329     return VLC_SUCCESS;
330 }
331
332 /*****************************************************************************
333  * Close: destroy interface window
334  *****************************************************************************/
335 static void Close( vlc_object_t *p_this )
336 {
337     intf_thread_t *p_intf = (intf_thread_t *)p_this;
338     intf_sys_t    *p_sys = p_intf->p_sys;
339     int i;
340
341     PlaylistDestroy( p_intf );
342
343     for( i = 0; i < p_sys->i_dir_entries; i++ )
344     {
345         struct dir_entry_t *p_dir_entry = p_sys->pp_dir_entries[i];
346         free( p_dir_entry->psz_path );
347         REMOVE_ELEM( p_sys->pp_dir_entries, p_sys->i_dir_entries, i );
348         free( p_dir_entry );
349     }
350     p_sys->pp_dir_entries = NULL;
351
352     free( p_sys->psz_current_dir );
353     free( p_sys->psz_search_chain );
354     free( p_sys->psz_old_search );
355     free( p_sys->psz_open_chain );
356
357     if( p_sys->p_input )
358     {
359         vlc_object_release( p_sys->p_input );
360     }
361     pl_Release( p_intf );
362
363     /* Close the ncurses interface */
364     endwin();
365
366     msg_Unsubscribe( p_intf, p_sys->p_sub );
367
368     /* Restores initial verbose setting */
369     vlc_value_t val;
370     val.i_int = p_sys->i_verbose;
371     var_Set( p_intf->p_libvlc, "verbose", val );
372
373     /* Destroy structure */
374     free( p_sys );
375 }
376
377 /*****************************************************************************
378  * Run: ncurses thread
379  *****************************************************************************/
380 static void Run( intf_thread_t *p_intf )
381 {
382     intf_sys_t    *p_sys = p_intf->p_sys;
383     playlist_t    *p_playlist = pl_Yield( p_intf );
384     p_sys->p_playlist = p_playlist;
385
386     int i_key;
387     time_t t_last_refresh;
388
389     /*
390      * force drawing the interface for the first time
391      */
392     t_last_refresh = ( time( 0 ) - 1);
393     /*
394      * force building of the playlist array
395      */
396     PlaylistRebuild( p_intf );
397     var_AddCallback( p_playlist, "intf-change", PlaylistChanged, p_intf );
398     var_AddCallback( p_playlist, "item-append", PlaylistChanged, p_intf );
399
400     while( !intf_ShouldDie( p_intf ) )
401     {
402         msleep( INTF_IDLE_SLEEP );
403
404         /* Update the input */
405         PL_LOCK;
406         if( p_sys->p_input == NULL )
407         {
408             p_sys->p_input = p_playlist->p_input;
409             if( p_sys->p_input )
410             {
411                 if( !p_sys->p_input->b_dead )
412                 {
413                     vlc_object_yield( p_sys->p_input );
414                 }
415             }
416         }
417         else if( p_sys->p_input->b_dead )
418         {
419             vlc_object_release( p_sys->p_input );
420             p_sys->p_input = NULL;
421             p_sys->f_slider = p_sys->f_slider_old = 0.0;
422             p_sys->b_box_cleared = false;
423         }
424         PL_UNLOCK;
425
426         if( p_sys->b_box_plidx_follow && p_playlist->status.p_item )
427         {
428             FindIndex( p_intf );
429         }
430     
431         while( ( i_key = wgetch( p_sys->w ) ) != -1 )
432         {
433             /*
434              * HandleKey returns 1 if the screen needs to be redrawn
435              */
436             if( HandleKey( p_intf, i_key ) )
437             {
438                 Redraw( p_intf, &t_last_refresh );
439             }
440         }
441         /* Hack */
442         if( p_sys->f_slider > 0.0001 && !p_sys->b_box_cleared )
443         {
444             clear();
445             Redraw( p_intf, &t_last_refresh );
446             p_sys->b_box_cleared = true;
447         }
448
449         /*
450          * redraw the screen every second
451          */
452         if( (time(0) - t_last_refresh) >= 1 )
453         {
454             ManageSlider( p_intf );
455             Redraw( p_intf, &t_last_refresh );
456         }
457     }
458     var_DelCallback( p_playlist, "intf-change", PlaylistChanged, p_intf );
459     var_DelCallback( p_playlist, "item-append", PlaylistChanged, p_intf );
460 }
461
462 /* following functions are local */
463 static void start_color_and_pairs( intf_thread_t *p_intf )
464 {
465     assert( p_intf->p_sys->b_color && !p_intf->p_sys->b_color_started );
466
467     if( !has_colors() )
468     {
469         p_intf->p_sys->b_color = false;
470         msg_Warn( p_intf, "Terminal doesn't support colors" );
471         return;
472     }
473
474     start_color();
475
476     /* Available colors: BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE */
477
478     /* untested, in all my terminals, !can_change_color() --funman */
479     if( can_change_color() )
480         init_color( COLOR_YELLOW, 960, 500, 0 ); /* YELLOW -> ORANGE */
481
482     /* title */
483     init_pair( C_TITLE, COLOR_YELLOW, COLOR_BLACK );
484
485     /* jamaican playlist */
486     init_pair( C_PLAYLIST_1, COLOR_GREEN, COLOR_BLACK );
487     init_pair( C_PLAYLIST_2, COLOR_YELLOW, COLOR_BLACK );
488     init_pair( C_PLAYLIST_3, COLOR_RED, COLOR_BLACK );
489
490     /* used in DrawBox() */
491     init_pair( C_BOX, COLOR_CYAN, COLOR_BLACK );
492     /* Source, State, Position, Volume, Chapters, etc...*/
493     init_pair( C_STATUS, COLOR_BLUE, COLOR_BLACK );
494
495     /* VLC messages, keep the order from highest priority to lowest */
496
497     /* infos */
498     init_pair( C_INFO, COLOR_BLACK, COLOR_WHITE );
499     /* errors */
500     init_pair( C_ERROR, COLOR_RED, COLOR_BLACK );
501     /* warnings */
502     init_pair( C_WARNING, COLOR_YELLOW, COLOR_BLACK );
503 /* debug */
504     init_pair( C_DEBUG, COLOR_WHITE, COLOR_BLACK );
505
506     /* Category title (help, info, metadata) */
507     init_pair( C_CATEGORY, COLOR_MAGENTA, COLOR_BLACK );
508
509     /* Folder (BOX_BROWSE) */
510     init_pair( C_FOLDER, COLOR_RED, COLOR_BLACK );
511
512     p_intf->p_sys->b_color_started = true;
513 }
514
515 #ifndef HAVE_NCURSESW
516 static char *KeyToUTF8( int i_key, char *psz_part )
517 {
518     char *psz_utf8;
519     int len = strlen( psz_part );
520     if( len == 6 )
521     {
522         /* overflow error - should not happen */
523         memset( psz_part, 0, 6 );
524         return NULL;
525     }
526
527     psz_part[len] = (char)i_key;
528
529     psz_utf8 = FromLocaleDup( psz_part );
530
531     /* Ugly check for incomplete bytes sequences
532      * (in case of non-UTF8 multibyte local encoding) */
533     char *psz;
534     for( psz = psz_utf8; *psz; psz++ )
535         if( ( *psz == '?' ) && ( *psz_utf8 != '?' ) )
536         {
537             /* incomplete bytes sequence detected
538              * (VLC core inserted dummy question marks) */
539             free( psz_utf8 );
540             return NULL;
541         }
542
543     /* Check for incomplete UTF8 bytes sequence */
544     if( EnsureUTF8( psz_utf8 ) == NULL )
545     {
546         free( psz_utf8 );
547         return NULL;
548     }
549
550     memset( psz_part, 0, 6 );
551     return psz_utf8;
552 }
553 #endif
554
555 static inline int RemoveLastUTF8Entity( char *psz, int len )
556 {
557     while( len && ( (psz[--len] & 0xc0) == 0x80 ) );
558                        /* UTF8 continuation byte */
559
560     psz[len] = '\0';
561     return len;
562 }
563
564 static int HandleKey( intf_thread_t *p_intf, int i_key )
565 {
566     intf_sys_t *p_sys = p_intf->p_sys;
567     vlc_value_t val;
568     
569     #define ReturnTrue \
570     vlc_object_release( p_playlist ); \
571     return 1
572     
573     #define ReturnFalse \
574     vlc_object_release( p_playlist ); \
575     return 0
576
577     playlist_t *p_playlist = pl_Yield( p_intf );
578
579     if( p_sys->i_box_type == BOX_PLAYLIST )
580     {
581         int b_ret = true;
582         bool b_box_plidx_follow = false;
583
584         switch( i_key )
585         {
586             vlc_value_t val;
587             /* Playlist Settings */
588             case 'r':
589                 var_Get( p_playlist, "random", &val );
590                 val.b_bool = !val.b_bool;
591                 var_Set( p_playlist, "random", val );
592                 ReturnTrue;
593             case 'l':
594                 var_Get( p_playlist, "loop", &val );
595                 val.b_bool = !val.b_bool;
596                 var_Set( p_playlist, "loop", val );
597                 ReturnTrue;
598             case 'R':
599                 var_Get( p_playlist, "repeat", &val );
600                 val.b_bool = !val.b_bool;
601                 var_Set( p_playlist, "repeat", val );
602                 ReturnTrue;
603
604             /* Playlist sort */
605             case 'o':
606                 playlist_RecursiveNodeSort( p_playlist,
607                                             PlaylistGetRoot( p_intf ),
608                                             SORT_TITLE_NODES_FIRST, ORDER_NORMAL );
609                 p_sys->b_need_update = true;
610                 ReturnTrue;
611             case 'O':
612                 playlist_RecursiveNodeSort( p_playlist,
613                                             PlaylistGetRoot( p_intf ),
614                                             SORT_TITLE_NODES_FIRST, ORDER_REVERSE );
615                 p_sys->b_need_update = true;
616                 ReturnTrue;
617
618             /* Playlist view */
619             case 'v':
620                 switch( p_sys->i_current_view )
621                 {
622                     case VIEW_CATEGORY:
623                         p_sys->i_current_view = VIEW_ONELEVEL;
624                         break;
625                     default:
626                         p_sys->i_current_view = VIEW_CATEGORY;
627                 }
628                 //p_sys->b_need_update = true;
629                 PlaylistRebuild( p_intf );
630                 ReturnTrue;
631
632             /* Playlist navigation */
633             case 'g':
634                 FindIndex( p_intf );
635                 break;
636             case KEY_HOME:
637                 p_sys->i_box_plidx = 0;
638                 break;
639 #ifdef __FreeBSD__
640 /* workaround for FreeBSD + xterm:
641  * see http://www.nabble.com/curses-vs.-xterm-key-mismatch-t3574377.html */
642             case KEY_SELECT:
643 #endif
644             case KEY_END:
645                 p_sys->i_box_plidx = p_playlist->items.i_size - 1;
646                 break;
647             case KEY_UP:
648                 p_sys->i_box_plidx--;
649                 break;
650             case KEY_DOWN:
651                 p_sys->i_box_plidx++;
652                 break;
653             case KEY_PPAGE:
654                 p_sys->i_box_plidx -= p_sys->i_box_lines;
655                 break;
656             case KEY_NPAGE:
657                 p_sys->i_box_plidx += p_sys->i_box_lines;
658                 break;
659             case 'D':
660             case KEY_BACKSPACE:
661             case 0x7f:
662             case KEY_DC:
663             {
664                 playlist_item_t *p_item;
665
666                 PL_LOCK;
667                 p_item = p_sys->pp_plist[p_sys->i_box_plidx]->p_item;
668                 if( p_item->i_children == -1 )
669                 {
670                     playlist_DeleteFromInput( p_playlist,
671                                               p_item->p_input->i_id, true );
672                 }
673                 else
674                 {
675                     playlist_NodeDelete( p_playlist, p_item,
676                                          true , false );
677                 }
678                 PL_UNLOCK;
679                 PlaylistRebuild( p_intf );
680                 break;
681             }
682
683             case KEY_ENTER:
684             case '\r':
685             case '\n':
686                 if( !p_sys->pp_plist[p_sys->i_box_plidx] )
687                 {
688                     b_ret = false;
689                     break;
690                 }
691                 if( p_sys->pp_plist[p_sys->i_box_plidx]->p_item->i_children
692                         == -1 )
693                 {
694                     playlist_item_t *p_item, *p_parent;
695                     p_item = p_parent =
696                             p_sys->pp_plist[p_sys->i_box_plidx]->p_item;
697
698                     if( !p_parent )
699                         p_parent = p_playlist->p_root_onelevel;
700                     while( p_parent->p_parent )
701                         p_parent = p_parent->p_parent;
702                     playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
703                                       true, p_parent, p_item );
704                 }
705                 else if( p_sys->pp_plist[p_sys->i_box_plidx]->p_item->i_children
706                         == 0 )
707                 {   /* We only want to set the current node */
708                     playlist_Stop( p_playlist );
709                     p_sys->p_node = p_sys->pp_plist[p_sys->i_box_plidx]->p_item;
710                 }
711                 else
712                 {
713                     p_sys->p_node = p_sys->pp_plist[p_sys->i_box_plidx]->p_item;
714                     playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, true,
715                         p_sys->pp_plist[p_sys->i_box_plidx]->p_item, NULL );
716                 }
717                 b_box_plidx_follow = true;
718                 break;
719             default:
720                 b_ret = false;
721                 break;
722         }
723
724         if( b_ret )
725         {
726             int i_max = p_sys->i_plist_entries;
727             if( p_sys->i_box_plidx >= i_max ) p_sys->i_box_plidx = i_max - 1;
728             if( p_sys->i_box_plidx < 0 ) p_sys->i_box_plidx = 0;
729             if( PlaylistIsPlaying( p_intf,
730                     p_sys->pp_plist[p_sys->i_box_plidx]->p_item ) )
731                 b_box_plidx_follow = true;
732             p_sys->b_box_plidx_follow = b_box_plidx_follow;
733             ReturnTrue;
734         }
735     }
736     if( p_sys->i_box_type == BOX_BROWSE )
737     {
738         bool b_ret = true;
739         /* Browser navigation */
740         switch( i_key )
741         {
742             case KEY_HOME:
743                 p_sys->i_box_bidx = 0;
744                 break;
745 #ifdef __FreeBSD__
746             case KEY_SELECT:
747 #endif
748             case KEY_END:
749                 p_sys->i_box_bidx = p_sys->i_dir_entries - 1;
750                 break;
751             case KEY_UP:
752                 p_sys->i_box_bidx--;
753                 break;
754             case KEY_DOWN:
755                 p_sys->i_box_bidx++;
756                 break;
757             case KEY_PPAGE:
758                 p_sys->i_box_bidx -= p_sys->i_box_lines;
759                 break;
760             case KEY_NPAGE:
761                 p_sys->i_box_bidx += p_sys->i_box_lines;
762                 break;
763             case '.': /* Toggle show hidden files */
764                 p_sys->b_show_hidden_files = ( p_sys->b_show_hidden_files ==
765                     true ? false : true );
766                 ReadDir( p_intf );
767                 break;
768
769             case KEY_ENTER:
770             case '\r':
771             case '\n':
772             case ' ':
773                 if( p_sys->pp_dir_entries[p_sys->i_box_bidx]->b_file || i_key == ' ' )
774                 {
775                     int i_size_entry = strlen( "directory://" ) +
776                                        strlen( p_sys->psz_current_dir ) +
777                                        strlen( p_sys->pp_dir_entries[p_sys->i_box_bidx]->psz_path ) + 2;
778                     char *psz_uri = (char *)malloc( sizeof(char)*i_size_entry);
779
780                     sprintf( psz_uri, "directory://%s/%s", p_sys->psz_current_dir, p_sys->pp_dir_entries[p_sys->i_box_bidx]->psz_path );
781
782                     playlist_item_t *p_parent = p_sys->p_node;
783                     if( !p_parent )
784                     p_parent = p_playlist->status.p_node;
785                     if( !p_parent )
786                         p_parent = p_playlist->p_local_onelevel;
787
788                     while( p_parent->p_parent && p_parent->p_parent->p_parent )
789                         p_parent = p_parent->p_parent;
790
791                     playlist_Add( p_playlist, psz_uri, NULL, PLAYLIST_APPEND,
792                                   PLAYLIST_END,
793                                   p_parent->p_input == 
794                                     p_playlist->p_local_onelevel->p_input
795                                   , false );
796
797                     p_sys->i_box_type = BOX_PLAYLIST;
798                     free( psz_uri );
799                 }
800                 else
801                 {
802                     int i_size_entry = strlen( p_sys->psz_current_dir ) +
803                                        strlen( p_sys->pp_dir_entries[p_sys->i_box_bidx]->psz_path ) + 2;
804                     char *psz_uri = (char *)malloc( sizeof(char)*i_size_entry);
805
806                     sprintf( psz_uri, "%s/%s", p_sys->psz_current_dir, p_sys->pp_dir_entries[p_sys->i_box_bidx]->psz_path );
807
808                     p_sys->psz_current_dir = strdup( psz_uri );
809                     ReadDir( p_intf );
810                     free( psz_uri );
811                 }
812                 break;
813             default:
814                 b_ret = false;
815                 break;
816         }
817         if( b_ret )
818         {
819             if( p_sys->i_box_bidx >= p_sys->i_dir_entries ) p_sys->i_box_bidx = p_sys->i_dir_entries - 1;
820             if( p_sys->i_box_bidx < 0 ) p_sys->i_box_bidx = 0;
821             ReturnTrue;
822         }
823     }
824     else if( p_sys->i_box_type == BOX_HELP || p_sys->i_box_type == BOX_INFO ||
825              p_sys->i_box_type == BOX_META || p_sys->i_box_type == BOX_STATS ||
826              p_sys->i_box_type == BOX_OBJECTS )
827     {
828         switch( i_key )
829         {
830             case KEY_HOME:
831                 p_sys->i_box_start = 0;
832                 ReturnTrue;
833 #ifdef __FreeBSD__
834             case KEY_SELECT:
835 #endif
836             case KEY_END:
837                 p_sys->i_box_start = p_sys->i_box_lines_total - 1;
838                 ReturnTrue;
839             case KEY_UP:
840                 if( p_sys->i_box_start > 0 ) p_sys->i_box_start--;
841                 ReturnTrue;
842             case KEY_DOWN:
843                 if( p_sys->i_box_start < p_sys->i_box_lines_total - 1 )
844                 {
845                     p_sys->i_box_start++;
846                 }
847                 ReturnTrue;
848             case KEY_PPAGE:
849                 p_sys->i_box_start -= p_sys->i_box_lines;
850                 if( p_sys->i_box_start < 0 ) p_sys->i_box_start = 0;
851                 ReturnTrue;
852             case KEY_NPAGE:
853                 p_sys->i_box_start += p_sys->i_box_lines;
854                 if( p_sys->i_box_start >= p_sys->i_box_lines_total )
855                 {
856                     p_sys->i_box_start = p_sys->i_box_lines_total - 1;
857                 }
858                 ReturnTrue;
859             default:
860                 break;
861         }
862     }
863     else if( p_sys->i_box_type == BOX_NONE )
864     {
865         switch( i_key )
866         {
867             case KEY_HOME:
868                 p_sys->f_slider = 0;
869                 ManageSlider( p_intf );
870                 ReturnTrue;
871 #ifdef __FreeBSD__
872             case KEY_SELECT:
873 #endif
874             case KEY_END:
875                 p_sys->f_slider = 99.9;
876                 ManageSlider( p_intf );
877                 ReturnTrue;
878             case KEY_UP:
879                 p_sys->f_slider += 5.0;
880                 if( p_sys->f_slider >= 99.0 ) p_sys->f_slider = 99.0;
881                 ManageSlider( p_intf );
882                 ReturnTrue;
883             case KEY_DOWN:
884                 p_sys->f_slider -= 5.0;
885                 if( p_sys->f_slider < 0.0 ) p_sys->f_slider = 0.0;
886                 ManageSlider( p_intf );
887                 ReturnTrue;
888
889             default:
890                 break;
891         }
892     }
893     else if( p_sys->i_box_type == BOX_SEARCH && p_sys->psz_search_chain )
894     {
895         int i_chain_len = strlen( p_sys->psz_search_chain );
896         switch( i_key )
897         {
898             case KEY_CLEAR:
899             case 0x0c:      /* ^l */
900                 clear();
901                 ReturnTrue;
902             case KEY_ENTER:
903             case '\r':
904             case '\n':
905                 if( i_chain_len > 0 )
906                 {
907                     p_sys->psz_old_search = strdup( p_sys->psz_search_chain );
908                 }
909                 else if( p_sys->psz_old_search )
910                 {
911                     SearchPlaylist( p_intf, p_sys->psz_old_search );
912                 }
913                 p_sys->i_box_type = BOX_PLAYLIST;
914                 ReturnTrue;
915             case 0x1b: /* ESC */
916                 /* Alt+key combinations return 2 keys in the terminal keyboard:
917                  * ESC, and the 2nd key.
918                  * If some other key is available immediately (where immediately
919                  * means after wgetch() 1 second delay ), that means that the
920                  * ESC key was not pressed.
921                  *
922                  * man 3X curs_getch says:
923                  *
924                  * Use of the escape key by a programmer for a single
925                  * character function is discouraged, as it will cause a delay 
926                  * of up to one second while the keypad code looks for a
927                  * following function-key sequence.
928                  *
929                  */
930                 if( wgetch( p_sys->w ) != ERR )
931                     ReturnFalse;
932                 p_sys->i_box_plidx = p_sys->i_before_search;
933                 p_sys->i_box_type = BOX_PLAYLIST;
934                 ReturnTrue;
935             case KEY_BACKSPACE:
936             case 0x7f:
937                 RemoveLastUTF8Entity( p_sys->psz_search_chain, i_chain_len );
938                 break;
939             default:
940             {
941 #ifdef HAVE_NCURSESW
942                 if( i_chain_len + 1 < SEARCH_CHAIN_SIZE )
943                 {
944                     p_sys->psz_search_chain[i_chain_len] = (char) i_key;
945                     p_sys->psz_search_chain[i_chain_len + 1] = '\0';
946                 }
947 #else
948                 char *psz_utf8 = KeyToUTF8( i_key, p_sys->psz_partial_keys );
949
950                 if( psz_utf8 != NULL )
951                 {
952                     if( i_chain_len + strlen( psz_utf8 ) < SEARCH_CHAIN_SIZE )
953                     {
954                         strcpy( p_sys->psz_search_chain + i_chain_len,
955                                 psz_utf8 );
956                     }
957                     free( psz_utf8 );
958                 }
959 #endif
960                 break;
961             }
962         }
963         free( p_sys->psz_old_search );
964         p_sys->psz_old_search = NULL;
965         SearchPlaylist( p_intf, p_sys->psz_search_chain );
966         ReturnTrue;
967     }
968     else if( p_sys->i_box_type == BOX_OPEN && p_sys->psz_open_chain )
969     {
970         int i_chain_len = strlen( p_sys->psz_open_chain );
971
972         switch( i_key )
973         {
974             case KEY_CLEAR:
975             case 0x0c:          /* ^l */
976                 clear();
977                 ReturnTrue;
978             case KEY_ENTER:
979             case '\r': 
980             case '\n':
981                 if( i_chain_len > 0 )
982                 {
983                     playlist_item_t *p_parent = p_sys->p_node;
984                    
985                     if( !p_parent )
986                     p_parent = p_playlist->status.p_node;
987                     if( !p_parent )
988                         p_parent = p_playlist->p_local_onelevel;
989
990                     while( p_parent->p_parent && p_parent->p_parent->p_parent )
991                         p_parent = p_parent->p_parent;
992
993                     playlist_Add( p_playlist, p_sys->psz_open_chain, NULL,
994                                   PLAYLIST_APPEND|PLAYLIST_GO, PLAYLIST_END,
995                                   p_parent->p_input == 
996                                     p_playlist->p_local_onelevel->p_input
997                                   , false );
998
999                     p_sys->b_box_plidx_follow = true;
1000                 }
1001                 p_sys->i_box_type = BOX_PLAYLIST;
1002                 ReturnTrue;
1003             case 0x1b:  /* ESC */
1004                 if( wgetch( p_sys->w ) != ERR )
1005                     ReturnFalse;
1006                 p_sys->i_box_type = BOX_PLAYLIST;
1007                 ReturnTrue;
1008             case KEY_BACKSPACE:
1009             case 0x7f:
1010                 RemoveLastUTF8Entity( p_sys->psz_open_chain, i_chain_len );
1011                 break;
1012             default:
1013             {
1014 #ifdef HAVE_NCURSESW
1015                 if( i_chain_len + 1 < OPEN_CHAIN_SIZE )
1016                 {
1017                     p_sys->psz_open_chain[i_chain_len] = (char) i_key;
1018                     p_sys->psz_open_chain[i_chain_len + 1] = '\0';
1019                 }
1020 #else
1021                 char *psz_utf8 = KeyToUTF8( i_key, p_sys->psz_partial_keys );
1022
1023                 if( psz_utf8 != NULL )
1024                 {
1025                     if( i_chain_len + strlen( psz_utf8 ) < OPEN_CHAIN_SIZE )
1026                     {
1027                         strcpy( p_sys->psz_open_chain + i_chain_len,
1028                                 psz_utf8 );
1029                     }
1030                     free( psz_utf8 );
1031                 }
1032 #endif
1033                 break;
1034             }
1035         }
1036         ReturnTrue;
1037     }
1038
1039
1040     /* Common keys */
1041     switch( i_key )
1042     {
1043         case 0x1b:  /* ESC */
1044             if( wgetch( p_sys->w ) != ERR )
1045                 ReturnFalse;
1046         case 'q':
1047         case 'Q':
1048         case KEY_EXIT:
1049             vlc_object_kill( p_intf->p_libvlc );
1050             ReturnFalse;
1051
1052         /* Box switching */
1053         case 'i':
1054             if( p_sys->i_box_type == BOX_INFO )
1055                 p_sys->i_box_type = BOX_NONE;
1056             else
1057                 p_sys->i_box_type = BOX_INFO;
1058             p_sys->i_box_lines_total = 0;
1059             ReturnTrue;
1060         case 'm':
1061             if( p_sys->i_box_type == BOX_META )
1062                 p_sys->i_box_type = BOX_NONE;
1063             else
1064                 p_sys->i_box_type = BOX_META;
1065             p_sys->i_box_lines_total = 0;
1066             ReturnTrue;
1067         case 'L':
1068             if( p_sys->i_box_type == BOX_LOG )
1069                 p_sys->i_box_type = BOX_NONE;
1070             else
1071                 p_sys->i_box_type = BOX_LOG;
1072             ReturnTrue;
1073         case 'P':
1074             if( p_sys->i_box_type == BOX_PLAYLIST )
1075                 p_sys->i_box_type = BOX_NONE;
1076             else
1077                 p_sys->i_box_type = BOX_PLAYLIST;
1078             ReturnTrue;
1079         case 'B':
1080             if( p_sys->i_box_type == BOX_BROWSE )
1081                 p_sys->i_box_type = BOX_NONE;
1082             else
1083                 p_sys->i_box_type = BOX_BROWSE;
1084             ReturnTrue;
1085         case 'x':
1086             if( p_sys->i_box_type == BOX_OBJECTS )
1087                 p_sys->i_box_type = BOX_NONE;
1088             else
1089                 p_sys->i_box_type = BOX_OBJECTS;
1090             ReturnTrue;
1091         case 'S':
1092             if( p_sys->i_box_type == BOX_STATS )
1093                 p_sys->i_box_type = BOX_NONE;
1094             else
1095                 p_sys->i_box_type = BOX_STATS;
1096             ReturnTrue;
1097         case 'c':
1098             p_sys->b_color = !p_sys->b_color;
1099             if( p_sys->b_color && !p_sys->b_color_started )
1100                 start_color_and_pairs( p_intf );
1101             ReturnTrue;
1102         case 'h':
1103         case 'H':
1104             if( p_sys->i_box_type == BOX_HELP )
1105                 p_sys->i_box_type = BOX_NONE;
1106             else
1107                 p_sys->i_box_type = BOX_HELP;
1108             p_sys->i_box_lines_total = 0;
1109             ReturnTrue;
1110         case '/':
1111             if( p_sys->i_box_type != BOX_SEARCH )
1112             {
1113                 if( p_sys->psz_search_chain == NULL )
1114                     ReturnTrue;
1115                 p_sys->psz_search_chain[0] = '\0';
1116                 p_sys->b_box_plidx_follow = false;
1117                 p_sys->i_before_search = p_sys->i_box_plidx;
1118                 p_sys->i_box_type = BOX_SEARCH;
1119             }
1120             ReturnTrue;
1121         case 'A': /* Open */
1122             if( p_sys->i_box_type != BOX_OPEN )
1123             {
1124                 if( p_sys->psz_open_chain == NULL )
1125                     ReturnTrue;
1126                 p_sys->psz_open_chain[0] = '\0';
1127                 p_sys->i_box_type = BOX_OPEN;
1128             }
1129             ReturnTrue;
1130
1131         /* Navigation */
1132         case KEY_RIGHT:
1133             p_sys->f_slider += 1.0;
1134             if( p_sys->f_slider > 99.9 ) p_sys->f_slider = 99.9;
1135             ManageSlider( p_intf );
1136             ReturnTrue;
1137
1138         case KEY_LEFT:
1139             p_sys->f_slider -= 1.0;
1140             if( p_sys->f_slider < 0.0 ) p_sys->f_slider = 0.0;
1141             ManageSlider( p_intf );
1142             ReturnTrue;
1143
1144         /* Common control */
1145         case 'f':
1146         {
1147             if( p_intf->p_sys->p_input )
1148             {
1149                 vout_thread_t *p_vout;
1150                 p_vout = vlc_object_find( p_intf->p_sys->p_input,
1151                                           VLC_OBJECT_VOUT, FIND_CHILD );
1152                 if( p_vout )
1153                 {
1154                     var_Get( p_vout, "fullscreen", &val );
1155                     val.b_bool = !val.b_bool;
1156                     var_Set( p_vout, "fullscreen", val );
1157                     vlc_object_release( p_vout );
1158                 }
1159                 else
1160                 {
1161                     var_Get( p_playlist, "fullscreen", &val );
1162                     val.b_bool = !val.b_bool;
1163                     var_Set( p_playlist, "fullscreen", val );
1164                 }
1165             }
1166             ReturnFalse;
1167         }
1168
1169         case ' ':
1170             PlayPause( p_intf );
1171             ReturnTrue;
1172
1173         case 's':
1174             playlist_Stop( p_playlist );
1175             ReturnTrue;
1176
1177         case 'e':
1178             Eject( p_intf );
1179             ReturnTrue;
1180
1181         case '[':
1182             if( p_sys->p_input )
1183             {
1184                 val.b_bool = true;
1185                 var_Set( p_sys->p_input, "prev-title", val );
1186             }
1187             ReturnTrue;
1188
1189         case ']':
1190             if( p_sys->p_input )
1191             {
1192                 val.b_bool = true;
1193                 var_Set( p_sys->p_input, "next-title", val );
1194             }
1195             ReturnTrue;
1196
1197         case '<':
1198             if( p_sys->p_input )
1199             {
1200                 val.b_bool = true;
1201                 var_Set( p_sys->p_input, "prev-chapter", val );
1202             }
1203             ReturnTrue;
1204
1205         case '>':
1206             if( p_sys->p_input )
1207             {
1208                 val.b_bool = true;
1209                 var_Set( p_sys->p_input, "next-chapter", val );
1210             }
1211             ReturnTrue;
1212
1213         case 'p':
1214             playlist_Prev( p_playlist );
1215             clear();
1216             ReturnTrue;
1217
1218         case 'n':
1219             playlist_Next( p_playlist );
1220             clear();
1221             ReturnTrue;
1222
1223         case 'a':
1224             aout_VolumeUp( p_intf, 1, NULL );
1225             clear();
1226             ReturnTrue;
1227
1228         case 'z':
1229             aout_VolumeDown( p_intf, 1, NULL );
1230             clear();
1231             ReturnTrue;
1232
1233         /*
1234          * ^l should clear and redraw the screen
1235          */
1236         case KEY_CLEAR:
1237         case 0x0c:          /* ^l */
1238             clear();
1239             ReturnTrue;
1240
1241         default:
1242             ReturnFalse;
1243     }
1244 }
1245
1246 static void ManageSlider( intf_thread_t *p_intf )
1247 {
1248     intf_sys_t     *p_sys = p_intf->p_sys;
1249     input_thread_t *p_input = p_sys->p_input;
1250     vlc_value_t     val;
1251
1252     if( p_input == NULL )
1253     {
1254         return;
1255     }
1256     var_Get( p_input, "state", &val );
1257     if( val.i_int != PLAYING_S )
1258     {
1259         return;
1260     }
1261
1262     var_Get( p_input, "position", &val );
1263     if( p_sys->f_slider == p_sys->f_slider_old )
1264     {
1265         p_sys->f_slider =
1266         p_sys->f_slider_old = 100 * val.f_float;
1267     }
1268     else
1269     {
1270         p_sys->f_slider_old = p_sys->f_slider;
1271
1272         val.f_float = p_sys->f_slider / 100.0;
1273         var_Set( p_input, "position", val );
1274     }
1275 }
1276
1277 static void SearchPlaylist( intf_thread_t *p_intf, char *psz_searchstring )
1278 {
1279     int i_max;
1280     int i_first = 0 ;
1281     int i_item = -1;
1282     intf_sys_t *p_sys = p_intf->p_sys;
1283
1284     if( p_sys->i_before_search >= 0 )
1285     {
1286         i_first = p_sys->i_before_search;
1287     }
1288
1289     if( ( ! psz_searchstring ) ||  strlen( psz_searchstring ) <= 0 )
1290     {
1291         p_sys->i_box_plidx = p_sys->i_before_search;
1292         return;
1293     }
1294
1295     i_max = p_sys->i_plist_entries;
1296
1297     i_item = SubSearchPlaylist( p_intf, psz_searchstring, i_first + 1, i_max );
1298     if( i_item < 0 )
1299     {
1300         i_item = SubSearchPlaylist( p_intf, psz_searchstring, 0, i_first );
1301     }
1302
1303     if( i_item < 0 || i_item >= i_max ) return;
1304
1305     p_sys->i_box_plidx = i_item;
1306 }
1307
1308 static int SubSearchPlaylist( intf_thread_t *p_intf, char *psz_searchstring,
1309                               int i_start, int i_stop )
1310 {
1311     intf_sys_t *p_sys = p_intf->p_sys;
1312     int i, i_item = -1;
1313
1314     for( i = i_start + 1; i < i_stop; i++ )
1315     {
1316         if( strcasestr( p_sys->pp_plist[i]->psz_display,
1317                         psz_searchstring ) != NULL )
1318         {
1319             i_item = i;
1320             break;
1321         }
1322     }
1323
1324     return i_item;
1325 }
1326
1327
1328 static void mvnprintw( int y, int x, int w, const char *p_fmt, ... )
1329 {
1330     va_list  vl_args;
1331     char    *p_buf = NULL;
1332     int      i_len;
1333
1334     va_start( vl_args, p_fmt );
1335     if( vasprintf( &p_buf, p_fmt, vl_args ) == -1 )
1336         return;
1337     va_end( vl_args );
1338
1339     if( ( p_buf == NULL ) || ( w <= 0 ) )
1340         return;
1341
1342     i_len = strlen( p_buf );
1343
1344 #ifdef HAVE_NCURSESW
1345     wchar_t psz_wide[i_len + 1];
1346     
1347     EnsureUTF8( p_buf );
1348     size_t i_char_len = mbstowcs( psz_wide, p_buf, i_len );
1349
1350     size_t i_width; /* number of columns */
1351
1352     if( i_char_len == (size_t)-1 )
1353         /* an invalid character was encountered */
1354         return;
1355     else
1356     {
1357         i_width = wcswidth( psz_wide, i_char_len );
1358         if( i_width == (size_t)-1 )
1359         {
1360             /* a non printable character was encountered */
1361             unsigned int i;
1362             int i_cwidth;
1363             i_width = 0;
1364             for( i = 0 ; i < i_char_len ; i++ )
1365             {
1366                 i_cwidth = wcwidth( psz_wide[i] );
1367                 if( i_cwidth != -1 )
1368                     i_width += i_cwidth;
1369             }
1370         }
1371     }
1372     if( i_width > (size_t)w )
1373     {
1374         int i_total_width = 0;
1375         int i = 0;
1376         while( i_total_width < w )
1377         {
1378             i_total_width += wcwidth( psz_wide[i] );
1379             if( w > 7 && i_total_width >= w/2 )
1380             {
1381                 psz_wide[i  ] = '.';
1382                 psz_wide[i+1] = '.';
1383                 i_total_width -= wcwidth( psz_wide[i] ) - 2;
1384                 if( i > 0 )
1385                 {
1386                     /* we require this check only if at least one character
1387                      * 4 or more columns wide exists (which i doubt) */
1388                     psz_wide[i-1] = '.';
1389                     i_total_width -= wcwidth( psz_wide[i-1] ) - 1;
1390                 }
1391
1392                 /* find the widest string */
1393                 int j, i_2nd_width = 0;
1394                 for( j = i_char_len - 1; i_2nd_width < w - i_total_width; j-- )
1395                     i_2nd_width += wcwidth( psz_wide[j] );
1396
1397                 /* we already have i_total_width columns filled, and we can't
1398                  * have more than w columns */
1399                 if( i_2nd_width > w - i_total_width )
1400                     j++;
1401
1402                 wmemmove( &psz_wide[i+2], &psz_wide[j+1], i_char_len - j - 1 );
1403                 psz_wide[i + 2 + i_char_len - j - 1] = '\0';
1404                 break;
1405             }
1406             i++;
1407         }
1408         if( w <= 7 ) /* we don't add the '...' else we lose too much chars */
1409             psz_wide[i] = '\0';
1410
1411         size_t i_wlen = wcslen( psz_wide ) * 6 + 1; /* worst case */
1412         char psz_ellipsized[i_wlen];
1413         wcstombs( psz_ellipsized, psz_wide, i_wlen );
1414         mvprintw( y, x, "%s", psz_ellipsized );
1415     }
1416     else
1417     {
1418         mvprintw( y, x, "%s", p_buf );
1419         mvhline( y, x + i_width, ' ', w - i_width );
1420     }
1421 #else
1422     if( i_len > w )
1423     {
1424         int i_cut = i_len - w;
1425         int x1 = i_len/2 - i_cut/2;
1426         int x2 = x1 + i_cut;
1427
1428         if( i_len > x2 )
1429         {
1430             memmove( &p_buf[x1], &p_buf[x2], i_len - x2 );
1431         }
1432         p_buf[w] = '\0';
1433         if( w > 7 )
1434         {
1435             p_buf[w/2-1] = '.';
1436             p_buf[w/2  ] = '.';
1437             p_buf[w/2+1] = '.';
1438         }
1439         char *psz_local = ToLocale( p_buf );
1440         mvprintw( y, x, "%s", psz_local );
1441         LocaleFree( p_buf );
1442     }
1443     else
1444     {
1445         char *psz_local = ToLocale( p_buf );
1446         mvprintw( y, x, "%s", psz_local );
1447         LocaleFree( p_buf );
1448         mvhline( y, x + i_len, ' ', w - i_len );
1449     }
1450 #endif
1451 }
1452 static void MainBoxWrite( intf_thread_t *p_intf, int l, int x, const char *p_fmt, ... )
1453 {
1454     intf_sys_t     *p_sys = p_intf->p_sys;
1455
1456     va_list  vl_args;
1457     char    *p_buf = NULL;
1458
1459     if( l < p_sys->i_box_start || l - p_sys->i_box_start >= p_sys->i_box_lines )
1460     {
1461         return;
1462     }
1463
1464     va_start( vl_args, p_fmt );
1465     if( vasprintf( &p_buf, p_fmt, vl_args ) == -1 )
1466         return;
1467     va_end( vl_args );
1468
1469     if( p_buf == NULL )
1470     {
1471         return;
1472     }
1473
1474     mvnprintw( p_sys->i_box_y + l - p_sys->i_box_start, x, COLS - x - 1, "%s", p_buf );
1475 }
1476
1477 static void DumpObject( intf_thread_t *p_intf, int *l, vlc_object_t *p_obj, int i_level )
1478 {
1479     vlc_object_yield( p_obj );
1480
1481     if( p_obj->psz_object_name )
1482         MainBoxWrite( p_intf, (*l)++, 1 + 2 * i_level, "%s \"%s\" (%d)",
1483                 p_obj->psz_object_type, p_obj->psz_object_name,
1484                 p_obj->i_object_id );
1485     else
1486         MainBoxWrite( p_intf, (*l)++, 1 + 2 * i_level, "%s (%d)",
1487                 p_obj->psz_object_type, p_obj->i_object_id );
1488     int i;
1489     for( i = 0; i < p_obj->i_children ; i++ )
1490     {
1491         MainBoxWrite( p_intf, *l, 1 + 2 * i_level, 
1492             i == p_obj->i_children - 1 ? "`-" : "|-" );
1493         DumpObject( p_intf, l, p_obj->pp_children[i], i_level + 1 );
1494     }
1495
1496     vlc_object_release( p_obj );
1497 }
1498
1499 static void Redraw( intf_thread_t *p_intf, time_t *t_last_refresh )
1500 {
1501     intf_sys_t     *p_sys = p_intf->p_sys;
1502     input_thread_t *p_input = p_sys->p_input;
1503     playlist_t     *p_playlist = pl_Yield( p_intf );
1504     int y = 0;
1505     int h;
1506     int y_end;
1507
1508     clear();
1509
1510     /* Title */
1511     attrset( A_REVERSE );
1512     int i_len = strlen( "VLC media player "PACKAGE_VERSION );
1513     int mid = ( COLS - i_len ) / 2;
1514     if( mid < 0 )
1515         mid = 0;
1516     int i_size = ( COLS > i_len + 1 ) ? COLS : i_len + 1;
1517     char psz_title[i_size];
1518     memset( psz_title, ' ', mid );
1519     if( p_sys->b_color )
1520         wcolor_set( p_sys->w, C_TITLE, NULL );
1521     snprintf( &psz_title[mid], i_size, "VLC media player "PACKAGE_VERSION );
1522     mvnprintw( y, 0, COLS, "%s", psz_title );
1523     attroff( A_REVERSE );
1524     y += 2;
1525
1526     if( p_sys->b_color )
1527         wcolor_set( p_sys->w, C_STATUS, NULL );
1528
1529     /* Infos */
1530     char *psz_state;
1531     if( asprintf( &psz_state, "%s%s%s",
1532             var_GetBool( p_playlist, "repeat" ) ? _( "[Repeat] " ) : "",
1533             var_GetBool( p_playlist, "random" ) ? _( "[Random] " ) : "",
1534             var_GetBool( p_playlist, "loop" ) ? _( "[Loop]" ) : "" ) == -1 )
1535         psz_state = NULL;
1536
1537     if( p_input && !p_input->b_dead )
1538     {
1539         char buf1[MSTRTIME_MAX_SIZE];
1540         char buf2[MSTRTIME_MAX_SIZE];
1541         vlc_value_t val;
1542         vlc_value_t val_list;
1543
1544         /* Source */
1545         char *psz_uri = input_item_GetURI( input_GetItem( p_input ) );
1546         mvnprintw( y++, 0, COLS, _(" Source   : %s"), psz_uri );
1547         free( psz_uri );
1548
1549         /* State */
1550         var_Get( p_input, "state", &val );
1551         if( val.i_int == PLAYING_S )
1552         {
1553             mvnprintw( y++, 0, COLS, _(" State    : Playing %s"), psz_state );
1554         }
1555         else if( val.i_int == OPENING_S )
1556         {
1557             mvnprintw( y++, 0, COLS, _(" State    : Opening/Connecting %s"), psz_state );
1558         }
1559         else if( val.i_int == BUFFERING_S )
1560         {
1561             mvnprintw( y++, 0, COLS, _(" State    : Buffering %s"), psz_state );
1562         }
1563         else if( val.i_int == PAUSE_S )
1564         {
1565             mvnprintw( y++, 0, COLS, _(" State    : Paused %s"), psz_state );
1566         }
1567
1568         if( val.i_int != INIT_S && val.i_int != END_S )
1569         {
1570             audio_volume_t i_volume;
1571
1572             /* Position */
1573             var_Get( p_input, "time", &val );
1574             msecstotimestr( buf1, val.i_time / 1000 );
1575
1576             var_Get( p_input, "length", &val );
1577             msecstotimestr( buf2, val.i_time / 1000 );
1578
1579             mvnprintw( y++, 0, COLS, _(" Position : %s/%s (%.2f%%)"), buf1, buf2, p_sys->f_slider );
1580
1581             /* Volume */
1582             aout_VolumeGet( p_intf, &i_volume );
1583             mvnprintw( y++, 0, COLS, _(" Volume   : %i%%"), i_volume*200/AOUT_VOLUME_MAX );
1584
1585             /* Title */
1586             if( !var_Get( p_input, "title", &val ) )
1587             {
1588                 var_Change( p_input, "title", VLC_VAR_GETCHOICES, &val_list, NULL );
1589                 if( val_list.p_list->i_count > 0 )
1590                 {
1591                     mvnprintw( y++, 0, COLS, _(" Title    : %d/%d"), val.i_int, val_list.p_list->i_count );
1592                 }
1593                 var_Change( p_input, "title", VLC_VAR_FREELIST, &val_list, NULL );
1594             }
1595
1596             /* Chapter */
1597             if( !var_Get( p_input, "chapter", &val ) )
1598             {
1599                 var_Change( p_input, "chapter", VLC_VAR_GETCHOICES, &val_list, NULL );
1600                 if( val_list.p_list->i_count > 0 )
1601                 {
1602                     mvnprintw( y++, 0, COLS, _(" Chapter  : %d/%d"), val.i_int, val_list.p_list->i_count );
1603                 }
1604                 var_Change( p_input, "chapter", VLC_VAR_FREELIST, &val_list, NULL );
1605             }
1606         }
1607         else
1608         {
1609             y += 2;
1610         }
1611     }
1612     else
1613     {
1614         mvnprintw( y++, 0, COLS, _(" Source: <no current item> %s"), psz_state );
1615         DrawEmptyLine( p_sys->w, y++, 0, COLS );
1616         mvnprintw( y++, 0, COLS, _(" [ h for help ]") );
1617         DrawEmptyLine( p_sys->w, y++, 0, COLS );
1618     }
1619     free( psz_state );
1620     if( p_sys->b_color )
1621         wcolor_set( p_sys->w, C_DEFAULT, NULL );
1622
1623     DrawBox( p_sys->w, y, 0, 3, COLS, "", p_sys->b_color );
1624     DrawEmptyLine( p_sys->w, y+1, 1, COLS-2);
1625     DrawLine( p_sys->w, y+1, 1, (int)(p_intf->p_sys->f_slider/100.0 * (COLS -2)) );
1626     y += 3;
1627
1628     p_sys->i_box_y = y + 1;
1629     p_sys->i_box_lines = LINES - y - 2;
1630
1631     h = LINES - y;
1632     y_end = y + h - 1;
1633
1634     if( p_sys->i_box_type == BOX_HELP )
1635     {
1636         /* Help box */
1637         int l = 0;
1638         DrawBox( p_sys->w, y++, 0, h, COLS, _(" Help "), p_sys->b_color );
1639
1640         if( p_sys->b_color )
1641             wcolor_set( p_sys->w, C_CATEGORY, NULL );
1642         MainBoxWrite( p_intf, l++, 1, _("[Display]") );
1643         if( p_sys->b_color )
1644             wcolor_set( p_sys->w, C_DEFAULT, NULL );
1645         MainBoxWrite( p_intf, l++, 1, _("     h,H         Show/Hide help box") );
1646         MainBoxWrite( p_intf, l++, 1, _("     i           Show/Hide info box") );
1647         MainBoxWrite( p_intf, l++, 1, _("     m           Show/Hide metadata box") );
1648         MainBoxWrite( p_intf, l++, 1, _("     L           Show/Hide messages box") );
1649         MainBoxWrite( p_intf, l++, 1, _("     P           Show/Hide playlist box") );
1650         MainBoxWrite( p_intf, l++, 1, _("     B           Show/Hide filebrowser") );
1651         MainBoxWrite( p_intf, l++, 1, _("     x           Show/Hide objects box") );
1652         MainBoxWrite( p_intf, l++, 1, _("     S           Show/Hide statistics box" ) );
1653         MainBoxWrite( p_intf, l++, 1, _("     c           Switch color on/off") );
1654         MainBoxWrite( p_intf, l++, 1, _("     Esc         Close Add/Search entry") );
1655         MainBoxWrite( p_intf, l++, 1, "" );
1656
1657         if( p_sys->b_color )
1658             wcolor_set( p_sys->w, C_CATEGORY, NULL );
1659         MainBoxWrite( p_intf, l++, 1, _("[Global]") );
1660         if( p_sys->b_color )
1661             wcolor_set( p_sys->w, C_DEFAULT, NULL );
1662         MainBoxWrite( p_intf, l++, 1, _("     q, Q, Esc   Quit") );
1663         MainBoxWrite( p_intf, l++, 1, _("     s           Stop") );
1664         MainBoxWrite( p_intf, l++, 1, _("     <space>     Pause/Play") );
1665         MainBoxWrite( p_intf, l++, 1, _("     f           Toggle Fullscreen") );
1666         MainBoxWrite( p_intf, l++, 1, _("     n, p        Next/Previous playlist item") );
1667         MainBoxWrite( p_intf, l++, 1, _("     [, ]        Next/Previous title") );
1668         MainBoxWrite( p_intf, l++, 1, _("     <, >        Next/Previous chapter") );
1669         MainBoxWrite( p_intf, l++, 1, _("     <right>     Seek +1%%") );
1670         MainBoxWrite( p_intf, l++, 1, _("     <left>      Seek -1%%") );
1671         MainBoxWrite( p_intf, l++, 1, _("     a           Volume Up") );
1672         MainBoxWrite( p_intf, l++, 1, _("     z           Volume Down") );
1673         MainBoxWrite( p_intf, l++, 1, "" );
1674
1675         if( p_sys->b_color )
1676             wcolor_set( p_sys->w, C_CATEGORY, NULL );
1677         MainBoxWrite( p_intf, l++, 1, _("[Playlist]") );
1678         if( p_sys->b_color )
1679             wcolor_set( p_sys->w, C_DEFAULT, NULL );
1680         MainBoxWrite( p_intf, l++, 1, _("     r           Toggle Random playing") );
1681         MainBoxWrite( p_intf, l++, 1, _("     l           Toggle Loop Playlist") );
1682         MainBoxWrite( p_intf, l++, 1, _("     R           Toggle Repeat item") );
1683         MainBoxWrite( p_intf, l++, 1, _("     o           Order Playlist by title") );
1684         MainBoxWrite( p_intf, l++, 1, _("     O           Reverse order Playlist by title") );
1685         MainBoxWrite( p_intf, l++, 1, _("     g           Go to the current playing item") );
1686         MainBoxWrite( p_intf, l++, 1, _("     /           Look for an item") );
1687         MainBoxWrite( p_intf, l++, 1, _("     A           Add an entry") );
1688         MainBoxWrite( p_intf, l++, 1, _("     D, <del>    Delete an entry") );
1689         MainBoxWrite( p_intf, l++, 1, _("     <backspace> Delete an entry") );
1690         MainBoxWrite( p_intf, l++, 1, _("     e           Eject (if stopped)") );
1691         MainBoxWrite( p_intf, l++, 1, "" );
1692
1693         if( p_sys->b_color )
1694             wcolor_set( p_sys->w, C_CATEGORY, NULL );
1695         MainBoxWrite( p_intf, l++, 1, _("[Filebrowser]") );
1696         if( p_sys->b_color )
1697             wcolor_set( p_sys->w, C_DEFAULT, NULL );
1698         MainBoxWrite( p_intf, l++, 1, _("     <enter>     Add the selected file to the playlist") );
1699         MainBoxWrite( p_intf, l++, 1, _("     <space>     Add the selected directory to the playlist") );
1700         MainBoxWrite( p_intf, l++, 1, _("     .           Show/Hide hidden files") );
1701         MainBoxWrite( p_intf, l++, 1, "" );
1702
1703         if( p_sys->b_color )
1704             wcolor_set( p_sys->w, C_CATEGORY, NULL );
1705         MainBoxWrite( p_intf, l++, 1, _("[Boxes]") );
1706         if( p_sys->b_color )
1707             wcolor_set( p_sys->w, C_DEFAULT, NULL );
1708         MainBoxWrite( p_intf, l++, 1, _("     <up>,<down>     Navigate through the box line by line") );
1709         MainBoxWrite( p_intf, l++, 1, _("     <pgup>,<pgdown> Navigate through the box page by page") );
1710         MainBoxWrite( p_intf, l++, 1, "" );
1711
1712         if( p_sys->b_color )
1713             wcolor_set( p_sys->w, C_CATEGORY, NULL );
1714         MainBoxWrite( p_intf, l++, 1, _("[Player]") );
1715         if( p_sys->b_color )
1716             wcolor_set( p_sys->w, C_DEFAULT, NULL );
1717         MainBoxWrite( p_intf, l++, 1, _("     <up>,<down>     Seek +/-5%%") );
1718         MainBoxWrite( p_intf, l++, 1, "" );
1719
1720         if( p_sys->b_color )
1721             wcolor_set( p_sys->w, C_CATEGORY, NULL );
1722         MainBoxWrite( p_intf, l++, 1, _("[Miscellaneous]") );
1723         if( p_sys->b_color )
1724             wcolor_set( p_sys->w, C_DEFAULT, NULL );
1725         MainBoxWrite( p_intf, l++, 1, _("     Ctrl-l          Refresh the screen") );
1726
1727         p_sys->i_box_lines_total = l;
1728         if( p_sys->i_box_start >= p_sys->i_box_lines_total )
1729         {
1730             p_sys->i_box_start = p_sys->i_box_lines_total - 1;
1731         }
1732
1733         if( l - p_sys->i_box_start < p_sys->i_box_lines )
1734         {
1735             y += l - p_sys->i_box_start;
1736         }
1737         else
1738         {
1739             y += p_sys->i_box_lines;
1740         }
1741     }
1742     else if( p_sys->i_box_type == BOX_INFO )
1743     {
1744         /* Info box */
1745         int l = 0;
1746         DrawBox( p_sys->w, y++, 0, h, COLS, _(" Information "), p_sys->b_color );
1747
1748         if( p_input )
1749         {
1750             int i,j;
1751             vlc_mutex_lock( &input_GetItem(p_input)->lock );
1752             for( i = 0; i < input_GetItem(p_input)->i_categories; i++ )
1753             {
1754                 info_category_t *p_category = input_GetItem(p_input)->pp_categories[i];
1755                 if( y >= y_end ) break;
1756                 if( p_sys->b_color )
1757                     wcolor_set( p_sys->w, C_CATEGORY, NULL );
1758                 MainBoxWrite( p_intf, l++, 1, _("  [%s]"), p_category->psz_name );
1759                 if( p_sys->b_color )
1760                     wcolor_set( p_sys->w, C_DEFAULT, NULL );
1761                 for( j = 0; j < p_category->i_infos; j++ )
1762                 {
1763                     info_t *p_info = p_category->pp_infos[j];
1764                     if( y >= y_end ) break;
1765                     MainBoxWrite( p_intf, l++, 1, _("      %s: %s"), p_info->psz_name, p_info->psz_value );
1766                 }
1767             }
1768             vlc_mutex_unlock( &input_GetItem(p_input)->lock );
1769         }
1770         else
1771         {
1772             MainBoxWrite( p_intf, l++, 1, _("No item currently playing") );
1773         }
1774         p_sys->i_box_lines_total = l;
1775         if( p_sys->i_box_start >= p_sys->i_box_lines_total )
1776         {
1777             p_sys->i_box_start = p_sys->i_box_lines_total - 1;
1778         }
1779
1780         if( l - p_sys->i_box_start < p_sys->i_box_lines )
1781         {
1782             y += l - p_sys->i_box_start;
1783         }
1784         else
1785         {
1786             y += p_sys->i_box_lines;
1787         }
1788     }
1789     else if( p_sys->i_box_type == BOX_META )
1790     {
1791         /* Meta data box */
1792         int l = 0;
1793
1794         DrawBox( p_sys->w, y++, 0, h, COLS, _("Meta-information"),
1795                  p_sys->b_color );
1796
1797         if( p_input )
1798         {
1799             int i;
1800             input_item_t *p_item = input_GetItem( p_input );
1801             vlc_mutex_lock( &p_item->lock );
1802             for( i=0; i<VLC_META_TYPE_COUNT; i++ )
1803             {
1804                 if( y >= y_end ) break;
1805                 char *psz_meta = p_item->p_meta->ppsz_meta[i];
1806                 if( psz_meta && *psz_meta )
1807                 {
1808                     const char *psz_meta_title;
1809                     switch( i )
1810                     {
1811                         case 0:
1812                             psz_meta_title = VLC_META_TITLE; break;
1813                         case 1:
1814                             psz_meta_title = VLC_META_ARTIST; break;
1815                         case 2:
1816                             psz_meta_title = VLC_META_GENRE ; break;
1817                         case 3:
1818                             psz_meta_title = VLC_META_COPYRIGHT; break;
1819                         case 4:
1820                             psz_meta_title = VLC_META_ALBUM; break;
1821                         case 5:
1822                             psz_meta_title = VLC_META_TRACK_NUMBER; break;
1823                         case 6:
1824                             psz_meta_title = VLC_META_DESCRIPTION; break;
1825                         case 7:
1826                             psz_meta_title = VLC_META_RATING; break;
1827                         case 8:
1828                             psz_meta_title = VLC_META_DATE; break;
1829                         case 9:
1830                             psz_meta_title = VLC_META_SETTING; break;
1831                         case 10:
1832                             psz_meta_title = VLC_META_URL; break;
1833                         case 11:
1834                             psz_meta_title = VLC_META_LANGUAGE; break;
1835                         case 12:
1836                             psz_meta_title = VLC_META_NOW_PLAYING; break;
1837                         case 13:
1838                             psz_meta_title = VLC_META_PUBLISHER; break;
1839                         case 14:
1840                             psz_meta_title = VLC_META_ENCODED_BY; break;
1841                         case 15:
1842                             psz_meta_title = VLC_META_ART_URL; break;
1843                         case 16:
1844                             psz_meta_title = VLC_META_TRACKID; break;
1845                         default:
1846                             psz_meta_title = ""; break;
1847                     }
1848                     if( p_sys->b_color )
1849                         wcolor_set( p_sys->w, C_CATEGORY, NULL );
1850                     MainBoxWrite( p_intf, l++, 1, "  [%s]", psz_meta_title );
1851                     if( p_sys->b_color )
1852                         wcolor_set( p_sys->w, C_DEFAULT, NULL );
1853                     MainBoxWrite( p_intf, l++, 1, "      %s", psz_meta );
1854                 }
1855             }
1856             vlc_mutex_unlock( &p_item->lock );
1857         }
1858         else
1859         {
1860             MainBoxWrite( p_intf, l++, 1, _("No item currently playing") );
1861         }
1862         p_sys->i_box_lines_total = l;
1863         if( p_sys->i_box_start >= p_sys->i_box_lines_total )
1864         {
1865             p_sys->i_box_start = p_sys->i_box_lines_total - 1;
1866         }
1867
1868         if( l - p_sys->i_box_start < p_sys->i_box_lines )
1869         {
1870             y += l - p_sys->i_box_start;
1871         }
1872         else
1873         {
1874             y += p_sys->i_box_lines;
1875         }
1876     }
1877     else if( p_sys->i_box_type == BOX_LOG )
1878     {
1879         int i_line = 0;
1880         int i_stop;
1881         int i_start;
1882
1883         DrawBox( p_sys->w, y++, 0, h, COLS, _(" Logs "), p_sys->b_color );
1884
1885         i_start = p_intf->p_sys->p_sub->i_start;
1886
1887         vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock );
1888         i_stop = *p_intf->p_sys->p_sub->pi_stop;
1889         vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock );
1890
1891         for( ;; )
1892         {
1893             static const char *ppsz_type[4] = { "", "error", "warning", "debug" };
1894             if( i_line >= h - 2 )
1895             {
1896                 break;
1897             }
1898             i_stop--;
1899             i_line++;
1900             if( i_stop < 0 ) i_stop += VLC_MSG_QSIZE;
1901             if( i_stop == i_start )
1902             {
1903                 break;
1904             }
1905             if( p_sys->b_color )
1906                 wcolor_set( p_sys->w, 
1907                     p_sys->p_sub->p_msg[i_stop].i_type + C_INFO,
1908                     NULL );
1909             mvnprintw( y + h-2-i_line, 1, COLS - 2, "   [%s] %s",
1910                       ppsz_type[p_sys->p_sub->p_msg[i_stop].i_type],
1911                       p_sys->p_sub->p_msg[i_stop].psz_msg );
1912             if( p_sys->b_color )
1913                 wcolor_set( p_sys->w, C_DEFAULT, NULL );
1914         }
1915
1916         vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock );
1917         p_intf->p_sys->p_sub->i_start = i_stop;
1918         vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock );
1919         y = y_end;
1920     }
1921     else if( p_sys->i_box_type == BOX_BROWSE )
1922     {
1923         /* Filebrowser box */
1924         int        i_start, i_stop;
1925         int        i_item;
1926         DrawBox( p_sys->w, y++, 0, h, COLS, _(" Browse "), p_sys->b_color );
1927
1928         if( p_sys->i_box_bidx >= p_sys->i_dir_entries ) p_sys->i_box_plidx = p_sys->i_dir_entries - 1;
1929         if( p_sys->i_box_bidx < 0 ) p_sys->i_box_bidx = 0;
1930
1931         if( p_sys->i_box_bidx < (h - 2)/2 )
1932         {
1933             i_start = 0;
1934             i_stop = h - 2;
1935         }
1936         else if( p_sys->i_dir_entries - p_sys->i_box_bidx > (h - 2)/2 )
1937         {
1938             i_start = p_sys->i_box_bidx - (h - 2)/2;
1939             i_stop = i_start + h - 2;
1940         }
1941         else
1942         {
1943             i_stop = p_sys->i_dir_entries;
1944             i_start = p_sys->i_dir_entries - (h - 2);
1945         }
1946         if( i_start < 0 )
1947         {
1948             i_start = 0;
1949         }
1950         if( i_stop > p_sys->i_dir_entries )
1951         {
1952             i_stop = p_sys->i_dir_entries;
1953         }
1954
1955         for( i_item = i_start; i_item < i_stop; i_item++ )
1956         {
1957             bool b_selected = ( p_sys->i_box_bidx == i_item );
1958
1959             if( y >= y_end ) break;
1960             if( b_selected )
1961             {
1962                 attrset( A_REVERSE );
1963             }
1964             if( p_sys->b_color && !p_sys->pp_dir_entries[i_item]->b_file )
1965                 wcolor_set( p_sys->w, C_FOLDER, NULL );
1966             mvnprintw( y++, 1, COLS - 2, " %c %s", p_sys->pp_dir_entries[i_item]->b_file == true ? ' ' : '+',
1967                             p_sys->pp_dir_entries[i_item]->psz_path );
1968             if( p_sys->b_color && !p_sys->pp_dir_entries[i_item]->b_file )
1969                 wcolor_set( p_sys->w, C_DEFAULT, NULL );
1970
1971             if( b_selected )
1972             {
1973                 attroff( A_REVERSE );
1974             }
1975         }
1976
1977     }
1978     else if( p_sys->i_box_type == BOX_OBJECTS )
1979     {
1980         int l = 0;
1981         DrawBox( p_sys->w, y++, 0, h, COLS, _(" Objects "), p_sys->b_color );
1982         DumpObject( p_intf, &l, VLC_OBJECT( p_intf->p_libvlc ), 0 );
1983
1984         p_sys->i_box_lines_total = l;
1985         if( p_sys->i_box_start >= p_sys->i_box_lines_total )
1986             p_sys->i_box_start = p_sys->i_box_lines_total - 1;
1987
1988         if( l - p_sys->i_box_start < p_sys->i_box_lines )
1989             y += l - p_sys->i_box_start;
1990         else
1991             y += p_sys->i_box_lines;
1992     }
1993     else if( p_sys->i_box_type == BOX_STATS )
1994     {
1995         DrawBox( p_sys->w, y++, 0, h, COLS, _(" Stats "), p_sys->b_color );
1996
1997         if( p_input )
1998         {
1999             input_item_t *p_item = input_GetItem( p_input );
2000             assert( p_item );
2001             vlc_mutex_lock( &p_item->lock );
2002             vlc_mutex_lock( &p_item->p_stats->lock );
2003
2004             int i_audio = 0;
2005             int i_video = 0;
2006             int i;
2007
2008             if( !p_item->i_es )
2009                 i_video = i_audio = 1;
2010             else
2011                 for( i = 0; i < p_item->i_es ; i++ )
2012                 {
2013                     i_audio += ( p_item->es[i]->i_cat == AUDIO_ES );
2014                     i_video += ( p_item->es[i]->i_cat == VIDEO_ES );
2015                 }
2016
2017             int l = 0;
2018
2019 #define SHOW_ACS(x,c) \
2020     if(l >= p_sys->i_box_start && l - p_sys->i_box_start < p_sys->i_box_lines) \
2021         mvaddch( p_sys->i_box_y - p_sys->i_box_start + l, x, c )
2022
2023             /* Input */
2024             if( p_sys->b_color ) wcolor_set( p_sys->w, C_CATEGORY, NULL );
2025             MainBoxWrite( p_intf, l, 1, _("+-[Incoming]"));
2026             SHOW_ACS( 1, ACS_ULCORNER );  SHOW_ACS( 2, ACS_HLINE ); l++;
2027             if( p_sys->b_color ) wcolor_set( p_sys->w, C_DEFAULT, NULL );
2028             MainBoxWrite( p_intf, l, 1, _("| input bytes read : %8.0f kB"),
2029                     (float)(p_item->p_stats->i_read_bytes)/1000 );
2030             SHOW_ACS( 1, ACS_VLINE ); l++;
2031             MainBoxWrite( p_intf, l, 1, _("| input bitrate    :   %6.0f kb/s"),
2032                     (float)(p_item->p_stats->f_input_bitrate)*8000 );
2033             MainBoxWrite( p_intf, l, 1, _("| demux bytes read : %8.0f kB"),
2034                     (float)(p_item->p_stats->i_demux_read_bytes)/1000 );
2035             SHOW_ACS( 1, ACS_VLINE ); l++;
2036             MainBoxWrite( p_intf, l, 1, _("| demux bitrate    :   %6.0f kb/s"),
2037                     (float)(p_item->p_stats->f_demux_bitrate)*8000 );
2038             SHOW_ACS( 1, ACS_VLINE ); l++; SHOW_ACS( 1, ACS_VLINE ); l++;
2039
2040             /* Video */
2041             if( i_video )
2042             {
2043                 if( p_sys->b_color ) wcolor_set( p_sys->w, C_CATEGORY, NULL );
2044                 MainBoxWrite( p_intf, l, 1, _("+-[Video Decoding]"));
2045                 SHOW_ACS( 1, ACS_LTEE );  SHOW_ACS( 2, ACS_HLINE ); l++;
2046                 if( p_sys->b_color ) wcolor_set( p_sys->w, C_DEFAULT, NULL );
2047                 MainBoxWrite( p_intf, l, 1, _("| video decoded    :    %5i"),
2048                         p_item->p_stats->i_decoded_video );
2049                 SHOW_ACS( 1, ACS_VLINE ); l++;
2050                 MainBoxWrite( p_intf, l, 1, _("| frames displayed :    %5i"),
2051                         p_item->p_stats->i_displayed_pictures );
2052                 SHOW_ACS( 1, ACS_VLINE ); l++;
2053                 MainBoxWrite( p_intf, l, 1, _("| frames lost      :    %5i"),
2054                         p_item->p_stats->i_lost_pictures );
2055                 SHOW_ACS( 1, ACS_VLINE ); l++; SHOW_ACS( 1, ACS_VLINE ); l++;
2056             }
2057             /* Audio*/
2058             if( i_audio )
2059             {
2060                 if( p_sys->b_color ) wcolor_set( p_sys->w, C_CATEGORY, NULL );
2061                 MainBoxWrite( p_intf, l, 1, _("+-[Audio Decoding]"));
2062                 SHOW_ACS( 1, ACS_LTEE );  SHOW_ACS( 2, ACS_HLINE ); l++;
2063                 if( p_sys->b_color ) wcolor_set( p_sys->w, C_DEFAULT, NULL );
2064                 MainBoxWrite( p_intf, l, 1, _("| audio decoded    :    %5i"),
2065                         p_item->p_stats->i_decoded_audio );
2066                 SHOW_ACS( 1, ACS_VLINE ); l++;
2067                 MainBoxWrite( p_intf, l, 1, _("| buffers played   :    %5i"),
2068                         p_item->p_stats->i_played_abuffers );
2069                 SHOW_ACS( 1, ACS_VLINE ); l++;
2070                 MainBoxWrite( p_intf, l, 1, _("| buffers lost     :    %5i"),
2071                         p_item->p_stats->i_lost_abuffers );
2072                 SHOW_ACS( 1, ACS_VLINE ); l++; SHOW_ACS( 1, ACS_VLINE ); l++;
2073             }
2074             /* Sout */
2075             if( p_sys->b_color ) wcolor_set( p_sys->w, C_CATEGORY, NULL );
2076             MainBoxWrite( p_intf, l, 1, _("+-[Streaming]"));
2077             SHOW_ACS( 1, ACS_LTEE );  SHOW_ACS( 2, ACS_HLINE ); l++;
2078             if( p_sys->b_color ) wcolor_set( p_sys->w, C_DEFAULT, NULL );
2079             MainBoxWrite( p_intf, l, 1, _("| packets sent     :    %5i"), p_item->p_stats->i_sent_packets );
2080             SHOW_ACS( 1, ACS_VLINE ); l++;
2081             MainBoxWrite( p_intf, l, 1, _("| bytes sent       : %8.0f kB"),
2082                     (float)(p_item->p_stats->i_sent_bytes)/1000 );
2083             SHOW_ACS( 1, ACS_VLINE ); l++;
2084             MainBoxWrite( p_intf, l, 1, _("\\ sending bitrate  :   %6.0f kb/s"),
2085                     (float)(p_item->p_stats->f_send_bitrate*8)*1000 );
2086             SHOW_ACS( 1, ACS_LLCORNER ); l++;
2087             if( p_sys->b_color ) wcolor_set( p_sys->w, C_DEFAULT, NULL );
2088
2089 #undef SHOW_ACS
2090
2091             p_sys->i_box_lines_total = l;
2092             if( p_sys->i_box_start >= p_sys->i_box_lines_total )
2093                 p_sys->i_box_start = p_sys->i_box_lines_total - 1;
2094
2095             if( l - p_sys->i_box_start < p_sys->i_box_lines )
2096                 y += l - p_sys->i_box_start;
2097             else
2098                 y += p_sys->i_box_lines;
2099
2100             vlc_mutex_unlock( &p_item->p_stats->lock );
2101             vlc_mutex_unlock( &p_item->lock );
2102
2103         }
2104     }
2105     else if( p_sys->i_box_type == BOX_PLAYLIST ||
2106                p_sys->i_box_type == BOX_SEARCH ||
2107                p_sys->i_box_type == BOX_OPEN   )
2108     {
2109         /* Playlist box */
2110         int        i_start, i_stop, i_max = p_sys->i_plist_entries;
2111         int        i_item;
2112         char       *psz_title;
2113
2114         switch( p_sys->i_current_view )
2115         {
2116             case VIEW_ONELEVEL:
2117                 psz_title = strdup( _(" Playlist (All, one level) ") );
2118                 break;
2119             case VIEW_CATEGORY:
2120                 psz_title = strdup( _(" Playlist (By category) ") );
2121                 break;
2122             default:
2123                 psz_title = strdup( _(" Playlist (Manually added) ") );
2124         }
2125
2126         DrawBox( p_sys->w, y++, 0, h, COLS, psz_title, p_sys->b_color );
2127
2128         if( p_sys->b_need_update || p_sys->pp_plist == NULL )
2129         {
2130             PlaylistRebuild( p_intf );
2131         }
2132         if( p_sys->b_box_plidx_follow )
2133         {
2134             FindIndex( p_intf );
2135         }
2136
2137         if( p_sys->i_box_plidx < 0 ) p_sys->i_box_plidx = 0;
2138         if( p_sys->i_box_plidx < 0 ) p_sys->i_box_plidx = 0;
2139         if( p_sys->i_box_plidx >= i_max ) p_sys->i_box_plidx = i_max - 1;
2140
2141         if( p_sys->i_box_plidx < (h - 2)/2 )
2142         {
2143             i_start = 0;
2144             i_stop = h - 2;
2145         }
2146         else if( i_max - p_sys->i_box_plidx > (h - 2)/2 )
2147         {
2148             i_start = p_sys->i_box_plidx - (h - 2)/2;
2149             i_stop = i_start + h - 2;
2150         }
2151         else
2152         {
2153             i_stop = i_max;
2154             i_start = i_max - (h - 2);
2155         }
2156         if( i_start < 0 )
2157         {
2158             i_start = 0;
2159         }
2160         if( i_stop > i_max )
2161         {
2162             i_stop = i_max;
2163         }
2164
2165         for( i_item = i_start; i_item < i_stop; i_item++ )
2166         {
2167             bool b_selected = ( p_sys->i_box_plidx == i_item );
2168             playlist_item_t *p_item = p_sys->pp_plist[i_item]->p_item;
2169             playlist_item_t *p_node = p_sys->p_node;
2170             int c = ' ';
2171             if( ( p_node && p_item->p_input == p_node->p_input ) ||
2172                         ( !p_node && p_item->p_input ==
2173                         p_playlist->status.p_node->p_input ) )
2174                 c = '*';
2175             else if( p_item == p_node || ( p_item != p_node &&
2176                         PlaylistIsPlaying( p_intf, p_item ) ) )
2177                 c = '>';
2178
2179             if( y >= y_end ) break;
2180             if( b_selected )
2181             {
2182                 attrset( A_REVERSE );
2183             }
2184             if( p_sys->b_color )
2185                 wcolor_set( p_sys->w, i_item % 3 + C_PLAYLIST_1, NULL );
2186             mvnprintw( y++, 1, COLS - 2, "%c%s", c,
2187                        p_sys->pp_plist[i_item]->psz_display );
2188             if( p_sys->b_color )
2189                 wcolor_set( p_sys->w, C_DEFAULT, NULL );
2190             if( b_selected )
2191             {
2192                 attroff( A_REVERSE );
2193             }
2194         }
2195
2196     }
2197     else
2198     {
2199         y++;
2200     }
2201     if( p_sys->i_box_type == BOX_SEARCH )
2202     {
2203         DrawEmptyLine( p_sys->w, 7, 1, COLS-2 );
2204         if( p_sys->psz_search_chain )
2205         {
2206             if( strlen( p_sys->psz_search_chain ) == 0 &&
2207                 p_sys->psz_old_search != NULL )
2208             {
2209                 /* Searching next entry */
2210                 mvnprintw( 7, 1, COLS-2, _("Find: %s"), p_sys->psz_old_search );
2211             }
2212             else
2213             {
2214                 mvnprintw( 7, 1, COLS-2, _("Find: %s"), p_sys->psz_search_chain );
2215             }
2216         }
2217     }
2218     if( p_sys->i_box_type == BOX_OPEN )
2219     {
2220         if( p_sys->psz_open_chain )
2221         {
2222             DrawEmptyLine( p_sys->w, 7, 1, COLS-2 );
2223             mvnprintw( 7, 1, COLS-2, _("Open: %s"), p_sys->psz_open_chain );
2224         }
2225     }
2226
2227     while( y < y_end )
2228     {
2229         DrawEmptyLine( p_sys->w, y++, 1, COLS - 2 );
2230     }
2231
2232     refresh();
2233
2234     *t_last_refresh = time( 0 );
2235     vlc_object_release( p_playlist );
2236 }
2237
2238 static playlist_item_t *PlaylistGetRoot( intf_thread_t *p_intf )
2239 {
2240     intf_sys_t *p_sys = p_intf->p_sys;
2241     playlist_t *p_playlist = pl_Yield( p_intf );
2242     playlist_item_t *p_item;
2243
2244     switch( p_sys->i_current_view )
2245     {
2246         case VIEW_CATEGORY:
2247             p_item = p_playlist->p_root_category;
2248         default:
2249             p_item = p_playlist->p_root_onelevel;
2250     }
2251     vlc_object_release( p_playlist );
2252     return p_item;
2253 }
2254
2255 static void PlaylistRebuild( intf_thread_t *p_intf )
2256 {
2257     intf_sys_t *p_sys = p_intf->p_sys;
2258     playlist_t *p_playlist = pl_Yield( p_intf );
2259
2260     PL_LOCK;
2261
2262     /* First clear the old one */
2263     PlaylistDestroy( p_intf );
2264
2265     /* Build the new one */
2266     PlaylistAddNode( p_intf, PlaylistGetRoot( p_intf ), 0, "" );
2267
2268     p_sys->b_need_update = false;
2269
2270     PL_UNLOCK;
2271     
2272     vlc_object_release( p_playlist );
2273 }
2274
2275 static void PlaylistAddNode( intf_thread_t *p_intf, playlist_item_t *p_node,
2276                              int i, const char *c )
2277 {
2278     intf_sys_t *p_sys = p_intf->p_sys;
2279     playlist_item_t *p_child;
2280     int k;
2281
2282     for( k = 0; k < p_node->i_children; k++ )
2283     {
2284         char *psz_display;
2285         p_child = p_node->pp_children[k];
2286         char *psz_name = input_item_GetTitle( p_child->p_input );
2287         if( !psz_name || !*psz_name )
2288         {
2289             free( psz_name );
2290             psz_name = input_item_GetName( p_child->p_input );
2291         }
2292
2293         if( c && *c )
2294         {
2295             if( asprintf( &psz_display, "%s%c-%s", c,
2296                     k == p_node->i_children - 1 ?  '`' : '|', psz_name ) == -1 )
2297                 return;
2298         }
2299         else
2300         {
2301             if( asprintf( &psz_display, " %s", psz_name ) == -1 )
2302                 return;
2303         }
2304         free( psz_name );
2305         struct pl_item_t *p_pl_item = malloc( sizeof( struct pl_item_t ) );
2306         if( !p_pl_item )
2307             return;
2308         p_pl_item->psz_display = psz_display;
2309         p_pl_item->p_item = p_child;
2310         INSERT_ELEM( p_sys->pp_plist, p_sys->i_plist_entries,
2311                      p_sys->i_plist_entries, p_pl_item );
2312         i++;
2313
2314         if( p_child->i_children > 0 )
2315         {
2316             char *psz_tmp;
2317             if( asprintf( &psz_tmp, "%s%c ", c,
2318                      k == p_node->i_children - 1 ? ' ' : '|' ) == -1 )
2319                 return; 
2320             PlaylistAddNode( p_intf, p_child, i,
2321                              strlen( c ) ? psz_tmp : " " );
2322             free( psz_tmp );
2323         }
2324     }
2325 }
2326
2327 static int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
2328                             vlc_value_t oval, vlc_value_t nval, void *param )
2329 {
2330     VLC_UNUSED(p_this); VLC_UNUSED(psz_variable);
2331     VLC_UNUSED(oval); VLC_UNUSED(nval);
2332     intf_thread_t *p_intf = (intf_thread_t *)param;
2333     playlist_t *p_playlist = pl_Yield( p_intf );
2334     p_intf->p_sys->b_need_update = true;
2335     p_intf->p_sys->p_node = p_playlist->status.p_node;
2336     vlc_object_release( p_playlist );
2337     return VLC_SUCCESS;
2338 }
2339
2340 /* Playlist suxx */
2341 static inline bool PlaylistIsPlaying( intf_thread_t *p_intf,
2342                                             playlist_item_t *p_item )
2343 {
2344     playlist_t *p_playlist = pl_Yield( p_intf );
2345     playlist_item_t *p_played_item = p_playlist->status.p_item;
2346     vlc_object_release( p_playlist );
2347     return( p_item != NULL && p_played_item != NULL &&
2348             p_item->p_input != NULL && p_played_item->p_input != NULL &&
2349             p_item->p_input->i_id == p_played_item->p_input->i_id );
2350 }
2351
2352 static void FindIndex( intf_thread_t *p_intf )
2353 {
2354     intf_sys_t *p_sys = p_intf->p_sys;
2355     int i;
2356
2357     if( p_sys->i_box_plidx < p_sys->i_plist_entries && p_sys->i_box_plidx >= 0 )
2358     {
2359         playlist_item_t *p_item = p_sys->pp_plist[p_sys->i_box_plidx]->p_item;
2360         if( ( p_item->i_children == 0 && p_item == p_sys->p_node ) ||
2361                 PlaylistIsPlaying( p_intf, p_item ) )
2362             return;
2363     }
2364
2365     for( i = 0; i < p_sys->i_plist_entries; i++ )
2366     {
2367         playlist_item_t *p_item = p_sys->pp_plist[i]->p_item;
2368         if( ( p_item->i_children == 0 && p_item == p_sys->p_node ) ||
2369                 PlaylistIsPlaying( p_intf, p_sys->pp_plist[i]->p_item ) )
2370         {
2371             p_sys->i_box_plidx = i;
2372             break;
2373         }
2374     }
2375 }
2376
2377 static void PlaylistDestroy( intf_thread_t *p_intf )
2378 {
2379     intf_sys_t *p_sys = p_intf->p_sys;
2380     int i;
2381
2382     for( i = 0; i < p_sys->i_plist_entries; i++ )
2383     {
2384         struct pl_item_t *p_pl_item = p_sys->pp_plist[i];
2385         free( p_pl_item->psz_display );
2386         REMOVE_ELEM( p_sys->pp_plist, p_sys->i_plist_entries, i );
2387         free( p_pl_item );
2388     }
2389     p_sys->pp_plist = NULL;
2390     p_sys->i_plist_entries = 0;
2391 }
2392
2393 static void Eject( intf_thread_t *p_intf )
2394 {
2395     char *psz_device = NULL, *psz_parser, *psz_name;
2396
2397     /*
2398      * Get the active input
2399      * Determine whether we can eject a media, ie it's a DVD, VCD or CD-DA
2400      * If it's neither of these, then return
2401      */
2402
2403     playlist_t * p_playlist = pl_Yield( p_intf );
2404     PL_LOCK;
2405
2406     if( p_playlist->status.p_item == NULL )
2407     {
2408         PL_UNLOCK;
2409         vlc_object_release( p_playlist );
2410         return;
2411     }
2412
2413     psz_name = p_playlist->status.p_item->p_input->psz_name;
2414
2415     if( psz_name )
2416     {
2417         if( !strncmp(psz_name, "dvd://", 4) )
2418         {
2419             switch( psz_name[strlen("dvd://")] )
2420             {
2421             case '\0':
2422             case '@':
2423                 psz_device = config_GetPsz( p_intf, "dvd" );
2424                 break;
2425             default:
2426                 /* Omit the first MRL-selector characters */
2427                 psz_device = strdup( psz_name + strlen("dvd://" ) );
2428                 break;
2429             }
2430         }
2431         else if( !strncmp(psz_name, VCD_MRL, strlen(VCD_MRL)) )
2432         {
2433             switch( psz_name[strlen(VCD_MRL)] )
2434             {
2435             case '\0':
2436             case '@':
2437                 psz_device = config_GetPsz( p_intf, VCD_MRL );
2438                 break;
2439             default:
2440                 /* Omit the beginning MRL-selector characters */
2441                 psz_device = strdup( psz_name + strlen(VCD_MRL) );
2442                 break;
2443             }
2444         }
2445         else if( !strncmp(psz_name, CDDA_MRL, strlen(CDDA_MRL) ) )
2446         {
2447             switch( psz_name[strlen(CDDA_MRL)] )
2448             {
2449             case '\0':
2450             case '@':
2451                 psz_device = config_GetPsz( p_intf, "cd-audio" );
2452                 break;
2453             default:
2454                 /* Omit the beginning MRL-selector characters */
2455                 psz_device = strdup( psz_name + strlen(CDDA_MRL) );
2456                 break;
2457             }
2458         }
2459         else
2460         {
2461             psz_device = strdup( psz_name );
2462         }
2463     }
2464
2465     PL_UNLOCK;
2466
2467     if( psz_device == NULL )
2468     {
2469         return;
2470     }
2471
2472     /* Remove what we have after @ */
2473     psz_parser = psz_device;
2474     for( psz_parser = psz_device ; *psz_parser ; psz_parser++ )
2475     {
2476         if( *psz_parser == '@' )
2477         {
2478             *psz_parser = '\0';
2479             break;
2480         }
2481     }
2482
2483     /* If there's a stream playing, we aren't allowed to eject ! */
2484     if( p_intf->p_sys->p_input == NULL )
2485     {
2486         msg_Dbg( p_intf, "ejecting %s", psz_device );
2487
2488         intf_Eject( p_intf, psz_device );
2489     }
2490
2491     free( psz_device );
2492     vlc_object_release( p_playlist );
2493     return;
2494 }
2495
2496 static int comp_dir_entries( const void *pp_dir_entry1,
2497                              const void *pp_dir_entry2 )
2498 {
2499     struct dir_entry_t *p_dir_entry1 = *(struct dir_entry_t**)pp_dir_entry1;
2500     struct dir_entry_t *p_dir_entry2 = *(struct dir_entry_t**)pp_dir_entry2;
2501     if ( p_dir_entry1->b_file == p_dir_entry2->b_file ) {
2502         return strcasecmp( p_dir_entry1->psz_path, p_dir_entry2->psz_path );
2503     }
2504     else
2505     {
2506         return ( p_dir_entry1->b_file ? 1 : -1 );
2507     }
2508 }
2509
2510 static void ReadDir( intf_thread_t *p_intf )
2511 {
2512     intf_sys_t *p_sys = p_intf->p_sys;
2513     DIR *p_current_dir;
2514     int i;
2515
2516     if( p_sys->psz_current_dir && *p_sys->psz_current_dir )
2517     {
2518         char *psz_entry;
2519
2520         /* Open the dir */
2521         p_current_dir = utf8_opendir( p_sys->psz_current_dir );
2522
2523         if( p_current_dir == NULL )
2524         {
2525             /* something went bad, get out of here ! */
2526             msg_Warn( p_intf, "cannot open directory `%s' (%m)",
2527                       p_sys->psz_current_dir );
2528             return;
2529         }
2530
2531         /* Clean the old shit */
2532         for( i = 0; i < p_sys->i_dir_entries; i++ )
2533         {
2534             struct dir_entry_t *p_dir_entry = p_sys->pp_dir_entries[i];
2535             free( p_dir_entry->psz_path );
2536             REMOVE_ELEM( p_sys->pp_dir_entries, p_sys->i_dir_entries, i );
2537             free( p_dir_entry );
2538         }
2539         p_sys->pp_dir_entries = NULL;
2540         p_sys->i_dir_entries = 0;
2541
2542         /* while we still have entries in the directory */
2543         while( ( psz_entry = utf8_readdir( p_current_dir ) ) != NULL )
2544         {
2545 #if defined( S_ISDIR )
2546             struct stat stat_data;
2547 #endif
2548             struct dir_entry_t *p_dir_entry;
2549             int i_size_entry = strlen( p_sys->psz_current_dir ) +
2550                                strlen( psz_entry ) + 2;
2551             char *psz_uri;
2552
2553             if( p_sys->b_show_hidden_files == false &&
2554                 ( strlen( psz_entry ) && psz_entry[0] == '.' ) &&
2555                 strcmp( psz_entry, ".." ) )
2556             {
2557                 free( psz_entry );
2558                 continue;
2559             }
2560
2561             psz_uri = (char *)malloc( sizeof(char)*i_size_entry);
2562             sprintf( psz_uri, "%s/%s", p_sys->psz_current_dir, psz_entry );
2563
2564             if( !( p_dir_entry = malloc( sizeof( struct dir_entry_t) ) ) )
2565             {
2566                 free( psz_uri );
2567                 free( psz_entry );
2568                 continue;
2569             }
2570
2571 #if defined( S_ISDIR )
2572             if( !utf8_stat( psz_uri, &stat_data )
2573              && S_ISDIR(stat_data.st_mode) )
2574 /*#elif defined( DT_DIR )
2575             if( p_dir_content->d_type & DT_DIR )*/
2576 #else
2577             if( 0 )
2578 #endif
2579             {
2580                 p_dir_entry->psz_path = strdup( psz_entry );
2581                 p_dir_entry->b_file = false;
2582                 INSERT_ELEM( p_sys->pp_dir_entries, p_sys->i_dir_entries,
2583                      p_sys->i_dir_entries, p_dir_entry );
2584             }
2585             else
2586             {
2587                 p_dir_entry->psz_path = strdup( psz_entry );
2588                 p_dir_entry->b_file = true;
2589                 INSERT_ELEM( p_sys->pp_dir_entries, p_sys->i_dir_entries,
2590                      p_sys->i_dir_entries, p_dir_entry );
2591             }
2592
2593             free( psz_uri );
2594             free( psz_entry );
2595         }
2596
2597         /* Sort */
2598         qsort( p_sys->pp_dir_entries, p_sys->i_dir_entries,
2599                sizeof(struct dir_entry_t*), &comp_dir_entries );
2600
2601         closedir( p_current_dir );
2602         return;
2603     }
2604     else
2605     {
2606         msg_Dbg( p_intf, "no current dir set" );
2607         return;
2608     }
2609 }
2610
2611 static void PlayPause( intf_thread_t *p_intf )
2612 {
2613     input_thread_t *p_input = p_intf->p_sys->p_input;
2614     playlist_t *p_playlist = pl_Yield( p_intf );
2615     vlc_value_t val;
2616
2617     if( p_input )
2618     {
2619         var_Get( p_input, "state", &val );
2620         if( val.i_int != PAUSE_S )
2621         {
2622             val.i_int = PAUSE_S;
2623         }
2624         else
2625         {
2626             val.i_int = PLAYING_S;
2627         }
2628         var_Set( p_input, "state", val );
2629     }
2630     else
2631         playlist_Play( p_playlist );
2632
2633     vlc_object_release( p_playlist );
2634 }
2635
2636 /****************************************************************************
2637  *
2638  ****************************************************************************/
2639 static void DrawBox( WINDOW *win, int y, int x, int h, int w, const char *title, bool b_color )
2640 {
2641     int i;
2642     int i_len;
2643
2644     if( w > 3 && h > 2 )
2645     {
2646         if( b_color )
2647             wcolor_set( win, C_BOX, NULL );
2648         if( title == NULL ) title = "";
2649         i_len = strlen( title );
2650
2651         if( i_len > w - 2 ) i_len = w - 2;
2652
2653         mvwaddch( win, y, x,    ACS_ULCORNER );
2654         mvwhline( win, y, x+1,  ACS_HLINE, ( w-i_len-2)/2 );
2655         mvwprintw( win,y, x+1+(w-i_len-2)/2, "%s", title );
2656         mvwhline( win, y, x+(w-i_len)/2+i_len,  ACS_HLINE, w - 1 - ((w-i_len)/2+i_len) );
2657         mvwaddch( win, y, x+w-1,ACS_URCORNER );
2658
2659         for( i = 0; i < h-2; i++ )
2660         {
2661             mvwaddch( win, y+i+1, x,     ACS_VLINE );
2662             mvwaddch( win, y+i+1, x+w-1, ACS_VLINE );
2663         }
2664
2665         mvwaddch( win, y+h-1, x,     ACS_LLCORNER );
2666         mvwhline( win, y+h-1, x+1,   ACS_HLINE, w - 2 );
2667         mvwaddch( win, y+h-1, x+w-1, ACS_LRCORNER );
2668         if( b_color )
2669             wcolor_set( win, C_DEFAULT, NULL );
2670     }
2671 }
2672
2673 static void DrawEmptyLine( WINDOW *win, int y, int x, int w )
2674 {
2675     if( w > 0 )
2676     {
2677         mvwhline( win, y, x, ' ', w );
2678     }
2679 }
2680
2681 static void DrawLine( WINDOW *win, int y, int x, int w )
2682 {
2683     if( w > 0 )
2684     {
2685         attrset( A_REVERSE );
2686         mvwhline( win, y, x, ' ', w );
2687         attroff( A_REVERSE );
2688     }
2689 }