]> git.sesse.net Git - vlc/blob - modules/gui/qt4/main_interface.cpp
09d88dd6a9b0ff3702504883e61cf3f7d448cbe1
[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
46 #include <assert.h>
47 #include <vlc_keys.h>
48 #include <vlc_vout.h>
49
50 #ifdef WIN32
51     #define PREF_W 410
52     #define PREF_H 151
53 #else
54     #define PREF_W 450
55     #define PREF_H 160
56 #endif
57
58 #define SET_WIDTH(i,j) i->widgetSize.setWidth(j)
59 #define SET_HEIGHT(i,j) i->widgetSize.setHeight(j)
60 #define SET_WH( i,j,k) i->widgetSize.setWidth(j); i->widgetSize.setHeight(k);
61
62 #define DS(i) i.width(),i.height()
63
64 /* Callback prototypes */
65 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
66                         vlc_value_t old_val, vlc_value_t new_val, void *param );
67 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
68                        vlc_value_t old_val, vlc_value_t new_val, void *param );
69 static int InteractCallback( vlc_object_t *, const char *, vlc_value_t,
70                              vlc_value_t, void *);
71 /* Video handling */
72 static void *DoRequest( intf_thread_t *p_intf, vout_thread_t *p_vout,
73                         int *pi1, int *pi2, unsigned int*pi3,unsigned int*pi4)
74 {
75     return p_intf->p_sys->p_mi->requestVideo( p_vout, pi1, pi2, pi3, pi4 );
76 }
77 static void DoRelease( intf_thread_t *p_intf, void *p_win )
78 {
79     return p_intf->p_sys->p_mi->releaseVideo( p_win );
80 }
81 static int DoControl( intf_thread_t *p_intf, void *p_win, int i_q, va_list a )
82 {
83     return p_intf->p_sys->p_mi->controlVideo( p_win, i_q, a );
84 }
85
86 MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf )
87 {
88     /* Variables initialisation */
89     need_components_update = false;
90     bgWidget = NULL; videoWidget = NULL; playlistWidget = NULL;
91     embeddedPlaylistWasActive = videoIsActive = false;
92     input_name = "";
93
94     /**
95      *  Configuration and settings
96      **/
97     settings = new QSettings( "VideoLAN", "VLC" );
98     settings->beginGroup( "MainWindow" );
99
100     /* Main settings */
101     setFocusPolicy( Qt::StrongFocus );
102     setAcceptDrops(true);
103     setWindowIcon( QApplication::windowIcon() );
104     setWindowOpacity( config_GetFloat( p_intf, "qt-opacity" ) );
105
106     /* Set The Video In emebedded Mode or not */
107     videoEmbeddedFlag = false;
108     if( config_GetInt( p_intf, "embedded-video" ) )
109         videoEmbeddedFlag = true;
110
111     alwaysVideoFlag = false;
112     if( videoEmbeddedFlag && config_GetInt( p_intf, "qt-always-video" ) )
113         alwaysVideoFlag = true;
114
115     /* Set the other interface settings */
116     playlistEmbeddedFlag = settings->value( "playlist-embedded", true).toBool();
117     visualSelectorEnabled = settings->value( "visual-selector", false ).toBool();
118     notificationEnabled = config_GetInt( p_intf, "qt-notification" )
119                           ? true : false;
120     /**************************
121      *  UI and Widgets design
122      **************************/
123     setVLCWindowsTitle();
124     handleMainUi( settings );
125
126     /* Menu Bar */
127     QVLCMenu::createMenuBar( this, p_intf, playlistEmbeddedFlag,
128                              isAdvancedVisible(), visualSelectorEnabled );
129
130     /* Status Bar */
131     /**
132      * TODO: clicking on the elapsed time should switch to the remaining time
133      **/
134     /**
135      * TODO: do we add a label for the current Volume ?
136      **/
137     b_remainingTime = false;
138     timeLabel = new QLabel;
139     nameLabel = new QLabel;
140     speedLabel = new QLabel( "1.0x" );
141     timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
142     speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
143     statusBar()->addWidget( nameLabel, 8 );
144     statusBar()->addPermanentWidget( speedLabel, 0 );
145     statusBar()->addPermanentWidget( timeLabel, 2 );
146     speedLabel->setContextMenuPolicy ( Qt::CustomContextMenu );
147     timeLabel->setContextMenuPolicy ( Qt::CustomContextMenu );
148     timeLabel->installEventFilter( this );
149     CONNECT( speedLabel, customContextMenuRequested( QPoint ),
150              this, showSpeedMenu( QPoint ) );
151     CONNECT( timeLabel, customContextMenuRequested( QPoint ),
152              this, showTimeMenu( QPoint ) );
153
154     /**********************
155      * Systray Management *
156      **********************/
157     sysTray = NULL;
158     bool b_createSystray = false;
159     bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
160     if( config_GetInt( p_intf, "qt-start-minimized") )
161     {
162         if( b_systrayAvailable ){
163             b_createSystray = true;
164             hide(); //FIXME
165         }
166         else msg_Warn( p_intf, "You can't minize if you haven't a system "
167                 "tray bar" );
168     }
169     if( config_GetInt( p_intf, "qt-system-tray") )
170         b_createSystray = true;
171
172     if( b_systrayAvailable && b_createSystray )
173             createSystray();
174
175     /* Init input manager */
176     MainInputManager::getInstance( p_intf );
177     ON_TIMEOUT( updateOnTimer() );
178
179     /**
180      * Various CONNECTs
181      **/
182
183     /* Connect the input manager to the GUI elements it manages */
184     /* It is also connected to the control->slider, see the ControlsWidget */
185     CONNECT( THEMIM->getIM(), positionUpdated( float, int, int ),
186              this, setDisplay( float, int, int ) );
187
188     /** Connects on nameChanged() */
189     /* Naming in the controller statusbar */
190     CONNECT( THEMIM->getIM(), nameChanged( QString ), this,
191              setName( QString ) );
192     /* and in the systray */
193     if( sysTray )
194     {
195         CONNECT( THEMIM->getIM(), nameChanged( QString ), this,
196                  updateSystrayTooltipName( QString ) );
197     }
198     /* and in the title of the controller */
199     if( config_GetInt( p_intf, "qt-name-in-title" ) )
200     {
201         CONNECT( THEMIM->getIM(), nameChanged( QString ), this,
202              setVLCWindowsTitle( QString ) );
203     }
204
205     /** CONNECTS on PLAY_STATUS **/
206     /* Status on the main controller */
207     CONNECT( THEMIM->getIM(), statusChanged( int ), this, setStatus( int ) );
208     /* and in the systray */
209     if( sysTray )
210     {
211         CONNECT( THEMIM->getIM(), statusChanged( int ), this,
212                  updateSystrayTooltipStatus( int ) );
213     }
214
215     /**
216      * Callbacks
217      **/
218     var_Create( p_intf, "interaction", VLC_VAR_ADDRESS );
219     var_AddCallback( p_intf, "interaction", InteractCallback, this );
220     p_intf->b_interaction = VLC_TRUE;
221
222     /* Register callback for the intf-popupmenu variable */
223     playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_intf,
224                                         VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
225     if( p_playlist != NULL )
226     {
227         var_AddCallback( p_playlist, "intf-popupmenu", PopupMenuCB, p_intf );
228         var_AddCallback( p_playlist, "intf-show", IntfShowCB, p_intf );
229         vlc_object_release( p_playlist );
230     }
231 }
232
233 MainInterface::~MainInterface()
234 {
235     /* Unregister callback for the intf-popupmenu variable */
236     playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_intf,
237                                         VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
238     if( p_playlist != NULL )
239     {
240         var_DelCallback( p_playlist, "intf-popupmenu", PopupMenuCB, p_intf );
241         var_DelCallback( p_playlist, "intf-show", IntfShowCB, p_intf );
242         vlc_object_release( p_playlist );
243     }
244
245     settings->setValue( "playlist-embedded", playlistEmbeddedFlag );
246     settings->setValue( "adv-controls", isAdvancedVisible() );
247     settings->setValue( "pos", pos() );
248     settings->endGroup();
249     delete settings;
250     p_intf->b_interaction = VLC_FALSE;
251     var_DelCallback( p_intf, "interaction", InteractCallback, this );
252
253     p_intf->pf_request_window = NULL;
254     p_intf->pf_release_window = NULL;
255     p_intf->pf_control_window = NULL;
256 }
257
258 /*****************************
259  *   Main UI handling        *
260  *****************************/
261
262 /**
263  * Give the decorations of the Main Window a correct Name.
264  * If nothing is given, set it to VLC...
265  **/
266 void MainInterface::setVLCWindowsTitle( QString aTitle )
267 {
268     if( aTitle.isEmpty() )
269     {
270         setWindowTitle( qtr( "VLC media player" ) );
271     }
272     else
273     {
274         setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
275     }
276 }
277
278
279 void MainInterface::handleMainUi( QSettings *settings )
280 {
281     /* Create the main Widget and the mainLayout */
282     QWidget *main = new QWidget( this );
283     mainLayout = new QVBoxLayout( main );
284     setCentralWidget( main );
285
286     /* Margins, spacing */
287     main->setContentsMargins( 0, 0, 0, 0 );
288     mainLayout->setMargin( 0 );
289
290     /* Create the CONTROLS Widget */
291     controls = new ControlsWidget( p_intf,
292                    settings->value( "adv-controls", false ).toBool() );
293
294     /* Configure the Controls */
295     BUTTON_SET_IMG( controls->playlistButton, "" , playlist_icon.png,
296                     playlistEmbeddedFlag ?  qtr( "Show playlist" ) :
297                                             qtr( "Open playlist" ) );
298     BUTTONACT( controls->playlistButton, togglePlaylist() );
299
300     /* Add the controls Widget to the main Widget */
301     mainLayout->addWidget( controls );
302
303
304     /* Set initial size */
305     resize( PREF_W, PREF_H );
306     addSize = QSize( mainLayout->margin() * 2, PREF_H );
307
308     /* Visualisation */
309     visualSelector = new VisualSelector( p_intf );
310     mainLayout->insertWidget( 0, visualSelector );
311     visualSelector->hide();
312
313     /* And video Outputs */
314     if( alwaysVideoFlag )
315     {
316         bgWidget = new BackgroundWidget( p_intf );
317         bgWidget->widgetSize = settings->value( "backgroundSize",
318                                            QSize( 300, 300 ) ).toSize();
319         bgWidget->resize( bgWidget->widgetSize );
320         bgWidget->updateGeometry();
321         mainLayout->insertWidget( 0, bgWidget );
322     }
323
324     if( videoEmbeddedFlag )
325     {
326         videoWidget = new VideoWidget( p_intf );
327         videoWidget->widgetSize = QSize( 1, 1 );
328         //videoWidget->resize( videoWidget->widgetSize );
329         mainLayout->insertWidget( 0, videoWidget );
330
331         p_intf->pf_request_window  = ::DoRequest;
332         p_intf->pf_release_window  = ::DoRelease;
333         p_intf->pf_control_window  = ::DoControl;
334     }
335
336     /* Finish the sizing */
337     setMinimumSize( PREF_W, addSize.height() );
338 }
339
340 /**********************************************************************
341  * Handling of sizing of the components
342  **********************************************************************/
343 void MainInterface::calculateInterfaceSize()
344 {
345     int width = 0, height = 0;
346     if( VISIBLE( bgWidget ) )
347     {
348         width = bgWidget->widgetSize.width();
349         height = bgWidget->widgetSize.height();
350         assert( !(playlistWidget && playlistWidget->isVisible() ) );
351     }
352     else if( VISIBLE( playlistWidget ) )
353     {
354         width = playlistWidget->widgetSize.width();
355         height = playlistWidget->widgetSize.height();
356     }
357     else if( videoIsActive )
358     {
359         width =  videoWidget->widgetSize.width() ;
360         height = videoWidget->widgetSize.height();
361     }
362     else
363     {
364         width = PREF_W - addSize.width();
365         height = PREF_H - addSize.height();
366     }
367     if( VISIBLE( visualSelector ) )
368         height += visualSelector->height();
369 /*    if( VISIBLE( advControls) )
370     {
371         height += advControls->sizeHint().height();
372     }*/
373     mainSize = QSize( width + addSize.width(), height + addSize.height() );
374 }
375
376 void MainInterface::resizeEvent( QResizeEvent *e )
377 {
378     videoWidget->widgetSize.setWidth(  e->size().width() - addSize.width() );
379     if( videoWidget && videoIsActive && videoWidget->widgetSize.height() > 1 )
380     {
381         SET_WH( videoWidget, e->size().width() - addSize.width(),
382                              e->size().height()  - addSize.height() );
383         videoWidget->updateGeometry();
384     }
385     if( VISIBLE( playlistWidget ) )
386     {
387         SET_WH( playlistWidget , e->size().width() - addSize.width(),
388                                  e->size().height() - addSize.height() );
389         playlistWidget->updateGeometry();
390     }
391 }
392
393 /****************************************************************************
394  * Small right-click menus
395  ****************************************************************************/
396 void MainInterface::showSpeedMenu( QPoint pos )
397 {
398     QMenu menu( this );
399     menu.addAction( "Not Implemented Yet" );
400     menu.exec( QCursor::pos() );
401 }
402
403 void MainInterface::showTimeMenu( QPoint pos )
404 {
405     QMenu menu( this );
406     menu.addAction(  qtr("Elapsed Time") , this, SLOT( setElapsedTime() ) );
407     menu.addAction(  qtr("Remaining Time") , this, SLOT( setRemainTime() ) );
408     menu.exec( QCursor::pos() );
409 }
410
411 /****************************************************************************
412  * Video Handling
413  ****************************************************************************/
414 void *MainInterface::requestVideo( vout_thread_t *p_nvout, int *pi_x,
415                                    int *pi_y, unsigned int *pi_width,
416                                    unsigned int *pi_height )
417 {
418     void *ret = videoWidget->request( p_nvout,pi_x, pi_y, pi_width, pi_height );
419     if( ret )
420     {
421         videoIsActive = true;
422         if( VISIBLE( playlistWidget ) )
423         {
424             embeddedPlaylistWasActive = true;
425 //            playlistWidget->hide();
426         }
427         bool bgWasVisible = false;
428         if( VISIBLE( bgWidget) )
429         {
430             bgWasVisible = true;
431             bgWidget->hide();
432         }
433         if( THEMIM->getIM()->hasVideo() || !bgWasVisible )
434         {
435             videoWidget->widgetSize = QSize( *pi_width, *pi_height );
436         }
437         else /* Background widget available, use its size */
438         {
439             /* Ok, our visualizations are bad, so don't do this for the moment
440              * use the requested size anyway */
441             // videoWidget->widgetSize = bgWidget->widgeTSize;
442             videoWidget->widgetSize = QSize( *pi_width, *pi_height );
443         }
444 //        videoWidget->updateGeometry(); /// FIXME: Needed ?
445         need_components_update = true;
446     }
447     return ret;
448 }
449
450 void MainInterface::releaseVideo( void *p_win )
451 {
452     videoWidget->release( p_win );
453     videoWidget->widgetSize = QSize( 0, 0 );
454     videoWidget->resize( videoWidget->widgetSize );
455
456     if( embeddedPlaylistWasActive )
457         playlistWidget->show();
458     else if( bgWidget )
459         bgWidget->show();
460
461     videoIsActive = false;
462     need_components_update = true;
463 }
464
465 class SetVideoOnTopQtEvent : public QEvent
466 {
467 public:
468     SetVideoOnTopQtEvent( bool _onTop ) :
469       QEvent( (QEvent::Type)SetVideoOnTopEvent_Type ), onTop( _onTop)
470     {
471     }
472
473     bool OnTop() const
474     {
475         return onTop;
476     }
477
478 private:
479     bool onTop;
480 };
481
482 int MainInterface::controlVideo( void *p_window, int i_query, va_list args )
483 {
484     int i_ret = VLC_EGENERIC;
485     switch( i_query )
486     {
487         case VOUT_GET_SIZE:
488         {
489             unsigned int *pi_width  = va_arg( args, unsigned int * );
490             unsigned int *pi_height = va_arg( args, unsigned int * );
491             *pi_width = videoWidget->widgetSize.width();
492             *pi_height = videoWidget->widgetSize.height();
493             i_ret = VLC_SUCCESS;
494             break;
495         }
496         case VOUT_SET_SIZE:
497         {
498             unsigned int i_width  = va_arg( args, unsigned int );
499             unsigned int i_height = va_arg( args, unsigned int );
500             videoWidget->widgetSize = QSize( i_width, i_height );
501             // videoWidget->updateGeometry();
502             need_components_update = true;
503             i_ret = VLC_SUCCESS;
504             break;
505         }
506         case VOUT_SET_STAY_ON_TOP:
507         {
508             int i_arg = va_arg( args, int );
509             QApplication::postEvent( this, new SetVideoOnTopQtEvent( i_arg ) );
510             i_ret = VLC_SUCCESS;
511             break;
512         }
513         default:
514             msg_Warn( p_intf, "unsupported control query" );
515             break;
516     }
517     return i_ret;
518 }
519
520 /*****************************************************************************
521  * Playlist, Visualisation and Menus handling
522  *****************************************************************************/
523 /**
524  * Toggle the playlist widget or dialog
525  **/
526 void MainInterface::togglePlaylist()
527 {
528     // Toggle the playlist dialog if not embedded and return
529     if( !playlistEmbeddedFlag )
530     {
531         if( playlistWidget )
532         {
533             /// \todo Destroy it
534         }
535         THEDP->playlistDialog();
536         return;
537     }
538
539     // Create the playlist Widget and destroy the existing dialog
540     if( !playlistWidget )
541     {
542         PlaylistDialog::killInstance();
543         playlistWidget = new PlaylistWidget( p_intf );
544         mainLayout->insertWidget( 0, playlistWidget );
545         playlistWidget->widgetSize = settings->value( "playlistSize",
546                                                QSize( 650, 310 ) ).toSize();
547         playlistWidget->hide();
548         if(bgWidget)
549         CONNECT( playlistWidget, artSet( QString ), bgWidget, setArt(QString) );
550     }
551
552     // And toggle visibility
553     if( VISIBLE( playlistWidget ) )
554     {
555         playlistWidget->hide();
556         if( bgWidget ) bgWidget->show();
557         if( videoIsActive )
558         {
559             videoWidget->widgetSize = savedVideoSize;
560             videoWidget->resize( videoWidget->widgetSize );
561             videoWidget->updateGeometry();
562             if( bgWidget ) bgWidget->hide();
563         }
564     }
565     else
566     {
567         playlistWidget->show();
568         if( videoIsActive )
569         {
570             savedVideoSize = videoWidget->widgetSize;
571             videoWidget->widgetSize.setHeight( 0 );
572             videoWidget->resize( videoWidget->widgetSize );
573             videoWidget->updateGeometry();
574         }
575         if( VISIBLE( bgWidget ) ) bgWidget->hide();
576     }
577
578     doComponentsUpdate();
579 }
580
581 void MainInterface::undockPlaylist()
582 {
583     if( playlistWidget )
584     {
585         playlistWidget->hide();
586         playlistWidget->deleteLater();
587         mainLayout->removeWidget( playlistWidget );
588         playlistWidget = NULL;
589         playlistEmbeddedFlag = false;
590
591         menuBar()->clear();
592         QVLCMenu::createMenuBar( this, p_intf, false, isAdvancedVisible(),
593                                  visualSelectorEnabled);
594
595         if( videoIsActive )
596         {
597             videoWidget->widgetSize = savedVideoSize;
598             videoWidget->resize( videoWidget->widgetSize );
599             videoWidget->updateGeometry();
600         }
601
602         doComponentsUpdate();
603         THEDP->playlistDialog();
604     }
605 }
606
607 #if 0
608 void MainInterface::visual()
609 {
610     if( !VISIBLE( visualSelector) )
611     {
612         visualSelector->show();
613         if( !THEMIM->getIM()->hasVideo() )
614         {
615             /* Show the background widget */
616         }
617         visualSelectorEnabled = true;
618     }
619     else
620     {
621         /* Stop any currently running visualization */
622         visualSelector->hide();
623         visualSelectorEnabled = false;
624     }
625     doComponentsUpdate();
626 }
627 #endif
628
629 void MainInterface::toggleMenus()
630 {
631     msg_Dbg( p_intf, "I HAS HERE, HIDING YOUR MENUZ: \\_o<~~ coin coin" );
632     TOGGLEV( controls );
633     TOGGLEV( statusBar() );
634     updateGeometry();
635 }
636
637 /* Video widget cannot do this synchronously as it runs in another thread */
638 /* Well, could it, actually ? Probably dangerous ... */
639 void MainInterface::doComponentsUpdate()
640 {
641     calculateInterfaceSize();
642     resize( mainSize );
643 }
644
645 void MainInterface::toggleAdvanced()
646 {
647     controls->toggleAdvanced();
648 }
649
650 bool MainInterface::isAdvancedVisible()
651 {
652     return controls->b_advancedVisible;
653 }
654
655 /************************************************************************
656  * Other stuff
657  ************************************************************************/
658 void MainInterface::setDisplay( float pos, int time, int length )
659 {
660     char psz_length[MSTRTIME_MAX_SIZE], psz_time[MSTRTIME_MAX_SIZE];
661     secstotimestr( psz_length, length );
662     secstotimestr( psz_time, b_remainingTime ? length - time : time );
663     QString title; title.sprintf( "%s/%s", psz_time, psz_length );
664     if( b_remainingTime ) timeLabel->setText( " -"+title+" " );
665     else timeLabel->setText( " "+title+" " );
666 }
667
668 void MainInterface::toggleTimeDisplay()
669 {
670     b_remainingTime = ( b_remainingTime ? false : true );
671 }
672
673 void MainInterface::setElapsedTime(){ b_remainingTime = false; }
674 void MainInterface::setRemainTime(){ b_remainingTime = true; }
675
676 void MainInterface::setName( QString name )
677 {
678     input_name = name;
679     nameLabel->setText( " " + name+" " );
680 }
681
682 void MainInterface::setStatus( int status )
683 {
684     controls->setStatus( status );
685     if( sysTray )
686         updateSystrayMenu( status );
687 }
688
689 void MainInterface::updateOnTimer()
690 {
691     /* \todo Make this event-driven */
692     if( intf_ShouldDie( p_intf ) )
693     {
694         QApplication::closeAllWindows();
695         QApplication::quit();
696     }
697     if( need_components_update )
698     {
699         doComponentsUpdate();
700         need_components_update = false;
701     }
702
703     controls->updateOnTimer();
704 }
705
706 /*****************************************************************************
707  * Systray Icon and Systray Menu
708  *****************************************************************************/
709
710 /**
711  * Create a SystemTray icon and a menu that would go with it.
712  * Connects to a click handler on the icon.
713  **/
714 void MainInterface::createSystray()
715 {
716     QIcon iconVLC =  QIcon( QPixmap( ":/vlc128.png" ) );
717     sysTray = new QSystemTrayIcon( iconVLC, this );
718     sysTray->setToolTip( qtr( "VLC media player" ));
719
720     systrayMenu = new QMenu( qtr( "VLC media player" ), this );
721     systrayMenu->setIcon( iconVLC );
722
723     QVLCMenu::updateSystrayMenu( this, p_intf, true );
724     sysTray->show();
725
726     CONNECT( sysTray, activated(  QSystemTrayIcon::ActivationReason ),
727             this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
728 }
729
730 /**
731  * Update the menu of the Systray Icon.
732  * May be unneedded, since it just calls QVLCMenu::update
733  * FIXME !!!
734  **/
735 void MainInterface::updateSystrayMenu( int status )
736 {
737     QVLCMenu::updateSystrayMenu( this, p_intf ) ;
738 }
739
740 /**
741  * Updates the Systray Icon's menu and toggle the main interface
742  */
743 void MainInterface::toggleUpdateSystrayMenu()
744 {
745     if( isHidden() )
746     {
747         show();
748         activateWindow();
749     }
750     else
751     {
752 #ifdef WIN32
753         /* check if any visible window is above vlc in the z-order,
754          * but ignore the ones always on top */
755         WINDOWINFO wi;
756         HWND hwnd;
757         wi.cbSize = sizeof( WINDOWINFO );
758         for( hwnd = GetNextWindow( internalWinId(), GW_HWNDPREV );
759                 hwnd && !IsWindowVisible( hwnd );
760                 hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) );
761         if( !hwnd || !GetWindowInfo( hwnd, &wi ) ||
762                 (wi.dwExStyle&WS_EX_TOPMOST) )
763 #else
764         if( isActiveWindow() )
765 #endif
766         {
767             hide();
768         }
769         else
770         {
771             activateWindow();
772         }
773     }
774     QVLCMenu::updateSystrayMenu( this, p_intf );
775 }
776
777 void MainInterface::handleSystrayClick(
778                                     QSystemTrayIcon::ActivationReason reason )
779 {
780     switch( reason )
781     {
782         case QSystemTrayIcon::Trigger:
783             toggleUpdateSystrayMenu();
784             break;
785         case QSystemTrayIcon::MiddleClick:
786             sysTray->showMessage( qtr( "VLC media player" ),
787                     qtr( "Control menu for the player" ),
788                     QSystemTrayIcon::Information, 4000 );
789             break;
790     }
791 }
792
793 /**
794  * Updates the name of the systray Icon tooltip.
795  * Doesn't check if the systray exists, check before you call it.
796  * FIXME !!! Fusion with next function ?
797  **/
798 void MainInterface::updateSystrayTooltipName( QString name )
799 {
800     if( name.isEmpty() )
801     {
802         sysTray->setToolTip( qtr( "VLC media player" ) );
803     }
804     else
805     {
806         sysTray->setToolTip( name );
807         if( notificationEnabled )
808         {
809             sysTray->showMessage( qtr( "VLC media player" ), name,
810                     QSystemTrayIcon::NoIcon, 4000 );
811         }
812     }
813 }
814
815 /**
816  * Updates the status of the systray Icon tooltip.
817  * Doesn't check if the systray exists, check before you call it.
818  **/
819 void MainInterface::updateSystrayTooltipStatus( int i_status )
820 {
821     switch( i_status )
822     {
823         case  0:
824             {
825                 sysTray->setToolTip( qtr( "VLC media player" ) );
826                 break;
827             }
828         case PLAYING_S:
829             {
830                 sysTray->setToolTip( input_name );
831                 //+ " - " + qtr( "Playing" ) );
832                 break;
833             }
834         case PAUSE_S:
835             {
836                 sysTray->setToolTip( input_name + " - "
837                         + qtr( "Paused") );
838                 break;
839             }
840     }
841 }
842
843 /************************************************************************
844  * D&D Events
845  ************************************************************************/
846 void MainInterface::dropEvent(QDropEvent *event)
847 {
848      const QMimeData *mimeData = event->mimeData();
849
850      /* D&D of a subtitles file, add it on the fly */
851      if( mimeData->urls().size() == 1 )
852      {
853         if( THEMIM->getIM()->hasInput() )
854         {
855             if( input_AddSubtitles( THEMIM->getInput(),
856                                     qtu( mimeData->urls()[0].toString() ),
857                                     VLC_TRUE ) )
858             {
859                 event->acceptProposedAction();
860                 return;
861             }
862         }
863      }
864      bool first = true;
865      foreach( QUrl url, mimeData->urls() ) {
866         QString s = url.toString();
867         if( s.length() > 0 ) {
868             playlist_Add( THEPL, qtu(s), NULL,
869                           PLAYLIST_APPEND | (first ? PLAYLIST_GO:0),
870                           PLAYLIST_END, VLC_TRUE, VLC_FALSE );
871             first = false;
872         }
873      }
874      event->acceptProposedAction();
875 }
876 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
877 {
878      event->acceptProposedAction();
879 }
880 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
881 {
882      event->acceptProposedAction();
883 }
884 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
885 {
886      event->accept();
887 }
888
889 /************************************************************************
890  * Events stuff
891  ************************************************************************/
892 void MainInterface::customEvent( QEvent *event )
893 {
894     if( event->type() == PLDockEvent_Type )
895     {
896         PlaylistDialog::killInstance();
897         playlistEmbeddedFlag = true;
898         menuBar()->clear();
899         QVLCMenu::createMenuBar(this, p_intf, true, isAdvancedVisible(),
900                                 visualSelectorEnabled);
901         togglePlaylist();
902     }
903     else if ( event->type() == SetVideoOnTopEvent_Type )
904     {
905         SetVideoOnTopQtEvent* p_event = (SetVideoOnTopQtEvent*)event;
906         if( p_event->OnTop() )
907             setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
908         else
909             setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
910         show(); /* necessary to apply window flags?? */
911     }
912 }
913
914 bool MainInterface::eventFilter(QObject *obj, QEvent *event)
915 {
916     if( (obj == timeLabel) && (event->type() == QEvent::MouseButtonPress) ) toggleTimeDisplay();
917 }
918
919
920 void MainInterface::keyPressEvent( QKeyEvent *e )
921 {
922     int i_vlck = qtEventToVLCKey( e );
923     if( i_vlck >= 0 )
924     {
925         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
926         e->accept();
927     }
928     else
929         e->ignore();
930 }
931
932 void MainInterface::wheelEvent( QWheelEvent *e )
933 {
934     int i_vlckey = qtWheelEventToVLCKey( e );
935     var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
936     e->accept();
937 }
938
939 void MainInterface::closeEvent( QCloseEvent *e )
940 {
941     hide();
942     vlc_object_kill( p_intf );
943 }
944
945 /*****************************************************************************
946  * Callbacks
947  *****************************************************************************/
948 static int InteractCallback( vlc_object_t *p_this,
949                              const char *psz_var, vlc_value_t old_val,
950                              vlc_value_t new_val, void *param )
951 {
952     intf_dialog_args_t *p_arg = new intf_dialog_args_t;
953     p_arg->p_dialog = (interaction_dialog_t *)(new_val.p_address);
954     DialogEvent *event = new DialogEvent( INTF_DIALOG_INTERACTION, 0, p_arg );
955     QApplication::postEvent( THEDP, static_cast<QEvent*>(event) );
956     return VLC_SUCCESS;
957 }
958
959 /*****************************************************************************
960  * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
961  *  We don't show the menu directly here because we don't want the
962  *  caller to block for a too long time.
963  *****************************************************************************/
964 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
965                         vlc_value_t old_val, vlc_value_t new_val, void *param )
966 {
967     intf_thread_t *p_intf = (intf_thread_t *)param;
968
969     if( p_intf->pf_show_dialog )
970     {
971         p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
972                                 new_val.b_bool, 0 );
973     }
974
975     return VLC_SUCCESS;
976 }
977
978 /*****************************************************************************
979  * IntfShowCB: callback triggered by the intf-show playlist variable.
980  *****************************************************************************/
981 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
982                        vlc_value_t old_val, vlc_value_t new_val, void *param )
983 {
984     intf_thread_t *p_intf = (intf_thread_t *)param;
985     //p_intf->p_sys->b_intf_show = VLC_TRUE;
986
987     return VLC_SUCCESS;
988 }