ncurses.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:51k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * ncurses.c : NCurses plugin for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2001-2004 VideoLAN
  5.  * $Id: ncurses.c 8644 2004-09-05 16:53:04Z fkuehne $
  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.  *
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2 of the License, or
  15.  * (at your option) any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; if not, write to the Free Software
  24.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  25.  *****************************************************************************/
  26. /*****************************************************************************
  27.  * Preamble
  28.  *****************************************************************************/
  29. #include <stdlib.h>                                      /* malloc(), free() */
  30. #include <string.h>
  31. #include <errno.h>                                                 /* ENOMEM */
  32. #include <stdio.h>
  33. #include <time.h>
  34. #include <curses.h>
  35. #include <vlc/vlc.h>
  36. #include <vlc/intf.h>
  37. #include <vlc/vout.h>
  38. #include <vlc/aout.h>
  39. #ifdef HAVE_SYS_STAT_H
  40. #   include <sys/stat.h>
  41. #endif
  42. #if (!defined( WIN32 ) || defined(__MINGW32__))
  43. /* Mingw has its own version of dirent */
  44. #   include <dirent.h>
  45. #endif
  46. #ifdef HAVE_CDDAX
  47. #define CDDA_MRL "cddax://"
  48. #else
  49. #define CDDA_MRL "cdda://"
  50. #endif
  51. #ifdef HAVE_VCDX
  52. #define VCD_MRL "vcdx://"
  53. #else
  54. #define VCD_MRL "vcdx://"
  55. #endif
  56. #define SEARCH_CHAIN_SIZE 20
  57. #define OPEN_CHAIN_SIZE 50
  58. /*****************************************************************************
  59.  * Local prototypes.
  60.  *****************************************************************************/
  61. static int  Open           ( vlc_object_t * );
  62. static void Close          ( vlc_object_t * );
  63. static void Run            ( intf_thread_t * );
  64. static void PlayPause      ( intf_thread_t * );
  65. static void Eject          ( intf_thread_t * );
  66. static int  HandleKey      ( intf_thread_t *, int );
  67. static void Redraw         ( intf_thread_t *, time_t * );
  68. static void SearchPlaylist ( intf_thread_t *, char * );
  69. static void ManageSlider   ( intf_thread_t * );
  70. static void ReadDir        ( intf_thread_t * );
  71. /*****************************************************************************
  72.  * Module descriptor
  73.  *****************************************************************************/
  74. #define BROWSE_TEXT N_("Filebrowser starting point")
  75. #define BROWSE_LONGTEXT N_( 
  76.     "This option allows you to specify the directory the ncurses filebrowser " 
  77.     "will show you initially.")
  78. vlc_module_begin();
  79.     set_description( _("ncurses interface") );
  80.     set_capability( "interface", 10 );
  81.     set_callbacks( Open, Close );
  82.     add_shortcut( "curses" );
  83.     add_directory( "browse-dir", NULL, NULL, BROWSE_TEXT, BROWSE_LONGTEXT, VLC_FALSE );
  84. vlc_module_end();
  85. /*****************************************************************************
  86.  * intf_sys_t: description and status of ncurses interface
  87.  *****************************************************************************/
  88. enum
  89. {
  90.     BOX_NONE,
  91.     BOX_HELP,
  92.     BOX_INFO,
  93.     BOX_LOG,
  94.     BOX_PLAYLIST,
  95.     BOX_SEARCH,
  96.     BOX_OPEN,
  97.     BOX_BROWSE
  98. };
  99. struct dir_entry_t
  100. {
  101.     vlc_bool_t  b_file;
  102.     char        *psz_path;
  103. };
  104. struct intf_sys_t
  105. {
  106.     playlist_t     *p_playlist;
  107.     input_thread_t *p_input;
  108.     float           f_slider;
  109.     float           f_slider_old;
  110.     WINDOW          *w;
  111.     int             i_box_type;
  112.     int             i_box_y;
  113.     int             i_box_lines;
  114.     int             i_box_lines_total;
  115.     int             i_box_start;
  116.     int             i_box_plidx;    /* Playlist index */
  117.     int             b_box_plidx_follow;
  118.     int             i_box_bidx;    /* browser index */
  119.     int             b_box_cleared;
  120.     msg_subscription_t* p_sub;                  /* message bank subscription */
  121.     char            *psz_search_chain;          /* for playlist searching    */
  122.     char            *psz_old_search;            /* for searching next        */
  123.     int             i_before_search;
  124.     char            *psz_open_chain;
  125.     
  126.     char            *psz_current_dir;
  127.     int             i_dir_entries;
  128.     struct dir_entry_t  **pp_dir_entries;
  129. };
  130. static void DrawBox( WINDOW *win, int y, int x, int h, int w, char *title );
  131. static void DrawLine( WINDOW *win, int y, int x, int w );
  132. static void DrawEmptyLine( WINDOW *win, int y, int x, int w );
  133. /*****************************************************************************
  134.  * Open: initialize and create window
  135.  *****************************************************************************/
  136. static int Open( vlc_object_t *p_this )
  137. {
  138.     intf_thread_t *p_intf = (intf_thread_t *)p_this;
  139.     intf_sys_t    *p_sys;
  140.     vlc_value_t    val;
  141.     /* Allocate instance and initialize some members */
  142.     p_sys = p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
  143.     p_sys->p_playlist = NULL;
  144.     p_sys->p_input = NULL;
  145.     p_sys->f_slider = 0.0;
  146.     p_sys->f_slider_old = 0.0;
  147.     p_sys->i_box_type = BOX_PLAYLIST;
  148.     p_sys->i_box_lines = 0;
  149.     p_sys->i_box_start= 0;
  150.     p_sys->i_box_lines_total = 0;
  151.     p_sys->b_box_plidx_follow = VLC_TRUE;
  152.     p_sys->b_box_cleared = VLC_FALSE;
  153.     p_sys->i_box_plidx = 0;
  154.     p_sys->i_box_bidx = 0;
  155.     p_sys->p_sub = msg_Subscribe( p_intf );
  156.     /* Initialize the curses library */
  157.     p_sys->w = initscr();
  158.     keypad( p_sys->w, TRUE );
  159.     /* Don't do NL -> CR/NL */
  160.     nonl();
  161.     /* Take input chars one at a time */
  162.     cbreak();
  163.     /* Don't echo */
  164.     noecho();
  165.     curs_set(0);
  166.     timeout(0);
  167.     clear();
  168.     /* exported function */
  169.     p_intf->pf_run = Run;
  170.     /* Set quiet mode */
  171.     val.i_int = -1;
  172.     var_Set( p_intf->p_vlc, "verbose", val );
  173.     /* Initialize search chain */
  174.     p_sys->psz_search_chain = (char *)malloc( SEARCH_CHAIN_SIZE + 1 );
  175.     p_sys->psz_old_search = NULL;
  176.     p_sys->i_before_search = 0;
  177.     /* Initialize open chain */
  178.     p_sys->psz_open_chain = (char *)malloc( OPEN_CHAIN_SIZE + 1 );
  179.     
  180.     /* Initialize browser options */
  181.     var_Create( p_intf, "browse-dir", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
  182.     var_Get( p_intf, "browse-dir", &val);
  183.     
  184.     if( val.psz_string && *val.psz_string )
  185.     {
  186.         p_sys->psz_current_dir = strdup( val.psz_string);
  187.         free( val.psz_string );
  188.     }
  189.     else
  190.     {
  191.         p_sys->psz_current_dir = strdup( p_intf->p_vlc->psz_homedir );
  192.     }
  193.     
  194.     p_sys->i_dir_entries = 0;
  195.     p_sys->pp_dir_entries  = NULL;
  196.     ReadDir( p_intf );
  197.     return VLC_SUCCESS;
  198. }
  199. /*****************************************************************************
  200.  * Close: destroy interface window
  201.  *****************************************************************************/
  202. static void Close( vlc_object_t *p_this )
  203. {
  204.     intf_thread_t *p_intf = (intf_thread_t *)p_this;
  205.     intf_sys_t    *p_sys = p_intf->p_sys;
  206.     int i;
  207.     for( i = 0; i < p_sys->i_dir_entries; i++ )
  208.     {
  209.         struct dir_entry_t *p_dir_entry = p_sys->pp_dir_entries[i];
  210.         if( p_dir_entry->psz_path ) free( p_dir_entry->psz_path );
  211.         REMOVE_ELEM( p_sys->pp_dir_entries, p_sys->i_dir_entries, i );
  212.         if( p_dir_entry ) free( p_dir_entry );
  213.     }
  214.     p_sys->pp_dir_entries = NULL;
  215.     
  216.     if( p_sys->psz_current_dir ) free( p_sys->psz_current_dir );
  217.     if( p_sys->psz_search_chain ) free( p_sys->psz_search_chain );
  218.     if( p_sys->psz_old_search ) free( p_sys->psz_old_search );
  219.     if( p_sys->psz_open_chain ) free( p_sys->psz_open_chain );
  220.     if( p_sys->p_input )
  221.     {
  222.         vlc_object_release( p_sys->p_input );
  223.     }
  224.     if( p_sys->p_playlist )
  225.     {
  226.         vlc_object_release( p_sys->p_playlist );
  227.     }
  228.     /* Close the ncurses interface */
  229.     endwin();
  230.     msg_Unsubscribe( p_intf, p_sys->p_sub );
  231.     /* Destroy structure */
  232.     free( p_sys );
  233. }
  234. /*****************************************************************************
  235.  * Run: ncurses thread
  236.  *****************************************************************************/
  237. static void Run( intf_thread_t *p_intf )
  238. {
  239.     intf_sys_t    *p_sys = p_intf->p_sys;
  240.     int i_key;
  241.     time_t t_last_refresh;
  242.     /*
  243.      * force drawing the interface for the first time
  244.      */
  245.     t_last_refresh = ( time( 0 ) - 1);
  246.     while( !p_intf->b_die )
  247.     {
  248.         msleep( INTF_IDLE_SLEEP );
  249.         /* Update the input */
  250.         if( p_sys->p_playlist == NULL )
  251.         {
  252.             p_sys->p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
  253.         }
  254.         if( p_sys->p_playlist )
  255.         {
  256.             vlc_mutex_lock( &p_sys->p_playlist->object_lock );
  257.             if( p_sys->p_input == NULL )
  258.             {
  259.                 p_sys->p_input = p_sys->p_playlist->p_input;
  260.                 if( p_sys->p_input )
  261.                 {
  262.                     if( !p_sys->p_input->b_dead )
  263.                     {
  264.                         vlc_object_yield( p_sys->p_input );
  265.                     }
  266.                 }
  267.             }
  268.             else if( p_sys->p_input->b_dead )
  269.             {
  270.                 vlc_object_release( p_sys->p_input );
  271.                 p_sys->p_input = NULL;
  272.                 p_sys->f_slider = p_sys->f_slider_old = 0.0;
  273.                 p_sys->b_box_cleared = VLC_FALSE;
  274.             }
  275.             vlc_mutex_unlock( &p_sys->p_playlist->object_lock );
  276.         }
  277.         if( p_sys->b_box_plidx_follow && p_sys->p_playlist->i_index >= 0 )
  278.         {
  279.             p_sys->i_box_plidx = p_sys->p_playlist->i_index;
  280.         }
  281.         while( ( i_key = getch()) != -1 )
  282.         {
  283.             /*
  284.              * HandleKey returns 1 if the screen needs to be redrawn
  285.              */
  286.             if ( HandleKey( p_intf, i_key ) )
  287.             {
  288.                 Redraw( p_intf, &t_last_refresh );
  289.             }
  290.         }
  291.         /* Hack */
  292.         if( p_sys->f_slider > 0.0001 && !p_sys->b_box_cleared )
  293.         {
  294.             clear();
  295.             Redraw( p_intf, &t_last_refresh );
  296.             p_sys->b_box_cleared = VLC_TRUE;
  297.         }
  298.         /*
  299.          * redraw the screen every second
  300.          */
  301.         if ( (time(0) - t_last_refresh) >= 1 )
  302.         {
  303.             ManageSlider ( p_intf );
  304.             Redraw( p_intf, &t_last_refresh );
  305.         }
  306.     }
  307. }
  308. /* following functions are local */
  309. static int HandleKey( intf_thread_t *p_intf, int i_key )
  310. {
  311.     intf_sys_t *p_sys = p_intf->p_sys;
  312.     vlc_value_t val;
  313.     if( p_sys->i_box_type == BOX_PLAYLIST && p_sys->p_playlist )
  314.     {
  315.         int b_ret = VLC_TRUE;
  316.         switch( i_key )
  317.         {
  318.             vlc_value_t val;
  319.             /* Playlist Settings */
  320.             case 'r':
  321.                 var_Get( p_sys->p_playlist, "random", &val );
  322.                 val.b_bool = !val.b_bool;
  323.                 var_Set( p_sys->p_playlist, "random", val );
  324.                 return 1;
  325.             case 'l':
  326.                 var_Get( p_sys->p_playlist, "loop", &val );
  327.                 val.b_bool = !val.b_bool;
  328.                 var_Set( p_sys->p_playlist, "loop", val );
  329.                 return 1;
  330.             case 'R':
  331.                 var_Get( p_sys->p_playlist, "repeat", &val );
  332.                 val.b_bool = !val.b_bool;
  333.                 var_Set( p_sys->p_playlist, "repeat", val );
  334.                 return 1;
  335.             /* Playlist sort */
  336.             case 'o':
  337.                 playlist_Sort( p_sys->p_playlist, SORT_TITLE, ORDER_NORMAL );
  338.                 return 1;
  339.             case 'O':
  340.                 playlist_Sort( p_sys->p_playlist, SORT_TITLE, ORDER_REVERSE );
  341.                 return 1;
  342.             /* Playlist navigation */
  343.             case KEY_HOME:
  344.                 p_sys->i_box_plidx = 0;
  345.                 break;
  346.             case KEY_END:
  347.                 p_sys->i_box_plidx = p_sys->p_playlist->i_size - 1;
  348.                 break;
  349.             case KEY_UP:
  350.                 p_sys->i_box_plidx--;
  351.                 break;
  352.             case KEY_DOWN:
  353.                 p_sys->i_box_plidx++;
  354.                 break;
  355.             case KEY_PPAGE:
  356.                 p_sys->i_box_plidx -= p_sys->i_box_lines;
  357.                 break;
  358.             case KEY_NPAGE:
  359.                 p_sys->i_box_plidx += p_sys->i_box_lines;
  360.                 break;
  361.             case 'D':
  362.             case KEY_BACKSPACE:
  363.             case KEY_DC:
  364.             {
  365.                 int i_item = p_sys->p_playlist->i_index;
  366.                 playlist_Delete( p_sys->p_playlist, p_sys->i_box_plidx );
  367.                 if( i_item < p_sys->p_playlist->i_size && i_item != p_sys->p_playlist->i_index )
  368.                 {
  369.                     playlist_Goto( p_sys->p_playlist, i_item );
  370.                 }
  371.                 break;
  372.             }
  373.             case KEY_ENTER:
  374.             case 0x0d:
  375.                 playlist_Goto( p_sys->p_playlist, p_sys->i_box_plidx );
  376.                 break;
  377.             default:
  378.                 b_ret = VLC_FALSE;
  379.                 break;
  380.         }
  381.         if( b_ret )
  382.         {
  383.             if( p_sys->i_box_plidx >= p_sys->p_playlist->i_size ) p_sys->i_box_plidx = p_sys->p_playlist->i_size - 1;
  384.             if( p_sys->i_box_plidx < 0 ) p_sys->i_box_plidx = 0;
  385.             if( p_sys->i_box_plidx == p_sys->p_playlist->i_index )
  386.                 p_sys->b_box_plidx_follow = VLC_TRUE;
  387.             else
  388.                 p_sys->b_box_plidx_follow = VLC_FALSE;
  389.             return 1;
  390.         }
  391.     }
  392.     if( p_sys->i_box_type == BOX_BROWSE )
  393.     {
  394.         vlc_bool_t b_ret = VLC_TRUE;
  395.         /* Browser navigation */
  396.         switch( i_key )
  397.         {
  398.             case KEY_HOME:
  399.                 p_sys->i_box_bidx = 0;
  400.                 break;
  401.             case KEY_END:
  402.                 p_sys->i_box_bidx = p_sys->i_dir_entries - 1;
  403.                 break;
  404.             case KEY_UP:
  405.                 p_sys->i_box_bidx--;
  406.                 break;
  407.             case KEY_DOWN:
  408.                 p_sys->i_box_bidx++;
  409.                 break;
  410.             case KEY_PPAGE:
  411.                 p_sys->i_box_bidx -= p_sys->i_box_lines;
  412.                 break;
  413.             case KEY_NPAGE:
  414.                 p_sys->i_box_bidx += p_sys->i_box_lines;
  415.                 break;
  416.             case KEY_ENTER:
  417.             case 0x0d:
  418.                 if( p_sys->pp_dir_entries[p_sys->i_box_bidx]->b_file )
  419.                 {
  420.                     int i_size_entry = strlen( p_sys->psz_current_dir ) +
  421.                                        strlen( p_sys->pp_dir_entries[p_sys->i_box_bidx]->psz_path ) + 2;
  422.                     char *psz_uri = (char *)malloc( sizeof(char)*i_size_entry);
  423.                     sprintf( psz_uri, "%s/%s", p_sys->psz_current_dir, p_sys->pp_dir_entries[p_sys->i_box_bidx]->psz_path );
  424.                     playlist_Add( p_sys->p_playlist, psz_uri,
  425.                                   psz_uri,
  426.                                   PLAYLIST_APPEND, PLAYLIST_END );
  427.                     p_sys->i_box_type = BOX_PLAYLIST;
  428.                     free( psz_uri );
  429.                 }
  430.                 else
  431.                 {
  432.                     int i_size_entry = strlen( p_sys->psz_current_dir ) +
  433.                                        strlen( p_sys->pp_dir_entries[p_sys->i_box_bidx]->psz_path ) + 2;
  434.                     char *psz_uri = (char *)malloc( sizeof(char)*i_size_entry);
  435.                     sprintf( psz_uri, "%s/%s", p_sys->psz_current_dir, p_sys->pp_dir_entries[p_sys->i_box_bidx]->psz_path );
  436.                     
  437.                     p_sys->psz_current_dir = strdup( psz_uri );
  438.                     ReadDir( p_intf );
  439.                     free( psz_uri );
  440.                 }
  441.                 break;
  442.             default:
  443.                 b_ret = VLC_FALSE;
  444.                 break;
  445.         }
  446.         if( b_ret )
  447.         {
  448.             if( p_sys->i_box_bidx >= p_sys->i_dir_entries ) p_sys->i_box_bidx = p_sys->i_dir_entries - 1;
  449.             if( p_sys->i_box_bidx < 0 ) p_sys->i_box_bidx = 0;
  450.             return 1;
  451.         }
  452.     }
  453.     else if( p_sys->i_box_type == BOX_HELP || p_sys->i_box_type == BOX_INFO )
  454.     {
  455.         switch( i_key )
  456.         {
  457.             case KEY_HOME:
  458.                 p_sys->i_box_start = 0;
  459.                 return 1;
  460.             case KEY_END:
  461.                 p_sys->i_box_start = p_sys->i_box_lines_total - 1;
  462.                 return 1;
  463.             case KEY_UP:
  464.                 if( p_sys->i_box_start > 0 ) p_sys->i_box_start--;
  465.                 return 1;
  466.             case KEY_DOWN:
  467.                 if( p_sys->i_box_start < p_sys->i_box_lines_total - 1 )
  468.                 {
  469.                     p_sys->i_box_start++;
  470.                 }
  471.                 return 1;
  472.             case KEY_PPAGE:
  473.                 p_sys->i_box_start -= p_sys->i_box_lines;
  474.                 if( p_sys->i_box_start < 0 ) p_sys->i_box_start = 0;
  475.                 return 1;
  476.             case KEY_NPAGE:
  477.                 p_sys->i_box_start += p_sys->i_box_lines;
  478.                 if( p_sys->i_box_start >= p_sys->i_box_lines_total )
  479.                 {
  480.                     p_sys->i_box_start = p_sys->i_box_lines_total - 1;
  481.                 }
  482.                 return 1;
  483.             default:
  484.                 break;
  485.         }
  486.     }
  487.     else if( p_sys->i_box_type == BOX_NONE )
  488.     {
  489.         switch( i_key )
  490.         {
  491.             case KEY_HOME:
  492.                 p_sys->f_slider = 0;
  493.                 ManageSlider ( p_intf );
  494.                 return 1;
  495.             case KEY_END:
  496.                 p_sys->f_slider = 99.9;
  497.                 ManageSlider ( p_intf );
  498.                 return 1;
  499.             case KEY_UP:
  500.                 p_sys->f_slider += 5.0;
  501.                 if( p_sys->f_slider >= 99.0 ) p_sys->f_slider = 99.0;
  502.                 ManageSlider ( p_intf );
  503.                 return 1;
  504.             case KEY_DOWN:
  505.                 p_sys->f_slider -= 5.0;
  506.                 if( p_sys->f_slider < 0.0 ) p_sys->f_slider = 0.0;
  507.                 ManageSlider ( p_intf );
  508.                 return 1;
  509.             default:
  510.                 break;
  511.         }
  512.     }
  513.     else if( p_sys->i_box_type == BOX_SEARCH && p_sys->psz_search_chain )
  514.     {
  515.         int i_chain_len;
  516.         i_chain_len = strlen( p_sys->psz_search_chain );
  517.         switch( i_key )
  518.         {
  519.             case 0x0c:      /* ^l */
  520.                 clear();
  521.                 return 1;
  522.             case KEY_ENTER:
  523.             case 0x0d:
  524.                 if( i_chain_len > 0 )
  525.                 {
  526.                     p_sys->psz_old_search = strdup( p_sys->psz_search_chain );
  527.                 }
  528.                 else if( p_sys->psz_old_search )
  529.                 {
  530.                     SearchPlaylist( p_intf, p_sys->psz_old_search );
  531.                 }
  532.                 p_sys->i_box_type = BOX_PLAYLIST;
  533.                 return 1;
  534.             case 0x1b:      /* Esc. */
  535.                 p_sys->i_box_plidx = p_sys->i_before_search;
  536.                 p_sys->i_box_type = BOX_PLAYLIST;
  537.                 return 1;
  538.             case KEY_BACKSPACE:
  539.                 if( i_chain_len > 0 )
  540.                 {
  541.                     p_sys->psz_search_chain[ i_chain_len - 1 ] = '';
  542.                 }
  543.                 break;
  544.             default:
  545.                 if( i_chain_len < SEARCH_CHAIN_SIZE )
  546.                 {
  547.                     p_sys->psz_search_chain[ i_chain_len++ ] = i_key;
  548.                     p_sys->psz_search_chain[ i_chain_len ] = 0;
  549.                 }
  550.                 break;
  551.         }
  552.         if( p_sys->psz_old_search )
  553.         {
  554.             free( p_sys->psz_old_search );
  555.             p_sys->psz_old_search = NULL;
  556.         }
  557.         SearchPlaylist( p_intf, p_sys->psz_search_chain );
  558.         return 1;
  559.     }
  560.     else if( p_sys->i_box_type == BOX_OPEN && p_sys->psz_open_chain )
  561.     {
  562.         int i_chain_len = strlen( p_sys->psz_open_chain );
  563.         playlist_t *p_playlist = p_sys->p_playlist;
  564.         switch( i_key )
  565.         {
  566.             case 0x0c:      /* ^l */
  567.                 clear();
  568.                 return 1;
  569.             case KEY_ENTER:
  570.             case 0x0d:
  571.                 if( p_playlist && i_chain_len > 0 )
  572.                 {
  573.                     playlist_Add( p_playlist, p_sys->psz_open_chain,
  574.                                   p_sys->psz_open_chain,
  575.                                   PLAYLIST_GO|PLAYLIST_APPEND, PLAYLIST_END );
  576.                     p_sys->b_box_plidx_follow = VLC_TRUE;
  577.                 }
  578.                 p_sys->i_box_type = BOX_PLAYLIST;
  579.                 return 1;
  580.             case 0x1b:      /* Esc. */
  581.                 p_sys->i_box_type = BOX_PLAYLIST;
  582.                 return 1;
  583.             case KEY_BACKSPACE:
  584.                 if( i_chain_len > 0 )
  585.                 {
  586.                     p_sys->psz_open_chain[ i_chain_len - 1 ] = '';
  587.                 }
  588.                 break;
  589.             default:
  590.                 if( i_chain_len < OPEN_CHAIN_SIZE )
  591.                 {
  592.                     p_sys->psz_open_chain[ i_chain_len++ ] = i_key;
  593.                     p_sys->psz_open_chain[ i_chain_len ] = 0;
  594.                 }
  595.                 break;
  596.         }
  597.         return 1;
  598.     }
  599.     /* Common keys */
  600.     switch( i_key )
  601.     {
  602.         case 'q':
  603.         case 'Q':
  604.         case 0x1b:  /* Esc */
  605.             p_intf->p_vlc->b_die = VLC_TRUE;
  606.             return 0;
  607.         /* Box switching */
  608.         case 'i':
  609.             if( p_sys->i_box_type == BOX_INFO )
  610.                 p_sys->i_box_type = BOX_NONE;
  611.             else
  612.                 p_sys->i_box_type = BOX_INFO;
  613.             p_sys->i_box_lines_total = 0;
  614.             return 1;
  615.         case 'L':
  616.             if( p_sys->i_box_type == BOX_LOG )
  617.                 p_sys->i_box_type = BOX_NONE;
  618.             else
  619.                 p_sys->i_box_type = BOX_LOG;
  620.             return 1;
  621.         case 'P':
  622.             if( p_sys->i_box_type == BOX_PLAYLIST )
  623.                 p_sys->i_box_type = BOX_NONE;
  624.             else
  625.                 p_sys->i_box_type = BOX_PLAYLIST;
  626.             return 1;
  627.         case 'B':
  628.             if( p_sys->i_box_type == BOX_BROWSE )
  629.                 p_sys->i_box_type = BOX_NONE;
  630.             else
  631.                 p_sys->i_box_type = BOX_BROWSE;
  632.             return 1;
  633.         case 'h':
  634.         case 'H':
  635.             if( p_sys->i_box_type == BOX_HELP )
  636.                 p_sys->i_box_type = BOX_NONE;
  637.             else
  638.                 p_sys->i_box_type = BOX_HELP;
  639.             p_sys->i_box_lines_total = 0;
  640.             return 1;
  641.         case '/':
  642.             if( p_sys->i_box_type != BOX_SEARCH )
  643.             {
  644.                 if( p_sys->psz_search_chain == NULL )
  645.                 {
  646.                     return 1;
  647.                 }
  648.                 p_sys->psz_search_chain[0] = '';
  649.                 p_sys->b_box_plidx_follow = VLC_FALSE;
  650.                 p_sys->i_before_search = p_sys->i_box_plidx;
  651.                 p_sys->i_box_type = BOX_SEARCH;
  652.             }
  653.             return 1;
  654.         case 'A': /* Open */
  655.             if( p_sys->i_box_type != BOX_OPEN )
  656.             {
  657.                 if( p_sys->psz_open_chain == NULL )
  658.                 {
  659.                     return 1;
  660.                 }
  661.                 p_sys->psz_open_chain[0] = '';
  662.                 p_sys->i_box_type = BOX_OPEN;
  663.             }
  664.             return 1;
  665.         /* Navigation */
  666.         case KEY_RIGHT:
  667.             p_sys->f_slider += 1.0;
  668.             if( p_sys->f_slider > 99.9 ) p_sys->f_slider = 99.9;
  669.             ManageSlider ( p_intf );
  670.             return 1;
  671.         case KEY_LEFT:
  672.             p_sys->f_slider -= 1.0;
  673.             if( p_sys->f_slider < 0.0 ) p_sys->f_slider = 0.0;
  674.             ManageSlider ( p_intf );
  675.             return 1;
  676.         /* Common control */
  677.         case 'f':
  678.         {
  679.             vout_thread_t *p_vout;
  680.             if( p_intf->p_sys->p_input )
  681.             {
  682.                 p_vout = vlc_object_find( p_intf->p_sys->p_input,
  683.                                           VLC_OBJECT_VOUT, FIND_CHILD );
  684.                 if( p_vout )
  685.                 {
  686.                     p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
  687.                     vlc_object_release( p_vout );
  688.                 }
  689.             }
  690.             return 0;
  691.         }
  692.         case ' ':
  693.             PlayPause( p_intf );
  694.             return 1;
  695.         case 's':
  696.             if( p_intf->p_sys->p_playlist )
  697.             {
  698.                 playlist_Stop( p_intf->p_sys->p_playlist );
  699.             }
  700.             return 1;
  701.         case 'e':
  702.             Eject( p_intf );
  703.             return 1;
  704.         case '[':
  705.             if( p_sys->p_input )
  706.             {
  707.                 val.b_bool = VLC_TRUE;
  708.                 var_Set( p_sys->p_input, "prev-title", val );
  709.             }
  710.             return 1;
  711.         case ']':
  712.             if( p_sys->p_input )
  713.             {
  714.                 val.b_bool = VLC_TRUE;
  715.                 var_Set( p_sys->p_input, "next-title", val );
  716.             }
  717.             return 1;
  718.         case '<':
  719.             if( p_sys->p_input )
  720.             {
  721.                 val.b_bool = VLC_TRUE;
  722.                 var_Set( p_sys->p_input, "prev-chapter", val );
  723.             }
  724.             return 1;
  725.         case '>':
  726.             if( p_sys->p_input )
  727.             {
  728.                 val.b_bool = VLC_TRUE;
  729.                 var_Set( p_sys->p_input, "next-chapter", val );
  730.             }
  731.             return 1;
  732.         case 'p':
  733.             if( p_intf->p_sys->p_playlist )
  734.             {
  735.                 playlist_Prev( p_intf->p_sys->p_playlist );
  736.             }
  737.             clear();
  738.             return 1;
  739.         case 'n':
  740.             if( p_intf->p_sys->p_playlist )
  741.             {
  742.                 playlist_Next( p_intf->p_sys->p_playlist );
  743.             }
  744.             clear();
  745.             return 1;
  746.         case 'a':
  747.             aout_VolumeUp( p_intf, 1, NULL );
  748.             clear();
  749.             return 1;
  750.         case 'z':
  751.             aout_VolumeDown( p_intf, 1, NULL );
  752.             clear();
  753.             return 1;
  754.         /*
  755.          * ^l should clear and redraw the screen
  756.          */
  757.         case 0x0c:
  758.             clear();
  759.             return 1;
  760.         default:
  761.             return 0;
  762.     }
  763. }
  764. static void ManageSlider ( intf_thread_t *p_intf )
  765. {
  766.     intf_sys_t     *p_sys = p_intf->p_sys;
  767.     input_thread_t *p_input = p_sys->p_input;
  768.     vlc_value_t     val;
  769.     if( p_input == NULL )
  770.     {
  771.         return;
  772.     }
  773.     var_Get( p_input, "state", &val );
  774.     if( val.i_int != PLAYING_S )
  775.     {
  776.         return;
  777.     }
  778.     var_Get( p_input, "position", &val );
  779.     if( p_sys->f_slider == p_sys->f_slider_old )
  780.     {
  781.         p_sys->f_slider =
  782.         p_sys->f_slider_old = 100 * val.f_float;
  783.     }
  784.     else
  785.     {
  786.         p_sys->f_slider_old = p_sys->f_slider;
  787.         val.f_float = p_sys->f_slider / 100.0;
  788.         var_Set( p_input, "position", val );
  789.     }
  790. }
  791. static void SearchPlaylist( intf_thread_t *p_intf, char *psz_searchstring )
  792. {
  793.     bool b_ok = false;
  794.     int i_current;
  795.     int i_first = 0 ;
  796.     int i_item = -1;
  797.     intf_sys_t *p_sys = p_intf->p_sys;
  798.     playlist_t *p_playlist = p_sys->p_playlist;
  799.     if( p_sys->i_before_search >= 0 )
  800.         i_first = p_sys->i_before_search;
  801.     if( ( ! psz_searchstring ) ||  strlen( psz_searchstring ) <= 0 )
  802.     {
  803.         p_sys->i_box_plidx = p_sys->i_before_search;
  804.         return;
  805.     }
  806.     for( i_current = i_first + 1; i_current < p_playlist->i_size;
  807.          i_current++ )
  808.     {
  809.         if( strcasestr( p_playlist->pp_items[i_current]->input.psz_name,
  810.                         psz_searchstring ) != NULL
  811.             || strcasestr( p_playlist->pp_items[i_current]->input.psz_uri,
  812.                            psz_searchstring ) != NULL )
  813.         {
  814.             i_item = i_current;
  815.             b_ok = true;
  816.             break;
  817.         }
  818.     }
  819.     if( !b_ok )
  820.     {
  821.         for( i_current = 0; i_current < i_first; i_current++ )
  822.         {
  823.             if( strcasestr( p_playlist->pp_items[i_current]->input.psz_name,
  824.                             psz_searchstring ) != NULL
  825.                 || strcasestr( p_playlist->pp_items[i_current]->input.psz_uri,
  826.                                psz_searchstring ) != NULL )
  827.             {
  828.                 i_item = i_current;
  829.                 b_ok = true;
  830.                 break;
  831.             }
  832.         }
  833.     }
  834.     if( i_item < 0 || i_item >= p_playlist->i_size ) return;
  835.     p_sys->i_box_plidx = i_item;
  836. }
  837. static void mvnprintw( int y, int x, int w, const char *p_fmt, ... )
  838. {
  839.     va_list  vl_args;
  840.     char    *p_buf = NULL;
  841.     int      i_len;
  842.     va_start ( vl_args, p_fmt );
  843.     vasprintf ( &p_buf, p_fmt, vl_args );
  844.     va_end ( vl_args );
  845.     if ( p_buf == NULL )
  846.     {
  847.         return;
  848.     }
  849.     if(  w > 0 )
  850.     {
  851.         if( ( i_len = strlen( p_buf ) ) > w )
  852.         {
  853.             int i_cut = i_len - w;
  854.             int x1 = i_len/2 - i_cut/2;
  855.             int x2 = x1 + i_cut;
  856.             if( i_len > x2 )
  857.             {
  858.                 memmove( &p_buf[x1], &p_buf[x2], i_len - x2 );
  859.             }
  860.             p_buf[w] = '';
  861.             if( w > 7 )
  862.             {
  863.                 p_buf[w/2-1] = '.';
  864.                 p_buf[w/2  ] = '.';
  865.                 p_buf[w/2+1] = '.';
  866.             }
  867.             mvprintw( y, x, "%s", p_buf );
  868.         }
  869.         else
  870.         {
  871.             mvprintw( y, x, "%s", p_buf );
  872.             mvhline( y, x + i_len, ' ', w - i_len );
  873.         }
  874.     }
  875. }
  876. static void MainBoxWrite( intf_thread_t *p_intf, int l, int x, const char *p_fmt, ... )
  877. {
  878.     intf_sys_t     *p_sys = p_intf->p_sys;
  879.     va_list  vl_args;
  880.     char    *p_buf = NULL;
  881.     if( l < p_sys->i_box_start || l - p_sys->i_box_start >= p_sys->i_box_lines )
  882.     {
  883.         return;
  884.     }
  885.     va_start ( vl_args, p_fmt );
  886.     vasprintf ( &p_buf, p_fmt, vl_args );
  887.     va_end ( vl_args );
  888.     if( p_buf == NULL )
  889.     {
  890.         return;
  891.     }
  892.     mvnprintw( p_sys->i_box_y + l - p_sys->i_box_start, x, COLS - x - 1, "%s", p_buf );
  893. }
  894. static void Redraw ( intf_thread_t *p_intf, time_t *t_last_refresh )
  895. {
  896.     intf_sys_t     *p_sys = p_intf->p_sys;
  897.     input_thread_t *p_input = p_sys->p_input;
  898.     int y = 0;
  899.     int h;
  900.     int y_end;
  901.     //clear();
  902.     /* Title */
  903.     attrset ( A_REVERSE );
  904.     mvnprintw( y, 0, COLS, "VLC media player" " (ncurses interface) [ h for help ]" );
  905.     attroff ( A_REVERSE );
  906.     y += 2;
  907.     /* Infos */
  908.     if( p_input && !p_input->b_dead )
  909.     {
  910.         char buf1[MSTRTIME_MAX_SIZE];
  911.         char buf2[MSTRTIME_MAX_SIZE];
  912.         vlc_value_t val;
  913.         vlc_value_t val_list;
  914.         /* Source */
  915.         mvnprintw( y++, 0, COLS, " Source   : %s",
  916.                    p_input->input.p_item->psz_uri );
  917.         /* State */
  918.         var_Get( p_input, "state", &val );
  919.         if( val.i_int == PLAYING_S )
  920.         {
  921.             mvnprintw( y++, 0, COLS, " State    : Playing" );
  922.         }
  923.         else if( val.i_int == PAUSE_S )
  924.         {
  925.             mvnprintw( y++, 0, COLS, " State    : Paused" );
  926.         }
  927.         else
  928.         {
  929.             y++;
  930.         }
  931.         if( val.i_int != INIT_S && val.i_int != END_S )
  932.         {
  933.             audio_volume_t i_volume;
  934.             /* Position */
  935.             var_Get( p_input, "time", &val );
  936.             msecstotimestr( buf1, val.i_time / 1000 );
  937.             var_Get( p_input, "length", &val );
  938.             msecstotimestr( buf2, val.i_time / 1000 );
  939.             mvnprintw( y++, 0, COLS, " Position : %s/%s (%.2f%%)", buf1, buf2, p_sys->f_slider );
  940.             /* Volume */
  941.             aout_VolumeGet( p_intf, &i_volume );
  942.             mvnprintw( y++, 0, COLS, " Volume   : %i%%", i_volume*200/AOUT_VOLUME_MAX );
  943.             /* Title */
  944.             if( !var_Get( p_input, "title", &val ) )
  945.             {
  946.                 var_Change( p_input, "title", VLC_VAR_GETCHOICES, &val_list, NULL );
  947.                 if( val_list.p_list->i_count > 0 )
  948.                 {
  949.                     mvnprintw( y++, 0, COLS, " Title    : %d/%d", val.i_int, val_list.p_list->i_count );
  950.                 }
  951.                 var_Change( p_input, "title", VLC_VAR_FREELIST, &val_list, NULL );
  952.             }
  953.             /* Chapter */
  954.             if( !var_Get( p_input, "chapter", &val ) )
  955.             {
  956.                 var_Change( p_input, "chapter", VLC_VAR_GETCHOICES, &val_list, NULL );
  957.                 if( val_list.p_list->i_count > 0 )
  958.                 {
  959.                     mvnprintw( y++, 0, COLS, " Chapter  : %d/%d", val.i_int, val_list.p_list->i_count );
  960.                 }
  961.                 var_Change( p_input, "chapter", VLC_VAR_FREELIST, &val_list, NULL );
  962.             }
  963.         }
  964.         else
  965.         {
  966.             y++;
  967.         }
  968.     }
  969.     else
  970.     {
  971.         mvnprintw( y++, 0, COLS, "Source: <no current item>" );
  972.         DrawEmptyLine( p_sys->w, y++, 0, COLS );
  973.         DrawEmptyLine( p_sys->w, y++, 0, COLS );
  974.         DrawEmptyLine( p_sys->w, y++, 0, COLS );
  975.     }
  976.     DrawBox( p_sys->w, y, 0, 3, COLS, "" );
  977.     DrawEmptyLine( p_sys->w, y+1, 1, COLS-2);
  978.     DrawLine( p_sys->w, y+1, 1, (int)(p_intf->p_sys->f_slider/100.0 * (COLS -2)) );
  979.     y += 3;
  980.     p_sys->i_box_y = y + 1;
  981.     p_sys->i_box_lines = LINES - y - 2;
  982.     h = LINES - y;
  983.     y_end = y + h - 1;
  984.     if( p_sys->i_box_type == BOX_HELP )
  985.     {
  986.         /* Help box */
  987.         int l = 0;
  988.         DrawBox( p_sys->w, y++, 0, h, COLS, " Help " );
  989.         MainBoxWrite( p_intf, l++, 1, "[Display]" );
  990.         MainBoxWrite( p_intf, l++, 1, "     h,H         Show/Hide help box" );
  991.         MainBoxWrite( p_intf, l++, 1, "     i           Show/Hide info box" );
  992.         MainBoxWrite( p_intf, l++, 1, "     L           Show/Hide messages box" );
  993.         MainBoxWrite( p_intf, l++, 1, "     P           Show/Hide playlist box" );
  994.         MainBoxWrite( p_intf, l++, 1, "     B           Show/Hide filebrowser" );
  995.         MainBoxWrite( p_intf, l++, 1, "" );
  996.         MainBoxWrite( p_intf, l++, 1, "[Global]" );
  997.         MainBoxWrite( p_intf, l++, 1, "     q, Q        Quit" );
  998.         MainBoxWrite( p_intf, l++, 1, "     s           Stop" );
  999.         MainBoxWrite( p_intf, l++, 1, "     <space>     Pause/Play" );
  1000.         MainBoxWrite( p_intf, l++, 1, "     f           Toggle Fullscreen" );
  1001.         MainBoxWrite( p_intf, l++, 1, "     n, p        Next/Previous playlist item" );
  1002.         MainBoxWrite( p_intf, l++, 1, "     [, ]        Next/Previous title" );
  1003.         MainBoxWrite( p_intf, l++, 1, "     <, >        Next/Previous chapter" );
  1004.         MainBoxWrite( p_intf, l++, 1, "     <right>     Seek +1%%" );
  1005.         MainBoxWrite( p_intf, l++, 1, "     <left>      Seek -1%%" );
  1006.         MainBoxWrite( p_intf, l++, 1, "     a           Volume Up" );
  1007.         MainBoxWrite( p_intf, l++, 1, "     z           Volume Down" );
  1008.         MainBoxWrite( p_intf, l++, 1, "" );
  1009.         MainBoxWrite( p_intf, l++, 1, "[Playlist]" );
  1010.         MainBoxWrite( p_intf, l++, 1, "     r           Random" );
  1011.         MainBoxWrite( p_intf, l++, 1, "     l           Loop Playlist" );
  1012.         MainBoxWrite( p_intf, l++, 1, "     R           Repeat item" );
  1013.         MainBoxWrite( p_intf, l++, 1, "     o           Order Playlist by title" );
  1014.         MainBoxWrite( p_intf, l++, 1, "     O           Reverse order Playlist by title" );
  1015.         MainBoxWrite( p_intf, l++, 1, "     /           Look for an item" );
  1016.         MainBoxWrite( p_intf, l++, 1, "     A           Add an entry" );
  1017.         MainBoxWrite( p_intf, l++, 1, "     D, <del>    Delete an entry" );
  1018.         MainBoxWrite( p_intf, l++, 1, "     <backspace> Delete an entry" );
  1019.         MainBoxWrite( p_intf, l++, 1, "" );
  1020.         MainBoxWrite( p_intf, l++, 1, "[Boxes]" );
  1021.         MainBoxWrite( p_intf, l++, 1, "     <up>,<down>     Navigate through the box line by line" );
  1022.         MainBoxWrite( p_intf, l++, 1, "     <pgup>,<pgdown> Navigate through the box page by page" );
  1023.         MainBoxWrite( p_intf, l++, 1, "" );
  1024.         MainBoxWrite( p_intf, l++, 1, "[Player]" );
  1025.         MainBoxWrite( p_intf, l++, 1, "     <up>,<down>     Seek +/-5%%" );
  1026.         MainBoxWrite( p_intf, l++, 1, "" );
  1027.         MainBoxWrite( p_intf, l++, 1, "[Miscellaneous]" );
  1028.         MainBoxWrite( p_intf, l++, 1, "     Ctrl-l          Refresh the screen" );
  1029.         p_sys->i_box_lines_total = l;
  1030.         if( p_sys->i_box_start >= p_sys->i_box_lines_total )
  1031.         {
  1032.             p_sys->i_box_start = p_sys->i_box_lines_total - 1;
  1033.         }
  1034.         if( l - p_sys->i_box_start < p_sys->i_box_lines )
  1035.         {
  1036.             y += l - p_sys->i_box_start;
  1037.         }
  1038.         else
  1039.         {
  1040.             y += p_sys->i_box_lines;
  1041.         }
  1042.     }
  1043.     else if( p_sys->i_box_type == BOX_INFO )
  1044.     {
  1045.         /* Info box */
  1046.         int l = 0;
  1047.         DrawBox( p_sys->w, y++, 0, h, COLS, " Information " );
  1048.         if( p_input )
  1049.         {
  1050.             int i,j;
  1051.             vlc_mutex_lock( &p_input->input.p_item->lock );
  1052.             for ( i = 0; i < p_input->input.p_item->i_categories; i++ )
  1053.             {
  1054.                 info_category_t *p_category = p_input->input.p_item->pp_categories[i];
  1055.                 if( y >= y_end ) break;
  1056.                 MainBoxWrite( p_intf, l++, 1, "  [%s]", p_category->psz_name );
  1057.                 for ( j = 0; j < p_category->i_infos; j++ )
  1058.                 {
  1059.                     info_t *p_info = p_category->pp_infos[j];
  1060.                     if( y >= y_end ) break;
  1061.                     MainBoxWrite( p_intf, l++, 1, "      %s: %s", p_info->psz_name, p_info->psz_value );
  1062.                 }
  1063.             }
  1064.             vlc_mutex_unlock( &p_input->input.p_item->lock );
  1065.         }
  1066.         else
  1067.         {
  1068.             MainBoxWrite( p_intf, l++, 1, "No item currently playing" );
  1069.         }
  1070.         p_sys->i_box_lines_total = l;
  1071.         if( p_sys->i_box_start >= p_sys->i_box_lines_total )
  1072.         {
  1073.             p_sys->i_box_start = p_sys->i_box_lines_total - 1;
  1074.         }
  1075.         if( l - p_sys->i_box_start < p_sys->i_box_lines )
  1076.         {
  1077.             y += l - p_sys->i_box_start;
  1078.         }
  1079.         else
  1080.         {
  1081.             y += p_sys->i_box_lines;
  1082.         }
  1083.     }
  1084.     else if( p_sys->i_box_type == BOX_LOG )
  1085.     {
  1086.         int i_line = 0;
  1087.         int i_stop;
  1088.         int i_start;
  1089.         DrawBox( p_sys->w, y++, 0, h, COLS, " Logs " );
  1090.         i_start = p_intf->p_sys->p_sub->i_start;
  1091.         vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock );
  1092.         i_stop = *p_intf->p_sys->p_sub->pi_stop;
  1093.         vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock );
  1094.         for( ;; )
  1095.         {
  1096.             static const char *ppsz_type[4] = { "", "error", "warning", "debug" };
  1097.             if( i_line >= h - 2 )
  1098.             {
  1099.                 break;
  1100.             }
  1101.             i_stop--;
  1102.             i_line++;
  1103.             if( i_stop < 0 ) i_stop += VLC_MSG_QSIZE;
  1104.             if( i_stop == i_start )
  1105.             {
  1106.                 break;
  1107.             }
  1108.             mvnprintw( y + h-2-i_line, 1, COLS - 2, "   [%s] %s",
  1109.                       ppsz_type[p_sys->p_sub->p_msg[i_stop].i_type],
  1110.                       p_sys->p_sub->p_msg[i_stop].psz_msg );
  1111.         }
  1112.         vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock );
  1113.         p_intf->p_sys->p_sub->i_start = i_stop;
  1114.         vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock );
  1115.         y = y_end;
  1116.     }
  1117.     else if( p_sys->i_box_type == BOX_BROWSE )
  1118.     {
  1119.         /* Playlist box */
  1120.         int        i_start, i_stop;
  1121.         int        i_item;
  1122.         DrawBox( p_sys->w, y++, 0, h, COLS, " Browse " );
  1123.         if( p_sys->i_box_bidx >= p_sys->i_dir_entries ) p_sys->i_box_plidx = p_sys->i_dir_entries - 1;
  1124.         if( p_sys->i_box_bidx < 0 ) p_sys->i_box_bidx = 0;
  1125.         if( p_sys->i_box_bidx < (h - 2)/2 )
  1126.         {
  1127.             i_start = 0;
  1128.             i_stop = h - 2;
  1129.         }
  1130.         else if( p_sys->i_dir_entries - p_sys->i_box_bidx > (h - 2)/2 )
  1131.         {
  1132.             i_start = p_sys->i_box_bidx - (h - 2)/2;
  1133.             i_stop = i_start + h - 2;
  1134.         }
  1135.         else
  1136.         {
  1137.             i_stop = p_sys->i_dir_entries;
  1138.             i_start = p_sys->i_dir_entries - (h - 2);
  1139.         }
  1140.         if( i_start < 0 )
  1141.         {
  1142.             i_start = 0;
  1143.         }
  1144.         if( i_stop > p_sys->i_dir_entries )
  1145.         {
  1146.             i_stop = p_sys->i_dir_entries;
  1147.         }
  1148.         for( i_item = i_start; i_item < i_stop; i_item++ )
  1149.         {
  1150.             vlc_bool_t b_selected = ( p_sys->i_box_bidx == i_item );
  1151.             if( y >= y_end ) break;
  1152.             if( b_selected )
  1153.             {
  1154.                 attrset( A_REVERSE );
  1155.             }
  1156.             mvnprintw( y++, 1, COLS - 2, "%c %s", p_sys->pp_dir_entries[i_item]->b_file == VLC_TRUE ? '-' : '+',
  1157.                             p_sys->pp_dir_entries[i_item]->psz_path );
  1158.             if( b_selected )
  1159.             {
  1160.                 attroff ( A_REVERSE );
  1161.             }
  1162.         }
  1163.     }
  1164.     else if( ( p_sys->i_box_type == BOX_PLAYLIST ||
  1165.                p_sys->i_box_type == BOX_SEARCH ||
  1166.                p_sys->i_box_type == BOX_OPEN  ) && p_sys->p_playlist )
  1167.     {
  1168.         /* Playlist box */
  1169.         playlist_t *p_playlist = p_sys->p_playlist;
  1170.         int        i_start, i_stop;
  1171.         int        i_item;
  1172.         DrawBox( p_sys->w, y++, 0, h, COLS, " Playlist " );
  1173.         if( p_sys->i_box_plidx >= p_playlist->i_size ) p_sys->i_box_plidx = p_playlist->i_size - 1;
  1174.         if( p_sys->i_box_plidx < 0 ) p_sys->i_box_plidx = 0;
  1175.         if( p_sys->i_box_plidx < (h - 2)/2 )
  1176.         {
  1177.             i_start = 0;
  1178.             i_stop = h - 2;
  1179.         }
  1180.         else if( p_playlist->i_size - p_sys->i_box_plidx > (h - 2)/2 )
  1181.         {
  1182.             i_start = p_sys->i_box_plidx - (h - 2)/2;
  1183.             i_stop = i_start + h - 2;
  1184.         }
  1185.         else
  1186.         {
  1187.             i_stop = p_playlist->i_size;
  1188.             i_start = p_playlist->i_size - (h - 2);
  1189.         }
  1190.         if( i_start < 0 )
  1191.         {
  1192.             i_start = 0;
  1193.         }
  1194.         if( i_stop > p_playlist->i_size )
  1195.         {
  1196.             i_stop = p_playlist->i_size;
  1197.         }
  1198.         for( i_item = i_start; i_item < i_stop; i_item++ )
  1199.         {
  1200.             vlc_bool_t b_selected = ( p_sys->i_box_plidx == i_item );
  1201.             int c = p_playlist->i_index == i_item ? '>' : ' ';
  1202.             if( y >= y_end ) break;
  1203.             if( b_selected )
  1204.             {
  1205.                 attrset( A_REVERSE );
  1206.             }
  1207.             if( !strcmp( p_playlist->pp_items[i_item]->input.psz_name,
  1208.                          p_playlist->pp_items[i_item]->input.psz_uri ) )
  1209.             {
  1210.                 mvnprintw( y++, 1, COLS - 2, "%c %d - '%s'",
  1211.                            c,
  1212.                            i_item,
  1213.                            p_playlist->pp_items[i_item]->input.psz_uri );
  1214.             }
  1215.             else
  1216.             {
  1217.                 mvnprintw( y++, 1, COLS - 2, "%c %d - '%s' (%s)",
  1218.                           c,
  1219.                           i_item,
  1220.                           p_playlist->pp_items[i_item]->input.psz_uri,
  1221.                           p_playlist->pp_items[i_item]->input.psz_name );
  1222.             }
  1223.             if( b_selected )
  1224.             {
  1225.                 attroff ( A_REVERSE );
  1226.             }
  1227.         }
  1228.     }
  1229.     else
  1230.     {
  1231.         y++;
  1232.     }
  1233.     if( p_sys->i_box_type == BOX_SEARCH )
  1234.     {
  1235.         DrawEmptyLine( p_sys->w, 7, 1, COLS-2 );
  1236.         if( p_sys->psz_search_chain )
  1237.         {
  1238.             if( strlen( p_sys->psz_search_chain ) == 0 &&
  1239.                 p_sys->psz_old_search != NULL )
  1240.             {
  1241.                 /* Searching next entry */
  1242.                 mvnprintw( 7, 1, COLS-2, "Find: %s", p_sys->psz_old_search );
  1243.             }
  1244.             else
  1245.             {
  1246.                 mvnprintw( 7, 1, COLS-2, "Find: %s", p_sys->psz_search_chain );
  1247.             }
  1248.         }
  1249.     }
  1250.     if( p_sys->i_box_type == BOX_OPEN )
  1251.     {
  1252.         if( p_sys->psz_open_chain )
  1253.         {
  1254.             DrawEmptyLine( p_sys->w, 7, 1, COLS-2 );
  1255.             mvnprintw( 7, 1, COLS-2, "Open: %s", p_sys->psz_open_chain );
  1256.         }
  1257.     }
  1258.     while( y < y_end )
  1259.     {
  1260.         DrawEmptyLine( p_sys->w, y++, 1, COLS - 2 );
  1261.     }
  1262.     refresh();
  1263.     *t_last_refresh = time( 0 );
  1264. }
  1265. static void Eject ( intf_thread_t *p_intf )
  1266. {
  1267.     char *psz_device = NULL, *psz_parser, *psz_name;
  1268.     /*
  1269.      * Get the active input
  1270.      * Determine whether we can eject a media, ie it's a DVD, VCD or CD-DA
  1271.      * If it's neither of these, then return
  1272.      */
  1273.     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  1274.                                                        FIND_ANYWHERE );
  1275.     if( p_playlist == NULL )
  1276.     {
  1277.         return;
  1278.     }
  1279.     vlc_mutex_lock( &p_playlist->object_lock );
  1280.     if( p_playlist->i_index < 0 )
  1281.     {
  1282.         vlc_mutex_unlock( &p_playlist->object_lock );
  1283.         vlc_object_release( p_playlist );
  1284.         return;
  1285.     }
  1286.     psz_name = p_playlist->pp_items[ p_playlist->i_index ]->input.psz_name;
  1287.     if( psz_name )
  1288.     {
  1289.         if( !strncmp(psz_name, "dvd://", 4) )
  1290.         {
  1291.             switch( psz_name[strlen("dvd://")] )
  1292.             {
  1293.             case '':
  1294.             case '@':
  1295.                 psz_device = config_GetPsz( p_intf, "dvd" );
  1296.                 break;
  1297.             default:
  1298.                 /* Omit the first MRL-selector characters */
  1299.                 psz_device = strdup( psz_name + strlen("dvd://" ) );
  1300.                 break;
  1301.             }
  1302.         }
  1303.         else if( !strncmp(psz_name, VCD_MRL, strlen(VCD_MRL)) )
  1304.         {
  1305.             switch( psz_name[strlen(VCD_MRL)] )
  1306.             {
  1307.             case '':
  1308.             case '@':
  1309.                 psz_device = config_GetPsz( p_intf, VCD_MRL );
  1310.                 break;
  1311.             default:
  1312.                 /* Omit the beginning MRL-selector characters */
  1313.                 psz_device = strdup( psz_name + strlen(VCD_MRL) );
  1314.                 break;
  1315.             }
  1316.         }
  1317.         else if( !strncmp(psz_name, CDDA_MRL, strlen(CDDA_MRL) ) )
  1318.         {
  1319.             switch( psz_name[strlen(CDDA_MRL)] )
  1320.             {
  1321.             case '':
  1322.             case '@':
  1323.                 psz_device = config_GetPsz( p_intf, "cd-audio" );
  1324.                 break;
  1325.             default:
  1326.                 /* Omit the beginning MRL-selector characters */
  1327.                 psz_device = strdup( psz_name + strlen(CDDA_MRL) );
  1328.                 break;
  1329.             }
  1330.         }
  1331.         else
  1332.         {
  1333.             psz_device = strdup( psz_name );
  1334.         }
  1335.     }
  1336.     vlc_mutex_unlock( &p_playlist->object_lock );
  1337.     vlc_object_release( p_playlist );
  1338.     if( psz_device == NULL )
  1339.     {
  1340.         return;
  1341.     }
  1342.     /* Remove what we have after @ */
  1343.     psz_parser = psz_device;
  1344.     for( psz_parser = psz_device ; *psz_parser ; psz_parser++ )
  1345.     {
  1346.         if( *psz_parser == '@' )
  1347.         {
  1348.             *psz_parser = '';
  1349.             break;
  1350.         }
  1351.     }
  1352.     /* If there's a stream playing, we aren't allowed to eject ! */
  1353.     if( p_intf->p_sys->p_input == NULL )
  1354.     {
  1355.         msg_Dbg( p_intf, "ejecting %s", psz_device );
  1356.         intf_Eject( p_intf, psz_device );
  1357.     }
  1358.     free(psz_device);
  1359.     return;
  1360. }
  1361. static void ReadDir( intf_thread_t *p_intf )
  1362. {
  1363.     intf_sys_t     *p_sys = p_intf->p_sys;
  1364.     DIR *                       p_current_dir;
  1365.     struct dirent *             p_dir_content;
  1366.     int i;
  1367.     if( p_sys->psz_current_dir && *p_sys->psz_current_dir )
  1368.     {
  1369.         /* Open the dir */
  1370.         p_current_dir = opendir( p_sys->psz_current_dir );
  1371.         if( p_current_dir == NULL )
  1372.         {
  1373.             /* something went bad, get out of here ! */
  1374. #ifdef HAVE_ERRNO_H
  1375.             msg_Warn( p_intf, "cannot open directory `%s' (%s)",
  1376.                       p_sys->psz_current_dir, strerror(errno));
  1377. #else
  1378.             msg_Warn( p_intf, "cannot open directory `%s'", p_sys->psz_current_dir );
  1379. #endif
  1380.             return;
  1381.         }
  1382.         
  1383.         /* Clean the old shit */
  1384.         for( i = 0; i < p_sys->i_dir_entries; i++ )
  1385.         {
  1386.             struct dir_entry_t *p_dir_entry = p_sys->pp_dir_entries[i];
  1387.             free( p_dir_entry->psz_path );
  1388.             REMOVE_ELEM( p_sys->pp_dir_entries, p_sys->i_dir_entries, i );
  1389.             free( p_dir_entry );
  1390.         }
  1391.         p_sys->pp_dir_entries = NULL;
  1392.         p_sys->i_dir_entries = 0;
  1393.         /* get the first directory entry */
  1394.         p_dir_content = readdir( p_current_dir );
  1395.         /* while we still have entries in the directory */
  1396.         while( p_dir_content != NULL )
  1397.         {
  1398. #if defined( S_ISDIR )
  1399.             struct stat stat_data;
  1400. #endif
  1401.             struct dir_entry_t *p_dir_entry;
  1402.             int i_size_entry = strlen( p_sys->psz_current_dir ) +
  1403.                                strlen( p_dir_content->d_name ) + 2;
  1404.             char *psz_uri = (char *)malloc( sizeof(char)*i_size_entry);
  1405.             sprintf( psz_uri, "%s/%s", p_sys->psz_current_dir,
  1406.                      p_dir_content->d_name );
  1407.             if( !( p_dir_entry = malloc( sizeof( struct dir_entry_t) ) ) )
  1408.             {
  1409.                 free( psz_uri);
  1410.                 return;
  1411.             }
  1412. #if defined( S_ISDIR )
  1413.             stat( psz_uri, &stat_data );
  1414.             if( S_ISDIR(stat_data.st_mode) )
  1415. #elif defined( DT_DIR )
  1416.             if( p_dir_content->d_type & DT_DIR )
  1417. #else
  1418.             if( 0 )
  1419. #endif
  1420.             {
  1421.                 p_dir_entry->psz_path = strdup( p_dir_content->d_name );
  1422.                 p_dir_entry->b_file = VLC_FALSE;
  1423.                 INSERT_ELEM( p_sys->pp_dir_entries, p_sys->i_dir_entries,
  1424.                      p_sys->i_dir_entries, p_dir_entry );
  1425.             }
  1426.             else
  1427.             {
  1428.                 p_dir_entry->psz_path = strdup( p_dir_content->d_name );
  1429.                 p_dir_entry->b_file = VLC_TRUE;
  1430.                 INSERT_ELEM( p_sys->pp_dir_entries, p_sys->i_dir_entries,
  1431.                      p_sys->i_dir_entries, p_dir_entry );
  1432.             }
  1433.             free( psz_uri );
  1434.             /* Read next entry */
  1435.             p_dir_content = readdir( p_current_dir );
  1436.         }
  1437.         closedir( p_current_dir );
  1438.         return;
  1439.     }
  1440.     else
  1441.     {
  1442.         msg_Dbg( p_intf, "no current dir set" );
  1443.         return;
  1444.     }
  1445. }
  1446. static void PlayPause( intf_thread_t *p_intf )
  1447. {
  1448.     input_thread_t *p_input = p_intf->p_sys->p_input;
  1449.     vlc_value_t val;
  1450.     if( p_input )
  1451.     {
  1452.         var_Get( p_input, "state", &val );
  1453.         if( val.i_int != PAUSE_S )
  1454.         {
  1455.             val.i_int = PAUSE_S;
  1456.         }
  1457.         else
  1458.         {
  1459.             val.i_int = PLAYING_S;
  1460.         }
  1461.         var_Set( p_input, "state", val );
  1462.     }
  1463.     else if( p_intf->p_sys->p_playlist )
  1464.     {
  1465.         playlist_Play( p_intf->p_sys->p_playlist );
  1466.     }
  1467. }
  1468. /****************************************************************************
  1469.  *
  1470.  ****************************************************************************/
  1471. static void DrawBox( WINDOW *win, int y, int x, int h, int w, char *title )
  1472. {
  1473.     int i;
  1474.     int i_len;
  1475.     if(  w > 3 && h > 2 )
  1476.     {
  1477.         if( title == NULL ) title = "";
  1478.         i_len = strlen( title );
  1479.         if( i_len > w - 2 ) i_len = w - 2;
  1480.         mvwaddch( win, y, x,    ACS_ULCORNER );
  1481.         mvwhline( win, y, x+1,  ACS_HLINE, ( w-i_len-2)/2 );
  1482.         mvwprintw( win,y, x+1+(w-i_len-2)/2, "%s", title );
  1483.         mvwhline( win, y, x+(w-i_len)/2+i_len,  ACS_HLINE, w - 1 - ((w-i_len)/2+i_len) );
  1484.         mvwaddch( win, y, x+w-1,ACS_URCORNER );
  1485.         for( i = 0; i < h-2; i++ )
  1486.         {
  1487.             mvwaddch( win, y+i+1, x,     ACS_VLINE );
  1488.             mvwaddch( win, y+i+1, x+w-1, ACS_VLINE );
  1489.         }
  1490.         mvwaddch( win, y+h-1, x,     ACS_LLCORNER );
  1491.         mvwhline( win, y+h-1, x+1,   ACS_HLINE, w - 2 );
  1492.         mvwaddch( win, y+h-1, x+w-1, ACS_LRCORNER );
  1493.     }
  1494. }
  1495. static void DrawEmptyLine( WINDOW *win, int y, int x, int w )
  1496. {
  1497.     if( w > 0 )
  1498.     {
  1499.         mvhline( y, x, ' ', w );
  1500.     }
  1501. }
  1502. static void DrawLine( WINDOW *win, int y, int x, int w )
  1503. {
  1504.     if( w > 0 )
  1505.     {
  1506.         attrset( A_REVERSE );
  1507.         mvhline( y, x, ' ', w );
  1508.         attroff ( A_REVERSE );
  1509.     }
  1510. }