main_interface.cpp 47.8 KB
Newer Older
zorglub's avatar
zorglub committed
1
/*****************************************************************************
zorglub's avatar
Wtf ?    
zorglub committed
2
 * main_interface.cpp : Main interface
zorglub's avatar
zorglub committed
3
 ****************************************************************************
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2006-2009 the VideoLAN team
5
 * $Id$
zorglub's avatar
zorglub committed
6
7
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
8
 *          Jean-Baptiste Kempf <jb@videolan.org>
9
 *          Ilkka Ollakka <ileoo@videolan.org>
zorglub's avatar
zorglub committed
10
11
12
13
14
15
16
17
18
19
20
21
22
 *
 * 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
23
 * 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
zorglub's avatar
zorglub committed
29

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

zorglub's avatar
zorglub committed
32
#include "main_interface.hpp"
zorglub's avatar
zorglub committed
33
#include "input_manager.hpp"
34
#include "actions_manager.hpp"
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
35

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

39
#include "components/interface_widgets.hpp"
40
#include "components/controller.hpp"
41
#include "components/playlist/playlist.hpp"
42
#include "dialogs/external.hpp"
43
#include "dialogs/firstrun.hpp"
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
44

45
#include "menus.hpp"
Ludovic Fauvet's avatar
Ludovic Fauvet committed
46
#include "recents.hpp"
47

zorglub's avatar
zorglub committed
48
#include <QCloseEvent>
49
#include <QKeyEvent>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
50

zorglub's avatar
zorglub committed
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
54
#include <QDate>

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

63
64
65
66
67
#ifdef WIN32
 #include <vlc_windows_interfaces.h>
 #include <QBitmap>
#endif

68
#include <assert.h>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
69
70

#include <vlc_keys.h> /* Wheel event */
71
#include <vlc_vout_window.h>
72
#include <vlc_vout_display.h>
zorglub's avatar
zorglub committed
73

74
// #define DEBUG_INTF
75
76
77
78
79
/* 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 );
zorglub's avatar
zorglub committed
80

zorglub's avatar
zorglub committed
81
MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf )
zorglub's avatar
zorglub committed
82
{
83
    /* Variables initialisation */
84
    // need_components_update = false;
85
86
87
    bgWidget             = NULL;
    videoWidget          = NULL;
    playlistWidget       = NULL;
88
#ifndef HAVE_MAEMO
89
    sysTray              = NULL;
90
#endif
91
    fullscreenControls   = NULL;
92
    cryptedLabel         = NULL;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
93
94
    controls             = NULL;
    inputC               = NULL;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
95
96
97
98

    b_hideAfterCreation  = false;
    playlistVisible      = false; // FIXME remove
    input_name           = "";
99

100
101
    i_bg_height          = 0;

102
    /* Ask for Privacy */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
103
    FirstRun::CheckAndRun( this, p_intf );
104

105
    /**
106
     *  Configuration and settings
107
     *  Pre-building of interface
108
     **/
109
110
    /* Main settings */
    setFocusPolicy( Qt::StrongFocus );
111
    setAcceptDrops( true );
Nick Pope's avatar
Nick Pope committed
112
    setWindowRole( "vlc-main" );
113
    setWindowIcon( QApplication::windowIcon() );
114
    setWindowOpacity( config_GetFloat( p_intf, "qt-opacity" ) );
115
116

    /* Set The Video In emebedded Mode or not */
117
    videoEmbeddedFlag = config_GetInt( p_intf, "embedded-video" );
zorglub's avatar
zorglub committed
118

119
120
    /* Does the interface resize to video size or the opposite */
    b_keep_size = !config_GetInt( p_intf, "qt-video-autoresize" );
121

122
    /* Are we in the enhanced always-video mode or not ? */
123
    i_visualmode = config_GetInt( p_intf, "qt-display-mode" );
zorglub's avatar
zorglub committed
124

125
    /* Do we want anoying popups or not */
126
127
    notificationEnabled = (bool)config_GetInt( p_intf, "qt-notification" );

128
    /* Set the other interface settings */
129
    settings = getSettings();
130
131
    settings->beginGroup( "MainWindow" );

132
133
134
135
136
137
138
139
140
    /**
     * Retrieve saved sizes for main window
     *   mainBasedSize = based window size for normal mode
     *                  (no video, no background)
     *   mainVideoSize = window size with video (all modes)
     **/
    mainBasedSize = settings->value( "mainBasedSize", QSize( 350, 120 ) ).toSize();
    mainVideoSize = settings->value( "mainVideoSize", QSize( 400, 300 ) ).toSize();

141

142
143
144
145
146
    /**************
     * Status Bar *
     **************/
    createStatusBar();

147
148
149
    /**************************
     *  UI and Widgets design
     **************************/
150
    setVLCWindowsTitle();
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
151
    createMainWidget( settings );
152

153
154
155
    /************
     * Menu Bar *
     ************/
156
    QVLCMenu::createMenuBar( this, p_intf );
157
158
    CONNECT( THEMIM->getIM(), voutListChanged( vout_thread_t **, int ),
             this, destroyPopupMenu() );
159

160
161
162
163
164
    /*********************************
     * Create the Systray Management *
     *********************************/
    initSystray();

165
166
167
168
    /********************
     * Input Manager    *
     ********************/
    MainInputManager::getInstance( p_intf );
169

170
#ifdef WIN32
171
    taskbar_wmsg = RegisterWindowMessage("TaskbarButtonCreated");
172
173
#endif

174
175
176
    /************************************************************
     * Connect the input manager to the GUI elements it manages *
     ************************************************************/
177
178
    /**
     * Connects on nameChanged()
179
180
181
     * Those connects are different because options can impeach them to trigger.
     **/
    /* Main Interface statusbar */
ivoire's avatar
ivoire committed
182
183
    CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
             this, setName( const QString& ) );
184
    /* and systray */
185
#ifndef HAVE_MAEMO
186
    if( sysTray )
187
    {
188
189
        CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
                 this, updateSystrayTooltipName( const QString& ) );
190
    }
191
#endif
192
    /* and title of the Main Interface*/
193
194
    if( config_GetInt( p_intf, "qt-name-in-title" ) )
    {
195
196
        CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
                 this, setVLCWindowsTitle( const QString& ) );
197
198
    }

199
    /**
200
     * CONNECTS on PLAY_STATUS
201
     **/
202
    /* Status on the systray */
203
#ifndef HAVE_MAEMO
204
    if( sysTray )
205
    {
206
207
        CONNECT( THEMIM->getIM(), statusChanged( int ),
                 this, updateSystrayTooltipStatus( int ) );
208
    }
209
#endif
210

211
212
    /* END CONNECTS ON IM */

213
    /************
214
     * Callbacks
215
     ************/
216
217
    var_AddCallback( p_intf->p_libvlc, "intf-show", IntfShowCB, p_intf );

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

221

222
223
224
225
    /* VideoWidget connects for asynchronous calls */
    connect( this, SIGNAL(askGetVideo(WId*,int*,int*,unsigned*,unsigned *)),
             this, SLOT(getVideoSlot(WId*,int*,int*,unsigned*,unsigned*)),
             Qt::BlockingQueuedConnection );
226
    connect( this, SIGNAL(askReleaseVideo( void )),
227
228
             this, SLOT(releaseVideoSlot( void )),
             Qt::BlockingQueuedConnection );
229

230
    if( videoWidget )
231
    {
232
233
        CONNECT( this, askVideoToResize( unsigned int, unsigned int ),
                 videoWidget, SetSizing( unsigned int, unsigned int ) );
234
235
        CONNECT( this, askVideoSetFullScreen( bool ),
                 videoWidget, SetFullScreen( bool ) );
236
237
        CONNECT( videoWidget, keyPressed( QKeyEvent * ),
                 this, handleKeyPress( QKeyEvent * ) );
238
239
    }

240
    CONNECT( this, askUpdate(), this, doComponentsUpdate() );
241
    CONNECT( THEDP, toolBarConfUpdated(), this, recreateToolbars() );
242

243
244
245
246
247
248
249
250
251
        /* Enable the popup menu in the MI */
    setContextMenuPolicy( Qt::CustomContextMenu );
    CONNECT( this, customContextMenuRequested( const QPoint& ),
             this, popupMenu( const QPoint& ) );

    /** END of CONNECTS**/


    /**** FINAL SIZING and placement of interface */
252
    settings->beginGroup( "MainWindow" );
253
    QVLCTools::restoreWidgetPosition( settings, this, QSize(380, 60) );
254

255
    /* resize to previously saved main window size if appicable */
256
257
258
259
260
261
262
263
264
265
266
267
268
    if( b_keep_size )
    {
       if( i_visualmode == QT_ALWAYS_VIDEO_MODE ||
           i_visualmode == QT_MINIMAL_MODE )
       {
           resize( mainVideoSize );
       }
       else
       {
           resize( mainBasedSize );
       }
    }

269
    msg_Dbg( p_intf, "%i", stackCentralOldState );
270
    /* Playlist */
271
272
273
    if( settings->value( "playlist-visible", 0 ).toInt() )
        togglePlaylist();
    settings->endGroup();
274

275
    /* Final sizing and showing */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
276
    setVisible( !b_hideAfterCreation );
277
    //setMinimumSize( QSize( 0, 0 ) );
278
279
    //    setMinimumWidth( __MAX( controls->sizeHint().width(),
    //                          menuBar()->sizeHint().width() ) );
280

281
    debug();
282
283
    /* And switch to minimal view if needed
       Must be called after the show() */
284
    if( i_visualmode == QT_MINIMAL_MODE )
285
        toggleMinimalView( true );
286

287
    /* Update the geometry : It is useful if you switch between
288
       qt-display-modes */
289
    updateGeometry();
290
    resize( sizeHint() );
291
292
293
294
}

MainInterface::~MainInterface()
{
295
296
    msg_Dbg( p_intf, "Destroying the main interface" );

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
297
    /* Unsure we hide the videoWidget before destroying it */
298
    if( stackCentralOldState == VIDEO_TAB )
299
        showBg();
300

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
301
    /* Save playlist state */
302
    if( playlistWidget )
303
304
305
    {
        if( !isDocked() )
            QVLCTools::saveWidgetPosition( p_intf, "Playlist", playlistWidget );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
306
307

        delete playlistWidget;
308
    }
309

310
#ifdef WIN32
311
312
    if( himl )
        ImageList_Destroy( himl );
313
314
315
316
317
    if(p_taskbl)
        p_taskbl->vt->Release(p_taskbl);
    CoUninitialize();
#endif

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
318
    /* Be sure to kill the actionsManager... FIXME */
319
320
    ActionsManager::killInstance();

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
321
    /* Delete the FSC controller */
322
    delete fullscreenControls;
323

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
324
    /* Save states */
325
    settings->beginGroup( "MainWindow" );
326
    settings->setValue( "pl-dock-status", (int)i_pl_dock );
327
    settings->setValue( "playlist-visible", (int)playlistVisible );
328
    settings->setValue( "adv-controls",
329
                        getControlsVisibilityStatus() & CONTROLS_ADVANCED );
330

331
332
333
    settings->setValue( "mainBasedSize", mainBasedSize );
    settings->setValue( "mainVideoSize", mainVideoSize );

334
335
    if( bgWidget )
        settings->setValue( "backgroundSize", bgWidget->size() );
336

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
337
    /* Save this size */
338
    QVLCTools::saveWidgetPosition(settings, this);
339
340
    settings->endGroup();

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
341
342
    /* Unregister callbacks */
    var_DelCallback( p_intf->p_libvlc, "intf-show", IntfShowCB, p_intf );
343
    var_DelCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
344

345
    p_intf->p_sys->p_mi = NULL;
346
347
}

348
349
350
/*****************************
 *   Main UI handling        *
 *****************************/
351
352
void MainInterface::recreateToolbars()
{
353
    //msg_Dbg( p_intf, "Recreating the toolbars" );
354
355
356
    settings->beginGroup( "MainWindow" );
    delete controls;
    delete inputC;
357

358
359
360
361
362
    controls = new ControlsWidget( p_intf, false, this ); /* FIXME */
    CONNECT( controls, advancedControlsToggled( bool ),
             this, doComponentsUpdate() );
    CONNECT( controls, sizeChanged(),
             this, doComponentsUpdate() );
363

364
365
    inputC = new InputControlsWidget( p_intf, this );

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
366
367
    mainLayout->insertWidget( 2, inputC );
    mainLayout->insertWidget( settings->value( "ToolbarPos", 0 ).toInt() ? 0: 3,
368
                              controls );
369
370
371
    settings->endGroup();
}

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
372
void MainInterface::createMainWidget( QSettings *settings )
373
{
374
    /* Create the main Widget and the mainLayout */
375
    QWidget *main = new QWidget;
376
    setCentralWidget( main );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
377
    mainLayout = new QVBoxLayout( main );
378

379
380
    /* Margins, spacing */
    main->setContentsMargins( 0, 0, 0, 0 );
381
    mainLayout->setSpacing( 0 ); mainLayout->setMargin( 0 );
382

383
    /* */
384
    stackCentralW = new QStackedWidget( main );
385

386
387
388
389
390
    /* Bg Cone */
    bgWidget = new BackgroundWidget( p_intf );
    bgWidget->resize(
            settings->value( "backgroundSize", QSize( 300, 200 ) ).toSize() );
    bgWidget->updateGeometry();
391
    stackCentralW->insertWidget( BACKG_TAB, bgWidget );
392

393

394
    /* And video Outputs */
395
    if( videoEmbeddedFlag )
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
396
    {
397
        videoWidget = new VideoWidget( p_intf );
398
        stackCentralW->insertWidget( VIDEO_TAB, videoWidget );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
399
    }
400
    mainLayout->insertWidget( 1, stackCentralW, 100 );
401
402


403
404
405
406
407
408
409
410
411
    /* Create the CONTROLS Widget */
    controls = new ControlsWidget( p_intf,
                   settings->value( "adv-controls", false ).toBool(), this );
    CONNECT( controls, advancedControlsToggled( bool ),
             this, doComponentsUpdate() );
    CONNECT( controls, sizeChanged(),
             this, doComponentsUpdate() );
    inputC = new InputControlsWidget( p_intf, this );

412
413
414
415
416
417
418
419
420
421
422
423
    if( i_visualmode != QT_ALWAYS_VIDEO_MODE &&
        i_visualmode != QT_MINIMAL_MODE )
    {
        hideStackWidget();
        stackCentralOldState = HIDDEN_TAB;
    }
    else
    {
        showTab( BACKG_TAB );
        stackCentralOldState = BACKG_TAB;
    }

424

425
    //mainLayout->setRowStretch( 1, 10 );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
426
427
428
    mainLayout->insertWidget( 2, inputC );
    mainLayout->insertWidget( settings->value( "ToolbarPos", 0 ).toInt() ? 0: 3,
                              controls );
429

430
431
432
433
434
435
436
437
    /* Visualisation */
    /* Disabled for now, they SUCK */
    #if 0
    visualSelector = new VisualSelector( p_intf );
    mainLayout->insertWidget( 0, visualSelector );
    visualSelector->hide();
    #endif

438
    /* Finish the sizing */
439
    main->updateGeometry();
440
441
442
443
444
445
446
447

    getSettings()->endGroup();
#ifdef WIN32
    if ( depth() > 8 )
#endif
    /* Create the FULLSCREEN CONTROLS Widget */
    if( config_GetInt( p_intf, "qt-fs-controller" ) )
    {
448
        fullscreenControls = new FullscreenControllerWidget( p_intf, this );
449
450
        CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
                 this, handleKeyPress( QKeyEvent * ) );
451
    }
zorglub's avatar
zorglub committed
452
453
}

454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
inline void MainInterface::initSystray()
{
#ifndef HAVE_MAEMO
    bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
    bool b_systrayWanted = config_GetInt( p_intf, "qt-system-tray" );

    if( config_GetInt( p_intf, "qt-start-minimized") > 0 )
    {
        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();
#endif
}

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
inline void MainInterface::createStatusBar()
{
    /****************
     *  Status Bar  *
     ****************/
    /* Widgets Creation*/
    QStatusBar *statusBarr = statusBar();

    TimeLabel *timeLabel = new TimeLabel( p_intf );
    nameLabel = new QLabel( this );
    nameLabel->setTextInteractionFlags( Qt::TextSelectableByMouse
                                      | Qt::TextSelectableByKeyboard );
    SpeedLabel *speedLabel = new SpeedLabel( p_intf, "1.00x", this );

    /* Styling those labels */
    timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
    speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
    nameLabel->setFrameStyle( QFrame::Sunken | QFrame::StyledPanel);

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

    /* timeLabel behaviour:
       - double clicking opens the goto time dialog
       - right-clicking and clicking just toggle between remaining and
         elapsed time.*/
    CONNECT( timeLabel, timeLabelDoubleClicked(), THEDP, gotoTimeDialog() );

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

510
511
512
#ifdef WIN32
void MainInterface::createTaskBarButtons()
{
513
    taskbar_wmsg = WM_NULL;
514
515
516
517
518
519
    /*Here is the code for the taskbar thumb buttons
    FIXME:We need pretty buttons in 16x16 px that are handled correctly by masks in Qt
    FIXME:the play button's picture doesn't changed to pause when clicked
    */
    OSVERSIONINFO winVer;
    winVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
Geoffroy Couprie's avatar
Geoffroy Couprie committed
520
    if( GetVersionEx(&winVer) && winVer.dwMajorVersion > 5 )
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
    {
        if(himl = ImageList_Create( 15, //cx
                                    18, //cy
                                    ILC_COLOR,//flags
                                    4,//initial nb of images
                                    0//nb of images that can be added
                                    ))
        {
            QPixmap img   = QPixmap(":/toolbar/previous_b");
            QPixmap img2  = QPixmap(":/toolbar/pause_b");
            QPixmap img3  = QPixmap(":/toolbar/play_b");
            QPixmap img4  = QPixmap(":/toolbar/next_b");
            QBitmap mask  = img.createMaskFromColor(Qt::transparent);
            QBitmap mask2 = img2.createMaskFromColor(Qt::transparent);
            QBitmap mask3 = img3.createMaskFromColor(Qt::transparent);
            QBitmap mask4 = img4.createMaskFromColor(Qt::transparent);

            if(-1 == ImageList_Add(himl, img.toWinHBITMAP(QPixmap::PremultipliedAlpha),mask.toWinHBITMAP()))
                msg_Err( p_intf, "ImageList_Add failed" );
            if(-1 == ImageList_Add(himl, img2.toWinHBITMAP(QPixmap::PremultipliedAlpha),mask2.toWinHBITMAP()))
                msg_Err( p_intf, "ImageList_Add failed" );
            if(-1 == ImageList_Add(himl, img3.toWinHBITMAP(QPixmap::PremultipliedAlpha),mask3.toWinHBITMAP()))
                msg_Err( p_intf, "ImageList_Add failed" );
            if(-1 == ImageList_Add(himl, img4.toWinHBITMAP(QPixmap::PremultipliedAlpha),mask4.toWinHBITMAP()))
                msg_Err( p_intf, "ImageList_Add failed" );
        }

        CoInitialize( 0 );

        if( S_OK == CoCreateInstance( &clsid_ITaskbarList,
                    NULL, CLSCTX_INPROC_SERVER,
                    &IID_ITaskbarList3,
                    (void **)&p_taskbl) )
        {
            p_taskbl->vt->HrInit(p_taskbl);

            // Define an array of two buttons. These buttons provide images through an
            // image list and also provide tooltips.
            DWORD dwMask = THB_BITMAP | THB_FLAGS;

ivoire's avatar
ivoire committed
561
            THUMBBUTTON thbButtons[3];
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
            thbButtons[0].dwMask = dwMask;
            thbButtons[0].iId = 0;
            thbButtons[0].iBitmap = 0;
            thbButtons[0].dwFlags = THBF_HIDDEN;

            thbButtons[1].dwMask = dwMask;
            thbButtons[1].iId = 1;
            thbButtons[1].iBitmap = 2;
            thbButtons[1].dwFlags = THBF_HIDDEN;

            thbButtons[2].dwMask = dwMask;
            thbButtons[2].iId = 2;
            thbButtons[2].iBitmap = 3;
            thbButtons[2].dwFlags = THBF_HIDDEN;

577
            HRESULT hr = p_taskbl->vt->ThumbBarSetImageList(p_taskbl, winId(), himl );
578
579
            if(S_OK != hr)
                msg_Err( p_intf, "ThumbBarSetImageList failed with error %08x", hr );
580
581
582
583
584
585
            else
            {
                hr = p_taskbl->vt->ThumbBarAddButtons(p_taskbl, winId(), 3, thbButtons);
                if(S_OK != hr)
                    msg_Err( p_intf, "ThumbBarAddButtons failed with error %08x", hr );
            }
586
            CONNECT( THEMIM->getIM(), statusChanged( int ), this, changeThumbbarButtons( int ) );
587
588
589
            CONNECT( this, playPauseSignal(), THEMIM, togglePlayPause() );
            CONNECT( this, prevSignal(), THEMIM, prev() );
            CONNECT( this, nextSignal(), THEMIM, next() );
590
591
592
593
            CONNECT( this, play(),  ActionsManager::getInstance( p_intf ), play() );
            CONNECT( this, mute(),  ActionsManager::getInstance( p_intf ), toggleMuteAudio() );
            CONNECT( this, volumeUp(),  ActionsManager::getInstance( p_intf ), AudioUp() );
            CONNECT( this, volumeDown(),  ActionsManager::getInstance( p_intf ), AudioDown() );
594
595
596
597
598
599
600
601
        }
    }
    else
    {
        himl = NULL;
        p_taskbl = NULL;
    }
}
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
602

603
604
605
606
607
608
609
bool MainInterface::winEvent ( MSG * msg, long * result )
{
    if (msg->message == taskbar_wmsg)
    {
        //We received the taskbarbuttoncreated, now we can really create th buttons
        createTaskBarButtons();
    }
610
611

    short cmd;
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
    switch( msg->message )
    {
        case WM_COMMAND:
            if (HIWORD(msg->wParam) == THBN_CLICKED)
            {
                switch(LOWORD(msg->wParam))
                {
                    case 0:
                        emit prevSignal();
                        break;
                    case 1:
                        emit playPauseSignal();
                        break;
                    case 2:
                        emit nextSignal();
                        break;
                }
            }
            break;
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
        case WM_APPCOMMAND:
            cmd = GET_APPCOMMAND_LPARAM(msg->lParam);
            msg_Err( p_intf, "button pressed = %d", cmd);
            switch(cmd)
            {
                case APPCOMMAND_MEDIA_PLAY_PAUSE:
                    emit playPauseSignal();
                    break;
                case APPCOMMAND_MEDIA_PLAY:
                    emit play();
                    break;
                case APPCOMMAND_MEDIA_PAUSE:
                    emit pause();
                    break;
                case APPCOMMAND_MEDIA_PREVIOUSTRACK:
                    emit prevSignal();
                    break;
                case APPCOMMAND_MEDIA_NEXTTRACK:
                    emit nextSignal();
                    break;
                case APPCOMMAND_MEDIA_STOP:
                    emit stop();
                    break;
                case APPCOMMAND_VOLUME_DOWN:
                    emit volumeDown();
                    break;
                case APPCOMMAND_VOLUME_UP:
                    emit volumeUp();
                    break;
                case APPCOMMAND_VOLUME_MUTE:
                    emit mute();
                    break;
                default:
                     msg_Dbg( p_intf, "unknown APPCOMMAND = %d", cmd);
                     break;
            }
            break;
668
669
670
671
    }
    return false;
}
#endif
672

673
/**********************************************************************
674
 * Handling of sizing of the components
675
 **********************************************************************/
676
677
678
679
680

/* This function is probably wrong, but we don't have many many choices...
   Since we can't know from the playlist Widget if we are inside a dock or not,
   because the playlist Widget can be called by THEDP, as a separate windows for
   the skins.
681
682
   Maybe the other solution is to redefine the sizeHint() of the playlist and
   ask _parent->isFloating()...
683
   If you think this would be better, please FIXME it...
684
*/
685

686
687
QSize MainInterface::sizeHint() const
{
688
#if 0
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
    if( b_keep_size )
    {
        if( i_visualmode == QT_ALWAYS_VIDEO_MODE ||
            i_visualmode == QT_MINIMAL_MODE )
        {
                return mainVideoSize;
        }
        else
        {
            if( VISIBLE( bgWidget) ||
                ( videoIsActive && videoWidget->isVisible() )
              )
                return mainVideoSize;
            else
                return mainBasedSize;
        }
    }
706
707
708
709
#endif

    int nwidth  = __MAX( controls->sizeHint().width(),
                         menuBar()->sizeHint().width() );
710

711
712
    int nheight = controls->isVisible() ?
                  controls->size().height()
713
                  + inputC->size().height()
714
715
716
                  + menuBar()->size().height()
                  + statusBar()->size().height()
                  : 0 ;
717

718
719
720
721
722
    if( stackCentralW->isVisible() )
        nheight += stackCentralW->height();
        nwidth  = __MAX( nwidth, stackCentralW->width() );

/*    if( VISIBLE( bgWidget ) )
723
    {
724
        msg_Warn( p_intf, "Hello here" );
725
726
727
728
729
        if( i_bg_height )
            nheight += i_bg_height;
        else
            nheight += bgWidget->size().height();
        nwidth  = __MAX( nwidth, bgWidget->size().width() );
730
    }
731
    else if( videoIsActive && videoWidget->isVisible() )
732
    {
733
        msg_Warn( p_intf, "Hello there" );
734
        nheight += videoWidget->sizeHint().height();
735
        nwidth  = __MAX( nwidth, videoWidget->sizeHint().width() );
736
    }*/
737
738
#if 0
    if( !dockPL->isFloating() && dockPL->isVisible() && dockPL->widget()  )
739
740
    {
        nheight += dockPL->size().height();
741
        nwidth = __MAX( nwidth, dockPL->size().width() );
742
        msg_Warn( p_intf, "3 %i %i", nheight, nwidth );
743
744
    }
#endif
745
    return QSize( nwidth, nheight );
746
}
747

748

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
749
750
/* Video widget cannot do this synchronously as it runs in another thread */
/* Well, could it, actually ? Probably dangerous ... */
751

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
752
753
754
755
756
757
/* This function is called:
   - toggling of minimal View
   - through askUpdate() by Vout thread request video and resize video (zoom)
   - Advanced buttons toggled
 */
void MainInterface::doComponentsUpdate()
758
{
759
    if( isFullScreen() || isMaximized() ) return;
760

761
//    msg_Warn( p_intf, "Updating the geometry" );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
762
763
    /* Here we resize to sizeHint() and not adjustsize because we want
       the videoWidget to be exactly the correctSize */
764

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
765
#ifndef NDEBUG
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
766
767
    debug();
#endif
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
768
    /* This is WRONG, but I believe there is a Qt bug here */
769
    setMinimumSize( 0, 0 );
770
    resize( sizeHint() );
771

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
772
    //adjustSize() ; /* This is not needed, but might help in the future */
773
774
}

775
776
void MainInterface::debug()
{
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
777
#ifndef NDEBUG
778
    msg_Dbg( p_intf, "Stack Size: %i - %i", stackCentralW->size().height(), size().width() );
779
780
781
782
783
784
    if( videoEmbeddedFlag )
        msg_Dbg( p_intf, "Stack Size: %i - %i",
                 stackCentralW->widget( VIDEO_TAB )->size().height(),
                 stackCentralW->widget( VIDEO_TAB )->size().width() );
    else
        msg_Dbg( p_intf, "no embedded video" );
785

786
787
    msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
    msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
788
789
790
791
792
    //msg_Dbg( p_intf, "maximumsize: %i - %i", maximumSize().height(), maximumSize().width() );

    msg_Dbg( p_intf, "Stack minimumsize: %i - %i", stackCentralW->minimumSize().height(), stackCentralW->minimumSize().width() );
    msg_Dbg( p_intf, "Controls minimumsize: %i - %i", controls->minimumSize().height(), controls->minimumSize().width() );
    msg_Dbg( p_intf, "Central minimumsize: %i - %i", centralWidget()->minimumSize().height(), centralWidget()->minimumSize().width() );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
793
794
795
    msg_Dbg( p_intf, "Menu minimumsize: %i - %i", menuBar()->minimumSize().height(), menuBar()->minimumSize().width() );
    msg_Dbg( p_intf, "Input minimuSize: %i - %i", inputC->minimumSize().height(), inputC->minimumSize().width() );
    msg_Dbg( p_intf, "Status minimumsize: %i - %i", statusBar()->minimumSize().height(), statusBar()->minimumSize().width() );
796
797
798
    msg_Dbg( p_intf, "minimumsize: %i - %i", minimumSize().height(), minimumSize().width() );

    /*if( videoWidget && videoWidget->isVisible() )
799
    {
800
801
        msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
        msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
802
    }*/
803
#endif
804
805
}

806
807
inline void MainInterface::showTab( int i_tab )
{
808
#ifdef DEBUG_INTF
809
810
    msg_Err( p_intf, "showTab %i", i_tab );
    msg_Warn( p_intf, "Old stackCentralOldState %i", stackCentralOldState );
811
#endif
812
813
    stackCentralOldState = stackCentralW->isVisible() ? stackCentralW->currentIndex()
                                          : HIDDEN_TAB;
814
#ifdef DEBUG_INTF
815
    msg_Warn( p_intf, "State change %i %i",  stackCentralW->currentIndex(), i_tab );
816
#endif
817
818
819
820

    if( i_visualmode == QT_NORMAL_MODE )
    {
        stackCentralW->setVisible( i_tab != HIDDEN_TAB );
821
        doComponentsUpdate(); // resize the player
822
823
824
825
826
    }
    else
        if( i_tab == HIDDEN_TAB ) i_tab == BACKG_TAB;

    stackCentralW->setCurrentIndex( i_tab );
827

828
#ifdef DEBUG_INTF
829
    msg_Warn( p_intf, "New stackCentralOldState %i", stackCentralOldState );
830
#endif
831
832
833
834
}

inline void MainInterface::restoreStackOldWidget()
{
835
#ifdef DEBUG_INTF
836
    msg_Warn( p_intf, "Old stackCentralOldState %i", stackCentralOldState );
837
#endif
838
839
840
841
    int temp = stackCentralW->isVisible() ? stackCentralW->currentIndex()
                                          : HIDDEN_TAB;
    stackCentralW->setCurrentIndex( stackCentralOldState );
    if( i_visualmode == QT_NORMAL_MODE )
842
    {
843
        stackCentralW->setVisible( stackCentralOldState != HIDDEN_TAB );
844
845
        doComponentsUpdate(); // resize the player
    }
846
847

    stackCentralOldState = temp;
848
#ifdef DEBUG_INTF
849
    msg_Warn( p_intf, "Debug %i %i", temp, stackCentralW->currentIndex() );
850
#endif
851
852
}

853
854
void MainInterface::destroyPopupMenu()
{
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
855
    QVLCMenu::PopupMenu( p_intf, false );
856
857
}

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
void MainInterface::toggleFSC()
{
   if( !fullscreenControls ) return;

   IMEvent *eShow = new IMEvent( FullscreenControlToggle_Type, 0 );
   QApplication::postEvent( fullscreenControls, eShow );
}

void MainInterface::popupMenu( const QPoint &p )
{
    /* Ow, that's ugly: don't show the popup menu if cursor over
     * the main menu bar or the status bar */
    if( !childAt( p ) || ( ( childAt( p ) != menuBar() )
                        && ( childAt( p )->parentWidget() != statusBar() ) ) )
        QVLCMenu::PopupMenu( p_intf, true );
}

875
876
877
/****************************************************************************
 * Video Handling
 ****************************************************************************/
878
879
880

/* This event is used to deal with the fullscreen and always on top
   issue conflict (bug in wx) */
881
882
883
884
885
class SetVideoOnTopQtEvent : public QEvent
{
public:
    SetVideoOnTopQtEvent( bool _onTop ) :
      QEvent( (QEvent::Type)SetVideoOnTopEvent_Type ), onTop( _onTop)
886
    {}
887

888
    bool OnTop() const { return onTop; }
889
890
891
892
893

private:
    bool onTop;
};

894
/**
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
 * NOTE:
 * You must note change the state of this object or other Qt4 UI objects,
 * from the video output thread - only from the Qt4 UI main loop thread.
 * 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 )
916
{
917
    /* Request the videoWidget */
918
    WId ret = videoWidget->request( pi_x, pi_y,
919
                                    pi_width, pi_height, b_keep_size );
920
    *p_id = ret;
921
    if( ret ) /* The videoWidget is available */
922
    {
923
        /* ask videoWidget to show */
924
        videoWidget->SetSizing( *pi_width, *pi_height );
925

926
        /* Consider the video active now */
927
928
929
        showVideo();

        stackCentralW->resize( *pi_width, *pi_height );
930

931
        emit askUpdate();
932
    }
933
934
}

935

936

937
/* Asynchronous call from the WindowClose function */
938
void MainInterface::releaseVideo( void )
939
{
940
    emit askReleaseVideo( );
941
942
}

943
/* Function that is CONNECTED to the previous emit */
944
void MainInterface::releaseVideoSlot( void )
945
{
946
    videoWidget->release( );
zorglub's avatar
zorglub committed
947

948
    restoreStackOldWidget();
zorglub's avatar
zorglub committed
949

950
    /* Try to resize, except when you are in Fullscreen mode */
951
//    doComponentsUpdate();
952
953
}

954
/* Asynchronous call from WindowControl function */
955
int MainInterface::controlVideo( int i_query, va_list args )
956
{
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
957
958
    /* Debug to check if VOUT_WINDOW_SET_SIZE is called, because this is broken now */
    msg_Warn( p_intf, "Control Video: %i", i_query );
959
960
    switch( i_query )
    {
961
962
963
964
965
966
    case VOUT_WINDOW_SET_SIZE:
    {
        unsigned int i_width  = va_arg( args, unsigned int );
        unsigned int i_height = va_arg( args, unsigned int );
        emit askVideoToResize( i_width, i_height );
        emit askUpdate();
967
        return VLC_EGENERIC;
968
    }
969
    case VOUT_WINDOW_SET_STATE:
970
    {
971
972
973
        unsigned i_arg = va_arg( args, unsigned );
        unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
        QApplication::postEvent( this, new SetVideoOnTopQtEvent( on_top ) );
974
975
        return VLC_SUCCESS;
    }
976
977
978
979
980
981
    case VOUT_WINDOW_SET_FULLSCREEN:
    {
        bool b_fs = va_arg( args, int );
        emit askVideoSetFullScreen( b_fs );
        return VLC_SUCCESS;
    }
982
983
984
    default:
        msg_Warn( p_intf, "unsupported control query" );
        return VLC_EGENERIC;
985
986
987
    }
}

988
989
990
991
992
993
/*****************************************************************************
 * Playlist, Visualisation and Menus handling
 *****************************************************************************/
/**
 * Toggle the playlist widget or dialog
 **/
994
void MainInterface::createPlaylist( bool b_show )
995
{
996
    playlistWidget = new PlaylistWidget( p_intf, this );
997

998
999
1000
    i_pl_dock = PL_BOTTOM;
    /* i_pl_dock = (pl_dock_e)getSettings()
      ->value( "pl-dock-status", PL_UNDOCKED ).toInt(); */
1001

1002
1003
1004
    if( i_pl_dock == PL_UNDOCKED )
    {
        playlistWidget->setWindowFlags( Qt::Window );
1005

1006
1007
1008
1009
1010
1011
1012
        /* This will restore the geometry but will not work for position,
           because of parenting */
        QVLCTools::restoreWidgetPosition( p_intf, "Playlist",
                playlistWidget, QSize( 600, 300 ) );
    }
    else
    {
1013
#ifdef DEBUG_INTF
1014
        msg_Warn( p_intf, "Here %i", stackCentralW->currentIndex() );
1015
#endif
1016
        stackCentralW->insertWidget( PLAYL_TAB, playlistWidget );