]> git.sesse.net Git - vlc/blob - modules/gui/qt4/input_manager.cpp
(qt4) Enable reverse playback direction button in qt4 interface.
[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 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include "qt4.hpp"
30 #include "input_manager.hpp"
31 #include "dialogs_provider.hpp"
32
33 static int ChangeSPU( vlc_object_t *p_this, const char *var, vlc_value_t o,
34                       vlc_value_t n, void *param );
35
36 static int ChangeTeletext( vlc_object_t *p_this, const char *var, vlc_value_t o,
37                            vlc_value_t n, void *param );
38
39 static int ItemChanged( vlc_object_t *, const char *,
40                         vlc_value_t, vlc_value_t, void * );
41 static int PLItemChanged( vlc_object_t *, const char *,
42                         vlc_value_t, vlc_value_t, void * );
43 static int InterfaceChanged( vlc_object_t *, const char *,
44                             vlc_value_t, vlc_value_t, void * );
45 static int StatisticsUpdated( vlc_object_t *, const char *,
46                             vlc_value_t, vlc_value_t, void * );
47 static int InterfaceVoutChanged( vlc_object_t *, const char *,
48                                  vlc_value_t, vlc_value_t, void * );
49 static int ItemStateChanged( vlc_object_t *, const char *,
50                         vlc_value_t, vlc_value_t, void * );
51 static int ItemRateChanged( vlc_object_t *, const char *,
52                         vlc_value_t, vlc_value_t, void * );
53 static int ItemTitleChanged( vlc_object_t *, const char *,
54                         vlc_value_t, vlc_value_t, void * );
55 static int VolumeChanged( vlc_object_t *, const char *,
56                         vlc_value_t, vlc_value_t, void * );
57
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  **********************************************************************/
64
65 InputManager::InputManager( QObject *parent, intf_thread_t *_p_intf) :
66                            QObject( parent ), p_intf( _p_intf )
67 {
68     i_old_playing_status = END_S;
69     oldName      = "";
70     artUrl       = "";
71     p_input      = NULL;
72     i_rate       = 0;
73     i_input_id   = 0;
74     b_video      = false;
75     timeA        = 0;
76     timeB        = 0;
77
78 }
79
80 InputManager::~InputManager()
81 {
82     delInput();
83 }
84
85 /* Define the Input used.
86    Add the callbacks on input
87    p_input is held once here */
88 void InputManager::setInput( input_thread_t *_p_input )
89 {
90     delInput();
91     p_input = _p_input;
92     if( p_input && !( p_input->b_dead || !vlc_object_alive (p_input) ) )
93     {
94         vlc_object_hold( p_input );
95         emit statusChanged( PLAYING_S );
96         UpdateMeta();
97         UpdateArt();
98         UpdateTeletext();
99         UpdateNavigation();
100         UpdateVout();
101         addCallbacks();
102         i_input_id = input_GetItem( p_input )->i_id;
103     }
104     else
105     {
106         p_input = NULL;
107         i_input_id = 0;
108         emit rateChanged( INPUT_RATE_DEFAULT );
109     }
110 }
111
112 /* delete Input if it ever existed.
113    Delete the callbacls on input
114    p_input is released once here */
115 void InputManager::delInput()
116 {
117     if( p_input )
118     {
119         delCallbacks();
120         i_old_playing_status = END_S;
121         i_input_id = 0;
122         oldName    = "";
123         artUrl     = "";
124         b_video    = false;
125         timeA      = 0;
126         timeB      = 0;
127         emit positionUpdated( -1.0, 0 ,0 );
128         emit statusChanged( END_S );
129         emit nameChanged( "" );
130         emit artChanged( NULL );
131         emit rateChanged( INPUT_RATE_DEFAULT );
132         emit voutChanged( false );
133         vlc_object_release( p_input );
134         p_input = NULL;
135         UpdateTeletext();
136     }
137 }
138
139 /* Add the callbacks on Input. Self explanatory */
140 void InputManager::addCallbacks()
141 {
142     /* We don't care about:
143        - chapter
144        - programs
145        - audio-delay
146        - spu-delay
147        - bookmark
148        - position, time, length, because they are included in intf-change
149      */
150     /* src/input/input.c:1629 */
151     var_AddCallback( p_input, "state", ItemStateChanged, this );
152     /* src/input/es-out.c:552 */
153     var_AddCallback( p_input, "spu-es", ChangeSPU, this );
154     /* emit UpdateStatus so that main_interface updates controls
155      * if there is new videotracks (mpeg-ts)*/
156     var_AddCallback( p_input, "video-es", ItemStateChanged, this );
157     /* src/input/es-out.c: */
158     var_AddCallback( p_input, "teletext-es", ChangeTeletext, this );
159     /* src/input/input.c:1765 */
160     var_AddCallback( p_input, "rate-change", ItemRateChanged, this );
161     /* src/input/input.c:2003 */
162     var_AddCallback( p_input, "title", ItemTitleChanged, this );
163     /* src/input/input.c:734 for timers update*/
164     var_AddCallback( p_input, "intf-change", InterfaceChanged, this );
165     /* src/input/input.c:710 for statistics update*/
166     var_AddCallback( p_input, "stats-change", StatisticsUpdated, this );
167     /* src/input/input.c for vout creation/destruction */
168     var_AddCallback( p_input, "intf-change-vout", InterfaceVoutChanged, this );
169 }
170
171 /* Delete the callbacks on Input. Self explanatory */
172 void InputManager::delCallbacks()
173 {
174     var_DelCallback( p_input, "spu-es", ChangeSPU, this );
175     var_DelCallback( p_input, "video-es", ItemStateChanged, this );
176     var_DelCallback( p_input, "teletext-es", ChangeTeletext, this );
177     var_DelCallback( p_input, "state", ItemStateChanged, this );
178     var_DelCallback( p_input, "rate-change", ItemRateChanged, this );
179     var_DelCallback( p_input, "title", ItemTitleChanged, this );
180     var_DelCallback( p_input, "intf-change", InterfaceChanged, this );
181     var_DelCallback( p_input, "stats-change", StatisticsUpdated, this );
182     var_DelCallback( p_input, "intf-change-vout", InterfaceVoutChanged, this );
183 }
184
185 /* Convert the event from the callbacks in actions */
186 void InputManager::customEvent( QEvent *event )
187 {
188     int i_type = event->type();
189     IMEvent *ple = static_cast<IMEvent *>(event);
190
191     if ( i_type != PositionUpdate_Type &&
192          i_type != ItemChanged_Type &&
193          i_type != ItemRateChanged_Type &&
194          i_type != ItemTitleChanged_Type &&
195          i_type != ItemSpuChanged_Type &&
196          i_type != ItemTeletextChanged_Type &&
197          i_type != ItemStateChanged_Type &&
198          i_type != StatisticsUpdate_Type &&
199          i_type != InterfaceVoutUpdate_Type )
200         return;
201
202     if( i_type == ItemStateChanged_Type )
203     {
204         UpdateNavigation();
205         UpdateTeletext();
206     }
207
208     if( !hasInput() ) return;
209
210     if( ( i_type != PositionUpdate_Type  &&
211           i_type != ItemRateChanged_Type &&
212           i_type != ItemSpuChanged_Type &&
213           i_type != ItemTeletextChanged_Type &&
214           i_type != ItemStateChanged_Type &&
215           i_type != StatisticsUpdate_Type &&
216           i_type != InterfaceVoutUpdate_Type
217         )
218         && ( i_input_id != ple->i_id ) )
219         return;
220
221     if( i_type != PositionUpdate_Type &&
222         i_type != StatisticsUpdate_Type )
223         msg_Dbg( p_intf, "New Event: type %i", i_type );
224
225     /* Actions */
226     switch( i_type )
227     {
228     case PositionUpdate_Type:
229         UpdatePosition();
230         break;
231     case StatisticsUpdate_Type:
232         UpdateStats();
233         break;
234     case ItemChanged_Type:
235         UpdateMeta();
236         UpdateStatus();
237         UpdateArt();
238         break;
239     case ItemStateChanged_Type:
240         UpdateStatus();
241         UpdateNavigation();
242         UpdateMeta();
243         break;
244     case ItemTitleChanged_Type:
245         UpdateNavigation();
246         UpdateMeta();
247         break;
248     case ItemRateChanged_Type:
249         UpdateRate();
250         break;
251     case ItemSpuChanged_Type:
252         UpdateSPU();
253         break;
254     case ItemTeletextChanged_Type:
255         UpdateTeletext();
256         break;
257     case InterfaceVoutUpdate_Type:
258         UpdateVout();
259         break;
260     default:
261         msg_Warn( p_intf, "This shouldn't happen: %i", i_type );
262     }
263 }
264
265 void InputManager::UpdateStats()
266 {
267     emit statisticsUpdated( input_GetItem( p_input ) );
268 }
269
270 void InputManager::UpdatePosition()
271 {
272     /* Update position */
273     int i_length, i_time; /* Int is enough, since we store seconds */
274     float f_pos;
275     i_length = var_GetTime(  p_input , "length" ) / 1000000;
276     i_time = var_GetTime(  p_input , "time") / 1000000;
277     f_pos = var_GetFloat(  p_input , "position" );
278     emit positionUpdated( f_pos, i_time, i_length );
279 }
280
281 void InputManager::UpdateNavigation()
282 {
283     /* Update navigation status */
284     vlc_value_t val; val.i_int = 0;
285
286     if( hasInput() )
287         var_Change( p_input, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
288
289     if( val.i_int > 0 )
290     {
291         emit titleChanged( true );
292         /* p_input != NULL since val.i_int != 0 */
293         val.i_int = 0;
294         var_Change( p_input, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
295         emit chapterChanged( (val.i_int > 0) );
296     }
297     else
298         emit titleChanged( false );
299 }
300
301 void InputManager::UpdateStatus()
302 {
303     /* Update playing status */
304     vlc_value_t val; val.i_int = 0;
305     var_Get( p_input, "state", &val );
306     if( i_old_playing_status != val.i_int )
307     {
308         i_old_playing_status = val.i_int;
309         emit statusChanged( val.i_int );
310     }
311 }
312
313 void InputManager::UpdateRate()
314 {
315     /* Update Rate */
316     int i_new_rate = var_GetInteger( p_input, "rate");
317     if( i_new_rate != i_rate )
318     {
319         i_rate = i_new_rate;
320         /* Update rate */
321         emit rateChanged( i_rate );
322     }
323 }
324
325 void InputManager::UpdateMeta()
326 {
327     /* Update text, name and nowplaying */
328     QString text;
329
330     /* Try to get the Title, then the Name */
331     char *psz_name = input_item_GetTitle( input_GetItem( p_input ) );
332     if( EMPTY_STR( psz_name ) )
333     {
334         free( psz_name );
335         psz_name = input_item_GetName( input_GetItem( p_input ) );
336     }
337
338     /* Try to get the nowplaying */
339     char *psz_nowplaying =
340         input_item_GetNowPlaying( input_GetItem( p_input ) );
341     if( !EMPTY_STR( psz_nowplaying ) )
342     {
343         text.sprintf( "%s - %s", psz_nowplaying, psz_name );
344     }
345     else  /* Do it ourself */
346     {
347         char *psz_artist = input_item_GetArtist( input_GetItem( p_input ) );
348
349         if( !EMPTY_STR( psz_artist ) )
350             text.sprintf( "%s - %s", psz_artist, psz_name );
351         else
352             text.sprintf( "%s", psz_name );
353
354         free( psz_artist );
355     }
356     /* Free everything */
357     free( psz_name );
358     free( psz_nowplaying );
359
360     /* If we have Nothing */
361     if( text.isEmpty() )
362     {
363         psz_name = input_item_GetURI( input_GetItem( p_input ) );
364         text.sprintf( "%s", psz_name );
365         text = text.remove( 0, text.lastIndexOf( DIR_SEP ) + 1 );
366         free( psz_name );
367     }
368
369     if( oldName != text )
370     {
371         emit nameChanged( text );
372         oldName=text;
373     }
374 }
375
376 bool InputManager::hasAudio()
377 {
378     if( hasInput() )
379     {
380         vlc_value_t val;
381         var_Change( p_input, "audio-es", VLC_VAR_CHOICESCOUNT, &val, NULL );
382         return val.i_int > 0;
383     }
384     return false;
385 }
386
387 void InputManager::UpdateSPU()
388 {
389     UpdateTeletext();
390 }
391
392 void InputManager::UpdateTeletext()
393 {
394     if( hasInput() )
395         telexActivation( var_GetInteger( p_input, "teletext-es" ) >= 0 );
396     else
397         telexActivation( false );
398 }
399
400 void InputManager::UpdateVout()
401 {
402     if( hasInput() )
403     {
404         bool b_old_video = b_video;
405
406         vlc_object_t *p_vout = (vlc_object_t*)vlc_object_find( p_input,
407                                          VLC_OBJECT_VOUT, FIND_CHILD );
408         b_video = p_vout != NULL;
409         if( p_vout )
410             vlc_object_release( p_vout );
411         if( !!b_old_video != !!b_video )
412             emit voutChanged( b_video );
413     }
414 }
415
416 void InputManager::UpdateArt()
417 {
418     /* Update Art meta */
419     emit artChanged( input_GetItem( p_input ) );
420 }
421
422 /* User update of the slider */
423 void InputManager::sliderUpdate( float new_pos )
424 {
425     if( hasInput() )
426         var_SetFloat( p_input, "position", new_pos );
427 }
428
429 /* User togglePlayPause */
430 void InputManager::togglePlayPause()
431 {
432     vlc_value_t state;
433     if( hasInput() )
434     {
435         var_Get( p_input, "state", &state );
436         state.i_int = ( state.i_int != PLAYING_S ) ? PLAYING_S : PAUSE_S;
437         var_Set( p_input, "state", state );
438         emit statusChanged( state.i_int );
439     }
440 }
441
442 void InputManager::sectionPrev()
443 {
444     if( hasInput() )
445     {
446         int i_type = var_Type( p_input, "next-chapter" );
447         vlc_value_t val; val.b_bool = true;
448         var_Set( p_input, (i_type & VLC_VAR_TYPE) != 0 ?
449                             "prev-chapter":"prev-title", val );
450     }
451 }
452
453 void InputManager::sectionNext()
454 {
455     if( hasInput() )
456     {
457         int i_type = var_Type( p_input, "next-chapter" );
458         vlc_value_t val; val.b_bool = true;
459         var_Set( p_input, (i_type & VLC_VAR_TYPE) != 0 ?
460                             "next-chapter":"next-title", val );
461     }
462 }
463
464 void InputManager::sectionMenu()
465 {
466     if( hasInput() )
467     {
468         vlc_value_t val, text;
469         vlc_value_t root;
470
471         if( var_Change( p_input, "title  0", VLC_VAR_GETLIST, &val, &text ) < 0 )
472             return;
473
474         /* XXX is it "Root" or "Title" we want here ?" (set 0 by default) */
475         root.i_int = 0;
476         for( int i = 0; i < val.p_list->i_count; i++ )
477         {
478             if( !strcmp( text.p_list->p_values[i].psz_string, "Title" ) )
479                 root.i_int = i;
480         }
481         var_Change( p_input, "title  0", VLC_VAR_FREELIST, &val, &text );
482
483         var_Set( p_input, "title  0", root );
484     }
485 }
486
487 /*
488  *  Teletext Functions
489  */
490
491 /* Set a new Teletext Page */
492 void InputManager::telexSetPage( int page )
493 {
494     if( hasInput() )
495     {
496         const int i_teletext_es = var_GetInteger( p_input, "teletext-es" );
497         const int i_spu_es = var_GetInteger( p_input, "spu-es" );
498
499         if( i_teletext_es >= 0 && i_teletext_es == i_spu_es )
500         {
501             vlc_object_t *p_vbi = (vlc_object_t *) vlc_object_find_name( p_input,
502                         "zvbi", FIND_ANYWHERE );
503             if( p_vbi )
504             {
505                 var_SetInteger( p_vbi, "vbi-page", page );
506                 vlc_object_release( p_vbi );
507                 emit newTelexPageSet( page );
508             }
509         }
510     }
511 }
512
513 /* Set the transparency on teletext */
514 void InputManager::telexSetTransparency( bool b_transparentTelextext )
515 {
516     if( hasInput() )
517     {
518         vlc_object_t *p_vbi = (vlc_object_t *) vlc_object_find_name( p_input,
519                     "zvbi", FIND_ANYWHERE );
520         if( p_vbi )
521         {
522             var_SetBool( p_vbi, "vbi-opaque", b_transparentTelextext );
523             vlc_object_release( p_vbi );
524             emit teletextTransparencyActivated( b_transparentTelextext );
525         }
526     }
527 }
528
529 void InputManager::telexActivation( bool b_enabled )
530 {
531     if( hasInput() )
532     {
533         const int i_teletext_es = var_GetInteger( p_input, "teletext-es" );
534         const int i_spu_es = var_GetInteger( p_input, "spu-es" );
535
536         /* Teletext is possible. Show the buttons */
537         b_enabled = (i_teletext_es >= 0);
538         emit teletextPossible( b_enabled );
539         if( !b_enabled ) return;
540
541         /* If Teletext is selected */
542         if( i_teletext_es == i_spu_es )
543         {
544             /* Activate the buttons */
545             teletextActivated( true );
546
547             /* Then, find the current page */
548             int i_page = 100;
549             vlc_object_t *p_vbi = (vlc_object_t *)
550                 vlc_object_find_name( p_input, "zvbi", FIND_ANYWHERE );
551             if( p_vbi )
552             {
553                 i_page = var_GetInteger( p_vbi, "vbi-page" );
554                 vlc_object_release( p_vbi );
555                 emit newTelexPageSet( i_page );
556             }
557         }
558     }
559     else
560         emit teletextPossible( b_enabled );
561 }
562
563 void InputManager::activateTeletext( bool b_enable )
564 {
565     if( hasInput() )
566     {
567         const int i_teletext_es = var_GetInteger( p_input, "teletext-es" );
568         if( i_teletext_es >= 0 )
569         {
570             var_SetInteger( p_input, "spu-es", b_enable ? i_teletext_es : -1 );
571         }
572     }
573 }
574
575 void InputManager::reverse()
576 {
577     if( hasInput() )
578     {
579         int i_rate = var_GetInteger( p_input, "rate" );
580         var_SetInteger( p_input, "rate", -i_rate );
581     }
582 }
583
584 void InputManager::slower()
585 {
586     if( hasInput() )
587         var_SetVoid( p_input, "rate-slower" );
588 }
589
590 void InputManager::faster()
591 {
592     if( hasInput() )
593         var_SetVoid( p_input, "rate-faster" );
594 }
595
596 void InputManager::normalRate()
597 {
598     if( hasInput() )
599         var_SetInteger( p_input, "rate", INPUT_RATE_DEFAULT );
600 }
601
602 void InputManager::setRate( int new_rate )
603 {
604     if( hasInput() )
605         var_SetInteger( p_input, "rate", new_rate );
606 }
607
608 void InputManager::setAtoB()
609 {
610     if( !timeA )
611     {
612         timeA = var_GetTime( THEMIM->getInput(), "time"  );
613     }
614     else if( !timeB )
615     {
616         timeB = var_GetTime( THEMIM->getInput(), "time"  );
617         var_SetTime( THEMIM->getInput(), "time" , timeA );
618     }
619     else
620     {
621         timeA = 0;
622         timeB = 0;
623     }
624     emit AtoBchanged( (timeA != 0 ), (timeB != 0 ) );
625 }
626
627 /* Function called regularly when in an AtoB loop */
628 void InputManager::AtoBLoop( int i_time )
629 {
630     if( timeB )
631     {
632         if( ( i_time >= (int)( timeB/1000000 ) )
633             || ( i_time < (int)( timeA/1000000 ) ) )
634             var_SetTime( THEMIM->getInput(), "time" , timeA );
635     }
636 }
637
638 /**********************************************************************
639  * MainInputManager implementation. Wrap an input manager and
640  * take care of updating the main playlist input.
641  * Used in the main playlist Dialog
642  **********************************************************************/
643 MainInputManager * MainInputManager::instance = NULL;
644
645 MainInputManager::MainInputManager( intf_thread_t *_p_intf )
646                  : QObject(NULL), p_intf( _p_intf )
647 {
648     p_input = NULL;
649     im = new InputManager( this, p_intf );
650
651     var_AddCallback( THEPL, "item-change", ItemChanged, im );
652     var_AddCallback( THEPL, "playlist-current", PLItemChanged, this );
653     var_AddCallback( THEPL, "activity", PLItemChanged, this );
654
655     var_AddCallback( p_intf->p_libvlc, "volume-change", VolumeChanged, this );
656
657     /* Warn our embedded IM about input changes */
658     CONNECT( this, inputChanged( input_thread_t * ),
659              im, setInput( input_thread_t * ) );
660
661     /* emit check if playlist has allready started playing */
662     vlc_value_t val;
663     var_Change( THEPL, "playlist-current", VLC_VAR_CHOICESCOUNT, &val, NULL );
664     IMEvent *event = new IMEvent( ItemChanged_Type, val.i_int);
665     QApplication::postEvent( this, static_cast<QEvent*>(event) );
666
667 }
668
669 MainInputManager::~MainInputManager()
670 {
671     if( p_input )
672     {
673        var_DelCallback( p_input, "state", PLItemChanged, this );
674        vlc_object_release( p_input );
675        emit inputChanged( NULL );
676     }
677
678     var_DelCallback( p_intf->p_libvlc, "volume-change", VolumeChanged, this );
679
680     var_DelCallback( THEPL, "activity", PLItemChanged, this );
681     var_DelCallback( THEPL, "item-change", ItemChanged, im );
682
683     var_DelCallback( THEPL, "playlist-current", PLItemChanged, this );
684 }
685
686 void MainInputManager::customEvent( QEvent *event )
687 {
688     int type = event->type();
689     if ( type != ItemChanged_Type && type != VolumeChanged_Type )
690         return;
691
692     // msg_Dbg( p_intf, "New MainIM Event of type: %i", type );
693     if( type == VolumeChanged_Type )
694     {
695         emit volumeChanged();
696         return;
697     }
698
699     /* Should be PLItemChanged Event */
700     if( !p_intf->p_sys->b_isDialogProvider )
701     {
702         vlc_mutex_lock( &p_intf->change_lock );
703         if( p_input && ( p_input->b_dead || !vlc_object_alive (p_input) ) )
704         {
705             var_DelCallback( p_input, "state", PLItemChanged, this );
706             vlc_object_release( p_input );
707             emit inputChanged( NULL );
708             p_input = NULL;
709             vlc_mutex_unlock( &p_intf->change_lock );
710             return;
711         }
712
713         if( !p_input )
714         {
715             p_input = playlist_CurrentInput(THEPL);
716             if( p_input )
717             {
718                 var_AddCallback( p_input, "state", PLItemChanged, this );
719                 emit inputChanged( p_input );
720             }
721         }
722         vlc_mutex_unlock( &p_intf->change_lock );
723     }
724     else
725     {
726         /* we are working as a dialogs provider */
727         playlist_t *p_playlist = pl_Hold( p_intf );
728         p_input = playlist_CurrentInput( p_playlist );
729         if( p_input )
730         {
731             emit inputChanged( p_input );
732             vlc_object_release( p_input );
733         }
734         pl_Release( p_intf );
735     }
736 }
737
738 /* Playlist Control functions */
739 void MainInputManager::stop()
740 {
741    playlist_Stop( THEPL );
742 }
743
744 void MainInputManager::next()
745 {
746    playlist_Next( THEPL );
747 }
748
749 void MainInputManager::prev()
750 {
751    playlist_Prev( THEPL );
752 }
753
754 void MainInputManager::togglePlayPause()
755 {
756     /* No input, play */
757     if( !p_input )
758         playlist_Play( THEPL );
759     else
760         getIM()->togglePlayPause();
761 }
762
763 /* Static callbacks */
764
765 /* IM */
766 static int InterfaceChanged( vlc_object_t *p_this, const char *psz_var,
767                            vlc_value_t oldval, vlc_value_t newval, void *param )
768 {
769     /* FIXME remove that static variable */
770     static int counter = 0;
771
772     InputManager *im = (InputManager*)param;
773
774     counter = ++counter % 4;
775     if(!counter) return VLC_SUCCESS;
776
777     IMEvent *event = new IMEvent( PositionUpdate_Type, 0 );
778     QApplication::postEvent( im, static_cast<QEvent*>(event) );
779     return VLC_SUCCESS;
780 }
781
782 static int StatisticsUpdated( vlc_object_t *p_this, const char *psz_var,
783                            vlc_value_t oldval, vlc_value_t newval, void *param )
784 {
785     InputManager *im = (InputManager*)param;
786
787     IMEvent *event = new IMEvent( StatisticsUpdate_Type, 0 );
788     QApplication::postEvent( im, static_cast<QEvent*>(event) );
789     return VLC_SUCCESS;
790 }
791
792 static int InterfaceVoutChanged( vlc_object_t *p_this, const char *psz_var,
793                                  vlc_value_t oldval, vlc_value_t newval, void *param )
794 {
795     InputManager *im = (InputManager*)param;
796
797     IMEvent *event = new IMEvent( InterfaceVoutUpdate_Type, 0 );
798     QApplication::postEvent( im, static_cast<QEvent*>(event) );
799     return VLC_SUCCESS;
800 }
801
802 static int ItemStateChanged( vlc_object_t *p_this, const char *psz_var,
803                            vlc_value_t oldval, vlc_value_t newval, void *param )
804 {
805     InputManager *im = (InputManager*)param;
806
807     IMEvent *event = new IMEvent( ItemStateChanged_Type, 0 );
808     QApplication::postEvent( im, static_cast<QEvent*>(event) );
809     return VLC_SUCCESS;
810 }
811
812 static int ItemRateChanged( vlc_object_t *p_this, const char *psz_var,
813                            vlc_value_t oldval, vlc_value_t newval, void *param )
814 {
815     InputManager *im = (InputManager*)param;
816
817     IMEvent *event = new IMEvent( ItemRateChanged_Type, 0 );
818     QApplication::postEvent( im, static_cast<QEvent*>(event) );
819     return VLC_SUCCESS;
820 }
821
822 static int ItemTitleChanged( vlc_object_t *p_this, const char *psz_var,
823                            vlc_value_t oldval, vlc_value_t newval, void *param )
824 {
825     InputManager *im = (InputManager*)param;
826
827     IMEvent *event = new IMEvent( ItemTitleChanged_Type, 0 );
828     QApplication::postEvent( im, static_cast<QEvent*>(event) );
829     return VLC_SUCCESS;
830 }
831
832 static int ItemChanged( vlc_object_t *p_this, const char *psz_var,
833                         vlc_value_t oldval, vlc_value_t newval, void *param )
834 {
835     InputManager *im = (InputManager*)param;
836
837     IMEvent *event = new IMEvent( ItemChanged_Type, newval.i_int );
838     QApplication::postEvent( im, static_cast<QEvent*>(event) );
839     return VLC_SUCCESS;
840 }
841
842 static int ChangeSPU( vlc_object_t *p_this, const char *var, vlc_value_t o,
843                         vlc_value_t n, void *param )
844 {
845     InputManager *im = (InputManager*)param;
846     IMEvent *event = new IMEvent( ItemSpuChanged_Type, 0 );
847     QApplication::postEvent( im, static_cast<QEvent*>(event) );
848     return VLC_SUCCESS;
849 }
850
851 static int ChangeTeletext( vlc_object_t *p_this, const char *var, vlc_value_t o,
852                            vlc_value_t n, void *param )
853 {
854
855     InputManager *im = (InputManager*)param;
856     IMEvent *event = new IMEvent( ItemTeletextChanged_Type, 0 );
857     QApplication::postEvent( im, static_cast<QEvent*>(event) );
858     return VLC_SUCCESS;
859 }
860
861 /* MIM */
862 static int PLItemChanged( vlc_object_t *p_this, const char *psz_var,
863                         vlc_value_t oldval, vlc_value_t newval, void *param )
864 {
865     MainInputManager *mim = (MainInputManager*)param;
866
867     IMEvent *event = new IMEvent( ItemChanged_Type, newval.i_int );
868     QApplication::postEvent( mim, static_cast<QEvent*>(event) );
869     return VLC_SUCCESS;
870 }
871
872 static int VolumeChanged( vlc_object_t *p_this, const char *psz_var,
873                         vlc_value_t oldval, vlc_value_t newval, void *param )
874 {
875     MainInputManager *mim = (MainInputManager*)param;
876
877     IMEvent *event = new IMEvent( VolumeChanged_Type, newval.i_int );
878     QApplication::postEvent( mim, static_cast<QEvent*>(event) );
879     return VLC_SUCCESS;
880 }