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 *****************************************************************************/
26 #define __STDC_FORMAT_MACROS 1
27 #define __STDC_CONSTANT_MACROS 1
33 #include "input_manager.hpp"
34 #include "recents.hpp"
36 #include <vlc_keys.h> /* ACTION_ID */
37 #include <vlc_url.h> /* decode_URI */
38 #include <vlc_strings.h> /* str_format_meta */
39 #include <vlc_aout.h> /* audio_output_t */
41 #include <QApplication>
44 #include <QSignalMapper>
45 #include <QMessageBox>
49 static int ItemChanged( vlc_object_t *, const char *,
50 vlc_value_t, vlc_value_t, void * );
51 static int LeafToParent( vlc_object_t *, const char *,
52 vlc_value_t, vlc_value_t, void * );
53 static int PLItemChanged( vlc_object_t *, const char *,
54 vlc_value_t, vlc_value_t, void * );
55 static int PLItemAppended( vlc_object_t *, const char *,
56 vlc_value_t, vlc_value_t, void * );
57 static int PLItemRemoved( vlc_object_t *, const char *,
58 vlc_value_t, vlc_value_t, void * );
60 static int InputEvent( vlc_object_t *, const char *,
61 vlc_value_t, vlc_value_t, void * );
62 static int VbiEvent( vlc_object_t *, const char *,
63 vlc_value_t, vlc_value_t, void * );
65 /* Ensure arbitratry (not dynamically allocated) event IDs are not in use */
66 static inline void registerAndCheckEventIds( int start, int end )
68 for ( int i=start ; i<=end ; i++ )
69 Q_ASSERT( QEvent::registerEventType( i ) == i ); /* event ID collision ! */
72 /**********************************************************************
73 * InputManager implementation
74 **********************************************************************
75 * The Input Manager can be the main one around the playlist
76 * But can also be used for VLM dialog or similar
77 **********************************************************************/
79 InputManager::InputManager( QObject *parent, intf_thread_t *_p_intf) :
80 QObject( parent ), p_intf( _p_intf )
82 i_old_playing_status = END_S;
92 f_cache = -1.; /* impossible initial value, different from all */
93 registerAndCheckEventIds( IMEvent::PositionUpdate, IMEvent::FullscreenControlPlanHide );
94 registerAndCheckEventIds( PLEvent::PLItemAppended, PLEvent::PLEmpty );
97 InputManager::~InputManager()
102 void InputManager::inputChangedHandler()
104 setInput( THEMIM->getInput() );
107 /* Define the Input used.
108 Add the callbacks on input
109 p_input is held once here */
110 void InputManager::setInput( input_thread_t *_p_input )
114 if( p_input != NULL )
116 msg_Dbg( p_intf, "IM: Setting an input" );
117 vlc_object_hold( p_input );
127 p_item = input_GetItem( p_input );
128 emit rateChanged( var_GetFloat( p_input, "rate" ) );
130 char *uri = input_item_GetURI( p_item );
133 if( p_item->i_type == ITEM_TYPE_FILE )
135 int i_time = RecentsMRL::getInstance( p_intf )->time( qfu(uri) );
136 if( i_time > 0 && qfu( uri ) != lastURI &&
137 !var_GetFloat( p_input, "run-time" ) &&
138 !var_GetFloat( p_input, "start-time" ) &&
139 !var_GetFloat( p_input, "stop-time" ) )
141 emit resumePlayback( (int64_t)i_time * 1000 );
145 // Save the latest URI to avoid asking to restore the
146 // position on the same input file.
147 lastURI = qfu( uri );
153 assert( !p_input_vbi );
154 emit rateChanged( var_InheritFloat( p_intf, "rate" ) );
158 /* delete Input if it ever existed.
159 Delete the callbacls on input
160 p_input is released once here */
161 void InputManager::delInput()
163 if( !p_input ) return;
164 msg_Dbg( p_intf, "IM: Deleting the input" );
166 /* Save time / position */
167 char *uri = input_item_GetURI( p_item );
169 float f_pos = var_GetFloat( p_input , "position" );
172 if( f_pos >= 0.05f && f_pos <= 0.95f
173 && var_GetTime( p_input, "length" ) >= 60 * CLOCK_FREQ )
174 i_time = var_GetTime( p_input, "time");
176 RecentsMRL::getInstance( p_intf )->setTime( qfu(uri), i_time );
181 i_old_playing_status = END_S;
192 vlc_object_release( p_input_vbi );
196 vlc_object_release( p_input );
199 emit positionUpdated( -1.0, 0 ,0 );
200 emit rateChanged( var_InheritFloat( p_intf, "rate" ) );
201 emit nameChanged( "" );
202 emit chapterChanged( 0 );
203 emit titleChanged( 0 );
204 emit playingStatusChanged( END_S );
206 emit teletextPossible( false );
207 emit AtoBchanged( false, false );
208 emit voutChanged( false );
209 emit voutListChanged( NULL, 0 );
211 /* Reset all InfoPanels but stats */
212 emit artChanged( NULL );
213 emit artChanged( "" );
214 emit infoChanged( NULL );
215 emit currentMetaChanged( (input_item_t *)NULL );
217 emit encryptionChanged( false );
218 emit recordingStateChanged( false );
220 emit cachingChanged( 0.0 );
223 /* Convert the event from the callbacks in actions */
224 void InputManager::customEvent( QEvent *event )
226 int i_type = event->type();
227 IMEvent *ple = static_cast<IMEvent *>(event);
229 if( i_type == IMEvent::ItemChanged )
230 UpdateMeta( ple->item() );
238 case IMEvent::PositionUpdate:
241 case IMEvent::StatisticsUpdate:
244 case IMEvent::ItemChanged:
245 /* Ignore ItemChanged_Type event that does not apply to our input */
246 if( p_item == ple->item() )
252 /* Update duration of file */
255 case IMEvent::ItemStateChanged:
258 case IMEvent::NameChanged:
261 case IMEvent::MetaChanged:
263 UpdateName(); /* Needed for NowPlaying */
264 UpdateArt(); /* Art is part of meta in the core */
266 case IMEvent::InfoChanged:
269 case IMEvent::ItemTitleChanged:
271 UpdateName(); /* Display the name of the Chapter, if exists */
273 case IMEvent::ItemRateChanged:
276 case IMEvent::ItemEsChanged:
278 // We don't do anything ES related. Why ?
280 case IMEvent::ItemTeletextChanged:
283 case IMEvent::InterfaceVoutUpdate:
286 case IMEvent::SynchroChanged:
287 emit synchroChanged();
289 case IMEvent::CachingEvent:
292 case IMEvent::BookmarksChanged:
293 emit bookmarksChanged();
295 case IMEvent::InterfaceAoutUpdate:
298 case IMEvent::RecordingEvent:
301 case IMEvent::ProgramChanged:
302 UpdateProgramEvent();
304 case IMEvent::EPGEvent:
308 msg_Warn( p_intf, "This shouldn't happen: %i", i_type );
309 vlc_assert_unreachable();
313 /* Add the callbacks on Input. Self explanatory */
314 inline void InputManager::addCallbacks()
316 var_AddCallback( p_input, "intf-event", InputEvent, this );
319 /* Delete the callbacks on Input. Self explanatory */
320 inline void InputManager::delCallbacks()
322 var_DelCallback( p_input, "intf-event", InputEvent, this );
325 /* Static callbacks for IM */
326 static int ItemChanged( vlc_object_t *p_this, const char *psz_var,
327 vlc_value_t oldval, vlc_value_t newval, void *param )
329 VLC_UNUSED( p_this ); VLC_UNUSED( psz_var ); VLC_UNUSED( oldval );
331 InputManager *im = (InputManager*)param;
332 input_item_t *p_item = static_cast<input_item_t *>(newval.p_address);
334 IMEvent *event = new IMEvent( IMEvent::ItemChanged, p_item );
335 QApplication::postEvent( im, event );
339 static int InputEvent( vlc_object_t *p_this, const char *,
340 vlc_value_t, vlc_value_t newval, void *param )
342 VLC_UNUSED( p_this );
344 InputManager *im = (InputManager*)param;
347 switch( newval.i_int )
349 case INPUT_EVENT_STATE:
350 event = new IMEvent( IMEvent::ItemStateChanged );
352 case INPUT_EVENT_RATE:
353 event = new IMEvent( IMEvent::ItemRateChanged );
355 case INPUT_EVENT_POSITION:
356 //case INPUT_EVENT_LENGTH:
357 event = new IMEvent( IMEvent::PositionUpdate );
360 case INPUT_EVENT_TITLE:
361 case INPUT_EVENT_CHAPTER:
362 event = new IMEvent( IMEvent::ItemTitleChanged );
366 event = new IMEvent( IMEvent::ItemEsChanged );
368 case INPUT_EVENT_TELETEXT:
369 event = new IMEvent( IMEvent::ItemTeletextChanged );
372 case INPUT_EVENT_STATISTICS:
373 event = new IMEvent( IMEvent::StatisticsUpdate );
376 case INPUT_EVENT_VOUT:
377 event = new IMEvent( IMEvent::InterfaceVoutUpdate );
379 case INPUT_EVENT_AOUT:
380 event = new IMEvent( IMEvent::InterfaceAoutUpdate );
383 case INPUT_EVENT_ITEM_META: /* Codec MetaData + Art */
384 event = new IMEvent( IMEvent::MetaChanged );
386 case INPUT_EVENT_ITEM_INFO: /* Codec Info */
387 event = new IMEvent( IMEvent::InfoChanged );
389 case INPUT_EVENT_ITEM_NAME:
390 event = new IMEvent( IMEvent::NameChanged );
393 case INPUT_EVENT_AUDIO_DELAY:
394 case INPUT_EVENT_SUBTITLE_DELAY:
395 event = new IMEvent( IMEvent::SynchroChanged );
398 case INPUT_EVENT_CACHE:
399 event = new IMEvent( IMEvent::CachingEvent );
402 case INPUT_EVENT_BOOKMARK:
403 event = new IMEvent( IMEvent::BookmarksChanged );
406 case INPUT_EVENT_RECORD:
407 event = new IMEvent( IMEvent::RecordingEvent );
410 case INPUT_EVENT_PROGRAM:
411 /* This is for PID changes */
412 event = new IMEvent( IMEvent::ProgramChanged );
415 case INPUT_EVENT_ITEM_EPG:
416 /* EPG data changed */
417 event = new IMEvent( IMEvent::EPGEvent );
420 case INPUT_EVENT_SIGNAL:
421 /* This is for capture-card signals */
422 /* event = new IMEvent( SignalChanged_Type );
430 QApplication::postEvent( im, event );
434 static int VbiEvent( vlc_object_t *, const char *,
435 vlc_value_t, vlc_value_t, void *param )
437 InputManager *im = (InputManager*)param;
438 IMEvent *event = new IMEvent( IMEvent::ItemTeletextChanged );
440 QApplication::postEvent( im, event );
444 void InputManager::UpdatePosition()
446 /* Update position */
450 i_length = var_GetTime( p_input , "length" ) / CLOCK_FREQ;
451 i_time = var_GetTime( p_input , "time");
452 f_pos = var_GetFloat( p_input , "position" );
453 emit positionUpdated( f_pos, i_time, i_length );
456 void InputManager::UpdateNavigation()
458 /* Update navigation status */
459 vlc_value_t val; val.i_int = 0;
460 vlc_value_t val2; val2.i_int = 0;
463 var_Change( p_input, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
467 /* p_input != NULL since val.i_int != 0 */
468 var_Change( p_input, "chapter", VLC_VAR_CHOICESCOUNT, &val2, NULL );
470 emit titleChanged( val.i_int > 1 );
471 emit chapterChanged( val2.i_int > 1 );
474 emit chapterChanged( false );
477 emit inputCanSeek( var_GetBool( p_input, "can-seek" ) );
479 emit inputCanSeek( false );
482 void InputManager::UpdateStatus()
484 /* Update playing status */
485 int state = var_GetInteger( p_input, "state" );
486 if( i_old_playing_status != state )
488 i_old_playing_status = state;
489 emit playingStatusChanged( state );
493 void InputManager::UpdateRate()
496 float f_new_rate = var_GetFloat( p_input, "rate" );
497 if( f_new_rate != f_rate )
501 emit rateChanged( f_rate );
505 void InputManager::UpdateName()
509 /* Update text, name and nowplaying */
512 /* Try to get the nowplaying */
513 char *format = var_InheritString( p_intf, "input-title-format" );
514 char *formated = str_format_meta( p_input, format );
516 name = qfu(formated);
519 /* If we have Nothing */
520 if( name.simplified().isEmpty() )
522 char *uri = input_item_GetURI( input_GetItem( p_input ) );
523 char *file = uri ? strrchr( uri, '/' ) : NULL;
526 decode_URI( ++file );
534 name = name.trimmed();
536 if( oldName != name )
538 emit nameChanged( name );
543 int InputManager::playingStatus()
545 return i_old_playing_status;
548 bool InputManager::hasAudio()
553 var_Change( p_input, "audio-es", VLC_VAR_CHOICESCOUNT, &val, NULL );
554 return val.i_int > 0;
559 bool InputManager::hasVisualisation()
564 audio_output_t *aout = input_GetAout( p_input );
568 char *visual = var_InheritString( aout, "visual" );
569 vlc_object_release( aout );
578 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 );
621 emit teletextActivated( false );
622 emit teletextPossible( false );
626 void InputManager::UpdateEPG()
634 void InputManager::UpdateVout()
638 /* Get current vout lists from input */
640 vout_thread_t **pp_vout;
641 if( input_Control( p_input, INPUT_GET_VOUTS, &pp_vout, &i_vout ) )
648 emit voutListChanged( pp_vout, i_vout );
651 bool b_old_video = b_video;
652 b_video = i_vout > 0;
653 if( !!b_old_video != !!b_video )
654 emit voutChanged( b_video );
656 /* Release the vout list */
657 for( size_t i = 0; i < i_vout; i++ )
658 vlc_object_release( (vlc_object_t*)pp_vout[i] );
662 void InputManager::UpdateAout()
669 void InputManager::UpdateCaching()
671 if(!hasInput()) return;
673 float f_newCache = var_GetFloat ( p_input, "cache" );
674 if( f_newCache != f_cache )
676 f_cache = f_newCache;
678 emit cachingChanged( f_cache );
682 void InputManager::requestArtUpdate( input_item_t *p_item, bool b_forced )
684 bool b_current_item = false;
685 if ( !p_item && hasInput() )
686 { /* default to current item */
687 p_item = input_GetItem( p_input );
688 b_current_item = true;
693 /* check if it has already been enqueued */
694 if ( p_item->p_meta && !b_forced )
696 int status = vlc_meta_GetStatus( p_item->p_meta );
697 if ( status & ( ITEM_ART_NOTFOUND|ITEM_ART_FETCHED ) )
700 libvlc_ArtRequest( p_intf->p_libvlc, p_item,
701 (b_forced) ? META_REQUEST_OPTION_SCOPE_ANY
702 : META_REQUEST_OPTION_NONE );
703 /* No input will signal the cover art to update,
704 * let's do it ourself */
705 if ( b_current_item )
708 emit artChanged( p_item );
712 const QString InputManager::decodeArtURL( input_item_t *p_item )
716 char *psz_art = input_item_GetArtURL( p_item );
719 char *psz = make_path( psz_art );
725 /* Taglib seems to define a attachment://, It won't work yet */
726 url = url.replace( "attachment://", "" );
729 QString path = qfu( psz_art ? psz_art : "" );
734 void InputManager::UpdateArt()
739 url = decodeArtURL( input_GetItem( p_input ) );
741 /* the art hasn't changed, no need to update */
745 /* Update Art meta */
747 emit artChanged( artUrl );
750 void InputManager::setArt( input_item_t *p_item, QString fileUrl )
754 char *psz_cachedir = config_GetUserDir( VLC_CACHE_DIR );
755 QString old_url = THEMIM->getIM()->decodeArtURL( p_item );
756 old_url = QDir( old_url ).canonicalPath();
758 if( old_url.startsWith( QString::fromUtf8( psz_cachedir ) ) )
759 QFile( old_url ).remove(); /* Purge cached artwork */
761 free( psz_cachedir );
763 input_item_SetArtURL( p_item , fileUrl.toUtf8().constData() );
768 inline void InputManager::UpdateStats()
771 emit statisticsUpdated( input_GetItem( p_input ) );
774 inline void InputManager::UpdateMeta( input_item_t *p_item_ )
776 emit metaChanged( p_item_ );
777 emit artChanged( p_item_ );
780 inline void InputManager::UpdateMeta()
783 emit currentMetaChanged( input_GetItem( p_input ) );
786 inline void InputManager::UpdateInfo()
789 emit infoChanged( input_GetItem( p_input ) );
792 void InputManager::UpdateRecord()
796 emit recordingStateChanged( var_GetBool( p_input, "record" ) );
800 void InputManager::UpdateProgramEvent()
804 bool b_scrambled = var_GetBool( p_input, "program-scrambled" );
805 emit encryptionChanged( b_scrambled );
809 /* User update of the slider */
810 void InputManager::sliderUpdate( float new_pos )
813 var_SetFloat( p_input, "position", new_pos );
814 emit seekRequested( new_pos );
817 void InputManager::sectionPrev()
821 int i_type = var_Type( p_input, "next-chapter" );
822 var_TriggerCallback( p_input, (i_type & VLC_VAR_TYPE) != 0 ?
823 "prev-chapter":"prev-title" );
827 void InputManager::sectionNext()
831 int i_type = var_Type( p_input, "next-chapter" );
832 var_TriggerCallback( p_input, (i_type & VLC_VAR_TYPE) != 0 ?
833 "next-chapter":"next-title" );
837 void InputManager::sectionMenu()
841 vlc_value_t val, text;
843 if( var_Change( p_input, "title 0", VLC_VAR_GETCHOICES, &val, &text ) < 0 )
846 /* XXX is it "Root" or "Title" we want here ?" (set 0 by default) */
848 for( int i = 0; i < val.p_list->i_count; i++ )
850 if( !strcmp( text.p_list->p_values[i].psz_string, "Title" ) )
853 var_FreeList( &val, &text );
855 var_SetInteger( p_input, "title 0", root );
863 /* Set a new Teletext Page */
864 void InputManager::telexSetPage( int page )
866 if( hasInput() && p_input_vbi )
868 const int i_teletext_es = var_GetInteger( p_input, "teletext-es" );
870 if( i_teletext_es >= 0 )
872 var_SetInteger( p_input_vbi, "vbi-page", page );
873 emit newTelexPageSet( page );
878 /* Set the transparency on teletext */
879 void InputManager::telexSetTransparency( bool b_transparentTelextext )
881 if( hasInput() && p_input_vbi )
883 var_SetBool( p_input_vbi, "vbi-opaque", !b_transparentTelextext );
884 emit teletextTransparencyActivated( b_transparentTelextext );
888 void InputManager::activateTeletext( bool b_enable )
892 if( hasInput() && !var_Change( p_input, "teletext-es", VLC_VAR_GETCHOICES, &list, &text ) )
894 if( list.p_list->i_count > 0 )
896 /* Prefer the page 100 if it is present */
898 for( i = 0; i < text.p_list->i_count; i++ )
900 /* The description is the page number as a string */
901 const char *psz_page = text.p_list->p_values[i].psz_string;
902 if( psz_page && !strcmp( psz_page, "100" ) )
905 if( i >= list.p_list->i_count )
907 var_SetInteger( p_input, "spu-es", b_enable ? list.p_list->p_values[i].i_int : -1 );
909 var_FreeList( &list, &text );
913 void InputManager::reverse()
917 float f_rate_ = var_GetFloat( p_input, "rate" );
918 var_SetFloat( p_input, "rate", -f_rate_ );
922 void InputManager::slower()
924 var_TriggerCallback( THEPL, "rate-slower" );
927 void InputManager::faster()
929 var_TriggerCallback( THEPL, "rate-faster" );
932 void InputManager::littlefaster()
934 var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_RATE_FASTER_FINE );
937 void InputManager::littleslower()
939 var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_RATE_SLOWER_FINE );
942 void InputManager::normalRate()
944 var_SetFloat( THEPL, "rate", 1. );
947 void InputManager::setRate( int new_rate )
949 var_SetFloat( THEPL, "rate",
950 (float)INPUT_RATE_DEFAULT / (float)new_rate );
953 void InputManager::jumpFwd()
955 int i_interval = var_InheritInteger( p_input, "short-jump-size" );
956 if( i_interval > 0 && hasInput() )
958 mtime_t val = CLOCK_FREQ * i_interval;
959 var_SetTime( p_input, "time-offset", val );
963 void InputManager::jumpBwd()
965 int i_interval = var_InheritInteger( p_input, "short-jump-size" );
966 if( i_interval > 0 && hasInput() )
968 mtime_t val = -CLOCK_FREQ * i_interval;
969 var_SetTime( p_input, "time-offset", val );
973 void InputManager::setAtoB()
977 timeA = var_GetTime( THEMIM->getInput(), "time" );
981 timeB = var_GetTime( THEMIM->getInput(), "time" );
982 var_SetTime( THEMIM->getInput(), "time" , timeA );
983 CONNECT( this, positionUpdated( float, int64_t, int ),
984 this, AtoBLoop( float, int64_t, int ) );
990 disconnect( this, SIGNAL( positionUpdated( float, int64_t, int ) ),
991 this, SLOT( AtoBLoop( float, int64_t, int ) ) );
993 emit AtoBchanged( (timeA != 0 ), (timeB != 0 ) );
996 /* Function called regularly when in an AtoB loop */
997 void InputManager::AtoBLoop( float, int64_t i_time, int )
999 if( timeB && i_time >= timeB )
1000 var_SetTime( THEMIM->getInput(), "time" , timeA );
1003 /**********************************************************************
1004 * MainInputManager implementation. Wrap an input manager and
1005 * take care of updating the main playlist input.
1006 * Used in the main playlist Dialog
1007 **********************************************************************/
1009 MainInputManager::MainInputManager( intf_thread_t *_p_intf )
1010 : QObject(NULL), p_input( NULL), p_intf( _p_intf ),
1011 random( VLC_OBJECT(THEPL), "random" ),
1012 repeat( VLC_OBJECT(THEPL), "repeat" ), loop( VLC_OBJECT(THEPL), "loop" ),
1013 volume( VLC_OBJECT(THEPL), "volume" ), mute( VLC_OBJECT(THEPL), "mute" )
1015 im = new InputManager( this, p_intf );
1018 menusAudioMapper = new QSignalMapper();
1019 CONNECT( menusAudioMapper, mapped(QString), this, menusUpdateAudio( QString ) );
1021 /* Core Callbacks */
1022 var_AddCallback( THEPL, "item-change", ItemChanged, im );
1023 var_AddCallback( THEPL, "activity", PLItemChanged, this );
1024 var_AddCallback( THEPL, "leaf-to-parent", LeafToParent, this );
1025 var_AddCallback( THEPL, "playlist-item-append", PLItemAppended, this );
1026 var_AddCallback( THEPL, "playlist-item-deleted", PLItemRemoved, this );
1028 /* Core Callbacks to widget */
1029 random.addCallback( this, SLOT(notifyRandom(bool)) );
1030 repeat.addCallback( this, SLOT(notifyRepeatLoop(bool)) );
1031 loop.addCallback( this, SLOT(notifyRepeatLoop(bool)) );
1032 volume.addCallback( this, SLOT(notifyVolume(float)) );
1033 mute.addCallback( this, SLOT(notifyMute(bool)) );
1035 /* Warn our embedded IM about input changes */
1036 DCONNECT( this, inputChanged( input_thread_t * ),
1037 im, inputChangedHandler() );
1039 /* initialize p_input (an input can already be running) */
1040 p_input = playlist_CurrentInput( THEPL );
1042 emit inputChanged( p_input );
1045 MainInputManager::~MainInputManager()
1049 vlc_object_release( p_input );
1051 emit inputChanged( NULL );
1054 var_DelCallback( THEPL, "activity", PLItemChanged, this );
1055 var_DelCallback( THEPL, "item-change", ItemChanged, im );
1056 var_DelCallback( THEPL, "leaf-to-parent", LeafToParent, this );
1058 var_DelCallback( THEPL, "playlist-item-append", PLItemAppended, this );
1059 var_DelCallback( THEPL, "playlist-item-deleted", PLItemRemoved, this );
1061 delete menusAudioMapper;
1064 vout_thread_t* MainInputManager::getVout()
1066 return p_input ? input_GetVout( p_input ) : NULL;
1069 audio_output_t * MainInputManager::getAout()
1071 return playlist_GetAout( THEPL );
1074 void MainInputManager::customEvent( QEvent *event )
1076 int type = event->type();
1080 // msg_Dbg( p_intf, "New MainIM Event of type: %i", type );
1083 case PLEvent::PLItemAppended:
1084 plEv = static_cast<PLEvent*>( event );
1085 emit playlistItemAppended( plEv->getItemId(), plEv->getParentId() );
1087 case PLEvent::PLItemRemoved:
1088 plEv = static_cast<PLEvent*>( event );
1089 emit playlistItemRemoved( plEv->getItemId() );
1091 case PLEvent::PLEmpty:
1092 plEv = static_cast<PLEvent*>( event );
1093 emit playlistNotEmpty( plEv->getItemId() >= 0 );
1095 case PLEvent::LeafToParent:
1096 plEv = static_cast<PLEvent*>( event );
1097 emit leafBecameParent( plEv->getItemId() );
1100 if( type != IMEvent::ItemChanged ) return;
1103 if( p_input != NULL )
1104 vlc_object_release( p_input );
1105 p_input = playlist_CurrentInput( THEPL );
1106 emit inputChanged( p_input );
1109 /* Playlist Control functions */
1110 void MainInputManager::stop()
1112 playlist_Stop( THEPL );
1113 getIM()->lastURI.clear();
1116 void MainInputManager::next()
1118 playlist_Next( THEPL );
1121 void MainInputManager::prev()
1123 playlist_Prev( THEPL );
1126 void MainInputManager::prevOrReset()
1128 if( !p_input || var_GetTime( p_input , "time") < 10000 )
1129 playlist_Prev( THEPL );
1131 getIM()->sliderUpdate( 0.0 );
1134 void MainInputManager::togglePlayPause()
1136 playlist_TogglePause( THEPL );
1139 void MainInputManager::play()
1141 playlist_Play( THEPL );
1144 void MainInputManager::pause()
1146 playlist_Pause( THEPL );
1149 void MainInputManager::toggleRandom()
1151 config_PutInt( p_intf, "random", var_ToggleBool( THEPL, "random" ) );
1154 void MainInputManager::notifyRandom(bool value)
1156 emit randomChanged(value);
1159 void MainInputManager::notifyRepeatLoop(bool)
1161 int i_value = var_GetBool( THEPL, "loop" ) * REPEAT_ALL
1162 + var_GetBool( THEPL, "repeat" ) * REPEAT_ONE;
1164 emit repeatLoopChanged( i_value );
1167 void MainInputManager::loopRepeatLoopStatus()
1169 /* Toggle Normal -> Loop -> Repeat -> Normal ... */
1170 bool loop = var_GetBool( THEPL, "loop" );
1171 bool repeat = var_GetBool( THEPL, "repeat" );
1189 var_SetBool( THEPL, "loop", loop );
1190 var_SetBool( THEPL, "repeat", repeat );
1191 config_PutInt( p_intf, "loop", loop );
1192 config_PutInt( p_intf, "repeat", repeat );
1195 void MainInputManager::activatePlayQuit( bool b_exit )
1197 var_SetBool( THEPL, "play-and-exit", b_exit );
1198 config_PutInt( p_intf, "play-and-exit", b_exit );
1201 bool MainInputManager::getPlayExitState()
1203 return var_InheritBool( THEPL, "play-and-exit" );
1206 bool MainInputManager::hasEmptyPlaylist()
1208 playlist_Lock( THEPL );
1209 bool b_empty = playlist_IsEmpty( THEPL );
1210 playlist_Unlock( THEPL );
1214 /****************************
1215 * Static callbacks for MIM *
1216 ****************************/
1217 static int PLItemChanged( vlc_object_t *p_this, const char *psz_var,
1218 vlc_value_t oldval, vlc_value_t val, void *param )
1220 VLC_UNUSED( p_this ); VLC_UNUSED( psz_var ); VLC_UNUSED( oldval );
1223 MainInputManager *mim = (MainInputManager*)param;
1225 IMEvent *event = new IMEvent( IMEvent::ItemChanged );
1226 QApplication::postEvent( mim, event );
1230 static int LeafToParent( vlc_object_t *p_this, const char *psz_var,
1231 vlc_value_t oldval, vlc_value_t newval, void *param )
1233 VLC_UNUSED( p_this ); VLC_UNUSED( psz_var ); VLC_UNUSED( oldval );
1234 MainInputManager *mim = (MainInputManager*)param;
1236 PLEvent *event = new PLEvent( PLEvent::LeafToParent, newval.i_int );
1238 QApplication::postEvent( mim, event );
1242 void MainInputManager::notifyVolume( float volume )
1244 emit volumeChanged( volume );
1247 void MainInputManager::notifyMute( bool mute )
1249 emit soundMuteChanged(mute);
1253 void MainInputManager::menusUpdateAudio( const QString& data )
1255 audio_output_t *aout = getAout();
1258 aout_DeviceSet( aout, qtu(data) );
1259 vlc_object_release( aout );
1263 static int PLItemAppended
1264 ( vlc_object_t * obj, const char *var, vlc_value_t old, vlc_value_t cur, void *data )
1266 VLC_UNUSED( obj ); VLC_UNUSED( var ); VLC_UNUSED( old );
1267 MainInputManager *mim = static_cast<MainInputManager*>(data);
1268 playlist_add_t *p_add = static_cast<playlist_add_t*>( cur.p_address );
1270 PLEvent *event = new PLEvent( PLEvent::PLItemAppended, p_add->i_item, p_add->i_node );
1271 QApplication::postEvent( mim, event );
1272 event = new PLEvent( PLEvent::PLEmpty, p_add->i_item, 0 );
1273 QApplication::postEvent( mim, event );
1277 static int PLItemRemoved
1278 ( vlc_object_t * obj, const char *var, vlc_value_t old, vlc_value_t cur, void *data )
1280 VLC_UNUSED( var ); VLC_UNUSED( old );
1282 playlist_t *pl = (playlist_t *) obj;
1283 MainInputManager *mim = static_cast<MainInputManager*>(data);
1285 PLEvent *event = new PLEvent( PLEvent::PLItemRemoved, cur.i_int, 0 );
1286 QApplication::postEvent( mim, event );
1287 // can't use playlist_IsEmpty( ) as it isn't true yet
1288 if ( pl->items.i_size == 1 ) // lock is held
1290 event = new PLEvent( PLEvent::PLEmpty, -1, 0 );
1291 QApplication::postEvent( mim, event );