1 /*****************************************************************************
2 * input_manager.cpp : Manage an input and interact with its GUI elements
3 ****************************************************************************
4 * Copyright (C) 2006-2008 the VideoLAN team
7 * Authors: Clément Stenac <zorglub@videolan.org>
8 * Ilkka Ollakka <ileoo@videolan.org>
9 * Jean-Baptiste <jb@videolan.org>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
30 #include "input_manager.hpp"
31 #include "dialogs_provider.hpp"
33 static int ChangeSPU( vlc_object_t *p_this, const char *var, vlc_value_t o,
34 vlc_value_t n, void *param );
36 static int ChangeTeletext( vlc_object_t *p_this, const char *var, vlc_value_t o,
37 vlc_value_t n, void *param );
39 static int ItemChanged( vlc_object_t *, const char *,
40 vlc_value_t, vlc_value_t, void * );
41 static int PLItemChanged( vlc_object_t *, const char *,
42 vlc_value_t, vlc_value_t, void * );
43 static int InterfaceChanged( vlc_object_t *, const char *,
44 vlc_value_t, vlc_value_t, void * );
45 static int StatisticsUpdated( vlc_object_t *, const char *,
46 vlc_value_t, vlc_value_t, void * );
47 static int InterfaceVoutChanged( vlc_object_t *, const char *,
48 vlc_value_t, vlc_value_t, void * );
49 static int ItemStateChanged( vlc_object_t *, const char *,
50 vlc_value_t, vlc_value_t, void * );
51 static int ItemRateChanged( vlc_object_t *, const char *,
52 vlc_value_t, vlc_value_t, void * );
53 static int ItemTitleChanged( vlc_object_t *, const char *,
54 vlc_value_t, vlc_value_t, void * );
55 static int VolumeChanged( vlc_object_t *, const char *,
56 vlc_value_t, vlc_value_t, void * );
58 /**********************************************************************
59 * InputManager implementation
60 **********************************************************************
61 * The Input Manager can be the main one around the playlist
62 * But can also be used for VLM dialog or similar
63 **********************************************************************/
65 InputManager::InputManager( QObject *parent, intf_thread_t *_p_intf) :
66 QObject( parent ), p_intf( _p_intf )
68 i_old_playing_status = END_S;
80 InputManager::~InputManager()
85 /* Define the Input used.
86 Add the callbacks on input
87 p_input is held once here */
88 void InputManager::setInput( input_thread_t *_p_input )
92 if( p_input && !( p_input->b_dead || !vlc_object_alive (p_input) ) )
94 vlc_object_hold( p_input );
95 emit statusChanged( PLAYING_S );
102 i_input_id = input_GetItem( p_input )->i_id;
108 emit rateChanged( INPUT_RATE_DEFAULT );
112 /* delete Input if it ever existed.
113 Delete the callbacls on input
114 p_input is released once here */
115 void InputManager::delInput()
120 i_old_playing_status = END_S;
127 emit positionUpdated( -1.0, 0 ,0 );
128 emit statusChanged( END_S );
129 emit nameChanged( "" );
130 emit artChanged( NULL );
131 emit rateChanged( INPUT_RATE_DEFAULT );
132 emit voutChanged( false );
133 vlc_object_release( p_input );
139 /* Add the callbacks on Input. Self explanatory */
140 void InputManager::addCallbacks()
142 /* We don't care about:
148 - position, time, length, because they are included in intf-change
150 /* src/input/input.c:1629 */
151 var_AddCallback( p_input, "state", ItemStateChanged, this );
152 /* src/input/es-out.c:552 */
153 var_AddCallback( p_input, "spu-es", ChangeSPU, this );
154 /* emit UpdateStatus so that main_interface updates controls
155 * if there is new videotracks (mpeg-ts)*/
156 var_AddCallback( p_input, "video-es", ItemStateChanged, this );
157 /* src/input/es-out.c: */
158 var_AddCallback( p_input, "teletext-es", ChangeTeletext, this );
159 /* src/input/input.c:1765 */
160 var_AddCallback( p_input, "rate-change", ItemRateChanged, this );
161 /* src/input/input.c:2003 */
162 var_AddCallback( p_input, "title", ItemTitleChanged, this );
163 /* src/input/input.c:734 for timers update*/
164 var_AddCallback( p_input, "intf-change", InterfaceChanged, this );
165 /* src/input/input.c:710 for statistics update*/
166 var_AddCallback( p_input, "stats-change", StatisticsUpdated, this );
167 /* src/input/input.c for vout creation/destruction */
168 var_AddCallback( p_input, "intf-change-vout", InterfaceVoutChanged, this );
171 /* Delete the callbacks on Input. Self explanatory */
172 void InputManager::delCallbacks()
174 var_DelCallback( p_input, "spu-es", ChangeSPU, this );
175 var_DelCallback( p_input, "video-es", ItemStateChanged, this );
176 var_DelCallback( p_input, "teletext-es", ChangeTeletext, this );
177 var_DelCallback( p_input, "state", ItemStateChanged, this );
178 var_DelCallback( p_input, "rate-change", ItemRateChanged, this );
179 var_DelCallback( p_input, "title", ItemTitleChanged, this );
180 var_DelCallback( p_input, "intf-change", InterfaceChanged, this );
181 var_DelCallback( p_input, "stats-change", StatisticsUpdated, this );
182 var_DelCallback( p_input, "intf-change-vout", InterfaceVoutChanged, this );
185 /* Convert the event from the callbacks in actions */
186 void InputManager::customEvent( QEvent *event )
188 int i_type = event->type();
189 IMEvent *ple = static_cast<IMEvent *>(event);
191 if ( i_type != PositionUpdate_Type &&
192 i_type != ItemChanged_Type &&
193 i_type != ItemRateChanged_Type &&
194 i_type != ItemTitleChanged_Type &&
195 i_type != ItemSpuChanged_Type &&
196 i_type != ItemTeletextChanged_Type &&
197 i_type != ItemStateChanged_Type &&
198 i_type != StatisticsUpdate_Type &&
199 i_type != InterfaceVoutUpdate_Type )
202 if( i_type == ItemStateChanged_Type )
208 if( !hasInput() ) return;
210 if( ( i_type != PositionUpdate_Type &&
211 i_type != ItemRateChanged_Type &&
212 i_type != ItemSpuChanged_Type &&
213 i_type != ItemTeletextChanged_Type &&
214 i_type != ItemStateChanged_Type &&
215 i_type != StatisticsUpdate_Type &&
216 i_type != InterfaceVoutUpdate_Type
218 && ( i_input_id != ple->i_id ) )
221 if( i_type != PositionUpdate_Type &&
222 i_type != StatisticsUpdate_Type )
223 msg_Dbg( p_intf, "New Event: type %i", i_type );
228 case PositionUpdate_Type:
231 case StatisticsUpdate_Type:
234 case ItemChanged_Type:
239 case ItemStateChanged_Type:
244 case ItemTitleChanged_Type:
248 case ItemRateChanged_Type:
251 case ItemSpuChanged_Type:
254 case ItemTeletextChanged_Type:
257 case InterfaceVoutUpdate_Type:
261 msg_Warn( p_intf, "This shouldn't happen: %i", i_type );
265 void InputManager::UpdateStats()
267 emit statisticsUpdated( input_GetItem( p_input ) );
270 void InputManager::UpdatePosition()
272 /* Update position */
273 int i_length, i_time; /* Int is enough, since we store seconds */
275 i_length = var_GetTime( p_input , "length" ) / 1000000;
276 i_time = var_GetTime( p_input , "time") / 1000000;
277 f_pos = var_GetFloat( p_input , "position" );
278 emit positionUpdated( f_pos, i_time, i_length );
281 void InputManager::UpdateNavigation()
283 /* Update navigation status */
284 vlc_value_t val; val.i_int = 0;
287 var_Change( p_input, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
291 emit titleChanged( true );
292 /* p_input != NULL since val.i_int != 0 */
294 var_Change( p_input, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
295 emit chapterChanged( (val.i_int > 0) );
298 emit titleChanged( false );
301 void InputManager::UpdateStatus()
303 /* Update playing status */
304 vlc_value_t val; val.i_int = 0;
305 var_Get( p_input, "state", &val );
306 if( i_old_playing_status != val.i_int )
308 i_old_playing_status = val.i_int;
309 emit statusChanged( val.i_int );
313 void InputManager::UpdateRate()
316 int i_new_rate = var_GetInteger( p_input, "rate");
317 if( i_new_rate != i_rate )
321 emit rateChanged( i_rate );
325 void InputManager::UpdateMeta()
327 /* Update text, name and nowplaying */
330 /* Try to get the Title, then the Name */
331 char *psz_name = input_item_GetTitle( input_GetItem( p_input ) );
332 if( EMPTY_STR( psz_name ) )
335 psz_name = input_item_GetName( input_GetItem( p_input ) );
338 /* Try to get the nowplaying */
339 char *psz_nowplaying =
340 input_item_GetNowPlaying( input_GetItem( p_input ) );
341 if( !EMPTY_STR( psz_nowplaying ) )
343 text.sprintf( "%s - %s", psz_nowplaying, psz_name );
345 else /* Do it ourself */
347 char *psz_artist = input_item_GetArtist( input_GetItem( p_input ) );
349 if( !EMPTY_STR( psz_artist ) )
350 text.sprintf( "%s - %s", psz_artist, psz_name );
352 text.sprintf( "%s", psz_name );
356 /* Free everything */
358 free( psz_nowplaying );
360 /* If we have Nothing */
363 psz_name = input_item_GetURI( input_GetItem( p_input ) );
364 text.sprintf( "%s", psz_name );
365 text = text.remove( 0, text.lastIndexOf( DIR_SEP ) + 1 );
369 if( oldName != text )
371 emit nameChanged( text );
376 bool InputManager::hasAudio()
381 var_Change( p_input, "audio-es", VLC_VAR_CHOICESCOUNT, &val, NULL );
382 return val.i_int > 0;
387 void InputManager::UpdateSPU()
392 void InputManager::UpdateTeletext()
395 telexActivation( var_GetInteger( p_input, "teletext-es" ) >= 0 );
397 telexActivation( false );
400 void InputManager::UpdateVout()
404 bool b_old_video = b_video;
406 vlc_object_t *p_vout = (vlc_object_t*)vlc_object_find( p_input,
407 VLC_OBJECT_VOUT, FIND_CHILD );
408 b_video = p_vout != NULL;
410 vlc_object_release( p_vout );
411 if( !!b_old_video != !!b_video )
412 emit voutChanged( b_video );
416 void InputManager::UpdateArt()
418 /* Update Art meta */
419 emit artChanged( input_GetItem( p_input ) );
422 /* User update of the slider */
423 void InputManager::sliderUpdate( float new_pos )
426 var_SetFloat( p_input, "position", new_pos );
429 /* User togglePlayPause */
430 void InputManager::togglePlayPause()
435 var_Get( p_input, "state", &state );
436 state.i_int = ( state.i_int != PLAYING_S ) ? PLAYING_S : PAUSE_S;
437 var_Set( p_input, "state", state );
438 emit statusChanged( state.i_int );
442 void InputManager::sectionPrev()
446 int i_type = var_Type( p_input, "next-chapter" );
447 vlc_value_t val; val.b_bool = true;
448 var_Set( p_input, (i_type & VLC_VAR_TYPE) != 0 ?
449 "prev-chapter":"prev-title", val );
453 void InputManager::sectionNext()
457 int i_type = var_Type( p_input, "next-chapter" );
458 vlc_value_t val; val.b_bool = true;
459 var_Set( p_input, (i_type & VLC_VAR_TYPE) != 0 ?
460 "next-chapter":"next-title", val );
464 void InputManager::sectionMenu()
468 vlc_value_t val, text;
471 if( var_Change( p_input, "title 0", VLC_VAR_GETLIST, &val, &text ) < 0 )
474 /* XXX is it "Root" or "Title" we want here ?" (set 0 by default) */
476 for( int i = 0; i < val.p_list->i_count; i++ )
478 if( !strcmp( text.p_list->p_values[i].psz_string, "Title" ) )
481 var_Change( p_input, "title 0", VLC_VAR_FREELIST, &val, &text );
483 var_Set( p_input, "title 0", root );
491 /* Set a new Teletext Page */
492 void InputManager::telexSetPage( int page )
496 const int i_teletext_es = var_GetInteger( p_input, "teletext-es" );
497 const int i_spu_es = var_GetInteger( p_input, "spu-es" );
499 if( i_teletext_es >= 0 && i_teletext_es == i_spu_es )
501 vlc_object_t *p_vbi = (vlc_object_t *) vlc_object_find_name( p_input,
502 "zvbi", FIND_ANYWHERE );
505 var_SetInteger( p_vbi, "vbi-page", page );
506 vlc_object_release( p_vbi );
507 emit newTelexPageSet( page );
513 /* Set the transparency on teletext */
514 void InputManager::telexSetTransparency( bool b_transparentTelextext )
518 vlc_object_t *p_vbi = (vlc_object_t *) vlc_object_find_name( p_input,
519 "zvbi", FIND_ANYWHERE );
522 var_SetBool( p_vbi, "vbi-opaque", b_transparentTelextext );
523 vlc_object_release( p_vbi );
524 emit teletextTransparencyActivated( b_transparentTelextext );
529 void InputManager::telexActivation( bool b_enabled )
533 const int i_teletext_es = var_GetInteger( p_input, "teletext-es" );
534 const int i_spu_es = var_GetInteger( p_input, "spu-es" );
536 /* Teletext is possible. Show the buttons */
537 b_enabled = (i_teletext_es >= 0);
538 emit teletextPossible( b_enabled );
539 if( !b_enabled ) return;
541 /* If Teletext is selected */
542 if( i_teletext_es == i_spu_es )
544 /* Activate the buttons */
545 teletextActivated( true );
547 /* Then, find the current page */
549 vlc_object_t *p_vbi = (vlc_object_t *)
550 vlc_object_find_name( p_input, "zvbi", FIND_ANYWHERE );
553 i_page = var_GetInteger( p_vbi, "vbi-page" );
554 vlc_object_release( p_vbi );
555 emit newTelexPageSet( i_page );
560 emit teletextPossible( b_enabled );
563 void InputManager::activateTeletext( bool b_enable )
567 const int i_teletext_es = var_GetInteger( p_input, "teletext-es" );
568 if( i_teletext_es >= 0 )
570 var_SetInteger( p_input, "spu-es", b_enable ? i_teletext_es : -1 );
575 void InputManager::reverse()
579 int i_rate = var_GetInteger( p_input, "rate" );
580 var_SetInteger( p_input, "rate", -i_rate );
584 void InputManager::slower()
587 var_SetVoid( p_input, "rate-slower" );
590 void InputManager::faster()
593 var_SetVoid( p_input, "rate-faster" );
596 void InputManager::normalRate()
599 var_SetInteger( p_input, "rate", INPUT_RATE_DEFAULT );
602 void InputManager::setRate( int new_rate )
605 var_SetInteger( p_input, "rate", new_rate );
608 void InputManager::setAtoB()
612 timeA = var_GetTime( THEMIM->getInput(), "time" );
616 timeB = var_GetTime( THEMIM->getInput(), "time" );
617 var_SetTime( THEMIM->getInput(), "time" , timeA );
624 emit AtoBchanged( (timeA != 0 ), (timeB != 0 ) );
627 /* Function called regularly when in an AtoB loop */
628 void InputManager::AtoBLoop( int i_time )
632 if( ( i_time >= (int)( timeB/1000000 ) )
633 || ( i_time < (int)( timeA/1000000 ) ) )
634 var_SetTime( THEMIM->getInput(), "time" , timeA );
638 /**********************************************************************
639 * MainInputManager implementation. Wrap an input manager and
640 * take care of updating the main playlist input.
641 * Used in the main playlist Dialog
642 **********************************************************************/
643 MainInputManager * MainInputManager::instance = NULL;
645 MainInputManager::MainInputManager( intf_thread_t *_p_intf )
646 : QObject(NULL), p_intf( _p_intf )
649 im = new InputManager( this, p_intf );
651 var_AddCallback( THEPL, "item-change", ItemChanged, im );
652 var_AddCallback( THEPL, "playlist-current", PLItemChanged, this );
653 var_AddCallback( THEPL, "activity", PLItemChanged, this );
655 var_AddCallback( p_intf->p_libvlc, "volume-change", VolumeChanged, this );
657 /* Warn our embedded IM about input changes */
658 CONNECT( this, inputChanged( input_thread_t * ),
659 im, setInput( input_thread_t * ) );
661 /* emit check if playlist has allready started playing */
663 var_Change( THEPL, "playlist-current", VLC_VAR_CHOICESCOUNT, &val, NULL );
664 IMEvent *event = new IMEvent( ItemChanged_Type, val.i_int);
665 QApplication::postEvent( this, static_cast<QEvent*>(event) );
669 MainInputManager::~MainInputManager()
673 var_DelCallback( p_input, "state", PLItemChanged, this );
674 vlc_object_release( p_input );
675 emit inputChanged( NULL );
678 var_DelCallback( p_intf->p_libvlc, "volume-change", VolumeChanged, this );
680 var_DelCallback( THEPL, "activity", PLItemChanged, this );
681 var_DelCallback( THEPL, "item-change", ItemChanged, im );
683 var_DelCallback( THEPL, "playlist-current", PLItemChanged, this );
686 void MainInputManager::customEvent( QEvent *event )
688 int type = event->type();
689 if ( type != ItemChanged_Type && type != VolumeChanged_Type )
692 // msg_Dbg( p_intf, "New MainIM Event of type: %i", type );
693 if( type == VolumeChanged_Type )
695 emit volumeChanged();
699 /* Should be PLItemChanged Event */
700 if( !p_intf->p_sys->b_isDialogProvider )
702 vlc_mutex_lock( &p_intf->change_lock );
703 if( p_input && ( p_input->b_dead || !vlc_object_alive (p_input) ) )
705 var_DelCallback( p_input, "state", PLItemChanged, this );
706 vlc_object_release( p_input );
707 emit inputChanged( NULL );
709 vlc_mutex_unlock( &p_intf->change_lock );
715 p_input = playlist_CurrentInput(THEPL);
718 var_AddCallback( p_input, "state", PLItemChanged, this );
719 emit inputChanged( p_input );
722 vlc_mutex_unlock( &p_intf->change_lock );
726 /* we are working as a dialogs provider */
727 playlist_t *p_playlist = pl_Hold( p_intf );
728 p_input = playlist_CurrentInput( p_playlist );
731 emit inputChanged( p_input );
732 vlc_object_release( p_input );
734 pl_Release( p_intf );
738 /* Playlist Control functions */
739 void MainInputManager::stop()
741 playlist_Stop( THEPL );
744 void MainInputManager::next()
746 playlist_Next( THEPL );
749 void MainInputManager::prev()
751 playlist_Prev( THEPL );
754 void MainInputManager::togglePlayPause()
758 playlist_Play( THEPL );
760 getIM()->togglePlayPause();
763 /* Static callbacks */
766 static int InterfaceChanged( vlc_object_t *p_this, const char *psz_var,
767 vlc_value_t oldval, vlc_value_t newval, void *param )
769 /* FIXME remove that static variable */
770 static int counter = 0;
772 InputManager *im = (InputManager*)param;
774 counter = ++counter % 4;
775 if(!counter) return VLC_SUCCESS;
777 IMEvent *event = new IMEvent( PositionUpdate_Type, 0 );
778 QApplication::postEvent( im, static_cast<QEvent*>(event) );
782 static int StatisticsUpdated( vlc_object_t *p_this, const char *psz_var,
783 vlc_value_t oldval, vlc_value_t newval, void *param )
785 InputManager *im = (InputManager*)param;
787 IMEvent *event = new IMEvent( StatisticsUpdate_Type, 0 );
788 QApplication::postEvent( im, static_cast<QEvent*>(event) );
792 static int InterfaceVoutChanged( vlc_object_t *p_this, const char *psz_var,
793 vlc_value_t oldval, vlc_value_t newval, void *param )
795 InputManager *im = (InputManager*)param;
797 IMEvent *event = new IMEvent( InterfaceVoutUpdate_Type, 0 );
798 QApplication::postEvent( im, static_cast<QEvent*>(event) );
802 static int ItemStateChanged( vlc_object_t *p_this, const char *psz_var,
803 vlc_value_t oldval, vlc_value_t newval, void *param )
805 InputManager *im = (InputManager*)param;
807 IMEvent *event = new IMEvent( ItemStateChanged_Type, 0 );
808 QApplication::postEvent( im, static_cast<QEvent*>(event) );
812 static int ItemRateChanged( vlc_object_t *p_this, const char *psz_var,
813 vlc_value_t oldval, vlc_value_t newval, void *param )
815 InputManager *im = (InputManager*)param;
817 IMEvent *event = new IMEvent( ItemRateChanged_Type, 0 );
818 QApplication::postEvent( im, static_cast<QEvent*>(event) );
822 static int ItemTitleChanged( vlc_object_t *p_this, const char *psz_var,
823 vlc_value_t oldval, vlc_value_t newval, void *param )
825 InputManager *im = (InputManager*)param;
827 IMEvent *event = new IMEvent( ItemTitleChanged_Type, 0 );
828 QApplication::postEvent( im, static_cast<QEvent*>(event) );
832 static int ItemChanged( vlc_object_t *p_this, const char *psz_var,
833 vlc_value_t oldval, vlc_value_t newval, void *param )
835 InputManager *im = (InputManager*)param;
837 IMEvent *event = new IMEvent( ItemChanged_Type, newval.i_int );
838 QApplication::postEvent( im, static_cast<QEvent*>(event) );
842 static int ChangeSPU( vlc_object_t *p_this, const char *var, vlc_value_t o,
843 vlc_value_t n, void *param )
845 InputManager *im = (InputManager*)param;
846 IMEvent *event = new IMEvent( ItemSpuChanged_Type, 0 );
847 QApplication::postEvent( im, static_cast<QEvent*>(event) );
851 static int ChangeTeletext( vlc_object_t *p_this, const char *var, vlc_value_t o,
852 vlc_value_t n, void *param )
855 InputManager *im = (InputManager*)param;
856 IMEvent *event = new IMEvent( ItemTeletextChanged_Type, 0 );
857 QApplication::postEvent( im, static_cast<QEvent*>(event) );
862 static int PLItemChanged( vlc_object_t *p_this, const char *psz_var,
863 vlc_value_t oldval, vlc_value_t newval, void *param )
865 MainInputManager *mim = (MainInputManager*)param;
867 IMEvent *event = new IMEvent( ItemChanged_Type, newval.i_int );
868 QApplication::postEvent( mim, static_cast<QEvent*>(event) );
872 static int VolumeChanged( vlc_object_t *p_this, const char *psz_var,
873 vlc_value_t oldval, vlc_value_t newval, void *param )
875 MainInputManager *mim = (MainInputManager*)param;
877 IMEvent *event = new IMEvent( VolumeChanged_Type, newval.i_int );
878 QApplication::postEvent( mim, static_cast<QEvent*>(event) );