hotkeys.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:42k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * hotkeys.c: Hotkey handling for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2005-2009 the VideoLAN team
  5.  * $Id: a7fdc618027eafd546b8a1f5dc31937843b76ea1 $
  6.  *
  7.  * Authors: Sigmund Augdal Helberg <dnumgis@videolan.org>
  8.  *          Jean-Paul Saman <jpsaman #_at_# m2x.nl>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23.  *****************************************************************************/
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #ifdef HAVE_CONFIG_H
  28. # include "config.h"
  29. #endif
  30. #include <vlc_common.h>
  31. #include <vlc_plugin.h>
  32. #include <vlc_interface.h>
  33. #include <vlc_input.h>
  34. #include <vlc_vout.h>
  35. #include <vlc_aout.h>
  36. #include <vlc_osd.h>
  37. #include <vlc_playlist.h>
  38. #include "vlc_keys.h"
  39. #include "math.h"
  40. #define BUFFER_SIZE 10
  41. #define CHANNELS_NUMBER 4
  42. #define VOLUME_TEXT_CHAN     p_intf->p_sys->p_channels[ 0 ]
  43. #define VOLUME_WIDGET_CHAN   p_intf->p_sys->p_channels[ 1 ]
  44. #define POSITION_TEXT_CHAN   p_intf->p_sys->p_channels[ 2 ]
  45. #define POSITION_WIDGET_CHAN p_intf->p_sys->p_channels[ 3 ]
  46. /*****************************************************************************
  47.  * intf_sys_t: description and status of FB interface
  48.  *****************************************************************************/
  49. struct intf_sys_t
  50. {
  51.     int                 p_actions[ BUFFER_SIZE ]; /* buffer that contains
  52.                                                    * action events */
  53.     int                 i_size;        /* number of events in buffer */
  54.     int                 p_channels[ CHANNELS_NUMBER ]; /* contains registered
  55.                                                         * channel IDs */
  56.     vlc_mutex_t         lock; /* callback lock */
  57.     vlc_cond_t          wait; /* callback event */
  58.     int                 i_mousewheel_mode;
  59. };
  60. /*****************************************************************************
  61.  * Local prototypes
  62.  *****************************************************************************/
  63. static int  Open    ( vlc_object_t * );
  64. static void Close   ( vlc_object_t * );
  65. static void Run     ( intf_thread_t * );
  66. static int  GetAction( intf_thread_t *);
  67. static int  ActionEvent( vlc_object_t *, char const *,
  68.                          vlc_value_t, vlc_value_t, void * );
  69. static int  SpecialKeyEvent( vlc_object_t *, char const *,
  70.                              vlc_value_t, vlc_value_t, void * );
  71. static void PlayBookmark( intf_thread_t *, int );
  72. static void SetBookmark ( intf_thread_t *, int );
  73. static void DisplayPosition( intf_thread_t *, vout_thread_t *, input_thread_t * );
  74. static void DisplayVolume  ( intf_thread_t *, vout_thread_t *, audio_volume_t );
  75. static void ClearChannels  ( intf_thread_t *, vout_thread_t * );
  76. /*****************************************************************************
  77.  * Module descriptor
  78.  *****************************************************************************/
  79. enum{
  80.     MOUSEWHEEL_VOLUME,
  81.     MOUSEWHEEL_POSITION,
  82.     NO_MOUSEWHEEL,
  83. };
  84. static const int i_mode_list[] =
  85.     { MOUSEWHEEL_VOLUME, MOUSEWHEEL_POSITION, NO_MOUSEWHEEL };
  86. static const char *const psz_mode_list_text[] =
  87.     { N_("Volume Control"), N_("Position Control"), N_("Ignore") };
  88. vlc_module_begin ()
  89.     set_shortname( N_("Hotkeys") )
  90.     set_description( N_("Hotkeys management interface") )
  91.     set_capability( "interface", 0 )
  92.     set_callbacks( Open, Close )
  93.     set_category( CAT_INTERFACE )
  94.     set_subcategory( SUBCAT_INTERFACE_HOTKEYS )
  95.     add_integer( "hotkeys-mousewheel-mode", MOUSEWHEEL_VOLUME, NULL,
  96.                  N_("MouseWheel x-axis Control"),
  97.                  N_("MouseWheel x-axis can control volume, position or "
  98.                     "mousewheel event can be ignored"), false )
  99.             change_integer_list( i_mode_list, psz_mode_list_text, NULL )
  100. vlc_module_end ()
  101. /*****************************************************************************
  102.  * Open: initialize interface
  103.  *****************************************************************************/
  104. static int Open( vlc_object_t *p_this )
  105. {
  106.     intf_thread_t *p_intf = (intf_thread_t *)p_this;
  107.     intf_sys_t *p_sys;
  108.     p_sys = malloc( sizeof( intf_sys_t ) );
  109.     if( !p_sys )
  110.         return VLC_ENOMEM;
  111.     p_intf->p_sys = p_sys;
  112.     p_intf->pf_run = Run;
  113.     p_sys->i_size = 0;
  114.     vlc_mutex_init( &p_sys->lock );
  115.     vlc_cond_init( &p_sys->wait );
  116.     p_intf->p_sys->i_mousewheel_mode =
  117.         config_GetInt( p_intf, "hotkeys-mousewheel-mode" );
  118.     var_AddCallback( p_intf->p_libvlc, "key-pressed", SpecialKeyEvent, p_intf );
  119.     var_AddCallback( p_intf->p_libvlc, "key-action", ActionEvent, p_intf );
  120.     return VLC_SUCCESS;
  121. }
  122. /*****************************************************************************
  123.  * Close: destroy interface
  124.  *****************************************************************************/
  125. static void Close( vlc_object_t *p_this )
  126. {
  127.     intf_thread_t *p_intf = (intf_thread_t *)p_this;
  128.     intf_sys_t *p_sys = p_intf->p_sys;
  129.     var_DelCallback( p_intf->p_libvlc, "key-action", ActionEvent, p_intf );
  130.     var_DelCallback( p_intf->p_libvlc, "key-pressed", SpecialKeyEvent, p_intf );
  131.     vlc_cond_destroy( &p_sys->wait );
  132.     vlc_mutex_destroy( &p_sys->lock );
  133.     /* Destroy structure */
  134.     free( p_intf->p_sys );
  135. }
  136. /*****************************************************************************
  137.  * Run: main loop
  138.  *****************************************************************************/
  139. static void Run( intf_thread_t *p_intf )
  140. {
  141.     vout_thread_t *p_vout = NULL;
  142.     aout_instance_t *p_aout = NULL;
  143.     playlist_t *p_playlist = pl_Hold( p_intf );
  144.     int canc = vlc_savecancel();
  145.     vlc_cleanup_push( __pl_Release, p_intf );
  146.     for( ;; )
  147.     {
  148.         input_thread_t *p_input;
  149.         vout_thread_t *p_last_vout;
  150.         int i_action;
  151.         vlc_restorecancel( canc );
  152.         i_action = GetAction( p_intf );
  153.         canc = vlc_savecancel();
  154.         /* Update the input */
  155.         p_input = playlist_CurrentInput( p_playlist );
  156.         /* Update the vout */
  157.         p_last_vout = p_vout;
  158.         p_vout = p_input ? input_GetVout( p_input ) : NULL;
  159.         /* Update the aout */
  160.         p_aout = p_input ? input_GetAout( p_input ) : NULL;
  161.         /* Register OSD channels */
  162.         if( p_vout && p_vout != p_last_vout )
  163.         {
  164.             int i;
  165.             for( i = 0; i < CHANNELS_NUMBER; i++ )
  166.             {
  167.                 spu_Control( p_vout->p_spu, SPU_CHANNEL_REGISTER,
  168.                              &p_intf->p_sys->p_channels[ i ] );
  169.             }
  170.         }
  171.         /* Quit */
  172.         if( i_action == ACTIONID_QUIT )
  173.         {
  174.             libvlc_Quit( p_intf->p_libvlc );
  175.             ClearChannels( p_intf, p_vout );
  176.             vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Quit" ) );
  177.             goto cleanup_and_continue;
  178.         }
  179.         /* Volume and audio actions */
  180.         else if( i_action == ACTIONID_VOL_UP )
  181.         {
  182.             audio_volume_t i_newvol;
  183.             aout_VolumeUp( p_intf, 1, &i_newvol );
  184.             DisplayVolume( p_intf, p_vout, i_newvol );
  185.         }
  186.         else if( i_action == ACTIONID_VOL_DOWN )
  187.         {
  188.             audio_volume_t i_newvol;
  189.             aout_VolumeDown( p_intf, 1, &i_newvol );
  190.             DisplayVolume( p_intf, p_vout, i_newvol );
  191.         }
  192.         else if( i_action == ACTIONID_VOL_MUTE )
  193.         {
  194.             audio_volume_t i_newvol = -1;
  195.             aout_VolumeMute( p_intf, &i_newvol );
  196.             if( p_vout )
  197.             {
  198.                 if( i_newvol == 0 )
  199.                 {
  200.                     ClearChannels( p_intf, p_vout );
  201.                     vout_OSDIcon( VLC_OBJECT( p_intf ), DEFAULT_CHAN,
  202.                                   OSD_MUTE_ICON );
  203.                 }
  204.                 else
  205.                 {
  206.                     DisplayVolume( p_intf, p_vout, i_newvol );
  207.                 }
  208.             }
  209.         }
  210.         /* Interface showing */
  211.         else if( i_action == ACTIONID_INTF_SHOW )
  212.             var_SetBool( p_intf->p_libvlc, "intf-show", true );
  213.         else if( i_action == ACTIONID_INTF_HIDE )
  214.             var_SetBool( p_intf->p_libvlc, "intf-show", false );
  215.         /* Video Output actions */
  216.         else if( i_action == ACTIONID_SNAPSHOT )
  217.         {
  218.             if( p_vout ) var_TriggerCallback( p_vout, "video-snapshot" );
  219.         }
  220.         else if( i_action == ACTIONID_TOGGLE_FULLSCREEN )
  221.         {
  222.             vlc_object_t *obj = p_vout ? VLC_OBJECT(p_vout)
  223.                                        : VLC_OBJECT(p_playlist);
  224.             bool b = var_GetBool( obj, "fullscreen" );
  225.             var_SetBool( obj, "fullscreen", !b );
  226.         }
  227.         else if( i_action == ACTIONID_LEAVE_FULLSCREEN )
  228.         {
  229.             if( p_vout && var_GetBool( p_vout, "fullscreen" ) )
  230.             {
  231.                 var_SetBool( p_vout, "fullscreen", false );
  232.             }
  233.         }
  234.         else if( i_action == ACTIONID_ZOOM_QUARTER ||
  235.                  i_action == ACTIONID_ZOOM_HALF ||
  236.                  i_action == ACTIONID_ZOOM_ORIGINAL ||
  237.                  i_action == ACTIONID_ZOOM_DOUBLE )
  238.         {
  239.             if( p_vout )
  240.             {
  241.                 float f;
  242.                 switch( i_action )
  243.                 {
  244.                     case ACTIONID_ZOOM_QUARTER:  f = 0.25; break;
  245.                     case ACTIONID_ZOOM_HALF:     f = 0.5;  break;
  246.                     case ACTIONID_ZOOM_ORIGINAL: f = 1.;   break;
  247.                      /*case ACTIONID_ZOOM_DOUBLE:*/
  248.                     default:                     f = 2.;   break;
  249.                 }
  250.                 var_SetFloat( p_vout, "zoom", f );
  251.             }
  252.         }
  253. #ifdef WIN32
  254.         else if( i_action == ACTIONID_WALLPAPER )
  255.         {   /* FIXME: this is invalid if not using DirectX output!!! */
  256.             vlc_object_t *obj = p_vout ? VLC_OBJECT(p_vout)
  257.                                        : VLC_OBJECT(p_playlist);
  258.             bool b = var_GetBool( obj, "directx-wallpaper" );
  259.             var_SetBool( obj, "directx-wallpaper", !b );
  260.         }
  261. #endif
  262.         /* Playlist actions */
  263.         else if( i_action == ACTIONID_LOOP )
  264.         {
  265.             /* Toggle Normal -> Loop -> Repeat -> Normal ... */
  266.             if( var_GetBool( p_playlist, "repeat" ) )
  267.                 var_SetBool( p_playlist, "repeat", false );
  268.             else
  269.             if( var_GetBool( p_playlist, "loop" ) )
  270.             { /* FIXME: this is not atomic, we should use a real tristate */
  271.                 var_SetBool( p_playlist, "loop", false );
  272.                 var_SetBool( p_playlist, "repeat", true );
  273.             }
  274.             else
  275.                 var_SetBool( p_playlist, "loop", true );
  276.         }
  277.         else if( i_action == ACTIONID_RANDOM )
  278.         {
  279.             bool b = var_GetBool( p_playlist, "random" );
  280.             var_SetBool( p_playlist, "random", !b );
  281.         }
  282.         else if( i_action == ACTIONID_PLAY_PAUSE )
  283.         {
  284.             if( p_input )
  285.             {
  286.                 ClearChannels( p_intf, p_vout );
  287.                 int state = var_GetInteger( p_input, "state" );
  288.                 if( state != PAUSE_S )
  289.                 {
  290.                     vout_OSDIcon( VLC_OBJECT( p_intf ), DEFAULT_CHAN,
  291.                                   OSD_PAUSE_ICON );
  292.                     state = PAUSE_S;
  293.                 }
  294.                 else
  295.                 {
  296.                     vout_OSDIcon( VLC_OBJECT( p_intf ), DEFAULT_CHAN,
  297.                                   OSD_PLAY_ICON );
  298.                     state = PLAYING_S;
  299.                 }
  300.                 var_SetInteger( p_input, "state", state );
  301.             }
  302.             else
  303.             {
  304.                 playlist_Play( p_playlist );
  305.             }
  306.         }
  307.         else if( ( i_action == ACTIONID_AUDIODEVICE_CYCLE ) && p_aout )
  308.         {
  309.             vlc_value_t val, list, list2;
  310.             int i_count, i;
  311.             var_Get( p_aout, "audio-device", &val );
  312.             var_Change( p_aout, "audio-device", VLC_VAR_GETCHOICES,
  313.                     &list, &list2 );
  314.             i_count = list.p_list->i_count;
  315.             if( i_count > 1 )
  316.             {
  317.                 for( i = 0; i < i_count; i++ )
  318.                 {
  319.                     if( val.i_int == list.p_list->p_values[i].i_int )
  320.                     {
  321.                         break;
  322.                     }
  323.                 }
  324.                 if( i == i_count )
  325.                 {
  326.                     msg_Warn( p_aout,
  327.                             "invalid current audio device, selecting 0" );
  328.                     var_Set( p_aout, "audio-device",
  329.                             list.p_list->p_values[0] );
  330.                     i = 0;
  331.                 }
  332.                 else if( i == i_count -1 )
  333.                 {
  334.                     var_Set( p_aout, "audio-device",
  335.                             list.p_list->p_values[0] );
  336.                     i = 0;
  337.                 }
  338.                 else
  339.                 {
  340.                     var_Set( p_aout, "audio-device",
  341.                             list.p_list->p_values[i+1] );
  342.                     i++;
  343.                 }
  344.                 vout_OSDMessage( p_intf, DEFAULT_CHAN,
  345.                         _("Audio Device: %s"),
  346.                         list2.p_list->p_values[i].psz_string);
  347.             }
  348.             var_Change( p_aout, "audio-device", VLC_VAR_FREELIST, &list,
  349.                         &list2 );
  350.         }
  351.         /* Input options */
  352.         else if( p_input )
  353.         {
  354.             bool b_seekable = var_GetBool( p_input, "can-seek" );
  355.             int i_interval =0;
  356.             if( i_action == ACTIONID_PAUSE )
  357.             {
  358.                 if( var_GetInteger( p_input, "state" ) != PAUSE_S )
  359.                 {
  360.                     ClearChannels( p_intf, p_vout );
  361.                     vout_OSDIcon( VLC_OBJECT( p_intf ), DEFAULT_CHAN,
  362.                                   OSD_PAUSE_ICON );
  363.                     var_SetInteger( p_input, "state", PAUSE_S );
  364.                 }
  365.             }
  366.             else if( i_action == ACTIONID_JUMP_BACKWARD_EXTRASHORT
  367.                      && b_seekable )
  368.             {
  369. #define SET_TIME( a, b ) 
  370.     i_interval = config_GetInt( p_input, a "-jump-size" ); 
  371.     if( i_interval > 0 ) { 
  372.         mtime_t i_time = (mtime_t)(i_interval * b) * 1000000L; 
  373.         var_SetTime( p_input, "time-offset", i_time ); 
  374.         DisplayPosition( p_intf, p_vout, p_input ); 
  375.     }
  376.                 SET_TIME( "extrashort", -1 );
  377.             }
  378.             else if( i_action == ACTIONID_JUMP_FORWARD_EXTRASHORT && b_seekable )
  379.             {
  380.                 SET_TIME( "extrashort", 1 );
  381.             }
  382.             else if( i_action == ACTIONID_JUMP_BACKWARD_SHORT && b_seekable )
  383.             {
  384.                 SET_TIME( "short", -1 );
  385.             }
  386.             else if( i_action == ACTIONID_JUMP_FORWARD_SHORT && b_seekable )
  387.             {
  388.                 SET_TIME( "short", 1 );
  389.             }
  390.             else if( i_action == ACTIONID_JUMP_BACKWARD_MEDIUM && b_seekable )
  391.             {
  392.                 SET_TIME( "medium", -1 );
  393.             }
  394.             else if( i_action == ACTIONID_JUMP_FORWARD_MEDIUM && b_seekable )
  395.             {
  396.                 SET_TIME( "medium", 1 );
  397.             }
  398.             else if( i_action == ACTIONID_JUMP_BACKWARD_LONG && b_seekable )
  399.             {
  400.                 SET_TIME( "long", -1 );
  401.             }
  402.             else if( i_action == ACTIONID_JUMP_FORWARD_LONG && b_seekable )
  403.             {
  404.                 SET_TIME( "long", 1 );
  405. #undef SET_TIME
  406.             }
  407.             else if( i_action == ACTIONID_AUDIO_TRACK )
  408.             {
  409.                 vlc_value_t val, list, list2;
  410.                 int i_count, i;
  411.                 var_Get( p_input, "audio-es", &val );
  412.                 var_Change( p_input, "audio-es", VLC_VAR_GETCHOICES,
  413.                             &list, &list2 );
  414.                 i_count = list.p_list->i_count;
  415.                 if( i_count > 1 )
  416.                 {
  417.                     for( i = 0; i < i_count; i++ )
  418.                     {
  419.                         if( val.i_int == list.p_list->p_values[i].i_int )
  420.                         {
  421.                             break;
  422.                         }
  423.                     }
  424.                     /* value of audio-es was not in choices list */
  425.                     if( i == i_count )
  426.                     {
  427.                         msg_Warn( p_input,
  428.                                   "invalid current audio track, selecting 0" );
  429.                         i = 0;
  430.                     }
  431.                     else if( i == i_count - 1 )
  432.                         i = 1;
  433.                     else
  434.                         i++;
  435.                     var_Set( p_input, "audio-es", list.p_list->p_values[i] );
  436.                     vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN,
  437.                                      _("Audio track: %s"),
  438.                                      list2.p_list->p_values[i].psz_string );
  439.                 }
  440.                 var_Change( p_input, "audio-es", VLC_VAR_FREELIST, &list,
  441.                             &list2 );
  442.             }
  443.             else if( i_action == ACTIONID_SUBTITLE_TRACK )
  444.             {
  445.                 vlc_value_t val, list, list2;
  446.                 int i_count, i;
  447.                 var_Get( p_input, "spu-es", &val );
  448.                 var_Change( p_input, "spu-es", VLC_VAR_GETCHOICES,
  449.                             &list, &list2 );
  450.                 i_count = list.p_list->i_count;
  451.                 if( i_count <= 1 )
  452.                 {
  453.                     vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN,
  454.                                      _("Subtitle track: %s"), _("N/A") );
  455.                     var_Change( p_input, "spu-es", VLC_VAR_FREELIST, &list,
  456.                                 &list2 );
  457.                     goto cleanup_and_continue;
  458.                 }
  459.                 for( i = 0; i < i_count; i++ )
  460.                 {
  461.                     if( val.i_int == list.p_list->p_values[i].i_int )
  462.                     {
  463.                         break;
  464.                     }
  465.                 }
  466.                 /* value of spu-es was not in choices list */
  467.                 if( i == i_count )
  468.                 {
  469.                     msg_Warn( p_input,
  470.                               "invalid current subtitle track, selecting 0" );
  471.                     i = 0;
  472.                 }
  473.                 else if( i == i_count - 1 )
  474.                     i = 0;
  475.                 else
  476.                     i++;
  477.                 var_Set( p_input, "spu-es", list.p_list->p_values[i] );
  478.                 vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN,
  479.                                  _("Subtitle track: %s"),
  480.                                  list2.p_list->p_values[i].psz_string );
  481.                 var_Change( p_input, "spu-es", VLC_VAR_FREELIST, &list,
  482.                             &list2 );
  483.             }
  484.             else if( i_action == ACTIONID_ASPECT_RATIO && p_vout )
  485.             {
  486.                 vlc_value_t val={0}, val_list, text_list;
  487.                 var_Get( p_vout, "aspect-ratio", &val );
  488.                 if( var_Change( p_vout, "aspect-ratio", VLC_VAR_GETLIST,
  489.                                 &val_list, &text_list ) >= 0 )
  490.                 {
  491.                     int i;
  492.                     for( i = 0; i < val_list.p_list->i_count; i++ )
  493.                     {
  494.                         if( !strcmp( val_list.p_list->p_values[i].psz_string,
  495.                                      val.psz_string ) )
  496.                         {
  497.                             i++;
  498.                             break;
  499.                         }
  500.                     }
  501.                     if( i == val_list.p_list->i_count ) i = 0;
  502.                     var_SetString( p_vout, "aspect-ratio",
  503.                                    val_list.p_list->p_values[i].psz_string );
  504.                     vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN,
  505.                                      _("Aspect ratio: %s"),
  506.                                      text_list.p_list->p_values[i].psz_string );
  507.                     var_Change( p_vout, "aspect-ratio", VLC_VAR_FREELIST, &val_list, &text_list );
  508.                 }
  509.                 free( val.psz_string );
  510.             }
  511.             else if( i_action == ACTIONID_CROP && p_vout )
  512.             {
  513.                 vlc_value_t val={0}, val_list, text_list;
  514.                 var_Get( p_vout, "crop", &val );
  515.                 if( var_Change( p_vout, "crop", VLC_VAR_GETLIST,
  516.                                 &val_list, &text_list ) >= 0 )
  517.                 {
  518.                     int i;
  519.                     for( i = 0; i < val_list.p_list->i_count; i++ )
  520.                     {
  521.                         if( !strcmp( val_list.p_list->p_values[i].psz_string,
  522.                                      val.psz_string ) )
  523.                         {
  524.                             i++;
  525.                             break;
  526.                         }
  527.                     }
  528.                     if( i == val_list.p_list->i_count ) i = 0;
  529.                     var_SetString( p_vout, "crop",
  530.                                    val_list.p_list->p_values[i].psz_string );
  531.                     vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN,
  532.                                      _("Crop: %s"),
  533.                                      text_list.p_list->p_values[i].psz_string );
  534.                     var_Change( p_vout, "crop", VLC_VAR_FREELIST, &val_list, &text_list );
  535.                 }
  536.                 free( val.psz_string );
  537.             }
  538.             else if( i_action == ACTIONID_TOGGLE_AUTOSCALE && p_vout )
  539.             {
  540.                 float f_scalefactor = var_GetFloat( p_vout, "scale" );
  541.                 if ( f_scalefactor != 1.0 )
  542.                 {
  543.                     var_SetFloat( p_vout, "scale", 1.0 );
  544.                     vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN,
  545.                                          "%s", _("Zooming reset") );
  546.                 }
  547.                 else
  548.                 {
  549.                     bool b_autoscale = !var_GetBool( p_vout, "autoscale" );
  550.                     var_SetBool( p_vout, "autoscale", b_autoscale );
  551.                     if( b_autoscale )
  552.                         vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN,
  553.                                          "%s", _("Scaled to screen") );
  554.                     else
  555.                         vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN,
  556.                                          "%s", _("Original Size") );
  557.                 }
  558.             }
  559.             else if( i_action == ACTIONID_SCALE_UP && p_vout )
  560.             {
  561.                float f_scalefactor;
  562.                f_scalefactor = var_GetFloat( p_vout, "scale" );
  563.                if( f_scalefactor < 10. )
  564.                    f_scalefactor += .1;
  565.                var_SetFloat( p_vout, "scale", f_scalefactor );
  566.             }
  567.             else if( i_action == ACTIONID_SCALE_DOWN && p_vout )
  568.             {
  569.                float f_scalefactor;
  570.                f_scalefactor = var_GetFloat( p_vout, "scale" );
  571.                if( f_scalefactor > .3 )
  572.                    f_scalefactor -= .1;
  573.                var_SetFloat( p_vout, "scale", f_scalefactor );
  574.             }
  575.             else if( i_action == ACTIONID_DEINTERLACE && p_vout )
  576.             {
  577.                 vlc_value_t val={0}, val_list, text_list;
  578.                 var_Get( p_vout, "deinterlace", &val );
  579.                 if( var_Change( p_vout, "deinterlace", VLC_VAR_GETLIST,
  580.                                 &val_list, &text_list ) >= 0 )
  581.                 {
  582.                     int i;
  583.                     for( i = 0; i < val_list.p_list->i_count; i++ )
  584.                     {
  585.                         if( !strcmp( val_list.p_list->p_values[i].psz_string,
  586.                                      val.psz_string ) )
  587.                         {
  588.                             i++;
  589.                             break;
  590.                         }
  591.                     }
  592.                     if( i == val_list.p_list->i_count ) i = 0;
  593.                     var_SetString( p_vout, "deinterlace",
  594.                                    val_list.p_list->p_values[i].psz_string );
  595.                     vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN,
  596.                                      _("Deinterlace mode: %s"),
  597.                                      text_list.p_list->p_values[i].psz_string );
  598.                     var_Change( p_vout, "deinterlace", VLC_VAR_FREELIST, &val_list, &text_list );
  599.                 }
  600.                 free( val.psz_string );
  601.             }
  602.             else if( ( i_action == ACTIONID_ZOOM || i_action == ACTIONID_UNZOOM ) && p_vout )
  603.             {
  604.                 vlc_value_t val={0}, val_list, text_list;
  605.                 var_Get( p_vout, "zoom", &val );
  606.                 if( var_Change( p_vout, "zoom", VLC_VAR_GETLIST,
  607.                                 &val_list, &text_list ) >= 0 )
  608.                 {
  609.                     int i;
  610.                     for( i = 0; i < val_list.p_list->i_count; i++ )
  611.                     {
  612.                         if( val_list.p_list->p_values[i].f_float
  613.                            == val.f_float )
  614.                         {
  615.                             if( i_action == ACTIONID_ZOOM )
  616.                                 i++;
  617.                             else /* ACTIONID_UNZOOM */
  618.                                 i--;
  619.                             break;
  620.                         }
  621.                     }
  622.                     if( i == val_list.p_list->i_count ) i = 0;
  623.                     if( i == -1 ) i = val_list.p_list->i_count-1;
  624.                     var_SetFloat( p_vout, "zoom",
  625.                                   val_list.p_list->p_values[i].f_float );
  626.                     vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN,
  627.                                      _("Zoom mode: %s"),
  628.                                 text_list.p_list->p_values[i].var.psz_name );
  629.                     var_Change( p_vout, "zoom", VLC_VAR_FREELIST, &val_list, &text_list );
  630.                 }
  631.             }
  632.             else if( i_action == ACTIONID_CROP_TOP && p_vout )
  633.                 var_IncInteger( p_vout, "crop-top" );
  634.             else if( i_action == ACTIONID_UNCROP_TOP && p_vout )
  635.                 var_DecInteger( p_vout, "crop-top" );
  636.             else if( i_action == ACTIONID_CROP_BOTTOM && p_vout )
  637.                 var_IncInteger( p_vout, "crop-bottom" );
  638.             else if( i_action == ACTIONID_UNCROP_BOTTOM && p_vout )
  639.                  var_DecInteger( p_vout, "crop-bottom" );
  640.             else if( i_action == ACTIONID_CROP_LEFT && p_vout )
  641.                  var_IncInteger( p_vout, "crop-left" );
  642.             else if( i_action == ACTIONID_UNCROP_LEFT && p_vout )
  643.                  var_DecInteger( p_vout, "crop-left" );
  644.             else if( i_action == ACTIONID_CROP_RIGHT && p_vout )
  645.                  var_IncInteger( p_vout, "crop-right" );
  646.             else if( i_action == ACTIONID_UNCROP_RIGHT && p_vout )
  647.                  var_DecInteger( p_vout, "crop-right" );
  648.             else if( i_action == ACTIONID_NEXT )
  649.             {
  650.                 vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN, "%s", _("Next") );
  651.                 playlist_Next( p_playlist );
  652.             }
  653.             else if( i_action == ACTIONID_PREV )
  654.             {
  655.                 vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN, "%s",
  656.                                  _("Previous") );
  657.                 playlist_Prev( p_playlist );
  658.             }
  659.             else if( i_action == ACTIONID_STOP )
  660.             {
  661.                 playlist_Stop( p_playlist );
  662.             }
  663.             else if( i_action == ACTIONID_FRAME_NEXT )
  664.             {
  665.                 var_SetVoid( p_input, "frame-next" );
  666.                 vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN,
  667.                                  "%s", _("Next frame") );
  668.             }
  669.             else if( i_action == ACTIONID_FASTER )
  670.             {
  671.                 var_SetVoid( p_input, "rate-faster" );
  672.                 vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN,
  673.                                  "%s", _("Faster") );
  674.             }
  675.             else if( i_action == ACTIONID_SLOWER )
  676.             {
  677.                 var_SetVoid( p_input, "rate-slower" );
  678.                 vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN,
  679.                                  "%s", _("Slower") );
  680.             }
  681.             else if( i_action == ACTIONID_RATE_NORMAL )
  682.             {
  683.                 var_SetInteger( p_input, "rate", INPUT_RATE_DEFAULT );
  684.                 vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN,
  685.                                  "%s", _("1.00x") );
  686.             }
  687.             else if( i_action == ACTIONID_RATE_FASTER_FINE ||
  688.                      i_action == ACTIONID_RATE_SLOWER_FINE )
  689.             {
  690.                 /* The playback rate is defined by INPUT_RATE_DEFAULT / "rate"
  691.                  * and we want to increase/decrease it by 0.1 while making sure
  692.                  * that the resulting playback rate is a multiple of 0.1
  693.                  */
  694.                 int i_rate = var_GetInteger( p_input, "rate" );
  695.                 if( i_rate == 0 )
  696.                     i_rate = INPUT_RATE_MIN;
  697.                 int i_sign = i_rate < 0 ? -1 : 1;
  698.                 const int i_dir = i_action == ACTIONID_RATE_FASTER_FINE ? 1 : -1;
  699.                 const double f_speed = floor( ( (double)INPUT_RATE_DEFAULT / abs(i_rate) + 0.05 ) / 0.1 + i_dir ) * 0.1;
  700.                 if( f_speed <= (double)INPUT_RATE_DEFAULT / INPUT_RATE_MAX ) /* Needed to avoid infinity */
  701.                     i_rate = INPUT_RATE_MAX;
  702.                 else
  703.                     i_rate = INPUT_RATE_DEFAULT / f_speed + 0.5;
  704.                 i_rate = i_sign * __MIN( __MAX( i_rate, INPUT_RATE_MIN ), INPUT_RATE_MAX );
  705.                 var_SetInteger( p_input, "rate", i_rate );
  706.                 char psz_msg[7+1];
  707.                 snprintf( psz_msg, sizeof(psz_msg), _("%.2fx"), (double)INPUT_RATE_DEFAULT / i_rate );
  708.                 vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN, "%s", psz_msg );
  709.             }
  710.             else if( i_action == ACTIONID_POSITION && b_seekable )
  711.             {
  712.                 DisplayPosition( p_intf, p_vout, p_input );
  713.             }
  714.             else if( i_action >= ACTIONID_PLAY_BOOKMARK1 &&
  715.                      i_action <= ACTIONID_PLAY_BOOKMARK10 )
  716.             {
  717.                 PlayBookmark( p_intf, i_action - ACTIONID_PLAY_BOOKMARK1 + 1 );
  718.             }
  719.             else if( i_action >= ACTIONID_SET_BOOKMARK1 &&
  720.                      i_action <= ACTIONID_SET_BOOKMARK10 )
  721.             {
  722.                 SetBookmark( p_intf, i_action - ACTIONID_SET_BOOKMARK1 + 1 );
  723.             }
  724.             /* Only makes sense with DVD */
  725.             else if( i_action == ACTIONID_TITLE_PREV )
  726.                 var_SetVoid( p_input, "prev-title" );
  727.             else if( i_action == ACTIONID_TITLE_NEXT )
  728.                 var_SetVoid( p_input, "next-title" );
  729.             else if( i_action == ACTIONID_CHAPTER_PREV )
  730.                 var_SetVoid( p_input, "prev-chapter" );
  731.             else if( i_action == ACTIONID_CHAPTER_NEXT )
  732.                 var_SetVoid( p_input, "next-chapter" );
  733.             else if( i_action == ACTIONID_DISC_MENU )
  734.                 var_SetInteger( p_input, "title  0", 2 );
  735.             else if( i_action == ACTIONID_SUBDELAY_DOWN )
  736.             {
  737.                 int64_t i_delay = var_GetTime( p_input, "spu-delay" );
  738.                 i_delay -= 50000;    /* 50 ms */
  739.                 var_SetTime( p_input, "spu-delay", i_delay );
  740.                 ClearChannels( p_intf, p_vout );
  741.                 vout_OSDMessage( p_intf, DEFAULT_CHAN,
  742.                                  _( "Subtitle delay %i ms" ),
  743.                                  (int)(i_delay/1000) );
  744.             }
  745.             else if( i_action == ACTIONID_SUBDELAY_UP )
  746.             {
  747.                 int64_t i_delay = var_GetTime( p_input, "spu-delay" );
  748.                 i_delay += 50000;    /* 50 ms */
  749.                 var_SetTime( p_input, "spu-delay", i_delay );
  750.                 ClearChannels( p_intf, p_vout );
  751.                 vout_OSDMessage( p_intf, DEFAULT_CHAN,
  752.                                 _( "Subtitle delay %i ms" ),
  753.                                  (int)(i_delay/1000) );
  754.             }
  755.             else if( i_action == ACTIONID_AUDIODELAY_DOWN )
  756.             {
  757.                 int64_t i_delay = var_GetTime( p_input, "audio-delay" );
  758.                 i_delay -= 50000;    /* 50 ms */
  759.                 var_SetTime( p_input, "audio-delay", i_delay );
  760.                 ClearChannels( p_intf, p_vout );
  761.                 vout_OSDMessage( p_intf, DEFAULT_CHAN,
  762.                                 _( "Audio delay %i ms" ),
  763.                                  (int)(i_delay/1000) );
  764.             }
  765.             else if( i_action == ACTIONID_AUDIODELAY_UP )
  766.             {
  767.                 int64_t i_delay = var_GetTime( p_input, "audio-delay" );
  768.                 i_delay += 50000;    /* 50 ms */
  769.                 var_SetTime( p_input, "audio-delay", i_delay );
  770.                 ClearChannels( p_intf, p_vout );
  771.                 vout_OSDMessage( p_intf, DEFAULT_CHAN,
  772.                                 _( "Audio delay %i ms" ),
  773.                                  (int)(i_delay/1000) );
  774.             }
  775.             else if( i_action == ACTIONID_PLAY )
  776.             {
  777.                 if( var_GetInteger( p_input, "rate" ) != INPUT_RATE_DEFAULT )
  778.                     /* Return to normal speed */
  779.                     var_SetInteger( p_input, "rate", INPUT_RATE_DEFAULT );
  780.                 else
  781.                 {
  782.                     ClearChannels( p_intf, p_vout );
  783.                     vout_OSDIcon( VLC_OBJECT( p_intf ), DEFAULT_CHAN,
  784.                                   OSD_PLAY_ICON );
  785.                     playlist_Play( p_playlist );
  786.                 }
  787.             }
  788.             else if( i_action == ACTIONID_MENU_ON )
  789.             {
  790.                 osd_MenuShow( VLC_OBJECT(p_intf) );
  791.             }
  792.             else if( i_action == ACTIONID_MENU_OFF )
  793.             {
  794.                 osd_MenuHide( VLC_OBJECT(p_intf) );
  795.             }
  796.             else if( i_action == ACTIONID_MENU_LEFT )
  797.             {
  798.                 osd_MenuPrev( VLC_OBJECT(p_intf) );
  799.             }
  800.             else if( i_action == ACTIONID_MENU_RIGHT )
  801.             {
  802.                 osd_MenuNext( VLC_OBJECT(p_intf) );
  803.             }
  804.             else if( i_action == ACTIONID_MENU_UP )
  805.             {
  806.                 osd_MenuUp( VLC_OBJECT(p_intf) );
  807.             }
  808.             else if( i_action == ACTIONID_MENU_DOWN )
  809.             {
  810.                 osd_MenuDown( VLC_OBJECT(p_intf) );
  811.             }
  812.             else if( i_action == ACTIONID_MENU_SELECT )
  813.             {
  814.                 osd_MenuActivate( VLC_OBJECT(p_intf) );
  815.             }
  816.             else if( i_action == ACTIONID_RECORD )
  817.             {
  818.                 if( var_GetBool( p_input, "can-record" ) )
  819.                 {
  820.                     const bool b_record = !var_GetBool( p_input, "record" );
  821.                     if( b_record )
  822.                         vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _("Recording") );
  823.                     else
  824.                         vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _("Recording done") );
  825.                     var_SetBool( p_input, "record", b_record );
  826.                 }
  827.             }
  828.         }
  829. cleanup_and_continue:
  830.         if( p_aout )
  831.             vlc_object_release( p_aout );
  832.         if( p_vout )
  833.             vlc_object_release( p_vout );
  834.         if( p_input )
  835.             vlc_object_release( p_input );
  836.     }
  837.     /* dead code */
  838.     abort();
  839.     vlc_cleanup_pop();
  840. }
  841. static int GetAction( intf_thread_t *p_intf )
  842. {
  843.     intf_sys_t *p_sys = p_intf->p_sys;
  844.     int i_ret;
  845.     vlc_mutex_lock( &p_sys->lock );
  846.     mutex_cleanup_push( &p_sys->lock );
  847.     while( p_sys->i_size == 0 )
  848.         vlc_cond_wait( &p_sys->wait, &p_sys->lock );
  849.     i_ret = p_sys->p_actions[ 0 ];
  850.     p_sys->i_size--;
  851.     for( int i = 0; i < p_sys->i_size; i++ )
  852.         p_sys->p_actions[i] = p_sys->p_actions[i + 1];
  853.     vlc_cleanup_run();
  854.     return i_ret;
  855. }
  856. static int PutAction( intf_thread_t *p_intf, int i_action )
  857. {
  858.     intf_sys_t *p_sys = p_intf->p_sys;
  859.     int i_ret = VLC_EGENERIC;
  860.     vlc_mutex_lock( &p_sys->lock );
  861.     if ( p_sys->i_size >= BUFFER_SIZE )
  862.         msg_Warn( p_intf, "event buffer full, dropping key actions" );
  863.     else
  864.         p_sys->p_actions[p_sys->i_size++] = i_action;
  865.     vlc_cond_signal( &p_sys->wait );
  866.     vlc_mutex_unlock( &p_sys->lock );
  867.     return i_ret;
  868. }
  869. /*****************************************************************************
  870.  * SpecialKeyEvent: callback for mouse events
  871.  *****************************************************************************/
  872. static int SpecialKeyEvent( vlc_object_t *libvlc, char const *psz_var,
  873.                             vlc_value_t oldval, vlc_value_t newval,
  874.                             void *p_data )
  875. {
  876.     intf_thread_t *p_intf = (intf_thread_t *)p_data;
  877.     int i_action = 0;
  878.     (void)psz_var;
  879.     (void)oldval;
  880.     int i_mode = p_intf->p_sys->i_mousewheel_mode;
  881.     /* Special action for mouse event */
  882.     /* FIXME: rework hotkeys handling to allow more than 1 event
  883.      * to trigger one same action */
  884.     switch (newval.i_int & KEY_SPECIAL)
  885.     {
  886.         case KEY_MOUSEWHEELUP:
  887.             i_action = (i_mode == MOUSEWHEEL_VOLUME ) ? ACTIONID_VOL_UP
  888.                                  : ACTIONID_JUMP_FORWARD_EXTRASHORT;
  889.             break;
  890.         case KEY_MOUSEWHEELDOWN:
  891.             i_action = (i_mode == MOUSEWHEEL_VOLUME ) ? ACTIONID_VOL_DOWN
  892.                                 : ACTIONID_JUMP_BACKWARD_EXTRASHORT;
  893.             break;
  894.         case KEY_MOUSEWHEELLEFT:
  895.             i_action = (i_mode == MOUSEWHEEL_VOLUME ) ?
  896.                         ACTIONID_JUMP_BACKWARD_EXTRASHORT : ACTIONID_VOL_DOWN;
  897.             break;
  898.         case KEY_MOUSEWHEELRIGHT:
  899.             i_action = (i_mode == MOUSEWHEEL_VOLUME ) ?
  900.                         ACTIONID_JUMP_FORWARD_EXTRASHORT : ACTIONID_VOL_UP;
  901.             break;
  902.         case KEY_MENU:
  903.             var_SetBool( libvlc, "intf-popupmenu", true );
  904.             break;
  905.         default:
  906.           return VLC_SUCCESS;
  907.     }
  908.     if( i_mode == NO_MOUSEWHEEL ) return VLC_SUCCESS;
  909.     if( i_action )
  910.         return PutAction( p_intf, i_action );
  911.     return VLC_SUCCESS;
  912. }
  913. /*****************************************************************************
  914.  * ActionEvent: callback for hotkey actions
  915.  *****************************************************************************/
  916. static int ActionEvent( vlc_object_t *libvlc, char const *psz_var,
  917.                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
  918. {
  919.     intf_thread_t *p_intf = (intf_thread_t *)p_data;
  920.     (void)libvlc;
  921.     (void)psz_var;
  922.     (void)oldval;
  923.     return PutAction( p_intf, newval.i_int );
  924. }
  925. static void PlayBookmark( intf_thread_t *p_intf, int i_num )
  926. {
  927.     char *psz_bookmark_name;
  928.     if( asprintf( &psz_bookmark_name, "bookmark%i", i_num ) == -1 )
  929.         return;
  930.     playlist_t *p_playlist = pl_Hold( p_intf );
  931.     char *psz_bookmark = var_CreateGetString( p_intf, psz_bookmark_name );
  932.     PL_LOCK;
  933.     FOREACH_ARRAY( playlist_item_t *p_item, p_playlist->items )
  934.         char *psz_uri = input_item_GetURI( p_item->p_input );
  935.         if( !strcmp( psz_bookmark, psz_uri ) )
  936.         {
  937.             free( psz_uri );
  938.             playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, pl_Locked,
  939.                               NULL, p_item );
  940.             break;
  941.         }
  942.         else
  943.             free( psz_uri );
  944.     FOREACH_END();
  945.     PL_UNLOCK;
  946.     free( psz_bookmark );
  947.     free( psz_bookmark_name );
  948.     pl_Release( p_intf );
  949. }
  950. static void SetBookmark( intf_thread_t *p_intf, int i_num )
  951. {
  952.     char *psz_bookmark_name;
  953.     if( asprintf( &psz_bookmark_name, "bookmark%i", i_num ) == -1 )
  954.         return;
  955.     playlist_t *p_playlist = pl_Hold( p_intf );
  956.     var_Create( p_intf, psz_bookmark_name,
  957.                 VLC_VAR_STRING|VLC_VAR_DOINHERIT );
  958.     playlist_item_t * p_item = playlist_CurrentPlayingItem( p_playlist );
  959.     if( p_item )
  960.     {
  961.         char *psz_uri = input_item_GetURI( p_item->p_input );
  962.         config_PutPsz( p_intf, psz_bookmark_name, psz_uri);
  963.         msg_Info( p_intf, "setting playlist bookmark %i to %s", i_num, psz_uri);
  964.         free( psz_uri );
  965.         config_SaveConfigFile( p_intf, "hotkeys" );
  966.     }
  967.     pl_Release( p_intf );
  968.     free( psz_bookmark_name );
  969. }
  970. static void DisplayPosition( intf_thread_t *p_intf, vout_thread_t *p_vout,
  971.                              input_thread_t *p_input )
  972. {
  973.     char psz_duration[MSTRTIME_MAX_SIZE];
  974.     char psz_time[MSTRTIME_MAX_SIZE];
  975.     vlc_value_t time, pos;
  976.     mtime_t i_seconds;
  977.     if( p_vout == NULL ) return;
  978.     ClearChannels( p_intf, p_vout );
  979.     var_Get( p_input, "time", &time );
  980.     i_seconds = time.i_time / 1000000;
  981.     secstotimestr ( psz_time, i_seconds );
  982.     var_Get( p_input, "length", &time );
  983.     if( time.i_time > 0 )
  984.     {
  985.         secstotimestr( psz_duration, time.i_time / 1000000 );
  986.         vout_OSDMessage( p_input, POSITION_TEXT_CHAN, "%s / %s",
  987.                          psz_time, psz_duration );
  988.     }
  989.     else if( i_seconds > 0 )
  990.     {
  991.         vout_OSDMessage( p_input, POSITION_TEXT_CHAN, "%s", psz_time );
  992.     }
  993.     if( var_GetBool( p_vout, "fullscreen" ) )
  994.     {
  995.         var_Get( p_input, "position", &pos );
  996.         vout_OSDSlider( VLC_OBJECT( p_input ), POSITION_WIDGET_CHAN,
  997.                         pos.f_float * 100, OSD_HOR_SLIDER );
  998.     }
  999. }
  1000. static void DisplayVolume( intf_thread_t *p_intf, vout_thread_t *p_vout,
  1001.                            audio_volume_t i_vol )
  1002. {
  1003.     if( p_vout == NULL )
  1004.     {
  1005.         return;
  1006.     }
  1007.     ClearChannels( p_intf, p_vout );
  1008.     if( var_GetBool( p_vout, "fullscreen" ) )
  1009.     {
  1010.         vout_OSDSlider( VLC_OBJECT( p_vout ), VOLUME_WIDGET_CHAN,
  1011.             i_vol*100/AOUT_VOLUME_MAX, OSD_VERT_SLIDER );
  1012.     }
  1013.     else
  1014.     {
  1015.         vout_OSDMessage( p_vout, VOLUME_TEXT_CHAN, _( "Volume %d%%" ),
  1016.                          i_vol*400/AOUT_VOLUME_MAX );
  1017.     }
  1018. }
  1019. static void ClearChannels( intf_thread_t *p_intf, vout_thread_t *p_vout )
  1020. {
  1021.     int i;
  1022.     if( p_vout )
  1023.     {
  1024.         spu_Control( p_vout->p_spu, SPU_CHANNEL_CLEAR, DEFAULT_CHAN );
  1025.         for( i = 0; i < CHANNELS_NUMBER; i++ )
  1026.         {
  1027.             spu_Control( p_vout->p_spu, SPU_CHANNEL_CLEAR,
  1028.                          p_intf->p_sys->p_channels[ i ] );
  1029.         }
  1030.     }
  1031. }