]> git.sesse.net Git - vlc/blob - modules/gui/qt4/main_interface.cpp
Qt4 - Start mode configuration simplification.
[vlc] / modules / gui / qt4 / main_interface.cpp
1 /*****************************************************************************
2  * main_interface.cpp : Main interface
3  ****************************************************************************
4  * Copyright (C) 2006-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@videolan.org>
8  *          Jean-Baptiste Kempf <jb@videolan.org>
9  *          Ilkka Ollakka <ileoo@videolan.org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include "qt4.hpp"
31 #include "main_interface.hpp"
32 #include "input_manager.hpp"
33 #include "util/qvlcframe.hpp"
34 #include "util/customwidgets.hpp"
35 #include "dialogs_provider.hpp"
36 #include "components/interface_widgets.hpp"
37 #include "components/playlist/playlist.hpp"
38 #include "dialogs/extended.hpp"
39 #include "dialogs/playlist.hpp"
40 #include "menus.hpp"
41
42 #include <QMenuBar>
43 #include <QCloseEvent>
44 #include <QPushButton>
45 #include <QStatusBar>
46 #include <QKeyEvent>
47 #include <QUrl>
48 #include <QSystemTrayIcon>
49 #include <QSize>
50 #include <QMenu>
51 #include <QLabel>
52 #include <QSlider>
53 #include <QWidgetAction>
54 #include <QDockWidget>
55 #include <QToolBar>
56 #include <QGroupBox>
57 #include <QDate>
58 #include <QProgressBar>
59
60 #include <assert.h>
61 #include <vlc_keys.h>
62 #include <vlc_vout.h>
63
64 #define SET_WIDTH(i,j) i->widgetSize.setWidth(j)
65 #define SET_HEIGHT(i,j) i->widgetSize.setHeight(j)
66 #define SET_WH( i,j,k) i->widgetSize.setWidth(j); i->widgetSize.setHeight(k);
67
68 #define DS(i) i.width(),i.height()
69
70 /* Callback prototypes */
71 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
72                         vlc_value_t old_val, vlc_value_t new_val, void *param );
73 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
74                        vlc_value_t old_val, vlc_value_t new_val, void *param );
75 static int InteractCallback( vlc_object_t *, const char *, vlc_value_t,
76                              vlc_value_t, void *);
77 /* Video handling */
78 static void *DoRequest( intf_thread_t *p_intf, vout_thread_t *p_vout,
79                         int *pi1, int *pi2, unsigned int*pi3,unsigned int*pi4)
80 {
81     return p_intf->p_sys->p_mi->requestVideo( p_vout, pi1, pi2, pi3, pi4 );
82 }
83 static void DoRelease( intf_thread_t *p_intf, void *p_win )
84 {
85     return p_intf->p_sys->p_mi->releaseVideo( p_win );
86 }
87 static int DoControl( intf_thread_t *p_intf, void *p_win, int i_q, va_list a )
88 {
89     return p_intf->p_sys->p_mi->controlVideo( p_win, i_q, a );
90 }
91
92 MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf )
93 {
94     /* Variables initialisation */
95     // need_components_update = false;
96     bgWidget = NULL; videoWidget = NULL; playlistWidget = NULL;
97     videoIsActive = false;
98     input_name = "";
99     playlistVisible = false;
100
101     /* Ask for privacy */
102     privacy();
103
104     /**
105      *  Configuration and settings
106      *  Pre-building of interface
107      **/
108     settings = new QSettings( "vlc", "vlc-qt-interface" );
109     settings->beginGroup( "MainWindow" );
110
111     /* Main settings */
112     setFocusPolicy( Qt::StrongFocus );
113     setAcceptDrops( true );
114     setWindowIcon( QApplication::windowIcon() );
115     setWindowOpacity( config_GetFloat( p_intf, "qt-opacity" ) );
116
117     /* Set The Video In emebedded Mode or not */
118     videoEmbeddedFlag = config_GetInt( p_intf, "embedded-video" );
119
120     /* Are we in the enhanced always-video mode or not ? */
121     i_visualmode = config_GetInt( p_intf, "qt-display-mode" );
122
123     /* Set the other interface settings */
124     //TODO: I don't like that code
125     visualSelectorEnabled = settings->value( "visual-selector", false ).toBool();
126     notificationEnabled = config_GetInt( p_intf, "qt-notification" )
127                           ? true : false;
128
129     /**************************
130      *  UI and Widgets design
131      **************************/
132     setVLCWindowsTitle();
133     handleMainUi( settings );
134
135     /* Create a Dock to get the playlist */
136     dockPL = new QDockWidget( qtr( "Playlist" ), this );
137     dockPL->setSizePolicy( QSizePolicy::Preferred,
138                            QSizePolicy::Expanding );
139     dockPL->setFeatures( QDockWidget::AllDockWidgetFeatures );
140     dockPL->setAllowedAreas( Qt::LeftDockWidgetArea
141                            | Qt::RightDockWidgetArea
142                            | Qt::BottomDockWidgetArea );
143     dockPL->hide();
144
145     /************
146      * Menu Bar
147      ************/
148     QVLCMenu::createMenuBar( this, p_intf, visualSelectorEnabled );
149
150     /****************
151      *  Status Bar  *
152      ****************/
153     /* Widgets Creation*/
154     b_remainingTime = false;
155     timeLabel = new TimeLabel;
156     timeLabel->setText( " --:--/--:-- " );
157     timeLabel->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
158     nameLabel = new QLabel;
159     nameLabel->setTextInteractionFlags( Qt::TextSelectableByMouse
160                                       | Qt::TextSelectableByKeyboard );
161     speedLabel = new QLabel( "1.00x" );
162     speedLabel->setContextMenuPolicy ( Qt::CustomContextMenu );
163
164     /* Styling those labels */
165     timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
166     speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
167     nameLabel->setFrameStyle( QFrame::Sunken | QFrame::StyledPanel);
168
169     pgBar = new QProgressBar;
170     pgBar->hide();
171
172     /* and adding those */
173     statusBar()->addWidget( nameLabel, 8 );
174     statusBar()->addPermanentWidget( speedLabel, 0 );
175     statusBar()->addPermanentWidget( pgBar, 0 );
176     statusBar()->addPermanentWidget( timeLabel, 0 );
177
178     /* timeLabel behaviour:
179        - double clicking opens the goto time dialog
180        - right-clicking and clicking just toggle between remaining and
181          elapsed time.*/
182     CONNECT( timeLabel, timeLabelClicked(), this, toggleTimeDisplay() );
183     CONNECT( timeLabel, timeLabelDoubleClicked(), THEDP, gotoTimeDialog() );
184     CONNECT( timeLabel, timeLabelDoubleClicked(), this, toggleTimeDisplay() );
185
186     /* Speed Label behaviour:
187        - right click gives the vertical speed slider */
188     CONNECT( speedLabel, customContextMenuRequested( QPoint ),
189              this, showSpeedMenu( QPoint ) );
190
191     /**********************
192      * Systray Management *
193      **********************/
194     sysTray = NULL;
195     bool b_createSystray = false;
196     bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
197     if( config_GetInt( p_intf, "qt-start-minimized") )
198     {
199         if( b_systrayAvailable )
200         {
201             b_createSystray = true;
202             hide(); //FIXME BUG HERE
203         }
204         else msg_Warn( p_intf, "You can't minize if you haven't a system "
205                 "tray bar" );
206     }
207     if( config_GetInt( p_intf, "qt-system-tray") )
208         b_createSystray = true;
209
210     if( b_systrayAvailable && b_createSystray )
211             createSystray();
212
213     /********************
214      * Input Manager    *
215      ********************/
216     MainInputManager::getInstance( p_intf );
217
218     /**************************
219      * Various CONNECTs on IM *
220      **************************/
221     /* Connect the input manager to the GUI elements it manages */
222
223     /* It is also connected to the control->slider, see the ControlsWidget */
224     CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
225              this, setDisplayPosition( float, int, int ) );
226     /* Change the SpeedRate in the Status */
227     CONNECT( THEMIM->getIM(), rateChanged( int ), this, setRate( int ) );
228
229     /**
230      * Connects on nameChanged()
231      * Those connects are not merged because different options can trigger
232      * them down.
233      */
234     /* Naming in the controller statusbar */
235     CONNECT( THEMIM->getIM(), nameChanged( QString ), this,
236              setName( QString ) );
237     /* and in the systray */
238     if( sysTray )
239     {
240         CONNECT( THEMIM->getIM(), nameChanged( QString ), this,
241                  updateSystrayTooltipName( QString ) );
242     }
243     /* and in the title of the controller */
244     if( config_GetInt( p_intf, "qt-name-in-title" ) )
245     {
246         CONNECT( THEMIM->getIM(), nameChanged( QString ), this,
247              setVLCWindowsTitle( QString ) );
248     }
249
250     /**
251      * CONNECTS on PLAY_STATUS
252      **/
253     /* Status on the main controller */
254     CONNECT( THEMIM->getIM(), statusChanged( int ), this, setStatus( int ) );
255     /* and in the systray */
256     if( sysTray )
257     {
258         CONNECT( THEMIM->getIM(), statusChanged( int ), this,
259                  updateSystrayTooltipStatus( int ) );
260     }
261
262     /** OnTimeOut **/
263     // TODO
264     ON_TIMEOUT( updateOnTimer() );
265     //ON_TIMEOUT( debug() );
266
267     /**
268      * Callbacks
269      **/
270     var_Create( p_intf, "interaction", VLC_VAR_ADDRESS );
271     var_AddCallback( p_intf, "interaction", InteractCallback, this );
272     p_intf->b_interaction = VLC_TRUE;
273
274     /* Register callback for the intf-popupmenu variable */
275     playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_intf,
276                                         VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
277     if( p_playlist != NULL )
278     {
279         var_AddCallback( p_playlist, "intf-popupmenu", PopupMenuCB, p_intf );
280         var_AddCallback( p_playlist, "intf-show", IntfShowCB, p_intf );
281         vlc_object_release( p_playlist );
282     }
283
284     /* VideoWidget connect mess to avoid different threads speaking to each other */
285     CONNECT( this, askReleaseVideo( void * ), this, releaseVideoSlot( void * ) );
286     CONNECT( this, askVideoToResize( unsigned int, unsigned int ),
287              videoWidget, SetSizing( unsigned int, unsigned int ) );
288     CONNECT( this, askUpdate(), this, doComponentsUpdate() );
289
290     CONNECT( dockPL, topLevelChanged( bool ), this, doComponentsUpdate() );
291     CONNECT( controls, advancedControlsToggled( bool ),
292              this, doComponentsUpdate() );
293
294
295     /* Size and placement of interface */
296     move( settings->value( "pos", QPoint( 0, 0 ) ).toPoint() );
297
298     QSize newSize = settings->value( "size", QSize( 350, 60 ) ).toSize();
299     if( newSize.isValid() )
300     {
301         resize( newSize );
302     }
303     else
304     {
305         msg_Warn( p_intf, "Invalid size in constructor" );
306     }
307
308     /* Playlist */
309     int tgPlay = settings->value( "playlist-visible", 0 ).toInt();
310     settings->endGroup();
311
312     if( tgPlay )
313     {
314         togglePlaylist();
315     }
316
317
318    if( i_visualmode == QT_MINIMAL_MODE )
319            toggleMinimalView();
320
321    /* Update the geometry TODO: is it useful */
322     updateGeometry();
323 }
324
325 MainInterface::~MainInterface()
326 {
327     msg_Dbg( p_intf, "Destroying the main interface" );
328
329     if( playlistWidget ) playlistWidget->savingSettings( settings );
330     if( ExtendedDialog::exists() )
331         ExtendedDialog::getInstance( p_intf )->savingSettings();
332
333     settings->beginGroup( "MainWindow" );
334     settings->setValue( "playlist-floats", (int)(dockPL->isFloating()) );
335     settings->setValue( "playlist-visible", (int)playlistVisible );
336     settings->setValue( "adv-controls",
337                         getControlsVisibilityStatus() & CONTROLS_ADVANCED );
338     settings->setValue( "pos", pos() );
339     settings->setValue( "size", size() );
340     if( bgWidget )
341         settings->setValue( "backgroundSize", bgWidget->size() );
342
343     settings->endGroup();
344     delete settings;
345
346     /* Unregister callback for the intf-popupmenu variable */
347     playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_intf,
348                                         VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
349     if( p_playlist != NULL )
350     {
351         var_DelCallback( p_playlist, "intf-popupmenu", PopupMenuCB, p_intf );
352         var_DelCallback( p_playlist, "intf-show", IntfShowCB, p_intf );
353         vlc_object_release( p_playlist );
354     }
355
356     p_intf->b_interaction = VLC_FALSE;
357     var_DelCallback( p_intf, "interaction", InteractCallback, this );
358
359     p_intf->pf_request_window = NULL;
360     p_intf->pf_release_window = NULL;
361     p_intf->pf_control_window = NULL;
362     p_intf->p_sys->p_mi = NULL;
363 }
364
365 /*****************************
366  *   Main UI handling        *
367  *****************************/
368
369 /**
370  * Give the decorations of the Main Window a correct Name.
371  * If nothing is given, set it to VLC...
372  **/
373 void MainInterface::setVLCWindowsTitle( QString aTitle )
374 {
375     if( aTitle.isEmpty() )
376     {
377         setWindowTitle( qtr( "VLC media player" ) );
378     }
379     else
380     {
381         setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
382     }
383 }
384
385 void MainInterface::handleMainUi( QSettings *settings )
386 {
387     /* Create the main Widget and the mainLayout */
388     QWidget *main = new QWidget;
389     setCentralWidget( main );
390     mainLayout = new QVBoxLayout( main );
391
392     /* Margins, spacing */
393     main->setContentsMargins( 0, 0, 0, 0 );
394    // main->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Maximum );
395     mainLayout->setMargin( 0 );
396
397     /* Create the CONTROLS Widget */
398     /* bool b_shiny = config_GetInt( p_intf, "qt-blingbling" ); */
399     controls = new ControlsWidget( p_intf, this,
400                    settings->value( "adv-controls", false ).toBool(),
401                    config_GetInt( p_intf, "qt-blingbling" ) );
402
403     /* Add the controls Widget to the main Widget */
404     mainLayout->insertWidget( 0, controls );
405
406     /* Create the Speed Control Widget */
407     speedControl = new SpeedControlWidget( p_intf );
408     speedControlMenu = new QMenu( this );
409
410     QWidgetAction *widgetAction = new QWidgetAction( speedControl );
411     widgetAction->setDefaultWidget( speedControl );
412     speedControlMenu->addAction( widgetAction );
413
414     /* Visualisation */
415     /* Disabled for now, they SUCK */
416     #if 0
417     visualSelector = new VisualSelector( p_intf );
418     mainLayout->insertWidget( 0, visualSelector );
419     visualSelector->hide();
420     #endif
421
422     /* And video Outputs */
423     if( i_visualmode == QT_ALWAYS_VIDEO_MODE ||
424         i_visualmode == QT_MINIMAL_MODE )
425     {
426         bgWidget = new BackgroundWidget( p_intf );
427         bgWidget->resize(
428              settings->value( "backgroundSize", QSize( 300, 150 ) ).toSize() );
429         bgWidget->updateGeometry();
430         mainLayout->insertWidget( 0, bgWidget );
431         CONNECT( this, askBgWidgetToToggle(), bgWidget, toggle() );
432     }
433
434     if( videoEmbeddedFlag )
435     {
436         videoWidget = new VideoWidget( p_intf );
437         mainLayout->insertWidget( 0, videoWidget );
438
439         p_intf->pf_request_window  = ::DoRequest;
440         p_intf->pf_release_window  = ::DoRelease;
441         p_intf->pf_control_window  = ::DoControl;
442     }
443
444     /* Finish the sizing */
445     updateGeometry();
446 }
447
448 inline void MainInterface::privacy()
449 {
450     /**
451      * Ask for the network policy on FIRST STARTUP
452      **/
453     if( config_GetInt( p_intf, "qt-privacy-ask") )
454     {
455         QList<ConfigControl *> controls;
456         if( privacyDialog( controls ) == QDialog::Accepted )
457         {
458             QList<ConfigControl *>::Iterator i;
459             for(  i = controls.begin() ; i != controls.end() ; i++ )
460             {
461                 ConfigControl *c = qobject_cast<ConfigControl *>(*i);
462                 c->doApply( p_intf );
463             }
464
465             config_PutInt( p_intf,  "qt-privacy-ask" , 0 );
466             config_SaveConfigFile( p_intf, NULL );
467         }
468     }
469 }
470
471 int MainInterface::privacyDialog( QList<ConfigControl *> controls )
472 {
473     QDialog *privacy = new QDialog( this );
474
475     privacy->setWindowTitle( qtr( "Privacy and Network policies" ) );
476
477     QGridLayout *gLayout = new QGridLayout( privacy );
478
479     QGroupBox *blabla = new QGroupBox( qtr( "Privacy and Network Warning" ) );
480     QGridLayout *blablaLayout = new QGridLayout( blabla );
481     QLabel *text = new QLabel( qtr(
482         "<p>The <i>VideoLAN Team</i> doesn't like when an application goes "
483         "online without authorization.</p>\n "
484         "<p><i>VLC media player</i> can request limited information on "
485         "the Internet, especially to get CD covers and songs metadata or to know "
486         "if updates are available.</p>\n"
487         "<p><i>VLC media player</i> <b>DOES NOT</b> send or collect <b>ANY</b> "
488         "information, even anonymously, about your usage.</p>\n"
489         "<p>Therefore please check the following options, the default being "
490         "almost no access on the web.</p>\n") );
491     text->setWordWrap( true );
492     text->setTextFormat( Qt::RichText );
493
494     blablaLayout->addWidget( text, 0, 0 ) ;
495
496     QGroupBox *options = new QGroupBox;
497     QGridLayout *optionsLayout = new QGridLayout( options );
498
499     gLayout->addWidget( blabla, 0, 0, 1, 3 );
500     gLayout->addWidget( options, 1, 0, 1, 3 );
501     module_config_t *p_config;
502     ConfigControl *control;
503     int line = 0;
504
505 #define CONFIG_GENERIC( option, type )                            \
506     p_config =  config_FindConfig( VLC_OBJECT(p_intf), option );  \
507     if( p_config )                                                \
508     {                                                             \
509         control =  new type ## ConfigControl( VLC_OBJECT(p_intf), \
510                 p_config, options, false, optionsLayout, line );  \
511         controls.append( control );                               \
512     }
513
514 #define CONFIG_GENERIC_NOBOOL( option, type )                     \
515     p_config =  config_FindConfig( VLC_OBJECT(p_intf), option );  \
516     if( p_config )                                                \
517     {                                                             \
518         control =  new type ## ConfigControl( VLC_OBJECT(p_intf), \
519                 p_config, options, optionsLayout, line );  \
520         controls.append( control );                               \
521     }
522
523     CONFIG_GENERIC( "album-art", IntegerList ); line++;
524     CONFIG_GENERIC_NOBOOL( "fetch-meta", Bool ); line++;
525 #ifdef UPDATE_CHECK
526     CONFIG_GENERIC_NOBOOL( "qt-updates-notif", Bool ); line++;
527     CONFIG_GENERIC_NOBOOL( "qt-updates-days", Integer ); line++;
528 #endif
529     QPushButton *ok = new QPushButton( qtr( "Ok" ) );
530
531     gLayout->addWidget( ok, 2, 2 );
532
533     CONNECT( ok, clicked(), privacy, accept() );
534     return privacy->exec();
535 }
536
537 //FIXME remove me at the end...
538 void MainInterface::debug()
539 {
540     msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
541     msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
542 }
543
544 /**********************************************************************
545  * Handling of sizing of the components
546  **********************************************************************/
547
548 /* This function is probably wrong, but we don't have many many choices...
549    Since we can't know from the playlist Widget if we are inside a dock or not,
550    because the playlist Widget can be called by THEDP, as a separate windows for
551    the skins.
552    Maybe the other solution is to redefine the sizeHint() of the playlist and
553    ask _parent->isFloating()...
554    If you think this would be better, please FIXME it...
555 */
556 QSize MainInterface::sizeHint() const
557 {
558     int nwidth  = controls->sizeHint().width();
559     int nheight = controls->isVisible() ?
560                   controls->size().height()
561                   + menuBar()->size().height()
562                   + statusBar()->size().height()
563                   : 0 ;
564
565     msg_Dbg( p_intf, "1 %i %i", nheight, nwidth );
566     if( VISIBLE( bgWidget ) )
567     {
568         nheight += bgWidget->size().height();
569         nwidth  = bgWidget->size().width();
570         msg_Dbg( p_intf, "1b %i %i", nheight, nwidth );
571     }
572     else if( videoIsActive )
573     {
574         nheight += videoWidget->size().height();
575         nwidth  = videoWidget->size().width();
576         msg_Dbg( p_intf, "2 %i %i", nheight, nwidth );
577     }
578     if( !dockPL->isFloating() && dockPL->isVisible() && dockPL->widget()  )
579     {
580         nheight += dockPL->size().height();
581         nwidth = __MAX( nwidth, dockPL->size().width() );
582         msg_Dbg( p_intf, "3 %i %i", nheight, nwidth );
583     }
584     msg_Dbg( p_intf, "4 %i %i", nheight, nwidth );
585     return QSize( nwidth, nheight );
586 }
587
588 #if 0
589 /* FIXME This is dead code and need to be removed AT THE END */
590 void MainInterface::resizeEvent( QResizeEvent *e )
591 {
592     if( videoWidget )
593         videoWidget->widgetSize.setWidth( e->size().width() - addSize.width() );
594     if( videoWidget && videoIsActive && videoWidget->widgetSize.height() > 1 )
595     {
596         SET_WH( videoWidget, e->size().width() - addSize.width(),
597                              e->size().height()  - addSize.height() );
598         videoWidget->updateGeometry();
599     }
600     if( VISIBLE( playlistWidget ) )
601     {
602 //        SET_WH( playlistWidget , e->size().width() - addSize.width(),
603               //                   e->size().height() - addSize.height() );
604         playlistWidget->updateGeometry();
605     }
606 }
607 #endif
608
609 /****************************************************************************
610  * Small right-click menu for rate control
611  ****************************************************************************/
612 void MainInterface::showSpeedMenu( QPoint pos )
613 {
614     speedControlMenu->exec( QCursor::pos() - pos
615                           + QPoint( 0, speedLabel->height() ) );
616 }
617
618 /****************************************************************************
619  * Video Handling
620  ****************************************************************************/
621 class SetVideoOnTopQtEvent : public QEvent
622 {
623 public:
624     SetVideoOnTopQtEvent( bool _onTop ) :
625       QEvent( (QEvent::Type)SetVideoOnTopEvent_Type ), onTop( _onTop)
626     {}
627
628     bool OnTop() const
629     {
630         return onTop;
631     }
632
633 private:
634     bool onTop;
635 };
636
637 /* function called from ::DoRequest in order to show a nice VideoWidget
638     at the good size */
639 void *MainInterface::requestVideo( vout_thread_t *p_nvout, int *pi_x,
640                                    int *pi_y, unsigned int *pi_width,
641                                    unsigned int *pi_height )
642 {
643     bool bgWasVisible = false;
644
645     /* Request the videoWidget */
646     void *ret = videoWidget->request( p_nvout,pi_x, pi_y, pi_width, pi_height );
647     if( ret ) /* The videoWidget is available */
648     {
649         /* Did we have a bg ? Hide it! */
650         if( VISIBLE( bgWidget) )
651         {
652             bgWasVisible = true;
653             emit askBgWidgetToToggle();
654         }
655
656         /*if( THEMIM->getIM()->hasVideo() || !bgWasVisible )
657         {
658             videoWidget->widgetSize = QSize( *pi_width, *pi_height );
659         }
660         else /* Background widget available, use its size */
661         /*{
662             /* Ok, our visualizations are bad, so don't do this for the moment
663              * use the requested size anyway */
664             // videoWidget->widgetSize = bgWidget->widgeTSize;
665           /*  videoWidget->widgetSize = QSize( *pi_width, *pi_height );
666         }*/
667
668         videoIsActive = true;
669
670         emit askVideoToResize( *pi_width, *pi_height );
671         emit askUpdate();
672     }
673     return ret;
674 }
675
676 void MainInterface::releaseVideo( void *p_win )
677 {
678     emit askReleaseVideo( p_win );
679 }
680
681 void MainInterface::releaseVideoSlot( void *p_win )
682 {
683     videoWidget->release( p_win );
684     videoWidget->hide();
685
686     if( bgWidget )// WORONG
687         bgWidget->show();
688
689     videoIsActive = false;
690     emit askUpdate();
691 }
692
693 int MainInterface::controlVideo( void *p_window, int i_query, va_list args )
694 {
695     int i_ret = VLC_EGENERIC;
696     switch( i_query )
697     {
698         case VOUT_GET_SIZE:
699         {
700             unsigned int *pi_width  = va_arg( args, unsigned int * );
701             unsigned int *pi_height = va_arg( args, unsigned int * );
702             *pi_width = videoWidget->width();
703             *pi_height = videoWidget->height();
704             i_ret = VLC_SUCCESS;
705             break;
706         }
707         case VOUT_SET_SIZE:
708         {
709             unsigned int i_width  = va_arg( args, unsigned int );
710             unsigned int i_height = va_arg( args, unsigned int );
711             emit askVideoToResize( i_width, i_height );
712             emit askUpdate();
713             updateGeometry();
714             i_ret = VLC_SUCCESS;
715             break;
716         }
717         case VOUT_SET_STAY_ON_TOP:
718         {
719             int i_arg = va_arg( args, int );
720             QApplication::postEvent( this, new SetVideoOnTopQtEvent( i_arg ) );
721             i_ret = VLC_SUCCESS;
722             break;
723         }
724         default:
725             msg_Warn( p_intf, "unsupported control query" );
726             break;
727     }
728     return i_ret;
729 }
730
731 /*****************************************************************************
732  * Playlist, Visualisation and Menus handling
733  *****************************************************************************/
734 /**
735  * Toggle the playlist widget or dialog
736  **/
737 void MainInterface::togglePlaylist()
738 {
739     /* CREATION
740     If no playlist exist, then create one and attach it to the DockPL*/
741     if( !playlistWidget )
742     {
743         playlistWidget = new PlaylistWidget( p_intf, settings, dockPL );
744
745         /* Add it to the parent DockWidget */
746         dockPL->setWidget( playlistWidget );
747
748         /* Add the dock to the main Interface */
749         addDockWidget( Qt::BottomDockWidgetArea, dockPL );
750
751         /* Make the playlist floating is requested. Default is not. */
752         settings->beginGroup( "MainWindow" );
753         if( settings->value( "playlist-floats", 1 ).toInt() )
754         {
755             msg_Dbg( p_intf, "we don't want the playlist inside");
756             dockPL->setFloating( true );
757         }
758         settings->endGroup();
759         settings->beginGroup( "playlist" );
760         dockPL->move( settings->value( "pos", QPoint( 0,0 ) ).toPoint() );
761         QSize newSize = settings->value( "size", QSize( 400, 300 ) ).toSize();
762         if( newSize.isValid() )
763             dockPL->resize( newSize );
764         settings->endGroup();
765
766         dockPL->show();
767         playlistVisible = true;
768     }
769     else
770     {
771     /* toggle the visibility of the playlist */
772        TOGGLEV( dockPL );
773        resize( sizeHint() );
774        playlistVisible = !playlistVisible;
775     }
776 }
777
778 /* Function called from the menu to undock the playlist */
779 void MainInterface::undockPlaylist()
780 {
781     dockPL->setFloating( true );
782     resize( sizeHint() );
783 }
784
785 void MainInterface::toggleMinimalView()
786 {
787     TOGGLEV( menuBar() );
788     TOGGLEV( controls );
789     TOGGLEV( statusBar() );
790     doComponentsUpdate();
791 }
792
793 /* Video widget cannot do this synchronously as it runs in another thread */
794 /* Well, could it, actually ? Probably dangerous ... */
795 void MainInterface::doComponentsUpdate()
796 {
797     resize( sizeHint() );
798     msg_Dbg( p_intf, "Updating the geometry" );
799     updateGeometry();
800 }
801
802 /* toggling advanced controls buttons */
803 void MainInterface::toggleAdvanced()
804 {
805     controls->toggleAdvanced();
806 }
807
808 /* Get the visibility status of the controls (hidden or not, advanced or not) */
809 int MainInterface::getControlsVisibilityStatus()
810 {
811     return( (controls->isVisible() ? CONTROLS_VISIBLE : CONTROLS_HIDDEN )
812                 + CONTROLS_ADVANCED * controls->b_advancedVisible );
813 }
814
815 #if 0
816 void MainInterface::visual()
817 {
818     if( !VISIBLE( visualSelector) )
819     {
820         visualSelector->show();
821         if( !THEMIM->getIM()->hasVideo() )
822         {
823             /* Show the background widget */
824         }
825         visualSelectorEnabled = true;
826     }
827     else
828     {
829         /* Stop any currently running visualization */
830         visualSelector->hide();
831         visualSelectorEnabled = false;
832     }
833     doComponentsUpdate();
834 }
835 #endif
836
837 /************************************************************************
838  * Other stuff
839  ************************************************************************/
840 void MainInterface::setDisplayPosition( float pos, int time, int length )
841 {
842     char psz_length[MSTRTIME_MAX_SIZE], psz_time[MSTRTIME_MAX_SIZE];
843     secstotimestr( psz_length, length );
844     secstotimestr( psz_time, ( b_remainingTime && length ) ? length - time
845                                                            : time );
846
847     QString timestr;
848     timestr.sprintf( "%s/%s", psz_time,
849                             ( !length && time ) ? "--:--" : psz_length );
850
851     /* Add a minus to remaining time*/
852     if( b_remainingTime && length ) timeLabel->setText( " -"+timestr+" " );
853     else timeLabel->setText( " "+timestr+" " );
854 }
855
856 void MainInterface::toggleTimeDisplay()
857 {
858     b_remainingTime = !b_remainingTime;
859 }
860
861 void MainInterface::setName( QString name )
862 {
863     input_name = name; /* store it for the QSystray use */
864     /* Display it in the status bar, but also as a Tooltip in case it doesn't
865        fit in the label */
866     nameLabel->setText( " " + name + " " );
867     nameLabel->setToolTip( " " + name +" " );
868 }
869
870 void MainInterface::setStatus( int status )
871 {
872     /* Forward the status to the controls to toggle Play/Pause */
873     controls->setStatus( status );
874     /* And in the systray for the menu */
875     if( sysTray )
876         QVLCMenu::updateSystrayMenu( this, p_intf );
877 }
878
879 void MainInterface::setRate( int rate )
880 {
881     QString str;
882     str.setNum( ( 1000 / (double)rate ), 'f', 2 );
883     str.append( "x" );
884     speedLabel->setText( str );
885     speedControl->updateControls( rate );
886 }
887
888 void MainInterface::updateOnTimer()
889 {
890     if( intf_ShouldDie( p_intf ) )
891     {
892         QApplication::closeAllWindows();
893         QApplication::quit();
894     }
895 #if 0
896     if( need_components_update )
897     {
898         doComponentsUpdate();
899         need_components_update = false;
900     }
901 #endif
902 }
903
904 /*****************************************************************************
905  * Systray Icon and Systray Menu
906  *****************************************************************************/
907
908 /**
909  * Create a SystemTray icon and a menu that would go with it.
910  * Connects to a click handler on the icon.
911  **/
912 void MainInterface::createSystray()
913 {
914     QIcon iconVLC;
915     if( QDate::currentDate().dayOfYear() >= 354 )
916         iconVLC =  QIcon( QPixmap( ":/vlc128-christmas.png" ) );
917     else
918         iconVLC =  QIcon( QPixmap( ":/vlc128.png" ) );
919     sysTray = new QSystemTrayIcon( iconVLC, this );
920     sysTray->setToolTip( qtr( "VLC media player" ));
921
922     systrayMenu = new QMenu( qtr( "VLC media player" ), this );
923     systrayMenu->setIcon( iconVLC );
924
925     QVLCMenu::updateSystrayMenu( this, p_intf, true );
926     sysTray->show();
927
928     CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
929             this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
930 }
931
932 /**
933  * Updates the Systray Icon's menu and toggle the main interface
934  */
935 void MainInterface::toggleUpdateSystrayMenu()
936 {
937     /* If hidden, show it */
938     if( isHidden() )
939     {
940         show();
941         activateWindow();
942     }
943     else if( isMinimized() )
944     {
945         /* Minimized */
946         showNormal();
947         activateWindow();
948     }
949     else
950     {
951         /* Visible */
952 #ifdef WIN32
953         /* check if any visible window is above vlc in the z-order,
954          * but ignore the ones always on top */
955         WINDOWINFO wi;
956         HWND hwnd;
957         wi.cbSize = sizeof( WINDOWINFO );
958         for( hwnd = GetNextWindow( internalWinId(), GW_HWNDPREV );
959                 hwnd && !IsWindowVisible( hwnd );
960                 hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) );
961         if( !hwnd || !GetWindowInfo( hwnd, &wi ) ||
962                 (wi.dwExStyle&WS_EX_TOPMOST) )
963 #else
964         if( isActiveWindow() )
965 #endif
966         {
967             hide();
968         }
969         else
970         {
971             activateWindow();
972         }
973     }
974     QVLCMenu::updateSystrayMenu( this, p_intf );
975 }
976
977 void MainInterface::handleSystrayClick(
978                                     QSystemTrayIcon::ActivationReason reason )
979 {
980     switch( reason )
981     {
982         case QSystemTrayIcon::Trigger:
983             toggleUpdateSystrayMenu();
984             break;
985         case QSystemTrayIcon::MiddleClick:
986             sysTray->showMessage( qtr( "VLC media player" ),
987                     qtr( "Control menu for the player" ),
988                     QSystemTrayIcon::Information, 3000 );
989             break;
990     }
991 }
992
993 /**
994  * Updates the name of the systray Icon tooltip.
995  * Doesn't check if the systray exists, check before you call it.
996  **/
997 void MainInterface::updateSystrayTooltipName( QString name )
998 {
999     if( name.isEmpty() )
1000     {
1001         sysTray->setToolTip( qtr( "VLC media player" ) );
1002     }
1003     else
1004     {
1005         sysTray->setToolTip( name );
1006         if( notificationEnabled && ( isHidden() || isMinimized() ) )
1007         {
1008             sysTray->showMessage( qtr( "VLC media player" ), name,
1009                     QSystemTrayIcon::NoIcon, 3000 );
1010         }
1011     }
1012 }
1013
1014 /**
1015  * Updates the status of the systray Icon tooltip.
1016  * Doesn't check if the systray exists, check before you call it.
1017  **/
1018 void MainInterface::updateSystrayTooltipStatus( int i_status )
1019 {
1020     switch( i_status )
1021     {
1022         case  0:
1023         case  END_S:
1024             {
1025                 sysTray->setToolTip( qtr( "VLC media player" ) );
1026                 break;
1027             }
1028         case PLAYING_S:
1029             {
1030                 sysTray->setToolTip( input_name );
1031                 break;
1032             }
1033         case PAUSE_S:
1034             {
1035                 sysTray->setToolTip( input_name + " - "
1036                         + qtr( "Paused") );
1037                 break;
1038             }
1039     }
1040 }
1041
1042 /************************************************************************
1043  * D&D Events
1044  ************************************************************************/
1045 void MainInterface::dropEvent(QDropEvent *event)
1046 {
1047      const QMimeData *mimeData = event->mimeData();
1048
1049      /* D&D of a subtitles file, add it on the fly */
1050      if( mimeData->urls().size() == 1 )
1051      {
1052         if( THEMIM->getIM()->hasInput() )
1053         {
1054             if( input_AddSubtitles( THEMIM->getInput(),
1055                                     qtu( mimeData->urls()[0].toString() ),
1056                                     VLC_TRUE ) )
1057             {
1058                 event->acceptProposedAction();
1059                 return;
1060             }
1061         }
1062      }
1063      bool first = true;
1064      foreach( QUrl url, mimeData->urls() ) {
1065         QString s = url.toString();
1066         if( s.length() > 0 ) {
1067             playlist_Add( THEPL, qtu(s), NULL,
1068                           PLAYLIST_APPEND | (first ? PLAYLIST_GO:0),
1069                           PLAYLIST_END, VLC_TRUE, VLC_FALSE );
1070             first = false;
1071         }
1072      }
1073      event->acceptProposedAction();
1074 }
1075 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1076 {
1077      event->acceptProposedAction();
1078 }
1079 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1080 {
1081      event->acceptProposedAction();
1082 }
1083 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1084 {
1085      event->accept();
1086 }
1087
1088 /************************************************************************
1089  * Events stuff
1090  ************************************************************************/
1091 void MainInterface::customEvent( QEvent *event )
1092 {
1093 #if 0
1094     if( event->type() == PLDockEvent_Type )
1095     {
1096         PlaylistDialog::killInstance();
1097         playlistEmbeddedFlag = true;
1098         menuBar()->clear();
1099         QVLCMenu::createMenuBar(this, p_intf, true, visualSelectorEnabled);
1100         togglePlaylist();
1101     }
1102 #endif
1103     /*else */
1104     if ( event->type() == SetVideoOnTopEvent_Type )
1105     {
1106         SetVideoOnTopQtEvent* p_event = (SetVideoOnTopQtEvent*)event;
1107         if( p_event->OnTop() )
1108             setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
1109         else
1110             setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
1111         show(); /* necessary to apply window flags?? */
1112     }
1113 }
1114
1115 void MainInterface::keyPressEvent( QKeyEvent *e )
1116 {
1117     if( ( e->modifiers() &  Qt::ControlModifier ) && ( e->key() & Qt::Key_H )
1118           && menuBar()->isHidden() )
1119     {
1120         toggleMinimalView();
1121         e->accept();
1122     }
1123
1124     int i_vlck = qtEventToVLCKey( e );
1125     if( i_vlck > 0 )
1126     {
1127         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1128         e->accept();
1129     }
1130     else
1131         e->ignore();
1132 }
1133
1134 void MainInterface::wheelEvent( QWheelEvent *e )
1135 {
1136     int i_vlckey = qtWheelEventToVLCKey( e );
1137     var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
1138     e->accept();
1139 }
1140
1141 void MainInterface::closeEvent( QCloseEvent *e )
1142 {
1143     hide();
1144     THEDP->quit();
1145 }
1146
1147 void MainInterface::toggleFullScreen( void )
1148 {
1149     if( isFullScreen() )
1150         showNormal();
1151     else
1152         showFullScreen();
1153 }
1154
1155 /*****************************************************************************
1156  * Callbacks
1157  *****************************************************************************/
1158 static int InteractCallback( vlc_object_t *p_this,
1159                              const char *psz_var, vlc_value_t old_val,
1160                              vlc_value_t new_val, void *param )
1161 {
1162     intf_dialog_args_t *p_arg = new intf_dialog_args_t;
1163     p_arg->p_dialog = (interaction_dialog_t *)(new_val.p_address);
1164     DialogEvent *event = new DialogEvent( INTF_DIALOG_INTERACTION, 0, p_arg );
1165     QApplication::postEvent( THEDP, static_cast<QEvent*>(event) );
1166     return VLC_SUCCESS;
1167 }
1168
1169 /*****************************************************************************
1170  * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1171  *  We don't show the menu directly here because we don't want the
1172  *  caller to block for a too long time.
1173  *****************************************************************************/
1174 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
1175                         vlc_value_t old_val, vlc_value_t new_val, void *param )
1176 {
1177     intf_thread_t *p_intf = (intf_thread_t *)param;
1178     msg_Dbg( p_this, "Menu Requested" ); // DEBUG to track the non disparition of the menu...
1179
1180     if( p_intf->pf_show_dialog )
1181     {
1182         p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1183                                 new_val.b_bool, 0 );
1184     }
1185
1186     return VLC_SUCCESS;
1187 }
1188
1189 /*****************************************************************************
1190  * IntfShowCB: callback triggered by the intf-show playlist variable.
1191  *****************************************************************************/
1192 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
1193                        vlc_value_t old_val, vlc_value_t new_val, void *param )
1194 {
1195     intf_thread_t *p_intf = (intf_thread_t *)param;
1196     msg_Dbg( p_this, "Intf Show Requested" ); // DEBUG to track the non disparition of the menu...
1197     //p_intf->p_sys->b_intf_show = VLC_TRUE;
1198
1199     return VLC_SUCCESS;
1200 }