main_interface.cpp 30.8 KB
Newer Older
Clément Stenac's avatar
Clément Stenac committed
1
/*****************************************************************************
Clément Stenac's avatar
Wtf ?  
Clément Stenac committed
2
 * main_interface.cpp : Main interface
Clément Stenac's avatar
Clément Stenac committed
3
 ****************************************************************************
4
 * Copyright (C) 2006-2007 the VideoLAN team
5
 * $Id$
Clément Stenac's avatar
Clément Stenac committed
6 7
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
8
 *          Jean-Baptiste Kempf <jb@videolan.org>
Clément Stenac's avatar
Clément Stenac committed
9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * 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
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23
 *****************************************************************************/
Clément Stenac's avatar
Clément Stenac committed
24

25
#include "qt4.hpp"
Clément Stenac's avatar
Clément Stenac committed
26
#include "main_interface.hpp"
Clément Stenac's avatar
Clément Stenac committed
27
#include "input_manager.hpp"
Clément Stenac's avatar
Clément Stenac committed
28
#include "util/qvlcframe.hpp"
29
#include "util/customwidgets.hpp"
Clément Stenac's avatar
Clément Stenac committed
30
#include "dialogs_provider.hpp"
31
#include "components/interface_widgets.hpp"
32 33 34
#include "dialogs/playlist.hpp"
#include "menus.hpp"

Clément Stenac's avatar
Clément Stenac committed
35
#include <QMenuBar>
Clément Stenac's avatar
Clément Stenac committed
36
#include <QCloseEvent>
Clément Stenac's avatar
Clément Stenac committed
37
#include <QPushButton>
Clément Stenac's avatar
Clément Stenac committed
38
#include <QStatusBar>
39
#include <QKeyEvent>
40
#include <QUrl>
41
#include <QSystemTrayIcon>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
42 43
#include <QSize>
#include <QMenu>
44
#include <QLabel>
45 46
#include <QSlider>
#include <QWidgetAction>
47 48

#include <assert.h>
49
#include <vlc_keys.h>
Clément Stenac's avatar
Clément Stenac committed
50
#include <vlc_vout.h>
Clément Stenac's avatar
Clément Stenac committed
51

Clément Stenac's avatar
Clément Stenac committed
52
#ifdef WIN32
53
    #define PREF_W 410
54
    #define PREF_H 151
Clément Stenac's avatar
Clément Stenac committed
55
#else
56 57
    #define PREF_W 400
    #define PREF_H 140
Clément Stenac's avatar
Clément Stenac committed
58
#endif
Clément Stenac's avatar
Clément Stenac committed
59

60 61 62 63 64 65
#define SET_WIDTH(i,j) i->widgetSize.setWidth(j)
#define SET_HEIGHT(i,j) i->widgetSize.setHeight(j)
#define SET_WH( i,j,k) i->widgetSize.setWidth(j); i->widgetSize.setHeight(k);

#define DS(i) i.width(),i.height()

66 67 68 69 70
/* Callback prototypes */
static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
                        vlc_value_t old_val, vlc_value_t new_val, void *param );
static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
                       vlc_value_t old_val, vlc_value_t new_val, void *param );
71 72
static int InteractCallback( vlc_object_t *, const char *, vlc_value_t,
                             vlc_value_t, void *);
73 74 75 76 77 78 79 80 81 82 83 84 85 86
/* Video handling */
static void *DoRequest( intf_thread_t *p_intf, vout_thread_t *p_vout,
                        int *pi1, int *pi2, unsigned int*pi3,unsigned int*pi4)
{
    return p_intf->p_sys->p_mi->requestVideo( p_vout, pi1, pi2, pi3, pi4 );
}
static void DoRelease( intf_thread_t *p_intf, void *p_win )
{
    return p_intf->p_sys->p_mi->releaseVideo( p_win );
}
static int DoControl( intf_thread_t *p_intf, void *p_win, int i_q, va_list a )
{
    return p_intf->p_sys->p_mi->controlVideo( p_win, i_q, a );
}
87

88
MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf )
Clément Stenac's avatar
Clément Stenac committed
89
{
90
    /* Variables initialisation */
91
    need_components_update = false;
92
    bgWidget = NULL; videoWidget = NULL; playlistWidget = NULL;
Clément Stenac's avatar
Clément Stenac committed
93
    embeddedPlaylistWasActive = videoIsActive = false;
94
    input_name = "";
95

96
    /**
97
     *  Configuration and settings
98
     **/
99
    settings = new QSettings( "vlc", "vlc-qt-interface" );
100 101
    settings->beginGroup( "MainWindow" );

102 103 104
    /* Main settings */
    setFocusPolicy( Qt::StrongFocus );
    setAcceptDrops(true);
105
    setWindowIcon( QApplication::windowIcon() );
106
    setWindowOpacity( config_GetFloat( p_intf, "qt-opacity" ) );
107 108

    /* Set The Video In emebedded Mode or not */
Clément Stenac's avatar
Clément Stenac committed
109
    videoEmbeddedFlag = false;
110 111
    if( config_GetInt( p_intf, "embedded-video" ) )
        videoEmbeddedFlag = true;
Clément Stenac's avatar
Clément Stenac committed
112 113

    alwaysVideoFlag = false;
114
    if( videoEmbeddedFlag && config_GetInt( p_intf, "qt-always-video" ) )
Clément Stenac's avatar
Clément Stenac committed
115 116
        alwaysVideoFlag = true;

117
    /* Set the other interface settings */
118 119 120 121
    playlistEmbeddedFlag = settings->value( "playlist-embedded", true).toBool();
    visualSelectorEnabled = settings->value( "visual-selector", false ).toBool();
    notificationEnabled = config_GetInt( p_intf, "qt-notification" )
                          ? true : false;
122 123 124
    /**************************
     *  UI and Widgets design
     **************************/
125
    setVLCWindowsTitle();
126
    handleMainUi( settings );
127 128

    /* Menu Bar */
Clément Stenac's avatar
Clément Stenac committed
129
    QVLCMenu::createMenuBar( this, p_intf, playlistEmbeddedFlag,
130
                             visualSelectorEnabled );
131 132

    /* Status Bar */
133 134 135 136
    /**
     * TODO: clicking on the elapsed time should switch to the remaining time
     **/
    /**
137
     * TODO: do we add a label for the current Volume ?
138
     **/
139
    b_remainingTime = false;
140
    timeLabel = new TimeLabel;
141
    nameLabel = new QLabel;
142
    speedLabel = new QLabel( "1.00x" );
143
    timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
144 145 146 147
    speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
    statusBar()->addWidget( nameLabel, 8 );
    statusBar()->addPermanentWidget( speedLabel, 0 );
    statusBar()->addPermanentWidget( timeLabel, 2 );
148 149
    speedLabel->setContextMenuPolicy ( Qt::CustomContextMenu );
    timeLabel->setContextMenuPolicy ( Qt::CustomContextMenu );
150
    CONNECT( timeLabel, timeLabelClicked(), this, toggleTimeDisplay() );
151 152 153 154
    CONNECT( speedLabel, customContextMenuRequested( QPoint ),
             this, showSpeedMenu( QPoint ) );
    CONNECT( timeLabel, customContextMenuRequested( QPoint ),
             this, showTimeMenu( QPoint ) );
155

156 157 158
    /**********************
     * Systray Management *
     **********************/
159
    sysTray = NULL;
160 161
    bool b_createSystray = false;
    bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
162
    if( config_GetInt( p_intf, "qt-start-minimized") )
163
    {
164 165 166 167 168 169
        if( b_systrayAvailable ){
            b_createSystray = true;
            hide(); //FIXME
        }
        else msg_Warn( p_intf, "You can't minize if you haven't a system "
                "tray bar" );
170
    }
171 172
    if( config_GetInt( p_intf, "qt-system-tray") )
        b_createSystray = true;
173 174

    if( b_systrayAvailable && b_createSystray )
175
            createSystray();
176

177 178 179 180
    /* Init input manager */
    MainInputManager::getInstance( p_intf );
    ON_TIMEOUT( updateOnTimer() );

181
    /**
182
     * Various CONNECTs
183 184
     **/

185
    /* Connect the input manager to the GUI elements it manages */
186
    /* It is also connected to the control->slider, see the ControlsWidget */
187
    CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
188
             this, setDisplayPosition( float, int, int ) );
189

190
    CONNECT( THEMIM->getIM(), rateChanged( int ), this, setRate( int ) );
191

192 193
    /** Connects on nameChanged() */
    /* Naming in the controller statusbar */
194 195
    CONNECT( THEMIM->getIM(), nameChanged( QString ), this,
             setName( QString ) );
196
    /* and in the systray */
197
    if( sysTray )
198 199
    {
        CONNECT( THEMIM->getIM(), nameChanged( QString ), this,
200
                 updateSystrayTooltipName( QString ) );
201
    }
202
    /* and in the title of the controller */
203 204 205 206 207 208
    if( config_GetInt( p_intf, "qt-name-in-title" ) )
    {
        CONNECT( THEMIM->getIM(), nameChanged( QString ), this,
             setVLCWindowsTitle( QString ) );
    }

209 210
    /** CONNECTS on PLAY_STATUS **/
    /* Status on the main controller */
211
    CONNECT( THEMIM->getIM(), statusChanged( int ), this, setStatus( int ) );
212
    /* and in the systray */
213
    if( sysTray )
214 215
    {
        CONNECT( THEMIM->getIM(), statusChanged( int ), this,
216
                 updateSystrayTooltipStatus( int ) );
217
    }
218

219 220 221
    /**
     * Callbacks
     **/
222 223 224
    var_Create( p_intf, "interaction", VLC_VAR_ADDRESS );
    var_AddCallback( p_intf, "interaction", InteractCallback, this );
    p_intf->b_interaction = VLC_TRUE;
225 226

    /* Register callback for the intf-popupmenu variable */
227 228
    playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_intf,
                                        VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
229 230 231 232 233 234
    if( p_playlist != NULL )
    {
        var_AddCallback( p_playlist, "intf-popupmenu", PopupMenuCB, p_intf );
        var_AddCallback( p_playlist, "intf-show", IntfShowCB, p_intf );
        vlc_object_release( p_playlist );
    }
235 236 237 238
}

MainInterface::~MainInterface()
{
239
    /* Unregister callback for the intf-popupmenu variable */
240 241
    playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_intf,
                                        VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
242 243 244 245 246 247 248
    if( p_playlist != NULL )
    {
        var_DelCallback( p_playlist, "intf-popupmenu", PopupMenuCB, p_intf );
        var_DelCallback( p_playlist, "intf-show", IntfShowCB, p_intf );
        vlc_object_release( p_playlist );
    }

Clément Stenac's avatar
Clément Stenac committed
249
    settings->setValue( "playlist-embedded", playlistEmbeddedFlag );
250
    settings->setValue( "adv-controls", getControlsVisibilityStatus() & 0x1 );
Clément Stenac's avatar
Clément Stenac committed
251 252 253
    settings->setValue( "pos", pos() );
    settings->endGroup();
    delete settings;
254 255
    p_intf->b_interaction = VLC_FALSE;
    var_DelCallback( p_intf, "interaction", InteractCallback, this );
256 257 258 259

    p_intf->pf_request_window = NULL;
    p_intf->pf_release_window = NULL;
    p_intf->pf_control_window = NULL;
260 261
}

262 263 264
/*****************************
 *   Main UI handling        *
 *****************************/
265 266 267 268 269

/**
 * Give the decorations of the Main Window a correct Name.
 * If nothing is given, set it to VLC...
 **/
270 271 272 273
void MainInterface::setVLCWindowsTitle( QString aTitle )
{
    if( aTitle.isEmpty() )
    {
274
        setWindowTitle( qtr( "VLC media player" ) );
275 276 277
    }
    else
    {
278
        setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
279 280 281
    }
}

282

283 284
void MainInterface::handleMainUi( QSettings *settings )
{
285
    /* Create the main Widget and the mainLayout */
286
    QWidget *main = new QWidget( this );
287
    mainLayout = new QVBoxLayout( main );
288 289
    setCentralWidget( main );

290 291 292 293
    /* Margins, spacing */
    main->setContentsMargins( 0, 0, 0, 0 );
    mainLayout->setMargin( 0 );

294 295 296
    /* Create the CONTROLS Widget */
    controls = new ControlsWidget( p_intf,
                   settings->value( "adv-controls", false ).toBool() );
297

298
    /* Configure the Controls */
299
    BUTTON_SET_IMG( controls->playlistButton, "" , playlist_icon.png,
300 301 302
                    playlistEmbeddedFlag ?  qtr( "Show playlist" ) :
                                            qtr( "Open playlist" ) );
    BUTTONACT( controls->playlistButton, togglePlaylist() );
303

304
    /* Add the controls Widget to the main Widget */
305 306
    mainLayout->addWidget( controls );

307 308 309 310 311 312
    /* Create the Speed Control Widget */
    speedControl = new SpeedControlWidget( p_intf );
    speedControlMenu = new QMenu( this );
    QWidgetAction *widgetAction = new QWidgetAction( this );
    widgetAction->setDefaultWidget( speedControl );
    speedControlMenu->addAction( widgetAction );
313

314 315
    /* Set initial size */
    resize( PREF_W, PREF_H );
316
    addSize = QSize( mainLayout->margin() * 2, PREF_H );
317

318
    /* Visualisation */
319
    visualSelector = new VisualSelector( p_intf );
320
    mainLayout->insertWidget( 0, visualSelector );
321 322
    visualSelector->hide();

323
    /* And video Outputs */
324
    if( alwaysVideoFlag )
325 326 327
    {
        bgWidget = new BackgroundWidget( p_intf );
        bgWidget->widgetSize = settings->value( "backgroundSize",
328
                                           QSize( 300, 300 ) ).toSize();
329 330
        bgWidget->resize( bgWidget->widgetSize );
        bgWidget->updateGeometry();
331
        mainLayout->insertWidget( 0, bgWidget );
332 333
    }

334
    if( videoEmbeddedFlag )
335
    {
336
        videoWidget = new VideoWidget( p_intf );
337
        videoWidget->widgetSize = QSize( 1, 1 );
338
        //videoWidget->resize( videoWidget->widgetSize );
339
        mainLayout->insertWidget( 0, videoWidget );
340

341 342 343
        p_intf->pf_request_window  = ::DoRequest;
        p_intf->pf_release_window  = ::DoRelease;
        p_intf->pf_control_window  = ::DoControl;
344
    }
345 346

    /* Finish the sizing */
Clément Stenac's avatar
Clément Stenac committed
347
    setMinimumSize( PREF_W, addSize.height() );
Clément Stenac's avatar
Clément Stenac committed
348 349
}

350
/**********************************************************************
351
 * Handling of sizing of the components
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
 **********************************************************************/
void MainInterface::calculateInterfaceSize()
{
    int width = 0, height = 0;
    if( VISIBLE( bgWidget ) )
    {
        width = bgWidget->widgetSize.width();
        height = bgWidget->widgetSize.height();
        assert( !(playlistWidget && playlistWidget->isVisible() ) );
    }
    else if( VISIBLE( playlistWidget ) )
    {
        width = playlistWidget->widgetSize.width();
        height = playlistWidget->widgetSize.height();
    }
    else if( videoIsActive )
    {
        width =  videoWidget->widgetSize.width() ;
        height = videoWidget->widgetSize.height();
    }
    else
    {
        width = PREF_W - addSize.width();
        height = PREF_H - addSize.height();
    }
    if( VISIBLE( visualSelector ) )
        height += visualSelector->height();
379
/*    if( VISIBLE( advControls) )
380 381
    {
        height += advControls->sizeHint().height();
382
    }*/
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
    mainSize = QSize( width + addSize.width(), height + addSize.height() );
}

void MainInterface::resizeEvent( QResizeEvent *e )
{
    videoWidget->widgetSize.setWidth(  e->size().width() - addSize.width() );
    if( videoWidget && videoIsActive && videoWidget->widgetSize.height() > 1 )
    {
        SET_WH( videoWidget, e->size().width() - addSize.width(),
                             e->size().height()  - addSize.height() );
        videoWidget->updateGeometry();
    }
    if( VISIBLE( playlistWidget ) )
    {
        SET_WH( playlistWidget , e->size().width() - addSize.width(),
                                 e->size().height() - addSize.height() );
        playlistWidget->updateGeometry();
    }
}
402

403 404 405 406 407
/****************************************************************************
 * Small right-click menus
 ****************************************************************************/
void MainInterface::showSpeedMenu( QPoint pos )
{
408
    speedControlMenu->exec( QCursor::pos() - pos + QPoint( 0, speedLabel->height() ) );
409 410 411 412 413
}

void MainInterface::showTimeMenu( QPoint pos )
{
    QMenu menu( this );
414 415
    menu.addAction(  qtr("Elapsed Time") , this, SLOT( setElapsedTime() ) );
    menu.addAction(  qtr("Remaining Time") , this, SLOT( setRemainTime() ) );
416
    menu.exec( QCursor::pos() - pos +QPoint( 0, timeLabel->height() ) );
417
}
418

419 420 421
/****************************************************************************
 * Video Handling
 ****************************************************************************/
422 423 424 425 426
void *MainInterface::requestVideo( vout_thread_t *p_nvout, int *pi_x,
                                   int *pi_y, unsigned int *pi_width,
                                   unsigned int *pi_height )
{
    void *ret = videoWidget->request( p_nvout,pi_x, pi_y, pi_width, pi_height );
427 428 429
    if( ret )
    {
        videoIsActive = true;
430
        if( VISIBLE( playlistWidget ) )
431 432
        {
            embeddedPlaylistWasActive = true;
433
//            playlistWidget->hide();
434
        }
435 436
        bool bgWasVisible = false;
        if( VISIBLE( bgWidget) )
Clément Stenac's avatar
Clément Stenac committed
437
        {
438
            bgWasVisible = true;
439
            bgWidget->hide();
Clément Stenac's avatar
Clément Stenac committed
440
        }
441 442 443 444 445 446 447 448 449 450 451
        if( THEMIM->getIM()->hasVideo() || !bgWasVisible )
        {
            videoWidget->widgetSize = QSize( *pi_width, *pi_height );
        }
        else /* Background widget available, use its size */
        {
            /* Ok, our visualizations are bad, so don't do this for the moment
             * use the requested size anyway */
            // videoWidget->widgetSize = bgWidget->widgeTSize;
            videoWidget->widgetSize = QSize( *pi_width, *pi_height );
        }
452
        videoWidget->updateGeometry(); // Needed for deinterlace
453 454
        need_components_update = true;
    }
455 456 457 458 459 460
    return ret;
}

void MainInterface::releaseVideo( void *p_win )
{
    videoWidget->release( p_win );
461 462
    videoWidget->widgetSize = QSize( 0, 0 );
    videoWidget->resize( videoWidget->widgetSize );
Clément Stenac's avatar
Clément Stenac committed
463

464
    if( embeddedPlaylistWasActive )
465
        playlistWidget->show();
Clément Stenac's avatar
Clément Stenac committed
466
    else if( bgWidget )
467
        bgWidget->show();
Clément Stenac's avatar
Clément Stenac committed
468

469
    videoIsActive = false;
470
    need_components_update = true;
471 472
}

473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
class SetVideoOnTopQtEvent : public QEvent
{
public:
    SetVideoOnTopQtEvent( bool _onTop ) :
      QEvent( (QEvent::Type)SetVideoOnTopEvent_Type ), onTop( _onTop)
    {
    }

    bool OnTop() const
    {
        return onTop;
    }

private:
    bool onTop;
};

490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
int MainInterface::controlVideo( void *p_window, int i_query, va_list args )
{
    int i_ret = VLC_EGENERIC;
    switch( i_query )
    {
        case VOUT_GET_SIZE:
        {
            unsigned int *pi_width  = va_arg( args, unsigned int * );
            unsigned int *pi_height = va_arg( args, unsigned int * );
            *pi_width = videoWidget->widgetSize.width();
            *pi_height = videoWidget->widgetSize.height();
            i_ret = VLC_SUCCESS;
            break;
        }
        case VOUT_SET_SIZE:
        {
            unsigned int i_width  = va_arg( args, unsigned int );
            unsigned int i_height = va_arg( args, unsigned int );
            videoWidget->widgetSize = QSize( i_width, i_height );
509
            // videoWidget->updateGeometry();
510 511 512 513 514
            need_components_update = true;
            i_ret = VLC_SUCCESS;
            break;
        }
        case VOUT_SET_STAY_ON_TOP:
515 516 517 518 519 520
        {
            int i_arg = va_arg( args, int );
            QApplication::postEvent( this, new SetVideoOnTopQtEvent( i_arg ) );
            i_ret = VLC_SUCCESS;
            break;
        }
521 522 523 524 525 526 527
        default:
            msg_Warn( p_intf, "unsupported control query" );
            break;
    }
    return i_ret;
}

528 529 530 531 532 533 534
/*****************************************************************************
 * Playlist, Visualisation and Menus handling
 *****************************************************************************/
/**
 * Toggle the playlist widget or dialog
 **/
void MainInterface::togglePlaylist()
535
{
536
    // Toggle the playlist dialog if not embedded and return
537 538 539 540
    if( !playlistEmbeddedFlag )
    {
        if( playlistWidget )
        {
541
            /// \todo Destroy it
542 543 544 545 546
        }
        THEDP->playlistDialog();
        return;
    }

547
    // Create the playlist Widget and destroy the existing dialog
548 549 550 551
    if( !playlistWidget )
    {
        PlaylistDialog::killInstance();
        playlistWidget = new PlaylistWidget( p_intf );
552
        mainLayout->insertWidget( 0, playlistWidget );
553
        playlistWidget->widgetSize = settings->value( "playlistSize",
Clément Stenac's avatar
Clément Stenac committed
554
                                               QSize( 650, 310 ) ).toSize();
555
        playlistWidget->hide();
556 557
        if(bgWidget)
        CONNECT( playlistWidget, artSet( QString ), bgWidget, setArt(QString) );
558
    }
559 560

    // And toggle visibility
561
    if( VISIBLE( playlistWidget ) )
562 563
    {
        playlistWidget->hide();
564
        if( bgWidget ) bgWidget->show();
565 566
        if( videoIsActive )
        {
567 568 569
            videoWidget->widgetSize = savedVideoSize;
            videoWidget->resize( videoWidget->widgetSize );
            videoWidget->updateGeometry();
570
            if( bgWidget ) bgWidget->hide();
571 572 573 574 575 576
        }
    }
    else
    {
        playlistWidget->show();
        if( videoIsActive )
577 578 579 580 581 582
        {
            savedVideoSize = videoWidget->widgetSize;
            videoWidget->widgetSize.setHeight( 0 );
            videoWidget->resize( videoWidget->widgetSize );
            videoWidget->updateGeometry();
        }
583
        if( VISIBLE( bgWidget ) ) bgWidget->hide();
584
    }
585

586
    doComponentsUpdate();
587 588
}

589
void MainInterface::undockPlaylist()
590
{
591
    if( playlistWidget )
592
    {
593 594
        playlistWidget->hide();
        playlistWidget->deleteLater();
595
        mainLayout->removeWidget( playlistWidget );
596 597
        playlistWidget = NULL;
        playlistEmbeddedFlag = false;
598

Clément Stenac's avatar
Clément Stenac committed
599
        menuBar()->clear();
600
        QVLCMenu::createMenuBar( this, p_intf, false, visualSelectorEnabled);
601 602 603 604 605 606 607 608 609 610

        if( videoIsActive )
        {
            videoWidget->widgetSize = savedVideoSize;
            videoWidget->resize( videoWidget->widgetSize );
            videoWidget->updateGeometry();
        }

        doComponentsUpdate();
        THEDP->playlistDialog();
611
    }
612 613
}

614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
#if 0
void MainInterface::visual()
{
    if( !VISIBLE( visualSelector) )
    {
        visualSelector->show();
        if( !THEMIM->getIM()->hasVideo() )
        {
            /* Show the background widget */
        }
        visualSelectorEnabled = true;
    }
    else
    {
        /* Stop any currently running visualization */
        visualSelector->hide();
        visualSelectorEnabled = false;
    }
    doComponentsUpdate();
}
#endif

636 637
void MainInterface::toggleMenus()
{
638
    msg_Dbg( p_intf, "I HAS HERE, HIDING YOUR MENUZ: \\_o<~~ coin coin" );
639 640
    TOGGLEV( controls );
    TOGGLEV( statusBar() );
641
    updateGeometry();
642 643
}

644 645 646
/* Video widget cannot do this synchronously as it runs in another thread */
/* Well, could it, actually ? Probably dangerous ... */
void MainInterface::doComponentsUpdate()
647
{
648 649 650 651 652 653 654 655 656
    calculateInterfaceSize();
    resize( mainSize );
}

void MainInterface::toggleAdvanced()
{
    controls->toggleAdvanced();
}

657
int MainInterface::getControlsVisibilityStatus()
658
{
659
    return( (controls->isVisible() ? 0x2 : 0x0 )
660
                + controls->b_advancedVisible );
661 662 663 664 665
}

/************************************************************************
 * Other stuff
 ************************************************************************/
666
void MainInterface::setDisplayPosition( float pos, int time, int length )
667 668 669
{
    char psz_length[MSTRTIME_MAX_SIZE], psz_time[MSTRTIME_MAX_SIZE];
    secstotimestr( psz_length, length );
670 671 672 673
    secstotimestr( psz_time, b_remainingTime ? length - time : time );
    QString title; title.sprintf( "%s/%s", psz_time, psz_length );
    if( b_remainingTime ) timeLabel->setText( " -"+title+" " );
    else timeLabel->setText( " "+title+" " );
674 675
}

676
void MainInterface::toggleTimeDisplay()
677 678 679 680 681 682 683
{
    b_remainingTime = ( b_remainingTime ? false : true );
}

void MainInterface::setElapsedTime(){ b_remainingTime = false; }
void MainInterface::setRemainTime(){ b_remainingTime = true; }

684 685 686 687 688 689 690 691 692 693 694 695 696
void MainInterface::setName( QString name )
{
    input_name = name;
    nameLabel->setText( " " + name+" " );
}

void MainInterface::setStatus( int status )
{
    controls->setStatus( status );
    if( sysTray )
        updateSystrayMenu( status );
}

697 698 699
void MainInterface::setRate( int rate )
{
    QString str;
700
    str.setNum( ( 1000 / (double)rate), 'f', 2 );
701 702
    str.append( "x" );
    speedLabel->setText( str );
703
    speedControl->updateControls( rate );
704 705
}

706 707 708 709
void MainInterface::updateOnTimer()
{
    /* \todo Make this event-driven */
    if( intf_ShouldDie( p_intf ) )
710
    {
711 712
        QApplication::closeAllWindows();
        QApplication::quit();
713
    }
714
    if( need_components_update )
715
    {
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
        doComponentsUpdate();
        need_components_update = false;
    }

    controls->updateOnTimer();
}

/*****************************************************************************
 * Systray Icon and Systray Menu
 *****************************************************************************/

/**
 * Create a SystemTray icon and a menu that would go with it.
 * Connects to a click handler on the icon.
 **/
void MainInterface::createSystray()
{
    QIcon iconVLC =  QIcon( QPixmap( ":/vlc128.png" ) );
    sysTray = new QSystemTrayIcon( iconVLC, this );
    sysTray->setToolTip( qtr( "VLC media player" ));

    systrayMenu = new QMenu( qtr( "VLC media player" ), this );
    systrayMenu->setIcon( iconVLC );

    QVLCMenu::updateSystrayMenu( this, p_intf, true );
    sysTray->show();

743
    CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766
            this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
}

/**
 * Update the menu of the Systray Icon.
 * May be unneedded, since it just calls QVLCMenu::update
 * FIXME !!!
 **/
void MainInterface::updateSystrayMenu( int status )
{
    QVLCMenu::updateSystrayMenu( this, p_intf ) ;
}

/**
 * Updates the Systray Icon's menu and toggle the main interface
 */
void MainInterface::toggleUpdateSystrayMenu()
{
    if( isHidden() )
    {
        show();
        activateWindow();
    }
767 768 769 770 771
    else if( isMinimized() )
    {
        showNormal();
        activateWindow();
    }
772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
    else
    {
#ifdef WIN32
        /* check if any visible window is above vlc in the z-order,
         * but ignore the ones always on top */
        WINDOWINFO wi;
        HWND hwnd;
        wi.cbSize = sizeof( WINDOWINFO );
        for( hwnd = GetNextWindow( internalWinId(), GW_HWNDPREV );
                hwnd && !IsWindowVisible( hwnd );
                hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) );
        if( !hwnd || !GetWindowInfo( hwnd, &wi ) ||
                (wi.dwExStyle&WS_EX_TOPMOST) )
#else
        if( isActiveWindow() )
#endif
        {
            hide();
        }
791
        else
792 793 794
        {
            activateWindow();
        }
795
    }
796
    QVLCMenu::updateSystrayMenu( this, p_intf );
797 798
}

799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828
void MainInterface::handleSystrayClick(
                                    QSystemTrayIcon::ActivationReason reason )
{
    switch( reason )
    {
        case QSystemTrayIcon::Trigger:
            toggleUpdateSystrayMenu();
            break;
        case QSystemTrayIcon::MiddleClick:
            sysTray->showMessage( qtr( "VLC media player" ),
                    qtr( "Control menu for the player" ),
                    QSystemTrayIcon::Information, 4000 );
            break;
    }
}

/**
 * Updates the name of the systray Icon tooltip.
 * Doesn't check if the systray exists, check before you call it.
 * FIXME !!! Fusion with next function ?
 **/
void MainInterface::updateSystrayTooltipName( QString name )
{
    if( name.isEmpty() )
    {
        sysTray->setToolTip( qtr( "VLC media player" ) );
    }
    else
    {
        sysTray->setToolTip( name );
829
        if( notificationEnabled && ( isHidden() || isMinimized() ) )
830 831 832 833
        {
            sysTray->showMessage( qtr( "VLC media player" ), name,
                    QSystemTrayIcon::NoIcon, 4000 );
        }
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863
    }
}

/**
 * Updates the status of the systray Icon tooltip.
 * Doesn't check if the systray exists, check before you call it.
 **/
void MainInterface::updateSystrayTooltipStatus( int i_status )
{
    switch( i_status )
    {
        case  0:
            {
                sysTray->setToolTip( qtr( "VLC media player" ) );
                break;
            }
        case PLAYING_S:
            {
                sysTray->setToolTip( input_name );
                //+ " - " + qtr( "Playing" ) );
                break;
            }
        case PAUSE_S:
            {
                sysTray->setToolTip( input_name + " - "
                        + qtr( "Paused") );
                break;
            }
    }
}
864 865

/************************************************************************
866
 * D&D Events
867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889
 ************************************************************************/
void MainInterface::dropEvent(QDropEvent *event)
{
     const QMimeData *mimeData = event->mimeData();

     /* D&D of a subtitles file, add it on the fly */
     if( mimeData->urls().size() == 1 )
     {
        if( THEMIM->getIM()->hasInput() )
        {
            if( input_AddSubtitles( THEMIM->getInput(),
                                    qtu( mimeData->urls()[0].toString() ),
                                    VLC_TRUE ) )
            {
                event->acceptProposedAction();
                return;
            }
        }
     }
     bool first = true;
     foreach( QUrl url, mimeData->urls() ) {
        QString s = url.toString();
        if( s.length() > 0 ) {
890 891
            playlist_Add( THEPL, qtu(s), NULL,
                          PLAYLIST_APPEND | (first ? PLAYLIST_GO:0),
892
                          PLAYLIST_END, VLC_TRUE, VLC_FALSE );
893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910
            first = false;
        }
     }
     event->acceptProposedAction();
}
void MainInterface::dragEnterEvent(QDragEnterEvent *event)
{
     event->acceptProposedAction();
}
void MainInterface::dragMoveEvent(QDragMoveEvent *event)
{
     event->acceptProposedAction();
}
void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
{
     event->accept();
}

911
/************************************************************************
912
 * Events stuff
913
 ************************************************************************/
914 915 916 917 918 919 920
void MainInterface::customEvent( QEvent *event )
{
    if( event->type() == PLDockEvent_Type )
    {
        PlaylistDialog::killInstance();
        playlistEmbeddedFlag = true;
        menuBar()->clear();
921
        QVLCMenu::createMenuBar(this, p_intf, true, visualSelectorEnabled);
922 923 924 925 926 927 928 929 930 931 932 933 934
        togglePlaylist();
    }
    else if ( event->type() == SetVideoOnTopEvent_Type )
    {
        SetVideoOnTopQtEvent* p_event = (SetVideoOnTopQtEvent*)event;
        if( p_event->OnTop() )
            setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
        else
            setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
        show(); /* necessary to apply window flags?? */
    }
}

935 936
void MainInterface::keyPressEvent( QKeyEvent *e )
{
937
    int i_vlck = qtEventToVLCKey( e );
938 939
    if( i_vlck >= 0 )
    {
940
        var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
941 942 943 944 945 946
        e->accept();
    }
    else
        e->ignore();
}

947 948
void MainInterface::wheelEvent( QWheelEvent *e )
{
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
949
    int i_vlckey = qtWheelEventToVLCKey( e );
950 951 952 953
    var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
    e->accept();
}

Clément Stenac's avatar
Clément Stenac committed
954 955 956
void MainInterface::closeEvent( QCloseEvent *e )
{
    hide();
957
    vlc_object_kill( p_intf );
Clément Stenac's avatar
Clément Stenac committed
958
}
959

960 961 962
/*****************************************************************************
 * Callbacks
 *****************************************************************************/
963 964 965 966 967 968 969
static int InteractCallback( vlc_object_t *p_this,
                             const char *psz_var, vlc_value_t old_val,
                             vlc_value_t new_val, void *param )
{
    intf_dialog_args_t *p_arg = new intf_dialog_args_t;
    p_arg->p_dialog = (interaction_dialog_t *)(new_val.p_address);
    DialogEvent *event = new DialogEvent( INTF_DIALOG_INTERACTION, 0, p_arg );
970
    QApplication::postEvent( THEDP, static_cast<QEvent*>(event) );
971 972
    return VLC_SUCCESS;
}
973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003

/*****************************************************************************
 * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
 *  We don't show the menu directly here because we don't want the
 *  caller to block for a too long time.
 *****************************************************************************/
static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
                        vlc_value_t old_val, vlc_value_t new_val, void *param )
{
    intf_thread_t *p_intf = (intf_thread_t *)param;

    if( p_intf->pf_show_dialog )
    {
        p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
                                new_val.b_bool, 0 );
    }

    return VLC_SUCCESS;
}

/*****************************************************************************
 * IntfShowCB: callback triggered by the intf-show playlist variable.
 *****************************************************************************/
static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
                       vlc_value_t old_val, vlc_value_t new_val, void *param )
{
    intf_thread_t *p_intf = (intf_thread_t *)param;
    //p_intf->p_sys->b_intf_show = VLC_TRUE;

    return VLC_SUCCESS;
}