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