]> git.sesse.net Git - vlc/blob - modules/gui/qt4/main_interface.cpp
Fix dangerous use of qtu() on anonymous QString
[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, QVLCStackedWidget
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     stackCentralOldWidget= NULL;
79 #ifndef HAVE_MAEMO
80     sysTray              = NULL;
81 #endif
82     fullscreenControls   = NULL;
83     cryptedLabel         = NULL;
84     controls             = NULL;
85     inputC               = NULL;
86
87     b_hideAfterCreation  = false; // --qt-start-minimized
88     playlistVisible      = false;
89     input_name           = "";
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     settings->endGroup( );
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( THEDP, toolBarConfUpdated(), this, recreateToolbars() );
230
231     /** END of CONNECTS**/
232
233
234     /************
235      * Callbacks
236      ************/
237     var_AddCallback( p_intf->p_libvlc, "intf-show", IntfShowCB, p_intf );
238
239     /* Register callback for the intf-popupmenu variable */
240     var_AddCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
241
242     /**** FINAL SIZING and placement of interface */
243     settings->beginGroup( "MainWindow" );
244     QVLCTools::restoreWidgetPosition( settings, this, QSize(400, 100) );
245
246     /* resize to previously saved main window size if appicable */
247     //FIXME remove.
248     if( b_keep_size )
249     {
250        if( i_visualmode )
251            resize( mainVideoSize );
252        else
253            resize( mainBasedSize );
254     }
255
256     /* Playlist */
257     int i_plVis = settings->value( "playlist-visible", false ).toBool();
258     settings->endGroup();
259
260     if( i_plVis ) togglePlaylist();
261
262     /* Final sizing and showing */
263     setVisible( !b_hideAfterCreation );
264
265     setMinimumWidth( __MAX( controls->sizeHint().width(),
266                             menuBar()->sizeHint().width() ) + 30 );
267
268     /* Switch to minimal view if needed, must be called after the show() */
269     if( i_visualmode )
270         toggleMinimalView( true );
271 }
272
273 MainInterface::~MainInterface()
274 {
275     /* Unsure we hide the videoWidget before destroying it */
276     if( stackCentralOldWidget == videoWidget )
277         showBg();
278
279 #ifdef WIN32
280     if( himl )
281         ImageList_Destroy( himl );
282     if(p_taskbl)
283         p_taskbl->vt->Release(p_taskbl);
284     CoUninitialize();
285 #endif
286
287     /* Be sure to kill the actionsManager... Only used in the MI and control */
288     ActionsManager::killInstance();
289
290     /* Idem */
291     ExtensionsManager::killInstance();
292
293     /* Delete the FSC controller */
294     delete fullscreenControls;
295
296     /* Save states */
297     settings->beginGroup( "MainWindow" );
298
299     settings->setValue( "pl-dock-status", b_plDocked );
300     /* Save playlist state */
301     if( playlistWidget )
302     {
303         settings->setValue( "playlist-visible",
304                             isPlDocked() ?
305                             playlistVisible :
306                             playlistWidget->isVisible() /* FIXME */ );
307     }
308
309     settings->setValue( "adv-controls",
310                         getControlsVisibilityStatus() & CONTROLS_ADVANCED );
311
312     settings->setValue( "mainBasedSize", mainBasedSize );
313     settings->setValue( "mainVideoSize", mainVideoSize );
314
315     settings->setValue( "backgroundSize", bgWidget->size() );
316
317     /* Save this size */
318     QVLCTools::saveWidgetPosition(settings, this);
319
320     settings->endGroup();
321
322     /* Save undocked playlist size */
323     if( playlistWidget && !isPlDocked() )
324         QVLCTools::saveWidgetPosition( p_intf, "Playlist", playlistWidget );
325
326     delete playlistWidget;
327
328     delete statusBar();
329
330     /* Unregister callbacks */
331     var_DelCallback( p_intf->p_libvlc, "intf-show", IntfShowCB, p_intf );
332     var_DelCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
333
334     p_intf->p_sys->p_mi = NULL;
335 }
336
337 /*****************************
338  *   Main UI handling        *
339  *****************************/
340 void MainInterface::recreateToolbars()
341 {
342     bool b_adv = getControlsVisibilityStatus() & CONTROLS_ADVANCED;
343
344     settings->beginGroup( "MainWindow" );
345     delete controls;
346     delete inputC;
347
348     controls = new ControlsWidget( p_intf, b_adv, this );
349     inputC = new InputControlsWidget( p_intf, this );
350
351     if( fullscreenControls )
352     {
353         delete fullscreenControls;
354         fullscreenControls = new FullscreenControllerWidget( p_intf, this );
355         CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
356                  this, handleKeyPress( QKeyEvent * ) );
357     }
358     mainLayout->insertWidget( 2, inputC );
359     mainLayout->insertWidget( settings->value( "ToolbarPos", 0 ).toInt() ? 0: 3,
360                               controls );
361     settings->endGroup();
362 }
363
364 void MainInterface::createMainWidget( QSettings *settings )
365 {
366     /* Create the main Widget and the mainLayout */
367     QWidget *main = new QWidget;
368     setCentralWidget( main );
369     mainLayout = new QVBoxLayout( main );
370     main->setContentsMargins( 0, 0, 0, 0 );
371     mainLayout->setSpacing( 0 ); mainLayout->setMargin( 0 );
372
373     /* */
374     stackCentralW = new QVLCStackedWidget( main );
375
376     /* Bg Cone */
377     bgWidget = new BackgroundWidget( p_intf );
378     stackCentralW->addWidget( bgWidget );
379
380     /* And video Outputs */
381     if( b_videoEmbedded )
382     {
383         videoWidget = new VideoWidget( p_intf );
384         stackCentralW->addWidget( videoWidget );
385     }
386     mainLayout->insertWidget( 1, stackCentralW );
387
388     settings->beginGroup( "MainWindow" );
389
390     /* Create the CONTROLS Widget */
391     controls = new ControlsWidget( p_intf,
392                    settings->value( "adv-controls", false ).toBool(), this );
393     inputC = new InputControlsWidget( p_intf, this );
394
395     mainLayout->insertWidget( 2, inputC );
396     mainLayout->insertWidget( settings->value( "ToolbarPos", 0 ).toInt() ? 0: 3,
397                               controls );
398
399     /* Visualisation, disabled for now, they SUCK */
400     #if 0
401     visualSelector = new VisualSelector( p_intf );
402     mainLayout->insertWidget( 0, visualSelector );
403     visualSelector->hide();
404     #endif
405
406     settings->endGroup();
407
408     /* Enable the popup menu in the MI */
409     main->setContextMenuPolicy( Qt::CustomContextMenu );
410     CONNECT( main, customContextMenuRequested( const QPoint& ),
411              this, popupMenu( const QPoint& ) );
412
413     if ( depth() > 8 ) /* 8bit depth has too many issues with opacity */
414         /* Create the FULLSCREEN CONTROLS Widget */
415         if( var_InheritBool( p_intf, "qt-fs-controller" ) )
416         {
417             fullscreenControls = new FullscreenControllerWidget( p_intf, this );
418             CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
419                      this, handleKeyPress( QKeyEvent * ) );
420         }
421 }
422
423 inline void MainInterface::initSystray()
424 {
425 #ifndef HAVE_MAEMO
426     bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
427     bool b_systrayWanted = var_InheritBool( p_intf, "qt-system-tray" );
428
429     if( var_InheritBool( p_intf, "qt-start-minimized") )
430     {
431         if( b_systrayAvailable )
432         {
433             b_systrayWanted = true;
434             b_hideAfterCreation = true;
435         }
436         else
437             msg_Err( p_intf, "cannot start minimized without system tray bar" );
438     }
439
440     if( b_systrayAvailable && b_systrayWanted )
441         createSystray();
442 #endif
443 }
444
445 inline void MainInterface::createStatusBar()
446 {
447     /****************
448      *  Status Bar  *
449      ****************/
450     /* Widgets Creation*/
451     QStatusBar *statusBarr = statusBar();
452
453     TimeLabel *timeLabel = new TimeLabel( p_intf );
454     nameLabel = new QLabel( this );
455     nameLabel->setTextInteractionFlags( Qt::TextSelectableByMouse
456                                       | Qt::TextSelectableByKeyboard );
457     SpeedLabel *speedLabel = new SpeedLabel( p_intf, this );
458
459     /* Styling those labels */
460     timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
461     speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
462     nameLabel->setFrameStyle( QFrame::Sunken | QFrame::StyledPanel);
463     timeLabel->setStyleSheet(
464             "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
465     speedLabel->setStyleSheet(
466             "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
467
468     /* and adding those */
469     statusBarr->addWidget( nameLabel, 8 );
470     statusBarr->addPermanentWidget( speedLabel, 0 );
471     statusBarr->addPermanentWidget( timeLabel, 0 );
472
473     /* timeLabel behaviour:
474        - double clicking opens the goto time dialog
475        - right-clicking and clicking just toggle between remaining and
476          elapsed time.*/
477     CONNECT( timeLabel, timeLabelDoubleClicked(), THEDP, gotoTimeDialog() );
478
479     CONNECT( THEMIM->getIM(), encryptionChanged( bool ),
480              this, showCryptedLabel( bool ) );
481
482     CONNECT( THEMIM->getIM(), seekRequested( float ),
483              timeLabel, setDisplayPosition( float ) );
484 }
485
486 /**********************************************************************
487  * Handling of sizing of the components
488  **********************************************************************/
489
490 void MainInterface::debug()
491 {
492 #ifdef DEBUG_INTF
493     msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
494     msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
495     msg_Dbg( p_intf, "minimumsize: %i - %i", minimumSize().height(), minimumSize().width() );
496
497     msg_Dbg( p_intf, "Stack size: %i - %i", stackCentralW->size().height(), stackCentralW->size().width() );
498     msg_Dbg( p_intf, "Stack sizeHint: %i - %i", stackCentralW->sizeHint().height(), stackCentralW->sizeHint().width() );
499     msg_Dbg( p_intf, "Central size: %i - %i", centralWidget()->size().height(), centralWidget()->size().width() );
500 #endif
501 }
502
503 inline void MainInterface::showVideo() { showTab( videoWidget ); }
504 inline void MainInterface::showBg() { showTab( bgWidget ); }
505
506 inline void MainInterface::showTab( QWidget *widget )
507 {
508 #ifdef DEBUG_INTF
509     msg_Warn( p_intf, "Old stackCentralOldWidget %i", stackCentralW->indexOf( stackCentralOldWidget ) );
510 #endif
511     stackCentralOldWidget = stackCentralW->currentWidget();
512     stackCentralW->setCurrentWidget( widget );
513
514 #ifdef DEBUG_INTF
515     msg_Warn( p_intf, "State change %i",  stackCentralW->currentIndex() );
516     msg_Warn( p_intf, "New stackCentralOldWidget %i", stackCentralW->indexOf( stackCentralOldWidget ) );
517 #endif
518 }
519
520 inline void MainInterface::restoreStackOldWidget()
521 {
522 #ifdef DEBUG_INTF
523     msg_Warn( p_intf, "New stackCentralOldWidget %i", stackCentralW->indexOf( stackCentralOldWidget ) );
524 #endif
525     QWidget *wTemp = stackCentralW->currentWidget();
526
527     stackCentralW->setCurrentWidget( stackCentralOldWidget );
528
529     stackCentralOldWidget = wTemp;
530 #ifdef DEBUG_INTF
531     msg_Warn( p_intf, "Debug %i %i",stackCentralW->indexOf( wTemp ), stackCentralW->indexOf( stackCentralW->currentWidget() ) );
532 #endif
533 }
534
535 void MainInterface::destroyPopupMenu()
536 {
537     QVLCMenu::PopupMenu( p_intf, false );
538 }
539
540 void MainInterface::popupMenu( const QPoint &p )
541 {
542     QVLCMenu::PopupMenu( p_intf, true );
543 }
544
545 void MainInterface::toggleFSC()
546 {
547    if( !fullscreenControls ) return;
548
549    IMEvent *eShow = new IMEvent( FullscreenControlToggle_Type, 0 );
550    QApplication::postEvent( fullscreenControls, eShow );
551 }
552
553 /****************************************************************************
554  * Video Handling
555  ****************************************************************************/
556
557 /* This event is used to deal with the fullscreen and always on top
558    issue conflict (bug in wx) */
559 class SetVideoOnTopQtEvent : public QEvent
560 {
561 public:
562     SetVideoOnTopQtEvent( bool _onTop ) :
563       QEvent( (QEvent::Type)SetVideoOnTopEvent_Type ), onTop( _onTop)
564     {}
565
566     bool OnTop() const { return onTop; }
567
568 private:
569     bool onTop;
570 };
571
572 /**
573  * NOTE:
574  * You must not change the state of this object or other Qt4 UI objects,
575  * from the video output thread - only from the Qt4 UI main loop thread.
576  * All window provider queries must be handled through signals or events.
577  * That's why we have all those emit statements...
578  */
579 WId MainInterface::getVideo( int *pi_x, int *pi_y,
580                              unsigned int *pi_width, unsigned int *pi_height )
581 {
582     if( !videoWidget )
583         return 0;
584
585     /* This is a blocking call signal. Results are returned through pointers.
586      * Beware of deadlocks! */
587     WId id;
588     emit askGetVideo( &id, pi_x, pi_y, pi_width, pi_height );
589     return id;
590 }
591
592 void MainInterface::getVideoSlot( WId *p_id, int *pi_x, int *pi_y,
593                                   unsigned *pi_width, unsigned *pi_height )
594 {
595     /* Request the videoWidget */
596     WId ret = videoWidget->request( pi_x, pi_y,
597                                     pi_width, pi_height, b_keep_size );
598     *p_id = ret;
599     if( ret ) /* The videoWidget is available */
600     {
601         /* Ask videoWidget to resize correctly, if we are in normal mode */
602         if( !isFullScreen() && !isMaximized() )
603             videoWidget->SetSizing( *pi_width, *pi_height );
604
605         /* Consider the video active now */
606         showVideo();
607     }
608 }
609
610 /* Asynchronous call from the WindowClose function */
611 void MainInterface::releaseVideo( void )
612 {
613     emit askReleaseVideo();
614 }
615
616 /* Function that is CONNECTED to the previous emit */
617 void MainInterface::releaseVideoSlot( void )
618 {
619     videoWidget->release();
620
621     if( stackCentralW->currentWidget() == videoWidget )
622         restoreStackOldWidget();
623
624     /* We don't want to have a blank video to popup */
625     stackCentralOldWidget = bgWidget;
626 }
627
628 /* Asynchronous call from WindowControl function */
629 int MainInterface::controlVideo( int i_query, va_list args )
630 {
631     switch( i_query )
632     {
633     case VOUT_WINDOW_SET_SIZE:
634     {
635         unsigned int i_width  = va_arg( args, unsigned int );
636         unsigned int i_height = va_arg( args, unsigned int );
637         if( isFullScreen() || isMaximized() )
638             showNormal();
639         emit askVideoToResize( i_width, i_height );
640         return VLC_SUCCESS;
641     }
642     case VOUT_WINDOW_SET_STATE:
643     {
644         unsigned i_arg = va_arg( args, unsigned );
645         unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
646         QApplication::postEvent( this, new SetVideoOnTopQtEvent( on_top ) );
647         return VLC_SUCCESS;
648     }
649     case VOUT_WINDOW_SET_FULLSCREEN:
650     {
651         bool b_fs = va_arg( args, int );
652         emit askVideoSetFullScreen( b_fs );
653         return VLC_SUCCESS;
654     }
655     default:
656         msg_Warn( p_intf, "unsupported control query" );
657         return VLC_EGENERIC;
658     }
659 }
660
661 /*****************************************************************************
662  * Playlist, Visualisation and Menus handling
663  *****************************************************************************/
664 /**
665  * Toggle the playlist widget or dialog
666  **/
667 void MainInterface::createPlaylist()
668 {
669     playlistWidget = new PlaylistWidget( p_intf, this );
670
671     if( !b_plDocked )
672     {
673         playlistWidget->setWindowFlags( Qt::Window );
674
675         /* This will restore the geometry but will not work for position,
676            because of parenting */
677         QVLCTools::restoreWidgetPosition( p_intf, "Playlist",
678                 playlistWidget, QSize( 600, 300 ) );
679     }
680     else
681     {
682         stackCentralW->addWidget( playlistWidget );
683     }
684 }
685
686 void MainInterface::togglePlaylist()
687 {
688     if( !playlistWidget )
689         createPlaylist();
690
691     if( b_plDocked )
692     {
693         /* Playlist is not visible, show it */
694         if( stackCentralW->currentWidget() != playlistWidget )
695         {
696             showTab( playlistWidget );
697         }
698         else /* Hide it! */
699         {
700             restoreStackOldWidget();
701         }
702         playlistVisible = ( stackCentralW->currentWidget() == playlistWidget );
703     }
704     else
705     {
706         playlistWidget->setWindowFlags( Qt::Window );
707         playlistVisible = !playlistVisible;
708         playlistWidget->setVisible( playlistVisible );
709     }
710     debug();
711 }
712
713 void MainInterface::dockPlaylist( bool p_docked )
714 {
715     if( b_plDocked == p_docked ) return;
716     b_plDocked = p_docked;
717
718     if( !playlistWidget ) return; /* Playlist wasn't created yet */
719     if( !p_docked )
720     {
721         stackCentralW->removeWidget( playlistWidget );
722         playlistWidget->setWindowFlags( Qt::Window );
723         QVLCTools::restoreWidgetPosition( p_intf, "Playlist",
724                 playlistWidget, QSize( 600, 300 ) );
725         playlistWidget->show();
726         restoreStackOldWidget();
727     }
728     else
729     {
730         QVLCTools::saveWidgetPosition( p_intf, "Playlist", playlistWidget );
731         playlistWidget->setWindowFlags( Qt::Widget ); // Probably a Qt bug here
732         // It would be logical that QStackWidget::addWidget reset the flags...
733         stackCentralW->addWidget( playlistWidget );
734         showTab( playlistWidget );
735     }
736     playlistVisible = true;
737 }
738
739 /*
740   If b_switch is false, then we are normalView
741  */
742 void MainInterface::toggleMinimalView( bool b_switch )
743 {
744     if( i_visualmode == 0 )
745     {
746         if( stackCentralW->currentWidget() == bgWidget )
747         {
748             if( stackCentralW->height() < 16 )
749             {
750                 resizeStack( stackCentralW->width(), 100 );
751             }
752         }
753     }
754
755     menuBar()->setVisible( !b_switch );
756     controls->setVisible( !b_switch );
757     statusBar()->setVisible( !b_switch );
758     inputC->setVisible( !b_switch );
759
760     emit minimalViewToggled( b_switch );
761 }
762
763 /* toggling advanced controls buttons */
764 void MainInterface::toggleAdvancedButtons()
765 {
766     controls->toggleAdvanced();
767 //    if( fullscreenControls ) fullscreenControls->toggleAdvanced();
768 }
769
770 /* Get the visibility status of the controls (hidden or not, advanced or not) */
771 int MainInterface::getControlsVisibilityStatus()
772 {
773     if( !controls ) return 0;
774     return( (controls->isVisible() ? CONTROLS_VISIBLE : CONTROLS_HIDDEN )
775                 + CONTROLS_ADVANCED * controls->b_advancedVisible );
776 }
777
778 #if 0
779 void MainInterface::visual()
780 {
781     if( !VISIBLE( visualSelector) )
782     {
783         visualSelector->show();
784         if( !THEMIM->getIM()->hasVideo() )
785         {
786             /* Show the background widget */
787         }
788         visualSelectorEnabled = true;
789     }
790     else
791     {
792         /* Stop any currently running visualization */
793         visualSelector->hide();
794         visualSelectorEnabled = false;
795     }
796 }
797 #endif
798
799 /************************************************************************
800  * Other stuff
801  ************************************************************************/
802 void MainInterface::setName( const QString& name )
803 {
804     input_name = name; /* store it for the QSystray use */
805     /* Display it in the status bar, but also as a Tooltip in case it doesn't
806        fit in the label */
807     nameLabel->setText( " " + name + " " );
808     nameLabel->setToolTip( " " + name +" " );
809 }
810
811 /**
812  * Give the decorations of the Main Window a correct Name.
813  * If nothing is given, set it to VLC...
814  **/
815 void MainInterface::setVLCWindowsTitle( const QString& aTitle )
816 {
817     if( aTitle.isEmpty() )
818     {
819         setWindowTitle( qtr( "VLC media player" ) );
820     }
821     else
822     {
823         setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
824     }
825 }
826
827 void MainInterface::showCryptedLabel( bool b_show )
828 {
829     if( cryptedLabel == NULL )
830     {
831         cryptedLabel = new QLabel;
832         // The lock icon is not the right one for DRM protection/scrambled.
833         //cryptedLabel->setPixmap( QPixmap( ":/lock" ) );
834         cryptedLabel->setText( "DRM" );
835         statusBar()->addWidget( cryptedLabel );
836     }
837
838     cryptedLabel->setVisible( b_show );
839 }
840
841 void MainInterface::showBuffering( float f_cache )
842 {
843     QString amount = QString("Buffering: %1%").arg( (int)(100*f_cache) );
844     statusBar()->showMessage( amount, 1000 );
845 }
846
847 /*****************************************************************************
848  * Systray Icon and Systray Menu
849  *****************************************************************************/
850 #ifndef HAVE_MAEMO
851 /**
852  * Create a SystemTray icon and a menu that would go with it.
853  * Connects to a click handler on the icon.
854  **/
855 void MainInterface::createSystray()
856 {
857     QIcon iconVLC;
858     if( QDate::currentDate().dayOfYear() >= 354 )
859         iconVLC =  QIcon( ":/logo/vlc128-christmas.png" );
860     else
861         iconVLC =  QIcon( ":/logo/vlc128.png" );
862     sysTray = new QSystemTrayIcon( iconVLC, this );
863     sysTray->setToolTip( qtr( "VLC media player" ));
864
865     systrayMenu = new QMenu( qtr( "VLC media player" ), this );
866     systrayMenu->setIcon( iconVLC );
867
868     QVLCMenu::updateSystrayMenu( this, p_intf, true );
869     sysTray->show();
870
871     CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
872             this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
873 }
874
875 /**
876  * Updates the Systray Icon's menu and toggle the main interface
877  */
878 void MainInterface::toggleUpdateSystrayMenu()
879 {
880     /* If hidden, show it */
881     if( isHidden() )
882     {
883         show();
884         activateWindow();
885     }
886     else if( isMinimized() )
887     {
888         /* Minimized */
889         showNormal();
890         activateWindow();
891     }
892     else
893     {
894         /* Visible (possibly under other windows) */
895 #ifdef WIN32
896         /* check if any visible window is above vlc in the z-order,
897          * but ignore the ones always on top
898          * and the ones which can't be activated */
899         WINDOWINFO wi;
900         HWND hwnd;
901         wi.cbSize = sizeof( WINDOWINFO );
902         for( hwnd = GetNextWindow( internalWinId(), GW_HWNDPREV );
903                 hwnd && ( !IsWindowVisible( hwnd ) ||
904                     ( GetWindowInfo( hwnd, &wi ) &&
905                       (wi.dwExStyle&WS_EX_NOACTIVATE) ) );
906                 hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) );
907             if( !hwnd || !GetWindowInfo( hwnd, &wi ) ||
908                 (wi.dwExStyle&WS_EX_TOPMOST) )
909             {
910                 hide();
911             }
912             else
913             {
914                 activateWindow();
915             }
916 #else
917         hide();
918 #endif
919     }
920     QVLCMenu::updateSystrayMenu( this, p_intf );
921 }
922
923 void MainInterface::handleSystrayClick(
924                                     QSystemTrayIcon::ActivationReason reason )
925 {
926     switch( reason )
927     {
928         case QSystemTrayIcon::Trigger:
929         case QSystemTrayIcon::DoubleClick:
930             toggleUpdateSystrayMenu();
931             break;
932         case QSystemTrayIcon::MiddleClick:
933             sysTray->showMessage( qtr( "VLC media player" ),
934                     qtr( "Control menu for the player" ),
935                     QSystemTrayIcon::Information, 3000 );
936             break;
937         default:
938             break;
939     }
940 }
941
942 /**
943  * Updates the name of the systray Icon tooltip.
944  * Doesn't check if the systray exists, check before you call it.
945  **/
946 void MainInterface::updateSystrayTooltipName( const QString& name )
947 {
948     if( name.isEmpty() )
949     {
950         sysTray->setToolTip( qtr( "VLC media player" ) );
951     }
952     else
953     {
954         sysTray->setToolTip( name );
955         if( b_notificationEnabled && ( isHidden() || isMinimized() ) )
956         {
957             sysTray->showMessage( qtr( "VLC media player" ), name,
958                     QSystemTrayIcon::NoIcon, 3000 );
959         }
960     }
961
962     QVLCMenu::updateSystrayMenu( this, p_intf );
963 }
964
965 /**
966  * Updates the status of the systray Icon tooltip.
967  * Doesn't check if the systray exists, check before you call it.
968  **/
969 void MainInterface::updateSystrayTooltipStatus( int i_status )
970 {
971     switch( i_status )
972     {
973     case PLAYING_S:
974         sysTray->setToolTip( input_name );
975         break;
976     case PAUSE_S:
977         sysTray->setToolTip( input_name + " - " + qtr( "Paused") );
978         break;
979     default:
980         sysTray->setToolTip( qtr( "VLC media player" ) );
981         break;
982     }
983     QVLCMenu::updateSystrayMenu( this, p_intf );
984 }
985 #endif
986
987 /************************************************************************
988  * D&D Events
989  ************************************************************************/
990 void MainInterface::dropEvent(QDropEvent *event)
991 {
992     dropEventPlay( event, true );
993 }
994
995 void MainInterface::dropEventPlay( QDropEvent *event, bool b_play )
996 {
997     event->setDropAction( Qt::CopyAction );
998     if( !event->possibleActions() & Qt::CopyAction )
999         return;
1000
1001     const QMimeData *mimeData = event->mimeData();
1002
1003     /* D&D of a subtitles file, add it on the fly */
1004     if( mimeData->urls().size() == 1 && THEMIM->getIM()->hasInput() )
1005     {
1006         QString s = toNativeSeparators( mimeData->urls()[0].toLocalFile() );
1007         if( s.length() > 0
1008          && input_AddSubtitle( THEMIM->getInput(), qtu(s), true ) == 0 )
1009         {
1010             event->accept();
1011             return;
1012         }
1013     }
1014
1015     bool first = b_play;
1016     foreach( const QUrl &url, mimeData->urls() )
1017     {
1018         QString s = url.toString();
1019
1020         if( s.length() > 0 ) {
1021             playlist_Add( THEPL, qtu(s), NULL,
1022                           PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1023                           PLAYLIST_END, true, pl_Unlocked );
1024             first = false;
1025             RecentsMRL::getInstance( p_intf )->addRecent( s );
1026         }
1027     }
1028     event->accept();
1029 }
1030 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1031 {
1032      event->acceptProposedAction();
1033 }
1034 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1035 {
1036      event->acceptProposedAction();
1037 }
1038 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1039 {
1040      event->accept();
1041 }
1042
1043 /************************************************************************
1044  * Events stuff
1045  ************************************************************************/
1046 void MainInterface::customEvent( QEvent *event )
1047 {
1048     if ( event->type() == (int)SetVideoOnTopEvent_Type )
1049     {
1050         SetVideoOnTopQtEvent* p_event = (SetVideoOnTopQtEvent*)event;
1051         if( p_event->OnTop() )
1052             setWindowFlags( windowFlags() | Qt::WindowStaysOnTopHint );
1053         else
1054             setWindowFlags( windowFlags() & ~Qt::WindowStaysOnTopHint );
1055         show(); /* necessary to apply window flags */
1056     }
1057 }
1058
1059 void MainInterface::keyPressEvent( QKeyEvent *e )
1060 {
1061     handleKeyPress( e );
1062 }
1063
1064 void MainInterface::handleKeyPress( QKeyEvent *e )
1065 {
1066     if( ( e->modifiers() &  Qt::ControlModifier ) && ( e->key() == Qt::Key_H )
1067           && !menuBar()->isVisible() )
1068     {
1069         toggleMinimalView( false );
1070         e->accept();
1071     }
1072
1073     int i_vlck = qtEventToVLCKey( e );
1074     if( i_vlck > 0 )
1075     {
1076         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1077         e->accept();
1078     }
1079     else
1080         e->ignore();
1081 }
1082
1083 void MainInterface::wheelEvent( QWheelEvent *e )
1084 {
1085     int i_vlckey = qtWheelEventToVLCKey( e );
1086     var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
1087     e->accept();
1088 }
1089
1090 void MainInterface::closeEvent( QCloseEvent *e )
1091 {
1092     e->accept();
1093     hide();
1094     THEDP->quit();
1095 }
1096
1097 void MainInterface::toggleFullScreen()
1098 {
1099     if( isFullScreen() )
1100     {
1101         showNormal();
1102         emit fullscreenInterfaceToggled( false );
1103     }
1104     else
1105     {
1106         showFullScreen();
1107         emit fullscreenInterfaceToggled( true );
1108     }
1109 }
1110
1111 /*****************************************************************************
1112  * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1113  *  We don't show the menu directly here because we don't want the
1114  *  caller to block for a too long time.
1115  *****************************************************************************/
1116 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
1117                         vlc_value_t old_val, vlc_value_t new_val, void *param )
1118 {
1119     intf_thread_t *p_intf = (intf_thread_t *)param;
1120
1121     if( p_intf->pf_show_dialog )
1122     {
1123         p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1124                                 new_val.b_bool, NULL );
1125     }
1126
1127     return VLC_SUCCESS;
1128 }
1129
1130 /*****************************************************************************
1131  * IntfShowCB: callback triggered by the intf-show libvlc variable.
1132  *****************************************************************************/
1133 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
1134                        vlc_value_t old_val, vlc_value_t new_val, void *param )
1135 {
1136     intf_thread_t *p_intf = (intf_thread_t *)param;
1137     p_intf->p_sys->p_mi->toggleFSC();
1138
1139     /* Show event */
1140      return VLC_SUCCESS;
1141 }