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