]> git.sesse.net Git - vlc/blob - modules/gui/qt4/main_interface.cpp
Qt: hide status bar
[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 #ifdef Q_WS_MAC
106     setAttribute( Qt::WA_MacBrushedMetal );
107 #endif
108
109     /* Is video in embedded in the UI or not */
110     b_videoEmbedded = var_InheritBool( p_intf, "embedded-video" );
111
112     /* Does the interface resize to video size or the opposite */
113     b_autoresize = var_InheritBool( p_intf, "qt-video-autoresize" );
114
115     /* Are we in the enhanced always-video mode or not ? */
116     b_minimalView = var_InheritBool( p_intf, "qt-minimal-view" );
117
118     /* Do we want anoying popups or not */
119     b_notificationEnabled = var_InheritBool( p_intf, "qt-notification" );
120
121     /* Set the other interface settings */
122     settings = getSettings();
123     settings->beginGroup( "MainWindow" );
124
125 #ifdef WIN32
126     /* Volume keys */
127     p_intf->p_sys->disable_volume_keys = var_InheritBool( p_intf, "qt-disable-volume-keys" );
128 #endif
129
130     /* */
131     b_plDocked = getSettings()->value( "pl-dock-status", true ).toBool();
132
133     settings->endGroup( );
134
135     /**************
136      * Status Bar *
137      **************/
138     createStatusBar();
139     statusBar()->setVisible( getSettings()->value( "status-bar-visible", false ).toBool() );
140
141     /**************************
142      *  UI and Widgets design
143      **************************/
144     setVLCWindowsTitle();
145
146     /************
147      * Menu Bar *
148      ************/
149     QVLCMenu::createMenuBar( this, p_intf );
150     CONNECT( THEMIM->getIM(), voutListChanged( vout_thread_t **, int ),
151              this, destroyPopupMenu() );
152
153     createMainWidget( settings );
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(), playingStatusChanged( int ),
203                  this, updateSystrayTooltipStatus( int ) );
204     }
205 #endif
206
207     /* END CONNECTS ON IM */
208
209     /* VideoWidget connects for asynchronous calls */
210     b_videoFullScreen = false;
211     b_videoOnTop = false;
212     connect( this, SIGNAL(askGetVideo(WId*,int*,int*,unsigned*,unsigned *)),
213              this, SLOT(getVideoSlot(WId*,int*,int*,unsigned*,unsigned*)),
214              Qt::BlockingQueuedConnection );
215     connect( this, SIGNAL(askReleaseVideo( void )),
216              this, SLOT(releaseVideoSlot( void )),
217              Qt::BlockingQueuedConnection );
218     CONNECT( this, askVideoOnTop(bool), this, setVideoOnTop(bool));
219
220     if( videoWidget )
221     {
222         if( b_autoresize )
223         {
224             CONNECT( this, askVideoToResize( unsigned int, unsigned int ),
225                      this, setVideoSize( unsigned int, unsigned int ) );
226             CONNECT( videoWidget, sizeChanged( int, int ),
227                      this, resizeStack( int,  int ) );
228         }
229         CONNECT( this, askVideoSetFullScreen( bool ),
230                  this, setVideoFullScreen( bool ) );
231     }
232
233     CONNECT( THEDP, toolBarConfUpdated(), this, recreateToolbars() );
234
235     CONNECT( this, askToQuit(), THEDP, quit() );
236
237     /** END of CONNECTS**/
238
239
240     /************
241      * Callbacks
242      ************/
243     var_AddCallback( p_intf->p_libvlc, "intf-show", IntfShowCB, p_intf );
244
245     /* Register callback for the intf-popupmenu variable */
246     var_AddCallback( p_intf->p_libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
247
248     /* Playlist */
249     int i_plVis = settings->value( "MainWindow/playlist-visible", false ).toBool();
250
251     if( i_plVis ) togglePlaylist();
252
253     /**** FINAL SIZING and placement of interface */
254     settings->beginGroup( "MainWindow" );
255     QVLCTools::restoreWidgetPosition( settings, this, QSize(400, 100) );
256     settings->endGroup();
257
258     b_interfaceFullScreen = isFullScreen();
259
260     /* Final sizing and showing */
261     setVisible( !b_hideAfterCreation );
262
263     computeMinimumSize();
264
265     /* Switch to minimal view if needed, must be called after the show() */
266     if( b_minimalView )
267         toggleMinimalView( true );
268
269     b_hasPausedWhenMinimized = false;
270 }
271
272 MainInterface::~MainInterface()
273 {
274     /* Unsure we hide the videoWidget before destroying it */
275     if( stackCentralOldWidget == videoWidget )
276         showTab( bgWidget );
277
278     if( videoWidget )
279         releaseVideoSlot();
280
281 #ifdef WIN32
282     if( himl )
283         ImageList_Destroy( himl );
284     if(p_taskbl)
285         p_taskbl->vt->Release(p_taskbl);
286     CoUninitialize();
287 #endif
288
289     /* Be sure to kill the actionsManager... Only used in the MI and control */
290     ActionsManager::killInstance();
291
292     /* Idem */
293     ExtensionsManager::killInstance();
294
295     /* Delete the FSC controller */
296     delete fullscreenControls;
297
298     /* Save states */
299     settings->beginGroup( "MainWindow" );
300
301     settings->setValue( "pl-dock-status", b_plDocked );
302     /* Save playlist state */
303     if( playlistWidget )
304         settings->setValue( "playlist-visible", playlistVisible );
305
306     settings->setValue( "adv-controls",
307                         getControlsVisibilityStatus() & CONTROLS_ADVANCED );
308     settings->setValue( "status-bar-visible", statusBar()->isVisible() );
309
310     /* Save the stackCentralW sizes */
311     settings->setValue( "bgSize", stackWidgetsSizes[bgWidget] );
312     settings->setValue( "playlistSize", stackWidgetsSizes[playlistWidget] );
313
314     /* Save this size */
315     QVLCTools::saveWidgetPosition(settings, this);
316
317     settings->endGroup();
318
319     /* Save undocked playlist size */
320     if( playlistWidget && !isPlDocked() )
321         QVLCTools::saveWidgetPosition( p_intf, "Playlist", playlistWidget );
322
323     delete playlistWidget;
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 void MainInterface::computeMinimumSize()
335 {
336     int minWidth = 30;
337     if( menuBar()->isVisible() )
338         minWidth += __MAX( controls->sizeHint().width(), menuBar()->sizeHint().width() );
339
340     setMinimumWidth( minWidth );
341 }
342
343 /*****************************
344  *   Main UI handling        *
345  *****************************/
346 void MainInterface::recreateToolbars()
347 {
348     bool b_adv = getControlsVisibilityStatus() & CONTROLS_ADVANCED;
349
350     settings->beginGroup( "MainWindow" );
351     delete controls;
352     delete inputC;
353
354     controls = new ControlsWidget( p_intf, b_adv, this );
355     inputC = new InputControlsWidget( p_intf, this );
356
357     if( fullscreenControls )
358     {
359         delete fullscreenControls;
360         fullscreenControls = new FullscreenControllerWidget( p_intf, this );
361         CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
362                  this, handleKeyPress( QKeyEvent * ) );
363     }
364     mainLayout->insertWidget( 2, inputC );
365     mainLayout->insertWidget( settings->value( "ToolbarPos", 0 ).toInt() ? 0: 3,
366                               controls );
367     settings->endGroup();
368 }
369
370 void MainInterface::createMainWidget( QSettings *settings )
371 {
372     /* Create the main Widget and the mainLayout */
373     QWidget *main = new QWidget;
374     setCentralWidget( main );
375     mainLayout = new QVBoxLayout( main );
376     main->setContentsMargins( 0, 0, 0, 0 );
377     mainLayout->setSpacing( 0 ); mainLayout->setMargin( 0 );
378
379     /* */
380     stackCentralW = new QVLCStackedWidget( main );
381
382     /* Bg Cone */
383     bgWidget = new BackgroundWidget( p_intf );
384     stackCentralW->addWidget( bgWidget );
385     if ( !var_InheritBool( p_intf, "qt-bgcone" ) )
386         bgWidget->setWithArt( false );
387     else
388         if ( var_InheritBool( p_intf, "qt-bgcone-expands" ) )
389             bgWidget->setExpandstoHeight( true );
390
391     /* And video Outputs */
392     if( b_videoEmbedded )
393     {
394         videoWidget = new VideoWidget( p_intf );
395         stackCentralW->addWidget( videoWidget );
396     }
397     mainLayout->insertWidget( 1, stackCentralW );
398
399     settings->beginGroup( "MainWindow" );
400     stackWidgetsSizes[bgWidget] = settings->value( "bgSize", QSize( 400, 0 ) ).toSize();
401     /* Resize even if no-auto-resize, because we are at creation */
402     resizeStack( stackWidgetsSizes[bgWidget].width(), stackWidgetsSizes[bgWidget].height() );
403
404     /* Create the CONTROLS Widget */
405     controls = new ControlsWidget( p_intf,
406                    settings->value( "adv-controls", false ).toBool(), this );
407     inputC = new InputControlsWidget( p_intf, this );
408
409     mainLayout->insertWidget( 2, inputC );
410     mainLayout->insertWidget( settings->value( "ToolbarPos", 0 ).toInt() ? 0: 3,
411                               controls );
412
413     /* Visualisation, disabled for now, they SUCK */
414     #if 0
415     visualSelector = new VisualSelector( p_intf );
416     mainLayout->insertWidget( 0, visualSelector );
417     visualSelector->hide();
418     #endif
419
420     settings->endGroup();
421
422     /* Enable the popup menu in the MI */
423     main->setContextMenuPolicy( Qt::CustomContextMenu );
424     CONNECT( main, customContextMenuRequested( const QPoint& ),
425              this, popupMenu( const QPoint& ) );
426
427     if ( depth() > 8 ) /* 8bit depth has too many issues with opacity */
428         /* Create the FULLSCREEN CONTROLS Widget */
429         if( var_InheritBool( p_intf, "qt-fs-controller" ) )
430         {
431             fullscreenControls = new FullscreenControllerWidget( p_intf, this );
432             CONNECT( fullscreenControls, keyPressed( QKeyEvent * ),
433                      this, handleKeyPress( QKeyEvent * ) );
434         }
435 }
436
437 inline void MainInterface::initSystray()
438 {
439 #ifndef HAVE_MAEMO
440     bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
441     bool b_systrayWanted = var_InheritBool( p_intf, "qt-system-tray" );
442
443     if( var_InheritBool( p_intf, "qt-start-minimized") )
444     {
445         if( b_systrayAvailable )
446         {
447             b_systrayWanted = true;
448             b_hideAfterCreation = true;
449         }
450         else
451             msg_Err( p_intf, "cannot start minimized without system tray bar" );
452     }
453
454     if( b_systrayAvailable && b_systrayWanted )
455         createSystray();
456 #endif
457 }
458
459 inline void MainInterface::createStatusBar()
460 {
461     /****************
462      *  Status Bar  *
463      ****************/
464     /* Widgets Creation*/
465     QStatusBar *statusBarr = statusBar();
466
467     TimeLabel *timeLabel = new TimeLabel( p_intf );
468     nameLabel = new QLabel( this );
469     nameLabel->setTextInteractionFlags( Qt::TextSelectableByMouse
470                                       | Qt::TextSelectableByKeyboard );
471     SpeedLabel *speedLabel = new SpeedLabel( p_intf, this );
472
473     /* Styling those labels */
474     timeLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
475     speedLabel->setFrameStyle( QFrame::Sunken | QFrame::Panel );
476     nameLabel->setFrameStyle( QFrame::Sunken | QFrame::StyledPanel);
477     timeLabel->setStyleSheet(
478             "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
479     speedLabel->setStyleSheet(
480             "QLabel:hover { background-color: rgba(255, 255, 255, 50%) }" );
481     /* pad both label and its tooltip */
482     nameLabel->setStyleSheet( "padding-left: 5px; padding-right: 5px;" );
483
484     /* and adding those */
485     statusBarr->addWidget( nameLabel, 8 );
486     statusBarr->addPermanentWidget( speedLabel, 0 );
487     statusBarr->addPermanentWidget( timeLabel, 0 );
488
489     /* timeLabel behaviour:
490        - double clicking opens the goto time dialog
491        - right-clicking and clicking just toggle between remaining and
492          elapsed time.*/
493     CONNECT( timeLabel, timeLabelDoubleClicked(), THEDP, gotoTimeDialog() );
494
495     CONNECT( THEMIM->getIM(), encryptionChanged( bool ),
496              this, showCryptedLabel( bool ) );
497
498     CONNECT( THEMIM->getIM(), seekRequested( float ),
499              timeLabel, setDisplayPosition( float ) );
500
501     /* This shouldn't be necessary, but for somehow reason, the statusBarr
502        starts at height of 20px and when a text is shown it needs more space.
503        But, as the QMainWindow policy doesn't allow statusBar to change QMW's
504        geometry, we need to force a height. If you have a better idea, please
505        tell me -- jb
506      */
507     statusBarr->setFixedHeight( statusBarr->sizeHint().height() + 2 );
508 }
509
510 /**********************************************************************
511  * Handling of sizing of the components
512  **********************************************************************/
513
514 void MainInterface::debug()
515 {
516 #ifdef DEBUG_INTF
517     msg_Dbg( p_intf, "size: %i - %i", size().height(), size().width() );
518     msg_Dbg( p_intf, "sizeHint: %i - %i", sizeHint().height(), sizeHint().width() );
519     msg_Dbg( p_intf, "minimumsize: %i - %i", minimumSize().height(), minimumSize().width() );
520
521     msg_Dbg( p_intf, "Stack size: %i - %i", stackCentralW->size().height(), stackCentralW->size().width() );
522     msg_Dbg( p_intf, "Stack sizeHint: %i - %i", stackCentralW->sizeHint().height(), stackCentralW->sizeHint().width() );
523     msg_Dbg( p_intf, "Central size: %i - %i", centralWidget()->size().height(), centralWidget()->size().width() );
524 #endif
525 }
526
527 inline void MainInterface::showVideo() { showTab( videoWidget ); }
528 inline void MainInterface::restoreStackOldWidget()
529             { showTab( stackCentralOldWidget ); }
530
531 inline void MainInterface::showTab( QWidget *widget )
532 {
533 #ifdef DEBUG_INTF
534     msg_Warn( p_intf, "Old stackCentralOldWidget %i", stackCentralW->indexOf( stackCentralOldWidget ) );
535 #endif
536
537     stackCentralOldWidget = stackCentralW->currentWidget();
538     stackWidgetsSizes[stackCentralOldWidget] = stackCentralW->size();
539
540     stackCentralW->setCurrentWidget( widget );
541     if( b_autoresize )
542         resizeStack( stackWidgetsSizes[widget].width(), stackWidgetsSizes[widget].height() );
543
544 #ifdef DEBUG_INTF
545     msg_Warn( p_intf, "State change %i",  stackCentralW->currentIndex() );
546     msg_Warn( p_intf, "New stackCentralOldWidget %i", stackCentralW->indexOf( stackCentralOldWidget ) );
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 /**
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_autoresize );
598     *p_id = ret;
599     if( ret ) /* The videoWidget is available */
600     {
601         /* Consider the video active now */
602         showVideo();
603
604         /* Ask videoWidget to resize correctly, if we are in normal mode */
605         if( !isFullScreen() && !isMaximized() && b_autoresize )
606             videoWidget->SetSizing( *pi_width, *pi_height );
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     /* This function is called when the embedded video window is destroyed,
620      * or in the rare case that the embedded window is still here but the
621      * Qt4 interface exits. */
622     assert( videoWidget );
623     videoWidget->release();
624     setVideoOnTop( false );
625     setVideoFullScreen( false );
626
627     if( stackCentralW->currentWidget() == videoWidget )
628         restoreStackOldWidget();
629
630     /* We don't want to have a blank video to popup */
631     stackCentralOldWidget = bgWidget;
632 }
633
634 void MainInterface::setVideoSize( unsigned int w, unsigned int h )
635 {
636     if( !isFullScreen() && !isMaximized() )
637         videoWidget->SetSizing( w, h );
638 }
639
640 void MainInterface::setVideoFullScreen( bool fs )
641 {
642     b_videoFullScreen = fs;
643     if( fs )
644     {
645         int numscreen = var_InheritInteger( p_intf, "qt-fullscreen-screennumber" );
646         /* if user hasn't defined screennumber, or screennumber that is bigger
647          * than current number of screens, take screennumber where current interface
648          * is
649          */
650         if( numscreen == -1 || numscreen > QApplication::desktop()->numScreens() )
651             numscreen = QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
652
653         QRect screenres = QApplication::desktop()->screenGeometry( numscreen );
654
655         /* To be sure window is on proper-screen in xinerama */
656         if( !screenres.contains( pos() ) )
657         {
658             msg_Dbg( p_intf, "Moving video to correct screen");
659             move( QPoint( screenres.x(), screenres.y() ) );
660         }
661         setMinimalView( true );
662         setInterfaceFullScreen( true );
663     }
664     else
665     {
666         /* TODO do we want to restore screen and position ? (when
667          * qt-fullscreen-screennumber is forced) */
668         setMinimalView( b_minimalView );
669         setInterfaceFullScreen( b_interfaceFullScreen );
670     }
671     videoWidget->sync();
672 }
673
674 /* Slot to change the video always-on-top flag.
675  * Emit askVideoOnTop() to invoke this from other thread. */
676 void MainInterface::setVideoOnTop( bool on_top )
677 {
678     b_videoOnTop = on_top;
679
680     Qt::WindowFlags oldflags = windowFlags(), newflags;
681
682     if( b_videoOnTop )
683         newflags = oldflags | Qt::WindowStaysOnTopHint;
684     else
685         newflags = oldflags & ~Qt::WindowStaysOnTopHint;
686
687     if( newflags != oldflags )
688     {
689         setWindowFlags( newflags );
690         show(); /* necessary to apply window flags */
691     }
692 }
693
694 /* Asynchronous call from WindowControl function */
695 int MainInterface::controlVideo( int i_query, va_list args )
696 {
697     switch( i_query )
698     {
699     case VOUT_WINDOW_SET_SIZE:
700     {
701         unsigned int i_width  = va_arg( args, unsigned int );
702         unsigned int i_height = va_arg( args, unsigned int );
703
704         emit askVideoToResize( i_width, i_height );
705         return VLC_SUCCESS;
706     }
707     case VOUT_WINDOW_SET_STATE:
708     {
709         unsigned i_arg = va_arg( args, unsigned );
710         unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
711
712         emit askVideoOnTop( on_top != 0 );
713         return VLC_SUCCESS;
714     }
715     case VOUT_WINDOW_SET_FULLSCREEN:
716     {
717         bool b_fs = va_arg( args, int );
718
719         emit askVideoSetFullScreen( b_fs );
720         return VLC_SUCCESS;
721     }
722     default:
723         msg_Warn( p_intf, "unsupported control query" );
724         return VLC_EGENERIC;
725     }
726 }
727
728 /*****************************************************************************
729  * Playlist, Visualisation and Menus handling
730  *****************************************************************************/
731 /**
732  * Toggle the playlist widget or dialog
733  **/
734 void MainInterface::createPlaylist()
735 {
736     playlistWidget = new PlaylistWidget( p_intf, this );
737
738     if( b_plDocked )
739     {
740         stackCentralW->addWidget( playlistWidget );
741         stackWidgetsSizes[playlistWidget] = settings->value( "playlistSize", QSize( 500, 250 ) ).toSize();
742     }
743     else
744     {
745 #ifdef WIN32
746         playlistWidget->setParent( NULL );
747 #endif
748         playlistWidget->setWindowFlags( Qt::Window );
749
750         /* This will restore the geometry but will not work for position,
751            because of parenting */
752         QVLCTools::restoreWidgetPosition( p_intf, "Playlist",
753                 playlistWidget, QSize( 600, 300 ) );
754     }
755 }
756
757 void MainInterface::togglePlaylist()
758 {
759     if( !playlistWidget )
760     {
761         createPlaylist();
762     }
763
764     if( b_plDocked )
765     {
766         /* Playlist is not visible, show it */
767         if( stackCentralW->currentWidget() != playlistWidget )
768         {
769             showTab( playlistWidget );
770         }
771         else /* Hide it! */
772         {
773             restoreStackOldWidget();
774         }
775         playlistVisible = ( stackCentralW->currentWidget() == playlistWidget );
776     }
777     else
778     {
779 #ifdef WIN32
780         playlistWidget->setParent( NULL );
781 #endif
782         playlistWidget->setWindowFlags( Qt::Window );
783         playlistVisible = !playlistVisible;
784         playlistWidget->setVisible( playlistVisible );
785     }
786     debug();
787 }
788
789 void MainInterface::dockPlaylist( bool p_docked )
790 {
791     if( b_plDocked == p_docked ) return;
792     b_plDocked = p_docked;
793
794     if( !playlistWidget ) return; /* Playlist wasn't created yet */
795     if( !p_docked )
796     {
797         stackCentralW->removeWidget( playlistWidget );
798 #ifdef WIN32
799         playlistWidget->setParent( NULL );
800 #endif
801         playlistWidget->setWindowFlags( Qt::Window );
802         QVLCTools::restoreWidgetPosition( p_intf, "Playlist",
803                 playlistWidget, QSize( 600, 300 ) );
804         playlistWidget->show();
805         restoreStackOldWidget();
806     }
807     else
808     {
809         QVLCTools::saveWidgetPosition( p_intf, "Playlist", playlistWidget );
810         playlistWidget->setWindowFlags( Qt::Widget ); // Probably a Qt bug here
811         // It would be logical that QStackWidget::addWidget reset the flags...
812         stackCentralW->addWidget( playlistWidget );
813         showTab( playlistWidget );
814     }
815     playlistVisible = true;
816 }
817
818 /*
819  * setMinimalView is the private function used by
820  * the SLOT toggleMinimalView and setVideoFullScreen
821  */
822 void MainInterface::setMinimalView( bool b_minimal )
823 {
824     menuBar()->setVisible( !b_minimal );
825     controls->setVisible( !b_minimal );
826     statusBar()->setVisible( !b_minimal );
827     inputC->setVisible( !b_minimal );
828 }
829
830 /*
831  * This public SLOT is used for moving to minimal View Mode
832  *
833  * If b_minimal is false, then we are normalView
834  */
835 void MainInterface::toggleMinimalView( bool b_minimal )
836 {
837     if( !b_minimalView && b_autoresize ) /* Normal mode */
838     {
839         if( stackCentralW->currentWidget() == bgWidget )
840         {
841             if( stackCentralW->height() < 16 )
842             {
843                 resizeStack( stackCentralW->width(), 100 );
844             }
845         }
846     }
847     b_minimalView = b_minimal;
848     if( !b_videoFullScreen )
849     {
850         setMinimalView( b_minimalView );
851         computeMinimumSize();
852     }
853
854     emit minimalViewToggled( b_minimalView );
855 }
856
857 /* toggling advanced controls buttons */
858 void MainInterface::toggleAdvancedButtons()
859 {
860     controls->toggleAdvanced();
861 //    if( fullscreenControls ) fullscreenControls->toggleAdvanced();
862 }
863
864 /* Get the visibility status of the controls (hidden or not, advanced or not) */
865 int MainInterface::getControlsVisibilityStatus()
866 {
867     if( !controls ) return 0;
868     return( (controls->isVisible() ? CONTROLS_VISIBLE : CONTROLS_HIDDEN )
869                 + CONTROLS_ADVANCED * controls->b_advancedVisible );
870 }
871
872 void MainInterface::setStatusBarVisibility( bool b_visible )
873 {
874     statusBar()->setVisible( b_visible );
875 }
876
877 #if 0
878 void MainInterface::visual()
879 {
880     if( !VISIBLE( visualSelector) )
881     {
882         visualSelector->show();
883         if( !THEMIM->getIM()->hasVideo() )
884         {
885             /* Show the background widget */
886         }
887         visualSelectorEnabled = true;
888     }
889     else
890     {
891         /* Stop any currently running visualization */
892         visualSelector->hide();
893         visualSelectorEnabled = false;
894     }
895 }
896 #endif
897
898 /************************************************************************
899  * Other stuff
900  ************************************************************************/
901 void MainInterface::setName( const QString& name )
902 {
903     input_name = name; /* store it for the QSystray use */
904     /* Display it in the status bar, but also as a Tooltip in case it doesn't
905        fit in the label */
906     nameLabel->setText( name );
907     nameLabel->setToolTip( name );
908 }
909
910 /**
911  * Give the decorations of the Main Window a correct Name.
912  * If nothing is given, set it to VLC...
913  **/
914 void MainInterface::setVLCWindowsTitle( const QString& aTitle )
915 {
916     if( aTitle.isEmpty() )
917     {
918         setWindowTitle( qtr( "VLC media player" ) );
919     }
920     else
921     {
922         setWindowTitle( aTitle + " - " + qtr( "VLC media player" ) );
923     }
924 }
925
926 void MainInterface::showCryptedLabel( bool b_show )
927 {
928     if( cryptedLabel == NULL )
929     {
930         cryptedLabel = new QLabel;
931         // The lock icon is not the right one for DRM protection/scrambled.
932         //cryptedLabel->setPixmap( QPixmap( ":/lock" ) );
933         cryptedLabel->setText( "DRM" );
934         statusBar()->addWidget( cryptedLabel );
935     }
936
937     cryptedLabel->setVisible( b_show );
938 }
939
940 void MainInterface::showBuffering( float f_cache )
941 {
942     QString amount = QString("Buffering: %1%").arg( (int)(100*f_cache) );
943     statusBar()->showMessage( amount, 1000 );
944 }
945
946 /*****************************************************************************
947  * Systray Icon and Systray Menu
948  *****************************************************************************/
949 #ifndef HAVE_MAEMO
950 /**
951  * Create a SystemTray icon and a menu that would go with it.
952  * Connects to a click handler on the icon.
953  **/
954 void MainInterface::createSystray()
955 {
956     QIcon iconVLC;
957     if( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY && var_InheritBool( p_intf, "qt-icon-change" ) )
958         iconVLC =  QIcon( ":/logo/vlc128-xmas.png" );
959     else
960         iconVLC =  QIcon( ":/logo/vlc128.png" );
961     sysTray = new QSystemTrayIcon( iconVLC, this );
962     sysTray->setToolTip( qtr( "VLC media player" ));
963
964     systrayMenu = new QMenu( qtr( "VLC media player" ), this );
965     systrayMenu->setIcon( iconVLC );
966
967     QVLCMenu::updateSystrayMenu( this, p_intf, true );
968     sysTray->show();
969
970     CONNECT( sysTray, activated( QSystemTrayIcon::ActivationReason ),
971             this, handleSystrayClick( QSystemTrayIcon::ActivationReason ) );
972 }
973
974 /**
975  * Updates the Systray Icon's menu and toggle the main interface
976  */
977 void MainInterface::toggleUpdateSystrayMenu()
978 {
979     /* If hidden, show it */
980     if( isHidden() )
981     {
982         show();
983         activateWindow();
984     }
985     else if( isMinimized() )
986     {
987         /* Minimized */
988         showNormal();
989         activateWindow();
990     }
991     else
992     {
993         /* Visible (possibly under other windows) */
994 #ifdef WIN32
995         /* check if any visible window is above vlc in the z-order,
996          * but ignore the ones always on top
997          * and the ones which can't be activated */
998         WINDOWINFO wi;
999         HWND hwnd;
1000         wi.cbSize = sizeof( WINDOWINFO );
1001         for( hwnd = GetNextWindow( internalWinId(), GW_HWNDPREV );
1002                 hwnd && ( !IsWindowVisible( hwnd ) ||
1003                     ( GetWindowInfo( hwnd, &wi ) &&
1004                       (wi.dwExStyle&WS_EX_NOACTIVATE) ) );
1005                 hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) );
1006             if( !hwnd || !GetWindowInfo( hwnd, &wi ) ||
1007                 (wi.dwExStyle&WS_EX_TOPMOST) )
1008             {
1009                 hide();
1010             }
1011             else
1012             {
1013                 activateWindow();
1014             }
1015 #else
1016         hide();
1017 #endif
1018     }
1019     QVLCMenu::updateSystrayMenu( this, p_intf );
1020 }
1021
1022 void MainInterface::showUpdateSystrayMenu()
1023 {
1024     if( isHidden() )
1025         show();
1026     if( isMinimized() )
1027         showNormal();
1028     activateWindow();
1029
1030     QVLCMenu::updateSystrayMenu( this, p_intf );
1031 }
1032
1033 void MainInterface::hideUpdateSystrayMenu()
1034 {
1035     hide();
1036     QVLCMenu::updateSystrayMenu( this, p_intf );
1037 }
1038
1039 void MainInterface::handleSystrayClick(
1040                                     QSystemTrayIcon::ActivationReason reason )
1041 {
1042     switch( reason )
1043     {
1044         case QSystemTrayIcon::Trigger:
1045         case QSystemTrayIcon::DoubleClick:
1046 #ifdef Q_WS_MAC
1047             QVLCMenu::updateSystrayMenu( this, p_intf );
1048 #else
1049             toggleUpdateSystrayMenu();
1050 #endif
1051             break;
1052         case QSystemTrayIcon::MiddleClick:
1053             sysTray->showMessage( qtr( "VLC media player" ),
1054                     qtr( "Control menu for the player" ),
1055                     QSystemTrayIcon::Information, 3000 );
1056             break;
1057         default:
1058             break;
1059     }
1060 }
1061
1062 /**
1063  * Updates the name of the systray Icon tooltip.
1064  * Doesn't check if the systray exists, check before you call it.
1065  **/
1066 void MainInterface::updateSystrayTooltipName( const QString& name )
1067 {
1068     if( name.isEmpty() )
1069     {
1070         sysTray->setToolTip( qtr( "VLC media player" ) );
1071     }
1072     else
1073     {
1074         sysTray->setToolTip( name );
1075         if( b_notificationEnabled && ( isHidden() || isMinimized() ) )
1076         {
1077             sysTray->showMessage( qtr( "VLC media player" ), name,
1078                     QSystemTrayIcon::NoIcon, 3000 );
1079         }
1080     }
1081
1082     QVLCMenu::updateSystrayMenu( this, p_intf );
1083 }
1084
1085 /**
1086  * Updates the status of the systray Icon tooltip.
1087  * Doesn't check if the systray exists, check before you call it.
1088  **/
1089 void MainInterface::updateSystrayTooltipStatus( int i_status )
1090 {
1091     switch( i_status )
1092     {
1093     case PLAYING_S:
1094         sysTray->setToolTip( input_name );
1095         break;
1096     case PAUSE_S:
1097         sysTray->setToolTip( input_name + " - " + qtr( "Paused") );
1098         break;
1099     default:
1100         sysTray->setToolTip( qtr( "VLC media player" ) );
1101         break;
1102     }
1103     QVLCMenu::updateSystrayMenu( this, p_intf );
1104 }
1105 #endif
1106
1107 void MainInterface::changeEvent(QEvent *event)
1108 {
1109     if( event->type() == QEvent::WindowStateChange )
1110     {
1111         QWindowStateChangeEvent *windowStateChangeEvent = static_cast<QWindowStateChangeEvent*>(event);
1112         Qt::WindowStates newState = windowState();
1113         Qt::WindowStates oldState = windowStateChangeEvent->oldState();
1114
1115         if( newState & Qt::WindowMinimized )
1116         {
1117             b_hasPausedWhenMinimized = false;
1118
1119             if( THEMIM->getIM()->playingStatus() == PLAYING_S &&
1120                 THEMIM->getIM()->hasVideo() &&
1121                 !THEMIM->getIM()->hasVisualisation() &&
1122                 var_InheritBool( p_intf, "qt-pause-minimized" ) )
1123             {
1124                 b_hasPausedWhenMinimized = true;
1125                 THEMIM->pause();
1126             }
1127         }
1128         else if( oldState & Qt::WindowMinimized && !( newState & Qt::WindowMinimized ) )
1129         {
1130             if( b_hasPausedWhenMinimized )
1131             {
1132                 THEMIM->play();
1133             }
1134         }
1135     }
1136
1137     QWidget::changeEvent(event);
1138 }
1139
1140 /************************************************************************
1141  * D&D Events
1142  ************************************************************************/
1143 void MainInterface::dropEvent(QDropEvent *event)
1144 {
1145     dropEventPlay( event, true );
1146 }
1147
1148 void MainInterface::dropEventPlay( QDropEvent *event, bool b_play )
1149 {
1150     if( event->possibleActions() & Qt::CopyAction )
1151        event->setDropAction( Qt::CopyAction );
1152     else
1153         return;
1154
1155     const QMimeData *mimeData = event->mimeData();
1156
1157     /* D&D of a subtitles file, add it on the fly */
1158     if( mimeData->urls().size() == 1 && THEMIM->getIM()->hasInput() )
1159     {
1160         if( !input_AddSubtitle( THEMIM->getInput(),
1161                  qtu( toNativeSeparators( mimeData->urls()[0].toLocalFile() ) ),
1162                  true ) )
1163         {
1164             event->accept();
1165             return;
1166         }
1167     }
1168
1169     bool first = b_play;
1170     foreach( const QUrl &url, mimeData->urls() )
1171     {
1172         if( url.isValid() )
1173         {
1174             QString mrl = toURI( url.toEncoded().constData() );
1175             playlist_Add( THEPL, qtu(mrl), NULL,
1176                           PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1177                           PLAYLIST_END, true, pl_Unlocked );
1178             first = false;
1179             RecentsMRL::getInstance( p_intf )->addRecent( url.toString() );
1180         }
1181     }
1182
1183     /* Browsers give content as text if you dnd the addressbar,
1184        so check if mimedata has valid url in text and use it
1185        if we didn't get any normal Urls()*/
1186     if( !mimeData->hasUrls() && mimeData->hasText() &&
1187         QUrl(mimeData->text()).isValid() )
1188     {
1189         QString mrl = toURI( mimeData->text() );
1190         playlist_Add( THEPL, qtu(mrl), NULL,
1191                       PLAYLIST_APPEND | (first ? PLAYLIST_GO: PLAYLIST_PREPARSE),
1192                       PLAYLIST_END, true, pl_Unlocked );
1193     }
1194     event->accept();
1195 }
1196 void MainInterface::dragEnterEvent(QDragEnterEvent *event)
1197 {
1198      event->acceptProposedAction();
1199 }
1200 void MainInterface::dragMoveEvent(QDragMoveEvent *event)
1201 {
1202      event->acceptProposedAction();
1203 }
1204 void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
1205 {
1206      event->accept();
1207 }
1208
1209 /************************************************************************
1210  * Events stuff
1211  ************************************************************************/
1212 void MainInterface::keyPressEvent( QKeyEvent *e )
1213 {
1214     handleKeyPress( e );
1215 }
1216
1217 void MainInterface::handleKeyPress( QKeyEvent *e )
1218 {
1219     if( ( e->modifiers() &  Qt::ControlModifier ) && ( e->key() == Qt::Key_H ) )
1220     {
1221         toggleMinimalView( !b_minimalView );
1222         e->accept();
1223     }
1224
1225     int i_vlck = qtEventToVLCKey( e );
1226     if( i_vlck > 0 )
1227     {
1228         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlck );
1229         e->accept();
1230     }
1231     else
1232         e->ignore();
1233 }
1234
1235 void MainInterface::wheelEvent( QWheelEvent *e )
1236 {
1237     int i_vlckey = qtWheelEventToVLCKey( e );
1238     var_SetInteger( p_intf->p_libvlc, "key-pressed", i_vlckey );
1239     e->accept();
1240 }
1241
1242 void MainInterface::closeEvent( QCloseEvent *e )
1243 {
1244     e->ignore();      /* Do not quit */
1245 //  hide();
1246     emit askToQuit(); /* ask THEDP to quit, so we have a unique method */
1247 }
1248
1249 void MainInterface::setInterfaceFullScreen( bool fs )
1250 {
1251     if( fs )
1252         setWindowState( windowState() | Qt::WindowFullScreen );
1253     else
1254         setWindowState( windowState() & ~Qt::WindowFullScreen );
1255 }
1256 void MainInterface::toggleInterfaceFullScreen()
1257 {
1258     b_interfaceFullScreen = !b_interfaceFullScreen;
1259     if( !b_videoFullScreen )
1260         setInterfaceFullScreen( b_interfaceFullScreen );
1261     emit fullscreenInterfaceToggled( b_interfaceFullScreen );
1262 }
1263
1264 /*****************************************************************************
1265  * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
1266  *  We don't show the menu directly here because we don't want the
1267  *  caller to block for a too long time.
1268  *****************************************************************************/
1269 static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
1270                         vlc_value_t old_val, vlc_value_t new_val, void *param )
1271 {
1272     intf_thread_t *p_intf = (intf_thread_t *)param;
1273
1274     if( p_intf->pf_show_dialog )
1275     {
1276         p_intf->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
1277                                 new_val.b_bool, NULL );
1278     }
1279
1280     return VLC_SUCCESS;
1281 }
1282
1283 /*****************************************************************************
1284  * IntfShowCB: callback triggered by the intf-show libvlc variable.
1285  *****************************************************************************/
1286 static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
1287                        vlc_value_t old_val, vlc_value_t new_val, void *param )
1288 {
1289     intf_thread_t *p_intf = (intf_thread_t *)param;
1290     p_intf->p_sys->p_mi->toggleFSC();
1291
1292     /* Show event */
1293      return VLC_SUCCESS;
1294 }