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