]> git.sesse.net Git - vlc/blob - modules/gui/qt4/input_manager.cpp
Qt: use QString iso std::string
[vlc] / modules / gui / qt4 / input_manager.cpp
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$
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@videolan.org>
8  *          Ilkka Ollakka  <ileoo@videolan.org>
9  *          Jean-Baptiste <jb@videolan.org>
10  *
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.
15  *
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.
20  *
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  *****************************************************************************/
25
26 #define __STDC_FORMAT_MACROS 1
27 #define __STDC_CONSTANT_MACROS 1
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include "input_manager.hpp"
34 #include <vlc_keys.h>
35 #include <vlc_url.h>
36 #include <vlc_strings.h>
37 #include <vlc_aout.h>
38
39 #include <QApplication>
40
41 #include <assert.h>
42
43 static int ItemChanged( vlc_object_t *, const char *,
44                         vlc_value_t, vlc_value_t, void * );
45 static int LeafToParent( vlc_object_t *, const char *,
46                         vlc_value_t, vlc_value_t, void * );
47 static int PLItemChanged( vlc_object_t *, const char *,
48                         vlc_value_t, vlc_value_t, void * );
49 static int PLItemAppended( vlc_object_t *, const char *,
50                         vlc_value_t, vlc_value_t, void * );
51 static int PLItemRemoved( vlc_object_t *, const char *,
52                         vlc_value_t, vlc_value_t, void * );
53 static int VolumeChanged( vlc_object_t *, const char *,
54                         vlc_value_t, vlc_value_t, void * );
55 static int SoundMuteChanged( vlc_object_t *, const char *,
56                         vlc_value_t, vlc_value_t, void * );
57
58 static int RandomChanged( vlc_object_t *, const char *,
59                         vlc_value_t, vlc_value_t, void * );
60 static int LoopChanged( vlc_object_t *, const char *,
61                         vlc_value_t, vlc_value_t, void * );
62 static int RepeatChanged( vlc_object_t *, const char *,
63                         vlc_value_t, vlc_value_t, void * );
64
65
66 static int InputEvent( vlc_object_t *, const char *,
67                        vlc_value_t, vlc_value_t, void * );
68 static int VbiEvent( vlc_object_t *, const char *,
69                      vlc_value_t, vlc_value_t, void * );
70
71
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  **********************************************************************/
78
79 InputManager::InputManager( QObject *parent, intf_thread_t *_p_intf) :
80                            QObject( parent ), p_intf( _p_intf )
81 {
82     i_old_playing_status = END_S;
83     oldName      = "";
84     artUrl       = "";
85     p_input      = NULL;
86     p_input_vbi  = NULL;
87     f_rate       = 0.;
88     p_item       = NULL;
89     b_video      = false;
90     timeA        = 0;
91     timeB        = 0;
92     f_cache      = -1.; /* impossible initial value, different from all */
93 }
94
95 InputManager::~InputManager()
96 {
97     delInput();
98 }
99
100 /* Define the Input used.
101    Add the callbacks on input
102    p_input is held once here */
103 void InputManager::setInput( input_thread_t *_p_input )
104 {
105     delInput();
106     p_input = _p_input;
107     if( p_input && !( p_input->b_dead || !vlc_object_alive (p_input) ) )
108     {
109         msg_Dbg( p_intf, "IM: Setting an input" );
110         vlc_object_hold( p_input );
111         addCallbacks();
112         UpdateStatus();
113         UpdateName();
114         UpdateArt();
115         UpdateTeletext();
116         UpdateNavigation();
117         UpdateVout();
118
119         p_item = input_GetItem( p_input );
120         emit rateChanged( var_GetFloat( p_input, "rate" ) );
121     }
122     else
123     {
124         p_input = NULL;
125         p_item = NULL;
126         assert( !p_input_vbi );
127         emit rateChanged( var_InheritFloat( p_intf, "rate" ) );
128     }
129 }
130
131 /* delete Input if it ever existed.
132    Delete the callbacls on input
133    p_input is released once here */
134 void InputManager::delInput()
135 {
136     if( !p_input ) return;
137     msg_Dbg( p_intf, "IM: Deleting the input" );
138
139     delCallbacks();
140     i_old_playing_status = END_S;
141     p_item               = NULL;
142     oldName              = "";
143     artUrl               = "";
144     b_video              = false;
145     timeA                = 0;
146     timeB                = 0;
147     f_rate               = 0. ;
148
149     if( p_input_vbi )
150     {
151         vlc_object_release( p_input_vbi );
152         p_input_vbi = NULL;
153     }
154
155     vlc_object_release( p_input );
156     p_input = NULL;
157
158     emit positionUpdated( -1.0, 0 ,0 );
159     emit rateChanged( var_InheritFloat( p_intf, "rate" ) );
160     emit nameChanged( "" );
161     emit chapterChanged( 0 );
162     emit titleChanged( 0 );
163     emit playingStatusChanged( END_S );
164
165     emit teletextPossible( false );
166     emit AtoBchanged( false, false );
167     emit voutChanged( false );
168     emit voutListChanged( NULL, 0 );
169
170     /* Reset all InfoPanels but stats */
171     emit artChanged( NULL );
172     emit infoChanged( NULL );
173     emit currentMetaChanged( (input_item_t *)NULL );
174
175     emit encryptionChanged( false );
176     emit recordingStateChanged( false );
177
178     emit cachingChanged( 1 );
179 }
180
181 /* Convert the event from the callbacks in actions */
182 void InputManager::customEvent( QEvent *event )
183 {
184     int i_type = event->type();
185     IMEvent *ple = static_cast<IMEvent *>(event);
186
187     if( i_type == ItemChanged_Type )
188         UpdateMeta( ple->p_item );
189
190     if( !hasInput() )
191         return;
192
193     /* Actions */
194     switch( i_type )
195     {
196     case PositionUpdate_Type:
197         UpdatePosition();
198         break;
199     case StatisticsUpdate_Type:
200         UpdateStats();
201         break;
202     case ItemChanged_Type:
203         /* Ignore ItemChanged_Type event that does not apply to our input */
204         if( p_item == ple->p_item )
205         {
206             UpdateStatus();
207             // UpdateName();
208             UpdateArt();
209             /* Update duration of file */
210         }
211         break;
212     case ItemStateChanged_Type:
213         // TODO: Fusion with above state
214         UpdateStatus();
215         // UpdateName();
216         // UpdateNavigation(); This shouldn't be useful now
217         // UpdateTeletext(); Same
218         break;
219     case NameChanged_Type:
220         UpdateName();
221         break;
222     case MetaChanged_Type:
223         UpdateMeta();
224         UpdateName(); /* Needed for NowPlaying */
225         UpdateArt(); /* Art is part of meta in the core */
226         break;
227     case InfoChanged_Type:
228         UpdateInfo();
229         break;
230     case ItemTitleChanged_Type:
231         UpdateNavigation();
232         UpdateName(); /* Display the name of the Chapter, if exists */
233         break;
234     case ItemRateChanged_Type:
235         UpdateRate();
236         break;
237     case ItemEsChanged_Type:
238         UpdateTeletext();
239         // We don't do anything ES related. Why ?
240         break;
241     case ItemTeletextChanged_Type:
242         UpdateTeletext();
243         break;
244     case InterfaceVoutUpdate_Type:
245         UpdateVout();
246         break;
247     case SynchroChanged_Type:
248         emit synchroChanged();
249         break;
250     case CachingEvent_Type:
251         UpdateCaching();
252         break;
253     case BookmarksChanged_Type:
254         emit bookmarksChanged();
255         break;
256     case InterfaceAoutUpdate_Type:
257         UpdateAout();
258         break;
259     case RecordingEvent_Type:
260         UpdateRecord();
261         break;
262     case ProgramChanged_Type:
263         UpdateProgramEvent();
264         break;
265     case EPGEvent_Type:
266         UpdateEPG();
267         break;
268     default:
269         msg_Warn( p_intf, "This shouldn't happen: %i", i_type );
270         assert(0);
271     }
272 }
273
274 /* Add the callbacks on Input. Self explanatory */
275 inline void InputManager::addCallbacks()
276 {
277     var_AddCallback( p_input, "intf-event", InputEvent, this );
278 }
279
280 /* Delete the callbacks on Input. Self explanatory */
281 inline void InputManager::delCallbacks()
282 {
283     var_DelCallback( p_input, "intf-event", InputEvent, this );
284 }
285
286 /* Static callbacks for IM */
287 static int ItemChanged( vlc_object_t *p_this, const char *psz_var,
288                         vlc_value_t oldval, vlc_value_t newval, void *param )
289 {
290     VLC_UNUSED( p_this ); VLC_UNUSED( psz_var ); VLC_UNUSED( oldval );
291
292     InputManager *im = (InputManager*)param;
293     input_item_t *p_item = static_cast<input_item_t *>(newval.p_address);
294
295     IMEvent *event = new IMEvent( ItemChanged_Type, p_item );
296     QApplication::postEvent( im, event );
297     return VLC_SUCCESS;
298 }
299
300 static int InputEvent( vlc_object_t *p_this, const char *,
301                        vlc_value_t, vlc_value_t newval, void *param )
302 {
303     VLC_UNUSED( p_this );
304
305     InputManager *im = (InputManager*)param;
306     IMEvent *event;
307
308     switch( newval.i_int )
309     {
310     case INPUT_EVENT_STATE:
311         event = new IMEvent( ItemStateChanged_Type );
312         break;
313     case INPUT_EVENT_RATE:
314         event = new IMEvent( ItemRateChanged_Type );
315         break;
316     case INPUT_EVENT_POSITION:
317     //case INPUT_EVENT_LENGTH:
318         event = new IMEvent( PositionUpdate_Type );
319         break;
320
321     case INPUT_EVENT_TITLE:
322     case INPUT_EVENT_CHAPTER:
323         event = new IMEvent( ItemTitleChanged_Type );
324         break;
325
326     case INPUT_EVENT_ES:
327         event = new IMEvent( ItemEsChanged_Type );
328         break;
329     case INPUT_EVENT_TELETEXT:
330         event = new IMEvent( ItemTeletextChanged_Type );
331         break;
332
333     case INPUT_EVENT_STATISTICS:
334         event = new IMEvent( StatisticsUpdate_Type );
335         break;
336
337     case INPUT_EVENT_VOUT:
338         event = new IMEvent( InterfaceVoutUpdate_Type );
339         break;
340     case INPUT_EVENT_AOUT:
341         event = new IMEvent( InterfaceAoutUpdate_Type );
342         break;
343
344     case INPUT_EVENT_ITEM_META: /* Codec MetaData + Art */
345         event = new IMEvent( MetaChanged_Type );
346         break;
347     case INPUT_EVENT_ITEM_INFO: /* Codec Info */
348         event = new IMEvent( InfoChanged_Type );
349         break;
350     case INPUT_EVENT_ITEM_NAME:
351         event = new IMEvent( NameChanged_Type );
352         break;
353
354     case INPUT_EVENT_AUDIO_DELAY:
355     case INPUT_EVENT_SUBTITLE_DELAY:
356         event = new IMEvent( SynchroChanged_Type );
357         break;
358
359     case INPUT_EVENT_CACHE:
360         event = new IMEvent( CachingEvent_Type );
361         break;
362
363     case INPUT_EVENT_BOOKMARK:
364         event = new IMEvent( BookmarksChanged_Type );
365         break;
366
367     case INPUT_EVENT_RECORD:
368         event = new IMEvent( RecordingEvent_Type );
369         break;
370
371     case INPUT_EVENT_PROGRAM:
372         /* This is for PID changes */
373         event = new IMEvent( ProgramChanged_Type );
374         break;
375
376     case INPUT_EVENT_ITEM_EPG:
377         /* EPG data changed */
378         event = new IMEvent( EPGEvent_Type );
379         break;
380
381     case INPUT_EVENT_SIGNAL:
382         /* This is for capture-card signals */
383         /* event = new IMEvent( SignalChanged_Type );
384         break; */
385     default:
386         event = NULL;
387         break;
388     }
389
390     if( event )
391         QApplication::postEvent( im, event );
392     return VLC_SUCCESS;
393 }
394
395 static int VbiEvent( vlc_object_t *, const char *,
396                      vlc_value_t, vlc_value_t, void *param )
397 {
398     InputManager *im = (InputManager*)param;
399     IMEvent *event = new IMEvent( ItemTeletextChanged_Type );
400
401     QApplication::postEvent( im, event );
402     return VLC_SUCCESS;
403 }
404
405 void InputManager::UpdatePosition()
406 {
407     /* Update position */
408     int i_length;
409     int64_t i_time;
410     float f_pos;
411     i_length = var_GetTime(  p_input , "length" ) / CLOCK_FREQ;
412     i_time = var_GetTime(  p_input , "time");
413     f_pos = var_GetFloat(  p_input , "position" );
414     emit positionUpdated( f_pos, i_time, i_length );
415 }
416
417 void InputManager::UpdateNavigation()
418 {
419     /* Update navigation status */
420     vlc_value_t val; val.i_int = 0;
421     vlc_value_t val2; val2.i_int = 0;
422
423     if( hasInput() )
424         var_Change( p_input, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
425
426     if( val.i_int > 0 )
427     {
428         emit titleChanged( true );
429         msg_Dbg( p_intf, "Title %"PRId64, val.i_int );
430         /* p_input != NULL since val.i_int != 0 */
431         var_Change( p_input, "chapter", VLC_VAR_CHOICESCOUNT, &val2, NULL );
432         emit chapterChanged( (val2.i_int > 1) || ( val2.i_int > 0 && val.i_int > 1 ) );
433         msg_Dbg( p_intf, "Chapter: %"PRId64, val2.i_int );
434     }
435     else
436         emit titleChanged( false );
437 }
438
439 void InputManager::UpdateStatus()
440 {
441     /* Update playing status */
442     int state = var_GetInteger( p_input, "state" );
443     if( i_old_playing_status != state )
444     {
445         i_old_playing_status = state;
446         emit playingStatusChanged( state );
447     }
448 }
449
450 void InputManager::UpdateRate()
451 {
452     /* Update Rate */
453     float f_new_rate = var_GetFloat( p_input, "rate" );
454     if( f_new_rate != f_rate )
455     {
456         f_rate = f_new_rate;
457         /* Update rate */
458         emit rateChanged( f_rate );
459     }
460 }
461
462 void InputManager::UpdateName()
463 {
464     /* Update text, name and nowplaying */
465     QString name;
466
467     /* Try to get the nowplaying */
468     char *format = var_InheritString( p_intf, "input-title-format" );
469     char *formated = str_format_meta( p_input, format );
470     free( format );
471     name = qfu(formated);
472     free( formated );
473
474     /* If we have Nothing */
475     if( name.isEmpty() )
476     {
477         char *uri = input_item_GetURI( input_GetItem( p_input ) );
478         char *file = uri ? strrchr( uri, '/' ) : NULL;
479         if( file != NULL )
480         {
481             decode_URI( ++file );
482             name = qfu(file);
483         }
484         else
485             name = qfu(uri);
486         free( uri );
487     }
488
489     name = name.trimmed();
490
491     if( oldName != name )
492     {
493         emit nameChanged( name );
494         oldName = name;
495     }
496 }
497
498 int InputManager::playingStatus()
499 {
500     return i_old_playing_status;
501 }
502
503 bool InputManager::hasAudio()
504 {
505     if( hasInput() )
506     {
507         vlc_value_t val;
508         var_Change( p_input, "audio-es", VLC_VAR_CHOICESCOUNT, &val, NULL );
509         return val.i_int > 0;
510     }
511     return false;
512 }
513
514 bool InputManager::hasVisualisation()
515 {
516     if( !p_input )
517         return false;
518
519     audio_output_t *aout = input_GetAout( p_input );
520     if( !aout )
521         return false;
522
523     char *visual = var_InheritString( aout, "visual" );
524     vlc_object_release( aout );
525
526     if( !visual )
527         return false;
528
529     free( visual );
530     return true;
531 }
532
533 void InputManager::UpdateTeletext()
534 {
535     if( hasInput() )
536     {
537         const bool b_enabled = var_CountChoices( p_input, "teletext-es" ) > 0;
538         const int i_teletext_es = var_GetInteger( p_input, "teletext-es" );
539
540         /* Teletext is possible. Show the buttons */
541         emit teletextPossible( b_enabled );
542
543         /* If Teletext is selected */
544         if( b_enabled && i_teletext_es >= 0 )
545         {
546             /* Then, find the current page */
547             int i_page = 100;
548             bool b_transparent = false;
549
550             if( p_input_vbi )
551             {
552                 var_DelCallback( p_input_vbi, "vbi-page", VbiEvent, this );
553                 vlc_object_release( p_input_vbi );
554             }
555
556             if( input_GetEsObjects( p_input, i_teletext_es, &p_input_vbi, NULL, NULL ) )
557                 p_input_vbi = NULL;
558
559             if( p_input_vbi )
560             {
561                 /* This callback is not remove explicitly, but interfaces
562                  * are guaranted to outlive input */
563                 var_AddCallback( p_input_vbi, "vbi-page", VbiEvent, this );
564
565                 i_page = var_GetInteger( p_input_vbi, "vbi-page" );
566                 b_transparent = !var_GetBool( p_input_vbi, "vbi-opaque" );
567             }
568             emit newTelexPageSet( i_page );
569             emit teletextTransparencyActivated( b_transparent );
570
571         }
572         emit teletextActivated( b_enabled && i_teletext_es >= 0 );
573     }
574     else
575     {
576         emit teletextActivated( false );
577         emit teletextPossible( false );
578     }
579 }
580
581 void InputManager::UpdateEPG()
582 {
583     if( hasInput() )
584     {
585        emit epgChanged();
586     }
587 }
588
589 void InputManager::UpdateVout()
590 {
591     if( hasInput() )
592     {
593         /* Get current vout lists from input */
594         size_t i_vout;
595         vout_thread_t **pp_vout;
596         if( input_Control( p_input, INPUT_GET_VOUTS, &pp_vout, &i_vout ) )
597         {
598             i_vout = 0;
599             pp_vout = NULL;
600         }
601
602         /* */
603         emit voutListChanged( pp_vout, i_vout );
604
605         /* */
606         bool b_old_video = b_video;
607         b_video = i_vout > 0;
608         if( !!b_old_video != !!b_video )
609             emit voutChanged( b_video );
610
611         /* Release the vout list */
612         for( size_t i = 0; i < i_vout; i++ )
613             vlc_object_release( (vlc_object_t*)pp_vout[i] );
614         free( pp_vout );
615     }
616 }
617 void InputManager::UpdateAout()
618 {
619     if( hasInput() )
620     {
621         /* TODO */
622     }
623 }
624 void InputManager::UpdateCaching()
625 {
626     if(!hasInput()) return;
627
628     float f_newCache = var_GetFloat ( p_input, "cache" );
629     if( f_newCache != f_cache )
630     {
631         f_cache = f_newCache;
632         /* Update cache */
633         emit cachingChanged( f_cache );
634     }
635 }
636
637 void InputManager::requestArtUpdate()
638 {
639     if( hasInput() )
640     {
641         playlist_AskForArtEnqueue( pl_Get(p_intf), input_GetItem( p_input ) );
642     }
643     else
644     {
645         /* No input will signal the cover art to update,
646          * let's do it ourself */
647         UpdateArt();
648     }
649 }
650
651 const QString InputManager::decodeArtURL( input_item_t *p_item )
652 {
653     assert( p_item );
654
655     char *psz_art = input_item_GetArtURL( p_item );
656     if( psz_art )
657     {
658         char *psz = make_path( psz_art );
659         free( psz_art );
660         psz_art = psz;
661     }
662
663 #if 0
664     /* Taglib seems to define a attachment://, It won't work yet */
665     url = url.replace( "attachment://", "" );
666 #endif
667
668     QString path = qfu( psz_art ? psz_art : "" );
669     free( psz_art );
670     return path;
671 }
672
673 void InputManager::UpdateArt()
674 {
675     QString url;
676
677     if( hasInput() )
678         url = decodeArtURL( input_GetItem( p_input ) );
679
680     /* the art hasn't changed, no need to update */
681     if(artUrl == url)
682         return;
683
684     /* Update Art meta */
685     artUrl = url;
686     emit artChanged( artUrl );
687 }
688
689 inline void InputManager::UpdateStats()
690 {
691     emit statisticsUpdated( input_GetItem( p_input ) );
692 }
693
694 inline void InputManager::UpdateMeta( input_item_t *p_item )
695 {
696     emit metaChanged( p_item );
697 }
698
699 inline void InputManager::UpdateMeta()
700 {
701     emit currentMetaChanged( input_GetItem( p_input ) );
702 }
703
704 inline void InputManager::UpdateInfo()
705 {
706     emit infoChanged( input_GetItem( p_input ) );
707 }
708
709 void InputManager::UpdateRecord()
710 {
711     if( hasInput() )
712     {
713         emit recordingStateChanged( var_GetBool( p_input, "record" ) );
714     }
715 }
716
717 void InputManager::UpdateProgramEvent()
718 {
719     if( hasInput() )
720     {
721         bool b_scrambled = var_GetBool( p_input, "program-scrambled" );
722         emit encryptionChanged( b_scrambled );
723     }
724 }
725
726 /* User update of the slider */
727 void InputManager::sliderUpdate( float new_pos )
728 {
729     if( hasInput() )
730         var_SetFloat( p_input, "position", new_pos );
731     emit seekRequested( new_pos );
732 }
733
734 /* User togglePlayPause */
735 void InputManager::togglePlayPause()
736 {
737     if( hasInput() )
738     {
739         int state = var_GetInteger( p_input, "state" );
740         state = ( state != PLAYING_S ) ? PLAYING_S : PAUSE_S;
741         var_SetInteger( p_input, "state", state );
742     }
743 }
744
745 void InputManager::sectionPrev()
746 {
747     if( hasInput() )
748     {
749         int i_type = var_Type( p_input, "next-chapter" );
750         var_TriggerCallback( p_input, (i_type & VLC_VAR_TYPE) != 0 ?
751                              "prev-chapter":"prev-title" );
752     }
753 }
754
755 void InputManager::sectionNext()
756 {
757     if( hasInput() )
758     {
759         int i_type = var_Type( p_input, "next-chapter" );
760         var_TriggerCallback( p_input, (i_type & VLC_VAR_TYPE) != 0 ?
761                              "next-chapter":"next-title" );
762     }
763 }
764
765 void InputManager::sectionMenu()
766 {
767     if( hasInput() )
768     {
769         vlc_value_t val, text;
770
771         if( var_Change( p_input, "title  0", VLC_VAR_GETLIST, &val, &text ) < 0 )
772             return;
773
774         /* XXX is it "Root" or "Title" we want here ?" (set 0 by default) */
775         int root = 0;
776         for( int i = 0; i < val.p_list->i_count; i++ )
777         {
778             if( !strcmp( text.p_list->p_values[i].psz_string, "Title" ) )
779                 root = i;
780         }
781         var_FreeList( &val, &text );
782
783         var_SetInteger( p_input, "title  0", root );
784     }
785 }
786
787 /*
788  *  Teletext Functions
789  */
790
791 /* Set a new Teletext Page */
792 void InputManager::telexSetPage( int page )
793 {
794     if( hasInput() && p_input_vbi )
795     {
796         const int i_teletext_es = var_GetInteger( p_input, "teletext-es" );
797
798         if( i_teletext_es >= 0 )
799         {
800             var_SetInteger( p_input_vbi, "vbi-page", page );
801             emit newTelexPageSet( page );
802         }
803     }
804 }
805
806 /* Set the transparency on teletext */
807 void InputManager::telexSetTransparency( bool b_transparentTelextext )
808 {
809     if( hasInput() && p_input_vbi )
810     {
811         var_SetBool( p_input_vbi, "vbi-opaque", !b_transparentTelextext );
812         emit teletextTransparencyActivated( b_transparentTelextext );
813     }
814 }
815
816 void InputManager::activateTeletext( bool b_enable )
817 {
818     vlc_value_t list;
819     vlc_value_t text;
820     if( hasInput() && !var_Change( p_input, "teletext-es", VLC_VAR_GETLIST, &list, &text ) )
821     {
822         if( list.p_list->i_count > 0 )
823         {
824             /* Prefer the page 100 if it is present */
825             int i;
826             for( i = 0; i < text.p_list->i_count; i++ )
827             {
828                 /* The description is the page number as a string */
829                 const char *psz_page = text.p_list->p_values[i].psz_string;
830                 if( psz_page && !strcmp( psz_page, "100" ) )
831                     break;
832             }
833             if( i >= list.p_list->i_count )
834                 i = 0;
835             var_SetInteger( p_input, "spu-es", b_enable ? list.p_list->p_values[i].i_int : -1 );
836         }
837         var_FreeList( &list, &text );
838     }
839 }
840
841 void InputManager::reverse()
842 {
843     if( hasInput() )
844     {
845         float f_rate = var_GetFloat( p_input, "rate" );
846         var_SetFloat( p_input, "rate", -f_rate );
847     }
848 }
849
850 void InputManager::slower()
851 {
852     var_TriggerCallback( THEPL, "rate-slower" );
853 }
854
855 void InputManager::faster()
856 {
857     var_TriggerCallback( THEPL, "rate-faster" );
858 }
859
860 void InputManager::littlefaster()
861 {
862     var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_RATE_FASTER_FINE );
863 }
864
865 void InputManager::littleslower()
866 {
867     var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_RATE_SLOWER_FINE );
868 }
869
870 void InputManager::normalRate()
871 {
872     var_SetFloat( THEPL, "rate", 1. );
873 }
874
875 void InputManager::setRate( int new_rate )
876 {
877     var_SetFloat( THEPL, "rate",
878                  (float)INPUT_RATE_DEFAULT / (float)new_rate );
879 }
880
881 void InputManager::jumpFwd()
882 {
883     int i_interval = var_InheritInteger( p_input, "short-jump-size" );
884     if( i_interval > 0 )
885     {
886         mtime_t val = CLOCK_FREQ * i_interval;
887         var_SetTime( p_input, "time-offset", val );
888     }
889 }
890
891 void InputManager::jumpBwd()
892 {
893     int i_interval = var_InheritInteger( p_input, "short-jump-size" );
894     if( i_interval > 0 )
895     {
896         mtime_t val = -CLOCK_FREQ * i_interval;
897         var_SetTime( p_input, "time-offset", val );
898     }
899 }
900
901 void InputManager::setAtoB()
902 {
903     if( !timeA )
904     {
905         timeA = var_GetTime( THEMIM->getInput(), "time"  );
906     }
907     else if( !timeB )
908     {
909         timeB = var_GetTime( THEMIM->getInput(), "time"  );
910         var_SetTime( THEMIM->getInput(), "time" , timeA );
911         CONNECT( this, positionUpdated( float, int64_t, int ),
912                  this, AtoBLoop( float, int64_t, int ) );
913     }
914     else
915     {
916         timeA = 0;
917         timeB = 0;
918         disconnect( this, SIGNAL( positionUpdated( float, int64_t, int ) ),
919                     this, SLOT( AtoBLoop( float, int64_t, int ) ) );
920     }
921     emit AtoBchanged( (timeA != 0 ), (timeB != 0 ) );
922 }
923
924 /* Function called regularly when in an AtoB loop */
925 void InputManager::AtoBLoop( float, int64_t i_time, int )
926 {
927     if( timeB )
928     {
929         if( i_time >= timeB || i_time < timeA )
930             var_SetTime( THEMIM->getInput(), "time" , timeA );
931     }
932 }
933
934 /**********************************************************************
935  * MainInputManager implementation. Wrap an input manager and
936  * take care of updating the main playlist input.
937  * Used in the main playlist Dialog
938  **********************************************************************/
939
940 MainInputManager::MainInputManager( intf_thread_t *_p_intf )
941                  : QObject(NULL), p_intf( _p_intf )
942 {
943     p_input = NULL;
944     im = new InputManager( this, p_intf );
945
946     var_AddCallback( THEPL, "item-change", ItemChanged, im );
947     var_AddCallback( THEPL, "item-current", PLItemChanged, this );
948     var_AddCallback( THEPL, "activity", PLItemChanged, this );
949     var_AddCallback( THEPL, "leaf-to-parent", LeafToParent, this );
950     var_AddCallback( THEPL, "playlist-item-append", PLItemAppended, this );
951     var_AddCallback( THEPL, "playlist-item-deleted", PLItemRemoved, this );
952     var_AddCallback( THEPL, "random", RandomChanged, this );
953     var_AddCallback( THEPL, "repeat", RepeatChanged, this );
954     var_AddCallback( THEPL, "loop", LoopChanged, this );
955
956     var_AddCallback( THEPL, "volume", VolumeChanged, this );
957     var_AddCallback( THEPL, "mute", SoundMuteChanged, this );
958
959     /* Warn our embedded IM about input changes */
960     DCONNECT( this, inputChanged( input_thread_t * ),
961               im, setInput( input_thread_t * ) );
962
963 }
964
965 MainInputManager::~MainInputManager()
966 {
967     if( p_input )
968     {
969        emit inputChanged( NULL );
970        var_DelCallback( p_input, "state", PLItemChanged, this );
971        vlc_object_release( p_input );
972     }
973
974     var_DelCallback( THEPL, "volume", VolumeChanged, this );
975     var_DelCallback( THEPL, "mute", SoundMuteChanged, this );
976
977     var_DelCallback( THEPL, "activity", PLItemChanged, this );
978     var_DelCallback( THEPL, "item-change", ItemChanged, im );
979     var_DelCallback( THEPL, "leaf-to-parent", LeafToParent, this );
980
981     var_DelCallback( THEPL, "item-current", PLItemChanged, this );
982     var_DelCallback( THEPL, "playlist-item-append", PLItemAppended, this );
983     var_DelCallback( THEPL, "playlist-item-deleted", PLItemRemoved, this );
984     var_DelCallback( THEPL, "random", RandomChanged, this );
985     var_DelCallback( THEPL, "repeat", RepeatChanged, this );
986     var_DelCallback( THEPL, "loop", LoopChanged, this );
987
988 }
989
990 vout_thread_t* MainInputManager::getVout()
991 {
992     return p_input ? input_GetVout( p_input ) : NULL;
993 }
994
995 audio_output_t * MainInputManager::getAout()
996 {
997     return p_input ? input_GetAout( p_input ) : NULL;
998 }
999
1000 void MainInputManager::customEvent( QEvent *event )
1001 {
1002     int type = event->type();
1003
1004     PLEvent *plEv;
1005
1006     // msg_Dbg( p_intf, "New MainIM Event of type: %i", type );
1007     switch( type )
1008     {
1009     case VolumeChanged_Type:
1010         emit volumeChanged();
1011         return;
1012     case SoundMuteChanged_Type:
1013         emit soundMuteChanged();
1014         return;
1015     case PLItemAppended_Type:
1016         plEv = static_cast<PLEvent*>( event );
1017         emit playlistItemAppended( plEv->i_item, plEv->i_parent );
1018         return;
1019     case PLItemRemoved_Type:
1020         plEv = static_cast<PLEvent*>( event );
1021         emit playlistItemRemoved( plEv->i_item );
1022         return;
1023     case RandomChanged_Type:
1024         emit randomChanged( var_GetBool( THEPL, "random" ) );
1025         return;
1026     case LoopChanged_Type:
1027     case RepeatChanged_Type:
1028         notifyRepeatLoop();
1029         return;
1030     case LeafToParent_Type:
1031         plEv = static_cast<PLEvent*>( event );
1032         emit leafBecameParent( plEv->i_item );
1033         return;
1034     default:
1035         if( type != ItemChanged_Type ) return;
1036     }
1037
1038     /* Should be PLItemChanged Event */
1039     if( !p_intf->p_sys->b_isDialogProvider )
1040     {
1041         if( p_input && ( p_input->b_dead || !vlc_object_alive (p_input) ) )
1042         {
1043             emit inputChanged( p_input );
1044             var_DelCallback( p_input, "state", PLItemChanged, this );
1045             vlc_object_release( p_input );
1046             p_input = NULL;
1047             return;
1048         }
1049
1050         if( !p_input )
1051         {
1052             p_input = playlist_CurrentInput(THEPL);
1053             if( p_input )
1054             {
1055                 var_AddCallback( p_input, "state", PLItemChanged, this );
1056                 emit inputChanged( p_input );
1057             }
1058         }
1059     }
1060     else
1061     {
1062         /* remove previous stored p_input */
1063         if( p_input )
1064         {
1065             vlc_object_release( p_input );
1066             p_input = NULL;
1067         }
1068         /* we are working as a dialogs provider */
1069         p_input = playlist_CurrentInput( pl_Get(p_intf) );
1070         if( p_input )
1071         {
1072             emit inputChanged( p_input );
1073         }
1074     }
1075 }
1076
1077 /* Playlist Control functions */
1078 void MainInputManager::stop()
1079 {
1080    playlist_Stop( THEPL );
1081 }
1082
1083 void MainInputManager::next()
1084 {
1085    playlist_Next( THEPL );
1086 }
1087
1088 void MainInputManager::prev()
1089 {
1090    playlist_Prev( THEPL );
1091 }
1092
1093 void MainInputManager::prevOrReset()
1094 {
1095     if( !p_input || var_GetTime(  p_input , "time") < 10000 )
1096         playlist_Prev( THEPL );
1097     else
1098         getIM()->sliderUpdate( 0.0 );
1099 }
1100
1101 void MainInputManager::togglePlayPause()
1102 {
1103     /* No input, play */
1104     if( !p_input )
1105         playlist_Play( THEPL );
1106     else
1107         getIM()->togglePlayPause();
1108 }
1109
1110 void MainInputManager::play()
1111 {
1112     /* No input, play */
1113     if( !p_input )
1114         playlist_Play( THEPL );
1115     else
1116     {
1117         if( PLAYING_S != var_GetInteger( p_input, "state" ) )
1118         {
1119             getIM()->togglePlayPause();
1120         }
1121     }
1122 }
1123
1124 void MainInputManager::pause()
1125 {
1126     if(p_input && PLAYING_S == var_GetInteger( p_input, "state" ) )
1127     {
1128         getIM()->togglePlayPause();
1129     }
1130 }
1131
1132 void MainInputManager::toggleRandom()
1133 {
1134     var_ToggleBool( THEPL, "random" );
1135 }
1136
1137 void MainInputManager::notifyRepeatLoop()
1138 {
1139     int i_value = var_GetBool( THEPL, "loop" ) * REPEAT_ALL
1140               + var_GetBool( THEPL, "repeat" ) * REPEAT_ONE;
1141
1142     emit repeatLoopChanged( i_value );
1143 }
1144
1145 void MainInputManager::loopRepeatLoopStatus()
1146 {
1147     /* Toggle Normal -> Loop -> Repeat -> Normal ... */
1148     if( var_GetBool( THEPL, "repeat" ) )
1149         var_SetBool( THEPL, "repeat", false );
1150     else if( var_GetBool( THEPL, "loop" ) )
1151     {
1152         var_SetBool( THEPL, "loop", false );
1153         var_SetBool( THEPL, "repeat", true );
1154     }
1155     else
1156         var_SetBool( THEPL, "loop", true );
1157 }
1158
1159 void MainInputManager::activatePlayQuit( bool b_exit )
1160 {
1161     var_SetBool( THEPL, "play-and-exit", b_exit );
1162 }
1163
1164 bool MainInputManager::getPlayExitState()
1165 {
1166     return var_GetBool( THEPL, "play-and-exit" );
1167 }
1168
1169 /****************************
1170  * Static callbacks for MIM *
1171  ****************************/
1172 static int PLItemChanged( vlc_object_t *p_this, const char *psz_var,
1173                         vlc_value_t oldval, vlc_value_t, void *param )
1174 {
1175     VLC_UNUSED( p_this ); VLC_UNUSED( psz_var ); VLC_UNUSED( oldval );
1176
1177     MainInputManager *mim = (MainInputManager*)param;
1178
1179     IMEvent *event = new IMEvent( ItemChanged_Type );
1180     QApplication::postEvent( mim, event );
1181     return VLC_SUCCESS;
1182 }
1183
1184 static int LeafToParent( vlc_object_t *p_this, const char *psz_var,
1185                         vlc_value_t oldval, vlc_value_t newval, void *param )
1186 {
1187     VLC_UNUSED( p_this ); VLC_UNUSED( psz_var ); VLC_UNUSED( oldval );
1188     MainInputManager *mim = (MainInputManager*)param;
1189
1190     PLEvent *event = new PLEvent( LeafToParent_Type, newval.i_int );
1191
1192     QApplication::postEvent( mim, event );
1193     return VLC_SUCCESS;
1194 }
1195
1196 static int VolumeChanged( vlc_object_t *p_this, const char *psz_var,
1197                         vlc_value_t oldval, vlc_value_t newval, void *param )
1198 {
1199     VLC_UNUSED( p_this ); VLC_UNUSED( psz_var ); VLC_UNUSED( oldval ); VLC_UNUSED( newval );
1200
1201     MainInputManager *mim = (MainInputManager*)param;
1202
1203     IMEvent *event = new IMEvent( VolumeChanged_Type );
1204     QApplication::postEvent( mim, event );
1205     return VLC_SUCCESS;
1206 }
1207
1208 static int SoundMuteChanged( vlc_object_t *p_this, const char *psz_var,
1209                         vlc_value_t oldval, vlc_value_t newval, void *param )
1210 {
1211     VLC_UNUSED( p_this ); VLC_UNUSED( psz_var ); VLC_UNUSED( oldval ); VLC_UNUSED( newval );
1212
1213     MainInputManager *mim = (MainInputManager*)param;
1214
1215     IMEvent *event = new IMEvent( SoundMuteChanged_Type );
1216     QApplication::postEvent( mim, event );
1217     return VLC_SUCCESS;
1218 }
1219
1220 static int PLItemAppended
1221 ( vlc_object_t * obj, const char *var, vlc_value_t old, vlc_value_t cur, void *data )
1222 {
1223     VLC_UNUSED( obj ); VLC_UNUSED( var ); VLC_UNUSED( old );
1224
1225     MainInputManager *mim = static_cast<MainInputManager*>(data);
1226     playlist_add_t *p_add = static_cast<playlist_add_t*>( cur.p_address );
1227
1228     PLEvent *event = new PLEvent( PLItemAppended_Type, p_add->i_item, p_add->i_node  );
1229     QApplication::postEvent( mim, event );
1230     return VLC_SUCCESS;
1231 }
1232 static int PLItemRemoved
1233 ( vlc_object_t * obj, const char *var, vlc_value_t old, vlc_value_t cur, void *data )
1234 {
1235     VLC_UNUSED( obj ); VLC_UNUSED( var ); VLC_UNUSED( old );
1236
1237     MainInputManager *mim = static_cast<MainInputManager*>(data);
1238
1239     PLEvent *event = new PLEvent( PLItemRemoved_Type, cur.i_int, 0  );
1240     QApplication::postEvent( mim, event );
1241     return VLC_SUCCESS;
1242 }
1243
1244 static int RandomChanged
1245 ( vlc_object_t * obj, const char *var, vlc_value_t old, vlc_value_t cur, void *data )
1246 {
1247     VLC_UNUSED( obj ); VLC_UNUSED( var ); VLC_UNUSED( old ); VLC_UNUSED( cur );
1248
1249     MainInputManager *mim = static_cast<MainInputManager*>(data);
1250
1251     IMEvent *event = new IMEvent( RandomChanged_Type );
1252     QApplication::postEvent( mim, event );
1253     return VLC_SUCCESS;
1254 }
1255
1256 /* Probably could be merged with next callback */
1257 static int LoopChanged
1258 ( vlc_object_t * obj, const char *var, vlc_value_t old, vlc_value_t cur, void *data )
1259 {
1260     VLC_UNUSED( obj ); VLC_UNUSED( var ); VLC_UNUSED( old ); VLC_UNUSED( cur );
1261
1262     MainInputManager *mim = static_cast<MainInputManager*>(data);
1263
1264     IMEvent *event = new IMEvent( LoopChanged_Type );
1265     QApplication::postEvent( mim, event );
1266     return VLC_SUCCESS;
1267 }
1268
1269 static int RepeatChanged
1270 ( vlc_object_t * obj, const char *var, vlc_value_t old, vlc_value_t cur, void *data )
1271 {
1272     VLC_UNUSED( obj ); VLC_UNUSED( var ); VLC_UNUSED( old ); VLC_UNUSED( cur );
1273
1274     MainInputManager *mim = static_cast<MainInputManager*>(data);
1275
1276     IMEvent *event = new IMEvent( RepeatChanged_Type );
1277     QApplication::postEvent( mim, event );
1278     return VLC_SUCCESS;
1279 }