input_manager.cpp 27.5 KB
Newer Older
1 2 3
/*****************************************************************************
 * input_manager.cpp : Manage an input and interact with its GUI elements
 ****************************************************************************
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 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/
25

26 27 28
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
29 30

#include "input_manager.hpp"
31
#include <vlc_keys.h>
32 33

#include <QApplication>
34

35 36
#include <assert.h>

37 38
static int ItemChanged( vlc_object_t *, const char *,
                        vlc_value_t, vlc_value_t, void * );
39
static int PLItemChanged( vlc_object_t *, const char *,
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
40
                        vlc_value_t, vlc_value_t, void * );
41 42
static int VolumeChanged( vlc_object_t *, const char *,
                        vlc_value_t, vlc_value_t, void * );
43

44 45
static int InputEvent( vlc_object_t *, const char *,
                       vlc_value_t, vlc_value_t, void * );
Laurent Aimar's avatar
Laurent Aimar committed
46 47
static int VbiEvent( vlc_object_t *, const char *,
                     vlc_value_t, vlc_value_t, void * );
48 49


50 51
/**********************************************************************
 * InputManager implementation
52 53 54
 **********************************************************************
 * The Input Manager can be the main one around the playlist
 * But can also be used for VLM dialog or similar
55 56
 **********************************************************************/

57 58 59
InputManager::InputManager( QObject *parent, intf_thread_t *_p_intf) :
                           QObject( parent ), p_intf( _p_intf )
{
60
    i_old_playing_status = END_S;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
61
    oldName      = "";
62 63 64 65
    artUrl       = "";
    p_input      = NULL;
    i_rate       = 0;
    i_input_id   = 0;
66
    b_video      = false;
67 68
    timeA        = 0;
    timeB        = 0;
69
    f_cache      = -1.; /* impossible initial value, different from all */
70 71 72 73
}

InputManager::~InputManager()
{
74
    delInput();
75 76
}

77 78
/* Define the Input used.
   Add the callbacks on input
79
   p_input is held once here */
80 81
void InputManager::setInput( input_thread_t *_p_input )
{
82
    delInput();
83
    p_input = _p_input;
84
    if( p_input && !( p_input->b_dead || !vlc_object_alive (p_input) ) )
85
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
86
        msg_Dbg( p_intf, "IM: Setting an input" );
87
        vlc_object_hold( p_input );
88
        emit statusChanged( PLAYING_S );
89
        UpdateName();
90
        UpdateArt();
91
        UpdateTeletext();
92
        UpdateNavigation();
93
        UpdateVout();
94
        addCallbacks();
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
95 96 97 98
        i_input_id = input_GetItem( p_input )->i_id;
    }
    else
    {
99 100
        p_input = NULL;
        i_input_id = 0;
101
        emit rateChanged( INPUT_RATE_DEFAULT );
102 103
    }
}
104

105 106 107
/* delete Input if it ever existed.
   Delete the callbacls on input
   p_input is released once here */
108 109
void InputManager::delInput()
{
110
    if( !p_input ) return;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
111
    msg_Dbg( p_intf, "IM: Deleting the input" );
112 113 114 115 116 117 118 119 120 121

    delCallbacks();
    i_old_playing_status = END_S;
    i_input_id           = 0;
    oldName              = "";
    artUrl               = "";
    b_video              = false;
    timeA                = 0;
    timeB                = 0;

122 123 124
    vlc_object_release( p_input );
    p_input = NULL;

125 126 127 128 129 130 131 132
    emit positionUpdated( -1.0, 0 ,0 );
    emit rateChanged( INPUT_RATE_DEFAULT ); /* TODO: Do we want this ? */
    emit nameChanged( "" );
    emit chapterChanged( 0 );
    emit titleChanged( 0 );
    emit statusChanged( END_S );

    emit teletextPossible( false );
133
    emit AtoBchanged( false, false );
134
    emit voutChanged( false );
135
    emit voutListChanged( NULL, 0 );
136

137 138 139
    /* Reset all InfoPanels but stats */
    emit artChanged( NULL );
    emit infoChanged( NULL );
140
    emit metaChanged( (input_item_t *)NULL );
141

142
    emit encryptionChanged( false );
143 144
}

145
/* Convert the event from the callbacks in actions */
146 147
void InputManager::customEvent( QEvent *event )
{
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
148
    int i_type = event->type();
149
    IMEvent *ple = static_cast<IMEvent *>(event);
150

151
    if( !hasInput() )
152
        return;
153

154
#ifndef NDEBUG
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
155
    if( i_type != PositionUpdate_Type &&
156 157
        i_type != StatisticsUpdate_Type &&
        i_type != ItemChanged_Type )
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
158
        msg_Dbg( p_intf, "New Event: type %i", i_type );
159
#endif
160

161
    /* Actions */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
162
    switch( i_type )
163
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
164
    case PositionUpdate_Type:
165
        UpdatePosition();
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
166
        break;
167 168 169
    case StatisticsUpdate_Type:
        UpdateStats();
        break;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
170
    case ItemChanged_Type:
171 172 173 174 175 176
        /* Ignore ItemChanged_Type event that does not apply to our input */
        if( i_input_id == ple->i_id )
        {
            UpdateStatus();
            // UpdateName();
            UpdateArt();
177
            /* Update duration of file */
178
        }
179
        UpdateMeta( ple->i_id );
180 181 182 183 184 185 186 187 188 189
        break;
    case ItemStateChanged_Type:
        // TODO: Fusion with above state
        UpdateStatus();
        // UpdateName();
        // UpdateNavigation(); This shouldn't be useful now
        // UpdateTeletext(); Same
        break;
    case NameChanged_Type:
        UpdateName();
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
190
        break;
191
    case MetaChanged_Type:
192
        UpdateMeta();
193
        UpdateName(); /* Needed for NowPlaying */
194
        UpdateArt(); /* Art is part of meta in the core */
195
        break;
196
    case InfoChanged_Type:
197
        UpdateInfo();
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
198 199
        break;
    case ItemTitleChanged_Type:
200
        UpdateNavigation();
201
        UpdateName(); /* Display the name of the Chapter, if exists */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
202
        break;
203 204 205
    case ItemRateChanged_Type:
        UpdateRate();
        break;
206
    case ItemEsChanged_Type:
Laurent Aimar's avatar
Laurent Aimar committed
207 208
        UpdateTeletext();
        // We don't do anything ES related. Why ?
209
        break;
210 211 212
    case ItemTeletextChanged_Type:
        UpdateTeletext();
        break;
213 214 215
    case InterfaceVoutUpdate_Type:
        UpdateVout();
        break;
216 217 218
    case SynchroChanged_Type:
        emit synchroChanged();
        break;
219 220 221
    case CachingEvent_Type:
        UpdateCaching();
        break;
222 223 224
    case BookmarksChanged_Type:
        emit bookmarksChanged();
        break;
225 226 227
    case InterfaceAoutUpdate_Type:
        UpdateAout();
        break;
228 229 230
    case RecordingEvent_Type:
        UpdateRecord();
        break;
231 232 233
    case ProgramChanged_Type:
        UpdateProgramEvent();
        break;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
234 235
    default:
        msg_Warn( p_intf, "This shouldn't happen: %i", i_type );
236
        assert(0);
237
    }
238
}
239

240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
/* Add the callbacks on Input. Self explanatory */
inline void InputManager::addCallbacks()
{
    var_AddCallback( p_input, "intf-event", InputEvent, this );
}

/* Delete the callbacks on Input. Self explanatory */
inline void InputManager::delCallbacks()
{
    var_DelCallback( p_input, "intf-event", InputEvent, this );
}

/* Static callbacks for IM */
static int ItemChanged( vlc_object_t *p_this, const char *psz_var,
                        vlc_value_t oldval, vlc_value_t newval, void *param )
{
    InputManager *im = (InputManager*)param;

    IMEvent *event = new IMEvent( ItemChanged_Type, newval.i_int );
259
    QApplication::postEvent( im, event );
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
    return VLC_SUCCESS;
}

static int InputEvent( vlc_object_t *p_this, const char *,
                       vlc_value_t, vlc_value_t newval, void *param )
{
    InputManager *im = (InputManager*)param;
    IMEvent *event;

    switch( newval.i_int )
    {
    case INPUT_EVENT_STATE:
        event = new IMEvent( ItemStateChanged_Type, 0 );
        break;
    case INPUT_EVENT_RATE:
        event = new IMEvent( ItemRateChanged_Type, 0 );
        break;
    case INPUT_EVENT_TIMES:
        event = new IMEvent( PositionUpdate_Type, 0 );
        break;

    case INPUT_EVENT_TITLE:
    case INPUT_EVENT_CHAPTER:
        event = new IMEvent( ItemTitleChanged_Type, 0 );
        break;

    case INPUT_EVENT_ES:
        event = new IMEvent( ItemEsChanged_Type, 0 );
        break;
    case INPUT_EVENT_TELETEXT:
        event = new IMEvent( ItemTeletextChanged_Type, 0 );
        break;

293 294 295 296
    case INPUT_EVENT_STATISTICS:
        event = new IMEvent( StatisticsUpdate_Type, 0 );
        break;

297 298 299
    case INPUT_EVENT_VOUT:
        event = new IMEvent( InterfaceVoutUpdate_Type, 0 );
        break;
300 301
    case INPUT_EVENT_AOUT:
        event = new IMEvent( InterfaceAoutUpdate_Type, 0 );
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
        break;

    case INPUT_EVENT_ITEM_META: /* Codec MetaData + Art */
        event = new IMEvent( MetaChanged_Type, 0 );
        break;
    case INPUT_EVENT_ITEM_INFO: /* Codec Info */
        event = new IMEvent( InfoChanged_Type, 0 );
        break;
    case INPUT_EVENT_ITEM_NAME:
        event = new IMEvent( NameChanged_Type, 0 );
        break;

    case INPUT_EVENT_AUDIO_DELAY:
    case INPUT_EVENT_SUBTITLE_DELAY:
        event = new IMEvent( SynchroChanged_Type, 0 );
        break;

    case INPUT_EVENT_CACHE:
        event = new IMEvent( CachingEvent_Type, 0 );
        break;

    case INPUT_EVENT_BOOKMARK:
        event = new IMEvent( BookmarksChanged_Type, 0 );
        break;

    case INPUT_EVENT_RECORD:
328 329
        event = new IMEvent( RecordingEvent_Type, 0 );
        break;
330 331 332

    case INPUT_EVENT_PROGRAM:
        /* This is for PID changes */
333 334 335
        event = new IMEvent( ProgramChanged_Type, 0 );
        break;

336 337 338 339 340 341 342 343 344 345
    case INPUT_EVENT_SIGNAL:
        /* This is for capture-card signals */
        /* event = new IMEvent( SignalChanged_Type, 0 );
        break; */
    default:
        event = NULL;
        break;
    }

    if( event )
346
        QApplication::postEvent( im, event );
347 348
    return VLC_SUCCESS;
}
349

Laurent Aimar's avatar
Laurent Aimar committed
350 351 352 353 354 355
static int VbiEvent( vlc_object_t *, const char *,
                     vlc_value_t, vlc_value_t, void *param )
{
    InputManager *im = (InputManager*)param;
    IMEvent *event = new IMEvent( ItemTeletextChanged_Type, 0 );

356
    QApplication::postEvent( im, event );
Laurent Aimar's avatar
Laurent Aimar committed
357 358 359
    return VLC_SUCCESS;
}

360
void InputManager::UpdatePosition()
361
{
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
362 363 364 365 366 367 368
    /* Update position */
    int i_length, i_time; /* Int is enough, since we store seconds */
    float f_pos;
    i_length = var_GetTime(  p_input , "length" ) / 1000000;
    i_time = var_GetTime(  p_input , "time") / 1000000;
    f_pos = var_GetFloat(  p_input , "position" );
    emit positionUpdated( f_pos, i_time, i_length );
369 370
}

371
void InputManager::UpdateNavigation()
372
{
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
373 374
    /* Update navigation status */
    vlc_value_t val; val.i_int = 0;
375

376 377
    if( hasInput() )
        var_Change( p_input, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
378

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
379 380
    if( val.i_int > 0 )
    {
381
        emit titleChanged( true );
382
        msg_Dbg( p_intf, "Title %i", val.i_int );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
383
        /* p_input != NULL since val.i_int != 0 */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
384 385
        val.i_int = 0;
        var_Change( p_input, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
386
        emit chapterChanged( (val.i_int > 0) );
387
        msg_Dbg( p_intf, "Chapter: %i", val.i_int );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
388 389
    }
    else
390
        emit titleChanged( false );
391 392
}

393
void InputManager::UpdateStatus()
394
{
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
395 396 397 398 399 400 401 402
    /* Update playing status */
    vlc_value_t val; val.i_int = 0;
    var_Get( p_input, "state", &val );
    if( i_old_playing_status != val.i_int )
    {
        i_old_playing_status = val.i_int;
        emit statusChanged( val.i_int );
    }
403 404
}

405
void InputManager::UpdateRate()
406
{
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
407 408 409 410 411 412 413 414
    /* Update Rate */
    int i_new_rate = var_GetInteger( p_input, "rate");
    if( i_new_rate != i_rate )
    {
        i_rate = i_new_rate;
        /* Update rate */
        emit rateChanged( i_rate );
    }
415 416
}

417
void InputManager::UpdateName()
418
{
419 420
    /* Update text, name and nowplaying */
    QString text;
421

422
    /* Try to get the Title, then the Name */
423 424 425 426 427 428 429
    char *psz_name = input_item_GetTitle( input_GetItem( p_input ) );
    if( EMPTY_STR( psz_name ) )
    {
        free( psz_name );
        psz_name = input_item_GetName( input_GetItem( p_input ) );
    }

430
    /* Try to get the nowplaying */
431 432 433 434 435 436
    char *psz_nowplaying =
        input_item_GetNowPlaying( input_GetItem( p_input ) );
    if( !EMPTY_STR( psz_nowplaying ) )
    {
        text.sprintf( "%s - %s", psz_nowplaying, psz_name );
    }
437
    else  /* Do it ourself */
438 439
    {
        char *psz_artist = input_item_GetArtist( input_GetItem( p_input ) );
440

441 442
        if( !EMPTY_STR( psz_artist ) )
            text.sprintf( "%s - %s", psz_artist, psz_name );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
443 444
        else
            text.sprintf( "%s", psz_name );
445

446
        free( psz_artist );
447
    }
448
    /* Free everything */
449 450 451
    free( psz_name );
    free( psz_nowplaying );

452 453 454 455 456 457 458 459 460
    /* If we have Nothing */
    if( text.isEmpty() )
    {
        psz_name = input_item_GetURI( input_GetItem( p_input ) );
        text.sprintf( "%s", psz_name );
        text = text.remove( 0, text.lastIndexOf( DIR_SEP ) + 1 );
        free( psz_name );
    }

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
461
    if( oldName != text )
462 463
    {
        emit nameChanged( text );
464
        oldName = text;
465
    }
466
}
467

468
bool InputManager::hasAudio()
469
{
470 471 472 473 474 475 476 477 478
    if( hasInput() )
    {
        vlc_value_t val;
        var_Change( p_input, "audio-es", VLC_VAR_CHOICESCOUNT, &val, NULL );
        return val.i_int > 0;
    }
    return false;
}

479
void InputManager::UpdateTeletext()
480 481
{
    if( hasInput() )
Laurent Aimar's avatar
Laurent Aimar committed
482 483 484 485 486 487 488 489 490 491 492 493
    {
        const bool b_enabled = var_CountChoices( p_input, "teletext-es" ) > 0;
        const int i_teletext_es = var_GetInteger( p_input, "teletext-es" );

        /* Teletext is possible. Show the buttons */
        emit teletextPossible( b_enabled );

        /* If Teletext is selected */
        if( b_enabled && i_teletext_es >= 0 )
        {
            /* Then, find the current page */
            int i_page = 100;
Laurent Aimar's avatar
Laurent Aimar committed
494
            bool b_transparent = false;
495

Laurent Aimar's avatar
Laurent Aimar committed
496
            vlc_object_t *p_vbi = (vlc_object_t *)
497
                vlc_object_find_name( p_input, "zvbi", FIND_CHILD );
498

Laurent Aimar's avatar
Laurent Aimar committed
499 500
            if( p_vbi )
            {
Laurent Aimar's avatar
Laurent Aimar committed
501 502 503 504 505 506 507
                /* We deleted it (if not here, it does not harm), because
                 * var_AddCallback will silently add a duplicated one */
                var_DelCallback( p_vbi, "vbi-page", VbiEvent, this );
                /* This callback is not remove explicitly, but interfaces
                 * are guaranted to outlive input */
                var_AddCallback( p_vbi, "vbi-page", VbiEvent, this );

Laurent Aimar's avatar
Laurent Aimar committed
508
                i_page = var_GetInteger( p_vbi, "vbi-page" );
Laurent Aimar's avatar
Laurent Aimar committed
509
                b_transparent = !var_GetBool( p_vbi, "vbi-opaque" );
Laurent Aimar's avatar
Laurent Aimar committed
510 511
                vlc_object_release( p_vbi );
            }
512
            emit newTelexPageSet( i_page );
Laurent Aimar's avatar
Laurent Aimar committed
513 514
            emit teletextTransparencyActivated( b_transparent );

Laurent Aimar's avatar
Laurent Aimar committed
515 516 517
        }
        emit teletextActivated( b_enabled && i_teletext_es >= 0 );
    }
518
    else
Laurent Aimar's avatar
Laurent Aimar committed
519 520 521 522
    {
        emit teletextActivated( false );
        emit teletextPossible( false );
    }
523 524
}

525 526 527 528
void InputManager::UpdateVout()
{
    if( hasInput() )
    {
529 530 531 532 533 534 535 536 537 538 539 540 541
        /* Get current vout lists from input */
        int i_vout;
        vout_thread_t **pp_vout;
        if( input_Control( p_input, INPUT_GET_VOUTS, &pp_vout, &i_vout ) )
        {
            i_vout = 0;
            pp_vout = NULL;
        }

        /* */
        emit voutListChanged( pp_vout, i_vout );

        /* */
542
        bool b_old_video = b_video;
543
        b_video = i_vout > 0;
544 545
        if( !!b_old_video != !!b_video )
            emit voutChanged( b_video );
546 547 548 549 550 551 552 553 554 555 556 557

        /* Release the vout list */
        for( int i = 0; i < i_vout; i++ )
            vlc_object_release( (vlc_object_t*)pp_vout[i] );
        free( pp_vout );
    }
}
void InputManager::UpdateAout()
{
    if( hasInput() )
    {
        /* TODO */
558 559
    }
}
560 561
void InputManager::UpdateCaching()
{
562 563 564
    if(!hasInput()) return;

    float f_newCache = var_GetFloat ( p_input, "cache" );
565 566
    if( f_newCache != f_cache )
    {
567
        f_cache = f_newCache;
568 569 570 571 572
        /* Update rate */
        emit cachingChanged( f_cache );
    }
}

573
void InputManager::requestArtUpdate()
574
{
575 576 577 578 579 580
    if( hasInput() )
    {
        playlist_t *p_playlist = pl_Hold( p_intf );
        playlist_AskForArtEnqueue( p_playlist, input_GetItem( p_input ), pl_Unlocked );
        pl_Release( p_intf );
    }
581 582 583 584 585 586
    else
    {
        /* No input will signal the cover art to update,
         * let's do it ourself */
        UpdateArt();
    }
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
}

void InputManager::UpdateArt()
{
    QString url;

    if( hasInput() )
    {
        char *psz_art = input_item_GetArtURL( input_GetItem( p_input ) );
        url = psz_art;
        free( psz_art );
    }
    url = url.replace( "file://", QString("" ) );
    /* Taglib seems to define a attachment://, It won't work yet */
    url = url.replace( "attachment://", QString("" ) );
602
    /* Update Art meta */
603
    emit artChanged( url );
604 605
}

606 607 608 609 610
inline void InputManager::UpdateStats()
{
    emit statisticsUpdated( input_GetItem( p_input ) );
}

611 612 613 614 615
inline void InputManager::UpdateMeta( int id )
{
    emit metaChanged( id );
}

616 617 618 619 620 621 622 623 624 625
inline void InputManager::UpdateMeta()
{
    emit metaChanged( input_GetItem( p_input ) );
}

inline void InputManager::UpdateInfo()
{
    emit infoChanged( input_GetItem( p_input ) );
}

626 627 628 629 630 631 632 633
void InputManager::UpdateRecord()
{
    if( hasInput() )
    {
        emit recordingStateChanged( var_GetBool( p_input, "record" ) );
    }
}

634 635 636 637 638 639 640 641 642
void InputManager::UpdateProgramEvent()
{
    if( hasInput() )
    {
        bool b_scrambled = var_GetBool( p_input, "program-scrambled" );
        emit encryptionChanged( b_scrambled );
    }
}

643
/* User update of the slider */
Clément Stenac's avatar
Clément Stenac committed
644 645
void InputManager::sliderUpdate( float new_pos )
{
646 647
    if( hasInput() )
        var_SetFloat( p_input, "position", new_pos );
Clément Stenac's avatar
Clément Stenac committed
648
}
649

650
/* User togglePlayPause */
651 652
void InputManager::togglePlayPause()
{
653 654
    if( hasInput() )
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
655 656 657 658
        int state = var_GetInteger( p_input, "state" );
        state = ( state != PLAYING_S ) ? PLAYING_S : PAUSE_S;
        var_SetInteger( p_input, "state", state );
        emit statusChanged( state );
659
    }
660 661
}

662 663 664 665
void InputManager::sectionPrev()
{
    if( hasInput() )
    {
666
        int i_type = var_Type( p_input, "next-chapter" );
667 668
        var_SetVoid( p_input, (i_type & VLC_VAR_TYPE) != 0 ?
                            "prev-chapter":"prev-title" );
669 670 671 672 673 674 675
    }
}

void InputManager::sectionNext()
{
    if( hasInput() )
    {
676
        int i_type = var_Type( p_input, "next-chapter" );
677 678
        var_SetVoid( p_input, (i_type & VLC_VAR_TYPE) != 0 ?
                            "next-chapter":"next-title" );
679 680 681 682 683 684
    }
}

void InputManager::sectionMenu()
{
    if( hasInput() )
685
    {
686 687 688 689 690 691
        vlc_value_t val, text;

        if( var_Change( p_input, "title  0", VLC_VAR_GETLIST, &val, &text ) < 0 )
            return;

        /* XXX is it "Root" or "Title" we want here ?" (set 0 by default) */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
692
        int root = 0;
693 694 695
        for( int i = 0; i < val.p_list->i_count; i++ )
        {
            if( !strcmp( text.p_list->p_values[i].psz_string, "Title" ) )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
696
                root = i;
697 698 699
        }
        var_Change( p_input, "title  0", VLC_VAR_FREELIST, &val, &text );

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
700
        var_SetInteger( p_input, "title  0", root );
701
    }
702 703
}

704 705 706 707 708 709
/*
 *  Teletext Functions
 */

/* Set a new Teletext Page */
void InputManager::telexSetPage( int page )
710
{
711
    if( hasInput() )
712
    {
713 714
        const int i_teletext_es = var_GetInteger( p_input, "teletext-es" );

Laurent Aimar's avatar
Laurent Aimar committed
715
        if( i_teletext_es >= 0 )
716
        {
717
            vlc_object_t *p_vbi = (vlc_object_t *) vlc_object_find_name( p_input,
718
                        "zvbi", FIND_CHILD );
719 720 721 722
            if( p_vbi )
            {
                var_SetInteger( p_vbi, "vbi-page", page );
                vlc_object_release( p_vbi );
723
                emit newTelexPageSet( page );
724
            }
725 726
        }
    }
727 728
}

729 730 731 732 733 734
/* Set the transparency on teletext */
void InputManager::telexSetTransparency( bool b_transparentTelextext )
{
    if( hasInput() )
    {
        vlc_object_t *p_vbi = (vlc_object_t *) vlc_object_find_name( p_input,
735
                    "zvbi", FIND_CHILD );
736 737
        if( p_vbi )
        {
Laurent Aimar's avatar
Laurent Aimar committed
738
            var_SetBool( p_vbi, "vbi-opaque", !b_transparentTelextext );
739 740 741 742 743 744 745
            vlc_object_release( p_vbi );
            emit teletextTransparencyActivated( b_transparentTelextext );
        }
    }
}

void InputManager::activateTeletext( bool b_enable )
Lukas Durfina's avatar
Lukas Durfina committed
746
{
Laurent Aimar's avatar
Laurent Aimar committed
747
    vlc_value_t list;
748 749
    vlc_value_t text;
    if( hasInput() && !var_Change( p_input, "teletext-es", VLC_VAR_GETLIST, &list, &text ) )
750
    {
Laurent Aimar's avatar
Laurent Aimar committed
751
        if( list.p_list->i_count > 0 )
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766
        {
            /* Prefer the page 100 if it is present */
            int i;
            for( i = 0; i < text.p_list->i_count; i++ )
            {
                /* The description is the page number as a string */
                const char *psz_page = text.p_list->p_values[i].psz_string;
                if( psz_page && !strcmp( psz_page, "100" ) )
                    break;
            }
            if( i >= list.p_list->i_count )
                i = 0;
            var_SetInteger( p_input, "spu-es", b_enable ? list.p_list->p_values[i].i_int : -1 );
        }
        var_Change( p_input, "teletext-es", VLC_VAR_FREELIST, &list, &text );
767
    }
768 769
}

770 771 772 773 774 775 776 777 778
void InputManager::reverse()
{
    if( hasInput() )
    {
        int i_rate = var_GetInteger( p_input, "rate" );
        var_SetInteger( p_input, "rate", -i_rate );
    }
}

Clément Stenac's avatar
Clément Stenac committed
779 780 781 782 783 784 785 786 787 788 789 790
void InputManager::slower()
{
    if( hasInput() )
        var_SetVoid( p_input, "rate-slower" );
}

void InputManager::faster()
{
    if( hasInput() )
        var_SetVoid( p_input, "rate-faster" );
}

791 792 793 794 795 796 797 798 799 800
void InputManager::littlefaster()
{
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_RATE_FASTER_FINE );
}

void InputManager::littleslower()
{
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_RATE_SLOWER_FINE );
}

Clément Stenac's avatar
Clément Stenac committed
801 802 803 804 805 806
void InputManager::normalRate()
{
    if( hasInput() )
        var_SetInteger( p_input, "rate", INPUT_RATE_DEFAULT );
}

807 808 809 810 811 812
void InputManager::setRate( int new_rate )
{
    if( hasInput() )
        var_SetInteger( p_input, "rate", new_rate );
}

813 814 815 816 817
void InputManager::jumpFwd()
{
    int i_interval = config_GetInt( p_input, "short-jump-size" );
    if( i_interval > 0 )
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
818 819
        mtime_t val = (mtime_t)(i_interval) * 1000000L;
        var_SetTime( p_input, "time-offset", val );
820 821 822 823 824 825 826 827
    }
}

void InputManager::jumpBwd()
{
    int i_interval = config_GetInt( p_input, "short-jump-size" );
    if( i_interval > 0 )
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
828 829
        mtime_t val = -1 *(mtime_t)(i_interval) * 1000000L;
        var_SetTime( p_input, "time-offset", val );
830 831 832
    }
}

833 834 835 836 837 838 839 840 841 842
void InputManager::setAtoB()
{
    if( !timeA )
    {
        timeA = var_GetTime( THEMIM->getInput(), "time"  );
    }
    else if( !timeB )
    {
        timeB = var_GetTime( THEMIM->getInput(), "time"  );
        var_SetTime( THEMIM->getInput(), "time" , timeA );
843 844
        CONNECT( this, positionUpdated( float, int, int ),
                 this, AtoBLoop( float, int, int ) );
845 846 847 848 849
    }
    else
    {
        timeA = 0;
        timeB = 0;
850 851
        disconnect( this, SIGNAL( positionUpdated( float, int, int ) ),
                    this, SLOT( AtoBLoop( float, int, int ) ) );
852 853 854 855 856
    }
    emit AtoBchanged( (timeA != 0 ), (timeB != 0 ) );
}

/* Function called regularly when in an AtoB loop */
857
void InputManager::AtoBLoop( float, int i_time, int )
858 859 860 861 862 863 864 865 866
{
    if( timeB )
    {
        if( ( i_time >= (int)( timeB/1000000 ) )
            || ( i_time < (int)( timeA/1000000 ) ) )
            var_SetTime( THEMIM->getInput(), "time" , timeA );
    }
}

867 868
/**********************************************************************
 * MainInputManager implementation. Wrap an input manager and
869 870
 * take care of updating the main playlist input.
 * Used in the main playlist Dialog
871 872 873
 **********************************************************************/
MainInputManager * MainInputManager::instance = NULL;

874 875
MainInputManager::MainInputManager( intf_thread_t *_p_intf )
                 : QObject(NULL), p_intf( _p_intf )
876 877 878
{
    p_input = NULL;
    im = new InputManager( this, p_intf );
879

880
    var_AddCallback( THEPL, "item-change", ItemChanged, im );
881
    var_AddCallback( THEPL, "item-current", PLItemChanged, this );
882
    var_AddCallback( THEPL, "activity", PLItemChanged, this );
883

884
    var_AddCallback( p_intf->p_libvlc, "volume-change", VolumeChanged, this );
885

886
    /* Warn our embedded IM about input changes */
887
    CONNECT( this, inputChanged( input_thread_t * ),
888
             im, setInput( input_thread_t * ) );
889 890 891

    /* emit check if playlist has allready started playing */
    vlc_value_t val;
892
    var_Change( THEPL, "item-current", VLC_VAR_CHOICESCOUNT, &val, NULL );
893

894
    IMEvent *event = new IMEvent( ItemChanged_Type, val.i_int);
895
    customEvent( event );
896
    delete event;
897 898
}

Clément Stenac's avatar
Clément Stenac committed
899 900
MainInputManager::~MainInputManager()
{
901 902
    if( p_input )
    {
903
       emit inputChanged( NULL );
904 905
       var_DelCallback( p_input, "state", PLItemChanged, this );
       vlc_object_release( p_input );
906
    }
907

908
    var_DelCallback( p_intf->p_libvlc, "volume-change", VolumeChanged, this );
909 910

    var_DelCallback( THEPL, "activity", PLItemChanged, this );
911
    var_DelCallback( THEPL, "item-change", ItemChanged, im );
912

913
    var_DelCallback( THEPL, "item-current", PLItemChanged, this );
Clément Stenac's avatar
Clément Stenac committed
914 915
}

916 917
vout_thread_t* MainInputManager::getVout()
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
918
    return p_input ? input_GetVout( p_input ) : NULL;
919 920 921 922
}

aout_instance_t * MainInputManager::getAout()
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
923
    return p_input ? input_GetAout( p_input ) : NULL;
924 925
}

926
void MainInputManager::customEvent( QEvent *event )
927
{
928
    int type = event->type();
929 930 931
    if ( type != ItemChanged_Type && type != VolumeChanged_Type )
        return;

932
    // msg_Dbg( p_intf, "New MainIM Event of type: %i", type );
933 934 935
    if( type == VolumeChanged_Type )
    {
        emit volumeChanged();
936
        return;
937
    }
938

939
    /* Should be PLItemChanged Event */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
940
    if( !p_intf->p_sys->b_isDialogProvider )
941
    {
942
        if( p_input && ( p_input->b_dead || !vlc_object_alive (p_input) ) )
943
        {
944
            emit inputChanged( p_input );
945 946
            var_DelCallback( p_input, "state", PLItemChanged, this );
            vlc_object_release( p_input );
947
            p_input = NULL;
948
            return;
949
        }
950

951 952
        if( !p_input )
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
953 954
            p_input = playlist_CurrentInput(THEPL);
            if( p_input )
955
            {
956
                var_AddCallback( p_input, "state", PLItemChanged, this );
957 958 959 960
                emit inputChanged( p_input );
            }
        }
    }
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
961 962
    else
    {
963 964 965 966 967 968
        /* remove previous stored p_input */
        if( p_input )
        {
            vlc_object_release( p_input );
            p_input = NULL;
        }
969
        /* we are working as a dialogs provider */
Antoine Cellerier's avatar
Antoine Cellerier committed
970
        playlist_t *p_playlist = pl_Hold( p_intf );
971
        p_input = playlist_CurrentInput( p_playlist );
972 973 974 975
        if( p_input )
        {
            emit inputChanged( p_input );
        }
976
        pl_Release( p_intf );
977 978
    }
}
979

980
/* Playlist Control functions */
981 982 983 984 985 986 987 988 989 990 991 992 993 994 995
void MainInputManager::stop()
{
   playlist_Stop( THEPL );
}

void MainInputManager::next()
{
   playlist_Next( THEPL );
}

void MainInputManager::prev()
{
   playlist_Prev( THEPL );
}

996 997
void MainInputManager::togglePlayPause()
{
998 999
    /* No input, play */
    if( !p_input )
1000
        playlist_Play( THEPL );
1001 1002
    else
        getIM()->togglePlayPause();
1003
}
1004

1005 1006 1007 1008 1009
void MainInputManager::activatePlayQuit( bool b_exit )
{
    var_SetBool( THEPL, "play-and-exit", b_exit );
}

1010
/* Static callbacks for MIM */
1011
static int PLItemChanged( vlc_object_t *p_this, const char *psz_var,
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
1012 1013
                        vlc_value_t oldval, vlc_value_t newval, void *param )
{
1014
    MainInputManager *mim = (MainInputManager*)param;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
1015 1016

    IMEvent *event = new IMEvent( ItemChanged_Type, newval.i_int );
1017
    QApplication::postEvent( mim, event );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
1018 1019 1020 1021 1022 1023
    return VLC_SUCCESS;
}

static int VolumeChanged( vlc_object_t *p_this, const char *psz_var,
                        vlc_value_t oldval, vlc_value_t newval, void *param )
{
1024
    MainInputManager *mim = (MainInputManager*)param;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
1025 1026

    IMEvent *event = new IMEvent( VolumeChanged_Type, newval.i_int );
1027
    QApplication::postEvent( mim, event );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
1028 1029
    return VLC_SUCCESS;
}
1030