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