1 /*****************************************************************************
2 * input_manager.cpp : Manage an input and interact with its GUI elements
3 ****************************************************************************
4 * Copyright (C) 2006-2008 the VideoLAN team
6 * Authors: Clément Stenac <zorglub@videolan.org>
7 * Ilkka Ollakka <ileoo@videolan.org>
8 * Jean-Baptiste <jb@videolan.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
29 #include "input_manager.hpp"
30 #include "recents.hpp"
32 #include <vlc_actions.h> /* ACTION_ID */
33 #include <vlc_url.h> /* vlc_uri_decode */
34 #include <vlc_strings.h> /* vlc_strfinput */
35 #include <vlc_aout.h> /* audio_output_t */
37 #include <QApplication>
40 #include <QSignalMapper>
41 #include <QMessageBox>
45 static int InputEvent( vlc_object_t
*, const char *,
46 vlc_value_t
, vlc_value_t
, void * );
47 static int VbiEvent( vlc_object_t
*, const char *,
48 vlc_value_t
, vlc_value_t
, void * );
50 /* Ensure arbitratry (not dynamically allocated) event IDs are not in use */
51 static inline void registerAndCheckEventIds( int start
, int end
)
53 for ( int i
=start
; i
<=end
; i
++ )
54 Q_ASSERT( QEvent::registerEventType( i
) == i
); /* event ID collision ! */
57 /**********************************************************************
58 * InputManager implementation
59 **********************************************************************
60 * The Input Manager can be the main one around the playlist
61 * But can also be used for VLM dialog or similar
62 **********************************************************************/
64 InputManager::InputManager( MainInputManager
*mim
, intf_thread_t
*_p_intf
) :
65 QObject( mim
), p_intf( _p_intf
)
68 i_old_playing_status
= END_S
;
76 timeA
= VLC_TICK_INVALID
;
77 timeB
= VLC_TICK_INVALID
;
78 f_cache
= -1.; /* impossible initial value, different from all */
79 registerAndCheckEventIds( IMEvent::PositionUpdate
, IMEvent::FullscreenControlPlanHide
);
80 registerAndCheckEventIds( PLEvent::PLItemAppended
, PLEvent::PLEmpty
);
83 InputManager::~InputManager()
88 void InputManager::inputChangedHandler()
90 setInput( p_mim
->getInput() );
93 /* Define the Input used.
94 Add the callbacks on input
95 p_input is held once here */
96 void InputManager::setInput( input_thread_t
*_p_input
)
100 if( p_input
!= NULL
)
102 msg_Dbg( p_intf
, "IM: Setting an input" );
103 vlc_object_hold( p_input
);
113 p_item
= input_GetItem( p_input
);
114 emit
rateChanged( var_GetFloat( p_input
, "rate" ) );
117 if( p_item
->i_type
== ITEM_TYPE_FILE
)
119 char *uri
= input_item_GetURI( p_item
);
121 vlc_tick_t i_time
= RecentsMRL::getInstance( p_intf
)->time( qfu(uri
) );
122 if( i_time
> 0 && qfu( uri
) != lastURI
&&
123 !var_GetFloat( p_input
, "run-time" ) &&
124 !var_GetFloat( p_input
, "start-time" ) &&
125 !var_GetFloat( p_input
, "stop-time" ) )
127 emit
resumePlayback( i_time
);
129 playlist_Lock( THEPL
);
130 // Add root items only
131 playlist_item_t
* p_node
= playlist_CurrentPlayingItem( THEPL
);
132 if ( p_node
!= NULL
&& p_node
->p_parent
!= NULL
&& p_node
->p_parent
->i_id
== THEPL
->p_playing
->i_id
)
134 // Save the latest URI to avoid asking to restore the
135 // position on the same input file.
136 lastURI
= qfu( uri
);
137 RecentsMRL::getInstance( p_intf
)->addRecent( lastURI
);
139 playlist_Unlock( THEPL
);
147 assert( !p_input_vbi
);
148 emit
rateChanged( var_InheritFloat( p_intf
, "rate" ) );
152 /* delete Input if it ever existed.
153 Delete the callbacls on input
154 p_input is released once here */
155 void InputManager::delInput()
157 if( !p_input
) return;
158 msg_Dbg( p_intf
, "IM: Deleting the input" );
160 /* Save time / position */
161 char *uri
= input_item_GetURI( p_item
);
163 float f_pos
= var_GetFloat( p_input
, "position" );
164 vlc_tick_t i_time
= -1;
166 if( f_pos
>= 0.05f
&& f_pos
<= 0.95f
167 && var_GetInteger( p_input
, "length" ) >= VLC_TICK_FROM_SEC(60))
168 i_time
= var_GetInteger( p_input
, "time");
170 RecentsMRL::getInstance( p_intf
)->setTime( qfu(uri
), i_time
);
175 i_old_playing_status
= END_S
;
180 timeA
= VLC_TICK_INVALID
;
181 timeB
= VLC_TICK_INVALID
;
186 vlc_object_release( p_input_vbi
);
190 vlc_object_release( p_input
);
193 emit
positionUpdated( -1.0, 0 ,0 );
194 emit
rateChanged( var_InheritFloat( p_intf
, "rate" ) );
195 emit
nameChanged( "" );
196 emit
chapterChanged( 0 );
197 emit
titleChanged( 0 );
198 emit
playingStatusChanged( END_S
);
200 emit
teletextPossible( false );
201 emit
AtoBchanged( false, false );
202 emit
voutChanged( false );
203 emit
voutListChanged( NULL
, 0 );
205 /* Reset all InfoPanels but stats */
206 emit
artChanged( NULL
);
207 emit
artChanged( "" );
208 emit
infoChanged( NULL
);
209 emit
currentMetaChanged( (input_item_t
*)NULL
);
211 emit
encryptionChanged( false );
212 emit
recordingStateChanged( false );
214 emit
cachingChanged( 0.0 );
217 /* Convert the event from the callbacks in actions */
218 void InputManager::customEvent( QEvent
*event
)
220 int i_type
= event
->type();
221 IMEvent
*ple
= static_cast<IMEvent
*>(event
);
223 if( i_type
== IMEvent::ItemChanged
)
224 UpdateMeta( ple
->item() );
232 case IMEvent::CapabilitiesChanged
:
233 UpdateCapabilities();
235 case IMEvent::PositionUpdate
:
238 case IMEvent::StatisticsUpdate
:
241 case IMEvent::ItemChanged
:
242 /* Ignore ItemChanged_Type event that does not apply to our input */
243 if( p_item
== ple
->item() )
249 /* Update duration of file */
252 case IMEvent::ItemStateChanged
:
255 case IMEvent::MetaChanged
:
257 UpdateName(); /* Needed for NowPlaying */
258 UpdateArt(); /* Art is part of meta in the core */
260 case IMEvent::InfoChanged
:
263 case IMEvent::ItemTitleChanged
:
265 UpdateName(); /* Display the name of the Chapter, if exists */
267 case IMEvent::ItemRateChanged
:
270 case IMEvent::ItemEsChanged
:
273 case IMEvent::InterfaceVoutUpdate
:
276 case IMEvent::SynchroChanged
:
277 emit
synchroChanged();
279 case IMEvent::CachingEvent
:
282 case IMEvent::BookmarksChanged
:
283 emit
bookmarksChanged();
285 case IMEvent::RecordingEvent
:
288 case IMEvent::ProgramChanged
:
289 UpdateProgramEvent();
291 case IMEvent::EPGEvent
:
295 msg_Warn( p_intf
, "This shouldn't happen: %i", i_type
);
296 vlc_assert_unreachable();
300 /* Add the callbacks on Input. Self explanatory */
301 inline void InputManager::addCallbacks()
303 var_AddCallback( p_input
, "intf-event", InputEvent
, this );
306 /* Delete the callbacks on Input. Self explanatory */
307 inline void InputManager::delCallbacks()
309 var_DelCallback( p_input
, "intf-event", InputEvent
, this );
312 /* Static callbacks for IM */
313 int MainInputManager::ItemChanged( vlc_object_t
*, const char *,
314 vlc_value_t
, vlc_value_t val
, void *param
)
316 InputManager
*im
= (InputManager
*)param
;
317 input_item_t
*p_item
= static_cast<input_item_t
*>(val
.p_address
);
319 IMEvent
*event
= new IMEvent( IMEvent::ItemChanged
, p_item
);
320 QApplication::postEvent( im
, event
);
324 static int InputEvent( vlc_object_t
*, const char *,
325 vlc_value_t
, vlc_value_t newval
, void *param
)
327 InputManager
*im
= (InputManager
*)param
;
330 switch( newval
.i_int
)
332 case INPUT_EVENT_STATE
:
333 event
= new IMEvent( IMEvent::ItemStateChanged
);
335 case INPUT_EVENT_RATE
:
336 event
= new IMEvent( IMEvent::ItemRateChanged
);
338 case INPUT_EVENT_CAPABILITIES
:
339 event
= new IMEvent( IMEvent::CapabilitiesChanged
);
341 case INPUT_EVENT_POSITION
:
342 //case INPUT_EVENT_LENGTH:
343 event
= new IMEvent( IMEvent::PositionUpdate
);
346 case INPUT_EVENT_TITLE
:
347 case INPUT_EVENT_CHAPTER
:
348 event
= new IMEvent( IMEvent::ItemTitleChanged
);
352 event
= new IMEvent( IMEvent::ItemEsChanged
);
355 case INPUT_EVENT_STATISTICS
:
356 event
= new IMEvent( IMEvent::StatisticsUpdate
);
359 case INPUT_EVENT_VOUT
:
360 event
= new IMEvent( IMEvent::InterfaceVoutUpdate
);
363 case INPUT_EVENT_ITEM_META
: /* Codec MetaData + Art */
364 event
= new IMEvent( IMEvent::MetaChanged
);
366 case INPUT_EVENT_ITEM_INFO
: /* Codec Info */
367 event
= new IMEvent( IMEvent::InfoChanged
);
370 case INPUT_EVENT_AUDIO_DELAY
:
371 case INPUT_EVENT_SUBTITLE_DELAY
:
372 event
= new IMEvent( IMEvent::SynchroChanged
);
375 case INPUT_EVENT_CACHE
:
376 event
= new IMEvent( IMEvent::CachingEvent
);
379 case INPUT_EVENT_BOOKMARK
:
380 event
= new IMEvent( IMEvent::BookmarksChanged
);
383 case INPUT_EVENT_RECORD
:
384 event
= new IMEvent( IMEvent::RecordingEvent
);
387 case INPUT_EVENT_PROGRAM
:
388 /* This is for PID changes */
389 event
= new IMEvent( IMEvent::ProgramChanged
);
392 case INPUT_EVENT_ITEM_EPG
:
393 /* EPG data changed */
394 event
= new IMEvent( IMEvent::EPGEvent
);
397 case INPUT_EVENT_SIGNAL
:
398 /* This is for capture-card signals */
399 /* event = new IMEvent( SignalChanged_Type );
407 QApplication::postEvent( im
, event
);
411 static int VbiEvent( vlc_object_t
*, const char *,
412 vlc_value_t
, vlc_value_t
, void *param
)
414 InputManager
*im
= (InputManager
*)param
;
415 IMEvent
*event
= new IMEvent( IMEvent::ItemEsChanged
);
417 QApplication::postEvent( im
, event
);
421 void InputManager::UpdatePosition()
423 /* Update position */
424 vlc_tick_t i_length
= var_GetInteger( p_input
, "length" );
425 vlc_tick_t i_time
= var_GetInteger( p_input
, "time");
426 float f_pos
= var_GetFloat( p_input
, "position" );
427 emit
positionUpdated( f_pos
, i_time
, SEC_FROM_VLC_TICK(i_length
) );
430 void InputManager::UpdateNavigation()
432 /* Update navigation status */
433 size_t ntitles
, nchapters
;
435 var_Change( p_input
, "title", VLC_VAR_CHOICESCOUNT
, &ntitles
);
442 input_title_t
**pp_title
= NULL
;
444 if( input_Control( p_input
, INPUT_GET_FULL_TITLE_INFO
, &pp_title
, &i_title
) == VLC_SUCCESS
)
446 for( int i
= 0; i
< i_title
; i
++ )
448 if( pp_title
[i
]->i_flags
& INPUT_TITLE_MENU
)
450 vlc_input_title_Delete(pp_title
[i
]);
456 /* p_input != NULL since val.i_int != 0 */
457 var_Change( p_input
, "chapter", VLC_VAR_CHOICESCOUNT
, &nchapters
);
459 emit
titleChanged( b_menu
);
460 emit
chapterChanged( nchapters
> 1 );
463 emit
chapterChanged( false );
466 emit
inputCanSeek( var_GetBool( p_input
, "can-seek" ) );
468 emit
inputCanSeek( false );
471 void InputManager::UpdateCapabilities()
473 emit
inputCanSeek( var_GetBool( p_input
, "can-seek" ) );
476 void InputManager::UpdateStatus()
478 /* Update playing status */
479 int state
= var_GetInteger( p_input
, "state" );
480 if( i_old_playing_status
!= state
)
482 i_old_playing_status
= state
;
483 emit
playingStatusChanged( state
);
487 void InputManager::UpdateRate()
490 float f_new_rate
= var_GetFloat( p_input
, "rate" );
491 if( f_new_rate
!= f_rate
)
495 emit
rateChanged( f_rate
);
499 void InputManager::UpdateName()
501 /* Update text, name and nowplaying */
504 /* Try to get the nowplaying */
505 char *format
= var_InheritString( p_intf
, "input-title-format" );
506 char *formatted
= NULL
;
509 formatted
= vlc_strfinput( p_input
, NULL
, format
);
511 if( formatted
!= NULL
)
513 name
= qfu(formatted
);
518 /* If we have Nothing */
519 if( name
.simplified().isEmpty() )
521 char *uri
= input_item_GetURI( input_GetItem( p_input
) );
522 char *file
= uri
? strrchr( uri
, '/' ) : NULL
;
525 vlc_uri_decode( ++file
);
533 name
= name
.trimmed();
535 if( oldName
!= name
)
537 emit
nameChanged( name
);
542 int InputManager::playingStatus() const
544 return i_old_playing_status
;
547 bool InputManager::hasAudio()
552 var_Change( p_input
, "audio-es", VLC_VAR_CHOICESCOUNT
, &val
);
558 bool InputManager::hasVisualisation()
563 audio_output_t
*aout
= input_GetAout( p_input
);
567 char *visual
= var_InheritString( aout
, "visual" );
568 vlc_object_release( aout
);
577 void InputManager::UpdateTeletext()
579 const bool b_enabled
= var_CountChoices( p_input
, "teletext-es" ) > 0;
580 const int i_teletext_es
= var_GetInteger( p_input
, "teletext-es" );
582 /* Teletext is possible. Show the buttons */
583 emit
teletextPossible( b_enabled
);
585 /* If Teletext is selected */
586 if( b_enabled
&& i_teletext_es
>= 0 )
588 /* Then, find the current page */
590 bool b_transparent
= false;
594 var_DelCallback( p_input_vbi
, "vbi-page", VbiEvent
, this );
595 vlc_object_release( p_input_vbi
);
598 if( input_GetEsObjects( p_input
, i_teletext_es
, &p_input_vbi
, NULL
, NULL
) )
603 /* This callback is not remove explicitly, but interfaces
604 * are guaranted to outlive input */
605 var_AddCallback( p_input_vbi
, "vbi-page", VbiEvent
, this );
607 i_page
= var_GetInteger( p_input_vbi
, "vbi-page" );
608 b_transparent
= !var_GetBool( p_input_vbi
, "vbi-opaque" );
610 emit
newTelexPageSet( i_page
);
611 emit
teletextTransparencyActivated( b_transparent
);
614 emit
teletextActivated( b_enabled
&& i_teletext_es
>= 0 );
617 void InputManager::UpdateEPG()
622 void InputManager::UpdateVout()
625 vout_thread_t
**pp_vout
;
630 /* Get current vout lists from input */
631 if( input_Control( p_input
, INPUT_GET_VOUTS
, &pp_vout
, &i_vout
) )
638 emit
voutListChanged( pp_vout
, i_vout
);
641 bool b_old_video
= b_video
;
642 b_video
= i_vout
> 0;
643 if( !!b_old_video
!= !!b_video
)
644 emit
voutChanged( b_video
);
646 /* Release the vout list */
647 for( size_t i
= 0; i
< i_vout
; i
++ )
648 vlc_object_release( (vlc_object_t
*)pp_vout
[i
] );
652 void InputManager::UpdateCaching()
654 float f_newCache
= var_GetFloat ( p_input
, "cache" );
655 if( f_newCache
!= f_cache
)
657 f_cache
= f_newCache
;
659 emit
cachingChanged( f_cache
);
663 void InputManager::requestArtUpdate( input_item_t
*p_item
, bool b_forced
)
665 bool b_current_item
= false;
666 if ( !p_item
&& hasInput() )
667 { /* default to current item */
668 p_item
= input_GetItem( p_input
);
669 b_current_item
= true;
674 /* check if it has already been enqueued */
675 if ( p_item
->p_meta
&& !b_forced
)
677 int status
= vlc_meta_GetStatus( p_item
->p_meta
);
678 if ( status
& ( ITEM_ART_NOTFOUND
|ITEM_ART_FETCHED
) )
681 libvlc_ArtRequest( p_intf
->obj
.libvlc
, p_item
,
682 (b_forced
) ? META_REQUEST_OPTION_SCOPE_ANY
683 : META_REQUEST_OPTION_NONE
,
685 /* No input will signal the cover art to update,
686 * let's do it ourself */
687 if ( b_current_item
)
690 emit
artChanged( p_item
);
694 const QString
InputManager::decodeArtURL( input_item_t
*p_item
)
698 char *psz_art
= input_item_GetArtURL( p_item
);
701 char *psz
= vlc_uri2path( psz_art
);
707 /* Taglib seems to define a attachment://, It won't work yet */
708 url
= url
.replace( "attachment://", "" );
711 QString path
= qfu( psz_art
? psz_art
: "" );
716 void InputManager::UpdateArt()
718 QString url
= decodeArtURL( input_GetItem( p_input
) );
720 /* the art hasn't changed, no need to update */
724 /* Update Art meta */
726 emit
artChanged( artUrl
);
729 void InputManager::setArt( input_item_t
*p_item
, QString fileUrl
)
733 char *psz_cachedir
= config_GetUserDir( VLC_CACHE_DIR
);
734 QString old_url
= p_mim
->getIM()->decodeArtURL( p_item
);
735 old_url
= QDir( old_url
).canonicalPath();
737 if( old_url
.startsWith( QString::fromUtf8( psz_cachedir
) ) )
738 QFile( old_url
).remove(); /* Purge cached artwork */
740 free( psz_cachedir
);
742 input_item_SetArtURL( p_item
, fileUrl
.toUtf8().constData() );
747 inline void InputManager::UpdateStats()
749 emit
statisticsUpdated( input_GetItem( p_input
) );
752 inline void InputManager::UpdateMeta( input_item_t
*p_item_
)
754 emit
metaChanged( p_item_
);
755 emit
artChanged( p_item_
);
758 inline void InputManager::UpdateMeta()
760 emit
currentMetaChanged( input_GetItem( p_input
) );
763 inline void InputManager::UpdateInfo()
766 emit
infoChanged( input_GetItem( p_input
) );
769 void InputManager::UpdateRecord()
771 emit
recordingStateChanged( var_GetBool( p_input
, "record" ) );
774 void InputManager::UpdateProgramEvent()
776 bool b_scrambled
= var_GetBool( p_input
, "program-scrambled" );
777 emit
encryptionChanged( b_scrambled
);
780 /* User update of the slider */
781 void InputManager::sliderUpdate( float new_pos
)
784 var_SetFloat( p_input
, "position", new_pos
);
785 emit
seekRequested( new_pos
);
788 void InputManager::sectionPrev()
792 int i_type
= var_Type( p_input
, "next-chapter" );
793 var_TriggerCallback( p_input
, (i_type
& VLC_VAR_TYPE
) != 0 ?
794 "prev-chapter":"prev-title" );
798 void InputManager::sectionNext()
802 int i_type
= var_Type( p_input
, "next-chapter" );
803 var_TriggerCallback( p_input
, (i_type
& VLC_VAR_TYPE
) != 0 ?
804 "next-chapter":"next-title" );
808 void InputManager::sectionMenu()
812 var_TriggerCallback( p_input
, "menu-title" );
820 void InputManager::changeProgram( int program
)
824 var_SetInteger( p_input
, "program", program
);
828 /* Set a new Teletext Page */
829 void InputManager::telexSetPage( int page
)
831 if( hasInput() && p_input_vbi
)
833 const int i_teletext_es
= var_GetInteger( p_input
, "teletext-es" );
835 if( i_teletext_es
>= 0 )
837 var_SetInteger( p_input_vbi
, "vbi-page", page
);
838 emit
newTelexPageSet( page
);
843 /* Set the transparency on teletext */
844 void InputManager::telexSetTransparency( bool b_transparentTelextext
)
846 if( hasInput() && p_input_vbi
)
848 var_SetBool( p_input_vbi
, "vbi-opaque", !b_transparentTelextext
);
849 emit
teletextTransparencyActivated( b_transparentTelextext
);
853 void InputManager::activateTeletext( bool b_enable
)
859 if( hasInput() && !var_Change( p_input
, "teletext-es", VLC_VAR_GETCHOICES
,
860 &count
, &list
, &text
) )
863 { /* Prefer the page 100 if it is present */
864 int id
= list
[0].i_int
;
865 for( size_t i
= 0; i
< count
; i
++ )
866 { /* The description is the page number as a string */
867 if( text
[i
] != NULL
&& !strcmp( text
[i
], "100" ) )
871 var_SetInteger( p_input
, "spu-es", b_enable
? id
: -1 );
878 void InputManager::reverse()
882 float f_rate_
= var_GetFloat( p_input
, "rate" );
883 var_SetFloat( p_input
, "rate", -f_rate_
);
887 void InputManager::slower()
889 var_TriggerCallback( THEPL
, "rate-slower" );
892 void InputManager::faster()
894 var_TriggerCallback( THEPL
, "rate-faster" );
897 void InputManager::littlefaster()
899 var_SetInteger( p_intf
->obj
.libvlc
, "key-action", ACTIONID_RATE_FASTER_FINE
);
902 void InputManager::littleslower()
904 var_SetInteger( p_intf
->obj
.libvlc
, "key-action", ACTIONID_RATE_SLOWER_FINE
);
907 void InputManager::normalRate()
909 var_SetFloat( THEPL
, "rate", 1. );
912 void InputManager::setRate( float new_rate
)
914 var_SetFloat( THEPL
, "rate", new_rate
);
917 void InputManager::jumpFwd()
919 int i_interval
= var_InheritInteger( p_input
, "short-jump-size" );
920 if( i_interval
> 0 && hasInput() )
922 vlc_tick_t val
= vlc_tick_from_sec( i_interval
);
923 var_SetInteger( p_input
, "time-offset", val
);
927 void InputManager::jumpBwd()
929 int i_interval
= var_InheritInteger( p_input
, "short-jump-size" );
930 if( i_interval
> 0 && hasInput() )
932 vlc_tick_t val
= vlc_tick_from_sec( -i_interval
);
933 var_SetInteger( p_input
, "time-offset", val
);
937 void InputManager::setAtoB()
939 if( timeA
!= VLC_TICK_INVALID
)
941 timeA
= var_GetInteger( p_mim
->getInput(), "time" );
943 else if( timeB
!= VLC_TICK_INVALID
)
945 timeB
= var_GetInteger( p_mim
->getInput(), "time" );
946 var_SetInteger( p_mim
->getInput(), "time" , timeA
);
947 CONNECT( this, positionUpdated( float, vlc_tick_t
, int ),
948 this, AtoBLoop( float, vlc_tick_t
, int ) );
952 timeA
= VLC_TICK_INVALID
;
953 timeB
= VLC_TICK_INVALID
;
954 disconnect( this, SIGNAL( positionUpdated( float, vlc_tick_t
, int ) ),
955 this, SLOT( AtoBLoop( float, vlc_tick_t
, int ) ) );
957 emit
AtoBchanged( (timeA
!= VLC_TICK_INVALID
), (timeB
!= VLC_TICK_INVALID
) );
960 /* Function called regularly when in an AtoB loop */
961 void InputManager::AtoBLoop( float, vlc_tick_t i_time
, int )
963 if( timeB
!= VLC_TICK_INVALID
&& i_time
>= timeB
)
964 var_SetInteger( p_mim
->getInput(), "time" , timeA
);
967 /**********************************************************************
968 * MainInputManager implementation. Wrap an input manager and
969 * take care of updating the main playlist input.
970 * Used in the main playlist Dialog
971 **********************************************************************/
973 MainInputManager::MainInputManager( intf_thread_t
*_p_intf
)
974 : QObject(NULL
), p_input( NULL
), p_intf( _p_intf
),
975 random( VLC_OBJECT(THEPL
), "random" ),
976 repeat( VLC_OBJECT(THEPL
), "repeat" ), loop( VLC_OBJECT(THEPL
), "loop" ),
977 volume( VLC_OBJECT(THEPL
), "volume" ), mute( VLC_OBJECT(THEPL
), "mute" )
979 im
= new InputManager( this, p_intf
);
982 menusAudioMapper
= new QSignalMapper();
983 CONNECT( menusAudioMapper
, mapped(QString
), this, menusUpdateAudio( QString
) );
986 var_AddCallback( THEPL
, "item-change", MainInputManager::ItemChanged
, im
);
987 var_AddCallback( THEPL
, "input-current", MainInputManager::PLItemChanged
, this );
988 var_AddCallback( THEPL
, "leaf-to-parent", MainInputManager::LeafToParent
, this );
989 var_AddCallback( THEPL
, "playlist-item-append", MainInputManager::PLItemAppended
, this );
990 var_AddCallback( THEPL
, "playlist-item-deleted", MainInputManager::PLItemRemoved
, this );
992 /* Core Callbacks to widget */
993 random
.addCallback( this, SLOT(notifyRandom(bool)) );
994 repeat
.addCallback( this, SLOT(notifyRepeatLoop(bool)) );
995 loop
.addCallback( this, SLOT(notifyRepeatLoop(bool)) );
996 volume
.addCallback( this, SLOT(notifyVolume(float)) );
997 mute
.addCallback( this, SLOT(notifyMute(bool)) );
999 /* Warn our embedded IM about input changes */
1000 DCONNECT( this, inputChanged( bool ),
1001 im
, inputChangedHandler() );
1004 MainInputManager::~MainInputManager()
1008 vlc_object_release( p_input
);
1010 emit
inputChanged( false );
1013 var_DelCallback( THEPL
, "input-current", MainInputManager::PLItemChanged
, this );
1014 var_DelCallback( THEPL
, "item-change", MainInputManager::ItemChanged
, im
);
1015 var_DelCallback( THEPL
, "leaf-to-parent", MainInputManager::LeafToParent
, this );
1017 var_DelCallback( THEPL
, "playlist-item-append", MainInputManager::PLItemAppended
, this );
1018 var_DelCallback( THEPL
, "playlist-item-deleted", MainInputManager::PLItemRemoved
, this );
1020 delete menusAudioMapper
;
1023 vout_thread_t
* MainInputManager::getVout()
1025 return p_input
? input_GetVout( p_input
) : NULL
;
1028 QVector
<vout_thread_t
*> MainInputManager::getVouts() const
1030 vout_thread_t
**pp_vout
;
1034 || input_Control( p_input
, INPUT_GET_VOUTS
, &pp_vout
, &i_vout
) != VLC_SUCCESS
1036 return QVector
<vout_thread_t
*>();
1038 QVector
<vout_thread_t
*> vector
= QVector
<vout_thread_t
*>();
1039 vector
.reserve( i_vout
);
1040 for( size_t i
= 0; i
< i_vout
; i
++ )
1042 assert( pp_vout
[i
] );
1043 vector
.append( pp_vout
[i
] );
1050 audio_output_t
* MainInputManager::getAout()
1052 return playlist_GetAout( THEPL
);
1055 void MainInputManager::customEvent( QEvent
*event
)
1057 int type
= event
->type();
1061 // msg_Dbg( p_intf, "New MainIM Event of type: %i", type );
1064 case PLEvent::PLItemAppended
:
1065 plEv
= static_cast<PLEvent
*>( event
);
1066 emit
playlistItemAppended( plEv
->getItemId(), plEv
->getParentId() );
1068 case PLEvent::PLItemRemoved
:
1069 plEv
= static_cast<PLEvent
*>( event
);
1070 emit
playlistItemRemoved( plEv
->getItemId() );
1072 case PLEvent::PLEmpty
:
1073 plEv
= static_cast<PLEvent
*>( event
);
1074 emit
playlistNotEmpty( plEv
->getItemId() >= 0 );
1076 case PLEvent::LeafToParent
:
1077 plEv
= static_cast<PLEvent
*>( event
);
1078 emit
leafBecameParent( plEv
->getItemId() );
1081 if( type
!= IMEvent::ItemChanged
) return;
1083 probeCurrentInput();
1086 void MainInputManager::probeCurrentInput()
1088 if( p_input
!= NULL
)
1089 vlc_object_release( p_input
);
1090 p_input
= playlist_CurrentInput( THEPL
);
1091 emit
inputChanged( p_input
!= NULL
);
1094 /* Playlist Control functions */
1095 void MainInputManager::stop()
1097 playlist_Stop( THEPL
);
1100 void MainInputManager::next()
1102 playlist_Next( THEPL
);
1105 void MainInputManager::prev()
1107 playlist_Prev( THEPL
);
1110 void MainInputManager::prevOrReset()
1112 if( !p_input
|| var_GetInteger( p_input
, "time") < VLC_TICK_FROM_MS(10) )
1113 playlist_Prev( THEPL
);
1115 getIM()->sliderUpdate( 0.0 );
1118 void MainInputManager::togglePlayPause()
1120 playlist_TogglePause( THEPL
);
1123 void MainInputManager::play()
1125 playlist_Play( THEPL
);
1128 void MainInputManager::pause()
1130 playlist_Pause( THEPL
);
1133 void MainInputManager::toggleRandom()
1135 config_PutInt( "random", var_ToggleBool( THEPL
, "random" ) );
1138 void MainInputManager::notifyRandom(bool value
)
1140 emit
randomChanged(value
);
1143 void MainInputManager::notifyRepeatLoop(bool)
1145 int i_state
= NORMAL
;
1147 if( var_GetBool( THEPL
, "loop" ) ) i_state
= REPEAT_ALL
;
1148 if( var_GetBool( THEPL
, "repeat" ) ) i_state
= REPEAT_ONE
;
1150 emit
repeatLoopChanged( i_state
);
1153 void MainInputManager::loopRepeatLoopStatus()
1155 /* Toggle Normal -> Loop -> Repeat -> Normal ... */
1156 bool loop
= var_GetBool( THEPL
, "loop" );
1157 bool repeat
= var_GetBool( THEPL
, "repeat" );
1175 var_SetBool( THEPL
, "loop", loop
);
1176 var_SetBool( THEPL
, "repeat", repeat
);
1177 config_PutInt( "loop", loop
);
1178 config_PutInt( "repeat", repeat
);
1181 void MainInputManager::activatePlayQuit( bool b_exit
)
1183 var_SetBool( THEPL
, "play-and-exit", b_exit
);
1184 config_PutInt( "play-and-exit", b_exit
);
1187 bool MainInputManager::getPlayExitState()
1189 return var_InheritBool( THEPL
, "play-and-exit" );
1192 bool MainInputManager::hasEmptyPlaylist()
1194 playlist_Lock( THEPL
);
1195 bool b_empty
= playlist_IsEmpty( THEPL
);
1196 playlist_Unlock( THEPL
);
1200 /****************************
1201 * Static callbacks for MIM *
1202 ****************************/
1203 int MainInputManager::PLItemChanged( vlc_object_t
*, const char *,
1204 vlc_value_t
, vlc_value_t
, void *param
)
1206 MainInputManager
*mim
= (MainInputManager
*)param
;
1208 IMEvent
*event
= new IMEvent( IMEvent::ItemChanged
);
1209 QApplication::postEvent( mim
, event
);
1213 int MainInputManager::LeafToParent( vlc_object_t
*, const char *,
1214 vlc_value_t
, vlc_value_t val
, void *param
)
1216 MainInputManager
*mim
= (MainInputManager
*)param
;
1218 PLEvent
*event
= new PLEvent( PLEvent::LeafToParent
, val
.i_int
);
1220 QApplication::postEvent( mim
, event
);
1224 void MainInputManager::notifyVolume( float volume
)
1226 emit
volumeChanged( volume
);
1229 void MainInputManager::notifyMute( bool mute
)
1231 emit
soundMuteChanged(mute
);
1235 void MainInputManager::menusUpdateAudio( const QString
& data
)
1237 audio_output_t
*aout
= getAout();
1240 aout_DeviceSet( aout
, qtu(data
) );
1241 vlc_object_release( aout
);
1245 int MainInputManager::PLItemAppended( vlc_object_t
*, const char *,
1246 vlc_value_t
, vlc_value_t cur
,
1249 MainInputManager
*mim
= static_cast<MainInputManager
*>(data
);
1250 playlist_item_t
*item
= static_cast<playlist_item_t
*>( cur
.p_address
);
1252 PLEvent
*event
= new PLEvent( PLEvent::PLItemAppended
, item
->i_id
,
1253 (item
->p_parent
!= NULL
) ? item
->p_parent
->i_id
: -1 );
1254 QApplication::postEvent( mim
, event
);
1256 event
= new PLEvent( PLEvent::PLEmpty
, item
->i_id
, 0 );
1257 QApplication::postEvent( mim
, event
);
1261 int MainInputManager::PLItemRemoved( vlc_object_t
*obj
, const char *,
1262 vlc_value_t
, vlc_value_t cur
, void *data
)
1264 playlist_t
*pl
= (playlist_t
*) obj
;
1265 MainInputManager
*mim
= static_cast<MainInputManager
*>(data
);
1266 playlist_item_t
*item
= static_cast<playlist_item_t
*>( cur
.p_address
);
1268 PLEvent
*event
= new PLEvent( PLEvent::PLItemRemoved
, item
->i_id
, 0 );
1269 QApplication::postEvent( mim
, event
);
1270 // can't use playlist_IsEmpty( ) as it isn't true yet
1271 if ( pl
->items
.i_size
== 1 ) // lock is held
1273 event
= new PLEvent( PLEvent::PLEmpty
, -1, 0 );
1274 QApplication::postEvent( mim
, event
);
1279 void MainInputManager::changeFullscreen( bool new_val
)
1281 if ( var_GetBool( THEPL
, "fullscreen" ) != new_val
)
1282 var_SetBool( THEPL
, "fullscreen", new_val
);