X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fcontrol%2Fhotkeys.c;h=25af282ad4e838a8b6473165e2533a09352787f1;hb=637278c0e0aef709cf752d7f537cfea23353453f;hp=423542c672aab6031dd5b60e59bea97e04ba1f03;hpb=6d032d9e5b01c12d4edc5e2e241e17117973f7c3;p=vlc diff --git a/modules/control/hotkeys.c b/modules/control/hotkeys.c index 423542c672..25af282ad4 100644 --- a/modules/control/hotkeys.c +++ b/modules/control/hotkeys.c @@ -1,7 +1,7 @@ /***************************************************************************** * hotkeys.c: Hotkey handling for vlc ***************************************************************************** - * Copyright (C) 2005 the VideoLAN team + * Copyright (C) 2005-2009 the VideoLAN team * $Id$ * * Authors: Sigmund Augdal Helberg @@ -25,40 +25,37 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include /* malloc(), free() */ -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include #include #include #include -#include +#include #include #include -#include "vlc_keys.h" - -#define BUFFER_SIZE 10 +#include +#include "math.h" #define CHANNELS_NUMBER 4 #define VOLUME_TEXT_CHAN p_intf->p_sys->p_channels[ 0 ] #define VOLUME_WIDGET_CHAN p_intf->p_sys->p_channels[ 1 ] #define POSITION_TEXT_CHAN p_intf->p_sys->p_channels[ 2 ] #define POSITION_WIDGET_CHAN p_intf->p_sys->p_channels[ 3 ] + /***************************************************************************** * intf_sys_t: description and status of FB interface *****************************************************************************/ struct intf_sys_t { - vlc_mutex_t change_lock; /* mutex to keep the callback - * and the main loop from - * stepping on each others - * toes */ - int p_keys[ BUFFER_SIZE ]; /* buffer that contains - * keyevents */ - int i_size; /* number of events in buffer */ + vout_thread_t *p_last_vout; int p_channels[ CHANNELS_NUMBER ]; /* contains registered * channel IDs */ - input_thread_t * p_input; /* pointer to input */ - vout_thread_t * p_vout; /* pointer to vout object */ + int i_mousewheel_mode; }; /***************************************************************************** @@ -66,39 +63,54 @@ struct intf_sys_t *****************************************************************************/ static int Open ( vlc_object_t * ); static void Close ( vlc_object_t * ); -static void Run ( intf_thread_t * ); -static int GetKey ( intf_thread_t *); -static int KeyEvent( vlc_object_t *, char const *, - vlc_value_t, vlc_value_t, void * ); -static int ActionKeyCB( vlc_object_t *, char const *, +static int ActionEvent( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * ); +static int SpecialKeyEvent( vlc_object_t *, char const *, + vlc_value_t, vlc_value_t, void * ); static void PlayBookmark( intf_thread_t *, int ); static void SetBookmark ( intf_thread_t *, int ); static void DisplayPosition( intf_thread_t *, vout_thread_t *, input_thread_t * ); -static void DisplayVolume ( intf_thread_t *, vout_thread_t *, audio_volume_t ); +static void DisplayVolume( intf_thread_t *, vout_thread_t *, float ); +static void DisplayRate ( vout_thread_t *, float ); +static float AdjustRateFine( input_thread_t *, const int ); static void ClearChannels ( intf_thread_t *, vout_thread_t * ); +#define DisplayMessage(vout, ch, fmt, ...) \ + do { if(vout) vout_OSDMessage(vout, ch, fmt, __VA_ARGS__); } while(0) +#define DisplayIcon(vout, icon) \ + do { if(vout) vout_OSDIcon(vout, SPU_DEFAULT_CHANNEL, icon); } while(0) + /***************************************************************************** * Module descriptor *****************************************************************************/ -#define BOOKMARK1_TEXT N_("Playlist bookmark 1") -#define BOOKMARK2_TEXT N_("Playlist bookmark 2") -#define BOOKMARK3_TEXT N_("Playlist bookmark 3") -#define BOOKMARK4_TEXT N_("Playlist bookmark 4") -#define BOOKMARK5_TEXT N_("Playlist bookmark 5") -#define BOOKMARK6_TEXT N_("Playlist bookmark 6") -#define BOOKMARK7_TEXT N_("Playlist bookmark 7") -#define BOOKMARK8_TEXT N_("Playlist bookmark 8") -#define BOOKMARK9_TEXT N_("Playlist bookmark 9") -#define BOOKMARK10_TEXT N_("Playlist bookmark 10") -#define BOOKMARK_LONGTEXT N_("Define playlist bookmarks.") - -vlc_module_begin(); - set_shortname( _("Hotkeys") ); - set_description( _("Hotkeys management interface") ); - set_capability( "interface", 0 ); - set_callbacks( Open, Close ); -vlc_module_end(); + +enum{ + MOUSEWHEEL_VOLUME, + MOUSEWHEEL_POSITION, + NO_MOUSEWHEEL, +}; + +static const int i_mode_list[] = + { MOUSEWHEEL_VOLUME, MOUSEWHEEL_POSITION, NO_MOUSEWHEEL }; + +static const char *const psz_mode_list_text[] = + { N_("Volume Control"), N_("Position Control"), N_("Ignore") }; + +vlc_module_begin () + set_shortname( N_("Hotkeys") ) + set_description( N_("Hotkeys management interface") ) + set_capability( "interface", 0 ) + set_callbacks( Open, Close ) + set_category( CAT_INTERFACE ) + set_subcategory( SUBCAT_INTERFACE_HOTKEYS ) + + add_integer( "hotkeys-mousewheel-mode", MOUSEWHEEL_VOLUME, + N_("MouseWheel up-down axis Control"), + N_("The MouseWheel up-down (vertical) axis can control volume, position or " + "mousewheel event can be ignored"), false ) + change_integer_list( i_mode_list, psz_mode_list_text ) + +vlc_module_end () /***************************************************************************** * Open: initialize interface @@ -106,13 +118,20 @@ vlc_module_end(); static int Open( vlc_object_t *p_this ) { intf_thread_t *p_intf = (intf_thread_t *)p_this; - MALLOC_ERR( p_intf->p_sys, intf_sys_t ); + intf_sys_t *p_sys; + p_sys = malloc( sizeof( intf_sys_t ) ); + if( !p_sys ) + return VLC_ENOMEM; + + p_intf->p_sys = p_sys; + p_intf->pf_run = NULL; - vlc_mutex_init( p_intf, &p_intf->p_sys->change_lock ); - p_intf->p_sys->i_size = 0; - p_intf->pf_run = Run; + p_sys->p_last_vout = NULL; + p_intf->p_sys->i_mousewheel_mode = + var_InheritInteger( p_intf, "hotkeys-mousewheel-mode" ); - var_AddCallback( p_intf->p_libvlc, "key-pressed", KeyEvent, p_intf ); + var_AddCallback( p_intf->p_libvlc, "key-pressed", SpecialKeyEvent, p_intf ); + var_AddCallback( p_intf->p_libvlc, "key-action", ActionEvent, p_intf ); return VLC_SUCCESS; } @@ -122,268 +141,258 @@ static int Open( vlc_object_t *p_this ) static void Close( vlc_object_t *p_this ) { intf_thread_t *p_intf = (intf_thread_t *)p_this; + intf_sys_t *p_sys = p_intf->p_sys; - var_DelCallback( p_intf->p_libvlc, "key-pressed", KeyEvent, p_intf ); + var_DelCallback( p_intf->p_libvlc, "key-action", ActionEvent, p_intf ); + var_DelCallback( p_intf->p_libvlc, "key-pressed", SpecialKeyEvent, p_intf ); - vlc_mutex_destroy( &p_intf->p_sys->change_lock ); /* Destroy structure */ - free( p_intf->p_sys ); + free( p_sys ); } -/***************************************************************************** - * Run: main loop - *****************************************************************************/ -static void Run( intf_thread_t *p_intf ) +static int PutAction( intf_thread_t *p_intf, int i_action ) { - input_thread_t *p_input = NULL; - vout_thread_t *p_vout = NULL; - vout_thread_t *p_last_vout = NULL; - struct hotkey *p_hotkeys = p_intf->p_libvlc->p_hotkeys; - vlc_value_t val; - int i; - playlist_t *p_playlist = pl_Yield( p_intf ); - - /* Initialize hotkey structure */ - for( i = 0; p_hotkeys[i].psz_action != NULL; i++ ) - { - var_Create( p_intf->p_libvlc, p_hotkeys[i].psz_action, - VLC_VAR_HOTKEY | VLC_VAR_DOINHERIT ); + intf_sys_t *p_sys = p_intf->p_sys; + playlist_t *p_playlist = pl_Get( p_intf ); - var_AddCallback( p_intf->p_libvlc, p_hotkeys[i].psz_action, - ActionKeyCB, NULL ); - var_Get( p_intf->p_libvlc, p_hotkeys[i].psz_action, &val ); - var_Set( p_intf->p_libvlc, p_hotkeys[i].psz_action, val ); - } + /* Update the input */ + input_thread_t *p_input = playlist_CurrentInput( p_playlist ); - while( !intf_ShouldDie( p_intf ) ) - { - int i_key, i_action; - int i_times = 0; + /* Update the vout */ + vout_thread_t *p_vout = p_input ? input_GetVout( p_input ) : NULL; + + /* Update the aout */ + vlc_object_t *p_aout = p_input ? (vlc_object_t *)input_GetAout( p_input ) : NULL; - /* Sleep a bit */ - /* msleep( INTF_IDLE_SLEEP ); */ + /* Register OSD channels */ + /* FIXME: this check can fail if the new vout is reallocated at the same + * address as the old one... We should rather listen to vout events. + * Alternatively, we should keep a reference to the vout thread. */ + if( p_vout && p_vout != p_sys->p_last_vout ) + for( unsigned i = 0; i < CHANNELS_NUMBER; i++ ) + p_intf->p_sys->p_channels[i] = vout_RegisterSubpictureChannel( p_vout ); + p_sys->p_last_vout = p_vout; - i_action = 0; - i_key = GetKey( p_intf ); + /* Quit */ + switch( i_action ) + { + case ACTIONID_QUIT: + libvlc_Quit( p_intf->p_libvlc ); - /* Special action for mouse event */ - /* FIXME: This should probably be configurable */ - /* FIXME: rework hotkeys handling to allow more than 1 event - * to trigger one same action */ - switch (i_key & KEY_SPECIAL) + ClearChannels( p_intf, p_vout ); + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, "%s", _( "Quit" ) ); + break; + + /* Volume and audio actions */ + case ACTIONID_VOL_UP: { - case KEY_MOUSEWHEELUP: - i_action = ACTIONID_VOL_UP; - break; - case KEY_MOUSEWHEELDOWN: - i_action = ACTIONID_VOL_DOWN; - break; - case KEY_MOUSEWHEELLEFT: - i_action = ACTIONID_JUMP_BACKWARD_EXTRASHORT; - break; - case KEY_MOUSEWHEELRIGHT: - i_action = ACTIONID_JUMP_FORWARD_EXTRASHORT; - break; - default: break; + float vol; + if( aout_VolumeUp( p_playlist, 1, &vol ) == 0 ) + DisplayVolume( p_intf, p_vout, vol ); + break; } - /* No mouse action, find action triggered by hotkey */ - if(!i_action) + case ACTIONID_VOL_DOWN: { - for( i = 0; i_key != -1 && p_hotkeys[i].psz_action != NULL; i++ ) + float vol; + if( aout_VolumeDown( p_playlist, 1, &vol ) == 0 ) + DisplayVolume( p_intf, p_vout, vol ); + break; + } + + case ACTIONID_VOL_MUTE: + if( aout_MuteToggle( p_playlist ) == 0 ) { - if( p_hotkeys[i].i_key == i_key ) + float vol = aout_VolumeGet( p_playlist ); + if( aout_MuteGet( p_playlist ) > 0 || vol == 0.f ) { - i_action = p_hotkeys[i].i_action; - i_times = p_hotkeys[i].i_times; - /* times key pressed within max. delta time */ - p_hotkeys[i].i_times = 0; - break; + ClearChannels( p_intf, p_vout ); + DisplayIcon( p_vout, OSD_MUTE_ICON ); } + else + DisplayVolume( p_intf, p_vout, vol ); } - } + break; - if( !i_action ) - { - vlc_mutex_lock( &p_intf->object_lock ); - vlc_cond_wait( &p_intf->object_wait, &p_intf->object_lock ); - vlc_mutex_unlock( &p_intf->object_lock ); - /* No key pressed, sleep a bit more */ -// msleep( INTF_IDLE_SLEEP ); - continue; - } + /* Interface showing */ + case ACTIONID_INTF_TOGGLE_FSC: + case ACTIONID_INTF_HIDE: + var_TriggerCallback( p_intf->p_libvlc, "intf-toggle-fscontrol" ); + break; - /* Update the input */ - PL_LOCK; - p_input = p_playlist->p_input; - if( p_input ) - vlc_object_yield( p_input ); - PL_UNLOCK; + case ACTIONID_INTF_BOSS: + var_TriggerCallback( p_intf->p_libvlc, "intf-boss" ); + break; - /* Update the vout */ - p_last_vout = p_vout; - p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE ); + /* Video Output actions */ + case ACTIONID_SNAPSHOT: + if( p_vout ) + var_TriggerCallback( p_vout, "video-snapshot" ); + break; - /* Register OSD channels */ - if( p_vout && p_vout != p_last_vout ) + case ACTIONID_TOGGLE_FULLSCREEN: { - for( i = 0; i < CHANNELS_NUMBER; i++ ) - { - spu_Control( p_vout->p_spu, SPU_CHANNEL_REGISTER, - &p_intf->p_sys->p_channels[ i ] ); - } + bool fs = var_ToggleBool( p_playlist, "fullscreen" ); + if( p_vout ) + var_SetBool( p_vout, "fullscreen", fs ); + break; } - if( i_action == ACTIONID_QUIT ) - { - p_intf->p_libvlc->b_die = VLC_TRUE; - ClearChannels( p_intf, p_vout ); - vout_OSDMessage( p_intf, DEFAULT_CHAN, _( "Quit" ) ); + case ACTIONID_LEAVE_FULLSCREEN: if( p_vout ) - vlc_object_release( p_vout ); - if( p_input ) - vlc_object_release( p_input ); - continue; - } - else if( i_action == ACTIONID_VOL_UP ) - { - audio_volume_t i_newvol; - aout_VolumeUp( p_intf, 1, &i_newvol ); - DisplayVolume( p_intf, p_vout, i_newvol ); - } - else if( i_action == ACTIONID_VOL_DOWN ) - { - audio_volume_t i_newvol; - aout_VolumeDown( p_intf, 1, &i_newvol ); - DisplayVolume( p_intf, p_vout, i_newvol ); - } - else if( i_action == ACTIONID_VOL_MUTE ) - { - audio_volume_t i_newvol = -1; - aout_VolumeMute( p_intf, &i_newvol ); + var_SetBool( p_vout, "fullscreen", false ); + var_SetBool( p_playlist, "fullscreen", false ); + break; + + case ACTIONID_ZOOM_QUARTER: + case ACTIONID_ZOOM_HALF: + case ACTIONID_ZOOM_ORIGINAL: + case ACTIONID_ZOOM_DOUBLE: if( p_vout ) { - if( i_newvol == 0 ) - { - ClearChannels( p_intf, p_vout ); - vout_OSDIcon( VLC_OBJECT( p_intf ), DEFAULT_CHAN, - OSD_MUTE_ICON ); - } - else + float f; + switch( i_action ) { - DisplayVolume( p_intf, p_vout, i_newvol ); + case ACTIONID_ZOOM_QUARTER: f = 0.25; break; + case ACTIONID_ZOOM_HALF: f = 0.5; break; + case ACTIONID_ZOOM_ORIGINAL: f = 1.; break; + /*case ACTIONID_ZOOM_DOUBLE:*/ + default: f = 2.; break; } + var_SetFloat( p_vout, "zoom", f ); } + break; + + case ACTIONID_WALLPAPER: + { /* FIXME: this is invalid if not using DirectX output!!! */ + vlc_object_t *obj = p_vout ? VLC_OBJECT(p_vout) + : VLC_OBJECT(p_playlist); + var_ToggleBool( obj, "video-wallpaper" ); + break; } - else if( i_action == ACTIONID_INTF_SHOW ) - var_SetBool( p_playlist, "intf-show", VLC_TRUE ); - else if( i_action == ACTIONID_INTF_HIDE ) - var_SetBool( p_playlist, "intf-show", VLC_FALSE ); - else if( i_action == ACTIONID_SNAPSHOT ) - { - if( p_vout ) vout_Control( p_vout, VOUT_SNAPSHOT ); - } - else if( i_action == ACTIONID_FULLSCREEN ) - { - if( p_vout ) - { - var_Get( p_vout, "fullscreen", &val ); - val.b_bool = !val.b_bool; - var_Set( p_vout, "fullscreen", val ); - } + + /* Playlist actions */ + case ACTIONID_LOOP: + /* Toggle Normal -> Loop -> Repeat -> Normal ... */ + if( var_GetBool( p_playlist, "repeat" ) ) + var_SetBool( p_playlist, "repeat", false ); else - { - var_Get( p_playlist, "fullscreen", &val ); - val.b_bool = !val.b_bool; - var_Set( p_playlist, "fullscreen", val ); + if( var_GetBool( p_playlist, "loop" ) ) + { /* FIXME: this is not atomic, we should use a real tristate */ + var_SetBool( p_playlist, "loop", false ); + var_SetBool( p_playlist, "repeat", true ); } - } - else if( i_action == ACTIONID_LOOP ) + else + var_SetBool( p_playlist, "loop", true ); + break; + + case ACTIONID_RANDOM: { - /* Toggle Normal -> Loop -> Repeat -> Normal ... */ - vlc_value_t val2; - var_Get( p_playlist, "loop", &val ); - var_Get( p_playlist, "repeat", &val2 ); - if( val2.b_bool == VLC_TRUE ) - { - val.b_bool = VLC_FALSE; - val2.b_bool = VLC_FALSE; - } - else if( val.b_bool == VLC_TRUE ) + var_ToggleBool( p_playlist, "random" ); + break; + } + + case ACTIONID_PLAY_PAUSE: + if( p_input ) { - val.b_bool = VLC_FALSE; - val2.b_bool = VLC_TRUE; + ClearChannels( p_intf, p_vout ); + + int state = var_GetInteger( p_input, "state" ); + DisplayIcon( p_vout, state != PAUSE_S ? OSD_PAUSE_ICON : OSD_PLAY_ICON ); + playlist_Pause( p_playlist ); } + else + playlist_Play( p_playlist ); + break; + + case ACTIONID_PLAY: + if( p_input && var_GetFloat( p_input, "rate" ) != 1. ) + /* Return to normal speed */ + var_SetFloat( p_input, "rate", 1. ); else { - val.b_bool = VLC_TRUE; + ClearChannels( p_intf, p_vout ); + DisplayIcon( p_vout, OSD_PLAY_ICON ); + playlist_Play( p_playlist ); } - var_Set( p_playlist, "loop", val ); - var_Set( p_playlist, "repeat", val2 ); - } - else if( i_action == ACTIONID_RANDOM ) - { - var_Get( p_playlist, "random", &val ); - val.b_bool = !val.b_bool; - var_Set( p_playlist, "random", val ); - } - else if( i_action == ACTIONID_PLAY_PAUSE ) + break; + + case ACTIONID_AUDIODEVICE_CYCLE: { - val.i_int = PLAYING_S; - if( p_input ) - { - ClearChannels( p_intf, p_vout ); + if( !p_aout ) + break; - var_Get( p_input, "state", &val ); - if( val.i_int != PAUSE_S ) + vlc_value_t val, list, list2; + int i_count, i; + + var_Get( p_aout, "audio-device", &val ); + var_Change( p_aout, "audio-device", VLC_VAR_GETCHOICES, + &list, &list2 ); + i_count = list.p_list->i_count; + + if( i_count > 1 ) + { + for( i = 0; i < i_count; i++ ) { - vout_OSDIcon( VLC_OBJECT( p_intf ), DEFAULT_CHAN, - OSD_PAUSE_ICON ); - val.i_int = PAUSE_S; + if( val.i_int == list.p_list->p_values[i].i_int ) + { + break; + } + } + if( i == i_count ) + { + msg_Warn( p_aout, + "invalid current audio device, selecting 0" ); + var_Set( p_aout, "audio-device", + list.p_list->p_values[0] ); + i = 0; + } + else if( i == i_count -1 ) + { + var_Set( p_aout, "audio-device", + list.p_list->p_values[0] ); + i = 0; } else { - vout_OSDIcon( VLC_OBJECT( p_intf ), DEFAULT_CHAN, - OSD_PLAY_ICON ); - val.i_int = PLAYING_S; + var_Set( p_aout, "audio-device", + list.p_list->p_values[i+1] ); + i++; } - var_Set( p_input, "state", val ); - } - else - { - playlist_Play( p_playlist ); + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, + _("Audio Device: %s"), + list2.p_list->p_values[i].psz_string); } + var_FreeList( &list, &list2 ); + break; } - else if( p_input ) + + /* Input options */ + default: { - /* FIXME --fenrir - * How to get a valid value ? - * That's not that easy with some special stream - */ - vlc_bool_t b_seekable = VLC_TRUE; + if( !p_input ) + break; + + bool b_seekable = var_GetBool( p_input, "can-seek" ); int i_interval =0; if( i_action == ACTIONID_PAUSE ) { - var_Get( p_input, "state", &val ); - if( val.i_int != PAUSE_S ) + if( var_GetInteger( p_input, "state" ) != PAUSE_S ) { ClearChannels( p_intf, p_vout ); - vout_OSDIcon( VLC_OBJECT( p_intf ), DEFAULT_CHAN, - OSD_PAUSE_ICON ); - val.i_int = PAUSE_S; - var_Set( p_input, "state", val ); + DisplayIcon( p_vout, OSD_PAUSE_ICON ); + var_SetInteger( p_input, "state", PAUSE_S ); } } else if( i_action == ACTIONID_JUMP_BACKWARD_EXTRASHORT && b_seekable ) { #define SET_TIME( a, b ) \ - i_interval = config_GetInt( p_input, a "-jump-size" ); \ + i_interval = var_InheritInteger( p_input, a "-jump-size" ); \ if( i_interval > 0 ) { \ - val.i_time = ( (mtime_t)(i_interval * b) * 1000000L \ - * ((mtime_t)(1 << i_times))); \ - var_Set( p_input, "time-offset", val ); \ + mtime_t i_time = (mtime_t)(i_interval * b) * 1000000L; \ + var_SetTime( p_input, "time-offset", i_time ); \ DisplayPosition( p_intf, p_vout, p_input ); \ } SET_TIME( "extrashort", -1 ); @@ -425,9 +434,48 @@ static void Run( intf_thread_t *p_intf ) var_Change( p_input, "audio-es", VLC_VAR_GETCHOICES, &list, &list2 ); i_count = list.p_list->i_count; + if( i_count > 1 ) + { + for( i = 0; i < i_count; i++ ) + { + if( val.i_int == list.p_list->p_values[i].i_int ) + { + break; + } + } + /* value of audio-es was not in choices list */ + if( i == i_count ) + { + msg_Warn( p_input, + "invalid current audio track, selecting 0" ); + i = 0; + } + else if( i == i_count - 1 ) + i = 1; + else + i++; + var_Set( p_input, "audio-es", list.p_list->p_values[i] ); + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, + _("Audio track: %s"), + list2.p_list->p_values[i].psz_string ); + } + var_FreeList( &list, &list2 ); + } + else if( i_action == ACTIONID_SUBTITLE_TRACK ) + { + vlc_value_t val, list, list2; + int i_count, i; + var_Get( p_input, "spu-es", &val ); + + var_Change( p_input, "spu-es", VLC_VAR_GETCHOICES, + &list, &list2 ); + i_count = list.p_list->i_count; if( i_count <= 1 ) { - continue; + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, + _("Subtitle track: %s"), _("N/A") ); + var_FreeList( &list, &list2 ); + goto cleanup_and_continue; } for( i = 0; i < i_count; i++ ) { @@ -436,45 +484,38 @@ static void Run( intf_thread_t *p_intf ) break; } } - /* value of audio-es was not in choices list */ + /* value of spu-es was not in choices list */ if( i == i_count ) { msg_Warn( p_input, - "invalid current audio track, selecting 0" ); - var_Set( p_input, "audio-es", - list.p_list->p_values[0] ); + "invalid current subtitle track, selecting 0" ); i = 0; } else if( i == i_count - 1 ) - { - var_Set( p_input, "audio-es", - list.p_list->p_values[1] ); - i = 1; - } + i = 0; else - { - var_Set( p_input, "audio-es", - list.p_list->p_values[i+1] ); i++; - } - vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN, - _("Audio track: %s"), - list2.p_list->p_values[i].psz_string ); + var_Set( p_input, "spu-es", list.p_list->p_values[i] ); + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, + _("Subtitle track: %s"), + list2.p_list->p_values[i].psz_string ); + var_FreeList( &list, &list2 ); } - else if( i_action == ACTIONID_SUBTITLE_TRACK ) + else if( i_action == ACTIONID_PROGRAM_SID ) { vlc_value_t val, list, list2; int i_count, i; - var_Get( p_input, "spu-es", &val ); + var_Get( p_input, "program", &val ); - var_Change( p_input, "spu-es", VLC_VAR_GETCHOICES, + var_Change( p_input, "program", VLC_VAR_GETCHOICES, &list, &list2 ); i_count = list.p_list->i_count; if( i_count <= 1 ) { - vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN, - _("Subtitle track: %s"), _("N/A") ); - continue; + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, + _("Program Service ID: %s"), _("N/A") ); + var_FreeList( &list, &list2 ); + goto cleanup_and_continue; } for( i = 0; i < i_count; i++ ) { @@ -483,27 +524,22 @@ static void Run( intf_thread_t *p_intf ) break; } } - /* value of spu-es was not in choices list */ + /* value of program was not in choices list */ if( i == i_count ) { msg_Warn( p_input, - "invalid current subtitle track, selecting 0" ); - var_Set( p_input, "spu-es", list.p_list->p_values[0] ); + "invalid current program SID, selecting 0" ); i = 0; } else if( i == i_count - 1 ) - { - var_Set( p_input, "spu-es", list.p_list->p_values[0] ); i = 0; - } else - { - var_Set( p_input, "spu-es", list.p_list->p_values[i+1] ); - i = i + 1; - } - vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN, - _("Subtitle track: %s"), - list2.p_list->p_values[i].psz_string ); + i++; + var_Set( p_input, "program", list.p_list->p_values[i] ); + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, + _("Program Service ID: %s"), + list2.p_list->p_values[i].psz_string ); + var_FreeList( &list, &list2 ); } else if( i_action == ACTIONID_ASPECT_RATIO && p_vout ) { @@ -525,9 +561,11 @@ static void Run( intf_thread_t *p_intf ) if( i == val_list.p_list->i_count ) i = 0; var_SetString( p_vout, "aspect-ratio", val_list.p_list->p_values[i].psz_string ); - vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN, - _("Aspect ratio: %s"), - text_list.p_list->p_values[i].psz_string ); + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, + _("Aspect ratio: %s"), + text_list.p_list->p_values[i].psz_string ); + + var_FreeList( &val_list, &text_list ); } free( val.psz_string ); } @@ -551,39 +589,89 @@ static void Run( intf_thread_t *p_intf ) if( i == val_list.p_list->i_count ) i = 0; var_SetString( p_vout, "crop", val_list.p_list->p_values[i].psz_string ); - vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN, - _("Crop: %s"), - text_list.p_list->p_values[i].psz_string ); + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, + _("Crop: %s"), + text_list.p_list->p_values[i].psz_string ); + + var_FreeList( &val_list, &text_list ); } free( val.psz_string ); } + else if( i_action == ACTIONID_TOGGLE_AUTOSCALE && p_vout ) + { + float f_scalefactor = var_GetFloat( p_vout, "scale" ); + if ( f_scalefactor != 1.0 ) + { + var_SetFloat( p_vout, "scale", 1.0 ); + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, + "%s", _("Zooming reset") ); + } + else + { + bool b_autoscale = !var_GetBool( p_vout, "autoscale" ); + var_SetBool( p_vout, "autoscale", b_autoscale ); + if( b_autoscale ) + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, + "%s", _("Scaled to screen") ); + else + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, + "%s", _("Original Size") ); + } + } + else if( i_action == ACTIONID_SCALE_UP && p_vout ) + { + float f_scalefactor; + + f_scalefactor = var_GetFloat( p_vout, "scale" ); + if( f_scalefactor < 10. ) + f_scalefactor += .1; + var_SetFloat( p_vout, "scale", f_scalefactor ); + } + else if( i_action == ACTIONID_SCALE_DOWN && p_vout ) + { + float f_scalefactor; + + f_scalefactor = var_GetFloat( p_vout, "scale" ); + if( f_scalefactor > .3 ) + f_scalefactor -= .1; + var_SetFloat( p_vout, "scale", f_scalefactor ); + } else if( i_action == ACTIONID_DEINTERLACE && p_vout ) { - vlc_value_t val={0}, val_list, text_list; - var_Get( p_vout, "deinterlace", &val ); - if( var_Change( p_vout, "deinterlace", VLC_VAR_GETLIST, - &val_list, &text_list ) >= 0 ) + int i_deinterlace = var_GetInteger( p_vout, "deinterlace" ); + if( i_deinterlace != 0 ) { - int i; - for( i = 0; i < val_list.p_list->i_count; i++ ) + var_SetInteger( p_vout, "deinterlace", 0 ); + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, + "%s", _("Deinterlace off") ); + } + else + { + var_SetInteger( p_vout, "deinterlace", 1 ); + + char *psz_mode = var_GetString( p_vout, "deinterlace-mode" ); + vlc_value_t vlist, tlist; + if( psz_mode && !var_Change( p_vout, "deinterlace-mode", VLC_VAR_GETCHOICES, &vlist, &tlist ) >= 0 ) { - if( !strcmp( val_list.p_list->p_values[i].psz_string, - val.psz_string ) ) + const char *psz_text = NULL; + for( int i = 0; i < vlist.p_list->i_count; i++ ) { - i++; - break; + if( !strcmp( vlist.p_list->p_values[i].psz_string, psz_mode ) ) + { + psz_text = tlist.p_list->p_values[i].psz_string; + break; + } } + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, + "%s (%s)", _("Deinterlace on"), psz_text ? psz_text : psz_mode ); + + var_FreeList( &vlist, &tlist ); } - if( i == val_list.p_list->i_count ) i = 0; - var_SetString( p_vout, "deinterlace", - val_list.p_list->p_values[i].psz_string ); - vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN, - _("Deinterlace mode: %s"), - text_list.p_list->p_values[i].psz_string ); + free( psz_mode ); } - free( val.psz_string ); } - else if( ( i_action == ACTIONID_ZOOM || i_action == ACTIONID_UNZOOM ) && p_vout ) + else if( ( i_action == ACTIONID_ZOOM || + i_action == ACTIONID_UNZOOM ) && p_vout ) { vlc_value_t val={0}, val_list, text_list; var_Get( p_vout, "zoom", &val ); @@ -607,9 +695,11 @@ static void Run( intf_thread_t *p_intf ) if( i == -1 ) i = val_list.p_list->i_count-1; var_SetFloat( p_vout, "zoom", val_list.p_list->p_values[i].f_float ); - vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN, - _("Zoom mode: %s"), - text_list.p_list->p_values[i].var.psz_name ); + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, + _("Zoom mode: %s"), + text_list.p_list->p_values[i].psz_string ); + + var_FreeList( &val_list, &text_list ); } } else if( i_action == ACTIONID_CROP_TOP && p_vout ) @@ -631,34 +721,53 @@ static void Run( intf_thread_t *p_intf ) else if( i_action == ACTIONID_NEXT ) { - vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN, _("Next") ); + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Next") ); playlist_Next( p_playlist ); } else if( i_action == ACTIONID_PREV ) { - vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN, - _("Previous") ); + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, "%s", + _("Previous") ); playlist_Prev( p_playlist ); } else if( i_action == ACTIONID_STOP ) { playlist_Stop( p_playlist ); } + else if( i_action == ACTIONID_FRAME_NEXT ) + { + var_TriggerCallback( p_input, "frame-next" ); + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, + "%s", _("Next frame") ); + } + else if( i_action == ACTIONID_RATE_NORMAL ) + { + var_SetFloat( p_playlist, "rate", 1. ); + DisplayRate( p_vout, var_GetFloat( p_input, "rate" ) ); + } else if( i_action == ACTIONID_FASTER ) { - var_SetVoid( p_input, "rate-faster" ); - vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN, - _("Faster") ); + var_TriggerCallback( p_playlist, "rate-faster" ); + DisplayRate( p_vout, var_GetFloat( p_input, "rate" ) ); } else if( i_action == ACTIONID_SLOWER ) { - var_SetVoid( p_input, "rate-slower" ); - vout_OSDMessage( VLC_OBJECT(p_input), DEFAULT_CHAN, - _("Slower") ); + var_TriggerCallback( p_playlist, "rate-slower" ); + DisplayRate( p_vout, var_GetFloat( p_input, "rate" ) ); } - else if( i_action == ACTIONID_POSITION && b_seekable ) + else if( i_action == ACTIONID_RATE_FASTER_FINE || + i_action == ACTIONID_RATE_SLOWER_FINE ) { - DisplayPosition( p_intf, p_vout, p_input ); + const int i_dir = i_action == ACTIONID_RATE_FASTER_FINE ? 1 : -1; + float f_newrate = AdjustRateFine( p_input, i_dir ); + + var_SetFloat( p_playlist, "rate", f_newrate ); + DisplayRate( p_vout, f_newrate ); + } + else if( i_action == ACTIONID_POSITION ) + { + if( ( !p_vout || vout_OSDEpg( p_vout, input_GetItem( p_input ) ) ) && b_seekable ) + DisplayPosition( p_intf, p_vout, p_input ); } else if( i_action >= ACTIONID_PLAY_BOOKMARK1 && i_action <= ACTIONID_PLAY_BOOKMARK10 ) @@ -672,13 +781,13 @@ static void Run( intf_thread_t *p_intf ) } /* Only makes sense with DVD */ else if( i_action == ACTIONID_TITLE_PREV ) - var_SetVoid( p_input, "prev-title" ); + var_TriggerCallback( p_input, "prev-title" ); else if( i_action == ACTIONID_TITLE_NEXT ) - var_SetVoid( p_input, "next-title" ); + var_TriggerCallback( p_input, "next-title" ); else if( i_action == ACTIONID_CHAPTER_PREV ) - var_SetVoid( p_input, "prev-chapter" ); + var_TriggerCallback( p_input, "prev-chapter" ); else if( i_action == ACTIONID_CHAPTER_NEXT ) - var_SetVoid( p_input, "next-chapter" ); + var_TriggerCallback( p_input, "next-chapter" ); else if( i_action == ACTIONID_DISC_MENU ) var_SetInteger( p_input, "title 0", 2 ); @@ -688,9 +797,9 @@ static void Run( intf_thread_t *p_intf ) i_delay -= 50000; /* 50 ms */ var_SetTime( p_input, "spu-delay", i_delay ); ClearChannels( p_intf, p_vout ); - vout_OSDMessage( p_intf, DEFAULT_CHAN, - _( "Subtitle delay %i ms" ), - (int)(i_delay/1000) ); + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, + _( "Subtitle delay %i ms" ), + (int)(i_delay/1000) ); } else if( i_action == ACTIONID_SUBDELAY_UP ) { @@ -698,17 +807,31 @@ static void Run( intf_thread_t *p_intf ) i_delay += 50000; /* 50 ms */ var_SetTime( p_input, "spu-delay", i_delay ); ClearChannels( p_intf, p_vout ); - vout_OSDMessage( p_intf, DEFAULT_CHAN, + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, _( "Subtitle delay %i ms" ), (int)(i_delay/1000) ); } + else if( ( i_action == ACTIONID_SUBPOS_DOWN || + i_action == ACTIONID_SUBPOS_UP ) && p_vout ) + { + int i_pos; + if( i_action == ACTIONID_SUBPOS_DOWN ) + i_pos = var_DecInteger( p_vout, "sub-margin" ); + else + i_pos = var_IncInteger( p_vout, "sub-margin" ); + + ClearChannels( p_intf, p_vout ); + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, + _( "Subtitle position %i px" ), + (int)(i_pos) ); + } else if( i_action == ACTIONID_AUDIODELAY_DOWN ) { int64_t i_delay = var_GetTime( p_input, "audio-delay" ); i_delay -= 50000; /* 50 ms */ var_SetTime( p_input, "audio-delay", i_delay ); ClearChannels( p_intf, p_vout ); - vout_OSDMessage( p_intf, DEFAULT_CHAN, + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, _( "Audio delay %i ms" ), (int)(i_delay/1000) ); } @@ -718,156 +841,177 @@ static void Run( intf_thread_t *p_intf ) i_delay += 50000; /* 50 ms */ var_SetTime( p_input, "audio-delay", i_delay ); ClearChannels( p_intf, p_vout ); - vout_OSDMessage( p_intf, DEFAULT_CHAN, + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, _( "Audio delay %i ms" ), (int)(i_delay/1000) ); } - else if( i_action == ACTIONID_PLAY ) + else if( i_action == ACTIONID_MENU_ON ) { - var_Get( p_input, "rate", &val ); - if( val.i_int != INPUT_RATE_DEFAULT ) - { - /* Return to normal speed */ - var_SetInteger( p_input, "rate", INPUT_RATE_DEFAULT ); - } - else + osd_MenuShow( VLC_OBJECT(p_intf) ); + } + else if( i_action == ACTIONID_MENU_OFF ) + { + osd_MenuHide( VLC_OBJECT(p_intf) ); + } + else if( i_action == ACTIONID_MENU_LEFT ) + { + osd_MenuPrev( VLC_OBJECT(p_intf) ); + } + else if( i_action == ACTIONID_MENU_RIGHT ) + { + osd_MenuNext( VLC_OBJECT(p_intf) ); + } + else if( i_action == ACTIONID_MENU_UP ) + { + osd_MenuUp( VLC_OBJECT(p_intf) ); + } + else if( i_action == ACTIONID_MENU_DOWN ) + { + osd_MenuDown( VLC_OBJECT(p_intf) ); + } + else if( i_action == ACTIONID_MENU_SELECT ) + { + osd_MenuActivate( VLC_OBJECT(p_intf) ); + } + else if( i_action == ACTIONID_RECORD ) + { + if( var_GetBool( p_input, "can-record" ) ) { - ClearChannels( p_intf, p_vout ); - vout_OSDIcon( VLC_OBJECT( p_intf ), DEFAULT_CHAN, - OSD_PLAY_ICON ); - playlist_Play( p_playlist ); + const bool b_record = var_ToggleBool( p_input, "record" ); + + if( b_record ) + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Recording") ); + else + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Recording done") ); } } } - if( p_vout ) - vlc_object_release( p_vout ); - if( p_input ) - vlc_object_release( p_input ); - } - pl_Release( p_intf ); -} - -static int GetKey( intf_thread_t *p_intf) -{ - vlc_mutex_lock( &p_intf->p_sys->change_lock ); - if ( p_intf->p_sys->i_size == 0 ) - { - vlc_mutex_unlock( &p_intf->p_sys->change_lock ); - return -1; - } - else - { - int i_return = p_intf->p_sys->p_keys[ 0 ]; - int i; - p_intf->p_sys->i_size--; - for ( i = 0; i < BUFFER_SIZE - 1; i++) - { - p_intf->p_sys->p_keys[ i ] = p_intf->p_sys->p_keys[ i + 1 ]; - } - vlc_mutex_unlock( &p_intf->p_sys->change_lock ); - return i_return; } +cleanup_and_continue: + if( p_aout ) + vlc_object_release( p_aout ); + if( p_vout ) + vlc_object_release( p_vout ); + if( p_input ) + vlc_object_release( p_input ); + return VLC_SUCCESS; } /***************************************************************************** - * KeyEvent: callback for keyboard events + * SpecialKeyEvent: callback for mouse events *****************************************************************************/ -static int KeyEvent( vlc_object_t *p_this, char const *psz_var, - vlc_value_t oldval, vlc_value_t newval, void *p_data ) +static int SpecialKeyEvent( vlc_object_t *libvlc, char const *psz_var, + vlc_value_t oldval, vlc_value_t newval, + void *p_data ) { intf_thread_t *p_intf = (intf_thread_t *)p_data; - if ( !newval.i_int ) - { - msg_Warn( p_this, "Received invalid key event %d", newval.i_int ); - return VLC_EGENERIC; - } - vlc_mutex_lock( &p_intf->p_sys->change_lock ); - if ( p_intf->p_sys->i_size == BUFFER_SIZE ) - { - msg_Warn( p_intf, "event buffer full, dropping keypress" ); - vlc_mutex_unlock( &p_intf->p_sys->change_lock ); - return VLC_EGENERIC; - } - else + int i_action = 0; + + (void)psz_var; + (void)oldval; + + int i_mode = p_intf->p_sys->i_mousewheel_mode; + + /* Special action for mouse event */ + /* FIXME: rework hotkeys handling to allow more than 1 event + * to trigger one same action */ + switch (newval.i_int & ~KEY_MODIFIER) { - p_intf->p_sys->p_keys[ p_intf->p_sys->i_size ] = newval.i_int; - p_intf->p_sys->i_size++; + case KEY_MOUSEWHEELUP: + i_action = (i_mode == MOUSEWHEEL_VOLUME ) ? ACTIONID_VOL_UP + : ACTIONID_JUMP_FORWARD_EXTRASHORT; + break; + case KEY_MOUSEWHEELDOWN: + i_action = (i_mode == MOUSEWHEEL_VOLUME ) ? ACTIONID_VOL_DOWN + : ACTIONID_JUMP_BACKWARD_EXTRASHORT; + break; + case KEY_MOUSEWHEELLEFT: + i_action = (i_mode == MOUSEWHEEL_VOLUME ) ? + ACTIONID_JUMP_BACKWARD_EXTRASHORT : ACTIONID_VOL_DOWN; + break; + case KEY_MOUSEWHEELRIGHT: + i_action = (i_mode == MOUSEWHEEL_VOLUME ) ? + ACTIONID_JUMP_FORWARD_EXTRASHORT : ACTIONID_VOL_UP; + break; + case KEY_MENU: + var_SetBool( libvlc, "intf-popupmenu", true ); + break; } - vlc_mutex_lock( &p_intf->object_lock ); - vlc_cond_signal( &p_intf->object_wait ); - vlc_mutex_unlock( &p_intf->object_lock ); - vlc_mutex_unlock( &p_intf->p_sys->change_lock ); + if( i_mode == NO_MOUSEWHEEL ) return VLC_SUCCESS; + + if( i_action ) + return PutAction( p_intf, i_action ); return VLC_SUCCESS; } -static int ActionKeyCB( vlc_object_t *p_this, char const *psz_var, +/***************************************************************************** + * ActionEvent: callback for hotkey actions + *****************************************************************************/ +static int ActionEvent( vlc_object_t *libvlc, char const *psz_var, vlc_value_t oldval, vlc_value_t newval, void *p_data ) { - libvlc_int_t *p_libvlc = (libvlc_int_t *)p_this; - struct hotkey *p_hotkeys = p_libvlc->p_hotkeys; - mtime_t i_date; - int i; + intf_thread_t *p_intf = (intf_thread_t *)p_data; - for( i = 0; p_hotkeys[i].psz_action != NULL; i++ ) - { - if( !strcmp( p_hotkeys[i].psz_action, psz_var ) ) - { - p_hotkeys[i].i_key = newval.i_int; - /* do hotkey accounting */ - i_date = mdate(); - if( (p_hotkeys[i].i_delta_date > 0) && - (p_hotkeys[i].i_delta_date <= (i_date - p_hotkeys[i].i_last_date) ) ) - p_hotkeys[i].i_times = 0; - else - p_hotkeys[i].i_times++; - p_hotkeys[i].i_last_date = i_date; - } - } + (void)libvlc; + (void)psz_var; + (void)oldval; - return VLC_SUCCESS; + return PutAction( p_intf, newval.i_int ); } static void PlayBookmark( intf_thread_t *p_intf, int i_num ) { - vlc_value_t val; - char psz_bookmark_name[11]; - playlist_t *p_playlist = pl_Yield( p_intf ); + char *psz_bookmark_name; + if( asprintf( &psz_bookmark_name, "bookmark%i", i_num ) == -1 ) + return; - sprintf( psz_bookmark_name, "bookmark%i", i_num ); - var_Create( p_intf, psz_bookmark_name, VLC_VAR_STRING|VLC_VAR_DOINHERIT ); - var_Get( p_intf, psz_bookmark_name, &val ); + playlist_t *p_playlist = pl_Get( p_intf ); + char *psz_bookmark = var_CreateGetString( p_intf, psz_bookmark_name ); - char *psz_bookmark = strdup( val.psz_string ); PL_LOCK; FOREACH_ARRAY( playlist_item_t *p_item, p_playlist->items ) - if( !strcmp( psz_bookmark, p_item->p_input->psz_uri ) ) + char *psz_uri = input_item_GetURI( p_item->p_input ); + if( !strcmp( psz_bookmark, psz_uri ) ) { - playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, VLC_TRUE, + free( psz_uri ); + playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, pl_Locked, NULL, p_item ); break; } + else + free( psz_uri ); FOREACH_END(); PL_UNLOCK; - vlc_object_release( p_playlist ); + + free( psz_bookmark ); + free( psz_bookmark_name ); } static void SetBookmark( intf_thread_t *p_intf, int i_num ) { - playlist_t *p_playlist = pl_Yield( p_intf ); - char psz_bookmark_name[11]; - sprintf( psz_bookmark_name, "bookmark%i", i_num ); + char *psz_bookmark_name; + char *psz_uri = NULL; + if( asprintf( &psz_bookmark_name, "bookmark%i", i_num ) == -1 ) + return; + + playlist_t *p_playlist = pl_Get( p_intf ); var_Create( p_intf, psz_bookmark_name, VLC_VAR_STRING|VLC_VAR_DOINHERIT ); - if( p_playlist->status.p_item ) + + PL_LOCK; + playlist_item_t * p_item = playlist_CurrentPlayingItem( p_playlist ); + if( p_item ) psz_uri = input_item_GetURI( p_item->p_input ); + PL_UNLOCK; + + if( p_item ) { - config_PutPsz( p_intf, psz_bookmark_name, - p_playlist->status.p_item->p_input->psz_uri); - msg_Info( p_intf, "setting playlist bookmark %i to %s", i_num, - p_playlist->status.p_item->p_input->psz_uri); - config_SaveConfigFile( p_intf, "hotkeys" ); + config_PutPsz( p_intf, psz_bookmark_name, psz_uri); + msg_Info( p_intf, "setting playlist bookmark %i to %s", i_num, psz_uri); } - pl_Release( p_intf ); + + free( psz_uri ); + free( psz_bookmark_name ); } static void DisplayPosition( intf_thread_t *p_intf, vout_thread_t *p_vout, @@ -890,54 +1034,66 @@ static void DisplayPosition( intf_thread_t *p_intf, vout_thread_t *p_vout, if( time.i_time > 0 ) { secstotimestr( psz_duration, time.i_time / 1000000 ); - vout_OSDMessage( p_input, POSITION_TEXT_CHAN, (char *) "%s / %s", - psz_time, psz_duration ); + DisplayMessage( p_vout, POSITION_TEXT_CHAN, "%s / %s", + psz_time, psz_duration ); } else if( i_seconds > 0 ) { - vout_OSDMessage( p_input, POSITION_TEXT_CHAN, psz_time ); + DisplayMessage( p_vout, POSITION_TEXT_CHAN, "%s", psz_time ); } - if( !p_vout->p_parent_intf || p_vout->b_fullscreen ) + if( var_GetBool( p_vout, "fullscreen" ) ) { var_Get( p_input, "position", &pos ); - vout_OSDSlider( VLC_OBJECT( p_input ), POSITION_WIDGET_CHAN, + vout_OSDSlider( p_vout, POSITION_WIDGET_CHAN, pos.f_float * 100, OSD_HOR_SLIDER ); } } static void DisplayVolume( intf_thread_t *p_intf, vout_thread_t *p_vout, - audio_volume_t i_vol ) + float vol ) { if( p_vout == NULL ) - { return; - } ClearChannels( p_intf, p_vout ); - if( !p_vout->p_parent_intf || p_vout->b_fullscreen ) - { - vout_OSDSlider( VLC_OBJECT( p_vout ), VOLUME_WIDGET_CHAN, - i_vol*100/AOUT_VOLUME_MAX, OSD_VERT_SLIDER ); - } - else - { - vout_OSDMessage( p_vout, VOLUME_TEXT_CHAN, _( "Volume %d%%" ), - i_vol*400/AOUT_VOLUME_MAX ); - } + if( var_GetBool( p_vout, "fullscreen" ) ) + vout_OSDSlider( p_vout, VOLUME_WIDGET_CHAN, lround(vol * 100.), + OSD_VERT_SLIDER ); + DisplayMessage( p_vout, VOLUME_TEXT_CHAN, _( "Volume %ld%%" ), + lround(vol * 100.) ); } -static void ClearChannels( intf_thread_t *p_intf, vout_thread_t *p_vout ) +static void DisplayRate( vout_thread_t *p_vout, float f_rate ) { - int i; + DisplayMessage( p_vout, SPU_DEFAULT_CHANNEL, _("Speed: %.2fx"), f_rate ); +} + +static float AdjustRateFine( input_thread_t *p_input, const int i_dir ) +{ + const float f_rate_min = (float)INPUT_RATE_DEFAULT / INPUT_RATE_MAX; + const float f_rate_max = (float)INPUT_RATE_DEFAULT / INPUT_RATE_MIN; + float f_rate = var_GetFloat( p_input, "rate" ); + + int i_sign = f_rate < 0 ? -1 : 1; + f_rate = floor( fabs(f_rate) / 0.1 + i_dir + 0.05 ) * 0.1; + + if( f_rate < f_rate_min ) + f_rate = f_rate_min; + else if( f_rate > f_rate_max ) + f_rate = f_rate_max; + f_rate *= i_sign; + + return f_rate; +} + +static void ClearChannels( intf_thread_t *p_intf, vout_thread_t *p_vout ) +{ if( p_vout ) { - spu_Control( p_vout->p_spu, SPU_CHANNEL_CLEAR, DEFAULT_CHAN ); - for( i = 0; i < CHANNELS_NUMBER; i++ ) - { - spu_Control( p_vout->p_spu, SPU_CHANNEL_CLEAR, - p_intf->p_sys->p_channels[ i ] ); - } + vout_FlushSubpictureChannel( p_vout, SPU_DEFAULT_CHANNEL ); + for( int i = 0; i < CHANNELS_NUMBER; i++ ) + vout_FlushSubpictureChannel( p_vout, p_intf->p_sys->p_channels[i] ); } }