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