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 "recents.hpp"
33 #include <vlc_actions.h> /* ACTION_ID */
34 #include <vlc_url.h> /* vlc_uri_decode */
35 #include <vlc_strings.h> /* vlc_strfinput */
36 #include <vlc_aout.h> /* audio_output_t */
38 #include <QApplication>
41 #include <QSignalMapper>
42 #include <QMessageBox>
46 static int InputEvent( vlc_object_t
*, const char *,
47 vlc_value_t
, vlc_value_t
, void * );
48 static int VbiEvent( vlc_object_t
*, const char *,
49 vlc_value_t
, vlc_value_t
, void * );
51 /* Ensure arbitratry (not dynamically allocated) event IDs are not in use */
52 static inline void registerAndCheckEventIds( int start
, int end
)
54 for ( int i
=start
; i
<=end
; i
++ )
55 Q_ASSERT( QEvent::registerEventType( i
) == i
); /* event ID collision ! */
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( MainInputManager
*mim
, intf_thread_t
*_p_intf
) :
66 QObject( mim
), p_intf( _p_intf
)
69 i_old_playing_status
= END_S
;
79 f_cache
= -1.; /* impossible initial value, different from all */
80 registerAndCheckEventIds( IMEvent::PositionUpdate
, IMEvent::FullscreenControlPlanHide
);
81 registerAndCheckEventIds( PLEvent::PLItemAppended
, PLEvent::PLEmpty
);
84 InputManager::~InputManager()
89 void InputManager::inputChangedHandler()
91 setInput( p_mim
->getInput() );
94 /* Define the Input used.
95 Add the callbacks on input
96 p_input is held once here */
97 void InputManager::setInput( input_thread_t
*_p_input
)
101 if( p_input
!= NULL
)
103 msg_Dbg( p_intf
, "IM: Setting an input" );
104 vlc_object_hold( p_input
);
114 p_item
= input_GetItem( p_input
);
115 emit
rateChanged( var_GetFloat( p_input
, "rate" ) );
118 if( p_item
->i_type
== ITEM_TYPE_FILE
)
120 char *uri
= input_item_GetURI( p_item
);
122 int i_time
= RecentsMRL::getInstance( p_intf
)->time( qfu(uri
) );
123 if( i_time
> 0 && qfu( uri
) != lastURI
&&
124 !var_GetFloat( p_input
, "run-time" ) &&
125 !var_GetFloat( p_input
, "start-time" ) &&
126 !var_GetFloat( p_input
, "stop-time" ) )
128 emit
resumePlayback( (int64_t)i_time
* 1000 );
130 playlist_Lock( THEPL
);
131 // Add root items only
132 playlist_item_t
* p_node
= playlist_CurrentPlayingItem( THEPL
);
133 if ( p_node
!= NULL
&& p_node
->p_parent
!= NULL
&& p_node
->p_parent
->i_id
== THEPL
->p_playing
->i_id
)
135 // Save the latest URI to avoid asking to restore the
136 // position on the same input file.
137 lastURI
= qfu( uri
);
138 RecentsMRL::getInstance( p_intf
)->addRecent( lastURI
);
140 playlist_Unlock( THEPL
);
148 assert( !p_input_vbi
);
149 emit
rateChanged( var_InheritFloat( p_intf
, "rate" ) );
153 /* delete Input if it ever existed.
154 Delete the callbacls on input
155 p_input is released once here */
156 void InputManager::delInput()
158 if( !p_input
) return;
159 msg_Dbg( p_intf
, "IM: Deleting the input" );
161 /* Save time / position */
162 char *uri
= input_item_GetURI( p_item
);
164 float f_pos
= var_GetFloat( p_input
, "position" );
167 if( f_pos
>= 0.05f
&& f_pos
<= 0.95f
168 && var_GetInteger( p_input
, "length" ) >= VLC_TICK_FROM_SEC(60))
169 i_time
= var_GetInteger( p_input
, "time");
171 RecentsMRL::getInstance( p_intf
)->setTime( qfu(uri
), i_time
);
176 i_old_playing_status
= END_S
;
187 vlc_object_release( p_input_vbi
);
191 vlc_object_release( p_input
);
194 emit
positionUpdated( -1.0, 0 ,0 );
195 emit
rateChanged( var_InheritFloat( p_intf
, "rate" ) );
196 emit
nameChanged( "" );
197 emit
chapterChanged( 0 );
198 emit
titleChanged( 0 );
199 emit
playingStatusChanged( END_S
);
201 emit
teletextPossible( false );
202 emit
AtoBchanged( false, false );
203 emit
voutChanged( false );
204 emit
voutListChanged( NULL
, 0 );
206 /* Reset all InfoPanels but stats */
207 emit
artChanged( NULL
);
208 emit
artChanged( "" );
209 emit
infoChanged( NULL
);
210 emit
currentMetaChanged( (input_item_t
*)NULL
);
212 emit
encryptionChanged( false );
213 emit
recordingStateChanged( false );
215 emit
cachingChanged( 0.0 );
218 /* Convert the event from the callbacks in actions */
219 void InputManager::customEvent( QEvent
*event
)
221 int i_type
= event
->type();
222 IMEvent
*ple
= static_cast<IMEvent
*>(event
);
224 if( i_type
== IMEvent::ItemChanged
)
225 UpdateMeta( ple
->item() );
233 case IMEvent::PositionUpdate
:
236 case IMEvent::StatisticsUpdate
:
239 case IMEvent::ItemChanged
:
240 /* Ignore ItemChanged_Type event that does not apply to our input */
241 if( p_item
== ple
->item() )
247 /* Update duration of file */
250 case IMEvent::ItemStateChanged
:
253 case IMEvent::MetaChanged
:
255 UpdateName(); /* Needed for NowPlaying */
256 UpdateArt(); /* Art is part of meta in the core */
258 case IMEvent::InfoChanged
:
261 case IMEvent::ItemTitleChanged
:
263 UpdateName(); /* Display the name of the Chapter, if exists */
265 case IMEvent::ItemRateChanged
:
268 case IMEvent::ItemEsChanged
:
270 // We don't do anything ES related. Why ?
272 case IMEvent::ItemTeletextChanged
:
275 case IMEvent::InterfaceVoutUpdate
:
278 case IMEvent::SynchroChanged
:
279 emit
synchroChanged();
281 case IMEvent::CachingEvent
:
284 case IMEvent::BookmarksChanged
:
285 emit
bookmarksChanged();
287 case IMEvent::InterfaceAoutUpdate
:
290 case IMEvent::RecordingEvent
:
293 case IMEvent::ProgramChanged
:
294 UpdateProgramEvent();
296 case IMEvent::EPGEvent
:
300 msg_Warn( p_intf
, "This shouldn't happen: %i", i_type
);
301 vlc_assert_unreachable();
305 /* Add the callbacks on Input. Self explanatory */
306 inline void InputManager::addCallbacks()
308 var_AddCallback( p_input
, "intf-event", InputEvent
, this );
311 /* Delete the callbacks on Input. Self explanatory */
312 inline void InputManager::delCallbacks()
314 var_DelCallback( p_input
, "intf-event", InputEvent
, this );
317 /* Static callbacks for IM */
318 int MainInputManager::ItemChanged( vlc_object_t
*, const char *,
319 vlc_value_t
, vlc_value_t val
, void *param
)
321 InputManager
*im
= (InputManager
*)param
;
322 input_item_t
*p_item
= static_cast<input_item_t
*>(val
.p_address
);
324 IMEvent
*event
= new IMEvent( IMEvent::ItemChanged
, p_item
);
325 QApplication::postEvent( im
, event
);
329 static int InputEvent( vlc_object_t
*, const char *,
330 vlc_value_t
, vlc_value_t newval
, void *param
)
332 InputManager
*im
= (InputManager
*)param
;
335 switch( newval
.i_int
)
337 case INPUT_EVENT_STATE
:
338 event
= new IMEvent( IMEvent::ItemStateChanged
);
340 case INPUT_EVENT_RATE
:
341 event
= new IMEvent( IMEvent::ItemRateChanged
);
343 case INPUT_EVENT_POSITION
:
344 //case INPUT_EVENT_LENGTH:
345 event
= new IMEvent( IMEvent::PositionUpdate
);
348 case INPUT_EVENT_TITLE
:
349 case INPUT_EVENT_CHAPTER
:
350 event
= new IMEvent( IMEvent::ItemTitleChanged
);
354 event
= new IMEvent( IMEvent::ItemEsChanged
);
356 case INPUT_EVENT_TELETEXT
:
357 event
= new IMEvent( IMEvent::ItemTeletextChanged
);
360 case INPUT_EVENT_STATISTICS
:
361 event
= new IMEvent( IMEvent::StatisticsUpdate
);
364 case INPUT_EVENT_VOUT
:
365 event
= new IMEvent( IMEvent::InterfaceVoutUpdate
);
367 case INPUT_EVENT_AOUT
:
368 event
= new IMEvent( IMEvent::InterfaceAoutUpdate
);
371 case INPUT_EVENT_ITEM_META
: /* Codec MetaData + Art */
372 event
= new IMEvent( IMEvent::MetaChanged
);
374 case INPUT_EVENT_ITEM_INFO
: /* Codec Info */
375 event
= new IMEvent( IMEvent::InfoChanged
);
378 case INPUT_EVENT_AUDIO_DELAY
:
379 case INPUT_EVENT_SUBTITLE_DELAY
:
380 event
= new IMEvent( IMEvent::SynchroChanged
);
383 case INPUT_EVENT_CACHE
:
384 event
= new IMEvent( IMEvent::CachingEvent
);
387 case INPUT_EVENT_BOOKMARK
:
388 event
= new IMEvent( IMEvent::BookmarksChanged
);
391 case INPUT_EVENT_RECORD
:
392 event
= new IMEvent( IMEvent::RecordingEvent
);
395 case INPUT_EVENT_PROGRAM
:
396 /* This is for PID changes */
397 event
= new IMEvent( IMEvent::ProgramChanged
);
400 case INPUT_EVENT_ITEM_EPG
:
401 /* EPG data changed */
402 event
= new IMEvent( IMEvent::EPGEvent
);
405 case INPUT_EVENT_SIGNAL
:
406 /* This is for capture-card signals */
407 /* event = new IMEvent( SignalChanged_Type );
415 QApplication::postEvent( im
, event
);
419 static int VbiEvent( vlc_object_t
*, const char *,
420 vlc_value_t
, vlc_value_t
, void *param
)
422 InputManager
*im
= (InputManager
*)param
;
423 IMEvent
*event
= new IMEvent( IMEvent::ItemTeletextChanged
);
425 QApplication::postEvent( im
, event
);
429 void InputManager::UpdatePosition()
431 /* Update position */
432 int64_t i_length
= var_GetInteger( p_input
, "length" );
433 int64_t i_time
= var_GetInteger( p_input
, "time");
434 float f_pos
= var_GetFloat( p_input
, "position" );
435 emit
positionUpdated( f_pos
, i_time
, SEC_FROM_VLC_TICK(i_length
) );
438 void InputManager::UpdateNavigation()
440 /* Update navigation status */
441 size_t ntitles
, nchapters
;
443 var_Change( p_input
, "title", VLC_VAR_CHOICESCOUNT
, &ntitles
);
450 input_title_t
**pp_title
= NULL
;
452 if( input_Control( p_input
, INPUT_GET_FULL_TITLE_INFO
, &pp_title
, &i_title
) == VLC_SUCCESS
)
454 for( int i
= 0; i
< i_title
; i
++ )
456 if( pp_title
[i
]->i_flags
& INPUT_TITLE_MENU
)
458 vlc_input_title_Delete(pp_title
[i
]);
464 /* p_input != NULL since val.i_int != 0 */
465 var_Change( p_input
, "chapter", VLC_VAR_CHOICESCOUNT
, &nchapters
);
467 emit
titleChanged( b_menu
);
468 emit
chapterChanged( nchapters
> 1 );
471 emit
chapterChanged( false );
474 emit
inputCanSeek( var_GetBool( p_input
, "can-seek" ) );
476 emit
inputCanSeek( false );
479 void InputManager::UpdateStatus()
481 /* Update playing status */
482 int state
= var_GetInteger( p_input
, "state" );
483 if( i_old_playing_status
!= state
)
485 i_old_playing_status
= state
;
486 emit
playingStatusChanged( state
);
490 void InputManager::UpdateRate()
493 float f_new_rate
= var_GetFloat( p_input
, "rate" );
494 if( f_new_rate
!= f_rate
)
498 emit
rateChanged( f_rate
);
502 void InputManager::UpdateName()
504 /* Update text, name and nowplaying */
507 /* Try to get the nowplaying */
508 char *format
= var_InheritString( p_intf
, "input-title-format" );
509 char *formatted
= NULL
;
512 formatted
= vlc_strfinput( p_input
, format
);
514 if( formatted
!= NULL
)
516 name
= qfu(formatted
);
521 /* If we have Nothing */
522 if( name
.simplified().isEmpty() )
524 char *uri
= input_item_GetURI( input_GetItem( p_input
) );
525 char *file
= uri
? strrchr( uri
, '/' ) : NULL
;
528 vlc_uri_decode( ++file
);
536 name
= name
.trimmed();
538 if( oldName
!= name
)
540 emit
nameChanged( name
);
545 int InputManager::playingStatus() const
547 return i_old_playing_status
;
550 bool InputManager::hasAudio()
555 var_Change( p_input
, "audio-es", VLC_VAR_CHOICESCOUNT
, &val
);
561 bool InputManager::hasVisualisation()
566 audio_output_t
*aout
= input_GetAout( p_input
);
570 char *visual
= var_InheritString( aout
, "visual" );
571 vlc_object_release( aout
);
580 void InputManager::UpdateTeletext()
582 const bool b_enabled
= var_CountChoices( p_input
, "teletext-es" ) > 0;
583 const int i_teletext_es
= var_GetInteger( p_input
, "teletext-es" );
585 /* Teletext is possible. Show the buttons */
586 emit
teletextPossible( b_enabled
);
588 /* If Teletext is selected */
589 if( b_enabled
&& i_teletext_es
>= 0 )
591 /* Then, find the current page */
593 bool b_transparent
= false;
597 var_DelCallback( p_input_vbi
, "vbi-page", VbiEvent
, this );
598 vlc_object_release( p_input_vbi
);
601 if( input_GetEsObjects( p_input
, i_teletext_es
, &p_input_vbi
, NULL
, NULL
) )
606 /* This callback is not remove explicitly, but interfaces
607 * are guaranted to outlive input */
608 var_AddCallback( p_input_vbi
, "vbi-page", VbiEvent
, this );
610 i_page
= var_GetInteger( p_input_vbi
, "vbi-page" );
611 b_transparent
= !var_GetBool( p_input_vbi
, "vbi-opaque" );
613 emit
newTelexPageSet( i_page
);
614 emit
teletextTransparencyActivated( b_transparent
);
617 emit
teletextActivated( b_enabled
&& i_teletext_es
>= 0 );
620 void InputManager::UpdateEPG()
625 void InputManager::UpdateVout()
628 vout_thread_t
**pp_vout
;
633 /* Get current vout lists from input */
634 if( input_Control( p_input
, INPUT_GET_VOUTS
, &pp_vout
, &i_vout
) )
641 emit
voutListChanged( pp_vout
, i_vout
);
644 bool b_old_video
= b_video
;
645 b_video
= i_vout
> 0;
646 if( !!b_old_video
!= !!b_video
)
647 emit
voutChanged( b_video
);
649 /* Release the vout list */
650 for( size_t i
= 0; i
< i_vout
; i
++ )
651 vlc_object_release( (vlc_object_t
*)pp_vout
[i
] );
655 void InputManager::UpdateAout()
660 void InputManager::UpdateCaching()
662 float f_newCache
= var_GetFloat ( p_input
, "cache" );
663 if( f_newCache
!= f_cache
)
665 f_cache
= f_newCache
;
667 emit
cachingChanged( f_cache
);
671 void InputManager::requestArtUpdate( input_item_t
*p_item
, bool b_forced
)
673 bool b_current_item
= false;
674 if ( !p_item
&& hasInput() )
675 { /* default to current item */
676 p_item
= input_GetItem( p_input
);
677 b_current_item
= true;
682 /* check if it has already been enqueued */
683 if ( p_item
->p_meta
&& !b_forced
)
685 int status
= vlc_meta_GetStatus( p_item
->p_meta
);
686 if ( status
& ( ITEM_ART_NOTFOUND
|ITEM_ART_FETCHED
) )
689 libvlc_ArtRequest( p_intf
->obj
.libvlc
, p_item
,
690 (b_forced
) ? META_REQUEST_OPTION_SCOPE_ANY
691 : META_REQUEST_OPTION_NONE
);
692 /* No input will signal the cover art to update,
693 * let's do it ourself */
694 if ( b_current_item
)
697 emit
artChanged( p_item
);
701 const QString
InputManager::decodeArtURL( input_item_t
*p_item
)
705 char *psz_art
= input_item_GetArtURL( p_item
);
708 char *psz
= vlc_uri2path( psz_art
);
714 /* Taglib seems to define a attachment://, It won't work yet */
715 url
= url
.replace( "attachment://", "" );
718 QString path
= qfu( psz_art
? psz_art
: "" );
723 void InputManager::UpdateArt()
725 QString url
= decodeArtURL( input_GetItem( p_input
) );
727 /* the art hasn't changed, no need to update */
731 /* Update Art meta */
733 emit
artChanged( artUrl
);
736 void InputManager::setArt( input_item_t
*p_item
, QString fileUrl
)
740 char *psz_cachedir
= config_GetUserDir( VLC_CACHE_DIR
);
741 QString old_url
= p_mim
->getIM()->decodeArtURL( p_item
);
742 old_url
= QDir( old_url
).canonicalPath();
744 if( old_url
.startsWith( QString::fromUtf8( psz_cachedir
) ) )
745 QFile( old_url
).remove(); /* Purge cached artwork */
747 free( psz_cachedir
);
749 input_item_SetArtURL( p_item
, fileUrl
.toUtf8().constData() );
754 inline void InputManager::UpdateStats()
756 emit
statisticsUpdated( input_GetItem( p_input
) );
759 inline void InputManager::UpdateMeta( input_item_t
*p_item_
)
761 emit
metaChanged( p_item_
);
762 emit
artChanged( p_item_
);
765 inline void InputManager::UpdateMeta()
767 emit
currentMetaChanged( input_GetItem( p_input
) );
770 inline void InputManager::UpdateInfo()
773 emit
infoChanged( input_GetItem( p_input
) );
776 void InputManager::UpdateRecord()
778 emit
recordingStateChanged( var_GetBool( p_input
, "record" ) );
781 void InputManager::UpdateProgramEvent()
783 bool b_scrambled
= var_GetBool( p_input
, "program-scrambled" );
784 emit
encryptionChanged( b_scrambled
);
787 /* User update of the slider */
788 void InputManager::sliderUpdate( float new_pos
)
791 var_SetFloat( p_input
, "position", new_pos
);
792 emit
seekRequested( new_pos
);
795 void InputManager::sectionPrev()
799 int i_type
= var_Type( p_input
, "next-chapter" );
800 var_TriggerCallback( p_input
, (i_type
& VLC_VAR_TYPE
) != 0 ?
801 "prev-chapter":"prev-title" );
805 void InputManager::sectionNext()
809 int i_type
= var_Type( p_input
, "next-chapter" );
810 var_TriggerCallback( p_input
, (i_type
& VLC_VAR_TYPE
) != 0 ?
811 "next-chapter":"next-title" );
815 void InputManager::sectionMenu()
819 var_TriggerCallback( p_input
, "menu-title" );
827 void InputManager::changeProgram( int program
)
831 var_SetInteger( p_input
, "program", program
);
835 /* Set a new Teletext Page */
836 void InputManager::telexSetPage( int page
)
838 if( hasInput() && p_input_vbi
)
840 const int i_teletext_es
= var_GetInteger( p_input
, "teletext-es" );
842 if( i_teletext_es
>= 0 )
844 var_SetInteger( p_input_vbi
, "vbi-page", page
);
845 emit
newTelexPageSet( page
);
850 /* Set the transparency on teletext */
851 void InputManager::telexSetTransparency( bool b_transparentTelextext
)
853 if( hasInput() && p_input_vbi
)
855 var_SetBool( p_input_vbi
, "vbi-opaque", !b_transparentTelextext
);
856 emit
teletextTransparencyActivated( b_transparentTelextext
);
860 void InputManager::activateTeletext( bool b_enable
)
866 if( hasInput() && !var_Change( p_input
, "teletext-es", VLC_VAR_GETCHOICES
,
867 &count
, &list
, &text
) )
870 { /* Prefer the page 100 if it is present */
871 int id
= list
[0].i_int
;
872 for( size_t i
= 0; i
< count
; i
++ )
873 { /* The description is the page number as a string */
874 if( text
[i
] != NULL
&& !strcmp( text
[i
], "100" ) )
878 var_SetInteger( p_input
, "spu-es", b_enable
? id
: -1 );
885 void InputManager::reverse()
889 float f_rate_
= var_GetFloat( p_input
, "rate" );
890 var_SetFloat( p_input
, "rate", -f_rate_
);
894 void InputManager::slower()
896 var_TriggerCallback( THEPL
, "rate-slower" );
899 void InputManager::faster()
901 var_TriggerCallback( THEPL
, "rate-faster" );
904 void InputManager::littlefaster()
906 var_SetInteger( p_intf
->obj
.libvlc
, "key-action", ACTIONID_RATE_FASTER_FINE
);
909 void InputManager::littleslower()
911 var_SetInteger( p_intf
->obj
.libvlc
, "key-action", ACTIONID_RATE_SLOWER_FINE
);
914 void InputManager::normalRate()
916 var_SetFloat( THEPL
, "rate", 1. );
919 void InputManager::setRate( int new_rate
)
921 var_SetFloat( THEPL
, "rate",
922 (float)INPUT_RATE_DEFAULT
/ (float)new_rate
);
925 void InputManager::jumpFwd()
927 int i_interval
= var_InheritInteger( p_input
, "short-jump-size" );
928 if( i_interval
> 0 && hasInput() )
930 vlc_tick_t val
= vlc_tick_from_sec( i_interval
);
931 var_SetInteger( p_input
, "time-offset", val
);
935 void InputManager::jumpBwd()
937 int i_interval
= var_InheritInteger( p_input
, "short-jump-size" );
938 if( i_interval
> 0 && hasInput() )
940 vlc_tick_t val
= vlc_tick_from_sec( -i_interval
);
941 var_SetInteger( p_input
, "time-offset", val
);
945 void InputManager::setAtoB()
949 timeA
= var_GetInteger( p_mim
->getInput(), "time" );
953 timeB
= var_GetInteger( p_mim
->getInput(), "time" );
954 var_SetInteger( p_mim
->getInput(), "time" , timeA
);
955 CONNECT( this, positionUpdated( float, int64_t, int ),
956 this, AtoBLoop( float, int64_t, int ) );
962 disconnect( this, SIGNAL( positionUpdated( float, int64_t, int ) ),
963 this, SLOT( AtoBLoop( float, int64_t, int ) ) );
965 emit
AtoBchanged( (timeA
!= 0 ), (timeB
!= 0 ) );
968 /* Function called regularly when in an AtoB loop */
969 void InputManager::AtoBLoop( float, int64_t i_time
, int )
971 if( timeB
&& i_time
>= timeB
)
972 var_SetInteger( p_mim
->getInput(), "time" , timeA
);
975 /**********************************************************************
976 * MainInputManager implementation. Wrap an input manager and
977 * take care of updating the main playlist input.
978 * Used in the main playlist Dialog
979 **********************************************************************/
981 MainInputManager::MainInputManager( intf_thread_t
*_p_intf
)
982 : QObject(NULL
), p_input( NULL
), p_intf( _p_intf
),
983 random( VLC_OBJECT(THEPL
), "random" ),
984 repeat( VLC_OBJECT(THEPL
), "repeat" ), loop( VLC_OBJECT(THEPL
), "loop" ),
985 volume( VLC_OBJECT(THEPL
), "volume" ), mute( VLC_OBJECT(THEPL
), "mute" )
987 im
= new InputManager( this, p_intf
);
990 menusAudioMapper
= new QSignalMapper();
991 CONNECT( menusAudioMapper
, mapped(QString
), this, menusUpdateAudio( QString
) );
994 var_AddCallback( THEPL
, "item-change", MainInputManager::ItemChanged
, im
);
995 var_AddCallback( THEPL
, "input-current", MainInputManager::PLItemChanged
, this );
996 var_AddCallback( THEPL
, "leaf-to-parent", MainInputManager::LeafToParent
, this );
997 var_AddCallback( THEPL
, "playlist-item-append", MainInputManager::PLItemAppended
, this );
998 var_AddCallback( THEPL
, "playlist-item-deleted", MainInputManager::PLItemRemoved
, this );
1000 /* Core Callbacks to widget */
1001 random
.addCallback( this, SLOT(notifyRandom(bool)) );
1002 repeat
.addCallback( this, SLOT(notifyRepeatLoop(bool)) );
1003 loop
.addCallback( this, SLOT(notifyRepeatLoop(bool)) );
1004 volume
.addCallback( this, SLOT(notifyVolume(float)) );
1005 mute
.addCallback( this, SLOT(notifyMute(bool)) );
1007 /* Warn our embedded IM about input changes */
1008 DCONNECT( this, inputChanged( bool ),
1009 im
, inputChangedHandler() );
1012 MainInputManager::~MainInputManager()
1016 vlc_object_release( p_input
);
1018 emit
inputChanged( false );
1021 var_DelCallback( THEPL
, "input-current", MainInputManager::PLItemChanged
, this );
1022 var_DelCallback( THEPL
, "item-change", MainInputManager::ItemChanged
, im
);
1023 var_DelCallback( THEPL
, "leaf-to-parent", MainInputManager::LeafToParent
, this );
1025 var_DelCallback( THEPL
, "playlist-item-append", MainInputManager::PLItemAppended
, this );
1026 var_DelCallback( THEPL
, "playlist-item-deleted", MainInputManager::PLItemRemoved
, this );
1028 delete menusAudioMapper
;
1031 vout_thread_t
* MainInputManager::getVout()
1033 return p_input
? input_GetVout( p_input
) : NULL
;
1036 QVector
<vout_thread_t
*> MainInputManager::getVouts() const
1038 vout_thread_t
**pp_vout
;
1042 || input_Control( p_input
, INPUT_GET_VOUTS
, &pp_vout
, &i_vout
) != VLC_SUCCESS
1044 return QVector
<vout_thread_t
*>();
1046 QVector
<vout_thread_t
*> vector
= QVector
<vout_thread_t
*>();
1047 vector
.reserve( i_vout
);
1048 for( size_t i
= 0; i
< i_vout
; i
++ )
1050 assert( pp_vout
[i
] );
1051 vector
.append( pp_vout
[i
] );
1058 audio_output_t
* MainInputManager::getAout()
1060 return playlist_GetAout( THEPL
);
1063 void MainInputManager::customEvent( QEvent
*event
)
1065 int type
= event
->type();
1069 // msg_Dbg( p_intf, "New MainIM Event of type: %i", type );
1072 case PLEvent::PLItemAppended
:
1073 plEv
= static_cast<PLEvent
*>( event
);
1074 emit
playlistItemAppended( plEv
->getItemId(), plEv
->getParentId() );
1076 case PLEvent::PLItemRemoved
:
1077 plEv
= static_cast<PLEvent
*>( event
);
1078 emit
playlistItemRemoved( plEv
->getItemId() );
1080 case PLEvent::PLEmpty
:
1081 plEv
= static_cast<PLEvent
*>( event
);
1082 emit
playlistNotEmpty( plEv
->getItemId() >= 0 );
1084 case PLEvent::LeafToParent
:
1085 plEv
= static_cast<PLEvent
*>( event
);
1086 emit
leafBecameParent( plEv
->getItemId() );
1089 if( type
!= IMEvent::ItemChanged
) return;
1091 probeCurrentInput();
1094 void MainInputManager::probeCurrentInput()
1096 if( p_input
!= NULL
)
1097 vlc_object_release( p_input
);
1098 p_input
= playlist_CurrentInput( THEPL
);
1099 emit
inputChanged( p_input
!= NULL
);
1102 /* Playlist Control functions */
1103 void MainInputManager::stop()
1105 playlist_Stop( THEPL
);
1108 void MainInputManager::next()
1110 playlist_Next( THEPL
);
1113 void MainInputManager::prev()
1115 playlist_Prev( THEPL
);
1118 void MainInputManager::prevOrReset()
1120 if( !p_input
|| var_GetInteger( p_input
, "time") < INT64_C(10000) )
1121 playlist_Prev( THEPL
);
1123 getIM()->sliderUpdate( 0.0 );
1126 void MainInputManager::togglePlayPause()
1128 playlist_TogglePause( THEPL
);
1131 void MainInputManager::play()
1133 playlist_Play( THEPL
);
1136 void MainInputManager::pause()
1138 playlist_Pause( THEPL
);
1141 void MainInputManager::toggleRandom()
1143 config_PutInt( "random", var_ToggleBool( THEPL
, "random" ) );
1146 void MainInputManager::notifyRandom(bool value
)
1148 emit
randomChanged(value
);
1151 void MainInputManager::notifyRepeatLoop(bool)
1153 int i_state
= NORMAL
;
1155 if( var_GetBool( THEPL
, "loop" ) ) i_state
= REPEAT_ALL
;
1156 if( var_GetBool( THEPL
, "repeat" ) ) i_state
= REPEAT_ONE
;
1158 emit
repeatLoopChanged( i_state
);
1161 void MainInputManager::loopRepeatLoopStatus()
1163 /* Toggle Normal -> Loop -> Repeat -> Normal ... */
1164 bool loop
= var_GetBool( THEPL
, "loop" );
1165 bool repeat
= var_GetBool( THEPL
, "repeat" );
1183 var_SetBool( THEPL
, "loop", loop
);
1184 var_SetBool( THEPL
, "repeat", repeat
);
1185 config_PutInt( "loop", loop
);
1186 config_PutInt( "repeat", repeat
);
1189 void MainInputManager::activatePlayQuit( bool b_exit
)
1191 var_SetBool( THEPL
, "play-and-exit", b_exit
);
1192 config_PutInt( "play-and-exit", b_exit
);
1195 bool MainInputManager::getPlayExitState()
1197 return var_InheritBool( THEPL
, "play-and-exit" );
1200 bool MainInputManager::hasEmptyPlaylist()
1202 playlist_Lock( THEPL
);
1203 bool b_empty
= playlist_IsEmpty( THEPL
);
1204 playlist_Unlock( THEPL
);
1208 /****************************
1209 * Static callbacks for MIM *
1210 ****************************/
1211 int MainInputManager::PLItemChanged( vlc_object_t
*, const char *,
1212 vlc_value_t
, vlc_value_t
, void *param
)
1214 MainInputManager
*mim
= (MainInputManager
*)param
;
1216 IMEvent
*event
= new IMEvent( IMEvent::ItemChanged
);
1217 QApplication::postEvent( mim
, event
);
1221 int MainInputManager::LeafToParent( vlc_object_t
*, const char *,
1222 vlc_value_t
, vlc_value_t val
, void *param
)
1224 MainInputManager
*mim
= (MainInputManager
*)param
;
1226 PLEvent
*event
= new PLEvent( PLEvent::LeafToParent
, val
.i_int
);
1228 QApplication::postEvent( mim
, event
);
1232 void MainInputManager::notifyVolume( float volume
)
1234 emit
volumeChanged( volume
);
1237 void MainInputManager::notifyMute( bool mute
)
1239 emit
soundMuteChanged(mute
);
1243 void MainInputManager::menusUpdateAudio( const QString
& data
)
1245 audio_output_t
*aout
= getAout();
1248 aout_DeviceSet( aout
, qtu(data
) );
1249 vlc_object_release( aout
);
1253 int MainInputManager::PLItemAppended( vlc_object_t
*, const char *,
1254 vlc_value_t
, vlc_value_t cur
,
1257 MainInputManager
*mim
= static_cast<MainInputManager
*>(data
);
1258 playlist_item_t
*item
= static_cast<playlist_item_t
*>( cur
.p_address
);
1260 PLEvent
*event
= new PLEvent( PLEvent::PLItemAppended
, item
->i_id
,
1261 (item
->p_parent
!= NULL
) ? item
->p_parent
->i_id
: -1 );
1262 QApplication::postEvent( mim
, event
);
1264 event
= new PLEvent( PLEvent::PLEmpty
, item
->i_id
, 0 );
1265 QApplication::postEvent( mim
, event
);
1269 int MainInputManager::PLItemRemoved( vlc_object_t
*obj
, const char *,
1270 vlc_value_t
, vlc_value_t cur
, void *data
)
1272 playlist_t
*pl
= (playlist_t
*) obj
;
1273 MainInputManager
*mim
= static_cast<MainInputManager
*>(data
);
1274 playlist_item_t
*item
= static_cast<playlist_item_t
*>( cur
.p_address
);
1276 PLEvent
*event
= new PLEvent( PLEvent::PLItemRemoved
, item
->i_id
, 0 );
1277 QApplication::postEvent( mim
, event
);
1278 // can't use playlist_IsEmpty( ) as it isn't true yet
1279 if ( pl
->items
.i_size
== 1 ) // lock is held
1281 event
= new PLEvent( PLEvent::PLEmpty
, -1, 0 );
1282 QApplication::postEvent( mim
, event
);
1287 void MainInputManager::changeFullscreen( bool new_val
)
1289 if ( var_GetBool( THEPL
, "fullscreen" ) != new_val
)
1290 var_SetBool( THEPL
, "fullscreen", new_val
);