00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <errno.h>
00033 #include <stdio.h>
00034 #include <time.h>
00035
00036 #include <curses.h>
00037
00038 #include <vlc/vlc.h>
00039 #include <vlc/intf.h>
00040 #include <vlc/vout.h>
00041 #include <vlc/aout.h>
00042
00043 #ifdef HAVE_SYS_STAT_H
00044 # include <sys/stat.h>
00045 #endif
00046 #if (!defined( WIN32 ) || defined(__MINGW32__))
00047
00048 # include <dirent.h>
00049 #endif
00050
00051 #ifdef HAVE_CDDAX
00052 #define CDDA_MRL "cddax://"
00053 #else
00054 #define CDDA_MRL "cdda://"
00055 #endif
00056
00057 #ifdef HAVE_VCDX
00058 #define VCD_MRL "vcdx://"
00059 #else
00060 #define VCD_MRL "vcdx://"
00061 #endif
00062
00063 #define SEARCH_CHAIN_SIZE 20
00064 #define OPEN_CHAIN_SIZE 50
00065
00066
00067
00068
00069 static int Open ( vlc_object_t * );
00070 static void Close ( vlc_object_t * );
00071
00072 static void Run ( intf_thread_t * );
00073 static void PlayPause ( intf_thread_t * );
00074 static void Eject ( intf_thread_t * );
00075
00076 static int HandleKey ( intf_thread_t *, int );
00077 static void Redraw ( intf_thread_t *, time_t * );
00078 static void PlaylistRebuild( intf_thread_t * );
00079 static void PlaylistAddNode( intf_thread_t *, playlist_item_t *, int, char *);
00080 static void PlaylistDestroy( intf_thread_t * );
00081 static int PlaylistChanged( vlc_object_t *, const char *, vlc_value_t,
00082 vlc_value_t, void * );
00083 static void FindIndex ( intf_thread_t * );
00084 static void SearchPlaylist ( intf_thread_t *, char * );
00085 static int SubSearchPlaylist( intf_thread_t *, char *, int, int );
00086 static void ManageSlider ( intf_thread_t * );
00087 static void ReadDir ( intf_thread_t * );
00088
00089
00090
00091
00092
00093 #define BROWSE_TEXT N_("Filebrowser starting point")
00094 #define BROWSE_LONGTEXT N_( \
00095 "This option allows you to specify the directory the ncurses filebrowser " \
00096 "will show you initially.")
00097
00098 vlc_module_begin();
00099 set_shortname( "Ncurses" );
00100 set_description( _("Ncurses interface") );
00101 set_capability( "interface", 10 );
00102 set_category( CAT_INTERFACE );
00103 set_subcategory( SUBCAT_INTERFACE_GENERAL );
00104 set_callbacks( Open, Close );
00105 add_shortcut( "curses" );
00106 add_directory( "browse-dir", NULL, NULL, BROWSE_TEXT, BROWSE_LONGTEXT, VLC_FALSE );
00107 vlc_module_end();
00108
00109
00110
00111
00112 enum
00113 {
00114 BOX_NONE,
00115 BOX_HELP,
00116 BOX_INFO,
00117 BOX_LOG,
00118 BOX_PLAYLIST,
00119 BOX_SEARCH,
00120 BOX_OPEN,
00121 BOX_BROWSE
00122 };
00123 struct dir_entry_t
00124 {
00125 vlc_bool_t b_file;
00126 char *psz_path;
00127 };
00128 struct pl_item_t
00129 {
00130 playlist_item_t *p_item;
00131 char *psz_display;
00132 };
00133 struct intf_sys_t
00134 {
00135 playlist_t *p_playlist;
00136 input_thread_t *p_input;
00137
00138 float f_slider;
00139 float f_slider_old;
00140
00141 WINDOW *w;
00142
00143 int i_box_type;
00144 int i_box_y;
00145 int i_box_lines;
00146 int i_box_lines_total;
00147 int i_box_start;
00148
00149 int i_box_plidx;
00150 int b_box_plidx_follow;
00151 playlist_item_t *p_plnode;
00152 int i_box_bidx;
00153
00154 int b_box_cleared;
00155
00156 msg_subscription_t* p_sub;
00157
00158 char *psz_search_chain;
00159 char *psz_old_search;
00160 int i_before_search;
00161
00162 char *psz_open_chain;
00163
00164 char *psz_current_dir;
00165 int i_dir_entries;
00166 struct dir_entry_t **pp_dir_entries;
00167 vlc_bool_t b_show_hidden_files;
00168
00169 int i_current_view;
00170 struct pl_item_t **pp_plist;
00171 int i_plist_entries;
00172 vlc_bool_t b_need_update;
00173 };
00174
00175 static void DrawBox( WINDOW *win, int y, int x, int h, int w, char *title );
00176 static void DrawLine( WINDOW *win, int y, int x, int w );
00177 static void DrawEmptyLine( WINDOW *win, int y, int x, int w );
00178
00179
00180
00181
00182 static int Open( vlc_object_t *p_this )
00183 {
00184 intf_thread_t *p_intf = (intf_thread_t *)p_this;
00185 intf_sys_t *p_sys;
00186 vlc_value_t val;
00187
00188
00189 p_sys = p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
00190 p_sys->p_playlist = NULL;
00191 p_sys->p_input = NULL;
00192 p_sys->f_slider = 0.0;
00193 p_sys->f_slider_old = 0.0;
00194 p_sys->i_box_type = BOX_PLAYLIST;
00195 p_sys->i_box_lines = 0;
00196 p_sys->i_box_start= 0;
00197 p_sys->i_box_lines_total = 0;
00198 p_sys->b_box_plidx_follow = VLC_TRUE;
00199 p_sys->b_box_cleared = VLC_FALSE;
00200 p_sys->i_box_plidx = 0;
00201 p_sys->p_plnode = NULL;
00202 p_sys->i_box_bidx = 0;
00203 p_sys->p_sub = msg_Subscribe( p_intf );
00204
00205
00206 p_sys->w = initscr();
00207 keypad( p_sys->w, TRUE );
00208
00209 nonl();
00210
00211 cbreak();
00212
00213 noecho();
00214
00215 curs_set(0);
00216 timeout(0);
00217
00218 clear();
00219
00220
00221 p_intf->pf_run = Run;
00222
00223
00224 val.i_int = -1;
00225 var_Set( p_intf->p_vlc, "verbose", val );
00226
00227
00228 p_sys->i_current_view = VIEW_CATEGORY;
00229 p_sys->pp_plist = NULL;
00230 p_sys->i_plist_entries = 0;
00231 p_sys->b_need_update = VLC_FALSE;
00232
00233
00234 p_sys->psz_search_chain = (char *)malloc( SEARCH_CHAIN_SIZE + 1 );
00235 p_sys->psz_old_search = NULL;
00236 p_sys->i_before_search = 0;
00237
00238
00239 p_sys->psz_open_chain = (char *)malloc( OPEN_CHAIN_SIZE + 1 );
00240
00241
00242 var_Create( p_intf, "browse-dir", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
00243 var_Get( p_intf, "browse-dir", &val);
00244
00245 if( val.psz_string && *val.psz_string )
00246 {
00247 p_sys->psz_current_dir = strdup( val.psz_string);
00248 free( val.psz_string );
00249 }
00250 else
00251 {
00252 p_sys->psz_current_dir = strdup( p_intf->p_vlc->psz_homedir );
00253 }
00254
00255 p_sys->i_dir_entries = 0;
00256 p_sys->pp_dir_entries = NULL;
00257 p_sys->b_show_hidden_files = VLC_FALSE;
00258 ReadDir( p_intf );
00259
00260 return VLC_SUCCESS;
00261 }
00262
00263
00264
00265
00266 static void Close( vlc_object_t *p_this )
00267 {
00268 intf_thread_t *p_intf = (intf_thread_t *)p_this;
00269 intf_sys_t *p_sys = p_intf->p_sys;
00270 int i;
00271
00272 var_DelCallback( p_sys->p_playlist, "intf-change", PlaylistChanged,
00273 p_intf );
00274 var_DelCallback( p_sys->p_playlist, "item-append", PlaylistChanged,
00275 p_intf );
00276
00277 PlaylistDestroy( p_intf );
00278
00279 for( i = 0; i < p_sys->i_dir_entries; i++ )
00280 {
00281 struct dir_entry_t *p_dir_entry = p_sys->pp_dir_entries[i];
00282 if( p_dir_entry->psz_path ) free( p_dir_entry->psz_path );
00283 REMOVE_ELEM( p_sys->pp_dir_entries, p_sys->i_dir_entries, i );
00284 if( p_dir_entry ) free( p_dir_entry );
00285 }
00286 p_sys->pp_dir_entries = NULL;
00287
00288 if( p_sys->psz_current_dir ) free( p_sys->psz_current_dir );
00289 if( p_sys->psz_search_chain ) free( p_sys->psz_search_chain );
00290 if( p_sys->psz_old_search ) free( p_sys->psz_old_search );
00291 if( p_sys->psz_open_chain ) free( p_sys->psz_open_chain );
00292
00293 if( p_sys->p_input )
00294 {
00295 vlc_object_release( p_sys->p_input );
00296 }
00297 if( p_sys->p_playlist )
00298 {
00299 vlc_object_release( p_sys->p_playlist );
00300 }
00301
00302
00303 endwin();
00304
00305 msg_Unsubscribe( p_intf, p_sys->p_sub );
00306
00307
00308 free( p_sys );
00309 }
00310
00311
00312
00313
00314 static void Run( intf_thread_t *p_intf )
00315 {
00316 intf_sys_t *p_sys = p_intf->p_sys;
00317
00318 int i_key;
00319 time_t t_last_refresh;
00320
00321
00322
00323
00324 t_last_refresh = ( time( 0 ) - 1);
00325
00326 while( !p_intf->b_die )
00327 {
00328 msleep( INTF_IDLE_SLEEP );
00329
00330
00331 if( p_sys->p_playlist == NULL )
00332 {
00333 p_sys->p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
00334 FIND_ANYWHERE );
00335 if( p_sys->p_playlist )
00336 {
00337 var_AddCallback( p_sys->p_playlist, "intf-change",
00338 PlaylistChanged, p_intf );
00339 var_AddCallback( p_sys->p_playlist, "item-append",
00340 PlaylistChanged, p_intf );
00341 }
00342 }
00343 if( p_sys->p_playlist )
00344 {
00345 vlc_mutex_lock( &p_sys->p_playlist->object_lock );
00346 if( p_sys->p_input == NULL )
00347 {
00348 p_sys->p_input = p_sys->p_playlist->p_input;
00349 if( p_sys->p_input )
00350 {
00351 if( !p_sys->p_input->b_dead )
00352 {
00353 vlc_object_yield( p_sys->p_input );
00354 }
00355 }
00356 }
00357 else if( p_sys->p_input->b_dead )
00358 {
00359 vlc_object_release( p_sys->p_input );
00360 p_sys->p_input = NULL;
00361 p_sys->f_slider = p_sys->f_slider_old = 0.0;
00362 p_sys->b_box_cleared = VLC_FALSE;
00363 }
00364 vlc_mutex_unlock( &p_sys->p_playlist->object_lock );
00365 }
00366
00367 if( p_sys->b_box_plidx_follow && p_sys->p_playlist->i_index >= 0 )
00368 {
00369 FindIndex( p_intf );
00370 }
00371
00372 while( ( i_key = getch()) != -1 )
00373 {
00374
00375
00376
00377 if( HandleKey( p_intf, i_key ) )
00378 {
00379 Redraw( p_intf, &t_last_refresh );
00380 }
00381 }
00382
00383 if( p_sys->f_slider > 0.0001 && !p_sys->b_box_cleared )
00384 {
00385 clear();
00386 Redraw( p_intf, &t_last_refresh );
00387 p_sys->b_box_cleared = VLC_TRUE;
00388 }
00389
00390
00391
00392
00393 if( (time(0) - t_last_refresh) >= 1 )
00394 {
00395 ManageSlider( p_intf );
00396 Redraw( p_intf, &t_last_refresh );
00397 }
00398 }
00399 }
00400
00401
00402
00403 static int HandleKey( intf_thread_t *p_intf, int i_key )
00404 {
00405 intf_sys_t *p_sys = p_intf->p_sys;
00406 vlc_value_t val;
00407
00408 if( p_sys->i_box_type == BOX_PLAYLIST && p_sys->p_playlist )
00409 {
00410 int b_ret = VLC_TRUE;
00411
00412 switch( i_key )
00413 {
00414 vlc_value_t val;
00415
00416 case 'r':
00417 var_Get( p_sys->p_playlist, "random", &val );
00418 val.b_bool = !val.b_bool;
00419 var_Set( p_sys->p_playlist, "random", val );
00420 return 1;
00421 case 'l':
00422 var_Get( p_sys->p_playlist, "loop", &val );
00423 val.b_bool = !val.b_bool;
00424 var_Set( p_sys->p_playlist, "loop", val );
00425 return 1;
00426 case 'R':
00427 var_Get( p_sys->p_playlist, "repeat", &val );
00428 val.b_bool = !val.b_bool;
00429 var_Set( p_sys->p_playlist, "repeat", val );
00430 return 1;
00431
00432
00433 case 'o':
00434 playlist_Sort( p_sys->p_playlist, SORT_TITLE, ORDER_NORMAL );
00435 return 1;
00436 case 'O':
00437 playlist_Sort( p_sys->p_playlist, SORT_TITLE, ORDER_REVERSE );
00438 return 1;
00439
00440
00441 case 'v':
00442 switch( p_sys->i_current_view )
00443 {
00444 case VIEW_CATEGORY:
00445 p_sys->i_current_view = VIEW_ALL;
00446 break;
00447 default:
00448 p_sys->i_current_view = VIEW_CATEGORY;
00449 }
00450 PlaylistRebuild( p_intf );
00451 FindIndex( p_intf );
00452 return 1;
00453
00454
00455 case KEY_HOME:
00456 p_sys->i_box_plidx = 0;
00457 break;
00458 case KEY_END:
00459 p_sys->i_box_plidx = p_sys->p_playlist->i_size - 1;
00460 break;
00461 case KEY_UP:
00462 p_sys->i_box_plidx--;
00463 break;
00464 case KEY_DOWN:
00465 p_sys->i_box_plidx++;
00466 break;
00467 case KEY_PPAGE:
00468 p_sys->i_box_plidx -= p_sys->i_box_lines;
00469 break;
00470 case KEY_NPAGE:
00471 p_sys->i_box_plidx += p_sys->i_box_lines;
00472 break;
00473 case 'D':
00474 case KEY_BACKSPACE:
00475 case KEY_DC:
00476 {
00477 int i_item = p_sys->p_playlist->i_index;
00478
00479 playlist_LockDelete( p_sys->p_playlist, p_sys->i_box_plidx );
00480 if( i_item < p_sys->p_playlist->i_size &&
00481 i_item != p_sys->p_playlist->i_index )
00482 {
00483 playlist_Goto( p_sys->p_playlist, i_item );
00484 }
00485 break;
00486 }
00487
00488 case KEY_ENTER:
00489 case 0x0d:
00490 if( p_sys->i_current_view == VIEW_ALL )
00491 {
00492 playlist_Goto( p_sys->p_playlist, p_sys->i_box_plidx );
00493 }
00494 else
00495 {
00496 if( p_sys->pp_plist[p_sys->i_box_plidx]->p_item->i_children
00497 == -1 )
00498 {
00499 playlist_Control( p_sys->p_playlist, PLAYLIST_ITEMPLAY,
00500 p_sys->pp_plist[p_sys->i_box_plidx]->p_item );
00501 }
00502 else
00503 {
00504 playlist_Control( p_sys->p_playlist, PLAYLIST_VIEWPLAY,
00505 p_sys->i_current_view,
00506 p_sys->pp_plist[p_sys->i_box_plidx]->p_item,
00507 NULL );
00508 }
00509 }
00510 p_sys->b_box_plidx_follow = VLC_TRUE;
00511 break;
00512 default:
00513 b_ret = VLC_FALSE;
00514 break;
00515 }
00516
00517 if( b_ret )
00518 {
00519 int i_max = p_sys->i_plist_entries;
00520 if( p_sys->i_current_view == VIEW_ALL )
00521 i_max = p_sys->p_playlist->i_size;
00522 if( p_sys->i_box_plidx >= i_max ) p_sys->i_box_plidx = i_max - 1;
00523 if( p_sys->i_box_plidx < 0 ) p_sys->i_box_plidx = 0;
00524 if( p_sys->i_current_view == VIEW_ALL )
00525 {
00526 if( p_sys->i_box_plidx == p_sys->p_playlist->i_index )
00527 p_sys->b_box_plidx_follow = VLC_TRUE;
00528 else
00529 p_sys->b_box_plidx_follow = VLC_FALSE;
00530 }
00531 else
00532 {
00533 if( p_sys->pp_plist[p_sys->i_box_plidx]->p_item ==
00534 p_sys->p_playlist->status.p_item )
00535 p_sys->b_box_plidx_follow = VLC_TRUE;
00536 else
00537 p_sys->b_box_plidx_follow = VLC_FALSE;
00538 }
00539 return 1;
00540 }
00541 }
00542 if( p_sys->i_box_type == BOX_BROWSE )
00543 {
00544 vlc_bool_t b_ret = VLC_TRUE;
00545
00546 switch( i_key )
00547 {
00548 case KEY_HOME:
00549 p_sys->i_box_bidx = 0;
00550 break;
00551 case KEY_END:
00552 p_sys->i_box_bidx = p_sys->i_dir_entries - 1;
00553 break;
00554 case KEY_UP:
00555 p_sys->i_box_bidx--;
00556 break;
00557 case KEY_DOWN:
00558 p_sys->i_box_bidx++;
00559 break;
00560 case KEY_PPAGE:
00561 p_sys->i_box_bidx -= p_sys->i_box_lines;
00562 break;
00563 case KEY_NPAGE:
00564 p_sys->i_box_bidx += p_sys->i_box_lines;
00565 break;
00566 case '.':
00567 p_sys->b_show_hidden_files = ( p_sys->b_show_hidden_files ==
00568 VLC_TRUE ? VLC_FALSE : VLC_TRUE );
00569 ReadDir( p_intf );
00570 break;
00571
00572 case KEY_ENTER:
00573 case 0x0d:
00574 case ' ':
00575 if( p_sys->pp_dir_entries[p_sys->i_box_bidx]->b_file || i_key == ' ' )
00576 {
00577 int i_size_entry = strlen( p_sys->psz_current_dir ) +
00578 strlen( p_sys->pp_dir_entries[p_sys->i_box_bidx]->psz_path ) + 2;
00579 char *psz_uri = (char *)malloc( sizeof(char)*i_size_entry);
00580
00581 sprintf( psz_uri, "%s/%s", p_sys->psz_current_dir, p_sys->pp_dir_entries[p_sys->i_box_bidx]->psz_path );
00582 playlist_Add( p_sys->p_playlist, psz_uri,
00583 psz_uri,
00584 PLAYLIST_APPEND, PLAYLIST_END );
00585 p_sys->i_box_type = BOX_PLAYLIST;
00586 free( psz_uri );
00587 }
00588 else
00589 {
00590 int i_size_entry = strlen( p_sys->psz_current_dir ) +
00591 strlen( p_sys->pp_dir_entries[p_sys->i_box_bidx]->psz_path ) + 2;
00592 char *psz_uri = (char *)malloc( sizeof(char)*i_size_entry);
00593
00594 sprintf( psz_uri, "%s/%s", p_sys->psz_current_dir, p_sys->pp_dir_entries[p_sys->i_box_bidx]->psz_path );
00595
00596 p_sys->psz_current_dir = strdup( psz_uri );
00597 ReadDir( p_intf );
00598 free( psz_uri );
00599 }
00600 break;
00601 default:
00602 b_ret = VLC_FALSE;
00603 break;
00604 }
00605 if( b_ret )
00606 {
00607 if( p_sys->i_box_bidx >= p_sys->i_dir_entries ) p_sys->i_box_bidx = p_sys->i_dir_entries - 1;
00608 if( p_sys->i_box_bidx < 0 ) p_sys->i_box_bidx = 0;
00609 return 1;
00610 }
00611 }
00612 else if( p_sys->i_box_type == BOX_HELP || p_sys->i_box_type == BOX_INFO )
00613 {
00614 switch( i_key )
00615 {
00616 case KEY_HOME:
00617 p_sys->i_box_start = 0;
00618 return 1;
00619 case KEY_END:
00620 p_sys->i_box_start = p_sys->i_box_lines_total - 1;
00621 return 1;
00622 case KEY_UP:
00623 if( p_sys->i_box_start > 0 ) p_sys->i_box_start--;
00624 return 1;
00625 case KEY_DOWN:
00626 if( p_sys->i_box_start < p_sys->i_box_lines_total - 1 )
00627 {
00628 p_sys->i_box_start++;
00629 }
00630 return 1;
00631 case KEY_PPAGE:
00632 p_sys->i_box_start -= p_sys->i_box_lines;
00633 if( p_sys->i_box_start < 0 ) p_sys->i_box_start = 0;
00634 return 1;
00635 case KEY_NPAGE:
00636 p_sys->i_box_start += p_sys->i_box_lines;
00637 if( p_sys->i_box_start >= p_sys->i_box_lines_total )
00638 {
00639 p_sys->i_box_start = p_sys->i_box_lines_total - 1;
00640 }
00641 return 1;
00642 default:
00643 break;
00644 }
00645 }
00646 else if( p_sys->i_box_type == BOX_NONE )
00647 {
00648 switch( i_key )
00649 {
00650 case KEY_HOME:
00651 p_sys->f_slider = 0;
00652 ManageSlider( p_intf );
00653 return 1;
00654 case KEY_END:
00655 p_sys->f_slider = 99.9;
00656 ManageSlider( p_intf );
00657 return 1;
00658 case KEY_UP:
00659 p_sys->f_slider += 5.0;
00660 if( p_sys->f_slider >= 99.0 ) p_sys->f_slider = 99.0;
00661 ManageSlider( p_intf );
00662 return 1;
00663 case KEY_DOWN:
00664 p_sys->f_slider -= 5.0;
00665 if( p_sys->f_slider < 0.0 ) p_sys->f_slider = 0.0;
00666 ManageSlider( p_intf );
00667 return 1;
00668
00669 default:
00670 break;
00671 }
00672 }
00673 else if( p_sys->i_box_type == BOX_SEARCH && p_sys->psz_search_chain )
00674 {
00675 int i_chain_len;
00676 i_chain_len = strlen( p_sys->psz_search_chain );
00677 switch( i_key )
00678 {
00679 case 0x0c:
00680 clear();
00681 return 1;
00682 case KEY_ENTER:
00683 case 0x0d:
00684 if( i_chain_len > 0 )
00685 {
00686 p_sys->psz_old_search = strdup( p_sys->psz_search_chain );
00687 }
00688 else if( p_sys->psz_old_search )
00689 {
00690 SearchPlaylist( p_intf, p_sys->psz_old_search );
00691 }
00692 p_sys->i_box_type = BOX_PLAYLIST;
00693 return 1;
00694 case 0x1b:
00695 p_sys->i_box_plidx = p_sys->i_before_search;
00696 p_sys->i_box_type = BOX_PLAYLIST;
00697 return 1;
00698 case KEY_BACKSPACE:
00699 if( i_chain_len > 0 )
00700 {
00701 p_sys->psz_search_chain[ i_chain_len - 1 ] = '\0';
00702 }
00703 break;
00704 default:
00705 if( i_chain_len < SEARCH_CHAIN_SIZE )
00706 {
00707 p_sys->psz_search_chain[ i_chain_len++ ] = i_key;
00708 p_sys->psz_search_chain[ i_chain_len ] = 0;
00709 }
00710 break;
00711 }
00712 if( p_sys->psz_old_search )
00713 {
00714 free( p_sys->psz_old_search );
00715 p_sys->psz_old_search = NULL;
00716 }
00717 SearchPlaylist( p_intf, p_sys->psz_search_chain );
00718 return 1;
00719 }
00720 else if( p_sys->i_box_type == BOX_OPEN && p_sys->psz_open_chain )
00721 {
00722 int i_chain_len = strlen( p_sys->psz_open_chain );
00723 playlist_t *p_playlist = p_sys->p_playlist;
00724
00725 switch( i_key )
00726 {
00727 case 0x0c:
00728 clear();
00729 return 1;
00730 case KEY_ENTER:
00731 case 0x0d:
00732 if( p_playlist && i_chain_len > 0 )
00733 {
00734 playlist_Add( p_playlist, p_sys->psz_open_chain,
00735 p_sys->psz_open_chain,
00736 PLAYLIST_GO|PLAYLIST_APPEND, PLAYLIST_END );
00737 p_sys->b_box_plidx_follow = VLC_TRUE;
00738 }
00739 p_sys->i_box_type = BOX_PLAYLIST;
00740 return 1;
00741 case 0x1b:
00742 p_sys->i_box_type = BOX_PLAYLIST;
00743 return 1;
00744 case KEY_BACKSPACE:
00745 if( i_chain_len > 0 )
00746 {
00747 p_sys->psz_open_chain[ i_chain_len - 1 ] = '\0';
00748 }
00749 break;
00750 default:
00751 if( i_chain_len < OPEN_CHAIN_SIZE )
00752 {
00753 p_sys->psz_open_chain[ i_chain_len++ ] = i_key;
00754 p_sys->psz_open_chain[ i_chain_len ] = 0;
00755 }
00756 break;
00757 }
00758 return 1;
00759 }
00760
00761
00762
00763 switch( i_key )
00764 {
00765 case 'q':
00766 case 'Q':
00767 case 0x1b:
00768 p_intf->p_vlc->b_die = VLC_TRUE;
00769 return 0;
00770
00771
00772 case 'i':
00773 if( p_sys->i_box_type == BOX_INFO )
00774 p_sys->i_box_type = BOX_NONE;
00775 else
00776 p_sys->i_box_type = BOX_INFO;
00777 p_sys->i_box_lines_total = 0;
00778 return 1;
00779 case 'L':
00780 if( p_sys->i_box_type == BOX_LOG )
00781 p_sys->i_box_type = BOX_NONE;
00782 else
00783 p_sys->i_box_type = BOX_LOG;
00784 return 1;
00785 case 'P':
00786 if( p_sys->i_box_type == BOX_PLAYLIST )
00787 p_sys->i_box_type = BOX_NONE;
00788 else
00789 p_sys->i_box_type = BOX_PLAYLIST;
00790 return 1;
00791 case 'B':
00792 if( p_sys->i_box_type == BOX_BROWSE )
00793 p_sys->i_box_type = BOX_NONE;
00794 else
00795 p_sys->i_box_type = BOX_BROWSE;
00796 return 1;
00797 case 'h':
00798 case 'H':
00799 if( p_sys->i_box_type == BOX_HELP )
00800 p_sys->i_box_type = BOX_NONE;
00801 else
00802 p_sys->i_box_type = BOX_HELP;
00803 p_sys->i_box_lines_total = 0;
00804 return 1;
00805 case '/':
00806 if( p_sys->i_box_type != BOX_SEARCH )
00807 {
00808 if( p_sys->psz_search_chain == NULL )
00809 {
00810 return 1;
00811 }
00812 p_sys->psz_search_chain[0] = '\0';
00813 p_sys->b_box_plidx_follow = VLC_FALSE;
00814 p_sys->i_before_search = p_sys->i_box_plidx;
00815 p_sys->i_box_type = BOX_SEARCH;
00816 }
00817 return 1;
00818 case 'A':
00819 if( p_sys->i_box_type != BOX_OPEN )
00820 {
00821 if( p_sys->psz_open_chain == NULL )
00822 {
00823 return 1;
00824 }
00825 p_sys->psz_open_chain[0] = '\0';
00826 p_sys->i_box_type = BOX_OPEN;
00827 }
00828 return 1;
00829
00830
00831 case KEY_RIGHT:
00832 p_sys->f_slider += 1.0;
00833 if( p_sys->f_slider > 99.9 ) p_sys->f_slider = 99.9;
00834 ManageSlider( p_intf );
00835 return 1;
00836
00837 case KEY_LEFT:
00838 p_sys->f_slider -= 1.0;
00839 if( p_sys->f_slider < 0.0 ) p_sys->f_slider = 0.0;
00840 ManageSlider( p_intf );
00841 return 1;
00842
00843
00844 case 'f':
00845 {
00846 if( p_intf->p_sys->p_input )
00847 {
00848 vout_thread_t *p_vout;
00849 p_vout = vlc_object_find( p_intf->p_sys->p_input,
00850 VLC_OBJECT_VOUT, FIND_CHILD );
00851 if( p_vout )
00852 {
00853 var_Get( p_vout, "fullscreen", &val );
00854 val.b_bool = !val.b_bool;
00855 var_Set( p_vout, "fullscreen", val );
00856 vlc_object_release( p_vout );
00857 }
00858 else
00859 {
00860 playlist_t *p_playlist;
00861 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
00862 FIND_ANYWHERE );
00863 if( p_playlist )
00864 {
00865 var_Get( p_playlist, "fullscreen", &val );
00866 val.b_bool = !val.b_bool;
00867 var_Set( p_playlist, "fullscreen", val );
00868 vlc_object_release( p_playlist );
00869 }
00870 }
00871 }
00872 return 0;
00873 }
00874
00875 case ' ':
00876 PlayPause( p_intf );
00877 return 1;
00878
00879 case 's':
00880 if( p_intf->p_sys->p_playlist )
00881 {
00882 playlist_Stop( p_intf->p_sys->p_playlist );
00883 }
00884 return 1;
00885
00886 case 'e':
00887 Eject( p_intf );
00888 return 1;
00889
00890 case '[':
00891 if( p_sys->p_input )
00892 {
00893 val.b_bool = VLC_TRUE;
00894 var_Set( p_sys->p_input, "prev-title", val );
00895 }
00896 return 1;
00897
00898 case ']':
00899 if( p_sys->p_input )
00900 {
00901 val.b_bool = VLC_TRUE;
00902 var_Set( p_sys->p_input, "next-title", val );
00903 }
00904 return 1;
00905
00906 case '<':
00907 if( p_sys->p_input )
00908 {
00909 val.b_bool = VLC_TRUE;
00910 var_Set( p_sys->p_input, "prev-chapter", val );
00911 }
00912 return 1;
00913
00914 case '>':
00915 if( p_sys->p_input )
00916 {
00917 val.b_bool = VLC_TRUE;
00918 var_Set( p_sys->p_input, "next-chapter", val );
00919 }
00920 return 1;
00921
00922 case 'p':
00923 if( p_intf->p_sys->p_playlist )
00924 {
00925 playlist_Prev( p_intf->p_sys->p_playlist );
00926 }
00927 clear();
00928 return 1;
00929
00930 case 'n':
00931 if( p_intf->p_sys->p_playlist )
00932 {
00933 playlist_Next( p_intf->p_sys->p_playlist );
00934 }
00935 clear();
00936 return 1;
00937
00938 case 'a':
00939 aout_VolumeUp( p_intf, 1, NULL );
00940 clear();
00941 return 1;
00942
00943 case 'z':
00944 aout_VolumeDown( p_intf, 1, NULL );
00945 clear();
00946 return 1;
00947
00948
00949
00950
00951 case 0x0c:
00952 clear();
00953 return 1;
00954
00955 default:
00956 return 0;
00957 }
00958 }
00959
00960 static void ManageSlider( intf_thread_t *p_intf )
00961 {
00962 intf_sys_t *p_sys = p_intf->p_sys;
00963 input_thread_t *p_input = p_sys->p_input;
00964 vlc_value_t val;
00965
00966 if( p_input == NULL )
00967 {
00968 return;
00969 }
00970 var_Get( p_input, "state", &val );
00971 if( val.i_int != PLAYING_S )
00972 {
00973 return;
00974 }
00975
00976 var_Get( p_input, "position", &val );
00977 if( p_sys->f_slider == p_sys->f_slider_old )
00978 {
00979 p_sys->f_slider =
00980 p_sys->f_slider_old = 100 * val.f_float;
00981 }
00982 else
00983 {
00984 p_sys->f_slider_old = p_sys->f_slider;
00985
00986 val.f_float = p_sys->f_slider / 100.0;
00987 var_Set( p_input, "position", val );
00988 }
00989 }
00990
00991 static void SearchPlaylist( intf_thread_t *p_intf, char *psz_searchstring )
00992 {
00993 int i_max;
00994 int i_first = 0 ;
00995 int i_item = -1;
00996 intf_sys_t *p_sys = p_intf->p_sys;
00997 playlist_t *p_playlist = p_sys->p_playlist;
00998
00999 if( p_sys->i_before_search >= 0 )
01000 {
01001 i_first = p_sys->i_before_search;
01002 }
01003
01004 if( ( ! psz_searchstring ) || strlen( psz_searchstring ) <= 0 )
01005 {
01006 p_sys->i_box_plidx = p_sys->i_before_search;
01007 return;
01008 }
01009
01010 i_max = p_sys->i_current_view == VIEW_ALL ?
01011 p_playlist->i_size : p_sys->i_plist_entries;
01012
01013 i_item = SubSearchPlaylist( p_intf, psz_searchstring, i_first + 1, i_max );
01014 if( i_item < 0 )
01015 {
01016 i_item = SubSearchPlaylist( p_intf, psz_searchstring, 0, i_first );
01017 }
01018
01019 if( i_item < 0 || i_item >= i_max ) return;
01020
01021 p_sys->i_box_plidx = i_item;
01022 }
01023
01024 static int SubSearchPlaylist( intf_thread_t *p_intf, char *psz_searchstring,
01025 int i_start, int i_stop )
01026 {
01027 intf_sys_t *p_sys = p_intf->p_sys;
01028 playlist_t *p_playlist = p_sys->p_playlist;
01029 int i, i_item = -1;
01030
01031 if( p_sys->i_current_view == VIEW_ALL )
01032 {
01033 for( i = i_start + 1; i < i_stop; i++ )
01034 {
01035 if( strcasestr( p_playlist->pp_items[i]->input.psz_name,
01036 psz_searchstring ) != NULL
01037 || strcasestr( p_playlist->pp_items[i]->input.psz_uri,
01038 psz_searchstring ) != NULL )
01039 {
01040 i_item = i;
01041 break;
01042 }
01043 }
01044 }
01045 else
01046 {
01047 for( i = i_start + 1; i < i_stop; i++ )
01048 {
01049 if( strcasestr( p_sys->pp_plist[i]->psz_display,
01050 psz_searchstring ) != NULL )
01051 {
01052 i_item = i;
01053 break;
01054 }
01055 }
01056 }
01057
01058 return i_item;
01059 }
01060
01061
01062 static void mvnprintw( int y, int x, int w, const char *p_fmt, ... )
01063 {
01064 va_list vl_args;
01065 char *p_buf = NULL;
01066 int i_len;
01067
01068 va_start( vl_args, p_fmt );
01069 vasprintf( &p_buf, p_fmt, vl_args );
01070 va_end( vl_args );
01071
01072 if( p_buf == NULL )
01073 {
01074 return;
01075 }
01076 if( w > 0 )
01077 {
01078 if( ( i_len = strlen( p_buf ) ) > w )
01079 {
01080 int i_cut = i_len - w;
01081 int x1 = i_len/2 - i_cut/2;
01082 int x2 = x1 + i_cut;
01083
01084 if( i_len > x2 )
01085 {
01086 memmove( &p_buf[x1], &p_buf[x2], i_len - x2 );
01087 }
01088 p_buf[w] = '\0';
01089 if( w > 7 )
01090 {
01091 p_buf[w/2-1] = '.';
01092 p_buf[w/2 ] = '.';
01093 p_buf[w/2+1] = '.';
01094 }
01095 mvprintw( y, x, "%s", p_buf );
01096 }
01097 else
01098 {
01099 mvprintw( y, x, "%s", p_buf );
01100 mvhline( y, x + i_len, ' ', w - i_len );
01101 }
01102 }
01103 }
01104 static void MainBoxWrite( intf_thread_t *p_intf, int l, int x, const char *p_fmt, ... )
01105 {
01106 intf_sys_t *p_sys = p_intf->p_sys;
01107
01108 va_list vl_args;
01109 char *p_buf = NULL;
01110
01111 if( l < p_sys->i_box_start || l - p_sys->i_box_start >= p_sys->i_box_lines )
01112 {
01113 return;
01114 }
01115
01116 va_start( vl_args, p_fmt );
01117 vasprintf( &p_buf, p_fmt, vl_args );
01118 va_end( vl_args );
01119
01120 if( p_buf == NULL )
01121 {
01122 return;
01123 }
01124
01125 mvnprintw( p_sys->i_box_y + l - p_sys->i_box_start, x, COLS - x - 1, "%s", p_buf );
01126 }
01127
01128 static void Redraw( intf_thread_t *p_intf, time_t *t_last_refresh )
01129 {
01130 intf_sys_t *p_sys = p_intf->p_sys;
01131 input_thread_t *p_input = p_sys->p_input;
01132 int y = 0;
01133 int h;
01134 int y_end;
01135
01136
01137
01138
01139 attrset( A_REVERSE );
01140 mvnprintw( y, 0, COLS, "VLC media player" " (ncurses interface) [ h for help ]" );
01141 attroff( A_REVERSE );
01142 y += 2;
01143
01144
01145 if( p_input && !p_input->b_dead )
01146 {
01147 char buf1[MSTRTIME_MAX_SIZE];
01148 char buf2[MSTRTIME_MAX_SIZE];
01149 vlc_value_t val;
01150 vlc_value_t val_list;
01151
01152
01153 mvnprintw( y++, 0, COLS, " Source : %s",
01154 p_input->input.p_item->psz_uri );
01155
01156
01157 var_Get( p_input, "state", &val );
01158 if( val.i_int == PLAYING_S )
01159 {
01160 mvnprintw( y++, 0, COLS, " State : Playing" );
01161 }
01162 else if( val.i_int == PAUSE_S )
01163 {
01164 mvnprintw( y++, 0, COLS, " State : Paused" );
01165 }
01166 else
01167 {
01168 y++;
01169 }
01170 if( val.i_int != INIT_S && val.i_int != END_S )
01171 {
01172 audio_volume_t i_volume;
01173
01174
01175 var_Get( p_input, "time", &val );
01176 msecstotimestr( buf1, val.i_time / 1000 );
01177
01178 var_Get( p_input, "length", &val );
01179 msecstotimestr( buf2, val.i_time / 1000 );
01180
01181 mvnprintw( y++, 0, COLS, " Position : %s/%s (%.2f%%)", buf1, buf2, p_sys->f_slider );
01182
01183
01184 aout_VolumeGet( p_intf, &i_volume );
01185 mvnprintw( y++, 0, COLS, " Volume : %i%%", i_volume*200/AOUT_VOLUME_MAX );
01186
01187
01188 if( !var_Get( p_input, "title", &val ) )
01189 {
01190 var_Change( p_input, "title", VLC_VAR_GETCHOICES, &val_list, NULL );
01191 if( val_list.p_list->i_count > 0 )
01192 {
01193 mvnprintw( y++, 0, COLS, " Title : %d/%d", val.i_int, val_list.p_list->i_count );
01194 }
01195 var_Change( p_input, "title", VLC_VAR_FREELIST, &val_list, NULL );
01196 }
01197
01198
01199 if( !var_Get( p_input, "chapter", &val ) )
01200 {
01201 var_Change( p_input, "chapter", VLC_VAR_GETCHOICES, &val_list, NULL );
01202 if( val_list.p_list->i_count > 0 )
01203 {
01204 mvnprintw( y++, 0, COLS, " Chapter : %d/%d", val.i_int, val_list.p_list->i_count );
01205 }
01206 var_Change( p_input, "chapter", VLC_VAR_FREELIST, &val_list, NULL );
01207 }
01208 }
01209 else
01210 {
01211 y += 2;
01212 }
01213 }
01214 else
01215 {
01216 mvnprintw( y++, 0, COLS, "Source: <no current item>" );
01217 DrawEmptyLine( p_sys->w, y++, 0, COLS );
01218 DrawEmptyLine( p_sys->w, y++, 0, COLS );
01219 DrawEmptyLine( p_sys->w, y++, 0, COLS );
01220 }
01221
01222 DrawBox( p_sys->w, y, 0, 3, COLS, "" );
01223 DrawEmptyLine( p_sys->w, y+1, 1, COLS-2);
01224 DrawLine( p_sys->w, y+1, 1, (int)(p_intf->p_sys->f_slider/100.0 * (COLS -2)) );
01225 y += 3;
01226
01227 p_sys->i_box_y = y + 1;
01228 p_sys->i_box_lines = LINES - y - 2;
01229
01230 h = LINES - y;
01231 y_end = y + h - 1;
01232
01233 if( p_sys->i_box_type == BOX_HELP )
01234 {
01235
01236 int l = 0;
01237 DrawBox( p_sys->w, y++, 0, h, COLS, " Help " );
01238
01239 MainBoxWrite( p_intf, l++, 1, "[Display]" );
01240 MainBoxWrite( p_intf, l++, 1, " h,H Show/Hide help box" );
01241 MainBoxWrite( p_intf, l++, 1, " i Show/Hide info box" );
01242 MainBoxWrite( p_intf, l++, 1, " L Show/Hide messages box" );
01243 MainBoxWrite( p_intf, l++, 1, " P Show/Hide playlist box" );
01244 MainBoxWrite( p_intf, l++, 1, " B Show/Hide filebrowser" );
01245 MainBoxWrite( p_intf, l++, 1, "" );
01246
01247 MainBoxWrite( p_intf, l++, 1, "[Global]" );
01248 MainBoxWrite( p_intf, l++, 1, " q, Q Quit" );
01249 MainBoxWrite( p_intf, l++, 1, " s Stop" );
01250 MainBoxWrite( p_intf, l++, 1, " <space> Pause/Play" );
01251 MainBoxWrite( p_intf, l++, 1, " f Toggle Fullscreen" );
01252 MainBoxWrite( p_intf, l++, 1, " n, p Next/Previous playlist item" );
01253 MainBoxWrite( p_intf, l++, 1, " [, ] Next/Previous title" );
01254 MainBoxWrite( p_intf, l++, 1, " <, > Next/Previous chapter" );
01255 MainBoxWrite( p_intf, l++, 1, " <right> Seek +1%%" );
01256 MainBoxWrite( p_intf, l++, 1, " <left> Seek -1%%" );
01257 MainBoxWrite( p_intf, l++, 1, " a Volume Up" );
01258 MainBoxWrite( p_intf, l++, 1, " z Volume Down" );
01259 MainBoxWrite( p_intf, l++, 1, "" );
01260
01261 MainBoxWrite( p_intf, l++, 1, "[Playlist]" );
01262 MainBoxWrite( p_intf, l++, 1, " r Random" );
01263 MainBoxWrite( p_intf, l++, 1, " l Loop Playlist" );
01264 MainBoxWrite( p_intf, l++, 1, " R Repeat item" );
01265 MainBoxWrite( p_intf, l++, 1, " o Order Playlist by title" );
01266 MainBoxWrite( p_intf, l++, 1, " O Reverse order Playlist by title" );
01267 MainBoxWrite( p_intf, l++, 1, " / Look for an item" );
01268 MainBoxWrite( p_intf, l++, 1, " A Add an entry" );
01269 MainBoxWrite( p_intf, l++, 1, " D, <del> Delete an entry" );
01270 MainBoxWrite( p_intf, l++, 1, " <backspace> Delete an entry" );
01271 MainBoxWrite( p_intf, l++, 1, "" );
01272
01273 MainBoxWrite( p_intf, l++, 1, "[Filebrowser]" );
01274 MainBoxWrite( p_intf, l++, 1, " <enter> Add the selected file to the playlist" );
01275 MainBoxWrite( p_intf, l++, 1, " <space> Add the selected directory to the playlist" );
01276 MainBoxWrite( p_intf, l++, 1, " . Show/Hide hidden files" );
01277 MainBoxWrite( p_intf, l++, 1, "" );
01278
01279 MainBoxWrite( p_intf, l++, 1, "[Boxes]" );
01280 MainBoxWrite( p_intf, l++, 1, " <up>,<down> Navigate through the box line by line" );
01281 MainBoxWrite( p_intf, l++, 1, " <pgup>,<pgdown> Navigate through the box page by page" );
01282 MainBoxWrite( p_intf, l++, 1, "" );
01283
01284 MainBoxWrite( p_intf, l++, 1, "[Player]" );
01285 MainBoxWrite( p_intf, l++, 1, " <up>,<down> Seek +/-5%%" );
01286 MainBoxWrite( p_intf, l++, 1, "" );
01287
01288 MainBoxWrite( p_intf, l++, 1, "[Miscellaneous]" );
01289 MainBoxWrite( p_intf, l++, 1, " Ctrl-l Refresh the screen" );
01290
01291 p_sys->i_box_lines_total = l;
01292 if( p_sys->i_box_start >= p_sys->i_box_lines_total )
01293 {
01294 p_sys->i_box_start = p_sys->i_box_lines_total - 1;
01295 }
01296
01297 if( l - p_sys->i_box_start < p_sys->i_box_lines )
01298 {
01299 y += l - p_sys->i_box_start;
01300 }
01301 else
01302 {
01303 y += p_sys->i_box_lines;
01304 }
01305 }
01306 else if( p_sys->i_box_type == BOX_INFO )
01307 {
01308
01309 int l = 0;
01310 DrawBox( p_sys->w, y++, 0, h, COLS, " Information " );
01311
01312 if( p_input )
01313 {
01314 int i,j;
01315 vlc_mutex_lock( &p_input->input.p_item->lock );
01316 for( i = 0; i < p_input->input.p_item->i_categories; i++ )
01317 {
01318 info_category_t *p_category = p_input->input.p_item->pp_categories[i];
01319 if( y >= y_end ) break;
01320 MainBoxWrite( p_intf, l++, 1, " [%s]", p_category->psz_name );
01321 for( j = 0; j < p_category->i_infos; j++ )
01322 {
01323 info_t *p_info = p_category->pp_infos[j];
01324 if( y >= y_end ) break;
01325 MainBoxWrite( p_intf, l++, 1, " %s: %s", p_info->psz_name, p_info->psz_value );
01326 }
01327 }
01328 vlc_mutex_unlock( &p_input->input.p_item->lock );
01329 }
01330 else
01331 {
01332 MainBoxWrite( p_intf, l++, 1, "No item currently playing" );
01333 }
01334 p_sys->i_box_lines_total = l;
01335 if( p_sys->i_box_start >= p_sys->i_box_lines_total )
01336 {
01337 p_sys->i_box_start = p_sys->i_box_lines_total - 1;
01338 }
01339
01340 if( l - p_sys->i_box_start < p_sys->i_box_lines )
01341 {
01342 y += l - p_sys->i_box_start;
01343 }
01344 else
01345 {
01346 y += p_sys->i_box_lines;
01347 }
01348 }
01349 else if( p_sys->i_box_type == BOX_LOG )
01350 {
01351 int i_line = 0;
01352 int i_stop;
01353 int i_start;
01354
01355 DrawBox( p_sys->w, y++, 0, h, COLS, " Logs " );
01356
01357 i_start = p_intf->p_sys->p_sub->i_start;
01358
01359 vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock );
01360 i_stop = *p_intf->p_sys->p_sub->pi_stop;
01361 vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock );
01362
01363 for( ;; )
01364 {
01365 static const char *ppsz_type[4] = { "", "error", "warning", "debug" };
01366 if( i_line >= h - 2 )
01367 {
01368 break;
01369 }
01370 i_stop--;
01371 i_line++;
01372 if( i_stop < 0 ) i_stop += VLC_MSG_QSIZE;
01373 if( i_stop == i_start )
01374 {
01375 break;
01376 }
01377 mvnprintw( y + h-2-i_line, 1, COLS - 2, " [%s] %s",
01378 ppsz_type[p_sys->p_sub->p_msg[i_stop].i_type],
01379 p_sys->p_sub->p_msg[i_stop].psz_msg );
01380 }
01381
01382 vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock );
01383 p_intf->p_sys->p_sub->i_start = i_stop;
01384 vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock );
01385 y = y_end;
01386 }
01387 else if( p_sys->i_box_type == BOX_BROWSE )
01388 {
01389
01390 int i_start, i_stop;
01391 int i_item;
01392 DrawBox( p_sys->w, y++, 0, h, COLS, " Browse " );
01393
01394 if( p_sys->i_box_bidx >= p_sys->i_dir_entries ) p_sys->i_box_plidx = p_sys->i_dir_entries - 1;
01395 if( p_sys->i_box_bidx < 0 ) p_sys->i_box_bidx = 0;
01396
01397 if( p_sys->i_box_bidx < (h - 2)/2 )
01398 {
01399 i_start = 0;
01400 i_stop = h - 2;
01401 }
01402 else if( p_sys->i_dir_entries - p_sys->i_box_bidx > (h - 2)/2 )
01403 {
01404 i_start = p_sys->i_box_bidx - (h - 2)/2;
01405 i_stop = i_start + h - 2;
01406 }
01407 else
01408 {
01409 i_stop = p_sys->i_dir_entries;
01410 i_start = p_sys->i_dir_entries - (h - 2);
01411 }
01412 if( i_start < 0 )
01413 {
01414 i_start = 0;
01415 }
01416 if( i_stop > p_sys->i_dir_entries )
01417 {
01418 i_stop = p_sys->i_dir_entries;
01419 }
01420
01421 for( i_item = i_start; i_item < i_stop; i_item++ )
01422 {
01423 vlc_bool_t b_selected = ( p_sys->i_box_bidx == i_item );
01424
01425 if( y >= y_end ) break;
01426 if( b_selected )
01427 {
01428 attrset( A_REVERSE );
01429 }
01430 mvnprintw( y++, 1, COLS - 2, " %c %s", p_sys->pp_dir_entries[i_item]->b_file == VLC_TRUE ? ' ' : '+',
01431 p_sys->pp_dir_entries[i_item]->psz_path );
01432 if( b_selected )
01433 {
01434 attroff( A_REVERSE );
01435 }
01436 }
01437
01438 }
01439 else if( ( p_sys->i_box_type == BOX_PLAYLIST ||
01440 p_sys->i_box_type == BOX_SEARCH ||
01441 p_sys->i_box_type == BOX_OPEN ) && p_sys->p_playlist )
01442 {
01443
01444 playlist_t *p_playlist = p_sys->p_playlist;
01445 int i_start, i_stop, i_max = p_sys->i_plist_entries;
01446 int i_item;
01447 char *psz_title;
01448
01449 switch( p_sys->i_current_view )
01450 {
01451 case VIEW_ALL:
01452 psz_title = strdup( " Playlist (All, unsorted) " );
01453 i_max = p_playlist->i_size;
01454 break;
01455 case VIEW_CATEGORY:
01456 psz_title = strdup( " Playlist (By category) " );
01457 break;
01458 default:
01459 psz_title = strdup( " Playlist (Manually added) " );
01460 }
01461
01462 DrawBox( p_sys->w, y++, 0, h, COLS, psz_title );
01463
01464 if( p_sys->i_current_view != VIEW_ALL &&
01465 ( p_sys->b_need_update || p_sys->pp_plist == NULL ) )
01466 {
01467 PlaylistRebuild( p_intf );
01468 }
01469 if( p_sys->b_box_plidx_follow )
01470 {
01471 FindIndex( p_intf );
01472 }
01473
01474 if( p_sys->i_box_plidx < 0 ) p_sys->i_box_plidx = 0;
01475
01476 if( p_sys->i_box_plidx < (h - 2)/2 )
01477 {
01478 i_start = 0;
01479 i_stop = h - 2;
01480 }
01481 else if( i_max - p_sys->i_box_plidx > (h - 2)/2 )
01482 {
01483 i_start = p_sys->i_box_plidx - (h - 2)/2;
01484 i_stop = i_start + h - 2;
01485 }
01486 else
01487 {
01488 i_stop = i_max;
01489 i_start = i_max - (h - 2);
01490 }
01491 if( i_start < 0 )
01492 {
01493 i_start = 0;
01494 }
01495 if( i_stop > i_max )
01496 {
01497 i_stop = i_max;
01498 }
01499
01500 if( p_sys->i_current_view == VIEW_ALL )
01501 {
01502
01503 for( i_item = i_start; i_item < i_stop; i_item++ )
01504 {
01505 vlc_bool_t b_selected = ( p_sys->i_box_plidx == i_item );
01506 int c = p_playlist->i_index == i_item ? '>' : ' ';
01507
01508 if( y >= y_end ) break;
01509 if( b_selected )
01510 {
01511 attrset( A_REVERSE );
01512 }
01513 if( !strcmp( p_playlist->pp_items[i_item]->input.psz_name,
01514 p_playlist->pp_items[i_item]->input.psz_uri ) )
01515 {
01516 mvnprintw( y++, 1, COLS - 2, "%c %d - '%s'",
01517 c,
01518 i_item,
01519 p_playlist->pp_items[i_item]->input.psz_uri );
01520 }
01521 else
01522 {
01523 mvnprintw( y++, 1, COLS - 2, "%c %d - '%s' (%s)",
01524 c,
01525 i_item,
01526 p_playlist->pp_items[i_item]->input.psz_uri,
01527 p_playlist->pp_items[i_item]->input.psz_name );
01528 }
01529 if( b_selected )
01530 {
01531 attroff( A_REVERSE );
01532 }
01533 }
01534
01535 }
01536 else
01537 {
01538
01539 for( i_item = i_start; i_item < i_stop; i_item++ )
01540 {
01541 vlc_bool_t b_selected = ( p_sys->i_box_plidx == i_item );
01542 int c = ( p_playlist->status.p_item ==
01543 p_sys->pp_plist[i_item]->p_item ) ? '>' : ' ';
01544
01545 if( y >= y_end ) break;
01546 if( b_selected )
01547 {
01548 attrset( A_REVERSE );
01549 }
01550 mvnprintw( y++, 1, COLS - 2, "%c%s", c,
01551 p_sys->pp_plist[i_item]->psz_display );
01552 if( b_selected )
01553 {
01554 attroff( A_REVERSE );
01555 }
01556 }
01557
01558 }
01559 }
01560 else
01561 {
01562 y++;
01563 }
01564 if( p_sys->i_box_type == BOX_SEARCH )
01565 {
01566 DrawEmptyLine( p_sys->w, 7, 1, COLS-2 );
01567 if( p_sys->psz_search_chain )
01568 {
01569 if( strlen( p_sys->psz_search_chain ) == 0 &&
01570 p_sys->psz_old_search != NULL )
01571 {
01572
01573 mvnprintw( 7, 1, COLS-2, "Find: %s", p_sys->psz_old_search );
01574 }
01575 else
01576 {
01577 mvnprintw( 7, 1, COLS-2, "Find: %s", p_sys->psz_search_chain );
01578 }
01579 }
01580 }
01581 if( p_sys->i_box_type == BOX_OPEN )
01582 {
01583 if( p_sys->psz_open_chain )
01584 {
01585 DrawEmptyLine( p_sys->w, 7, 1, COLS-2 );
01586 mvnprintw( 7, 1, COLS-2, "Open: %s", p_sys->psz_open_chain );
01587 }
01588 }
01589
01590 while( y < y_end )
01591 {
01592 DrawEmptyLine( p_sys->w, y++, 1, COLS - 2 );
01593 }
01594
01595 refresh();
01596
01597 *t_last_refresh = time( 0 );
01598 }
01599
01600 static void PlaylistRebuild( intf_thread_t *p_intf )
01601 {
01602 intf_sys_t *p_sys = p_intf->p_sys;
01603 playlist_view_t *p_view;
01604 playlist_t *p_playlist = p_sys->p_playlist;
01605
01606 if( p_playlist == NULL )
01607 {
01608 return;
01609 }
01610
01611 vlc_mutex_lock( &p_playlist->object_lock );
01612
01613 p_view = playlist_ViewFind( p_playlist, p_intf->p_sys->i_current_view );
01614
01615
01616 PlaylistDestroy( p_intf );
01617
01618
01619 PlaylistAddNode( p_intf, p_view->p_root, 0, "" );
01620
01621 p_sys->b_need_update = VLC_FALSE;
01622
01623 vlc_mutex_unlock( &p_playlist->object_lock );
01624 }
01625
01626 static void PlaylistAddNode( intf_thread_t *p_intf, playlist_item_t *p_node,
01627 int i, char *c )
01628 {
01629 intf_sys_t *p_sys = p_intf->p_sys;
01630 playlist_item_t *p_child;
01631 char *psz_tmp;
01632 int k;
01633
01634 psz_tmp = (char *)malloc( strlen( c ) + 4 );
01635 if( psz_tmp == NULL ) return;
01636 for( k = 0; k < p_node->i_children; k++ )
01637 {
01638 struct pl_item_t *p_pl_item;
01639 char *buff;
01640 int i_size;
01641
01642 p_child = p_node->pp_children[k];
01643 i_size = strlen( c ) + strlen( p_child->input.psz_name ) + 4;
01644 buff = (char *)malloc( sizeof( char ) * i_size );
01645 p_pl_item = (struct pl_item_t *)malloc( sizeof( struct pl_item_t ) );
01646 if( p_pl_item == NULL || buff == NULL ) return;
01647
01648 if( strlen( c ) )
01649 {
01650 sprintf( buff, "%s%c-%s", c, k == p_node->i_children - 1 ?
01651 '`' : '|', p_child->input.psz_name );
01652 }
01653 else
01654 {
01655 sprintf( buff, " %s", p_child->input.psz_name );
01656 }
01657 p_pl_item->psz_display = strdup( buff );
01658 p_pl_item->p_item = p_child;
01659 INSERT_ELEM( p_sys->pp_plist, p_sys->i_plist_entries,
01660 p_sys->i_plist_entries, p_pl_item );
01661 free( buff );
01662 i++;
01663
01664 if( p_child->i_children > 0 )
01665 {
01666 sprintf( psz_tmp, "%s%c ", c,
01667 k == p_node->i_children - 1 ? ' ' : '|' );
01668 PlaylistAddNode( p_intf, p_child, i,
01669 strlen( c ) ? psz_tmp : " " );
01670 }
01671 }
01672 free( psz_tmp );
01673 }
01674
01675 static int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
01676 vlc_value_t oval, vlc_value_t nval, void *param )
01677 {
01678 intf_thread_t *p_intf = (intf_thread_t *)param;
01679 p_intf->p_sys->b_need_update = VLC_TRUE;
01680 return VLC_SUCCESS;
01681 }
01682
01683 static void FindIndex( intf_thread_t *p_intf )
01684 {
01685 intf_sys_t *p_sys = p_intf->p_sys;
01686 int i;
01687
01688 if( p_sys->i_current_view == VIEW_ALL )
01689 {
01690 p_sys->i_box_plidx = p_sys->p_playlist->i_index;
01691 }
01692 else if( ( p_sys->i_box_plidx < p_sys->i_plist_entries &&
01693 p_sys->pp_plist[p_sys->i_box_plidx]->p_item !=
01694 p_sys->p_playlist->status.p_item ) )
01695 {
01696 for( i = 0; i < p_sys->i_plist_entries; i++ )
01697 {
01698 if( p_sys->pp_plist[i]->p_item ==
01699 p_sys->p_playlist->status.p_item )
01700 {
01701 p_sys->i_box_plidx = i;
01702 break;
01703 }
01704 }
01705 }
01706 }
01707
01708 static void PlaylistDestroy( intf_thread_t *p_intf )
01709 {
01710 intf_sys_t *p_sys = p_intf->p_sys;
01711 int i;
01712
01713 for( i = 0; i < p_sys->i_plist_entries; i++ )
01714 {
01715 struct pl_item_t *p_pl_item = p_sys->pp_plist[i];
01716 free( p_pl_item->psz_display );
01717 REMOVE_ELEM( p_sys->pp_plist, p_sys->i_plist_entries, i );
01718 free( p_pl_item );
01719 }
01720 p_sys->pp_plist = NULL;
01721 p_sys->i_plist_entries = 0;
01722 }
01723
01724 static void Eject( intf_thread_t *p_intf )
01725 {
01726 char *psz_device = NULL, *psz_parser, *psz_name;
01727
01728
01729
01730
01731
01732
01733
01734 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
01735 FIND_ANYWHERE );
01736
01737 if( p_playlist == NULL )
01738 {
01739 return;
01740 }
01741
01742 vlc_mutex_lock( &p_playlist->object_lock );
01743
01744 if( p_playlist->i_index < 0 )
01745 {
01746 vlc_mutex_unlock( &p_playlist->object_lock );
01747 vlc_object_release( p_playlist );
01748 return;
01749 }
01750
01751 psz_name = p_playlist->pp_items[ p_playlist->i_index ]->input.psz_name;
01752
01753 if( psz_name )
01754 {
01755 if( !strncmp(psz_name, "dvd://", 4) )
01756 {
01757 switch( psz_name[strlen("dvd://")] )
01758 {
01759 case '\0':
01760 case '@':
01761 psz_device = config_GetPsz( p_intf, "dvd" );
01762 break;
01763 default:
01764
01765 psz_device = strdup( psz_name + strlen("dvd://" ) );
01766 break;
01767 }
01768 }
01769 else if( !strncmp(psz_name, VCD_MRL, strlen(VCD_MRL)) )
01770 {
01771 switch( psz_name[strlen(VCD_MRL)] )
01772 {
01773 case '\0':
01774 case '@':
01775 psz_device = config_GetPsz( p_intf, VCD_MRL );
01776 break;
01777 default:
01778
01779 psz_device = strdup( psz_name + strlen(VCD_MRL) );
01780 break;
01781 }
01782 }
01783 else if( !strncmp(psz_name, CDDA_MRL, strlen(CDDA_MRL) ) )
01784 {
01785 switch( psz_name[strlen(CDDA_MRL)] )
01786 {
01787 case '\0':
01788 case '@':
01789 psz_device = config_GetPsz( p_intf, "cd-audio" );
01790 break;
01791 default:
01792
01793 psz_device = strdup( psz_name + strlen(CDDA_MRL) );
01794 break;
01795 }
01796 }
01797 else
01798 {
01799 psz_device = strdup( psz_name );
01800 }
01801 }
01802
01803 vlc_mutex_unlock( &p_playlist->object_lock );
01804 vlc_object_release( p_playlist );
01805
01806 if( psz_device == NULL )
01807 {
01808 return;
01809 }
01810
01811
01812 psz_parser = psz_device;
01813 for( psz_parser = psz_device ; *psz_parser ; psz_parser++ )
01814 {
01815 if( *psz_parser == '@' )
01816 {
01817 *psz_parser = '\0';
01818 break;
01819 }
01820 }
01821
01822
01823 if( p_intf->p_sys->p_input == NULL )
01824 {
01825 msg_Dbg( p_intf, "ejecting %s", psz_device );
01826
01827 intf_Eject( p_intf, psz_device );
01828 }
01829
01830 free(psz_device);
01831 return;
01832 }
01833
01834 static int comp_dir_entries( const void *pp_dir_entry1,
01835 const void *pp_dir_entry2 )
01836 {
01837 struct dir_entry_t *p_dir_entry1 = *(struct dir_entry_t**)pp_dir_entry1;
01838 struct dir_entry_t *p_dir_entry2 = *(struct dir_entry_t**)pp_dir_entry2;
01839 if ( p_dir_entry1->b_file == p_dir_entry2->b_file ) {
01840 return strcasecmp( p_dir_entry1->psz_path, p_dir_entry2->psz_path );
01841 }
01842 else
01843 {
01844 return ( p_dir_entry1->b_file ? 1 : -1 );
01845 }
01846 }
01847
01848 static void ReadDir( intf_thread_t *p_intf )
01849 {
01850 intf_sys_t *p_sys = p_intf->p_sys;
01851 DIR * p_current_dir;
01852 struct dirent * p_dir_content;
01853 int i;
01854
01855 if( p_sys->psz_current_dir && *p_sys->psz_current_dir )
01856 {
01857
01858 p_current_dir = opendir( p_sys->psz_current_dir );
01859
01860 if( p_current_dir == NULL )
01861 {
01862
01863 #ifdef HAVE_ERRNO_H
01864 msg_Warn( p_intf, "cannot open directory `%s' (%s)",
01865 p_sys->psz_current_dir, strerror(errno));
01866 #else
01867 msg_Warn( p_intf, "cannot open directory `%s'", p_sys->psz_current_dir );
01868 #endif
01869 return;
01870 }
01871
01872
01873 for( i = 0; i < p_sys->i_dir_entries; i++ )
01874 {
01875 struct dir_entry_t *p_dir_entry = p_sys->pp_dir_entries[i];
01876 free( p_dir_entry->psz_path );
01877 REMOVE_ELEM( p_sys->pp_dir_entries, p_sys->i_dir_entries, i );
01878 free( p_dir_entry );
01879 }
01880 p_sys->pp_dir_entries = NULL;
01881 p_sys->i_dir_entries = 0;
01882
01883
01884 p_dir_content = readdir( p_current_dir );
01885
01886
01887 while( p_dir_content != NULL )
01888 {
01889 #if defined( S_ISDIR )
01890 struct stat stat_data;
01891 #endif
01892 struct dir_entry_t *p_dir_entry;
01893 int i_size_entry = strlen( p_sys->psz_current_dir ) +
01894 strlen( p_dir_content->d_name ) + 2;
01895 char *psz_uri;
01896
01897 if( p_sys->b_show_hidden_files == VLC_FALSE &&
01898 ( strlen( p_dir_content->d_name ) &&
01899 p_dir_content->d_name[0] == '.' ) &&
01900 strcmp( p_dir_content->d_name, ".." ) )
01901 {
01902 p_dir_content = readdir( p_current_dir );
01903 continue;
01904 }
01905
01906 psz_uri = (char *)malloc( sizeof(char)*i_size_entry);
01907 sprintf( psz_uri, "%s/%s", p_sys->psz_current_dir,
01908 p_dir_content->d_name );
01909
01910 if( !( p_dir_entry = malloc( sizeof( struct dir_entry_t) ) ) )
01911 {
01912 free( psz_uri);
01913 return;
01914 }
01915
01916 #if defined( S_ISDIR )
01917 stat( psz_uri, &stat_data );
01918 if( S_ISDIR(stat_data.st_mode) )
01919 #elif defined( DT_DIR )
01920 if( p_dir_content->d_type & DT_DIR )
01921 #else
01922 if( 0 )
01923 #endif
01924 {
01925 p_dir_entry->psz_path = strdup( p_dir_content->d_name );
01926 p_dir_entry->b_file = VLC_FALSE;
01927 INSERT_ELEM( p_sys->pp_dir_entries, p_sys->i_dir_entries,
01928 p_sys->i_dir_entries, p_dir_entry );
01929 }
01930 else
01931 {
01932 p_dir_entry->psz_path = strdup( p_dir_content->d_name );
01933 p_dir_entry->b_file = VLC_TRUE;
01934 INSERT_ELEM( p_sys->pp_dir_entries, p_sys->i_dir_entries,
01935 p_sys->i_dir_entries, p_dir_entry );
01936 }
01937
01938 free( psz_uri );
01939
01940 p_dir_content = readdir( p_current_dir );
01941 }
01942
01943
01944 qsort( p_sys->pp_dir_entries, p_sys->i_dir_entries,
01945 sizeof(struct dir_entry_t*), &comp_dir_entries );
01946
01947 closedir( p_current_dir );
01948 return;
01949 }
01950 else
01951 {
01952 msg_Dbg( p_intf, "no current dir set" );
01953 return;
01954 }
01955 }
01956
01957 static void PlayPause( intf_thread_t *p_intf )
01958 {
01959 input_thread_t *p_input = p_intf->p_sys->p_input;
01960 vlc_value_t val;
01961
01962 if( p_input )
01963 {
01964 var_Get( p_input, "state", &val );
01965 if( val.i_int != PAUSE_S )
01966 {
01967 val.i_int = PAUSE_S;
01968 }
01969 else
01970 {
01971 val.i_int = PLAYING_S;
01972 }
01973 var_Set( p_input, "state", val );
01974 }
01975 else if( p_intf->p_sys->p_playlist )
01976 {
01977 playlist_Play( p_intf->p_sys->p_playlist );
01978 }
01979 }
01980
01981
01982
01983
01984 static void DrawBox( WINDOW *win, int y, int x, int h, int w, char *title )
01985 {
01986 int i;
01987 int i_len;
01988
01989 if( w > 3 && h > 2 )
01990 {
01991 if( title == NULL ) title = "";
01992 i_len = strlen( title );
01993
01994 if( i_len > w - 2 ) i_len = w - 2;
01995
01996 mvwaddch( win, y, x, ACS_ULCORNER );
01997 mvwhline( win, y, x+1, ACS_HLINE, ( w-i_len-2)/2 );
01998 mvwprintw( win,y, x+1+(w-i_len-2)/2, "%s", title );
01999 mvwhline( win, y, x+(w-i_len)/2+i_len, ACS_HLINE, w - 1 - ((w-i_len)/2+i_len) );
02000 mvwaddch( win, y, x+w-1,ACS_URCORNER );
02001
02002 for( i = 0; i < h-2; i++ )
02003 {
02004 mvwaddch( win, y+i+1, x, ACS_VLINE );
02005 mvwaddch( win, y+i+1, x+w-1, ACS_VLINE );
02006 }
02007
02008 mvwaddch( win, y+h-1, x, ACS_LLCORNER );
02009 mvwhline( win, y+h-1, x+1, ACS_HLINE, w - 2 );
02010 mvwaddch( win, y+h-1, x+w-1, ACS_LRCORNER );
02011 }
02012 }
02013
02014 static void DrawEmptyLine( WINDOW *win, int y, int x, int w )
02015 {
02016 if( w > 0 )
02017 {
02018 mvhline( y, x, ' ', w );
02019 }
02020 }
02021
02022 static void DrawLine( WINDOW *win, int y, int x, int w )
02023 {
02024 if( w > 0 )
02025 {
02026 attrset( A_REVERSE );
02027 mvhline( y, x, ' ', w );
02028 attroff( A_REVERSE );
02029 }
02030 }