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