]> git.sesse.net Git - vlc/blob - modules/gui/qt4/input_manager.cpp
Qt4 - Try to fix the detection of video tracks and show of related buttons, fix a...
[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 ChangeVideo( vlc_object_t *p_this, const char *var, vlc_value_t o,
34                         vlc_value_t n, void *param );
35 static int ChangeAudio( vlc_object_t *p_this, const char *var, vlc_value_t o,
36                         vlc_value_t n, void *param );
37 static int ItemChanged( vlc_object_t *, const char *,
38                         vlc_value_t, vlc_value_t, void * );
39 static int PLItemChanged( vlc_object_t *, const char *,
40                         vlc_value_t, vlc_value_t, void * );
41 static int InterfaceChanged( vlc_object_t *, const char *,
42                             vlc_value_t, vlc_value_t, void * );
43 static int ItemStateChanged( vlc_object_t *, const char *,
44                         vlc_value_t, vlc_value_t, void * );
45 static int ItemRateChanged( vlc_object_t *, const char *,
46                         vlc_value_t, vlc_value_t, void * );
47 static int ItemTitleChanged( vlc_object_t *, const char *,
48                         vlc_value_t, vlc_value_t, void * );
49 static int VolumeChanged( vlc_object_t *, const char *,
50                         vlc_value_t, vlc_value_t, void * );
51
52 /**********************************************************************
53  * InputManager implementation
54  **********************************************************************
55  * The Input Manager can be the main one around the playlist
56  * But can also be used for VLM dialog or similar
57  **********************************************************************/
58
59 InputManager::InputManager( QObject *parent, intf_thread_t *_p_intf) :
60                            QObject( parent ), p_intf( _p_intf )
61 {
62     i_old_playing_status = END_S;
63     old_name = "";
64     p_input = NULL;
65     i_rate = 0;
66 }
67
68 InputManager::~InputManager()
69 {
70     delInput();
71 }
72
73 /* Define the Input used.
74    Add the callbacks on input
75    p_input is yield once here */
76 void InputManager::setInput( input_thread_t *_p_input )
77 {
78     delInput();
79     p_input = _p_input;
80     b_had_audio = b_had_video = b_has_audio = b_has_video = false;
81     if( p_input )
82     {
83         vlc_object_yield( p_input );
84         vlc_value_t val;
85         var_Change( p_input, "video-es", VLC_VAR_CHOICESCOUNT, &val, NULL );
86         b_has_video = val.i_int > 0;
87         var_Change( p_input, "audio-es", VLC_VAR_CHOICESCOUNT, &val, NULL );
88         b_has_audio = val.i_int > 0;
89         emit statusChanged( PLAYING_S );
90         addCallbacks();
91     }
92 }
93
94 /* delete Input if it ever existed.
95    Delete the callbacls on input
96    p_input is released once here */
97 void InputManager::delInput()
98 {
99     if( p_input )
100     {
101         delCallbacks();
102         vlc_object_release( p_input );
103         i_old_playing_status = END_S;
104
105         old_name=qfu("");
106         artUrl = qfu("");
107         emit positionUpdated( 0.0, 0 ,0 );
108         emit statusChanged( END_S );
109         emit nameChanged( "" );
110         emit artChanged( "" );
111         p_input = NULL;
112     }
113 }
114
115 /* Add the callbacks on Input. Self explanatory */
116 void InputManager::addCallbacks()
117 {
118     /* We don't care about:
119        - spu-es
120        - chapter
121        - programs
122        - audio-delay
123        - spu-delay
124        - bookmark
125        - position, time, length, because they are included in intf-change
126      */
127     /* src/input/input.c:1629 */
128     var_AddCallback( p_input, "state", ItemStateChanged, this );
129     /* src/input/es-out.c:550 */
130     var_AddCallback( p_input, "audio-es", ChangeAudio, this );
131     /* src/input/es-out.c:551 */
132     var_AddCallback( p_input, "video-es", ChangeVideo, this );
133     /* src/input/input.c:1765 */
134     var_AddCallback( p_input, "rate", ItemRateChanged, this );
135     /* src/input/input.c:2003 */
136     var_AddCallback( p_input, "title", ItemTitleChanged, this );
137     /* src/input/input.c:734 for timers update*/
138     var_AddCallback( p_input, "intf-change", InterfaceChanged, this );
139 }
140
141 /* Delete the callbacks on Input. Self explanatory */
142 void InputManager::delCallbacks()
143 {
144     var_DelCallback( p_input, "audio-es", ChangeAudio, this );
145     var_DelCallback( p_input, "video-es", ChangeVideo, this );
146     var_DelCallback( p_input, "state", ItemStateChanged, this );
147     var_DelCallback( p_input, "rate", ItemRateChanged, this );
148     var_DelCallback( p_input, "title", ItemTitleChanged, this );
149     var_DelCallback( p_input, "intf-change", InterfaceChanged, this );
150 }
151
152 /* Convert the event from the callbacks in actions */
153 void InputManager::customEvent( QEvent *event )
154 {
155     int type = event->type();
156     if ( type != PositionUpdate_Type &&
157          type != ItemChanged_Type &&
158          type != ItemRateChanged_Type &&
159          type != ItemTitleChanged_Type &&
160          type != ItemStateChanged_Type )
161         return;
162
163     /* Delete the input */
164     if( !p_input || p_input->b_dead || p_input->b_die )
165     {
166          delInput();
167          return;
168     }
169
170     /* Actions */
171     switch( type )
172     {
173     case PositionUpdate_Type:
174         UpdatePosition();
175         break;
176     case ItemChanged_Type:
177         UpdateMeta();
178         UpdateTitle();
179         break;
180     case ItemRateChanged_Type:
181         UpdateRate();
182         break;
183     case ItemTitleChanged_Type:
184         UpdateTitle();
185         break;
186     case ItemStateChanged_Type:
187        UpdateStatus();
188        break;
189     }
190 }
191
192 void InputManager::UpdatePosition( void )
193 {
194      /* Update position */
195      int i_length, i_time; /* Int is enough, since we store seconds */
196      float f_pos;
197      i_length = var_GetTime(  p_input , "length" ) / 1000000;
198      i_time = var_GetTime(  p_input , "time") / 1000000;
199      f_pos = var_GetFloat(  p_input , "position" );
200      emit positionUpdated( f_pos, i_time, i_length );
201 }
202
203 void InputManager::UpdateTitle( void )
204 {
205      /* Update navigation status */
206      vlc_value_t val; val.i_int = 0;
207      var_Change( p_input, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
208      msg_Dbg( p_intf, "updateTitle called" );
209      if( val.i_int > 0 )
210      {
211          val.i_int = 0;
212          var_Change( p_input, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
213          emit navigationChanged( (val.i_int > 0) ? 1 : 2 );
214      }
215      else
216      {
217          emit navigationChanged( 0 );
218      }
219 }
220
221 void InputManager::UpdateStatus( void )
222 {
223      /* Update playing status */
224      vlc_value_t val; val.i_int = 0;
225      var_Get( p_input, "state", &val );
226      if( i_old_playing_status != val.i_int )
227      {
228          i_old_playing_status = val.i_int;
229          emit statusChanged( val.i_int );
230      }
231 }
232
233 void InputManager::UpdateRate( void )
234 {
235      /* Update Rate */
236      int i_new_rate = var_GetInteger( p_input, "rate");
237      if( i_new_rate != i_rate )
238      {
239          i_rate = i_new_rate;
240          /* Update rate */
241          emit rateChanged( i_rate );
242      }
243 }
244
245 void InputManager::UpdateMeta( void )
246 {
247     /* Update text, name and nowplaying */
248     QString text;
249
250     char *psz_name = input_item_GetTitle( input_GetItem( p_input ) );
251     if( EMPTY_STR( psz_name ) )
252     {
253         free( psz_name );
254         psz_name = input_item_GetName( input_GetItem( p_input ) );
255     }
256
257     char *psz_nowplaying =
258         input_item_GetNowPlaying( input_GetItem( p_input ) );
259     if( !EMPTY_STR( psz_nowplaying ) )
260     {
261         text.sprintf( "%s - %s", psz_nowplaying, psz_name );
262     }
263     else
264     {
265         char *psz_artist = input_item_GetArtist( input_GetItem( p_input ) );
266         if( !EMPTY_STR( psz_artist ) )
267         {
268             text.sprintf( "%s - %s", psz_artist, psz_name );
269         }
270         else
271         {
272             text.sprintf( "%s", psz_name );
273         }
274         free( psz_artist );
275     }
276     free( psz_name );
277     free( psz_nowplaying );
278
279     if( old_name != text )
280     {
281         emit nameChanged( text );
282         old_name=text;
283     }
284
285     /* Update Art meta */
286     QString url;
287     char *psz_art = input_item_GetArtURL( input_GetItem( p_input ) );
288     url.sprintf("%s", psz_art );
289     free( psz_art );
290     if( artUrl != url )
291     {
292         artUrl = url.replace( "file://",QString("" ) );
293         emit artChanged( artUrl );
294     }
295
296     /* Update ZVBI status */
297 #ifdef ZVBI_COMPILED
298     /* Update teletext status*/
299     emit teletextEnabled( true );/* FIXME */
300 #endif
301 }
302
303 /* User update of the slider */
304 void InputManager::sliderUpdate( float new_pos )
305 {
306     if( hasInput() )
307         var_SetFloat( p_input, "position", new_pos );
308 }
309
310 /* User togglePlayPause */
311 void InputManager::togglePlayPause()
312 {
313     vlc_value_t state;
314     var_Get( p_input, "state", &state );
315     state.i_int = ( state.i_int != PLAYING_S ) ? PLAYING_S : PAUSE_S;
316     var_Set( p_input, "state", state );
317     emit statusChanged( state.i_int );
318 }
319
320 void InputManager::sectionPrev()
321 {
322     if( hasInput() )
323     {
324         int i_type = var_Type( p_input, "next-chapter" );
325         vlc_value_t val; val.b_bool = VLC_TRUE;
326         var_Set( p_input, (i_type & VLC_VAR_TYPE) != 0 ?
327                             "prev-chapter":"prev-title", val );
328     }
329 }
330
331 void InputManager::sectionNext()
332 {
333     if( hasInput() )
334     {
335         int i_type = var_Type( p_input, "next-chapter" );
336         vlc_value_t val; val.b_bool = VLC_TRUE;
337         var_Set( p_input, (i_type & VLC_VAR_TYPE) != 0 ?
338                             "next-chapter":"next-title", val );
339     }
340 }
341
342 void InputManager::sectionMenu()
343 {
344     if( hasInput() )
345         var_SetInteger( p_input, "title 0", 2 );
346 }
347
348 #ifdef ZVBI_COMPILED
349 void InputManager::telexGotoPage( int page )
350 {
351     if( hasInput() )
352     {
353         vlc_object_t *p_vbi;
354         p_vbi = (vlc_object_t *) vlc_object_find_name( p_input,
355                     "zvbi", FIND_ANYWHERE );
356         if( p_vbi )
357         {
358             var_SetInteger( p_vbi, "vbi-page", page );
359             vlc_object_release( p_vbi );
360         }
361     }
362 }
363
364 void InputManager::telexToggle( bool b_enabled )
365 {
366     int i_page = 0;
367
368     if( b_enabled )
369         i_page = 100;
370     telexGotoPage( i_page );
371 }
372
373 void InputManager::telexSetTransparency( bool b_transp )
374 {
375     if( hasInput() )
376     {
377         vlc_object_t *p_vbi;
378         p_vbi = (vlc_object_t *) vlc_object_find_name( p_input,
379                     "zvbi", FIND_ANYWHERE );
380         if( p_vbi )
381         {
382             var_SetBool( p_input->p_libvlc, "vbi-opaque", b_transp );
383             vlc_object_release( p_vbi );
384         }
385     }
386 }
387 #endif
388
389 void InputManager::slower()
390 {
391     if( hasInput() )
392         var_SetVoid( p_input, "rate-slower" );
393 }
394
395 void InputManager::faster()
396 {
397     if( hasInput() )
398         var_SetVoid( p_input, "rate-faster" );
399 }
400
401 void InputManager::normalRate()
402 {
403     if( hasInput() )
404         var_SetInteger( p_input, "rate", INPUT_RATE_DEFAULT );
405 }
406
407 void InputManager::setRate( int new_rate )
408 {
409     if( hasInput() )
410         var_SetInteger( p_input, "rate", new_rate );
411 }
412
413 /**********************************************************************
414  * MainInputManager implementation. Wrap an input manager and
415  * take care of updating the main playlist input.
416  * Used in the main playlist Dialog
417  **********************************************************************/
418 MainInputManager * MainInputManager::instance = NULL;
419
420 MainInputManager::MainInputManager( intf_thread_t *_p_intf )
421                  : QObject(NULL), p_intf( _p_intf )
422 {
423     p_input = NULL;
424     im = new InputManager( this, p_intf );
425
426     var_AddCallback( THEPL, "item-change", PLItemChanged, this );
427     var_AddCallback( THEPL, "playlist-current", PLItemChanged, this );
428     var_AddCallback( THEPL, "activity", PLItemChanged, this );
429
430     var_AddCallback( THEPL, "playlist-current", ItemChanged, im );
431
432     var_AddCallback( p_intf->p_libvlc, "volume-change", VolumeChanged, this );
433
434     // No necessary, I think TODO REMOVE ME at the end
435     //var_AddCallback( THEPL, "intf-change", ItemChanged, im );
436
437     /* Warn our embedded IM about input changes */
438     CONNECT( this, inputChanged( input_thread_t * ),
439              im, setInput( input_thread_t * ) );
440 }
441
442 MainInputManager::~MainInputManager()
443 {
444     if( p_input )
445     {
446        emit inputChanged( NULL );
447     }
448
449     var_DelCallback( p_intf->p_libvlc, "volume-change", VolumeChanged, this );
450
451     var_DelCallback( THEPL, "playlist-current", PLItemChanged, this );
452     var_DelCallback( THEPL, "activity", PLItemChanged, this );
453     var_DelCallback( THEPL, "item-change", PLItemChanged, this );
454
455     var_DelCallback( THEPL, "playlist-current", ItemChanged, im );
456 }
457
458 void MainInputManager::customEvent( QEvent *event )
459 {
460     int type = event->type();
461     if ( type != ItemChanged_Type && type != VolumeChanged_Type )
462         return;
463
464     if( type == VolumeChanged_Type )
465     {
466         emit volumeChanged();
467         return;
468     }
469
470     /* Should be PLItemChanged Event */
471     if( VLC_OBJECT_INTF == p_intf->i_object_type )
472     {
473         vlc_mutex_lock( &p_intf->change_lock );
474         if( p_input && ( p_input->b_dead || p_input->b_die ) )
475         {
476             im->delInput();
477             emit inputChanged( NULL );
478             p_input = NULL;
479         }
480
481         if( !p_input )
482         {
483             QPL_LOCK;
484             p_input = THEPL->p_input;
485             if( p_input && !( p_input->b_die || p_input->b_dead) )
486             {
487                 emit inputChanged( p_input );
488             }
489             else
490                 p_input = NULL;
491             QPL_UNLOCK;
492         }
493         vlc_mutex_unlock( &p_intf->change_lock );
494     }
495     else
496     {
497         /* we are working as a dialogs provider */
498         playlist_t *p_playlist = (playlist_t *) vlc_object_find( p_intf,
499                                        VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
500         if( p_playlist )
501         {
502             p_input = p_playlist->p_input;
503             emit inputChanged( p_input );
504         }
505     }
506 }
507
508 /* Playlist Control functions */
509 void MainInputManager::stop()
510 {
511    playlist_Stop( THEPL );
512 }
513
514 void MainInputManager::next()
515 {
516    playlist_Next( THEPL );
517 }
518
519 void MainInputManager::prev()
520 {
521    playlist_Prev( THEPL );
522 }
523
524 void MainInputManager::togglePlayPause()
525 {
526     if( p_input == NULL )
527     {
528         playlist_Play( THEPL );
529         return;
530     }
531     getIM()->togglePlayPause();
532 }
533
534 /* Static callbacks */
535
536 /* IM */
537 static int InterfaceChanged( vlc_object_t *p_this, const char *psz_var,
538                            vlc_value_t oldval, vlc_value_t newval, void *param )
539 {
540     static int counter = 0;
541     InputManager *im = (InputManager*)param;
542
543     counter = counter++ % 4;
544     if(!counter)
545         return VLC_SUCCESS;
546     IMEvent *event = new IMEvent( PositionUpdate_Type, 0 );
547     QApplication::postEvent( im, static_cast<QEvent*>(event) );
548     return VLC_SUCCESS;
549 }
550
551 static int ItemStateChanged( vlc_object_t *p_this, const char *psz_var,
552                             vlc_value_t oldval, vlc_value_t newval, void *param )
553 {
554     InputManager *im = (InputManager*)param;
555
556     IMEvent *event = new IMEvent( ItemStateChanged_Type, 0 );
557     QApplication::postEvent( im, static_cast<QEvent*>(event) );
558     return VLC_SUCCESS;
559 }
560
561 static int ItemRateChanged( vlc_object_t *p_this, const char *psz_var,
562                             vlc_value_t oldval, vlc_value_t newval, void *param )
563 {
564     InputManager *im = (InputManager*)param;
565
566     IMEvent *event = new IMEvent( ItemRateChanged_Type, 0 );
567     QApplication::postEvent( im, static_cast<QEvent*>(event) );
568     return VLC_SUCCESS;
569 }
570
571 static int ItemTitleChanged( vlc_object_t *p_this, const char *psz_var,
572                             vlc_value_t oldval, vlc_value_t newval, void *param )
573 {
574     InputManager *im = (InputManager*)param;
575
576     IMEvent *event = new IMEvent( ItemTitleChanged_Type, 0 );
577     QApplication::postEvent( im, static_cast<QEvent*>(event) );
578     return VLC_SUCCESS;
579 }
580
581 static int ItemChanged( vlc_object_t *p_this, const char *psz_var,
582                         vlc_value_t oldval, vlc_value_t newval, void *param )
583 {
584     InputManager *im = (InputManager*)param;
585
586     IMEvent *event = new IMEvent( ItemChanged_Type, newval.i_int );
587     QApplication::postEvent( im, static_cast<QEvent*>(event) );
588     return VLC_SUCCESS;
589 }
590
591
592 static int ChangeAudio( vlc_object_t *p_this, const char *var, vlc_value_t o,
593                         vlc_value_t n, void *param )
594 {
595     InputManager *im = (InputManager*)param;
596     im->b_has_audio = true;
597     return VLC_SUCCESS;
598 }
599
600 static int ChangeVideo( vlc_object_t *p_this, const char *var, vlc_value_t o,
601                         vlc_value_t n, void *param )
602 {
603     InputManager *im = (InputManager*)param;
604     im->b_has_video = true;
605     return VLC_SUCCESS;
606 }
607
608 /* MIM */
609 static int PLItemChanged( vlc_object_t *p_this, const char *psz_var,
610                         vlc_value_t oldval, vlc_value_t newval, void *param )
611 {
612     MainInputManager *mim = (MainInputManager*)param;
613
614     IMEvent *event = new IMEvent( ItemChanged_Type, newval.i_int );
615     QApplication::postEvent( mim, static_cast<QEvent*>(event) );
616     return VLC_SUCCESS;
617 }
618
619 static int VolumeChanged( vlc_object_t *p_this, const char *psz_var,
620                         vlc_value_t oldval, vlc_value_t newval, void *param )
621 {
622     MainInputManager *mim = (MainInputManager*)param;
623
624     IMEvent *event = new IMEvent( VolumeChanged_Type, newval.i_int );
625     QApplication::postEvent( mim, static_cast<QEvent*>(event) );
626     return VLC_SUCCESS;
627 }
628