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