]> git.sesse.net Git - vlc/blob - modules/gui/qt4/main_interface.cpp
c3fa016e3447dca7b392347c412b5ecbc330b64c
[vlc] / modules / gui / qt4 / main_interface.cpp
1 /*****************************************************************************
2  * main_interface.cpp : Main interface
3  ****************************************************************************
4  * Copyright (C) 2006-2010 VideoLAN and AUTHORS
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 Foundation, Inc.,
23  * 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
32 #include "main_interface.hpp"
33 #include "input_manager.hpp"                    // Creation
34 #include "actions_manager.hpp"                  // killInstance
35 #include "extensions_manager.hpp"               // killInstance
36
37 #include "util/customwidgets.hpp"               // qtEventToVLCKey
38 #include "util/qt_dirs.hpp"                     // toNativeSeparators
39
40 #include "components/interface_widgets.hpp"     // bgWidget, videoWidget
41 #include "components/controller.hpp"            // controllers
42 #include "components/playlist/playlist.hpp"     // plWidget
43 #include "dialogs/firstrun.hpp"                 // First Run
44
45 #include "menus.hpp"                            // Menu creation
46 #include "recents.hpp"                          // RecentItems when DnD
47
48 #include <QCloseEvent>
49 #include <QKeyEvent>
50
51 #include <QUrl>
52 #include <QSize>
53 #include <QDate>
54
55 #include <QMenu>
56 #include <QMenuBar>
57 #include <QStatusBar>
58 #include <QLabel>
59 #include <QStackedWidget>
60
61 #include <vlc_keys.h>                       /* Wheel event */
62 #include <vlc_vout_display.h>               /* vout_thread_t and VOUT_ events */
63
64 // #define DEBUG_INTF
65
66 /* Callback prototypes */
67 static int PopupMenuCB( 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 IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
70                        vlc_value_t old_val, vlc_value_t new_val, void *param );
71
72 MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf )
73 {
74     /* Variables initialisation */
75     bgWidget             = NULL;
76     videoWidget          = NULL;
77     playlistWidget       = NULL;
78 #ifndef HAVE_MAEMO
79     sysTray              = NULL;
80 #endif
81     fullscreenControls   = NULL;
82     cryptedLabel         = NULL;
83     controls             = NULL;
84     inputC               = NULL;
85
86     b_hideAfterCreation  = false; // --qt-start-minimized
87     playlistVisible      = false;
88     input_name           = "";
89     i_bg_height          = 0;
90
91
92     /* Ask for Privacy */
93     FirstRun::CheckAndRun( this, p_intf );
94
95     /**
96      *  Configuration and settings
97      *  Pre-building of interface
98      **/
99     /* Main settings */
100     setFocusPolicy( Qt::StrongFocus );
101     setAcceptDrops( true );
102     setWindowRole( "vlc-main" );
103     setWindowIcon( QApplication::windowIcon() );
104     setWindowOpacity( var_InheritFloat( p_intf, "qt-opacity" ) );
105
106     /* Is video in embedded in the UI or not */
107     b_videoEmbedded = var_InheritBool( p_intf, "embedded-video" );
108
109     /* Does the interface resize to video size or the opposite */
110     b_keep_size = !var_InheritBool( p_intf, "qt-video-autoresize" );
111
112     /* Are we in the enhanced always-video mode or not ? */
113     i_visualmode = var_InheritInteger( p_intf, "qt-minimal-view" );
114
115     /* Do we want anoying popups or not */
116     b_notificationEnabled = var_InheritBool( p_intf, "qt-notification" );
117
118     /* Set the other interface settings */
119     settings = getSettings();
120     settings->beginGroup( "MainWindow" );
121
122     /* */
123     b_plDocked = getSettings()->value( "pl-dock-status", true ).toBool();
124
125
126     /**
127      * Retrieve saved sizes for main window
128      *   mainBasedSize = based window size for normal mode
129      *                  (no video, no background)
130      *   mainVideoSize = window size with video (all modes)
131      **/
132     mainBasedSize = settings->value( "mainBasedSize", QSize( 350, 120 ) ).toSize();
133     mainVideoSize = settings->value( "mainVideoSize", QSize( 400, 300 ) ).toSize();
134
135
136     /**************
137      * Status Bar *
138      **************/
139     createStatusBar();
140
141     /**************************
142      *  UI and Widgets design
143      **************************/
144     setVLCWindowsTitle();
145     createMainWidget( settings );
146
147     /************
148      * Menu Bar *
149      ************/
150     QVLCMenu::createMenuBar( this, p_intf );
151     CONNECT( THEMIM->getIM(), voutListChanged( vout_thread_t **, int ),
152              this, destroyPopupMenu() );
153
154     /*********************************
155      * Create the Systray Management *
156      *********************************/
157     initSystray();
158
159     /********************
160      * Input Manager    *
161      ********************/
162     MainInputManager::getInstance( p_intf );
163
164 #ifdef WIN32
165     himl = NULL;
166     p_taskbl = NULL;
167     taskbar_wmsg = RegisterWindowMessage("TaskbarButtonCreated");
168 #endif
169
170     /************************************************************
171      * Connect the input manager to the GUI elements it manages *
172      ************************************************************/
173     /**
174      * Connects on nameChanged()
175      * Those connects are different because options can impeach them to trigger.
176      **/
177     /* Main Interface statusbar */
178     CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
179              this, setName( const QString& ) );
180     /* and systray */
181 #ifndef HAVE_MAEMO
182     if( sysTray )
183     {
184         CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
185                  this, updateSystrayTooltipName( const QString& ) );
186     }
187 #endif
188     /* and title of the Main Interface*/
189     if( var_InheritBool( p_intf, "qt-name-in-title" ) )
190     {
191         CONNECT( THEMIM->getIM(), nameChanged( const QString& ),
192                  this, setVLCWindowsTitle( const QString& ) );
193     }
194
195     /**
196      * CONNECTS on PLAY_STATUS
197      **/
198     /* Status on the systray */
199 #ifndef HAVE_MAEMO
200     if( sysTray )
201     {
202         CONNECT( THEMIM->getIM(), statusChanged( int ),
203                  this, updateSystrayTooltipStatus( int ) );
204     }
205 #endif
206
207     /* END CONNECTS ON IM */
208
209     /* VideoWidget connects for asynchronous calls */
210     connect( this, SIGNAL(askGetVideo(WId*,int*,int*,unsigned*,unsigned *)),
211              this, SLOT(getVideoSlot(WId*,int*,int*,unsigned*,unsigned*)),
212              Qt::BlockingQueuedConnection );
213     connect( this, SIGNAL(askReleaseVideo( void )),
214              this, SLOT(releaseVideoSlot( void )),
215              Qt::BlockingQueuedConnection );
216
217     if( videoWidget )
218     {
219         CONNECT( this, askVideoToResize( unsigned int, unsigned int ),
220                  videoWidget, SetSizing( unsigned int, unsigned int ) );
221         CONNECT( videoWidget, sizeChanged( int, int ),
222                  this, resizeStack( int,  int ) );
223         CONNECT( this, askVideoSetFullScreen( bool ),
224                  videoWidget, SetFullScreen( bool ) );
225         CONNECT( videoWidget, keyPressed( QKeyEvent * ),
226                  this, handleKeyPress( QKeyEvent * ) );
227     }
228
229     CONNECT( this, askUpdate(), this, doComponentsUpdate() );
230     CONNECT( THEDP, toolBarConfUpdated(), this, recreateToolbars() );
231
232     /** END of CONNECTS**/
233
234
235     /************
236      * Callbacks
237      ************/
238     var_AddCallback( p_intf->p_libvlc, "intf-show", IntfShowCB, p_intf );
239
240     /* Register callback for the intf-popupmenu variable */
241     var_AddCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
242
243     /**** FINAL SIZING and placement of interface */
244     settings->beginGroup( "MainWindow" );
245     QVLCTools::restoreWidgetPosition( settings, this, QSize(400, 100) );
246
247     /* resize to previously saved main window size if appicable */
248     //FIXME remove.
249     if( b_keep_size )
250     {
251        if( i_visualmode )
252            resize( mainVideoSize );
253        else
254            resize( mainBasedSize );
255     }
256
257     /* Playlist */
258     int i_plVis = settings->value( "playlist-visible", 0 ).toInt();
259
260     settings->endGroup();
261
262     if( i_plVis ) togglePlaylist();
263
264     /* Final sizing and showing */
265     setVisible( !b_hideAfterCreation );
266
267     setMinimumWidth( __MAX( controls->sizeHint().width(),
268                             menuBar()->sizeHint().width() ) + 30 );
269
270     /* Switch to minimal view if needed, must be called after the show() */
271     if( i_visualmode )
272         toggleMinimalView( true );
273 }
274
275 MainInterface::~MainInterface()
276 {
277     /* Unsure we hide the videoWidget before destroying it */
278     if( stackCentralOldWidget == playlistWidget )
279         showBg();
280
281     /* Save playlist state */
282     if( playlistWidget )
283     {
284         if( !isPlDocked() )
285             QVLCTools::saveWidgetPosition( p_intf, "Playlist", playlistWidget );
286
287         delete playlistWidget;
288     }
289
290 #ifdef WIN32
291     if( himl )
292         ImageList_Destroy( himl );
293     if(p_taskbl)
294         p_taskbl->vt->Release(p_taskbl);
295     CoUninitialize();
296 #endif
297
298     /* Be sure to kill the actionsManager... Only used in the MI and control */
299     ActionsManager::killInstance();
300
301     /* Idem */
302     ExtensionsManager::killInstance();
303
304     /* Delete the FSC controller */
305     delete fullscreenControls;
306
307     /* Save states */
308     settings->beginGroup( "MainWindow" );
309     settings->setValue( "pl-dock-status", b_plDocked );
310     settings->setValue( "playlist-visible", (int)playlistVisible );
311     settings->setValue( "adv-controls",
312                         getControlsVisibilityStatus() & CONTROLS_ADVANCED );
313
314     settings->setValue( "mainBasedSize", mainBasedSize );
315     settings->setValue( "mainVideoSize", mainVideoSize );
316
317     settings->setValue( "backgroundSize", bgWidget->size() );
318
319     /* Save this size */
320     QVLCTools::saveWidgetPosition(settings, this);
321     settings->endGroup();
322
323     delete statusBar();
324
325     /* Unregister callbacks */
326     var_DelCallback( p_intf->p_libvlc, "intf-show", IntfShowCB, p_intf );
327     var_DelCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
328
329     p_intf->p_sys->p_mi = NULL;
330 }
331
332 /*****************************
333  *   Main UI handling        *
334  *****************************/
335 void MainInterface::recreateToolbars()
336 {
337     // FIXME: do the same for the FSC
338     settings->beginGroup( "MainWindow" );
339     delete controls;
340     delete inputC;
341
342     controls = new ControlsWidget( p_intf, false, this ); /* FIXME */
343     CONNECT( controls, advancedControlsToggled( bool ),
344              this, doComponentsUpdate() );
345     CONNECT( controls, sizeChanged(),
346              this, doComponentsUpdate() );
347
348     inputC = new InputControlsWidget( p_intf, this );
349
350     mainLayout->insertWidget( 2, inputC );
351     mainLayout->insertWidget( settings->value( "ToolbarPos", 0 ).toInt() ? 0: 3,
352                               controls );
353     settings->endGroup();
354 }
355
356 void MainInterface::createMainWidget( QSettings *settings )
357 {
358     /* Create the main Widget and the mainLayout */
359     QWidget *main = new QWidget;
360     setCentralWidget( main );
361     mainLayout = new QVBoxLayout( main );
362     main->setContentsMargins( 0, 0, 0, 0 );
363     mainLayout->setSpacing( 0 ); mainLayout->setMargin( 0 );
364
365     /* */
366     stackCentralW = new QStackedWidget( main );
367
368     /* Bg Cone */
369     bgWidget = new BackgroundWidget( p_intf );
370     stackCentralW->addWidget( bgWidget );
371
372     /* And video Outputs */
373     if( b_videoEmbedded )
374     {
375         videoWidget = new VideoWidget( p_intf );
376         stackCentralW->addWidget( videoWidget );
377     }
378     mainLayout->insertWidget( 1, stackCentralW );
379
380     /* Create the CONTROLS Widget */
381     controls = new ControlsWidget( p_intf,
382                    settings->value( "adv-controls", false ).toBool(), this );
383     CONNECT( controls, advancedControlsToggled( bool ),
384              this, doComponentsUpdate() );
385     CONNECT( controls, sizeChanged(),
386              this, doComponentsUpdate() );
387     inputC = new InputControlsWidget( p_intf, this );
388
389     mainLayout->insertWidget( 2, inputC );
390     mainLayout->insertWidget( settings->value( "ToolbarPos", 0 ).toInt() ? 0: 3,
391                               controls );
392
393     /* Visualisation, disabled for now, they SUCK */
394     #if 0
395     visualSelector = new VisualSelector( p_intf );
396     mainLayout->insertWidget( 0, visualSelector );
397     visualSelector->hide();
398     #endif
399
400     getSettings()->endGroup();
401
402     /* Enable the popup menu in the MI */
403     main->setContextMenuPolicy( Qt::CustomContextMenu );
404     CONNECT( main, customContextMenuRequested( const QPoint& ),
405              this, popupMenu( const QPoint& ) );
406
407     if ( depth() > 8 ) /* 8bit depth has too many issues with opacity */
408         /* Create the FULLSCREEN CONTROLS Widget */
409         if( var_InheritBool( p_intf, "qt-fs-controller" ) )
410         {
411             fullscreenControls = new FullscreenControllerWidget( p_intf, this );
412             CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
413                      this, handleKeyPress( QKeyEvent * ) );
414         }
415 }
416
417 inline void MainInterface::initSystray()
418 {
419 #ifndef HAVE_MAEMO
420     bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
421     bool b_systrayWanted = var_InheritBool( p_intf, "qt-system-tray" );
422
423     if( var_InheritBool( p_intf, "qt-start-minimized") )
424     {
425         if( b_systrayAvailable )
426         {
427             b_systrayWanted = true;
428             b_hideAfterCreation = true;
429         }
430         else
431             msg_Err( p_intf, "cannot start minimized without system tray bar" );
432     }
433
434     if( b_systrayAvailable && b_systrayWanted )
435         createSystray();
436 #endif
437 }
438
439 inline void MainInterface::createStatusBar()
440 {
441     /****************
442      *  Status Bar  *
443      ****************/
444     /* Widgets Creation*/
445     QStatusBar *statusBarr = statusBar();
446
447     TimeLabel *timeLabel = new TimeLabel( p_intf );
448     nameLabel = new QLabel( this );
449     nameLabel->setTextInteractionFlags( Qt::TextSelectableByMouse
450                                       | Qt::TextSelectableByKeyboard );
451     SpeedLabel *speedLabel = new SpeedLabel( p_intf, this );
452
453     /* Styling those labels */
454     timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
455     speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
456     nameLabel->setFrameStyle( QFrame::Sunken | QFrame::StyledPanel);
457
458     /* and adding those */
459     statusBarr->addWidget( nameLabel, 8 );
460     statusBarr->addPermanentWidget( speedLabel, 0 );
461     statusBarr->addPermanentWidget( timeLabel, 0 );
462
463     /* timeLabel behaviour:
464        - double clicking opens the goto time dialog
465        - right-clicking and clicking just toggle between remaining and
466          elapsed time.*/
467     CONNECT( timeLabel, timeLabelDoubleClicked(), THEDP, gotoTimeDialog() );
468
469     CONNECT( THEMIM->getIM(), encryptionChanged( bool ),
470              this, showCryptedLabel( bool ) );
471
472     CONNECT( THEMIM->getIM(), seekRequested( float ),
473              timeLabel, setDisplayPosition( float ) );
474 }
475
476 /**********************************************************************
477  * Handling of sizing of the components
478  **********************************************************************/
479
480 /* This function is called:
481    - toggling of minimal View
482    - through askUpdate() by Vout thread request video and resize video (zoom)
483    - Advanced buttons toggled
484  */
485 void MainInterface::doComponentsUpdate()
486 {
487 #if 0
488     if( isFullScreen() || isMaximized() ) return;
489
490 //    msg_Warn( p_intf, "Updating the geometry" );
491     /* Here we resize to sizeHint() and not adjustsize because we want
492        the videoWidget to be exactly the correctSize */
493
494 #ifdef DEBUG_INTF
495     debug();
496 #endif
497     /* This is WRONG, but I believe there is a Qt bug here */
498     setMinimumSize( 0, 0 );
499     //resize( sizeHint() );
500
501     //adjustSize() ; /* This is not needed, but might help in the future */
502 #endif
503 }
504
505 void MainInterface::debug()
506 {
507 #ifdef DEBUG_INTF
508     msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
509     msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
510     msg_Dbg( p_intf, "minimumsize: %i - %i", minimumSize().height(), minimumSize().width() );
511
512     msg_Dbg( p_intf, "Stack size: %i - %i", stackCentralW->size().height(), stackCentralW->size().width() );
513     msg_Dbg( p_intf, "Stack sizeHint: %i - %i", stackCentralW->sizeHint().height(), stackCentralW->sizeHint().width() );
514     msg_Dbg( p_intf, "Central size: %i - %i", centralWidget()->size().height(), centralWidget()->size().width() );
515 #endif
516 }
517
518 inline void MainInterface::showVideo() { showTab( videoWidget ); }
519 inline void MainInterface::showBg() { showTab( bgWidget ); }
520
521 inline void MainInterface::showTab( QWidget *widget )
522 {
523 #ifdef DEBUG_INTF
524     msg_Warn( p_intf, "Old stackCentralOldWidget %i", stackCentralW->indexOf( stackCentralOldWidget ) );
525 #endif
526     stackCentralOldWidget = stackCentralW->currentWidget();
527     stackCentralW->setCurrentWidget( widget );
528
529 #ifdef DEBUG_INTF
530     msg_Warn( p_intf, "State change %i",  stackCentralW->currentIndex() );
531     msg_Warn( p_intf, "New stackCentralOldWidget %i", stackCentralW->indexOf( stackCentralOldWidget ) );
532 #endif
533 }
534
535 inline void MainInterface::restoreStackOldWidget()
536 {
537 #ifdef DEBUG_INTF
538     msg_Warn( p_intf, "New stackCentralOldWidget %i", stackCentralW->indexOf( stackCentralOldWidget ) );
539 #endif
540     QWidget *wTemp = stackCentralW->currentWidget();
541
542     stackCentralW->setCurrentWidget( stackCentralOldWidget );
543
544     stackCentralOldWidget = wTemp;
545 #ifdef DEBUG_INTF
546     msg_Warn( p_intf, "Debug %i %i",stackCentralW->indexOf( wTemp ), stackCentralW->indexOf( stackCentralW->currentWidget() ) );
547 #endif
548 }
549
550 void MainInterface::destroyPopupMenu()
551 {
552     QVLCMenu::PopupMenu( p_intf, false );
553 }
554
555 void MainInterface::popupMenu( const QPoint &p )
556 {
557     QVLCMenu::PopupMenu( p_intf, true );
558 }
559
560 void MainInterface::toggleFSC()
561 {
562    if( !fullscreenControls ) return;
563
564    IMEvent *eShow = new IMEvent( FullscreenControlToggle_Type, 0 );
565    QApplication::postEvent( fullscreenControls, eShow );
566 }
567
568 /****************************************************************************
569  * Video Handling
570  ****************************************************************************/
571
572 /* This event is used to deal with the fullscreen and always on top
573    issue conflict (bug in wx) */
574 class SetVideoOnTopQtEvent : public QEvent
575 {
576 public:
577     SetVideoOnTopQtEvent( bool _onTop ) :
578       QEvent( (QEvent::Type)SetVideoOnTopEvent_Type ), onTop( _onTop)
579     {}
580
581     bool OnTop() const { return onTop; }
582
583 private:
584     bool onTop;
585 };
586
587 /**
588  * NOTE:
589  * You must not change the state of this object or other Qt4 UI objects,
590  * from the video output thread - only from the Qt4 UI main loop thread.
591  * All window provider queries must be handled through signals or events.
592  * That's why we have all those emit statements...
593  */
594 WId MainInterface::getVideo( int *pi_x, int *pi_y,
595                              unsigned int *pi_width, unsigned int *pi_height )
596 {
597     if( !videoWidget )
598         return 0;
599
600     /* This is a blocking call signal. Results are returned through pointers.
601      * Beware of deadlocks! */
602     WId id;
603     emit askGetVideo( &id, pi_x, pi_y, pi_width, pi_height );
604     return id;
605 }
606
607 void MainInterface::getVideoSlot( WId *p_id, int *pi_x, int *pi_y,
608                                   unsigned *pi_width, unsigned *pi_height )
609 {
610     /* Request the videoWidget */
611     WId ret = videoWidget->request( pi_x, pi_y,
612                                     pi_width, pi_height, b_keep_size );
613     *p_id = ret;
614     if( ret ) /* The videoWidget is available */
615     {
616         /* ask videoWidget to show */
617         videoWidget->SetSizing( *pi_width, *pi_height );
618
619         /* Consider the video active now */
620         showVideo();
621     }
622 }
623
624
625
626 /* Asynchronous call from the WindowClose function */
627 void MainInterface::releaseVideo( void )
628 {
629     emit askReleaseVideo( );
630 }
631
632 /* Function that is CONNECTED to the previous emit */
633 void MainInterface::releaseVideoSlot( void )
634 {
635     videoWidget->release( );
636
637     restoreStackOldWidget();
638
639     /* We don't want to have a blank video to popup */
640     stackCentralOldWidget = bgWidget;
641
642     /* Try to resize, except when you are in Fullscreen mode */
643 //    doComponentsUpdate();
644 }
645
646 /* Asynchronous call from WindowControl function */
647 int MainInterface::controlVideo( int i_query, va_list args )
648 {
649     switch( i_query )
650     {
651     case VOUT_WINDOW_SET_SIZE:
652     {
653         unsigned int i_width  = va_arg( args, unsigned int );
654         unsigned int i_height = va_arg( args, unsigned int );
655         emit askVideoToResize( i_width, i_height );
656         return VLC_SUCCESS;
657     }
658     case VOUT_WINDOW_SET_STATE:
659     {
660         unsigned i_arg = va_arg( args, unsigned );
661         unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
662         QApplication::postEvent( this, new SetVideoOnTopQtEvent( on_top ) );
663         return VLC_SUCCESS;
664     }
665     case VOUT_WINDOW_SET_FULLSCREEN:
666     {
667         bool b_fs = va_arg( args, int );
668         emit askVideoSetFullScreen( b_fs );
669         return VLC_SUCCESS;
670     }
671     default:
672         msg_Warn( p_intf, "unsupported control query" );
673         return VLC_EGENERIC;
674     }
675 }
676
677 /*****************************************************************************
678  * Playlist, Visualisation and Menus handling
679  *****************************************************************************/
680 /**
681  * Toggle the playlist widget or dialog
682  **/
683 void MainInterface::createPlaylist()
684 {
685     playlistWidget = new PlaylistWidget( p_intf, this );
686
687     if( !b_plDocked )
688     {
689         playlistWidget->setWindowFlags( Qt::Window );
690
691         /* This will restore the geometry but will not work for position,
692            because of parenting */
693         QVLCTools::restoreWidgetPosition( p_intf, "Playlist",
694                 playlistWidget, QSize( 600, 300 ) );
695     }
696     else
697     {
698         stackCentralW->addWidget( playlistWidget );
699     }
700 }
701
702 void MainInterface::togglePlaylist()
703 {
704     if( !playlistWidget )
705         createPlaylist();
706
707     if( b_plDocked )
708     {
709         /* Playlist is not visible, show it */
710         if( stackCentralW->currentWidget() != playlistWidget )
711         {
712             playlistWidget->forceShow();
713             showTab( playlistWidget );
714         }
715         else /* Hide it! */
716         {
717             restoreStackOldWidget();
718             stackCentralW->updateGeometry();
719             // HACK: So it doesn't limit the stackWidget minimumSize
720             playlistWidget->forceHide();
721         }
722         playlistVisible = ( stackCentralW->currentWidget() == playlistWidget );
723     }
724     else
725     {
726         playlistWidget->setWindowFlags( Qt::Window );
727         playlistVisible = !playlistVisible;
728         playlistWidget->setVisible( playlistVisible );
729     }
730     debug();
731 }
732
733 void MainInterface::dockPlaylist( bool p_docked )
734 {
735     if( b_plDocked == p_docked ) return;
736     b_plDocked = p_docked;
737
738     if( !playlistWidget ) return; /* Playlist wasn't created yet */
739     if( !p_docked )
740     {
741         stackCentralW->removeWidget( playlistWidget );
742         playlistWidget->setWindowFlags( Qt::Window );
743         QVLCTools::restoreWidgetPosition( p_intf, "Playlist",
744                 playlistWidget, QSize( 600, 300 ) );
745         playlistWidget->show();
746         restoreStackOldWidget();
747     }
748     else
749     {
750         playlistWidget->setWindowFlags( Qt::Widget ); // Probably a Qt bug here
751         // It would be logical that QStackWidget::addWidget reset the flags...
752         stackCentralW->addWidget( playlistWidget );
753         stackCentralW->setCurrentWidget( playlistWidget );
754     }
755 }
756
757 /*
758   If b_switch is false, then we are normalView
759  */
760 void MainInterface::toggleMinimalView( bool b_switch )
761 {
762     if( i_visualmode == 0 )
763     { /* NORMAL MODE then */
764         if( !videoWidget || stackCentralW->currentWidget() != videoWidget )
765         {
766             showBg();
767         }
768         else
769         {
770             /* If video is visible, then toggle the status of bgWidget */
771             //FIXME
772             //bgWasVisible = !bgWasVisible;
773             /* if( stackCentralOldState == BACK G_TAB )
774                 stackCentralOldState = HID DEN_TAB;
775             else
776                 stackCentralOldState = BACK G_TAB;
777
778                 */
779         }
780     }
781
782     i_bg_height = stackCentralW->height();
783
784     menuBar()->setVisible( !b_switch );
785     controls->setVisible( !b_switch );
786     statusBar()->setVisible( !b_switch );
787     inputC->setVisible( !b_switch );
788
789     doComponentsUpdate();
790
791     emit minimalViewToggled( b_switch );
792 }
793
794 /* toggling advanced controls buttons */
795 void MainInterface::toggleAdvanced()
796 {
797     controls->toggleAdvanced();
798 //    if( fullscreenControls ) fullscreenControls->toggleAdvanced();
799 }
800
801 /* Get the visibility status of the controls (hidden or not, advanced or not) */
802 int MainInterface::getControlsVisibilityStatus()
803 {
804     return( (controls->isVisible() ? CONTROLS_VISIBLE : CONTROLS_HIDDEN )
805                 + CONTROLS_ADVANCED * controls->b_advancedVisible );
806 }
807
808 #if 0
809 void MainInterface::visual()
810 {
811     if( !VISIBLE( visualSelector) )
812     {
813         visualSelector->show();
814         if( !THEMIM->getIM()->hasVideo() )
815         {
816             /* Show the background widget */
817         }
818         visualSelectorEnabled = true;
819     }
820     else
821     {
822         /* Stop any currently running visualization */
823         visualSelector->hide();
824         visualSelectorEnabled = false;
825     }
826     doComponentsUpdate();
827 }
828 #endif
829
830 /************************************************************************
831  * Other stuff
832  ************************************************************************/
833 void MainInterface::setName( const QString& name )
834 {
835     input_name = name; /* store it for the QSystray use */
836     /* Display it in the status bar, but also as a Tooltip in case it doesn't
837        fit in the label */
838     nameLabel->setText( " " + name + " " );
839     nameLabel->setToolTip( " " + name +" " );
840 }
841
842 /**
843  * Give the decorations of the Main Window a correct Name.
844  * If nothing is given, set it to VLC...
845  **/
846 void MainInterface::setVLCWindowsTitle( const QString& aTitle )
847 {
848     if( aTitle.isEmpty() )
849     {
850         setWindowTitle( qtr( "VLC media player" ) );
851     }
852     else
853     {
854         setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
855     }
856 }
857
858 void MainInterface::showCryptedLabel( bool b_show )
859 {
860     if( cryptedLabel == NULL )
861     {
862         cryptedLabel = new QLabel;
863         // The lock icon is not the right one for DRM protection/scrambled.
864         //cryptedLabel->setPixmap( QPixmap( ":/lock" ) );
865         cryptedLabel->setText( "DRM" );
866         statusBar()->addWidget( cryptedLabel );
867     }
868
869     cryptedLabel->setVisible( b_show );
870 }
871
872 void MainInterface::showBuffering( float f_cache )
873 {
874     QString amount = QString("Buffering: %1%").arg( (int)(100*f_cache) );
875     statusBar()->showMessage( amount, 1000 );
876 }
877
878 /*****************************************************************************
879  * Systray Icon and Systray Menu
880  *****************************************************************************/
881 #ifndef HAVE_MAEMO
882 /**
883  * Create a SystemTray icon and a menu that would go with it.
884  * Connects to a click handler on the icon.
885  **/
886 void MainInterface::createSystray()
887 {
888     QIcon iconVLC;
889     if( QDate::currentDate().dayOfYear() >= 354 )
890         iconVLC =  QIcon( ":/logo/vlc128-christmas.png" );
891     else
892         iconVLC =  QIcon( ":/logo/vlc128.png" );
893     sysTray = new QSystemTrayIcon( iconVLC, this );
894     sysTray->setToolTip( qtr( "VLC media player" ));
895
896     systrayMenu = new QMenu( qtr( "VLC media player" ), this );
897     systrayMenu->setIcon( iconVLC );
898
899     QVLCMenu::updateSystrayMenu( this, p_intf, true );
900     sysTray->show();
901
902     CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
903             this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
904 }
905
906 /**
907  * Updates the Systray Icon's menu and toggle the main interface
908  */
909 void MainInterface::toggleUpdateSystrayMenu()
910 {
911     /* If hidden, show it */
912     if( isHidden() )
913     {
914         show();
915         activateWindow();
916     }
917     else if( isMinimized() )
918     {
919         /* Minimized */
920         showNormal();
921         activateWindow();
922     }
923     else
924     {
925         /* Visible (possibly under other windows) */
926 #ifdef WIN32
927         /* check if any visible window is above vlc in the z-order,
928          * but ignore the ones always on top
929          * and the ones which can't be activated */
930         WINDOWINFO wi;
931         HWND hwnd;
932         wi.cbSize = sizeof( WINDOWINFO );
933         for( hwnd = GetNextWindow( internalWinId(), GW_HWNDPREV );
934                 hwnd && ( !IsWindowVisible( hwnd ) ||
935                     ( GetWindowInfo( hwnd, &wi ) &&
936                       (wi.dwExStyle&WS_EX_NOACTIVATE) ) );
937                 hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) );
938             if( !hwnd || !GetWindowInfo( hwnd, &wi ) ||
939                 (wi.dwExStyle&WS_EX_TOPMOST) )
940             {
941                 hide();
942             }
943             else
944             {
945                 activateWindow();
946             }
947 #else
948         hide();
949 #endif
950     }
951     QVLCMenu::updateSystrayMenu( this, p_intf );
952 }
953
954 void MainInterface::handleSystrayClick(
955                                     QSystemTrayIcon::ActivationReason reason )
956 {
957     switch( reason )
958     {
959         case QSystemTrayIcon::Trigger:
960         case QSystemTrayIcon::DoubleClick:
961             toggleUpdateSystrayMenu();
962             break;
963         case QSystemTrayIcon::MiddleClick:
964             sysTray->showMessage( qtr( "VLC media player" ),
965                     qtr( "Control menu for the player" ),
966                     QSystemTrayIcon::Information, 3000 );
967             break;
968         default:
969             break;
970     }
971 }
972
973 /**
974  * Updates the name of the systray Icon tooltip.
975  * Doesn't check if the systray exists, check before you call it.
976  **/
977 void MainInterface::updateSystrayTooltipName( const QString& name )
978 {
979     if( name.isEmpty() )
980     {
981         sysTray->setToolTip( qtr( "VLC media player" ) );
982     }
983     else
984     {
985         sysTray->setToolTip( name );
986         if( b_notificationEnabled && ( isHidden() || isMinimized() ) )
987         {
988             sysTray->showMessage( qtr( "VLC media player" ), name,
989                     QSystemTrayIcon::NoIcon, 3000 );
990         }
991     }
992
993     QVLCMenu::updateSystrayMenu( this, p_intf );
994 }
995
996 /**
997  * Updates the status of the systray Icon tooltip.
998  * Doesn't check if the systray exists, check before you call it.
999  **/
1000 void MainInterface::updateSystrayTooltipStatus( int i_status )
1001 {
1002     switch( i_status )
1003     {
1004         case  0:
1005         case  END_S:
1006             {
1007                 sysTray->setToolTip( qtr( "VLC media player" ) );
1008                 break;
1009             }
1010         case PLAYING_S:
1011             {
1012                 sysTray->setToolTip( input_name );
1013                 break;
1014             }
1015         case PAUSE_S:
1016             {
1017                 sysTray->setToolTip( input_name + " - "
1018                         + qtr( "Paused") );
1019                 break;
1020             }
1021     }
1022     QVLCMenu::updateSystrayMenu( this, p_intf );
1023 }
1024 #endif
1025
1026 /************************************************************************
1027  * D&D Events
1028  ************************************************************************/
1029 void MainInterface::dropEvent(QDropEvent *event)
1030 {
1031     dropEventPlay( event, true );
1032 }
1033
1034 void MainInterface::dropEventPlay( QDropEvent *event, bool b_play )
1035 {
1036     event->setDropAction( Qt::CopyAction );
1037     if( !event->possibleActions() & Qt::CopyAction )
1038         return;
1039
1040     const QMimeData *mimeData = event->mimeData();
1041
1042     /* D&D of a subtitles file, add it on the fly */
1043     if( mimeData->urls().size() == 1 && THEMIM->getIM()->hasInput() )
1044     {
1045         if( !input_AddSubtitle( THEMIM->getInput(),
1046                  qtu( toNativeSeparators( mimeData->urls()[0].toLocalFile() ) ),
1047                  true ) )
1048         {
1049             event->accept();
1050             return;
1051         }
1052     }
1053
1054     bool first = b_play;
1055     foreach( const QUrl &url, mimeData->urls() )
1056     {
1057         QString s = toNativeSeparators( url.toLocalFile() );
1058
1059         if( s.length() > 0 ) {
1060             char* psz_uri = make_URI( qtu(s) );
1061             playlist_Add( THEPL, psz_uri, NULL,
1062                           PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1063                           PLAYLIST_END, true, pl_Unlocked );
1064             free( psz_uri );
1065             first = false;
1066             RecentsMRL::getInstance( p_intf )->addRecent( s );
1067         }
1068     }
1069     event->accept();
1070 }
1071 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1072 {
1073      event->acceptProposedAction();
1074 }
1075 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1076 {
1077      event->acceptProposedAction();
1078 }
1079 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1080 {
1081      event->accept();
1082 }
1083
1084 /************************************************************************
1085  * Events stuff
1086  ************************************************************************/
1087 void MainInterface::customEvent( QEvent *event )
1088 {
1089 #if 0
1090     if( event->type() == PLDockEvent_Type )
1091     {
1092         PlaylistDialog::killInstance();
1093         playlistEmbeddedFlag = true;
1094         menuBar()->clear();
1095         QVLCMenu::createMenuBar(this, p_intf, true, visualSelectorEnabled);
1096         togglePlaylist();
1097     }
1098 #endif
1099     /*else */
1100     if ( event->type() == (int)SetVideoOnTopEvent_Type )
1101     {
1102         SetVideoOnTopQtEvent* p_event = (SetVideoOnTopQtEvent*)event;
1103         if( p_event->OnTop() )
1104             setWindowFlags( windowFlags() | Qt::WindowStaysOnTopHint );
1105         else
1106             setWindowFlags( windowFlags() & ~Qt::WindowStaysOnTopHint );
1107         show(); /* necessary to apply window flags */
1108     }
1109 }
1110
1111 void MainInterface::keyPressEvent( QKeyEvent *e )
1112 {
1113     handleKeyPress( e );
1114 }
1115
1116 void MainInterface::handleKeyPress( QKeyEvent *e )
1117 {
1118     if( ( e->modifiers() &  Qt::ControlModifier ) && ( e->key() == Qt::Key_H )
1119           && !menuBar()->isVisible() )
1120     {
1121         toggleMinimalView( false );
1122         e->accept();
1123     }
1124
1125     int i_vlck = qtEventToVLCKey( e );
1126     if( i_vlck > 0 )
1127     {
1128         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1129         e->accept();
1130     }
1131     else
1132         e->ignore();
1133 }
1134
1135 void MainInterface::resizeEvent( QResizeEvent * event )
1136 {
1137 #if 0
1138     if( b_keep_size )
1139     {
1140         if( i_visualmode )
1141         {
1142                 mainVideoSize = size();
1143         }
1144         else
1145         {
1146             if( VISIBLE( bgWidget) ||
1147                 ( videoIsActive && videoWidget->isVisible() )
1148               )
1149                 mainVideoSize = size();
1150             else
1151                 mainBasedSize = size();
1152         }
1153     }
1154 #endif
1155     QVLCMW::resizeEvent( event );
1156     msg_Dbg( p_intf, "Resize Event, height: %i", size().height() );
1157     debug();
1158 }
1159
1160 void MainInterface::wheelEvent( QWheelEvent *e )
1161 {
1162     int i_vlckey = qtWheelEventToVLCKey( e );
1163     var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
1164     e->accept();
1165 }
1166
1167 void MainInterface::closeEvent( QCloseEvent *e )
1168 {
1169     e->accept();
1170     hide();
1171     THEDP->quit();
1172 }
1173
1174 void MainInterface::toggleFullScreen()
1175 {
1176     if( isFullScreen() )
1177     {
1178         showNormal();
1179         emit fullscreenInterfaceToggled( false );
1180     }
1181     else
1182     {
1183         showFullScreen();
1184         emit fullscreenInterfaceToggled( true );
1185     }
1186 }
1187
1188 /*****************************************************************************
1189  * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1190  *  We don't show the menu directly here because we don't want the
1191  *  caller to block for a too long time.
1192  *****************************************************************************/
1193 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
1194                         vlc_value_t old_val, vlc_value_t new_val, void *param )
1195 {
1196     intf_thread_t *p_intf = (intf_thread_t *)param;
1197
1198     if( p_intf->pf_show_dialog )
1199     {
1200         p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1201                                 new_val.b_bool, NULL );
1202     }
1203
1204     return VLC_SUCCESS;
1205 }
1206
1207 /*****************************************************************************
1208  * IntfShowCB: callback triggered by the intf-show libvlc variable.
1209  *****************************************************************************/
1210 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
1211                        vlc_value_t old_val, vlc_value_t new_val, void *param )
1212 {
1213     intf_thread_t *p_intf = (intf_thread_t *)param;
1214     p_intf->p_sys->p_mi->toggleFSC();
1215
1216     /* Show event */
1217      return VLC_SUCCESS;
1218 }