main_interface.cpp 47.9 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-2011 VideoLAN and AUTHORS
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>
9
 *          Ilkka Ollakka <ileoo@videolan.org>
Clément Stenac's avatar
Clément Stenac committed
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
22 23
 * along with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24
 *****************************************************************************/
25

26 27 28
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
Clément Stenac's avatar
Clément Stenac committed
29

30
#include "qt4.hpp"
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
31

Clément Stenac's avatar
Clément Stenac committed
32
#include "main_interface.hpp"
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
33 34
#include "input_manager.hpp"                    // Creation
#include "actions_manager.hpp"                  // killInstance
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
35

36
#include "util/customwidgets.hpp"               // qtEventToVLCKey, QVLCStackedWidget
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
37
#include "util/qt_dirs.hpp"                     // toNativeSeparators
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
38

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
39 40 41 42
#include "components/interface_widgets.hpp"     // bgWidget, videoWidget
#include "components/controller.hpp"            // controllers
#include "components/playlist/playlist.hpp"     // plWidget
#include "dialogs/firstrun.hpp"                 // First Run
43
#include "dialogs/playlist.hpp"                 // PlaylistDialog
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
44

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
45 46
#include "menus.hpp"                            // Menu creation
#include "recents.hpp"                          // RecentItems when DnD
47

Clément Stenac's avatar
Clément Stenac committed
48
#include <QCloseEvent>
49
#include <QKeyEvent>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
50

51
#include <QUrl>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
52
#include <QSize>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
53
#include <QDate>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
54
#include <QMimeData>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
55

56
#include <QMenu>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
57 58
#include <QMenuBar>
#include <QStatusBar>
59
#include <QLabel>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
60
#include <QStackedWidget>
61
#include <QFileInfo>
62

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
63 64
#include <vlc_keys.h>                       /* Wheel event */
#include <vlc_vout_display.h>               /* vout_thread_t and VOUT_ events */
65

66

67
#if defined(_WIN32) && HAS_QT5
68 69 70 71
#include <QWindow>
#include <qpa/qplatformnativeinterface.h>
#endif

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
72
// #define DEBUG_INTF
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
73

74 75 76 77 78
/* 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 );
79 80
static int IntfBossCB( vlc_object_t *p_this, const char *psz_variable,
                       vlc_value_t old_val, vlc_value_t new_val, void *param );
81 82 83
static int IntfRaiseMainCB( vlc_object_t *p_this, const char *psz_variable,
                           vlc_value_t old_val, vlc_value_t new_val,
                           void *param );
84

85 86 87
const QEvent::Type MainInterface::ToolbarsNeedRebuild =
        (QEvent::Type)QEvent::registerEventType();

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 92 93
    bgWidget             = NULL;
    videoWidget          = NULL;
    playlistWidget       = NULL;
94
    stackCentralOldWidget= NULL;
95 96
    sysTray              = NULL;
    fullscreenControls   = NULL;
97
    cryptedLabel         = NULL;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
98 99
    controls             = NULL;
    inputC               = NULL;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
100

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
101
    b_hideAfterCreation  = false; // --qt-start-minimized
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
102
    playlistVisible      = false;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
103
    input_name           = "";
104
    b_interfaceFullScreen= false;
105
    b_hasPausedWhenMinimized = false;
106
    i_kc_offset          = false;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
107

108
    /* Ask for Privacy */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
109
    FirstRun::CheckAndRun( this, p_intf );
110

111
    /**
112
     *  Configuration and settings
113
     *  Pre-building of interface
114
     **/
115 116
    /* Main settings */
    setFocusPolicy( Qt::StrongFocus );
117
    setAcceptDrops( true );
Nick Pope's avatar
Nick Pope committed
118
    setWindowRole( "vlc-main" );
119
    setWindowIcon( QApplication::windowIcon() );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
120
    setWindowOpacity( var_InheritFloat( p_intf, "qt-opacity" ) );
121
#ifdef Q_OS_MAC
122 123
    setAttribute( Qt::WA_MacBrushedMetal );
#endif
124

Rémi Denis-Courmont's avatar
Grammar  
Rémi Denis-Courmont committed
125
    /* Is video in embedded in the UI or not */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
126
    b_videoEmbedded = var_InheritBool( p_intf, "embedded-video" );
Clément Stenac's avatar
Clément Stenac committed
127

128
    /* Does the interface resize to video size or the opposite */
129
    b_autoresize = var_InheritBool( p_intf, "qt-video-autoresize" );
130

131
    /* Are we in the enhanced always-video mode or not ? */
132
    b_minimalView = var_InheritBool( p_intf, "qt-minimal-view" );
Clément Stenac's avatar
Clément Stenac committed
133

134
    /* Do we want anoying popups or not */
135
    i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
136

137
    /* */
138 139
    b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );

140
    /* Set the other interface settings */
141
    settings = getSettings();
142

143
#ifdef _WIN32
144 145 146 147
    /* Volume keys */
    p_intf->p_sys->disable_volume_keys = var_InheritBool( p_intf, "qt-disable-volume-keys" );
#endif

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
148
    /* */
149
    b_plDocked = getSettings()->value( "MainWindow/pl-dock-status", true ).toBool();
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
150

151

152 153 154
    /**************************
     *  UI and Widgets design
     **************************/
155
    setVLCWindowsTitle();
156

157 158 159
    /************
     * Menu Bar *
     ************/
160
    VLCMenuBar::createMenuBar( this, p_intf );
161
    CONNECT( THEMIM->getIM(), voutListChanged( vout_thread_t **, int ),
162
             THEDP, destroyPopupMenu() );
163

164
    createMainWidget( settings );
165 166 167 168 169 170 171

    /**************
     * Status Bar *
     **************/
    createStatusBar();
    setStatusBarVisibility( getSettings()->value( "MainWindow/status-bar-visible", false ).toBool() );

172
#ifdef _WIN32
173 174
    himl = NULL;
    p_taskbl = NULL;
175
    taskbar_wmsg = RegisterWindowMessage(TEXT("TaskbarButtonCreated"));
176 177
#endif

178 179 180 181 182
    /*********************************
     * Create the Systray Management *
     *********************************/
    initSystray();

183 184 185 186
    /*************************************************************
     * Connect the input manager to the GUI elements it manages  *
     * Beware initSystray did some connects on input manager too *
     *************************************************************/
187 188
    /**
     * Connects on nameChanged()
189 190 191
     * Those connects are different because options can impeach them to trigger.
     **/
    /* Main Interface statusbar */
Rémi Duraffort's avatar
Rémi Duraffort committed
192 193
    CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
             this, setName( const QString& ) );
194
    /* and title of the Main Interface*/
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
195
    if( var_InheritBool( p_intf, "qt-name-in-title" ) )
196
    {
197 198
        CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
                 this, setVLCWindowsTitle( const QString& ) );
199
    }
200 201
    /* END CONNECTS ON IM */

202
    /* VideoWidget connects for asynchronous calls */
203
    b_videoFullScreen = false;
204 205 206
    connect( this, SIGNAL(askGetVideo(WId*,int*,int*,unsigned*,unsigned *)),
             this, SLOT(getVideoSlot(WId*,int*,int*,unsigned*,unsigned*)),
             Qt::BlockingQueuedConnection );
207
    connect( this, SIGNAL(askReleaseVideo( void )),
208 209
             this, SLOT(releaseVideoSlot( void )),
             Qt::BlockingQueuedConnection );
210
    CONNECT( this, askVideoOnTop(bool), this, setVideoOnTop(bool));
211

212
    if( videoWidget )
213
    {
214 215 216
        if( b_autoresize )
        {
            CONNECT( this, askVideoToResize( unsigned int, unsigned int ),
217
                     this, setVideoSize( unsigned int, unsigned int ) );
218
            CONNECT( videoWidget, sizeChanged( int, int ),
219
                     this, videoSizeChanged( int,  int ) );
220
        }
221
        CONNECT( this, askVideoSetFullScreen( bool ),
222
                 this, setVideoFullScreen( bool ) );
223 224
    }

225 226
    CONNECT( THEDP, toolBarConfUpdated(), this, toolBarConfUpdated() );
    installEventFilter( this );
227

228 229
    CONNECT( this, askToQuit(), THEDP, quit() );

230
    CONNECT( this, askBoss(), this, setBoss() );
231
    CONNECT( this, askRaise(), this, setRaise() );
232

233 234 235
    /** END of CONNECTS**/


236 237 238
    /************
     * Callbacks
     ************/
239
    var_AddCallback( p_intf->p_libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
240
    var_AddCallback( p_intf->p_libvlc, "intf-boss", IntfBossCB, p_intf );
241
    var_AddCallback( p_intf->p_libvlc, "intf-show", IntfRaiseMainCB, p_intf );
242 243 244 245

    /* Register callback for the intf-popupmenu variable */
    var_AddCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );

246

247
    /* Final Sizing, restoration and placement of the interface */
248
    if( settings->value( "MainWindow/playlist-visible", false ).toBool() )
249 250
        togglePlaylist();

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
251
    QVLCTools::restoreWidgetPosition( settings, this, QSize(600, 420) );
252

253 254
    b_interfaceFullScreen = isFullScreen();

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
255
    setVisible( !b_hideAfterCreation );
256

257
    /* Switch to minimal view if needed, must be called after the show() */
258
    if( b_minimalView )
259
        toggleMinimalView( true );
260 261

    computeMinimumSize();
262 263 264 265
}

MainInterface::~MainInterface()
{
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
266
    /* Unsure we hide the videoWidget before destroying it */
267
    if( stackCentralOldWidget == videoWidget )
268
        showTab( bgWidget );
269

270 271
    if( videoWidget )
        releaseVideoSlot();
272

273
#ifdef _WIN32
274 275
    if( himl )
        ImageList_Destroy( himl );
276
    if(p_taskbl)
277
        p_taskbl->Release();
278 279 280
    CoUninitialize();
#endif

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
281
    /* Be sure to kill the actionsManager... Only used in the MI and control */
282 283
    ActionsManager::killInstance();

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
284
    /* Delete the FSC controller */
285
    delete fullscreenControls;
286

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
287
    /* Save states */
288

289
    settings->beginGroup("MainWindow");
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
290
    settings->setValue( "pl-dock-status", b_plDocked );
291

292
    /* Save playlist state */
293
    settings->setValue( "playlist-visible", playlistVisible );
294

295
    settings->setValue( "adv-controls",
296
                        getControlsVisibilityStatus() & CONTROLS_ADVANCED );
297
    settings->setValue( "status-bar-visible", b_statusbarVisible );
298

299 300 301
    /* Save the stackCentralW sizes */
    settings->setValue( "bgSize", stackWidgetsSizes[bgWidget] );
    settings->setValue( "playlistSize", stackWidgetsSizes[playlistWidget] );
302
    settings->endGroup();
303

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
304
    /* Save this size */
305
    QVLCTools::saveWidgetPosition(settings, this);
306

307 308
    delete statusBar();

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
309
    /* Unregister callbacks */
310
    var_DelCallback( p_intf->p_libvlc, "intf-boss", IntfBossCB, p_intf );
311
    var_DelCallback( p_intf->p_libvlc, "intf-show", IntfRaiseMainCB, p_intf );
312
    var_DelCallback( p_intf->p_libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
313
    var_DelCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
314

315
    p_intf->p_sys->p_mi = NULL;
316 317
}

318 319
void MainInterface::computeMinimumSize()
{
320
    int minWidth = 80;
321
    if( menuBar()->isVisible() )
322
        minWidth += controls->sizeHint().width();
323 324 325 326

    setMinimumWidth( minWidth );
}

327 328 329
/*****************************
 *   Main UI handling        *
 *****************************/
330 331
void MainInterface::recreateToolbars()
{
332 333
    bool b_adv = getControlsVisibilityStatus() & CONTROLS_ADVANCED;

334 335
    delete controls;
    delete inputC;
336

337
    controls = new ControlsWidget( p_intf, b_adv, this );
338
    inputC = new InputControlsWidget( p_intf, this );
339
    mainLayout->insertWidget( 2, inputC );
340
    mainLayout->insertWidget( settings->value( "MainWindow/ToolbarPos", 0 ).toInt() ? 0: 3,
341
                              controls );
342

343 344 345 346 347 348
    if( fullscreenControls )
    {
        delete fullscreenControls;
        fullscreenControls = new FullscreenControllerWidget( p_intf, this );
        CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
                 this, handleKeyPress( QKeyEvent * ) );
349
        THEMIM->requestVoutUpdate();
350
    }
351 352

    setMinimalView( b_minimalView );
353 354
}

355 356
void MainInterface::reloadPrefs()
{
357
    i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
358
    b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
359
#ifdef _WIN32
360 361 362 363 364 365 366 367 368
    p_intf->p_sys->disable_volume_keys = var_InheritBool( p_intf, "qt-disable-volume-keys" );
#endif
    if( !var_InheritBool( p_intf, "qt-fs-controller" ) && fullscreenControls )
    {
        delete fullscreenControls;
        fullscreenControls = NULL;
    }
}

369
void MainInterface::createMainWidget( QSettings *creationSettings )
370
{
371
    /* Create the main Widget and the mainLayout */
372
    QWidget *main = new QWidget;
373
    setCentralWidget( main );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
374
    mainLayout = new QVBoxLayout( main );
375
    main->setContentsMargins( 0, 0, 0, 0 );
376
    mainLayout->setSpacing( 0 ); mainLayout->setMargin( 0 );
377

378
    /* */
379
    stackCentralW = new QVLCStackedWidget( main );
380

381
    /* Bg Cone */
382 383 384 385 386 387 388 389 390
    if ( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY
         && var_InheritBool( p_intf, "qt-icon-change" ) )
    {
        bgWidget = new EasterEggBackgroundWidget( p_intf );
        CONNECT( this, kc_pressed(), bgWidget, animate() );
    }
    else
        bgWidget = new BackgroundWidget( p_intf );

391
    stackCentralW->addWidget( bgWidget );
392 393 394 395 396
    if ( !var_InheritBool( p_intf, "qt-bgcone" ) )
        bgWidget->setWithArt( false );
    else
        if ( var_InheritBool( p_intf, "qt-bgcone-expands" ) )
            bgWidget->setExpandstoHeight( true );
397

398
    /* And video Outputs */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
399
    if( b_videoEmbedded )
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
400
    {
401
        videoWidget = new VideoWidget( p_intf );
402
        stackCentralW->addWidget( videoWidget );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
403
    }
404
    mainLayout->insertWidget( 1, stackCentralW );
405

406 407
    stackWidgetsSizes[bgWidget] =
        creationSettings->value( "MainWindow/bgSize", QSize( 600, 0 ) ).toSize();
408 409
    /* Resize even if no-auto-resize, because we are at creation */
    resizeStack( stackWidgetsSizes[bgWidget].width(), stackWidgetsSizes[bgWidget].height() );
Jakob Leben's avatar
Jakob Leben committed
410

411 412
    /* Create the CONTROLS Widget */
    controls = new ControlsWidget( p_intf,
413
        creationSettings->value( "MainWindow/adv-controls", false ).toBool(), this );
414 415
    inputC = new InputControlsWidget( p_intf, this );

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
416
    mainLayout->insertWidget( 2, inputC );
417 418 419
    mainLayout->insertWidget(
        creationSettings->value( "MainWindow/ToolbarPos", 0 ).toInt() ? 0: 3,
        controls );
420

421
    /* Visualisation, disabled for now, they SUCK */
422 423 424 425 426 427
    #if 0
    visualSelector = new VisualSelector( p_intf );
    mainLayout->insertWidget( 0, visualSelector );
    visualSelector->hide();
    #endif

428

429 430 431
    /* Enable the popup menu in the MI */
    main->setContextMenuPolicy( Qt::CustomContextMenu );
    CONNECT( main, customContextMenuRequested( const QPoint& ),
432
             THEDP, setPopupMenu() );
433

434 435 436 437 438 439 440 441
    if ( depth() > 8 ) /* 8bit depth has too many issues with opacity */
        /* Create the FULLSCREEN CONTROLS Widget */
        if( var_InheritBool( p_intf, "qt-fs-controller" ) )
        {
            fullscreenControls = new FullscreenControllerWidget( p_intf, this );
            CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
                     this, handleKeyPress( QKeyEvent * ) );
        }
Clément Stenac's avatar
Clément Stenac committed
442 443
}

444 445 446
inline void MainInterface::initSystray()
{
    bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
447
    bool b_systrayWanted = var_InheritBool( p_intf, "qt-system-tray" );
448

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
449
    if( var_InheritBool( p_intf, "qt-start-minimized") )
450 451 452 453 454 455 456 457 458 459 460 461 462 463
    {
        if( b_systrayAvailable )
        {
            b_systrayWanted = true;
            b_hideAfterCreation = true;
        }
        else
            msg_Err( p_intf, "cannot start minimized without system tray bar" );
    }

    if( b_systrayAvailable && b_systrayWanted )
        createSystray();
}

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
464 465 466 467 468 469 470 471 472
inline void MainInterface::createStatusBar()
{
    /****************
     *  Status Bar  *
     ****************/
    /* Widgets Creation*/
    QStatusBar *statusBarr = statusBar();

    TimeLabel *timeLabel = new TimeLabel( p_intf );
473
    nameLabel = new ClickableQLabel();
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
474 475
    nameLabel->setTextInteractionFlags( Qt::TextSelectableByMouse
                                      | Qt::TextSelectableByKeyboard );
476
    SpeedLabel *speedLabel = new SpeedLabel( p_intf, this );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
477 478 479 480 481

    /* Styling those labels */
    timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
    speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
    nameLabel->setFrameStyle( QFrame::Sunken | QFrame::StyledPanel);
482 483 484 485
    timeLabel->setStyleSheet(
            "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
    speedLabel->setStyleSheet(
            "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
486 487
    /* pad both label and its tooltip */
    nameLabel->setStyleSheet( "padding-left: 5px; padding-right: 5px;" );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
488 489 490 491 492 493

    /* and adding those */
    statusBarr->addWidget( nameLabel, 8 );
    statusBarr->addPermanentWidget( speedLabel, 0 );
    statusBarr->addPermanentWidget( timeLabel, 0 );

494
    CONNECT( nameLabel, doubleClicked(), THEDP, epgDialog() );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
495 496 497 498
    /* timeLabel behaviour:
       - double clicking opens the goto time dialog
       - right-clicking and clicking just toggle between remaining and
         elapsed time.*/
499
    CONNECT( timeLabel, doubleClicked(), THEDP, gotoTimeDialog() );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
500 501 502

    CONNECT( THEMIM->getIM(), encryptionChanged( bool ),
             this, showCryptedLabel( bool ) );
503

504 505
    CONNECT( THEMIM->getIM(), seekRequested( float ),
             timeLabel, setDisplayPosition( float ) );
506 507 508 509 510 511 512 513

    /* This shouldn't be necessary, but for somehow reason, the statusBarr
       starts at height of 20px and when a text is shown it needs more space.
       But, as the QMainWindow policy doesn't allow statusBar to change QMW's
       geometry, we need to force a height. If you have a better idea, please
       tell me -- jb
     */
    statusBarr->setFixedHeight( statusBarr->sizeHint().height() + 2 );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
514 515
}

516
/**********************************************************************
517
 * Handling of sizing of the components
518
 **********************************************************************/
519

520 521
void MainInterface::debug()
{
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
522
#ifdef DEBUG_INTF
523 524 525 526 527 528
    if( controls ) {
        msg_Dbg( p_intf, "Controls size: %i - %i", controls->size().height(), controls->size().width() );
        msg_Dbg( p_intf, "Controls minimumsize: %i - %i", controls->minimumSize().height(), controls->minimumSize().width() );
        msg_Dbg( p_intf, "Controls sizeHint: %i - %i", controls->sizeHint().height(), controls->sizeHint().width() );
    }

529 530
    msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
    msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
531
    msg_Dbg( p_intf, "minimumsize: %i - %i", minimumSize().height(), minimumSize().width() );
532

533
    msg_Dbg( p_intf, "Stack size: %i - %i", stackCentralW->size().height(), stackCentralW->size().width() );
534
    msg_Dbg( p_intf, "Stack sizeHint: %i - %i", stackCentralW->sizeHint().height(), stackCentralW->sizeHint().width() );
535
    msg_Dbg( p_intf, "Central size: %i - %i", centralWidget()->size().height(), centralWidget()->size().width() );
536
#endif
537 538
}

539
inline void MainInterface::showVideo() { showTab( videoWidget ); setRaise(); }
540 541
inline void MainInterface::restoreStackOldWidget()
            { showTab( stackCentralOldWidget ); }
542 543

inline void MainInterface::showTab( QWidget *widget )
544
{
545
    if ( !widget ) widget = bgWidget; /* trying to restore a null oldwidget */
546
#ifdef DEBUG_INTF
547 548 549 550 551
    if ( stackCentralOldWidget )
        msg_Dbg( p_intf, "Old stackCentralOldWidget %s at index %i",
                 stackCentralOldWidget->metaObject()->className(),
                 stackCentralW->indexOf( stackCentralOldWidget ) );
    msg_Dbg( p_intf, "ShowTab request for %s", widget->metaObject()->className() );
552
#endif
François Cartegnie's avatar
typo  
François Cartegnie committed
553
    /* fixing when the playlist has been undocked after being hidden.
554 555 556 557
       restoreStackOldWidget() is called when video stops but
       stackCentralOldWidget would still be pointing to playlist */
    if ( widget == playlistWidget && !isPlDocked() )
        widget = bgWidget;
558

559
    stackCentralOldWidget = stackCentralW->currentWidget();
560 561
    stackWidgetsSizes[stackCentralOldWidget] = stackCentralW->size();

562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
    /* If we are playing video, embedded */
    if( videoWidget && THEMIM->getIM()->hasVideo() )
    {
        /* Video -> Playlist */
        if( videoWidget == stackCentralOldWidget && widget == playlistWidget )
        {
            stackCentralW->removeWidget( videoWidget );
            videoWidget->show(); videoWidget->raise();
        }

        /* Playlist -> Video */
        if( playlistWidget == stackCentralOldWidget && widget == videoWidget )
        {
            playlistWidget->artContainer->removeWidget( videoWidget );
            videoWidget->show(); videoWidget->raise();
            stackCentralW->addWidget( videoWidget );
        }
579 580 581 582

        /* Embedded playlist -> Non-embedded playlist */
        if( bgWidget == stackCentralOldWidget && widget == videoWidget )
        {
583 584 585
            /* In rare case when video is started before the interface */
            if( playlistWidget != NULL )
                playlistWidget->artContainer->removeWidget( videoWidget );
586 587 588 589
            videoWidget->show(); videoWidget->raise();
            stackCentralW->addWidget( videoWidget );
            stackCentralW->setCurrentWidget( videoWidget );
        }
590 591
    }

592
    stackCentralW->setCurrentWidget( widget );
593 594
    if( b_autoresize )
        resizeStack( stackWidgetsSizes[widget].width(), stackWidgetsSizes[widget].height() );
595

596
#ifdef DEBUG_INTF
597 598 599 600 601 602
    msg_Dbg( p_intf, "Stack state changed to %s, index %i",
              stackCentralW->currentWidget()->metaObject()->className(),
              stackCentralW->currentIndex() );
    msg_Dbg( p_intf, "New stackCentralOldWidget %s at index %i",
              stackCentralOldWidget->metaObject()->className(),
              stackCentralW->indexOf( stackCentralOldWidget ) );
603
#endif
604 605 606 607 608 609 610 611

    /* This part is done later, to account for the new pl size */
    if( videoWidget && THEMIM->getIM()->hasVideo() &&
        videoWidget == stackCentralOldWidget && widget == playlistWidget )
    {
        playlistWidget->artContainer->addWidget( videoWidget );
        playlistWidget->artContainer->setCurrentWidget( videoWidget );
    }
612
}
613

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
614 615 616 617
void MainInterface::toggleFSC()
{
   if( !fullscreenControls ) return;

618
   IMEvent *eShow = new IMEvent( IMEvent::FullscreenControlToggle );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
619 620 621
   QApplication::postEvent( fullscreenControls, eShow );
}

622 623 624
/****************************************************************************
 * Video Handling
 ****************************************************************************/
625

626
/**
627
 * NOTE:
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
628 629
 * You must not change the state of this object or other Qt UI objects,
 * from the video output thread - only from the Qt UI main loop thread.
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647
 * All window provider queries must be handled through signals or events.
 * That's why we have all those emit statements...
 */
WId MainInterface::getVideo( int *pi_x, int *pi_y,
                             unsigned int *pi_width, unsigned int *pi_height )
{
    if( !videoWidget )
        return 0;

    /* This is a blocking call signal. Results are returned through pointers.
     * Beware of deadlocks! */
    WId id;
    emit askGetVideo( &id, pi_x, pi_y, pi_width, pi_height );
    return id;
}

void MainInterface::getVideoSlot( WId *p_id, int *pi_x, int *pi_y,
                                  unsigned *pi_width, unsigned *pi_height )
648
{
649 650 651 652
    /* Hidden or minimized, activate */
    if( isHidden() || isMinimized() )
        toggleUpdateSystrayMenu();

653
    /* Request the videoWidget */
654
    WId ret = videoWidget->request( pi_x, pi_y,
655
                                    pi_width, pi_height, !b_autoresize );
656
    *p_id = ret;
657
    if( ret ) /* The videoWidget is available */
658
    {
659
        /* Consider the video active now */
660
        showVideo();
661 662 663 664

        /* Ask videoWidget to resize correctly, if we are in normal mode */
        if( !isFullScreen() && !isMaximized() && b_autoresize )
            videoWidget->SetSizing( *pi_width, *pi_height );
665
    }
666 667
}

668
/* Asynchronous call from the WindowClose function */
669
void MainInterface::releaseVideo( void )
670
{
671
    emit askReleaseVideo();
672 673
}

674
/* Function that is CONNECTED to the previous emit */
675
void MainInterface::releaseVideoSlot( void )
676
{
677 678
    /* This function is called when the embedded video window is destroyed,
     * or in the rare case that the embedded window is still here but the
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
679
     * Qt interface exits. */
680 681
    assert( videoWidget );
    videoWidget->release();
682
    setVideoOnTop( false );
683
    setVideoFullScreen( false );
Clément Stenac's avatar
Clément Stenac committed
684

Jakob Leben's avatar
Jakob Leben committed
685 686
    if( stackCentralW->currentWidget() == videoWidget )
        restoreStackOldWidget();
687 688
    else if( playlistWidget &&
             playlistWidget->artContainer->currentWidget() == videoWidget )
689 690 691 692
    {
        playlistWidget->artContainer->setCurrentIndex( 0 );
        stackCentralW->addWidget( videoWidget );
    }
Clément Stenac's avatar
Clément Stenac committed
693

694 695
    /* We don't want to have a blank video to popup */
    stackCentralOldWidget = bgWidget;
696 697
}

698 699
void MainInterface::setVideoSize( unsigned int w, unsigned int h )
{
700 701
    if( !isFullScreen() && !isMaximized() )
        videoWidget->SetSizing( w, h );
702 703
}

704 705 706 707 708 709
void MainInterface::videoSizeChanged( int w, int h )
{
    if( !playlistWidget || playlistWidget->artContainer->currentWidget() != videoWidget )
        resizeStack( w, h );
}

710 711 712
void MainInterface::setVideoFullScreen( bool fs )
{
    b_videoFullScreen = fs;
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
    if( fs )
    {
        int numscreen = var_InheritInteger( p_intf, "qt-fullscreen-screennumber" );
        /* if user hasn't defined screennumber, or screennumber that is bigger
         * than current number of screens, take screennumber where current interface
         * is
         */
        if( numscreen == -1 || numscreen > QApplication::desktop()->numScreens() )
            numscreen = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );

        QRect screenres = QApplication::desktop()->screenGeometry( numscreen );

        /* To be sure window is on proper-screen in xinerama */
        if( !screenres.contains( pos() ) )
        {
            msg_Dbg( p_intf, "Moving video to correct screen");
            move( QPoint( screenres.x(), screenres.y() ) );
        }
731 732

        /* */
Edward Wang's avatar
Edward Wang committed
733
        if( playlistWidget != NULL && playlistWidget->artContainer->currentWidget() == videoWidget )
734 735 736 737 738
        {
            showTab( videoWidget );
        }

        /* */
739 740 741 742 743 744 745 746 747 748 749
        setMinimalView( true );
        setInterfaceFullScreen( true );
    }
    else
    {
        /* TODO do we want to restore screen and position ? (when
         * qt-fullscreen-screennumber is forced) */
        setMinimalView( b_minimalView );
        setInterfaceFullScreen( b_interfaceFullScreen );
    }
    videoWidget->sync();
750 751
}

752 753 754 755 756 757
/* Slot to change the video always-on-top flag.
 * Emit askVideoOnTop() to invoke this from other thread. */
void MainInterface::setVideoOnTop( bool on_top )
{
    Qt::WindowFlags oldflags = windowFlags(), newflags;

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
758
    if( on_top )
759 760 761
        newflags = oldflags | Qt::WindowStaysOnTopHint;
    else
        newflags = oldflags & ~Qt::WindowStaysOnTopHint;
762
    if( newflags != oldflags && !b_videoFullScreen )
763 764 765 766 767 768 769

    {
        setWindowFlags( newflags );
        show(); /* necessary to apply window flags */
    }
}

770
/* Asynchronous call from WindowControl function */
771
int MainInterface::controlVideo( int i_query, va_list args )
772 773 774
{
    switch( i_query )
    {
775 776 777 778
    case VOUT_WINDOW_SET_SIZE:
    {
        unsigned int i_width  = va_arg( args, unsigned int );
        unsigned int i_height = va_arg( args, unsigned int );
779

780
        emit askVideoToResize( i_width, i_height );
781
        return VLC_SUCCESS;
782
    }
783
    case VOUT_WINDOW_SET_STATE:
784
    {
785 786
        unsigned i_arg = va_arg( args, unsigned );
        unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
787 788

        emit askVideoOnTop( on_top != 0 );
789 790
        return VLC_SUCCESS;
    }
791 792 793
    case VOUT_WINDOW_SET_FULLSCREEN:
    {
        bool b_fs = va_arg( args, int );
794

795 796 797
        emit askVideoSetFullScreen( b_fs );
        return VLC_SUCCESS;
    }
798 799 800
    default:
        msg_Warn( p_intf, "unsupported control query" );
        return VLC_EGENERIC;
801 802 803
    }
}

804 805 806 807 808 809
/*****************************************************************************
 * Playlist, Visualisation and Menus handling
 *****************************************************************************/
/**
 * Toggle the playlist widget or dialog
 **/
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
810
void MainInterface::createPlaylist()
811
{
812
    PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
813

814 815
    if( b_plDocked )
    {
816
        playlistWidget = dialog->exportPlaylistWidget();
817
        stackCentralW->addWidget( playlistWidget );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
818
        stackWidgetsSizes[playlistWidget] = settings->value( "playlistSize", QSize( 600, 300 ) ).toSize();
819
    }
820
    CONNECT( dialog, visibilityChanged(bool), this, setPlaylistVisibility(bool) );
821
}
822

823 824
void MainInterface::togglePlaylist()
{
825
    if( !playlistWidget ) createPlaylist();
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
826

827
    PlaylistDialog *dialog = PlaylistDialog::getInstance( p_intf );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
828
    if( b_plDocked )
829
    {
830 831
        if ( dialog->hasPlaylistWidget() )
            playlistWidget = dialog->exportPlaylistWidget();
832 833 834
        /* Playlist is not visible, show it */
        if( stackCentralW->currentWidget() != playlistWidget )
        {
835 836
            if( stackCentralW->indexOf( playlistWidget ) == -1 )
                stackCentralW->addWidget( playlistWidget );
<