]> git.sesse.net Git - vlc/blob - modules/gui/qt4/main_interface.cpp
Qt: no need to restart VLC to get the new toolbars.
[vlc] / modules / gui / qt4 / main_interface.cpp
1 /*****************************************************************************
2  * main_interface.cpp : Main interface
3  ****************************************************************************
4  * Copyright (C) 2006-2008 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
32 #include "main_interface.hpp"
33 #include "input_manager.hpp"
34 #include "actions_manager.hpp"
35
36 #include "util/customwidgets.hpp"
37 #include "util/qt_dirs.hpp"
38
39 #include "components/interface_widgets.hpp"
40 #include "components/controller.hpp"
41 #include "components/playlist/playlist.hpp"
42 #include "dialogs/external.hpp"
43
44 #include "menus.hpp"
45 #include "recents.hpp"
46
47 #include <QCloseEvent>
48 #include <QKeyEvent>
49
50 #include <QUrl>
51 #include <QSize>
52 #include <QDate>
53
54 #include <QMenu>
55 #include <QMenuBar>
56 #include <QStatusBar>
57 #include <QLabel>
58 #include <QGroupBox>
59 #include <QPushButton>
60
61 #include <assert.h>
62
63 #include <vlc_keys.h> /* Wheel event */
64 #include <vlc_vout.h>
65
66 /* Callback prototypes */
67 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
68                         vlc_value_t old_val, vlc_value_t new_val, void *param );
69 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
70                        vlc_value_t old_val, vlc_value_t new_val, void *param );
71
72 MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf )
73 {
74     /* Variables initialisation */
75     // need_components_update = false;
76     bgWidget             = NULL;
77     videoWidget          = NULL;
78     playlistWidget       = NULL;
79     sysTray              = NULL;
80     videoIsActive        = false;
81     playlistVisible      = false;
82     input_name           = "";
83     fullscreenControls   = NULL;
84     cryptedLabel         = NULL;
85
86     bgWasVisible         = false;
87     i_bg_height          = 0;
88
89     /* Ask for privacy */
90     askForPrivacy();
91
92     /**
93      *  Configuration and settings
94      *  Pre-building of interface
95      **/
96     /* Main settings */
97     setFocusPolicy( Qt::StrongFocus );
98     setAcceptDrops( true );
99     setWindowIcon( QApplication::windowIcon() );
100     setWindowOpacity( config_GetFloat( p_intf, "qt-opacity" ) );
101
102     /* Set The Video In emebedded Mode or not */
103     videoEmbeddedFlag = config_GetInt( p_intf, "embedded-video" );
104
105     /* Does the interface resize to video size or the opposite */
106     b_keep_size = !config_GetInt( p_intf, "qt-video-autoresize" );
107
108     /* Are we in the enhanced always-video mode or not ? */
109     i_visualmode = config_GetInt( p_intf, "qt-display-mode" );
110
111     /* Set the other interface settings */
112     settings = getSettings();
113     settings->beginGroup( "MainWindow" );
114
115     /**
116      * Retrieve saved sizes for main window
117      *   mainBasedSize = based window size for normal mode
118      *                  (no video, no background)
119      *   mainVideoSize = window size with video (all modes)
120      **/
121     mainBasedSize = settings->value( "mainBasedSize", QSize( 350, 120 ) ).toSize();
122     mainVideoSize = settings->value( "mainVideoSize", QSize( 400, 300 ) ).toSize();
123
124     /* Do we want anoying popups or not */
125     notificationEnabled = (bool)config_GetInt( p_intf, "qt-notification" );
126
127     /**************
128      * Status Bar *
129      **************/
130     createStatusBar();
131
132     /**************************
133      *  UI and Widgets design
134      **************************/
135     setVLCWindowsTitle();
136     handleMainUi( settings );
137
138     /************
139      * Menu Bar *
140      ************/
141     QVLCMenu::createMenuBar( this, p_intf );
142
143 #if 0
144     /* Create a Dock to get the playlist */
145     dockPL = new QDockWidget( qtr( "Playlist" ), this );
146     dockPL->setSizePolicy( QSizePolicy::Preferred,
147                            QSizePolicy::Expanding );
148     dockPL->setFeatures( QDockWidget::AllDockWidgetFeatures );
149     dockPL->setAllowedAreas( Qt::LeftDockWidgetArea
150                            | Qt::RightDockWidgetArea
151                            | Qt::BottomDockWidgetArea );
152     dockPL->hide();
153 #endif
154
155     /********************
156      * Input Manager    *
157      ********************/
158     MainInputManager::getInstance( p_intf );
159
160     /**************************
161      * Various CONNECTs on IM *
162      **************************/
163     /* Connect the input manager to the GUI elements it manages */
164
165     /**
166      * Connects on nameChanged()
167      * Those connects are not merged because different options can trigger
168      * them down.
169      */
170     /* Naming in the controller statusbar */
171     CONNECT( THEMIM->getIM(), nameChanged( QString ),
172              this, setName( QString ) );
173     /* and in the systray */
174     if( sysTray )
175     {
176         CONNECT( THEMIM->getIM(), nameChanged( QString ), this,
177                  updateSystrayTooltipName( QString ) );
178     }
179     /* and in the title of the controller */
180     if( config_GetInt( p_intf, "qt-name-in-title" ) )
181     {
182         CONNECT( THEMIM->getIM(), nameChanged( QString ), this,
183              setVLCWindowsTitle( QString ) );
184     }
185
186     /**
187      * CONNECTS on PLAY_STATUS
188      **/
189     /* Status on the systray */
190     if( sysTray )
191     {
192         CONNECT( THEMIM->getIM(), statusChanged( int ),
193                  this, updateSystrayTooltipStatus( int ) );
194     }
195
196     /* END CONNECTS ON IM */
197
198     dialogHandler = new DialogHandler (p_intf);
199
200     /************
201      * Callbacks
202      ************/
203     var_AddCallback( p_intf->p_libvlc, "intf-show", IntfShowCB, p_intf );
204
205     /* Register callback for the intf-popupmenu variable */
206     var_AddCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
207
208
209     /* VideoWidget connects to avoid different threads speaking to each other */
210     connect( this, SIGNAL(askReleaseVideo( void )),
211              this, SLOT(releaseVideoSlot( void )), Qt::BlockingQueuedConnection );
212
213     if( videoWidget )
214     {
215         CONNECT( this, askVideoToResize( unsigned int, unsigned int ),
216                  videoWidget, SetSizing( unsigned int, unsigned int ) );
217
218         connect( this, SIGNAL(askVideoToShow( unsigned int, unsigned int)),
219              videoWidget, SLOT(SetSizing(unsigned int, unsigned int )),
220              Qt::BlockingQueuedConnection );
221     }
222
223     CONNECT( this, askUpdate(), this, doComponentsUpdate() );
224     CONNECT( THEDP, toolBarConfUpdated(), this, recreateToolbars() );
225
226     /* Size and placement of interface */
227     settings->beginGroup( "MainWindow" );
228     QVLCTools::restoreWidgetPosition( settings, this, QSize(380, 60) );
229
230     /* resize to previously saved main window size if appicable */
231     if( b_keep_size )
232     {
233        if( i_visualmode == QT_ALWAYS_VIDEO_MODE ||
234            i_visualmode == QT_MINIMAL_MODE )
235        {
236            resize( mainVideoSize );
237        }
238        else
239        {
240            resize( mainBasedSize );
241        }
242     }
243
244     bool b_visible = settings->value( "playlist-visible", 0 ).toInt();
245     settings->endGroup();
246
247     /* Playlist */
248     if( b_visible ) togglePlaylist();
249
250     /* Enable the popup menu in the MI */
251     setContextMenuPolicy( Qt::CustomContextMenu );
252     CONNECT( this, customContextMenuRequested( const QPoint& ),
253              this, popupMenu( const QPoint& ) );
254
255     /* Final sizing and showing */
256     setMinimumWidth( __MAX( controls->sizeHint().width(),
257                             menuBar()->sizeHint().width() ) );
258     show();
259
260     /* And switch to minimal view if needed
261        Must be called after the show() */
262     if( i_visualmode == QT_MINIMAL_MODE )
263         toggleMinimalView( true );
264
265     /* Update the geometry : It is useful if you switch between
266        qt-display-modes ?*/
267     updateGeometry();
268     resize( sizeHint() );
269
270     /*****************************************************
271      * End everything by creating the Systray Management *
272      *****************************************************/
273     initSystray();
274 }
275
276 MainInterface::~MainInterface()
277 {
278     msg_Dbg( p_intf, "Destroying the main interface" );
279
280     delete dialogHandler;
281
282     /* Unsure we hide the videoWidget before destroying it */
283     if( videoIsActive ) videoWidget->hide();
284
285     /* Save playlist state */
286     if( playlistWidget )
287     {
288         if( !isDocked() )
289             QVLCTools::saveWidgetPosition( p_intf, "Playlist", playlistWidget );
290
291         delete playlistWidget;
292     }
293
294     /* Be sure to kill the actionsManager... FIXME */
295     ActionsManager::killInstance();
296
297     /* Delete the FSC controller */
298     delete fullscreenControls;
299
300     /* Save states */
301     settings->beginGroup( "MainWindow" );
302     settings->setValue( "pl-dock-status", (int)i_pl_dock );
303     settings->setValue( "playlist-visible", (int)playlistVisible );
304     settings->setValue( "adv-controls",
305                         getControlsVisibilityStatus() & CONTROLS_ADVANCED );
306
307     settings->setValue( "mainBasedSize", mainBasedSize );
308     settings->setValue( "mainVideoSize", mainVideoSize );
309
310     if( bgWidget )
311         settings->setValue( "backgroundSize", bgWidget->size() );
312
313     /* Save this size */
314     QVLCTools::saveWidgetPosition(settings, this);
315     settings->endGroup();
316
317
318     /* Unregister callbacks */
319     var_DelCallback( p_intf->p_libvlc, "intf-show", IntfShowCB, p_intf );
320     var_DelCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
321
322     p_intf->p_sys->p_mi = NULL;
323 }
324
325 /*****************************
326  *   Main UI handling        *
327  *****************************/
328
329 inline void MainInterface::createStatusBar()
330 {
331     /****************
332      *  Status Bar  *
333      ****************/
334     /* Widgets Creation*/
335     QStatusBar *statusBarr = statusBar();
336
337     TimeLabel *timeLabel = new TimeLabel( p_intf );
338     nameLabel = new QLabel( this );
339     nameLabel->setTextInteractionFlags( Qt::TextSelectableByMouse
340                                       | Qt::TextSelectableByKeyboard );
341     SpeedLabel *speedLabel = new SpeedLabel( p_intf, "1.00x", this );
342
343     /* Styling those labels */
344     timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
345     speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
346     nameLabel->setFrameStyle( QFrame::Sunken | QFrame::StyledPanel);
347
348     /* and adding those */
349     statusBarr->addWidget( nameLabel, 8 );
350     statusBarr->addPermanentWidget( speedLabel, 0 );
351     statusBarr->addPermanentWidget( timeLabel, 0 );
352
353     /* timeLabel behaviour:
354        - double clicking opens the goto time dialog
355        - right-clicking and clicking just toggle between remaining and
356          elapsed time.*/
357     CONNECT( timeLabel, timeLabelDoubleClicked(), THEDP, gotoTimeDialog() );
358
359     CONNECT( THEMIM->getIM(), encryptionChanged( bool ) , this, showCryptedLabel( bool ) );
360 }
361
362 void MainInterface::showCryptedLabel( bool b_show )
363 {
364     if( cryptedLabel == NULL )
365     {
366         cryptedLabel = new QLabel;
367         // The lock icon is not the right one for DRM protection/scrambled.
368         //cryptedLabel->setPixmap( QPixmap( ":/lock" ) );
369         cryptedLabel->setText( "DRM" );
370         statusBar()->addWidget( cryptedLabel );
371     }
372
373     cryptedLabel->setVisible( b_show );
374 }
375
376 inline void MainInterface::initSystray()
377 {
378     bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
379     bool b_systrayWanted = config_GetInt( p_intf, "qt-system-tray" );
380
381     if( config_GetInt( p_intf, "qt-start-minimized") > 0 )
382     {
383         if( b_systrayAvailable )
384         {
385             b_systrayWanted = true;
386             hide();
387         }
388         else
389             msg_Err( p_intf, "cannot start minimized without system tray bar" );
390     }
391
392     if( b_systrayAvailable && b_systrayWanted )
393             createSystray();
394 }
395
396 /**
397  * Give the decorations of the Main Window a correct Name.
398  * If nothing is given, set it to VLC...
399  **/
400 void MainInterface::setVLCWindowsTitle( QString aTitle )
401 {
402     if( aTitle.isEmpty() )
403     {
404         setWindowTitle( qtr( "VLC media player" ) );
405     }
406     else
407     {
408         setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
409     }
410 }
411
412 void MainInterface::recreateToolbars()
413 {
414     settings->beginGroup( "MainWindow" );
415     delete controls;
416     delete inputC;
417     controls = new ControlsWidget( p_intf, false, this ); /* FIXME */
418     CONNECT( controls, advancedControlsToggled( bool ),
419              this, doComponentsUpdate() );
420     CONNECT( controls, sizeChanged(),
421              this, doComponentsUpdate() );
422     inputC = new InputControlsWidget( p_intf, this );
423
424     mainLayout->insertWidget( 2, inputC, 0, Qt::AlignBottom );
425     mainLayout->insertWidget( settings->value( "ToolbarPos", 0 ).toInt() ? 0: 3,
426                               controls, 0, Qt::AlignBottom );
427     settings->endGroup();
428 }
429
430 void MainInterface::handleMainUi( QSettings *settings )
431 {
432     /* Create the main Widget and the mainLayout */
433     QWidget *main = new QWidget;
434     setCentralWidget( main );
435     mainLayout = new QVBoxLayout( main );
436
437     /* Margins, spacing */
438     main->setContentsMargins( 0, 0, 0, 0 );
439     main->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Maximum );
440     mainLayout->setSpacing( 0 );
441     mainLayout->setMargin( 0 );
442
443     /* Visualisation */
444     /* Disabled for now, they SUCK */
445     #if 0
446     visualSelector = new VisualSelector( p_intf );
447     mainLayout->insertWidget( 0, visualSelector );
448     visualSelector->hide();
449     #endif
450
451     /* Bg Cone */
452     bgWidget = new BackgroundWidget( p_intf );
453     bgWidget->resize(
454             settings->value( "backgroundSize", QSize( 300, 200 ) ).toSize() );
455     bgWidget->updateGeometry();
456     CONNECT( this, askBgWidgetToToggle(), bgWidget, toggle() );
457
458     if( i_visualmode != QT_ALWAYS_VIDEO_MODE &&
459         i_visualmode != QT_MINIMAL_MODE )
460     {
461         bgWidget->hide();
462     }
463
464     /* And video Outputs */
465     if( videoEmbeddedFlag )
466         videoWidget = new VideoWidget( p_intf );
467
468     /* Create the CONTROLS Widget */
469     controls = new ControlsWidget( p_intf,
470                    settings->value( "adv-controls", false ).toBool(), this );
471     CONNECT( controls, advancedControlsToggled( bool ),
472              this, doComponentsUpdate() );
473     CONNECT( controls, sizeChanged(),
474              this, doComponentsUpdate() );
475     inputC = new InputControlsWidget( p_intf, this );
476
477
478     /* Add the controls Widget to the main Widget */
479     mainLayout->insertWidget( 0, bgWidget );
480     if( videoWidget ) mainLayout->insertWidget( 0, videoWidget, 10 );
481     mainLayout->insertWidget( 2, inputC, 0, Qt::AlignBottom );
482     mainLayout->insertWidget( settings->value( "ToolbarPos", 0 ).toInt() ? 0: 3,
483                               controls, 0, Qt::AlignBottom );
484
485     /* Finish the sizing */
486     main->updateGeometry();
487
488     getSettings()->endGroup();
489 #ifdef WIN32
490     if ( depth() > 8 )
491 #endif
492     /* Create the FULLSCREEN CONTROLS Widget */
493     if( config_GetInt( p_intf, "qt-fs-controller" ) )
494     {
495         fullscreenControls = new FullscreenControllerWidget( p_intf );
496     }
497 }
498
499 inline void MainInterface::askForPrivacy()
500 {
501     /**
502      * Ask for the network policy on FIRST STARTUP
503      **/
504     if( config_GetInt( p_intf, "qt-privacy-ask") )
505     {
506         QList<ConfigControl *> controls;
507         if( privacyDialog( &controls ) == QDialog::Accepted )
508         {
509             QList<ConfigControl *>::Iterator i;
510             for(  i = controls.begin() ; i != controls.end() ; i++ )
511             {
512                 ConfigControl *c = qobject_cast<ConfigControl *>(*i);
513                 c->doApply( p_intf );
514             }
515
516             config_PutInt( p_intf,  "qt-privacy-ask" , 0 );
517             /* We have to save here because the user may not launch Prefs */
518             config_SaveConfigFile( p_intf, NULL );
519         }
520     }
521 }
522
523 int MainInterface::privacyDialog( QList<ConfigControl *> *controls )
524 {
525     QDialog *privacy = new QDialog( this );
526
527     privacy->setWindowTitle( qtr( "Privacy and Network Policies" ) );
528
529     QGridLayout *gLayout = new QGridLayout( privacy );
530
531     QGroupBox *blabla = new QGroupBox( qtr( "Privacy and Network Warning" ) );
532     QGridLayout *blablaLayout = new QGridLayout( blabla );
533     QLabel *text = new QLabel( qtr(
534         "<p>The <i>VideoLAN Team</i> doesn't like when an application goes "
535         "online without authorization.</p>\n "
536         "<p><i>VLC media player</i> can retreive limited information from "
537         "the Internet in order to get CD covers or to check "
538         "for available updates.</p>\n"
539         "<p><i>VLC media player</i> <b>DOES NOT</b> send or collect <b>ANY</b> "
540         "information, even anonymously, about your usage.</p>\n"
541         "<p>Therefore please select from the following options, the default being "
542         "almost no access to the web.</p>\n") );
543     text->setWordWrap( true );
544     text->setTextFormat( Qt::RichText );
545
546     blablaLayout->addWidget( text, 0, 0 ) ;
547
548     QGroupBox *options = new QGroupBox;
549     QGridLayout *optionsLayout = new QGridLayout( options );
550
551     gLayout->addWidget( blabla, 0, 0, 1, 3 );
552     gLayout->addWidget( options, 1, 0, 1, 3 );
553     module_config_t *p_config;
554     ConfigControl *control;
555     int line = 0;
556
557 #define CONFIG_GENERIC( option, type )                            \
558     p_config =  config_FindConfig( VLC_OBJECT(p_intf), option );  \
559     if( p_config )                                                \
560     {                                                             \
561         control =  new type ## ConfigControl( VLC_OBJECT(p_intf), \
562                 p_config, options, false, optionsLayout, line );  \
563         controls->append( control );                               \
564     }
565
566 #define CONFIG_GENERIC_NOBOOL( option, type )                     \
567     p_config =  config_FindConfig( VLC_OBJECT(p_intf), option );  \
568     if( p_config )                                                \
569     {                                                             \
570         control =  new type ## ConfigControl( VLC_OBJECT(p_intf), \
571                 p_config, options, optionsLayout, line );  \
572         controls->append( control );                               \
573     }
574
575     CONFIG_GENERIC( "album-art", IntegerList ); line++;
576 #ifdef UPDATE_CHECK
577     CONFIG_GENERIC_NOBOOL( "qt-updates-notif", Bool ); line++;
578 #endif
579
580     QPushButton *ok = new QPushButton( qtr( "OK" ) );
581
582     gLayout->addWidget( ok, 2, 2 );
583
584     CONNECT( ok, clicked(), privacy, accept() );
585     return privacy->exec();
586 }
587
588
589 /**********************************************************************
590  * Handling of sizing of the components
591  **********************************************************************/
592
593 /* This function is probably wrong, but we don't have many many choices...
594    Since we can't know from the playlist Widget if we are inside a dock or not,
595    because the playlist Widget can be called by THEDP, as a separate windows for
596    the skins.
597    Maybe the other solution is to redefine the sizeHint() of the playlist and
598    ask _parent->isFloating()...
599    If you think this would be better, please FIXME it...
600 */
601
602 QSize MainInterface::sizeHint() const
603 {
604     if( b_keep_size )
605     {
606         if( i_visualmode == QT_ALWAYS_VIDEO_MODE ||
607             i_visualmode == QT_MINIMAL_MODE )
608         {
609                 return mainVideoSize;
610         }
611         else
612         {
613             if( VISIBLE( bgWidget) ||
614                 ( videoIsActive && videoWidget->isVisible() )
615               )
616                 return mainVideoSize;
617             else
618                 return mainBasedSize;
619         }
620     }
621
622     int nwidth  = controls->sizeHint().width();
623     int nheight = controls->isVisible() ?
624                   controls->size().height()
625                   + inputC->size().height()
626                   + menuBar()->size().height()
627                   + statusBar()->size().height()
628                   : 0 ;
629
630     if( VISIBLE( bgWidget ) )
631     {
632         if( i_bg_height )
633             nheight += i_bg_height;
634         else
635             nheight += bgWidget->size().height();
636         nwidth  = __MAX( nwidth, bgWidget->size().width() );
637     }
638     else if( videoIsActive && videoWidget->isVisible() )
639     {
640         nheight += videoWidget->sizeHint().height();
641         nwidth  = __MAX( nwidth, videoWidget->sizeHint().width() );
642     }
643 #if 0
644     if( !dockPL->isFloating() && dockPL->isVisible() && dockPL->widget()  )
645     {
646         nheight += dockPL->size().height();
647         nwidth = __MAX( nwidth, dockPL->size().width() );
648         msg_Warn( p_intf, "3 %i %i", nheight, nwidth );
649     }
650 #endif
651     return QSize( nwidth, nheight );
652 }
653
654 void MainInterface::toggleFSC()
655 {
656    if( !fullscreenControls ) return;
657
658    IMEvent *eShow = new IMEvent( FullscreenControlToggle_Type, 0 );
659    QApplication::postEvent( fullscreenControls, eShow );
660 }
661
662 void MainInterface::popupMenu( const QPoint &p )
663 {
664     /* Ow, that's ugly: don't show the popup menu if cursor over
665      * the main menu bar or the status bar */
666     if( !childAt( p ) || ( ( childAt( p ) != menuBar() )
667                         && ( childAt( p )->parentWidget() != statusBar() ) ) )
668         QVLCMenu::PopupMenu( p_intf, true );
669 }
670
671 void MainInterface::debug()
672 {
673 #ifndef NDEBUG
674     msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
675     msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
676     if( videoWidget && videoWidget->isVisible() )
677     {
678         msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
679         msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
680     }
681 #endif
682 }
683
684 /****************************************************************************
685  * Video Handling
686  ****************************************************************************/
687
688 /* This event is used to deal with the fullscreen and always on top
689    issue conflict (bug in wx) */
690 class SetVideoOnTopQtEvent : public QEvent
691 {
692 public:
693     SetVideoOnTopQtEvent( bool _onTop ) :
694       QEvent( (QEvent::Type)SetVideoOnTopEvent_Type ), onTop( _onTop)
695     {}
696
697     bool OnTop() const { return onTop; }
698
699 private:
700     bool onTop;
701 };
702
703 /**
704  * README
705  * Thou shall not call/resize/hide widgets from on another thread.
706  * This is wrong, and this is THE reason to emit signals on those Video Functions
707  **/
708 WId MainInterface::requestVideo( vout_thread_t *p_nvout, int *pi_x,
709                                  int *pi_y, unsigned int *pi_width,
710                                  unsigned int *pi_height )
711 {
712     /* Request the videoWidget */
713     WId ret = videoWidget->request( p_nvout,pi_x, pi_y,
714                                     pi_width, pi_height, b_keep_size );
715     if( ret ) /* The videoWidget is available */
716     {
717         /* Did we have a bg ? Hide it! */
718         if( VISIBLE( bgWidget) )
719         {
720             bgWasVisible = true;
721             emit askBgWidgetToToggle();
722         }
723         else
724             bgWasVisible = false;
725
726         /* ask videoWidget to show */
727         emit askVideoToShow( *pi_width, *pi_height );
728
729         /* Consider the video active now */
730         videoIsActive = true;
731
732         emit askUpdate();
733     }
734     return ret;
735 }
736
737 /* Call from the WindowClose function */
738 void MainInterface::releaseVideo( void )
739 {
740     emit askReleaseVideo( );
741 }
742
743 /* Function that is CONNECTED to the previous emit */
744 void MainInterface::releaseVideoSlot( void )
745 {
746     videoWidget->release( );
747
748     if( bgWasVisible )
749     {
750         /* Reset the bg state */
751         bgWasVisible = false;
752         bgWidget->show();
753     }
754
755     videoIsActive = false;
756
757     /* Try to resize, except when you are in Fullscreen mode */
758     if( !isFullScreen() ) doComponentsUpdate();
759 }
760
761 /* Call from WindowControl function */
762 int MainInterface::controlVideo( int i_query, va_list args )
763 {
764     int i_ret = VLC_SUCCESS;
765     switch( i_query )
766     {
767         case VOUT_SET_SIZE:
768         {
769             unsigned int i_width  = va_arg( args, unsigned int );
770             unsigned int i_height = va_arg( args, unsigned int );
771             emit askVideoToResize( i_width, i_height );
772             emit askUpdate();
773             break;
774         }
775         case VOUT_SET_STAY_ON_TOP:
776         {
777             int i_arg = va_arg( args, int );
778             QApplication::postEvent( this, new SetVideoOnTopQtEvent( i_arg ) );
779             break;
780         }
781         default:
782             i_ret = VLC_EGENERIC;
783             msg_Warn( p_intf, "unsupported control query" );
784             break;
785     }
786     return i_ret;
787 }
788
789 /*****************************************************************************
790  * Playlist, Visualisation and Menus handling
791  *****************************************************************************/
792 /**
793  * Toggle the playlist widget or dialog
794  **/
795 void MainInterface::togglePlaylist()
796 {
797     /* CREATION
798     If no playlist exist, then create one and attach it to the DockPL*/
799     if( !playlistWidget )
800     {
801         playlistWidget = new PlaylistWidget( p_intf );
802
803         i_pl_dock = PL_UNDOCKED;
804 /*        i_pl_dock = (pl_dock_e)getSettings()
805                          ->value( "pl-dock-status", PL_UNDOCKED ).toInt(); */
806
807         if( i_pl_dock == PL_UNDOCKED )
808         {
809             playlistWidget->setWindowFlags( Qt::Window );
810
811             /* This will restore the geometry but will not work for position,
812                because of parenting */
813             QVLCTools::restoreWidgetPosition( p_intf, "Playlist",
814                     playlistWidget, QSize( 600, 300 ) );
815         }
816         else
817         {
818             mainLayout->insertWidget( 4, playlistWidget );
819         }
820         playlistVisible = true;
821
822         playlistWidget->show();
823     }
824     else
825     {
826     /* toggle the visibility of the playlist */
827        TOGGLEV( playlistWidget );
828        playlistVisible = !playlistVisible;
829        //doComponentsUpdate(); //resize( sizeHint() );
830     }
831 }
832
833 /* Function called from the menu to undock the playlist */
834 void MainInterface::undockPlaylist()
835 {
836 //    dockPL->setFloating( true );
837 //    adjustSize();
838 }
839
840 void MainInterface::dockPlaylist( pl_dock_e i_pos )
841 {
842 }
843
844 void MainInterface::toggleMinimalView( bool b_switch )
845 {
846     if( i_visualmode != QT_ALWAYS_VIDEO_MODE &&
847         i_visualmode != QT_MINIMAL_MODE )
848     { /* NORMAL MODE then */
849         if( !videoWidget || videoWidget->isHidden() )
850         {
851             emit askBgWidgetToToggle();
852         }
853         else
854         {
855             /* If video is visible, then toggle the status of bgWidget */
856             bgWasVisible = !bgWasVisible;
857         }
858     }
859
860     i_bg_height = bgWidget->height();
861
862     menuBar()->setVisible( !b_switch );
863     controls->setVisible( !b_switch );
864     statusBar()->setVisible( !b_switch );
865     inputC->setVisible( !b_switch );
866
867     doComponentsUpdate();
868
869     emit minimalViewToggled( b_switch );
870 }
871
872 /* Video widget cannot do this synchronously as it runs in another thread */
873 /* Well, could it, actually ? Probably dangerous ... */
874
875 /* This function is called:
876    - toggling of minimal View
877    - through askUpdate() by Vout thread request video and resize video (zoom)
878    - Advanced buttons toggled
879  */
880 void MainInterface::doComponentsUpdate()
881 {
882     msg_Dbg( p_intf, "Updating the geometry" );
883     /* Here we resize to sizeHint() and not adjustsize because we want
884        the videoWidget to be exactly the correctSize */
885     resize( sizeHint() );
886     //    adjustSize()  ;
887 #ifndef NDEBUG
888     debug();
889 #endif
890 }
891
892 /* toggling advanced controls buttons */
893 void MainInterface::toggleAdvanced()
894 {
895     controls->toggleAdvanced();
896 //    if( fullscreenControls ) fullscreenControls->toggleAdvanced();
897 }
898
899 /* Get the visibility status of the controls (hidden or not, advanced or not) */
900 int MainInterface::getControlsVisibilityStatus()
901 {
902     return( (controls->isVisible() ? CONTROLS_VISIBLE : CONTROLS_HIDDEN )
903                 + CONTROLS_ADVANCED * controls->b_advancedVisible );
904 }
905
906 #if 0
907 void MainInterface::visual()
908 {
909     if( !VISIBLE( visualSelector) )
910     {
911         visualSelector->show();
912         if( !THEMIM->getIM()->hasVideo() )
913         {
914             /* Show the background widget */
915         }
916         visualSelectorEnabled = true;
917     }
918     else
919     {
920         /* Stop any currently running visualization */
921         visualSelector->hide();
922         visualSelectorEnabled = false;
923     }
924     doComponentsUpdate();
925 }
926 #endif
927
928 /************************************************************************
929  * Other stuff
930  ************************************************************************/
931 void MainInterface::setName( QString name )
932 {
933     input_name = name; /* store it for the QSystray use */
934     /* Display it in the status bar, but also as a Tooltip in case it doesn't
935        fit in the label */
936     nameLabel->setText( " " + name + " " );
937     nameLabel->setToolTip( " " + name +" " );
938 }
939
940 /*****************************************************************************
941  * Systray Icon and Systray Menu
942  *****************************************************************************/
943
944 /**
945  * Create a SystemTray icon and a menu that would go with it.
946  * Connects to a click handler on the icon.
947  **/
948 void MainInterface::createSystray()
949 {
950     QIcon iconVLC;
951     if( QDate::currentDate().dayOfYear() >= 354 )
952         iconVLC =  QIcon( QPixmap( ":/vlc128-christmas.png" ) );
953     else
954         iconVLC =  QIcon( QPixmap( ":/vlc128.png" ) );
955     sysTray = new QSystemTrayIcon( iconVLC, this );
956     sysTray->setToolTip( qtr( "VLC media player" ));
957
958     systrayMenu = new QMenu( qtr( "VLC media player" ), this );
959     systrayMenu->setIcon( iconVLC );
960
961     QVLCMenu::updateSystrayMenu( this, p_intf, true );
962     sysTray->show();
963
964     CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
965             this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
966 }
967
968 /**
969  * Updates the Systray Icon's menu and toggle the main interface
970  */
971 void MainInterface::toggleUpdateSystrayMenu()
972 {
973     /* If hidden, show it */
974     if( isHidden() )
975     {
976         show();
977         activateWindow();
978     }
979     else if( isMinimized() )
980     {
981         /* Minimized */
982         showNormal();
983         activateWindow();
984     }
985     else
986     {
987         /* Visible (possibly under other windows) */
988 #ifdef WIN32
989         /* check if any visible window is above vlc in the z-order,
990          * but ignore the ones always on top
991          * and the ones which can't be activated */
992         WINDOWINFO wi;
993         HWND hwnd;
994         wi.cbSize = sizeof( WINDOWINFO );
995         for( hwnd = GetNextWindow( internalWinId(), GW_HWNDPREV );
996                 hwnd && ( !IsWindowVisible( hwnd ) ||
997                     ( GetWindowInfo( hwnd, &wi ) &&
998                       (wi.dwExStyle&WS_EX_NOACTIVATE) ) );
999                 hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) );
1000             if( !hwnd || !GetWindowInfo( hwnd, &wi ) ||
1001                 (wi.dwExStyle&WS_EX_TOPMOST) )
1002             {
1003                 hide();
1004             }
1005             else
1006             {
1007                 activateWindow();
1008             }
1009 #else
1010         hide();
1011 #endif
1012     }
1013     QVLCMenu::updateSystrayMenu( this, p_intf );
1014 }
1015
1016 void MainInterface::handleSystrayClick(
1017                                     QSystemTrayIcon::ActivationReason reason )
1018 {
1019     switch( reason )
1020     {
1021         case QSystemTrayIcon::Trigger:
1022         case QSystemTrayIcon::DoubleClick:
1023             toggleUpdateSystrayMenu();
1024             break;
1025         case QSystemTrayIcon::MiddleClick:
1026             sysTray->showMessage( qtr( "VLC media player" ),
1027                     qtr( "Control menu for the player" ),
1028                     QSystemTrayIcon::Information, 3000 );
1029             break;
1030         default:
1031             break;
1032     }
1033 }
1034
1035 /**
1036  * Updates the name of the systray Icon tooltip.
1037  * Doesn't check if the systray exists, check before you call it.
1038  **/
1039 void MainInterface::updateSystrayTooltipName( QString name )
1040 {
1041     if( name.isEmpty() )
1042     {
1043         sysTray->setToolTip( qtr( "VLC media player" ) );
1044     }
1045     else
1046     {
1047         sysTray->setToolTip( name );
1048         if( notificationEnabled && ( isHidden() || isMinimized() ) )
1049         {
1050             sysTray->showMessage( qtr( "VLC media player" ), name,
1051                     QSystemTrayIcon::NoIcon, 3000 );
1052         }
1053     }
1054
1055     QVLCMenu::updateSystrayMenu( this, p_intf );
1056 }
1057
1058 /**
1059  * Updates the status of the systray Icon tooltip.
1060  * Doesn't check if the systray exists, check before you call it.
1061  **/
1062 void MainInterface::updateSystrayTooltipStatus( int i_status )
1063 {
1064     switch( i_status )
1065     {
1066         case  0:
1067         case  END_S:
1068             {
1069                 sysTray->setToolTip( qtr( "VLC media player" ) );
1070                 break;
1071             }
1072         case PLAYING_S:
1073             {
1074                 sysTray->setToolTip( input_name );
1075                 break;
1076             }
1077         case PAUSE_S:
1078             {
1079                 sysTray->setToolTip( input_name + " - "
1080                         + qtr( "Paused") );
1081                 break;
1082             }
1083     }
1084 }
1085
1086 /************************************************************************
1087  * D&D Events
1088  ************************************************************************/
1089 void MainInterface::dropEvent(QDropEvent *event)
1090 {
1091     dropEventPlay( event, true );
1092 }
1093
1094 void MainInterface::dropEventPlay( QDropEvent *event, bool b_play )
1095 {
1096      const QMimeData *mimeData = event->mimeData();
1097
1098      /* D&D of a subtitles file, add it on the fly */
1099      if( mimeData->urls().size() == 1 )
1100      {
1101         if( THEMIM->getIM()->hasInput() )
1102         {
1103             if( !input_AddSubtitle( THEMIM->getInput(),
1104                                     qtu( toNativeSeparators(
1105                                          mimeData->urls()[0].toLocalFile() ) ),
1106                                     true ) )
1107             {
1108                 event->acceptProposedAction();
1109                 return;
1110             }
1111         }
1112      }
1113      bool first = b_play;
1114      foreach( const QUrl &url, mimeData->urls() )
1115      {
1116         QString s = toNativeSeparators( url.toLocalFile() );
1117
1118         if( s.length() > 0 ) {
1119             playlist_Add( THEPL, qtu(s), NULL,
1120                           PLAYLIST_APPEND | (first ? PLAYLIST_GO: 0),
1121                           PLAYLIST_END, true, false );
1122             first = false;
1123             RecentsMRL::getInstance( p_intf )->addRecent( s );
1124         }
1125      }
1126      event->acceptProposedAction();
1127 }
1128 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1129 {
1130      event->acceptProposedAction();
1131 }
1132 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1133 {
1134      event->acceptProposedAction();
1135 }
1136 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1137 {
1138      event->accept();
1139 }
1140
1141 /************************************************************************
1142  * Events stuff
1143  ************************************************************************/
1144 void MainInterface::customEvent( QEvent *event )
1145 {
1146 #if 0
1147     if( event->type() == PLDockEvent_Type )
1148     {
1149         PlaylistDialog::killInstance();
1150         playlistEmbeddedFlag = true;
1151         menuBar()->clear();
1152         QVLCMenu::createMenuBar(this, p_intf, true, visualSelectorEnabled);
1153         togglePlaylist();
1154     }
1155 #endif
1156     /*else */
1157     if ( event->type() == (int)SetVideoOnTopEvent_Type )
1158     {
1159         SetVideoOnTopQtEvent* p_event = (SetVideoOnTopQtEvent*)event;
1160         if( p_event->OnTop() )
1161             setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
1162         else
1163             setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
1164         show(); /* necessary to apply window flags?? */
1165     }
1166 }
1167
1168 void MainInterface::keyPressEvent( QKeyEvent *e )
1169 {
1170     if( ( e->modifiers() &  Qt::ControlModifier ) && ( e->key() == Qt::Key_H )
1171           && !menuBar()->isVisible() )
1172     {
1173         toggleMinimalView( false );
1174         e->accept();
1175     }
1176
1177     int i_vlck = qtEventToVLCKey( e );
1178     if( i_vlck > 0 )
1179     {
1180         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1181         e->accept();
1182     }
1183     else
1184         e->ignore();
1185 }
1186
1187 void MainInterface::resizeEvent( QResizeEvent * event )
1188 {
1189     if( b_keep_size )
1190     {
1191         if( i_visualmode == QT_ALWAYS_VIDEO_MODE ||
1192             i_visualmode == QT_MINIMAL_MODE )
1193         {
1194                 mainVideoSize = size();
1195         }
1196         else
1197         {
1198             if( VISIBLE( bgWidget) ||
1199                 ( videoIsActive && videoWidget->isVisible() )
1200               )
1201                 mainVideoSize = size();
1202             else
1203                 mainBasedSize = size();
1204         }
1205     }
1206 }
1207
1208 void MainInterface::wheelEvent( QWheelEvent *e )
1209 {
1210     int i_vlckey = qtWheelEventToVLCKey( e );
1211     var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
1212     e->accept();
1213 }
1214
1215 void MainInterface::closeEvent( QCloseEvent *e )
1216 {
1217     e->accept();
1218     hide();
1219     THEDP->quit();
1220 }
1221
1222 void MainInterface::toggleFullScreen( void )
1223 {
1224     if( isFullScreen() )
1225     {
1226         showNormal();
1227         emit askUpdate(); // Needed if video was launched after the F11
1228         emit fullscreenInterfaceToggled( false );
1229     }
1230     else
1231     {
1232         showFullScreen();
1233         emit fullscreenInterfaceToggled( true );
1234     }
1235
1236 }
1237
1238 /*****************************************************************************
1239  * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1240  *  We don't show the menu directly here because we don't want the
1241  *  caller to block for a too long time.
1242  *****************************************************************************/
1243 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
1244                         vlc_value_t old_val, vlc_value_t new_val, void *param )
1245 {
1246     intf_thread_t *p_intf = (intf_thread_t *)param;
1247
1248     if( p_intf->pf_show_dialog )
1249     {
1250         p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1251                                 new_val.b_bool, NULL );
1252     }
1253
1254     return VLC_SUCCESS;
1255 }
1256
1257 /*****************************************************************************
1258  * IntfShowCB: callback triggered by the intf-show libvlc variable.
1259  *****************************************************************************/
1260 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
1261                        vlc_value_t old_val, vlc_value_t new_val, void *param )
1262 {
1263     intf_thread_t *p_intf = (intf_thread_t *)param;
1264     p_intf->p_sys->p_mi->toggleFSC();
1265
1266     /* Show event */
1267      return VLC_SUCCESS;
1268 }
1269