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