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::slower()
578 var_SetVoid( p_input, "rate-slower" );
581 void InputManager::faster()
584 var_SetVoid( p_input, "rate-faster" );
587 void InputManager::normalRate()
590 var_SetInteger( p_input, "rate", INPUT_RATE_DEFAULT );
593 void InputManager::setRate( int new_rate )
596 var_SetInteger( p_input, "rate", new_rate );
599 void InputManager::setAtoB()
603 timeA = var_GetTime( THEMIM->getInput(), "time" );
607 timeB = var_GetTime( THEMIM->getInput(), "time" );
608 var_SetTime( THEMIM->getInput(), "time" , timeA );
615 emit AtoBchanged( (timeA != 0 ), (timeB != 0 ) );
618 /* Function called regularly when in an AtoB loop */
619 void InputManager::AtoBLoop( int i_time )
623 if( ( i_time >= (int)( timeB/1000000 ) )
624 || ( i_time < (int)( timeA/1000000 ) ) )
625 var_SetTime( THEMIM->getInput(), "time" , timeA );
629 /**********************************************************************
630 * MainInputManager implementation. Wrap an input manager and
631 * take care of updating the main playlist input.
632 * Used in the main playlist Dialog
633 **********************************************************************/
634 MainInputManager * MainInputManager::instance = NULL;
636 MainInputManager::MainInputManager( intf_thread_t *_p_intf )
637 : QObject(NULL), p_intf( _p_intf )
640 im = new InputManager( this, p_intf );
642 var_AddCallback( THEPL, "item-change", ItemChanged, im );
643 var_AddCallback( THEPL, "playlist-current", PLItemChanged, this );
644 var_AddCallback( THEPL, "activity", PLItemChanged, this );
646 var_AddCallback( p_intf->p_libvlc, "volume-change", VolumeChanged, this );
648 /* Warn our embedded IM about input changes */
649 CONNECT( this, inputChanged( input_thread_t * ),
650 im, setInput( input_thread_t * ) );
652 /* emit check if playlist has allready started playing */
654 var_Change( THEPL, "playlist-current", VLC_VAR_CHOICESCOUNT, &val, NULL );
655 IMEvent *event = new IMEvent( ItemChanged_Type, val.i_int);
656 QApplication::postEvent( this, static_cast<QEvent*>(event) );
660 MainInputManager::~MainInputManager()
664 var_DelCallback( p_input, "state", PLItemChanged, this );
665 vlc_object_release( p_input );
666 emit inputChanged( NULL );
669 var_DelCallback( p_intf->p_libvlc, "volume-change", VolumeChanged, this );
671 var_DelCallback( THEPL, "activity", PLItemChanged, this );
672 var_DelCallback( THEPL, "item-change", ItemChanged, im );
674 var_DelCallback( THEPL, "playlist-current", PLItemChanged, this );
677 void MainInputManager::customEvent( QEvent *event )
679 int type = event->type();
680 if ( type != ItemChanged_Type && type != VolumeChanged_Type )
683 // msg_Dbg( p_intf, "New MainIM Event of type: %i", type );
684 if( type == VolumeChanged_Type )
686 emit volumeChanged();
690 /* Should be PLItemChanged Event */
691 if( !p_intf->p_sys->b_isDialogProvider )
693 vlc_mutex_lock( &p_intf->change_lock );
694 if( p_input && ( p_input->b_dead || !vlc_object_alive (p_input) ) )
696 var_DelCallback( p_input, "state", PLItemChanged, this );
697 vlc_object_release( p_input );
698 emit inputChanged( NULL );
700 vlc_mutex_unlock( &p_intf->change_lock );
706 p_input = playlist_CurrentInput(THEPL);
709 var_AddCallback( p_input, "state", PLItemChanged, this );
710 emit inputChanged( p_input );
713 vlc_mutex_unlock( &p_intf->change_lock );
717 /* we are working as a dialogs provider */
718 playlist_t *p_playlist = pl_Hold( p_intf );
719 p_input = playlist_CurrentInput( p_playlist );
722 emit inputChanged( p_input );
723 vlc_object_release( p_input );
725 pl_Release( p_intf );
729 /* Playlist Control functions */
730 void MainInputManager::stop()
732 playlist_Stop( THEPL );
735 void MainInputManager::next()
737 playlist_Next( THEPL );
740 void MainInputManager::prev()
742 playlist_Prev( THEPL );
745 void MainInputManager::togglePlayPause()
749 playlist_Play( THEPL );
751 getIM()->togglePlayPause();
754 /* Static callbacks */
757 static int InterfaceChanged( vlc_object_t *p_this, const char *psz_var,
758 vlc_value_t oldval, vlc_value_t newval, void *param )
760 /* FIXME remove that static variable */
761 static int counter = 0;
763 InputManager *im = (InputManager*)param;
765 counter = ++counter % 4;
766 if(!counter) return VLC_SUCCESS;
768 IMEvent *event = new IMEvent( PositionUpdate_Type, 0 );
769 QApplication::postEvent( im, static_cast<QEvent*>(event) );
773 static int StatisticsUpdated( vlc_object_t *p_this, const char *psz_var,
774 vlc_value_t oldval, vlc_value_t newval, void *param )
776 InputManager *im = (InputManager*)param;
778 IMEvent *event = new IMEvent( StatisticsUpdate_Type, 0 );
779 QApplication::postEvent( im, static_cast<QEvent*>(event) );
783 static int InterfaceVoutChanged( vlc_object_t *p_this, const char *psz_var,
784 vlc_value_t oldval, vlc_value_t newval, void *param )
786 InputManager *im = (InputManager*)param;
788 IMEvent *event = new IMEvent( InterfaceVoutUpdate_Type, 0 );
789 QApplication::postEvent( im, static_cast<QEvent*>(event) );
793 static int ItemStateChanged( vlc_object_t *p_this, const char *psz_var,
794 vlc_value_t oldval, vlc_value_t newval, void *param )
796 InputManager *im = (InputManager*)param;
798 IMEvent *event = new IMEvent( ItemStateChanged_Type, 0 );
799 QApplication::postEvent( im, static_cast<QEvent*>(event) );
803 static int ItemRateChanged( vlc_object_t *p_this, const char *psz_var,
804 vlc_value_t oldval, vlc_value_t newval, void *param )
806 InputManager *im = (InputManager*)param;
808 IMEvent *event = new IMEvent( ItemRateChanged_Type, 0 );
809 QApplication::postEvent( im, static_cast<QEvent*>(event) );
813 static int ItemTitleChanged( vlc_object_t *p_this, const char *psz_var,
814 vlc_value_t oldval, vlc_value_t newval, void *param )
816 InputManager *im = (InputManager*)param;
818 IMEvent *event = new IMEvent( ItemTitleChanged_Type, 0 );
819 QApplication::postEvent( im, static_cast<QEvent*>(event) );
823 static int ItemChanged( vlc_object_t *p_this, const char *psz_var,
824 vlc_value_t oldval, vlc_value_t newval, void *param )
826 InputManager *im = (InputManager*)param;
828 IMEvent *event = new IMEvent( ItemChanged_Type, newval.i_int );
829 QApplication::postEvent( im, static_cast<QEvent*>(event) );
833 static int ChangeSPU( vlc_object_t *p_this, const char *var, vlc_value_t o,
834 vlc_value_t n, void *param )
836 InputManager *im = (InputManager*)param;
837 IMEvent *event = new IMEvent( ItemSpuChanged_Type, 0 );
838 QApplication::postEvent( im, static_cast<QEvent*>(event) );
842 static int ChangeTeletext( vlc_object_t *p_this, const char *var, vlc_value_t o,
843 vlc_value_t n, void *param )
846 InputManager *im = (InputManager*)param;
847 IMEvent *event = new IMEvent( ItemTeletextChanged_Type, 0 );
848 QApplication::postEvent( im, static_cast<QEvent*>(event) );
853 static int PLItemChanged( vlc_object_t *p_this, const char *psz_var,
854 vlc_value_t oldval, vlc_value_t newval, void *param )
856 MainInputManager *mim = (MainInputManager*)param;
858 IMEvent *event = new IMEvent( ItemChanged_Type, newval.i_int );
859 QApplication::postEvent( mim, static_cast<QEvent*>(event) );
863 static int VolumeChanged( vlc_object_t *p_this, const char *psz_var,
864 vlc_value_t oldval, vlc_value_t newval, void *param )
866 MainInputManager *mim = (MainInputManager*)param;
868 IMEvent *event = new IMEvent( VolumeChanged_Type, newval.i_int );
869 QApplication::postEvent( mim, static_cast<QEvent*>(event) );