qt: convert vlc_tick_t to seconds explicitly using SEC_FROM_VLC_TICK()
[vlc.git] / modules / gui / qt / input_manager.cpp
blob97892ee877c57fd010c2b18b0515326ccd667a59
1 /*****************************************************************************
2 * input_manager.cpp : Manage an input and interact with its GUI elements
3 ****************************************************************************
4 * Copyright (C) 2006-2008 the VideoLAN team
5 * $Id$
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 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
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>
39 #include <QFile>
40 #include <QDir>
41 #include <QSignalMapper>
42 #include <QMessageBox>
44 #include <assert.h>
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 )
68 p_mim = mim;
69 i_old_playing_status = END_S;
70 oldName = "";
71 artUrl = "";
72 p_input = NULL;
73 p_input_vbi = NULL;
74 f_rate = 0.;
75 p_item = NULL;
76 b_video = false;
77 timeA = 0;
78 timeB = 0;
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()
86 delInput();
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 )
99 delInput();
100 p_input = _p_input;
101 if( p_input != NULL )
103 msg_Dbg( p_intf, "IM: Setting an input" );
104 vlc_object_hold( p_input );
105 addCallbacks();
107 UpdateStatus();
108 UpdateName();
109 UpdateArt();
110 UpdateTeletext();
111 UpdateNavigation();
112 UpdateVout();
114 p_item = input_GetItem( p_input );
115 emit rateChanged( var_GetFloat( p_input, "rate" ) );
117 /* Get Saved Time */
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 );
141 free( uri );
144 else
146 p_item = NULL;
147 lastURI.clear();
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 );
163 if( uri != NULL ) {
164 float f_pos = var_GetFloat( p_input , "position" );
165 int64_t i_time = -1;
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 );
172 free(uri);
175 delCallbacks();
176 i_old_playing_status = END_S;
177 p_item = NULL;
178 oldName = "";
179 artUrl = "";
180 b_video = false;
181 timeA = 0;
182 timeB = 0;
183 f_rate = 0. ;
185 if( p_input_vbi )
187 vlc_object_release( p_input_vbi );
188 p_input_vbi = NULL;
191 vlc_object_release( p_input );
192 p_input = NULL;
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() );
227 if( !hasInput() )
228 return;
230 /* Actions */
231 switch( i_type )
233 case IMEvent::PositionUpdate:
234 UpdatePosition();
235 break;
236 case IMEvent::StatisticsUpdate:
237 UpdateStats();
238 break;
239 case IMEvent::ItemChanged:
240 /* Ignore ItemChanged_Type event that does not apply to our input */
241 if( p_item == ple->item() )
243 UpdateStatus();
244 UpdateName();
245 UpdateArt();
246 UpdateMeta();
247 /* Update duration of file */
249 break;
250 case IMEvent::ItemStateChanged:
251 UpdateStatus();
252 break;
253 case IMEvent::MetaChanged:
254 UpdateMeta();
255 UpdateName(); /* Needed for NowPlaying */
256 UpdateArt(); /* Art is part of meta in the core */
257 break;
258 case IMEvent::InfoChanged:
259 UpdateInfo();
260 break;
261 case IMEvent::ItemTitleChanged:
262 UpdateNavigation();
263 UpdateName(); /* Display the name of the Chapter, if exists */
264 break;
265 case IMEvent::ItemRateChanged:
266 UpdateRate();
267 break;
268 case IMEvent::ItemEsChanged:
269 UpdateTeletext();
270 // We don't do anything ES related. Why ?
271 break;
272 case IMEvent::ItemTeletextChanged:
273 UpdateTeletext();
274 break;
275 case IMEvent::InterfaceVoutUpdate:
276 UpdateVout();
277 break;
278 case IMEvent::SynchroChanged:
279 emit synchroChanged();
280 break;
281 case IMEvent::CachingEvent:
282 UpdateCaching();
283 break;
284 case IMEvent::BookmarksChanged:
285 emit bookmarksChanged();
286 break;
287 case IMEvent::InterfaceAoutUpdate:
288 UpdateAout();
289 break;
290 case IMEvent::RecordingEvent:
291 UpdateRecord();
292 break;
293 case IMEvent::ProgramChanged:
294 UpdateProgramEvent();
295 break;
296 case IMEvent::EPGEvent:
297 UpdateEPG();
298 break;
299 default:
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 );
326 return VLC_SUCCESS;
329 static int InputEvent( vlc_object_t *, const char *,
330 vlc_value_t, vlc_value_t newval, void *param )
332 InputManager *im = (InputManager*)param;
333 IMEvent *event;
335 switch( newval.i_int )
337 case INPUT_EVENT_STATE:
338 event = new IMEvent( IMEvent::ItemStateChanged );
339 break;
340 case INPUT_EVENT_RATE:
341 event = new IMEvent( IMEvent::ItemRateChanged );
342 break;
343 case INPUT_EVENT_POSITION:
344 //case INPUT_EVENT_LENGTH:
345 event = new IMEvent( IMEvent::PositionUpdate );
346 break;
348 case INPUT_EVENT_TITLE:
349 case INPUT_EVENT_CHAPTER:
350 event = new IMEvent( IMEvent::ItemTitleChanged );
351 break;
353 case INPUT_EVENT_ES:
354 event = new IMEvent( IMEvent::ItemEsChanged );
355 break;
356 case INPUT_EVENT_TELETEXT:
357 event = new IMEvent( IMEvent::ItemTeletextChanged );
358 break;
360 case INPUT_EVENT_STATISTICS:
361 event = new IMEvent( IMEvent::StatisticsUpdate );
362 break;
364 case INPUT_EVENT_VOUT:
365 event = new IMEvent( IMEvent::InterfaceVoutUpdate );
366 break;
367 case INPUT_EVENT_AOUT:
368 event = new IMEvent( IMEvent::InterfaceAoutUpdate );
369 break;
371 case INPUT_EVENT_ITEM_META: /* Codec MetaData + Art */
372 event = new IMEvent( IMEvent::MetaChanged );
373 break;
374 case INPUT_EVENT_ITEM_INFO: /* Codec Info */
375 event = new IMEvent( IMEvent::InfoChanged );
376 break;
378 case INPUT_EVENT_AUDIO_DELAY:
379 case INPUT_EVENT_SUBTITLE_DELAY:
380 event = new IMEvent( IMEvent::SynchroChanged );
381 break;
383 case INPUT_EVENT_CACHE:
384 event = new IMEvent( IMEvent::CachingEvent );
385 break;
387 case INPUT_EVENT_BOOKMARK:
388 event = new IMEvent( IMEvent::BookmarksChanged );
389 break;
391 case INPUT_EVENT_RECORD:
392 event = new IMEvent( IMEvent::RecordingEvent );
393 break;
395 case INPUT_EVENT_PROGRAM:
396 /* This is for PID changes */
397 event = new IMEvent( IMEvent::ProgramChanged );
398 break;
400 case INPUT_EVENT_ITEM_EPG:
401 /* EPG data changed */
402 event = new IMEvent( IMEvent::EPGEvent );
403 break;
405 case INPUT_EVENT_SIGNAL:
406 /* This is for capture-card signals */
407 /* event = new IMEvent( SignalChanged_Type );
408 break; */
409 default:
410 event = NULL;
411 break;
414 if( event )
415 QApplication::postEvent( im, event );
416 return VLC_SUCCESS;
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 );
426 return VLC_SUCCESS;
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 );
445 if( ntitles > 0 )
447 bool b_menu = false;
448 if( ntitles > 1 )
450 input_title_t **pp_title = NULL;
451 int i_title = 0;
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 )
457 b_menu = true;
458 vlc_input_title_Delete(pp_title[i]);
460 free( pp_title );
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 );
470 else
471 emit chapterChanged( false );
473 if( hasInput() )
474 emit inputCanSeek( var_GetBool( p_input, "can-seek" ) );
475 else
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()
492 /* Update Rate */
493 float f_new_rate = var_GetFloat( p_input, "rate" );
494 if( f_new_rate != f_rate )
496 f_rate = f_new_rate;
497 /* Update rate */
498 emit rateChanged( f_rate );
502 void InputManager::UpdateName()
504 /* Update text, name and nowplaying */
505 QString name;
507 /* Try to get the nowplaying */
508 char *format = var_InheritString( p_intf, "input-title-format" );
509 char *formatted = NULL;
510 if (format != NULL)
512 formatted = vlc_strfinput( p_input, format );
513 free( format );
514 if( formatted != NULL )
516 name = qfu(formatted);
517 free( 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;
526 if( file != NULL )
528 vlc_uri_decode( ++file );
529 name = qfu(file);
531 else
532 name = qfu(uri);
533 free( uri );
536 name = name.trimmed();
538 if( oldName != name )
540 emit nameChanged( name );
541 oldName = name;
545 int InputManager::playingStatus() const
547 return i_old_playing_status;
550 bool InputManager::hasAudio()
552 if( hasInput() )
554 size_t val;
555 var_Change( p_input, "audio-es", VLC_VAR_CHOICESCOUNT, &val );
556 return val > 0;
558 return false;
561 bool InputManager::hasVisualisation()
563 if( !p_input )
564 return false;
566 audio_output_t *aout = input_GetAout( p_input );
567 if( !aout )
568 return false;
570 char *visual = var_InheritString( aout, "visual" );
571 vlc_object_release( aout );
573 if( !visual )
574 return false;
576 free( visual );
577 return true;
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 */
592 int i_page = 100;
593 bool b_transparent = false;
595 if( p_input_vbi )
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 ) )
602 p_input_vbi = NULL;
604 if( p_input_vbi )
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()
622 emit epgChanged();
625 void InputManager::UpdateVout()
627 size_t i_vout;
628 vout_thread_t **pp_vout;
630 if( !p_input )
631 return;
633 /* Get current vout lists from input */
634 if( input_Control( p_input, INPUT_GET_VOUTS, &pp_vout, &i_vout ) )
636 i_vout = 0;
637 pp_vout = NULL;
640 /* */
641 emit voutListChanged( pp_vout, i_vout );
643 /* */
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] );
652 free( pp_vout );
655 void InputManager::UpdateAout()
657 /* TODO */
660 void InputManager::UpdateCaching()
662 float f_newCache = var_GetFloat ( p_input, "cache" );
663 if( f_newCache != f_cache )
665 f_cache = f_newCache;
666 /* Update cache */
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;
680 if ( p_item )
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 ) )
687 return;
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 )
695 UpdateArt();
696 else
697 emit artChanged( p_item );
701 const QString InputManager::decodeArtURL( input_item_t *p_item )
703 assert( p_item );
705 char *psz_art = input_item_GetArtURL( p_item );
706 if( psz_art )
708 char *psz = vlc_uri2path( psz_art );
709 free( psz_art );
710 psz_art = psz;
713 #if 0
714 /* Taglib seems to define a attachment://, It won't work yet */
715 url = url.replace( "attachment://", "" );
716 #endif
718 QString path = qfu( psz_art ? psz_art : "" );
719 free( psz_art );
720 return path;
723 void InputManager::UpdateArt()
725 QString url = decodeArtURL( input_GetItem( p_input ) );
727 /* the art hasn't changed, no need to update */
728 if(artUrl == url)
729 return;
731 /* Update Art meta */
732 artUrl = url;
733 emit artChanged( artUrl );
736 void InputManager::setArt( input_item_t *p_item, QString fileUrl )
738 if( hasInput() )
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() );
750 UpdateArt();
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()
772 assert( p_input );
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 )
790 if( hasInput() )
791 var_SetFloat( p_input, "position", new_pos );
792 emit seekRequested( new_pos );
795 void InputManager::sectionPrev()
797 if( hasInput() )
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()
807 if( hasInput() )
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()
817 if( hasInput() )
819 var_TriggerCallback( p_input, "menu-title" );
824 * Teletext Functions
827 void InputManager::changeProgram( int program )
829 if( hasInput() )
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 )
862 vlc_value_t *list;
863 char **text;
864 size_t count;
866 if( hasInput() && !var_Change( p_input, "teletext-es", VLC_VAR_GETCHOICES,
867 &count, &list, &text ) )
869 if( count > 0 )
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" ) )
875 id = list[i].i_int;
876 free(text[i]);
878 var_SetInteger( p_input, "spu-es", b_enable ? id : -1 );
880 free(text);
881 free(list);
885 void InputManager::reverse()
887 if( hasInput() )
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()
947 if( !timeA )
949 timeA = var_GetInteger( p_mim->getInput(), "time" );
951 else if( !timeB )
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 ) );
958 else
960 timeA = 0;
961 timeB = 0;
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 );
989 /* Audio Menu */
990 menusAudioMapper = new QSignalMapper();
991 CONNECT( menusAudioMapper, mapped(QString), this, menusUpdateAudio( QString ) );
993 /* Core Callbacks */
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()
1014 if( p_input )
1016 vlc_object_release( p_input );
1017 p_input = NULL;
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;
1039 size_t i_vout;
1041 if( p_input == NULL
1042 || input_Control( p_input, INPUT_GET_VOUTS, &pp_vout, &i_vout ) != VLC_SUCCESS
1043 || i_vout == 0 )
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] );
1053 free( pp_vout );
1055 return vector;
1058 audio_output_t * MainInputManager::getAout()
1060 return playlist_GetAout( THEPL );
1063 void MainInputManager::customEvent( QEvent *event )
1065 int type = event->type();
1067 PLEvent *plEv;
1069 // msg_Dbg( p_intf, "New MainIM Event of type: %i", type );
1070 switch( type )
1072 case PLEvent::PLItemAppended:
1073 plEv = static_cast<PLEvent*>( event );
1074 emit playlistItemAppended( plEv->getItemId(), plEv->getParentId() );
1075 return;
1076 case PLEvent::PLItemRemoved:
1077 plEv = static_cast<PLEvent*>( event );
1078 emit playlistItemRemoved( plEv->getItemId() );
1079 return;
1080 case PLEvent::PLEmpty:
1081 plEv = static_cast<PLEvent*>( event );
1082 emit playlistNotEmpty( plEv->getItemId() >= 0 );
1083 return;
1084 case PLEvent::LeafToParent:
1085 plEv = static_cast<PLEvent*>( event );
1086 emit leafBecameParent( plEv->getItemId() );
1087 return;
1088 default:
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 );
1122 else
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" );
1167 if( repeat )
1169 loop = false;
1170 repeat = false;
1172 else if( loop )
1174 loop = false;
1175 repeat = true;
1177 else
1179 loop = true;
1180 //repeat = false;
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 );
1205 return b_empty;
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 );
1218 return VLC_SUCCESS;
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 );
1229 return VLC_SUCCESS;
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();
1246 if( aout != NULL )
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,
1255 void *data )
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 );
1266 return VLC_SUCCESS;
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 );
1284 return VLC_SUCCESS;
1287 void MainInputManager::changeFullscreen( bool new_val )
1289 if ( var_GetBool( THEPL, "fullscreen" ) != new_val)
1290 var_SetBool( THEPL, "fullscreen", new_val );